rubysinatrahaml

How to create a HAML6 helper that renders and returns at the same time?


I'm trying to design a helper for HAML, which would work like this:

%table
- tabular(items) do |i|
  %tr
    %td
      = i[:title]

I expect it to render the following HTML:

<table>
  <tr><td>first</td></tr>
  <tr><td>second</td></tr>
  <tr><td>Total: 2</td></tr> <!-- This is not an item! -->
</table>

I'm trying this approach, but doesn't work:

def tabular(items)
  total = 0
  items.each do |i|
    total += 1
    yield i
  end
  "<tr><td>Total: #{total}</td></tr>" # this line doesn't print :(
end

Solution

  • There is an output buffer instance variable @_out_buf, you can append to it:

    # views/index.haml
    
    - items = [{title: :first}, {title: :second}]
    
    %table
      # you have to indent this
      - tabular(items) do |i|
        %tr
          %td
            = i[:title]
    
    # app.rb
    
    require "sinatra"
    
    helpers do
      def concat string
        @_out_buf << string
      end
    
      def tabular(items)
        total = 0
        items.each do |i|
          total += 1
          yield i
        end
        concat "<tr><td>Total: #{total}</td></tr>"
      end
    end
    
    get "/" do
      haml :index
    end
    

    Renders:

    <table>
     <tr><td>first</td></tr>
     <tr><td>second</td></tr>
     <tr><td>Total: 2</td></tr>
    </table>