19

During refactoring it would be quite handy just to copy part of HAML template and paste it to helper's code. Currently in such cases 1) I have to rewrite that part of view from scratch 2) I have to use that verbose syntax like content_tag or haml_tag.

I know that it's possible to define partials with HAML systax that will serve as helper. Though 1) as for me it's inconvinient to create a separate file for each small tiny function 2) invocation syntax for partial is quite verbose.

Ideally i'd like my *_helper class to look like this:

- def some_helper(*its_args)
  .some_class
    = some_ruby_expression
  %some_tag#some_id
    - another_expression do
      etc

or at least like this:

define_haml_helper :some_helper, [:arg1, :arg2], %{
  .some_class
    = some_ruby_expression
  %some_tag#some_id
    - another_expression do
      etc
}

Is there a plugin that solves my issue?

Alternatively, maybe you can describe how do you refactor HAML snippets to reusable elements (helpers/functions/partials/builders/etc)?

tereško
  • 58,060
  • 25
  • 98
  • 150
Alexey
  • 9,197
  • 5
  • 64
  • 76

4 Answers4

13

From the reference:

def render_haml(code)
    engine = Haml::Engine.new(code)
    engine.render
end

This initiates a new Haml engine and renders it.

  • It would be nice to have the functionality wrapped with pritty-looking syntax for engine caching. I just wonder maybe there exists a gem for that matter. – Alexey Mar 09 '11 at 13:07
  • @Alexy I'm bored anyway so I'll write that gem. Soon. I can't think of such a gem that already exists right now but it's not hard to implement. –  Mar 09 '11 at 13:18
  • is it worth caching this? so @haml_engine ||= etc... ? – Simon Mar 09 '11 at 14:54
  • 1
    @PeterEhrlich I have a helper method called `hamlize` which consists only of `Haml::Engine.new( yield ).render if block_given?` This seems to do what you're thinking of: `hamlize{ "%div.some-class" + some_method_that_returns_valid_haml( arg1, arg2 ) }` Though I would be interested in the answer to @Simon's comment too -- not sure if I should cache the Engine? Also still working on getting other helper methods into the Engine's context... – Jazz Nov 15 '12 at 15:46
  • @Simon that will break if you want to render different templates. –  Apr 21 '13 at 11:15
4

If all you are after is a method for small reusable snippets, how about partials with local variables? http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials

ghempton
  • 7,777
  • 7
  • 48
  • 53
3

Haml now has a capture_haml method that you can use to accomplish this.

  def some_helper
    capture_haml do
      .some_class
        = yield
      #some-code-after
    end
  end

some_helper do
  %h1 Hello World
end
=> <div class="some_class">
     <h1>Hello World</h1>
   </div>
   <div id="some-code-after"></div>

Here is a link with more info on capture_haml: http://haml.info/docs/yardoc/Haml/Helpers.html#capture_haml-instance_method

richoffrails
  • 1,003
  • 8
  • 11
  • 4
    I think you misunderstood the meaning of the function. The snippet you gave cannot work - you cannot put HAML right in the middle of Ruby. – Alexey Oct 10 '13 at 20:36
0

I used heredoc for such purposes:

  def view_helper
    Haml::Engine.new(<<~HAML).render
      .example
        #id ID
        .desc Description
    HAML
  end

This way has a lot of issues with a scope of variables, so, as mentioned above, the much more correct way is to use partials for this.

UPD1: here is a solution on how to solve issues with scope:

  def view_helper
    Haml::Engine.new(<<~HAML).render(self)
      .form
        = form_tag root_path do
          = submit_tag :submit
    HAML
  end

UPD2: even better solution(founded on the internet):

def render_haml(haml, locals = {})
  Haml::Engine.new(haml.strip_heredoc, format: :html5).render(self, locals)
end

def greeting
  render_haml <<-HAML
    .greeting
      Welcome to
      %span.greeting--location
        = Rails.env
  HAML
end
SERGHII
  • 64
  • 5