require 'sinatra/base' require 'sinatra/capture' module Sinatra # = Sinatra::ContentFor # # Sinatra::ContentFor is a set of helpers that allows you to capture # blocks inside views to be rendered later during the request. The most # common use is to populate different parts of your layout from your view. # # The currently supported engines are: Erb, Erubis, Haml and Slim. # # == Usage # # You call +content_for+, generally from a view, to capture a block of markup # giving it an identifier: # # # index.erb # <% content_for :some_key do %> # ... # <% end %> # # Then, you call +yield_content+ with that identifier, generally from a # layout, to render the captured block: # # # layout.erb # <%= yield_content :some_key %> # # === Classic Application # # To use the helpers in a classic application all you need to do is require # them: # # require "sinatra" # require "sinatra/content_for" # # # Your classic application code goes here... # # === Modular Application # # To use the helpers in a modular application you need to require them, and # then, tell the application you will use them: # # require "sinatra/base" # require "sinatra/content_for" # # class MyApp < Sinatra::Base # helpers Sinatra::ContentFor # # # The rest of your modular application code goes here... # end # # == And How Is This Useful? # # For example, some of your views might need a few javascript tags and # stylesheets, but you don't want to force this files in all your pages. # Then you can put <% yield_content :scripts_and_styles %> on your # layout, inside the tag, and each view can call content_for # setting the appropriate set of tags that should be added to the layout. # module ContentFor include Capture # Capture a block of content to be rendered later. For example: # # <% content_for :head do %> # # <% end %> # # You can call +content_for+ multiple times with the same key # (in the example +:head+), and when you render the blocks for # that key all of them will be rendered, in the same order you # captured them. # # Your blocks can also receive values, which are passed to them # by yield_content def content_for(key, &block) content_blocks[key.to_sym] << capture_later(&block) end # Check if a block of content with the given key was defined. For # example: # # <% content_for :head do %> # # <% end %> # # <% if content_for? :head %> # content "head" was defined. # <% end %> def content_for?(key) content_blocks[key.to_sym].any? end # Render the captured blocks for a given key. For example: # # # Example # <%= yield_content :head %> # # # Would render everything you declared with content_for # :head before closing the tag. # # You can also pass values to the content blocks by passing them # as arguments after the key: # # <%= yield_content :head, 1, 2 %> # # Would pass 1 and 2 to all the blocks registered # for :head. def yield_content(key, *args) content_blocks[key.to_sym].map { |b| capture(*args, &b) }.join end private def content_blocks @content_blocks ||= Hash.new {|h,k| h[k] = [] } end end helpers ContentFor end