Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

add template support to namespaces

  • Loading branch information...
commit aaf66d7f67c3172003fac378a311d6dc5d0bd295 1 parent 10a2734
@rkh rkh authored
View
2  ideas.md
@@ -23,5 +23,3 @@
* Extend `sinatra-content-for` to support Liquid, Radius, Markaby, Nokogiri and
Builder. At least the first two probably involve patching Tilt.
-
-* Have `sinatra-namespace` support namespace local templates.
View
63 lib/sinatra/namespace.rb
@@ -1,3 +1,4 @@
+require 'backports'
require 'sinatra/base'
require 'sinatra/decompile'
@@ -6,23 +7,34 @@ module Namespace
def self.new(base, pattern, conditions = {}, &block)
Module.new do
extend NamespacedMethods
- @base, @extensions = base, []
+ include InstanceMethods
+ @base, @extensions = base, []
@pattern, @conditions = compile(pattern, conditions)
-
+ @templates = Hash.new { |h,k| @base.templates[k] }
namespace = self
- before { extend namespace }
- define_method(:error_block!) do |*keys|
- if block = keys.inject(nil) { |b,k| b ||= namespace.errors[k] }
- instance_eval(&block)
- else
- super(*keys)
- end
- end
-
+ before { extend(@namespace = namespace) }
class_eval(&block)
end
end
+ module InstanceMethods
+ def settings
+ @namespace
+ end
+
+ def template_cache
+ super.fetch(:nested, @namespace) { Tilt::Cache.new }
+ end
+
+ def error_block!(*keys)
+ if block = keys.inject(nil) { |b,k| b ||= @namespace.errors[k] }
+ instance_eval(&block)
+ else
+ super
+ end
+ end
+ end
+
module SharedMethods
def namespace(pattern, conditions = {}, &block)
Sinatra::Namespace.new(self, pattern, conditions, &block)
@@ -32,7 +44,7 @@ def namespace(pattern, conditions = {}, &block)
module NamespacedMethods
include SharedMethods
include Sinatra::Decompile
- attr_reader :base
+ attr_reader :base, :templates
def self.prefixed(*names)
names.each { |n| define_method(n) { |*a, &b| prefixed(n, *a, &b) }}
@@ -75,6 +87,30 @@ def respond_to(*args)
@conditions[:provides] = args
end
+ def set(key, value = self, &block)
+ raise ArgumentError, "may not set #{key}" if key != :views
+ return key.each { |k,v| set(k, v) } if block.nil? and value == self
+ block ||= proc { value }
+ singleton_class.send(:define_method, key, &block)
+ end
+
+ def enable(*opts)
+ opts.each { |key| set(key, true) }
+ end
+
+ def disable(*opts)
+ opts.each { |key| set(key, false) }
+ end
+
+ def template(name, &block)
+ filename, line = caller_locations.first
+ templates[name] = [block, filename, line.to_i]
+ end
+
+ def layout(name=:layout, &block)
+ template name, &block
+ end
+
private
def app
@@ -118,8 +154,7 @@ def prefixed(method, pattern = nil, conditions = {}, &block)
end
def method_missing(meth, *args, &block)
- return super if args.any? or block or not base.respond_to? meth
- base.send meth
+ base.send(meth, *args, &block)
end
end
View
1  spec/namespace/foo.erb
@@ -0,0 +1 @@
+hi
View
1  spec/namespace/nested/foo.erb
@@ -0,0 +1 @@
+ho
View
83 spec/namespace_spec.rb
@@ -490,9 +490,86 @@ def magic
end
describe 'templates' do
- it "allows to define nested templates"
- it "allows to define nested layouts"
- it "allows setting a different views directory"
+ it "allows using templates from the base" do
+ mock_app do
+ template(:foo) { 'hi' }
+ send(verb, '/') { erb :foo }
+ namespace '/foo' do
+ send(verb) { erb :foo }
+ end
+ end
+
+ if verb != :head
+ send(verb, '/').body.should == "hi"
+ send(verb, '/foo').body.should == "hi"
+ end
+ end
+
+ it "allows to define nested templates" do
+ mock_app do
+ template(:foo) { 'hi' }
+ send(verb, '/') { erb :foo }
+ namespace '/foo' do
+ template(:foo) { 'ho' }
+ send(verb) { erb :foo }
+ end
+ end
+
+ if verb != :head
+ send(verb, '/').body.should == "hi"
+ send(verb, '/foo').body.should == "ho"
+ end
+ end
+
+ it "allows to define nested layouts" do
+ mock_app do
+ layout { 'Hello <%= yield %>!' }
+ template(:foo) { 'World' }
+ send(verb, '/') { erb :foo }
+ namespace '/foo' do
+ layout { 'Hi <%= yield %>!' }
+ send(verb) { erb :foo }
+ end
+ end
+
+ if verb != :head
+ send(verb, '/').body.should == "Hello World!"
+ send(verb, '/foo').body.should == "Hi World!"
+ end
+ end
+
+ it "allows using templates from the base" do
+ mock_app do
+ layout { "he said: <%= yield %>" }
+ template(:foo) { 'hi' }
+ send(verb, '/') { erb :foo }
+ namespace '/foo' do
+ template(:foo) { 'ho' }
+ send(verb) { erb :foo }
+ end
+ end
+
+ if verb != :head
+ send(verb, '/').body.should == "he said: hi"
+ send(verb, '/foo').body.should == "he said: ho"
+ end
+ end
+
+ it "allows setting a different views directory" do
+ mock_app do
+ set :views, File.expand_path('../namespace', __FILE__)
+ send(verb, '/') { erb :foo }
+ namespace('/foo') do
+ set :views, File.expand_path('../namespace/nested', __FILE__)
+ send(verb) { erb :foo }
+ end
+ end
+
+ if verb != :head
+ send(verb, '/').body.should == "hi\n"
+ send(verb, '/foo').body.should == "ho\n"
+ end
+ end
end
describe 'extensions' do
Please sign in to comment.
Something went wrong with that request. Please try again.