Giter VIP home page Giter VIP logo

block_helpers's Introduction

Block Helpers

When we write ERB views in Rails, etc., we generally DRY up the markup using helpers or partials.

However, it's quite common to overdo the 'DRYing up'.

When you find yourself passing in optional arguments to a helper/partial such as :extra_text => 'eggs', :to_s_method => 'cheese', you know that there must be a better way.

Rails already has a great solution for forms with form-builders, using helpers which yield an object which can be used for further rendering.

This small gem generates helpers similar to the form-builders, but for the general case.

Installation

To use in Rails, add to your environment.rb:

config.gem "block_helpers", :source => "http://gemcutter.org"

for Merb, in init.rb:

dependency "block_helpers"

If using Rails 3.x, add to your Gemfile

gem "block_helpers"

and run 'bundle install'.

Example usage

Please note that these examples are very contrived just for brevity! These block helpers are much more useful than just printing 'Hi there Marmaduke!'

Simple case

In the helper file:

module MyHelper

  class MyBlockHelper < BlockHelpers::Base
  
    def hello(name)
      "<p>Hi there #{name}!</p>"
    end
  
  end

end

This has generated a helper called my_block_helper. So in the view:

<% my_block_helper do |h| %>
  Here goes...
  <%= h.hello('Marmaduke') %>
  ...hooray!
<% end %>

This will generate the following:

Here goes...
<p>Hi there Marmaduke!</p>
...hooray!

Accessing other helper methods

Methods available in the parent helper are available to the block helper class. In case of name clashes, you can also access those methods via the protected object helper. In the helper:

module MyHelper

  def angry
    "I'm very angry"
  end

  class MyBlockHelper < BlockHelpers::Base

    def angry
      content_tag :div, helper.angry
    end

  end

end

In the view:

<% my_block_helper do |h| %>
  <%= h.angry %>
<% end %>

This generates:

<div>I'm very angry</div>

Using arguments

You can pass in arguments to the helper, and these will be passed through to the class's initialize method. In the helper:

module MyHelper

  class MyBlockHelper < BlockHelpers::Base

    def initialize(tag_type)
      @tag_type = tag_type
    end

    def hello(name)
      content_tag @tag_type, "Hi there #{name}!"
    end

  end

end

In the view:

<% my_block_helper(:span) do |h| %>
  <%= h.hello('Marmaduke') %>
<% end %>

This generates:

<span>Hi there Marmaduke!</span>

Surrounding markup

Use the display method to surround the block with markup, e.g. In the helper:

module MyHelper

  class RoundedBox < BlockHelpers::Base

    def display(body)
      %(
        <div class="tl">
          <div class="tr">
            <div class="bl">
              <div class="br">
                #{body}
              </div>
            </div>
          </div>
        </div>
      )
    end

  end

end

In the view:

<% rounded_box do %>
  Oi oi!!!
<% end %>

This generates:

<div class="tl">
  <div class="tr">
    <div class="bl">
      <div class="br">
        Oi oi!!!
      </div>
    </div>
  </div>
</div>

Of course, you could use display for more than just surrounding markup.

Nesting

You can even nest block helpers:

module MyHelper

  class Nav < BlockHelpers::Base

    #...code....

    class SubNav < BlockHelpers::Base

      #...code...

    end

  end

end

In the view:

<% nav do |h| %>
  ...
  <% h.sub_nav do %>
    ...
  <% end %>
  ...
<% end %>

However... I'd be careful not to abuse this, as the code could end up more confusing than it needs be. Nested block helpers can access the parent block helper by using the parent method.

Testing

I'm not too sure about other testing frameworks, but with rspec-rails you can use 'eval_erb', e.g.

eval_erb(%(
  <% my_block_helper do |h| %>
    <h2>Hello</h2>
    <%= h.write_blah %>
  <% end %>
)).should match_html("<h2>Hello</h2> blah blah blah ")

In the above I've used the following simple matcher match_html:

def match_html(html)
  # Match two strings, but don't care about whitespace
  simple_matcher("should match #{html}"){|given| given.strip.gsub(/\s+/,' ').gsub('> <','><') == html.strip.gsub(/\s+/,' ').gsub('> <','><') }
end

Obviously you test however you want but I've included the above in case it's useful.

Using with Rails 3

Rails 3 uses a littlebit different helper block syntax than Rails 2. (See the screencast from Ryan Bates for more details.) In short: blocks need to be marked with <%= %> instead of <% %>.

Block_helpers will work as per the new syntax if run on Rails 3. If you want it to fall back to the Rails 2 syntax (in Rails 3) redefine the rails2_compatibility_mode? method to return true (either at custom class level or at application level in an initializer).

Compatibility

Currently it depends on activesupport, and requires that the helper already has the methods concat and capture available (which is the case in Rails and Merb). Please, note, that ActiveSupport 3.1+ breaks the capture method (see this comment and this commit). Thus capture got replicated in the gem.

It works with both the one and two argument versions of concat, so should work with all recent versions of Rails and Merb.

Credits

Copyright

Copyright (c) 2009 Mark Evans. See LICENSE for details.

block_helpers's People

Contributors

fastcatch avatar nesquena avatar

Stargazers

 avatar  avatar  avatar

Forkers

taf2 nachokb

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.