rubycut-sinatra-contrib 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.md +136 -0
- data/Rakefile +75 -0
- data/ideas.md +29 -0
- data/lib/sinatra/capture.rb +124 -0
- data/lib/sinatra/config_file.rb +167 -0
- data/lib/sinatra/content_for.rb +125 -0
- data/lib/sinatra/contrib.rb +39 -0
- data/lib/sinatra/contrib/all.rb +2 -0
- data/lib/sinatra/contrib/setup.rb +53 -0
- data/lib/sinatra/contrib/version.rb +17 -0
- data/lib/sinatra/cookies.rb +331 -0
- data/lib/sinatra/decompile.rb +120 -0
- data/lib/sinatra/engine_tracking.rb +96 -0
- data/lib/sinatra/extension.rb +95 -0
- data/lib/sinatra/json.rb +130 -0
- data/lib/sinatra/link_header.rb +132 -0
- data/lib/sinatra/multi_route.rb +87 -0
- data/lib/sinatra/namespace.rb +284 -0
- data/lib/sinatra/reloader.rb +394 -0
- data/lib/sinatra/respond_with.rb +249 -0
- data/lib/sinatra/streaming.rb +267 -0
- data/lib/sinatra/test_helpers.rb +87 -0
- data/sinatra-contrib.gemspec +127 -0
- data/spec/capture_spec.rb +93 -0
- data/spec/config_file/key_value.yml +6 -0
- data/spec/config_file/key_value.yml.erb +6 -0
- data/spec/config_file/key_value_override.yml +2 -0
- data/spec/config_file/missing_env.yml +4 -0
- data/spec/config_file/with_envs.yml +7 -0
- data/spec/config_file/with_nested_envs.yml +11 -0
- data/spec/config_file_spec.rb +63 -0
- data/spec/content_for/different_key.erb +1 -0
- data/spec/content_for/different_key.erubis +1 -0
- data/spec/content_for/different_key.haml +2 -0
- data/spec/content_for/different_key.slim +2 -0
- data/spec/content_for/layout.erb +1 -0
- data/spec/content_for/layout.erubis +1 -0
- data/spec/content_for/layout.haml +1 -0
- data/spec/content_for/layout.slim +1 -0
- data/spec/content_for/multiple_blocks.erb +4 -0
- data/spec/content_for/multiple_blocks.erubis +4 -0
- data/spec/content_for/multiple_blocks.haml +8 -0
- data/spec/content_for/multiple_blocks.slim +8 -0
- data/spec/content_for/multiple_yields.erb +3 -0
- data/spec/content_for/multiple_yields.erubis +3 -0
- data/spec/content_for/multiple_yields.haml +3 -0
- data/spec/content_for/multiple_yields.slim +3 -0
- data/spec/content_for/passes_values.erb +1 -0
- data/spec/content_for/passes_values.erubis +1 -0
- data/spec/content_for/passes_values.haml +1 -0
- data/spec/content_for/passes_values.slim +1 -0
- data/spec/content_for/same_key.erb +1 -0
- data/spec/content_for/same_key.erubis +1 -0
- data/spec/content_for/same_key.haml +2 -0
- data/spec/content_for/same_key.slim +2 -0
- data/spec/content_for/takes_values.erb +1 -0
- data/spec/content_for/takes_values.erubis +1 -0
- data/spec/content_for/takes_values.haml +3 -0
- data/spec/content_for/takes_values.slim +3 -0
- data/spec/content_for_spec.rb +213 -0
- data/spec/cookies_spec.rb +802 -0
- data/spec/decompile_spec.rb +44 -0
- data/spec/extension_spec.rb +33 -0
- data/spec/json_spec.rb +117 -0
- data/spec/link_header_spec.rb +100 -0
- data/spec/multi_route_spec.rb +60 -0
- data/spec/namespace/foo.erb +1 -0
- data/spec/namespace/nested/foo.erb +1 -0
- data/spec/namespace_spec.rb +676 -0
- data/spec/okjson.rb +581 -0
- data/spec/reloader/app.rb.erb +40 -0
- data/spec/reloader_spec.rb +441 -0
- data/spec/respond_with/bar.erb +1 -0
- data/spec/respond_with/bar.json.erb +1 -0
- data/spec/respond_with/foo.html.erb +1 -0
- data/spec/respond_with/not_html.sass +2 -0
- data/spec/respond_with_spec.rb +297 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/streaming_spec.rb +436 -0
- metadata +313 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'backports'
|
2
|
+
require_relative 'spec_helper'
|
3
|
+
|
4
|
+
RSpec::Matchers.define :decompile do |path|
|
5
|
+
match do |app|
|
6
|
+
@compiled, @keys = app.send :compile, path
|
7
|
+
@decompiled = app.decompile(@compiled, @keys)
|
8
|
+
@decompiled.should == path
|
9
|
+
end
|
10
|
+
|
11
|
+
failure_message_for_should do |app|
|
12
|
+
values = [app, @compiled, @keys, path, @decompiled].map(&:inspect)
|
13
|
+
"expected %s to decompile %s with %s to %s, but was %s" % values
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe Sinatra::Decompile do
|
18
|
+
subject { Sinatra::Application }
|
19
|
+
it { should decompile("") }
|
20
|
+
it { should decompile("/") }
|
21
|
+
it { should decompile("/?") }
|
22
|
+
it { should decompile("/foo") }
|
23
|
+
it { should decompile("/:name") }
|
24
|
+
it { should decompile("/:name?") }
|
25
|
+
it { should decompile("/:foo/:bar") }
|
26
|
+
it { should decompile("/page/:id/edit") }
|
27
|
+
it { should decompile("/hello/*") }
|
28
|
+
it { should decompile("/*/foo/*") }
|
29
|
+
it { should decompile("*") }
|
30
|
+
it { should decompile(":name.:format") }
|
31
|
+
it { should decompile("a b") }
|
32
|
+
it { should decompile("a+b") }
|
33
|
+
it { should decompile(/./) }
|
34
|
+
it { should decompile(/f(oo)/) }
|
35
|
+
it { should decompile(/ba+r/) }
|
36
|
+
|
37
|
+
it 'just returns strings' do
|
38
|
+
subject.decompile('/foo').should == '/foo'
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'just decompile simple regexps without keys' do
|
42
|
+
subject.decompile(%r{/foo}).should == '/foo'
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'backports'
|
2
|
+
require_relative 'spec_helper'
|
3
|
+
|
4
|
+
describe Sinatra::Extension do
|
5
|
+
module ExampleExtension
|
6
|
+
extend Sinatra::Extension
|
7
|
+
|
8
|
+
set :foo, :bar
|
9
|
+
settings.set :bar, :blah
|
10
|
+
|
11
|
+
configure :test, :production do
|
12
|
+
set :reload_stuff, false
|
13
|
+
end
|
14
|
+
|
15
|
+
configure :development do
|
16
|
+
set :reload_stuff, true
|
17
|
+
end
|
18
|
+
|
19
|
+
get '/' do
|
20
|
+
"from extension, yay"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
before { mock_app { register ExampleExtension }}
|
25
|
+
|
26
|
+
it('allows using set') { settings.foo.should == :bar }
|
27
|
+
it('implements configure') { settings.reload_stuff.should be_false }
|
28
|
+
|
29
|
+
it 'allows defing routes' do
|
30
|
+
get('/').should be_ok
|
31
|
+
body.should == "from extension, yay"
|
32
|
+
end
|
33
|
+
end
|
data/spec/json_spec.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'backports'
|
2
|
+
require 'multi_json'
|
3
|
+
|
4
|
+
require_relative 'spec_helper'
|
5
|
+
require_relative 'okjson'
|
6
|
+
|
7
|
+
shared_examples_for "a json encoder" do |lib, const|
|
8
|
+
before do
|
9
|
+
begin
|
10
|
+
require lib if lib
|
11
|
+
@encoder = eval(const)
|
12
|
+
rescue LoadError
|
13
|
+
pending "unable to load #{lib}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "allows setting :encoder to #{const}" do
|
18
|
+
enc = @encoder
|
19
|
+
mock_app { get('/') { json({'foo' => 'bar'}, :encoder => enc) }}
|
20
|
+
results_in 'foo' => 'bar'
|
21
|
+
end
|
22
|
+
|
23
|
+
it "allows setting settings.json_encoder to #{const}" do
|
24
|
+
enc = @encoder
|
25
|
+
mock_app do
|
26
|
+
set :json_encoder, enc
|
27
|
+
get('/') { json 'foo' => 'bar' }
|
28
|
+
end
|
29
|
+
results_in 'foo' => 'bar'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe Sinatra::JSON do
|
34
|
+
def mock_app(&block)
|
35
|
+
super do
|
36
|
+
helpers Sinatra::JSON
|
37
|
+
class_eval(&block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def results_in(obj)
|
42
|
+
OkJson.decode(get('/').body).should == obj
|
43
|
+
end
|
44
|
+
|
45
|
+
it "encodes objects to json out of the box" do
|
46
|
+
mock_app { get('/') { json :foo => [1, 'bar', nil] } }
|
47
|
+
results_in 'foo' => [1, 'bar', nil]
|
48
|
+
end
|
49
|
+
|
50
|
+
it "sets the content type to 'application/json'" do
|
51
|
+
mock_app { get('/') { json({}) } }
|
52
|
+
get('/')["Content-Type"].should include("application/json")
|
53
|
+
end
|
54
|
+
|
55
|
+
it "allows overriding content type with :content_type" do
|
56
|
+
mock_app { get('/') { json({}, :content_type => "foo/bar") } }
|
57
|
+
get('/')["Content-Type"].should == "foo/bar"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "accepts shorthands for :content_type" do
|
61
|
+
mock_app { get('/') { json({}, :content_type => :js) } }
|
62
|
+
get('/')["Content-Type"].should == "application/javascript;charset=utf-8"
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'calls generate on :encoder if available' do
|
66
|
+
enc = Object.new
|
67
|
+
def enc.generate(obj) obj.inspect end
|
68
|
+
mock_app { get('/') { json(42, :encoder => enc) }}
|
69
|
+
get('/').body.should == '42'
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'calls encode on :encoder if available' do
|
73
|
+
enc = Object.new
|
74
|
+
def enc.encode(obj) obj.inspect end
|
75
|
+
mock_app { get('/') { json(42, :encoder => enc) }}
|
76
|
+
get('/').body.should == '42'
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'sends :encoder as method call if it is a Symbol' do
|
80
|
+
mock_app { get('/') { json(42, :encoder => :inspect) }}
|
81
|
+
get('/').body.should == '42'
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'calls generate on settings.json_encoder if available' do
|
85
|
+
enc = Object.new
|
86
|
+
def enc.generate(obj) obj.inspect end
|
87
|
+
mock_app do
|
88
|
+
set :json_encoder, enc
|
89
|
+
get('/') { json 42 }
|
90
|
+
end
|
91
|
+
get('/').body.should == '42'
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'calls encode on settings.json_encode if available' do
|
95
|
+
enc = Object.new
|
96
|
+
def enc.encode(obj) obj.inspect end
|
97
|
+
mock_app do
|
98
|
+
set :json_encoder, enc
|
99
|
+
get('/') { json 42 }
|
100
|
+
end
|
101
|
+
get('/').body.should == '42'
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'sends settings.json_encode as method call if it is a Symbol' do
|
105
|
+
mock_app do
|
106
|
+
set :json_encoder, :inspect
|
107
|
+
get('/') { json 42 }
|
108
|
+
end
|
109
|
+
get('/').body.should == '42'
|
110
|
+
end
|
111
|
+
|
112
|
+
describe('Yajl') { it_should_behave_like "a json encoder", "yajl", "Yajl::Encoder" } unless defined? JRUBY_VERSION
|
113
|
+
describe('JSON') { it_should_behave_like "a json encoder", "json", "::JSON" }
|
114
|
+
describe('OkJson') { it_should_behave_like "a json encoder", nil, "OkJson" }
|
115
|
+
describe('to_json') { it_should_behave_like "a json encoder", "json", ":to_json" }
|
116
|
+
describe('without') { it_should_behave_like "a json encoder", nil, "Sinatra::JSON" }
|
117
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'backports'
|
2
|
+
require_relative 'spec_helper'
|
3
|
+
|
4
|
+
describe Sinatra::LinkHeader do
|
5
|
+
before do
|
6
|
+
mock_app do
|
7
|
+
helpers Sinatra::LinkHeader
|
8
|
+
before('/') { link 'something', :rel => 'from-filter', :foo => :bar }
|
9
|
+
|
10
|
+
get '/' do
|
11
|
+
link :something, 'booyah'
|
12
|
+
end
|
13
|
+
|
14
|
+
get '/style' do
|
15
|
+
stylesheet '/style.css'
|
16
|
+
end
|
17
|
+
|
18
|
+
get '/prefetch' do
|
19
|
+
prefetch '/foo'
|
20
|
+
end
|
21
|
+
|
22
|
+
get '/link_headers' do
|
23
|
+
response['Link'] = "<foo> ;bar=\"baz\""
|
24
|
+
stylesheet '/style.css'
|
25
|
+
prefetch '/foo'
|
26
|
+
link_headers
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe :link do
|
32
|
+
it "sets link headers" do
|
33
|
+
get '/'
|
34
|
+
headers['Link'].lines.should include('<booyah>; rel="something"')
|
35
|
+
end
|
36
|
+
|
37
|
+
it "returns link html tags" do
|
38
|
+
get '/'
|
39
|
+
body.should == '<link href="booyah" rel="something" />'
|
40
|
+
end
|
41
|
+
|
42
|
+
it "takes an options hash" do
|
43
|
+
get '/'
|
44
|
+
elements = ["<something>", "foo=\"bar\"", "rel=\"from-filter\""]
|
45
|
+
headers['Link'].lines.first.strip.split('; ').sort.should == elements
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe :stylesheet do
|
50
|
+
it 'sets link headers' do
|
51
|
+
get '/style'
|
52
|
+
headers['Link'].should match(%r{^</style\.css>;})
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'sets type to text/css' do
|
56
|
+
get '/style'
|
57
|
+
headers['Link'].should include('type="text/css"')
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'sets rel to stylesheet' do
|
61
|
+
get '/style'
|
62
|
+
headers['Link'].should include('rel="stylesheet"')
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns html tag' do
|
66
|
+
get '/style'
|
67
|
+
body.should match(%r{^<link href="/style\.css"})
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe :prefetch do
|
72
|
+
it 'sets link headers' do
|
73
|
+
get '/prefetch'
|
74
|
+
headers['Link'].should match(%r{^</foo>;})
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'sets rel to prefetch' do
|
78
|
+
get '/prefetch'
|
79
|
+
headers['Link'].should include('rel="prefetch"')
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'returns html tag' do
|
83
|
+
get '/prefetch'
|
84
|
+
body.should == '<link href="/foo" rel="prefetch" />'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe :link_headers do
|
89
|
+
it 'generates html for all link headers' do
|
90
|
+
get '/link_headers'
|
91
|
+
body.should include('<link href="/foo" rel="prefetch" />')
|
92
|
+
body.should include('<link href="/style.css" ')
|
93
|
+
end
|
94
|
+
|
95
|
+
it "respects Link headers not generated on its own" do
|
96
|
+
get '/link_headers'
|
97
|
+
body.should include('<link href="foo" bar="baz" />')
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'backports'
|
2
|
+
require_relative 'spec_helper'
|
3
|
+
|
4
|
+
describe Sinatra::MultiRoute do
|
5
|
+
|
6
|
+
it 'does not break normal routing' do
|
7
|
+
mock_app do
|
8
|
+
register Sinatra::MultiRoute
|
9
|
+
get('/') { 'normal' }
|
10
|
+
end
|
11
|
+
|
12
|
+
get('/').should be_ok
|
13
|
+
body.should be == 'normal'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'supports multiple routes' do
|
17
|
+
mock_app do
|
18
|
+
register Sinatra::MultiRoute
|
19
|
+
get('/foo', '/bar') { 'paths' }
|
20
|
+
end
|
21
|
+
|
22
|
+
get('/foo').should be_ok
|
23
|
+
body.should be == 'paths'
|
24
|
+
get('/bar').should be_ok
|
25
|
+
body.should be == 'paths'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'triggers conditions' do
|
29
|
+
count = 0
|
30
|
+
mock_app do
|
31
|
+
register Sinatra::MultiRoute
|
32
|
+
set(:some_condition) { |_| count += 1 }
|
33
|
+
get('/foo', '/bar', :some_condition => true) { 'paths' }
|
34
|
+
end
|
35
|
+
|
36
|
+
count.should be == 4
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'supports multiple verbs' do
|
40
|
+
mock_app do
|
41
|
+
register Sinatra::MultiRoute
|
42
|
+
route('PUT', 'POST', '/') { 'verb' }
|
43
|
+
end
|
44
|
+
|
45
|
+
post('/').should be_ok
|
46
|
+
body.should be == 'verb'
|
47
|
+
put('/').should be_ok
|
48
|
+
body.should be == 'verb'
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'takes symbols as verbs' do
|
52
|
+
mock_app do
|
53
|
+
register Sinatra::MultiRoute
|
54
|
+
route(:get, '/baz') { 'symbol as verb' }
|
55
|
+
end
|
56
|
+
|
57
|
+
get('/baz').should be_ok
|
58
|
+
body.should be == 'symbol as verb'
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
hi
|
@@ -0,0 +1 @@
|
|
1
|
+
ho
|
@@ -0,0 +1,676 @@
|
|
1
|
+
require 'backports'
|
2
|
+
require_relative 'spec_helper'
|
3
|
+
|
4
|
+
describe Sinatra::Namespace do
|
5
|
+
verbs = [:get, :head, :post, :put, :delete, :options]
|
6
|
+
verbs << :patch if Sinatra::VERSION >= '1.3'
|
7
|
+
|
8
|
+
def mock_app(&block)
|
9
|
+
super do
|
10
|
+
register Sinatra::Namespace
|
11
|
+
class_eval(&block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def namespace(*args, &block)
|
16
|
+
mock_app { namespace(*args, &block) }
|
17
|
+
end
|
18
|
+
|
19
|
+
verbs.each do |verb|
|
20
|
+
describe "HTTP #{verb.to_s.upcase}" do
|
21
|
+
|
22
|
+
it 'prefixes the path with the namespace' do
|
23
|
+
namespace('/foo') { send(verb, '/bar') { 'baz' }}
|
24
|
+
send(verb, '/foo/bar').should be_ok
|
25
|
+
body.should == 'baz' unless verb == :head
|
26
|
+
send(verb, '/foo/baz').should_not be_ok
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when namespace is a string' do
|
30
|
+
it 'accepts routes with no path' do
|
31
|
+
namespace('/foo') { send(verb) { 'bar' } }
|
32
|
+
send(verb, '/foo').should be_ok
|
33
|
+
body.should == 'bar' unless verb == :head
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'accepts the path as a named parameter' do
|
37
|
+
namespace('/foo') { send(verb, '/:bar') { params[:bar] }}
|
38
|
+
send(verb, '/foo/bar').should be_ok
|
39
|
+
body.should == 'bar' unless verb == :head
|
40
|
+
send(verb, '/foo/baz').should be_ok
|
41
|
+
body.should == 'baz' unless verb == :head
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'accepts the path as a regular expression' do
|
45
|
+
namespace('/foo') { send(verb, /\/\d\d/) { 'bar' }}
|
46
|
+
send(verb, '/foo/12').should be_ok
|
47
|
+
body.should == 'bar' unless verb == :head
|
48
|
+
send(verb, '/foo/123').should_not be_ok
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when namespace is a named parameter' do
|
53
|
+
it 'accepts routes with no path' do
|
54
|
+
namespace('/:foo') { send(verb) { 'bar' } }
|
55
|
+
send(verb, '/foo').should be_ok
|
56
|
+
body.should == 'bar' unless verb == :head
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'sets the parameter correctly' do
|
60
|
+
namespace('/:foo') { send(verb, '/bar') { params[:foo] }}
|
61
|
+
send(verb, '/foo/bar').should be_ok
|
62
|
+
body.should == 'foo' unless verb == :head
|
63
|
+
send(verb, '/fox/bar').should be_ok
|
64
|
+
body.should == 'fox' unless verb == :head
|
65
|
+
send(verb, '/foo/baz').should_not be_ok
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'accepts the path as a named parameter' do
|
69
|
+
namespace('/:foo') { send(verb, '/:bar') { params[:bar] }}
|
70
|
+
send(verb, '/foo/bar').should be_ok
|
71
|
+
body.should == 'bar' unless verb == :head
|
72
|
+
send(verb, '/foo/baz').should be_ok
|
73
|
+
body.should == 'baz' unless verb == :head
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'accepts the path as regular expression' do
|
77
|
+
namespace('/:foo') { send(verb, %r{/bar}) { params[:foo] }}
|
78
|
+
send(verb, '/foo/bar').should be_ok
|
79
|
+
body.should == 'foo' unless verb == :head
|
80
|
+
send(verb, '/fox/bar').should be_ok
|
81
|
+
body.should == 'fox' unless verb == :head
|
82
|
+
send(verb, '/foo/baz').should_not be_ok
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when namespace is a regular expression' do
|
87
|
+
it 'accepts routes with no path' do
|
88
|
+
namespace(%r{/foo}) { send(verb) { 'bar' } }
|
89
|
+
send(verb, '/foo').should be_ok
|
90
|
+
body.should == 'bar' unless verb == :head
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'accepts the path as a named parameter' do
|
94
|
+
namespace(%r{/foo}) { send(verb, '/:bar') { params[:bar] }}
|
95
|
+
send(verb, '/foo/bar').should be_ok
|
96
|
+
body.should == 'bar' unless verb == :head
|
97
|
+
send(verb, '/foo/baz').should be_ok
|
98
|
+
body.should == 'baz' unless verb == :head
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'accepts the path as a regular expression' do
|
102
|
+
namespace(/\/\d\d/) { send(verb, /\/\d\d/) { 'foo' }}
|
103
|
+
send(verb, '/23/12').should be_ok
|
104
|
+
body.should == 'foo' unless verb == :head
|
105
|
+
send(verb, '/123/12').should_not be_ok
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'when namespace is a splat' do
|
110
|
+
it 'accepts the path as a splat' do
|
111
|
+
namespace('/*') { send(verb, '/*') { params[:splat].join ' - ' }}
|
112
|
+
send(verb, '/foo/bar').should be_ok
|
113
|
+
body.should == 'foo - bar' unless verb == :head
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe 'before-filters' do
|
118
|
+
specify 'are triggered' do
|
119
|
+
ran = false
|
120
|
+
namespace('/foo') { before { ran = true }}
|
121
|
+
send(verb, '/foo')
|
122
|
+
ran.should be_true
|
123
|
+
end
|
124
|
+
|
125
|
+
specify 'are not triggered for a different namespace' do
|
126
|
+
ran = false
|
127
|
+
namespace('/foo') { before { ran = true }}
|
128
|
+
send(verb, '/fox')
|
129
|
+
ran.should be_false
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe 'after-filters' do
|
134
|
+
specify 'are triggered' do
|
135
|
+
ran = false
|
136
|
+
namespace('/foo') { after { ran = true }}
|
137
|
+
send(verb, '/foo')
|
138
|
+
ran.should be_true
|
139
|
+
end
|
140
|
+
|
141
|
+
specify 'are not triggered for a different namespace' do
|
142
|
+
ran = false
|
143
|
+
namespace('/foo') { after { ran = true }}
|
144
|
+
send(verb, '/fox')
|
145
|
+
ran.should be_false
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe 'conditions' do
|
150
|
+
context 'when the namespace has no prefix' do
|
151
|
+
specify 'are accepted in the namespace' do
|
152
|
+
mock_app do
|
153
|
+
namespace(:host_name => 'example.com') { send(verb) { 'yes' }}
|
154
|
+
send(verb, '/') { 'no' }
|
155
|
+
end
|
156
|
+
send(verb, '/', {}, 'HTTP_HOST' => 'example.com')
|
157
|
+
last_response.should be_ok
|
158
|
+
body.should == 'yes' unless verb == :head
|
159
|
+
send(verb, '/', {}, 'HTTP_HOST' => 'example.org')
|
160
|
+
last_response.should be_ok
|
161
|
+
body.should == 'no' unless verb == :head
|
162
|
+
end
|
163
|
+
|
164
|
+
specify 'are accepted in the route definition' do
|
165
|
+
namespace :host_name => 'example.com' do
|
166
|
+
send(verb, '/foo', :provides => :txt) { 'ok' }
|
167
|
+
end
|
168
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain').should be_ok
|
169
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/html').should_not be_ok
|
170
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org', 'HTTP_ACCEPT' => 'text/plain').should_not be_ok
|
171
|
+
end
|
172
|
+
|
173
|
+
specify 'are accepted in the before-filter' do
|
174
|
+
ran = false
|
175
|
+
namespace :provides => :txt do
|
176
|
+
before('/foo', :host_name => 'example.com') { ran = true }
|
177
|
+
send(verb, '/*') { 'ok' }
|
178
|
+
end
|
179
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org', 'HTTP_ACCEPT' => 'text/plain')
|
180
|
+
ran.should be_false
|
181
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/html')
|
182
|
+
ran.should be_false
|
183
|
+
send(verb, '/bar', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain')
|
184
|
+
ran.should be_false
|
185
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain')
|
186
|
+
ran.should be_true
|
187
|
+
end
|
188
|
+
|
189
|
+
specify 'are accepted in the after-filter' do
|
190
|
+
ran = false
|
191
|
+
namespace :provides => :txt do
|
192
|
+
after('/foo', :host_name => 'example.com') { ran = true }
|
193
|
+
send(verb, '/*') { 'ok' }
|
194
|
+
end
|
195
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org', 'HTTP_ACCEPT' => 'text/plain')
|
196
|
+
ran.should be_false
|
197
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/html')
|
198
|
+
ran.should be_false
|
199
|
+
send(verb, '/bar', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain')
|
200
|
+
ran.should be_false
|
201
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain')
|
202
|
+
ran.should be_true
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'when the namespace is a string' do
|
207
|
+
specify 'are accepted in the namespace' do
|
208
|
+
namespace '/foo', :host_name => 'example.com' do
|
209
|
+
send(verb) { 'ok' }
|
210
|
+
end
|
211
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com').should be_ok
|
212
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org').should_not be_ok
|
213
|
+
end
|
214
|
+
|
215
|
+
specify 'are accepted in the before-filter' do
|
216
|
+
namespace '/foo' do
|
217
|
+
before(:host_name => 'example.com') { @yes = 'yes' }
|
218
|
+
send(verb) { @yes || 'no' }
|
219
|
+
end
|
220
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com')
|
221
|
+
last_response.should be_ok
|
222
|
+
body.should == 'yes' unless verb == :head
|
223
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org')
|
224
|
+
last_response.should be_ok
|
225
|
+
body.should == 'no' unless verb == :head
|
226
|
+
end
|
227
|
+
|
228
|
+
specify 'are accepted in the after-filter' do
|
229
|
+
ran = false
|
230
|
+
namespace '/foo' do
|
231
|
+
before(:host_name => 'example.com') { ran = true }
|
232
|
+
send(verb) { 'ok' }
|
233
|
+
end
|
234
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org')
|
235
|
+
ran.should be_false
|
236
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com')
|
237
|
+
ran.should be_true
|
238
|
+
end
|
239
|
+
|
240
|
+
specify 'are accepted in the route definition' do
|
241
|
+
namespace '/foo' do
|
242
|
+
send(verb, :host_name => 'example.com') { 'ok' }
|
243
|
+
end
|
244
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com').should be_ok
|
245
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org').should_not be_ok
|
246
|
+
end
|
247
|
+
|
248
|
+
context 'when the namespace has a condition' do
|
249
|
+
specify 'are accepted in the before-filter' do
|
250
|
+
ran = false
|
251
|
+
namespace '/', :provides => :txt do
|
252
|
+
before(:host_name => 'example.com') { ran = true }
|
253
|
+
send(verb) { 'ok' }
|
254
|
+
end
|
255
|
+
send(verb, '/', {}, 'HTTP_HOST' => 'example.org', 'HTTP_ACCEPT' => 'text/plain')
|
256
|
+
ran.should be_false
|
257
|
+
send(verb, '/', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/html')
|
258
|
+
ran.should be_false
|
259
|
+
send(verb, '/', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain')
|
260
|
+
ran.should be_true
|
261
|
+
end
|
262
|
+
|
263
|
+
specify 'are accepted in the filters' do
|
264
|
+
ran = false
|
265
|
+
namespace '/f', :provides => :txt do
|
266
|
+
before('oo', :host_name => 'example.com') { ran = true }
|
267
|
+
send(verb, '/*') { 'ok' }
|
268
|
+
end
|
269
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.org', 'HTTP_ACCEPT' => 'text/plain')
|
270
|
+
ran.should be_false
|
271
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/html')
|
272
|
+
ran.should be_false
|
273
|
+
send(verb, '/far', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain')
|
274
|
+
ran.should be_false
|
275
|
+
send(verb, '/foo', {}, 'HTTP_HOST' => 'example.com', 'HTTP_ACCEPT' => 'text/plain')
|
276
|
+
ran.should be_true
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
describe 'helpers' do
|
283
|
+
it 'are defined using the helpers method' do
|
284
|
+
namespace '/foo' do
|
285
|
+
helpers do
|
286
|
+
def magic
|
287
|
+
42
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
send verb, '/bar' do
|
292
|
+
magic.to_s
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
send(verb, '/foo/bar').should be_ok
|
297
|
+
body.should == '42' unless verb == :head
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'can be defined as normal methods' do
|
301
|
+
namespace '/foo' do
|
302
|
+
def magic
|
303
|
+
42
|
304
|
+
end
|
305
|
+
|
306
|
+
send verb, '/bar' do
|
307
|
+
magic.to_s
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
send(verb, '/foo/bar').should be_ok
|
312
|
+
body.should == '42' unless verb == :head
|
313
|
+
end
|
314
|
+
|
315
|
+
it 'can be defined using module mixins' do
|
316
|
+
mixin = Module.new do
|
317
|
+
def magic
|
318
|
+
42
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
namespace '/foo' do
|
323
|
+
helpers mixin
|
324
|
+
send verb, '/bar' do
|
325
|
+
magic.to_s
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
send(verb, '/foo/bar').should be_ok
|
330
|
+
body.should == '42' unless verb == :head
|
331
|
+
end
|
332
|
+
|
333
|
+
specify 'are unavailable outside the namespace where they are defined' do
|
334
|
+
mock_app do
|
335
|
+
namespace '/foo' do
|
336
|
+
def magic
|
337
|
+
42
|
338
|
+
end
|
339
|
+
|
340
|
+
send verb, '/bar' do
|
341
|
+
magic.to_s
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
send verb, '/' do
|
346
|
+
magic.to_s
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
proc { send verb, '/' }.should raise_error(NameError)
|
351
|
+
end
|
352
|
+
|
353
|
+
specify 'are unavailable outside the namespace that they are mixed into' do
|
354
|
+
mixin = Module.new do
|
355
|
+
def magic
|
356
|
+
42
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
mock_app do
|
361
|
+
namespace '/foo' do
|
362
|
+
helpers mixin
|
363
|
+
send verb, '/bar' do
|
364
|
+
magic.to_s
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
send verb, '/' do
|
369
|
+
magic.to_s
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
proc { send verb, '/' }.should raise_error(NameError)
|
374
|
+
end
|
375
|
+
|
376
|
+
specify 'are available to nested namespaces' do
|
377
|
+
mock_app do
|
378
|
+
helpers do
|
379
|
+
def magic
|
380
|
+
42
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
namespace '/foo' do
|
385
|
+
send verb, '/bar' do
|
386
|
+
magic.to_s
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
send(verb, '/foo/bar').should be_ok
|
392
|
+
body.should == '42' unless verb == :head
|
393
|
+
end
|
394
|
+
|
395
|
+
specify 'can call super from nested definitions' do
|
396
|
+
mock_app do
|
397
|
+
helpers do
|
398
|
+
def magic
|
399
|
+
42
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
namespace '/foo' do
|
404
|
+
def magic
|
405
|
+
super - 19
|
406
|
+
end
|
407
|
+
|
408
|
+
send verb, '/bar' do
|
409
|
+
magic.to_s
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
send(verb, '/foo/bar').should be_ok
|
415
|
+
body.should == '23' unless verb == :head
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
describe 'nesting' do
|
420
|
+
it 'routes to nested namespaces' do
|
421
|
+
namespace '/foo' do
|
422
|
+
namespace '/bar' do
|
423
|
+
send(verb, '/baz') { 'OKAY!!11!'}
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
send(verb, '/foo/bar/baz').should be_ok
|
428
|
+
body.should == 'OKAY!!11!' unless verb == :head
|
429
|
+
end
|
430
|
+
|
431
|
+
it 'exposes helpers to nested namespaces' do
|
432
|
+
namespace '/foo' do
|
433
|
+
helpers do
|
434
|
+
def magic
|
435
|
+
42
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
namespace '/bar' do
|
440
|
+
send verb, '/baz' do
|
441
|
+
magic.to_s
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
send(verb, '/foo/bar/baz').should be_ok
|
447
|
+
body.should == '42' unless verb == :head
|
448
|
+
end
|
449
|
+
|
450
|
+
specify 'does not provide access to nested helper methods' do
|
451
|
+
namespace '/foo' do
|
452
|
+
namespace '/bar' do
|
453
|
+
def magic
|
454
|
+
42
|
455
|
+
end
|
456
|
+
|
457
|
+
send verb, '/baz' do
|
458
|
+
magic.to_s
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
send verb do
|
463
|
+
magic.to_s
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
proc { send verb, '/foo' }.should raise_error(NameError)
|
468
|
+
end
|
469
|
+
|
470
|
+
it 'accepts a nested namespace as a named parameter' do
|
471
|
+
namespace('/:a') { namespace('/:b') { send(verb) { params[:a] }}}
|
472
|
+
send(verb, '/foo/bar').should be_ok
|
473
|
+
body.should == 'foo' unless verb == :head
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
describe 'error handling' do
|
478
|
+
it 'can be customized using the not_found block' do
|
479
|
+
namespace('/de') do
|
480
|
+
not_found { 'nicht gefunden' }
|
481
|
+
end
|
482
|
+
send(verb, '/foo').status.should == 404
|
483
|
+
last_response.body.should_not == 'nicht gefunden' unless verb == :head
|
484
|
+
get('/en/foo').status.should == 404
|
485
|
+
last_response.body.should_not == 'nicht gefunden' unless verb == :head
|
486
|
+
get('/de/foo').status.should == 404
|
487
|
+
last_response.body.should == 'nicht gefunden' unless verb == :head
|
488
|
+
end
|
489
|
+
|
490
|
+
it 'can be customized for specific error codes' do
|
491
|
+
namespace('/de') do
|
492
|
+
error(404) { 'nicht gefunden' }
|
493
|
+
end
|
494
|
+
send(verb, '/foo').status.should == 404
|
495
|
+
last_response.body.should_not == 'nicht gefunden' unless verb == :head
|
496
|
+
get('/en/foo').status.should == 404
|
497
|
+
last_response.body.should_not == 'nicht gefunden' unless verb == :head
|
498
|
+
get('/de/foo').status.should == 404
|
499
|
+
last_response.body.should == 'nicht gefunden' unless verb == :head
|
500
|
+
end
|
501
|
+
|
502
|
+
it 'falls back to the handler defined in the base app' do
|
503
|
+
mock_app do
|
504
|
+
error(404) { 'not found...' }
|
505
|
+
namespace('/en') do
|
506
|
+
end
|
507
|
+
namespace('/de') do
|
508
|
+
error(404) { 'nicht gefunden' }
|
509
|
+
end
|
510
|
+
end
|
511
|
+
send(verb, '/foo').status.should == 404
|
512
|
+
last_response.body.should == 'not found...' unless verb == :head
|
513
|
+
get('/en/foo').status.should == 404
|
514
|
+
last_response.body.should == 'not found...' unless verb == :head
|
515
|
+
get('/de/foo').status.should == 404
|
516
|
+
last_response.body.should == 'nicht gefunden' unless verb == :head
|
517
|
+
end
|
518
|
+
|
519
|
+
it 'can be customized for specific Exception classes' do
|
520
|
+
mock_app do
|
521
|
+
class AError < StandardError; end
|
522
|
+
class BError < AError; end
|
523
|
+
|
524
|
+
error(AError) do
|
525
|
+
body('auth failed')
|
526
|
+
401
|
527
|
+
end
|
528
|
+
|
529
|
+
namespace('/en') do
|
530
|
+
get '/foo' do
|
531
|
+
raise BError
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
namespace('/de') do
|
536
|
+
error(AError) do
|
537
|
+
body('methode nicht erlaubt')
|
538
|
+
406
|
539
|
+
end
|
540
|
+
|
541
|
+
get '/foo' do
|
542
|
+
raise BError
|
543
|
+
end
|
544
|
+
end
|
545
|
+
end
|
546
|
+
get('/en/foo').status.should == 401
|
547
|
+
last_response.body.should == 'auth failed' unless verb == :head
|
548
|
+
get('/de/foo').status.should == 406
|
549
|
+
last_response.body.should == 'methode nicht erlaubt' unless verb == :head
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
unless verb == :head
|
554
|
+
describe 'templates' do
|
555
|
+
specify 'default to the base app\'s template' do
|
556
|
+
mock_app do
|
557
|
+
template(:foo) { 'hi' }
|
558
|
+
send(verb, '/') { erb :foo }
|
559
|
+
namespace '/foo' do
|
560
|
+
send(verb) { erb :foo }
|
561
|
+
end
|
562
|
+
end
|
563
|
+
|
564
|
+
send(verb, '/').body.should == 'hi'
|
565
|
+
send(verb, '/foo').body.should == 'hi'
|
566
|
+
end
|
567
|
+
|
568
|
+
specify 'can be nested' do
|
569
|
+
mock_app do
|
570
|
+
template(:foo) { 'hi' }
|
571
|
+
send(verb, '/') { erb :foo }
|
572
|
+
namespace '/foo' do
|
573
|
+
template(:foo) { 'ho' }
|
574
|
+
send(verb) { erb :foo }
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
send(verb, '/').body.should == 'hi'
|
579
|
+
send(verb, '/foo').body.should == 'ho'
|
580
|
+
end
|
581
|
+
|
582
|
+
specify 'can use a custom views directory' do
|
583
|
+
mock_app do
|
584
|
+
set :views, File.expand_path('../namespace', __FILE__)
|
585
|
+
send(verb, '/') { erb :foo }
|
586
|
+
namespace('/foo') do
|
587
|
+
set :views, File.expand_path('../namespace/nested', __FILE__)
|
588
|
+
send(verb) { erb :foo }
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
send(verb, '/').body.should == "hi\n"
|
593
|
+
send(verb, '/foo').body.should == "ho\n"
|
594
|
+
end
|
595
|
+
|
596
|
+
specify 'default to the base app\'s layout' do
|
597
|
+
mock_app do
|
598
|
+
layout { 'he said: <%= yield %>' }
|
599
|
+
template(:foo) { 'hi' }
|
600
|
+
send(verb, '/') { erb :foo }
|
601
|
+
namespace '/foo' do
|
602
|
+
template(:foo) { 'ho' }
|
603
|
+
send(verb) { erb :foo }
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
send(verb, '/').body.should == 'he said: hi'
|
608
|
+
send(verb, '/foo').body.should == 'he said: ho'
|
609
|
+
end
|
610
|
+
|
611
|
+
specify 'can define nested layouts' do
|
612
|
+
mock_app do
|
613
|
+
layout { 'Hello <%= yield %>!' }
|
614
|
+
template(:foo) { 'World' }
|
615
|
+
send(verb, '/') { erb :foo }
|
616
|
+
namespace '/foo' do
|
617
|
+
layout { 'Hi <%= yield %>!' }
|
618
|
+
send(verb) { erb :foo }
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
send(verb, '/').body.should == 'Hello World!'
|
623
|
+
send(verb, '/foo').body.should == 'Hi World!'
|
624
|
+
end
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
describe 'extensions' do
|
629
|
+
specify 'provide read access to settings' do
|
630
|
+
value = nil
|
631
|
+
mock_app do
|
632
|
+
set :foo, 42
|
633
|
+
namespace '/foo' do
|
634
|
+
value = foo
|
635
|
+
end
|
636
|
+
end
|
637
|
+
value.should == 42
|
638
|
+
end
|
639
|
+
|
640
|
+
specify 'can be registered within a namespace' do
|
641
|
+
a = b = nil
|
642
|
+
extension = Module.new { define_method(:views) { 'CUSTOM!!!' } }
|
643
|
+
mock_app do
|
644
|
+
namespace '/' do
|
645
|
+
register extension
|
646
|
+
a = views
|
647
|
+
end
|
648
|
+
b = views
|
649
|
+
end
|
650
|
+
a.should == 'CUSTOM!!!'
|
651
|
+
b.should_not == 'CUSTOM!!!'
|
652
|
+
end
|
653
|
+
|
654
|
+
specify 'trigger the route_added hook' do
|
655
|
+
route = nil
|
656
|
+
extension = Module.new
|
657
|
+
extension.singleton_class.class_eval do
|
658
|
+
define_method(:route_added) { |*r| route = r }
|
659
|
+
end
|
660
|
+
mock_app do
|
661
|
+
namespace '/f' do
|
662
|
+
register extension
|
663
|
+
get('oo') { }
|
664
|
+
end
|
665
|
+
get('/bar') { }
|
666
|
+
end
|
667
|
+
route[1].should == '/foo'
|
668
|
+
end
|
669
|
+
|
670
|
+
specify 'prevent app-global settings from being changed' do
|
671
|
+
proc { namespace('/') { set :foo, :bar }}.should raise_error
|
672
|
+
end
|
673
|
+
end
|
674
|
+
end
|
675
|
+
end
|
676
|
+
end
|