Want a MSN hotmail account? Be prepared to run this gauntlet:
About Jamis
He makes marshmallows and bow ties, plays guitar, and researches dead people. Sometimes all at the same time.
Beautiful Code: The evolution of an iterator
David, Marcel, and I had an interesting design-related discussion yesterday. But it wasn’t related to designing graphical UI’s — it was abut designing developer UI’s in code.
I was sharing some code I’d written related to the new data export feature we’re adding to Basecamp. The Export model supports a set of distinct states, “pending”, “processing”, and “completed”. I found myself iterating over those states in a few different places so I added a custom iterator to the model. This allowed me to centralize the work needed to do that loop:
class Export < ActiveRecord::Base
PENDING = "pending"
PROCESSING = "processing"
COMPLETED = "completed"
STATES = [PENDING, PROCESSING, COMPLETED]
def self.each_state
STATES.each { |state| yield state }
end
# ...
end
The custom iterator is then used something like this:
class ExportPresenter
# ...
Export.each_state do |state|
class_eval "def #{state}?; @export && @export.#{state}?; end"
end
# ...
end
Some discussion ensued:
The result was much cleaner, and allowed for the full gamut of Array operations to be performed on Export.states.
class Export < ActiveRecord::Base
PENDING = "pending"
PROCESSING = "processing"
COMPLETED = "completed"
def self.states
@states ||= [PENDING, PROCESSING, COMPLETED]
end
# ...
end
class ExportPresenter
# ...
Export.states.each do |state|
class_eval "def #{state}?; @export && @export.#{state}?; end"
end
# ...
end
