I’m a fan of the DRY (Don’t Repeat Yourself) principal. I think that computers were invented for a reason and that reason was not so that I could do the same thing over and over. If it’s one thing that computers do well, it’s doing the exact same thing ad nauseum. So, I do as much as I can in order not to repeat myself a lot when coding.
I have an case now where within the main portion where content is rendered sometimes there separate content on the right side, and sometimes there is not. For example, with no content on the right side, it looks like so:
<div id="left">
I am left content
</div>
Simple enough, but when there is content on the right side, the left side has to get a little smaller, so there is a class added called “with_left” to the left div that makes the width less to accommodate the right content.
<div id="right">
I am right content
</div>
<div id="left" class="with_right">
I am left content
</div>
The problem comes in when the right content is different from page to page and I’m not exactly sure if there is going to be any right content to begin with, as it relies on some dynamic data. Sure, I could do something like this for every page, but I would get annoying fast, and I’m sure there would be one instance where I would forget to do it the right way:
<% if right_content %>
<div id="right">
<%= right_content %>
</div>
<% end %>
<div id="left" <%= 'class="with_right"' if right_content -%>>
I am left content
</div>
So, in comes Ruby to the rescue. I heart blocks and I’m glad that ruby has them, because this is a great case where they come in handy. Instead of doing the above logic over and over again, I can create a method called main_content that allows me to do this in a more generic way.
def main_content(params={},&block)
right_content = params[:right_content]
unless right_content.blank?
right_div = <<-HTML
<div id="right">
#{right_content}
</div>
HTML
concat(right_div)
concat('<div id="left" class="with_right">')
else
concat('<div id="left">')
end
yield
concat('</div>')
end
Now I can use this method like so:
<% main_content(:right_content=>render(:partial=>'account_actions')) do %>
<h3>Edit Account</h3>
<% end >%
If the partial account_actions renders anything, I will get this:
<div id="right">
Output of account_actions partial
</div>
<div id="left" class="with_right">
<h3>Edit Account</h3>
</div>
If the account_actions partial doesn’t end up rendering anything, then I get:
<div>
<h3>Edit Account</h3>
</div>
Nice! Everything looks good, so I can start adding some tests to it. Here’s how I tested it with rspec:
describe 'main content renderer' do
before do
@buffer = ""
stub!(:output_buffer).and_return(@buffer)
end
it 'will render only the left div when there is no right content' do
main_content{}
output_buffer.should have_tag("div#left")
end
it 'will put the yielded content in the left div' do
main_content{concat("Yielded content")}
output_buffer.should have_tag("div#left","Yielded content")
end
it 'will display the right content in the right div if there is any' do
main_content(:right_content=>'Right'){}
output_buffer.should have_tag("div#right","Right")
end
it 'will add a class of "with_right" to the left div if there is right content' do
main_content(:right_content=>'Right'){}
output_buffer.should have_tag("div#left.with_right")
end
end