Customizing Markaby – Language Level Refactorings
It’s very easy to call out to methods in markaby, but it’d be nice if you could actually customize the dsl as well.
For example, on many of our pages we have a bottom row that has buttons that look a certain way. So on every page, we have :
table(:width => "100%") do tr do td.left do previous_button first_button end td.center do print end td.right do next_button last_button end end end
The code for the actual buttons changes, and after a few tries to extract the whole thing into a single method, we gave up. Our efforts had made it harder to read, not easier. There was always just a little too much variance, and it didn’t feel right.
What we really wanted to write was :
last_row do column do previous_button first_button end column do print end column do next_button last_button end end
This lets the buttons that change all stay in the view, and gets rid of the skeleton and positional stuff that doesn’t change. Furthermore, it’s DRY and puts all that positional logic in one place instead of scattered across 20 views.
How to do this?
I wrote a test (in RSpec) that looks something like :
describe ApplicationHelper do it "should generate a table from a buttons method" do last_row(:columns => 2) do column do "foo" end column do "bar" end end.should == '<table width="100%"><tr>' + '<td class="left">foo</td>' + '<td class="right">bar</td>' + '</tr></table>' end end
After a bunch of fiddling and poking around, I finally made the test (and a couple others) pass with this code in my ApplicationHelper :
def last_row(options, &block) markaby do table(:width => "100%") do tr do LastRowContext.new(self, options[:columns]). instance_eval(&block) end end end end class LastRowContext def initialize(markaby, columns) @markaby, @column_count, @column_index = markaby, columns, 0 end def column(&block) alignment = case @column_index += 1 when 1 : :left when @column_count : :right else :center end @markaby.instance_eval do td(:class => alignment, &block) end end end
I’m sure this could get cleaned up more; this was the work of less than an hour. In particular, if you did this often, you could extract a common MarkabyContext superclass that had some convenience methods. The point is, this is really easy to do, and we shouldn’t be scared to try “Language level refactorings” like this.
September 26th, 2007 at 11:14 pm
Hello-
I was looking at your work, and think you might be able to help out with an
existing project I am working on (in-line text ad network)—I can explain
further later, but was wondering what your hourly rate for php/js/ajax/maybe RoR development is and if you are available to help out with this….
Currently the project is being developed in Bangelore, India—but I want some more reliable, experienced developers to help clean up the code and user experience with more ajax/RoR integration (drag + drop, etc.) on the clientfacing advertiser/publisger admin. Bottom line is that I need solid, local, experienced developers I can trust to finish out and make this application robust, scalable, and at the end of the day a success.
Main Competitors: Kontera.com, vibrantmedia.com, mediatext.com
Thanks. Please let me know either way.
Best-
Richard
Seattle, WA
September 26th, 2007 at 11:14 pm
Hey Richard,
I’m going to need some more contact info there, I’m with “pivotal”:http://pivotallabs.com/ these days and I’d love to talk to you and see whether we’d be a good fit for you. Shoot me an e-mail @ jeremystellsmith@gmail.com.