Carl Fyffe submitted a small snippet of an existing application, asking how we’d polish it. We’ve decided to try out a new format for this kind of micro-refactoring; let us know what you think.
Before:
1 2 3 4 5 6 7 8 9 10 11 12
# returns Hash of Engagements keyed on date.
def self.find_by_year_month(year, month)
date = Time.gm year, month
engagements = {}
all = find(:all, :conditions => ["start >= ? and start <= ?", date.last_month.end_of_month, date.next_month.beginning_of_month], :order => :start)
all.each do |e|
key = e.start.strftime('%Y%m%d')
engagements[key] = [] unless engagements.has_key?(key)
engagements[key].push e
end
engagements
end
After:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
def self.find_by_year_month(year, month)
# We're dealing with Dates, so let's use the Date class. Date can
# be a little slower than Time, but as this method isn't going to
# perform thousands of operations per request, we'll be fine.
requested_date = Date.new(year, month, 1)
# The range in the original code went from the last day of the
# previous month, to the first day of the following month.
# Date#- subtracts days from a given date, which lets us find
# the end of last month.
from = requested_date - 1
# Date#>> lets us advance requested date by one month,
# giving us the first of the next month.
to = requested_date >> 1
# The BETWEEN operator lets you simplify the SQL, and it more
# clearly matches the intent.
engagements = find(:all, :conditions => ["start BETWEEN ? and ?", from, to],
:order => :start)
# Enumerable#group_by returns a hash with the date strings as keys
# and an array of the corresponding engagements as the values.
# If you find yourself initializing a collection, adding some items
# then returning it, you can probably find a method to tidy that
# up.
engagements.group_by do |engagement|
engagement.start.strftime("%Y%m%d")
end
end
No comments yet.
You must be logged in to add your own comment.