.erb, the buffer?
This one is a little bit old, but if any of you are familiar with rails' views you'll probably have seen bits of view code like:
<% form_for @user do |f| %>
...
<% end %>
And if you've ever jumped into erb in your own ruby you've probably made an attempt at doing something similar trying to put something into the buffer without the use of =. This is of course because ERB doesn't let you use blocks when you make use of =.
How do we even do this? In erb there is absolutely no way to use put
or anything else to echo something from one of your methods.
The first question most people ask is how does rails do it. Which has a simple answer which makes things insanely complex. They have a huge setup where they do some sort of extension of erb, throw in special handling of the buffer into a way that allows them to create a concat method which can be used to push things into the buffer. I completely failed at attempting to include that portion of rails code outside of rails.
I to needed to be able to do something similar for a ruby project at work, and I had no intention of using rails in the project. I ended up trying out erubis instead of erb and found out I could make the buffer available to my helper methods using a bit of code like so:
class Template < Erubis::Eruby
alias :old_result :result
def result(_binding=TOPLEVEL_BINDING)
@src = "@buf = " + @src
res = old_result(_binding)
@src = @src[7..-1]
res
end
end
I was already extending whatever ERB or Erubis I was making use of into a Template class for some other purposes. But basically here what I did was make a minor extension to the Erubis's result method. I just shoved a "@buf = "
onto the compiled template code. The end result from this minor piece of code is that @buf
becomes available to all my helper methods, and so I can do things like:
def js(&block)
@buf << '<script type="text/javascript">'
block.call
@buf << '</script>'
end
Note that you don't use @buf <<
when you call the block, that's because the template already has buf <<
inside of the block itself.
It might be a hack, but compared to rails' hack it's quite elegant imho.