From 8db79da471d6f06d7a70ed88f3bb03db6d5bc212 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Fri, 22 Apr 2011 23:04:13 +0200 Subject: [PATCH] move capturing to its own extension --- lib/sinatra/capture.rb | 46 ++++++++++++++++++++++++++++++++++++++ lib/sinatra/content_for.rb | 31 +++++-------------------- lib/sinatra/contrib.rb | 2 ++ sinatra-contrib.gemspec | 1 + 4 files changed, 55 insertions(+), 25 deletions(-) create mode 100644 lib/sinatra/capture.rb diff --git a/lib/sinatra/capture.rb b/lib/sinatra/capture.rb new file mode 100644 index 0000000..4d2bd71 --- /dev/null +++ b/lib/sinatra/capture.rb @@ -0,0 +1,46 @@ +require 'sinatra/base' + +module Sinatra + module Capture + DUMMIES = { + Tilt::HamlTemplate => "!= capture_haml(*args, &block)", + Tilt::ERBTemplate => "<% yield(*args) %>", + Tilt::ErubisTemplate => "<%= yield(*args) %>", + :slim => "== yield(*args)" + } + + def call!(env) + @current_engine = :ruby + super + end + + def capture(options = {}, &block) + opts = { :block => block, :args => [] }.merge options + engine = opts.delete(:engine) || @current_engine + block = opts[:block] + if engine == :ruby + block[*opts[:args]] + else + dummy = DUMMIES[Tilt[engine]] || DUMMIES.fetch(engine) + eval '_buf.clear if defined? _buf', block.binding + render(engine, dummy, {}, opts, &block) + end + end + + def capture_later(options = {}, &block) + opts = { :block => block, :args => [], :engine => @current_engine } + opts.merge options + end + + private + + def render(engine, *) + @current_engine, engine_was = engine.to_sym, @current_engine + super + ensure + @current_engine = engine_was + end + end + + helpers Capture +end diff --git a/lib/sinatra/content_for.rb b/lib/sinatra/content_for.rb index ff3010e..f9ef185 100644 --- a/lib/sinatra/content_for.rb +++ b/lib/sinatra/content_for.rb @@ -1,4 +1,5 @@ require 'sinatra/base' +require 'sinatra/capture' module Sinatra ## @@ -36,6 +37,8 @@ module Sinatra # 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 %> @@ -50,8 +53,7 @@ module ContentFor # Your blocks can also receive values, which are passed to them # by yield_content def content_for(key, &block) - @current_engine ||= :ruby - content_blocks[key.to_sym] << [@current_engine, block] + content_blocks[key.to_sym] << capture_later(&block) end # Render the captured blocks for a given key. For example: @@ -72,33 +74,12 @@ def content_for(key, &block) # Would pass 1 and 2 to all the blocks registered # for :head. def yield_content(key, *args) - content_blocks[key.to_sym].map { |e,b| capture(e, args, b) }.join - end - - def self.capture - @capture ||= {} + opts = { :args => args } + content_blocks[key.to_sym].map { |c| capture c.merge(opts) }.join end private - # generated templates will be cached by Sinatra in production - capture[:haml] = "!= capture_haml(*args, &block)" - capture[:erb] = "<% yield(*args) %>" - capture[:erubis] = "<%= yield(*args) %>" - capture[:slim] = "== yield(*args)" - - def capture(engine, args, block) - eval '_buf.clear if defined? _buf', block.binding - render(engine, Sinatra::ContentFor.capture.fetch(engine), {}, :args => args, :block => block, &block) - end - - def render(engine, *) - @current_engine, engine_was = engine.to_sym, @current_engine - super - ensure - @current_engine = engine_was - end - def content_blocks @content_blocks ||= Hash.new {|h,k| h[k] = [] } end diff --git a/lib/sinatra/contrib.rb b/lib/sinatra/contrib.rb index a042492..a29ba9f 100644 --- a/lib/sinatra/contrib.rb +++ b/lib/sinatra/contrib.rb @@ -11,6 +11,8 @@ module Common register :ConfigFile register :Namespace register :RespondWith + + helpers :Capture helpers :ContentFor helpers :LinkHeader end diff --git a/sinatra-contrib.gemspec b/sinatra-contrib.gemspec index b91d0e0..71b7668 100644 --- a/sinatra-contrib.gemspec +++ b/sinatra-contrib.gemspec @@ -28,6 +28,7 @@ Gem::Specification.new do |s| "README.md", "Rakefile", "ideas.md", + "lib/sinatra/capture.rb", "lib/sinatra/config_file.rb", "lib/sinatra/content_for.rb", "lib/sinatra/contrib.rb",