Skip to content

Instantly share code, notes, and snippets.

@joseph
Created July 22, 2011 01:12
Show Gist options
  • Save joseph/1098634 to your computer and use it in GitHub Desktop.
Save joseph/1098634 to your computer and use it in GitHub Desktop.
blocks_for helper
# Iterates over an array and creates a bunch of "blocks" containing the
# yielded content. Example:
#
# <% urls = [
# "http://inventivelabs.com.au",
# "http://booki.sh",
# "http://nomify.com",
# "http://rungs.com.au",
# "http://getslipcase.com"
# ] %>
# <% blocks_for(urls, 2) do |url, pos| %>
# <%= link_to(url, url) %>
# <% end %>
#
# ... produces ...
#
# <div class="block_first">
# <a href="http://inventivelabs.com.au">http://inventivelabs.com.au</a>
# <a href="http://booki.sh">http://booki.sh</a>
# </div>
# <div>
# <a href="http://nomify.com">http://nomify.com</a>
# <a href="http://rungs.com.au">http://rungs.com.au</a>
# </div>
# <div class="block_last">
# <a href="http://getslipcase.com">http://getslipcase.com</a>
# </div>
#
#
# Options:
#
# - :block_tag (defaults to "div")
# - :first_block_class (defaults to "block_first")
# - :last_block_class (defaults to "block_last")
#
# All other options are passed directly to block tag.
#
# Yielded to block:
#
# |obj, pos, index|
#
# ... where 'pos' is an object you can interrogate like this:
#
# pos.first? -> true if first object in the block
# pos.last? -> true if the per-block-th object in the block
# pos.middle? -> true if not first or last object in the block
#
# Not that if per-block is say, 6, and the array is 20 items long, the
# last block will contain 2 objects -- no object will have pos.last? in
# this block.
#
def blocks_for(array, per_block, options = {}, &blk)
options = options.with_indifferent_access
block_tag = options.delete(:block_tag) || "div"
first_class = options.delete(:first_block_class) || "block_first"
first_class += " #{options[:class]}"
last_class = options.delete(:last_block_class) || "block_last"
last_class += " #{options[:class]}"
blocks = []
bits = []
new_block = lambda { |cursor|
opts = options
if cursor < per_block
opts = opts.merge(:class => first_class.strip)
elsif cursor > (array.size - per_block)
opts = opts.merge(:class => last_class.strip)
end
blocks << content_tag(block_tag, bits.join("\n"), opts)
bits = []
}
array.each_with_index { |obj, i|
mod_i = i % per_block
pos = ActiveSupport::StringInquirer.new(
mod_i == 0 ? "first" : mod_i == per_block - 1 ? "last" : "middle"
)
bits << capture(obj, pos, mod_i, &blk)
new_block.call(i) if pos.last?
}
new_block.call(array.size - 1) if bits.any?
concat(blocks.join("\n"))
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment