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