Slides from my Lightning Talk at AgileBrazil 2011 in Fortaleza about refactoring katas. Check the code on Github at: http://github.com/dtsato/kata-refactoring-calendar
42. Plano
1. Centralizar lógica de manipulação de datas
2. Unificar named scopes
3. Extrair lógica do Controller
4. Quebrar lógica de timeframes diferentes
43. def index(params)
case params[:timeframe]
when 'tomorrow'
date = DateTime.now + 1
start_date = date.at_beginning_of_day
end_date = start_date.end_of_day
when 'this_week'
start_date = DateTime.now
end_date = (DateTime.now + 6 ).end_of_day
when 'custom'
start_date = params[:start_date].blank? ? DateTime.now.beginning_of_week :
DateTime.strptime(params[:start_date], '%m/%d/%Y')
end_date = params[:end_date].blank? ? (DateTime.now.end_of_week - 2) :
DateTime.strptime(params[:end_date], '%m/%d/%Y').end_of_day
when 'hour'
start_date = DateTime.strptime(params[:hour], '%m/%d/%Y %H:%M')
end_date = start_date + 1.hour-1.second
when 'today'
date = DateTime.now
start_date = date.at_beginning_of_day
end_date = start_date.end_of_day
end
@events = Event.between_dates(start_date, end_date)
end
44. class Event < ActiveRecord::Base
named_scope :between_dates, lambda { |start_date, end_date|
{:conditions => {:at => start_date..end_date}}
}
end
47. Antes Depois
.......
.
............
ds Finished in
0 .49367 secon 0.25355 seco
Finished in res 7 examples, nds
13 examp les, 0 failu 0 failures
class Event < ActiveRecord::Base
named_scope :between_dates, lambda { |start_date, end_date|
{:conditions => {:at => start_date..end_date}}
}
end
lib/calendar_search_controller.rb | 27 +++++++++++++--------------
lib/event.rb | 13 +------------
spec/event_spec.rb | 37 -------------------------------------
3 files changed, 14 insertions(+), 63 deletions(-)
48. class CalendarSearchController
attr_reader :events
def index(params)
timeframe = TimeFrame.for(params[:timeframe], params[:start_date],
params[:end_date], params[:hour])
@events = Event.between_dates(timeframe.start_date, timeframe.end_date)
end
end
mudança nos testes:
it "should create time frame from params and retrieve events" do
timeframe = TimeFrame.new(DateTime.now, DateTime.now)
TimeFrame.should_receive(:for).with('today', 'start', 'end',
'hour').and_return(timeframe)
events = [Event.new, Event.new]
Event.should_receive(:between_dates).with(timeframe.start_date,
timeframe.end_date).and_return(events)
@controller.index(:timeframe => 'today', :start_date => 'start', :end_date =>
'end', :hour => 'hour')
@controller.events.should == events
end
49. class TimeFrame < Struct.new(:start_date, :end_date)
def self.for(type, start_date, end_date, hour)
case type
when 'tomorrow'
date = DateTime.now + 1
TimeFrame.new(date.at_beginning_of_day, date.end_of_day)
when 'this_week'
TimeFrame.new(DateTime.now, (DateTime.now + 6 ).end_of_day)
when 'custom'
start_date = start_date.blank? ? DateTime.now.beginning_of_week :
DateTime.strptime(start_date, '%m/%d/%Y')
end_date = end_date.blank? ? (DateTime.now.end_of_week - 2) :
DateTime.strptime(end_date, '%m/%d/%Y').end_of_day
TimeFrame.new(start_date, end_date)
when 'hour'
start_date = DateTime.strptime(hour, '%m/%d/%Y %H:%M')
end_date = start_date + 1.hour-1.second
TimeFrame.new(start_date, end_date)
when 'today'
date = DateTime.now
TimeFrame.new(date.at_beginning_of_day, date.end_of_day)
end
end
end
50. describe TimeFrame do
before do
@today = DateTime.strptime('06/01/2011', '%m/%d/%Y')
DateTime.stub!(:now).and_return(@today)
end
describe "today's event" do
it "should use beginning and end of day" do
timeframe = TimeFrame.for('today', nil, nil, nil)
timeframe.start_date.should == @today.at_beginning_of_day
timeframe.end_date.should == @today.end_of_day
end
end
...
end
51. describe TimeFrame do
before do
@today = DateTime.strptime('06/01/2011', '%m/%d/%Y')
DateTime.stub!(:now).and_return(@today)
end
describe "today's event" do
it "should use beginning and end of day" do
timeframe = TimeFrame.for('today', nil, nil, nil)
timeframe.start_date.should == @today.at_beginning_of_day
timeframe.end_date.should == @today.end_of_day
end
Rakefile | 4 ++
end
lib/calendar_search_controller.rb | 24 +---------
...
lib/time_frame.rb | 24 ++++++++++
end
spec/acceptance_tests.rb | 75 +++++++++++++++++++++++++++++++
spec/calendar_search_controller_spec.rb | 75 ++++---------------------------
spec/time_frame_spec.rb | 63 ++++++++++++++++++++++++++
6 files changed, 178 insertions(+), 87 deletions(-)
52. Antes
.......
ds
describe d in 0 .25355 secon
Finishe TimeFrame do es
before les, 0 failur
7 examp do
@today = DateTime.strptime('06/01/2011', '%m/%d/%Y')
DateTime.stub!(:now).and_return(@today)
end
describe "today's event" do
it "should use beginning and end of day" do
timeframe = TimeFrame.for('today', nil, nil, nil)
timeframe.start_date.should == @today.at_beginning_of_day
timeframe.end_date.should == @today.end_of_day
end
Rakefile | 4 ++
end
lib/calendar_search_controller.rb | 24 +---------
...
lib/time_frame.rb | 24 ++++++++++
end
spec/acceptance_tests.rb | 75 +++++++++++++++++++++++++++++++
spec/calendar_search_controller_spec.rb | 75 ++++---------------------------
spec/time_frame_spec.rb | 63 ++++++++++++++++++++++++++
6 files changed, 178 insertions(+), 87 deletions(-)
53. Antes Depois
........
.......
ds Finished in
describe d in 0 .25355 secon
she TimeFrame do
0.17938 seco
nds
Fini 8 examples,
before les, 0 failures
7 ex amp do
0 failures
@today = DateTime.strptime('06/01/2011', '%m/%d/%Y')
DateTime.stub!(:now).and_return(@today)
end
describe "today's event" do
it "should use beginning and end of day" do
timeframe = TimeFrame.for('today', nil, nil, nil)
timeframe.start_date.should == @today.at_beginning_of_day
timeframe.end_date.should == @today.end_of_day
end
Rakefile | 4 ++
end
lib/calendar_search_controller.rb | 24 +---------
...
lib/time_frame.rb | 24 ++++++++++
end
spec/acceptance_tests.rb | 75 +++++++++++++++++++++++++++++++
spec/calendar_search_controller_spec.rb | 75 ++++---------------------------
spec/time_frame_spec.rb | 63 ++++++++++++++++++++++++++
6 files changed, 178 insertions(+), 87 deletions(-)
54. class TimeFrame
attr_reader :start_date, :end_date
class Today < TimeFrame
def initialize
date = DateTime.now
@start_date, @end_date = date.at_beginning_of_day, date.end_of_day
end
end
...
end
describe TimeFrame::Today do
it "should use beginning and end of day" do
timeframe = TimeFrame::Today.new
timeframe.start_date.should == @today.at_beginning_of_day
timeframe.end_date.should == @today.end_of_day
end
...
end
55. class TimeFrame
...
def self.for(type, start_date, end_date, hour)
case type
when 'tomorrow' then Tomorrow.new
when 'this_week' then ThisWeek.new
when 'custom' then Custom.new(start_date, end_date)
when 'hour' then Hour.new(hour)
when 'today' then Today.new
end
end
end
describe TimeFrame::Today do
...
describe "parsing" do
it "should parse today's timeframe" do
TimeFrame.for('today', nil, nil, nil).should
be_an_instance_of(TimeFrame::Today)
end
...
end
end
56. class TimeFrame
...
def self.for(type, start_date, end_date, hour)
case type
when 'tomorrow' then Tomorrow.new
when 'this_week' then ThisWeek.new
when 'custom' then Custom.new(start_date, end_date)
when 'hour' then Hour.new(hour)
when 'today' then Today.new
end
end
end
describe TimeFrame::Today do
...
describe "parsing" do
lib/time_frame.rb | 59 +++++++++++++++++++++++++++++++++-------------
it "should parse today's timeframe" do
spec/time_frame_spec.rb | 44 ++++++++++++++++++++++++++--------
TimeFrame.for('today', nil, nil, nil).should
2 files changed, 75 insertions(+), 28 deletions(-)
be_an_instance_of(TimeFrame::Today)
end
...
end
end
57. class TimeFrame
... Antes
.def .self.for(type, start_date, end_date, hour)
... ...
case type
ds
0 .17938 secon
when 'tomorrow' then Tomorrow.new
Finished in
when les, 0 failures ThisWeek.new
8 examp 'this_week' then
when 'custom' then Custom.new(start_date, end_date)
when 'hour' then Hour.new(hour)
when 'today' then Today.new
end
end
end
describe TimeFrame::Today do
...
describe "parsing" do
lib/time_frame.rb | 59 +++++++++++++++++++++++++++++++++-------------
it "should parse today's timeframe" do
spec/time_frame_spec.rb | 44 ++++++++++++++++++++++++++--------
TimeFrame.for('today', nil, nil, nil).should
2 files changed, 75 insertions(+), 28 deletions(-)
be_an_instance_of(TimeFrame::Today)
end
...
end
end
58. class TimeFrame
... Antes Depois
............
def .self.for(type, start_date, end_date, hour) .
.... ...
case type
ds Finished in
when d in 0 .17938 secon
she 'tomorrow' then Tomorrow.new
0.19023 seco
nds
Fini 13 examples,
when les, 0 failures ThisWeek.new
8 examp 'this_week' then
0 failures
when 'custom' then Custom.new(start_date, end_date)
when 'hour' then Hour.new(hour)
when 'today' then Today.new
end
end
end
describe TimeFrame::Today do
...
describe "parsing" do
lib/time_frame.rb | 59 +++++++++++++++++++++++++++++++++-------------
it "should parse today's timeframe" do
spec/time_frame_spec.rb | 44 ++++++++++++++++++++++++++--------
TimeFrame.for('today', nil, nil, nil).should
2 files changed, 75 insertions(+), 28 deletions(-)
be_an_instance_of(TimeFrame::Today)
end
...
end
end