sinatra-namespace 0.4.1 → 0.5.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/README.md CHANGED
@@ -34,6 +34,16 @@ Classic style:
34
34
  end
35
35
 
36
36
  namspace "/ruby" do
37
+ before { @an_important_note = "filters work, too" }
38
+
39
+ after do
40
+ @an_important_note = nil # don't tell
41
+ end
42
+
43
+ not_found do
44
+ "ruby does not know this ditty"
45
+ end
46
+
37
47
  helpers do
38
48
  def posts
39
49
  super.where :topic => "ruby"
@@ -108,7 +118,7 @@ So, how does one create a namespace from a module without that auto detection? S
108
118
  Installation
109
119
  ------------
110
120
 
111
- gem install sinatra-namespace --prerelease
121
+ gem install sinatra-namespace
112
122
 
113
123
  Alternatives
114
124
  ------------
@@ -119,7 +129,7 @@ If that is no what you are looking for, you have two alternative directions.
119
129
  Simple prefixing, shares all state/helpers:
120
130
 
121
131
  require "sinatra/base"
122
- require "monkey"
132
+ require "monkey-lib"
123
133
 
124
134
  admin_prefix = "/this/is/the/admin/prefix"
125
135
  get(admin_prefix) { haml :admin_index }
@@ -1,13 +1,17 @@
1
- require "monkey"
1
+ require "monkey-lib"
2
2
  require "sinatra/base"
3
3
  require "sinatra/sugar"
4
4
  require "sinatra/advanced_routes"
5
5
 
6
6
  module Sinatra
7
7
  module Namespace
8
- DONT_FORWARD = %w[after before call configure disable enable error new not_found register reset! run! set use]
8
+ DONT_FORWARD = %w[call configure disable enable new register reset! run! set use template]
9
9
 
10
10
  module NestedMethods
11
+ def errors
12
+ @errors ||= {}
13
+ end
14
+
11
15
  def prefix(value = nil)
12
16
  @prefix = value if value
13
17
  @prefix
@@ -29,6 +33,14 @@ module Sinatra
29
33
  def delete(name = nil, options = {}, &block); prefixed(:delete, name, options, &block); end
30
34
  def head(name = nil, options = {}, &block); prefixed(:head, name, options, &block); end
31
35
 
36
+ def error(codes=Exception, &block)
37
+ [*codes].each { |c| errors[c] = block }
38
+ end
39
+
40
+ def not_found(&block)
41
+ error(404, &block)
42
+ end
43
+
32
44
  def respond_to?(name)
33
45
  super or (base.respond_to? name and forward? name)
34
46
  end
@@ -37,8 +49,28 @@ module Sinatra
37
49
  (super + base.methods(*args).select { |m| forward? m }).uniq
38
50
  end
39
51
 
52
+ def before_filters
53
+ @before_filters ||= []
54
+ end
55
+
56
+ def after_filters
57
+ @after_filters ||= []
58
+ end
59
+
60
+ def before(&block)
61
+ before_filters << block
62
+ end
63
+
64
+ def after(&block)
65
+ after_filters << block
66
+ end
67
+
40
68
  private
41
69
 
70
+ def always_activate
71
+ get(/.*/) { pass }
72
+ end
73
+
42
74
  def application
43
75
  klass = self
44
76
  klass = klass.base while klass.respond_to? :base
@@ -63,8 +95,22 @@ module Sinatra
63
95
  base.send(verb, path, options, &wrapper)
64
96
  end
65
97
 
66
- def wrap(unbound_method, app, *args)
98
+ def prepare_instance(app)
99
+ return if app.is_a? self
100
+ base.prepare_instance app if base.respond_to? :prepare_instance
101
+ class << app
102
+ @filters ||= {}
103
+ @filters[:after] ||= []
104
+ @after_filters ||= []
105
+ end
106
+ before_filters.each { |block| app.instance_eval(&block) }
107
+ after_filters.each { |block| app.singleton_class.after(&block) }
67
108
  app.extend self
109
+ end
110
+
111
+ def wrap(unbound_method, app, *args)
112
+ prepare_instance app
113
+ app.current_namespace = self
68
114
  unbound_method.bind(app).call(*args)
69
115
  end
70
116
 
@@ -82,7 +128,8 @@ module Sinatra
82
128
 
83
129
  def self.registered(klass)
84
130
  klass.register Sinatra::Sugar
85
- klass.set :merge_namespaces => false, :auto_namespace => true
131
+ klass.__send__ :include, InstanceMethods
132
+ klass.enable :merge_namespaces, :auto_namespace, :always_activate_namespaces
86
133
  end
87
134
 
88
135
  def self.make_namespace(mod, options = {})
@@ -96,9 +143,44 @@ module Sinatra
96
143
  mod.extend self
97
144
  mod.extend NestedMethods
98
145
  options.each { |k,v| mod.send(k, v) }
146
+ mod.send(:always_activate) if options[:base].always_activate_namespaces?
99
147
  mod
100
148
  end
101
149
 
150
+ module InstanceMethods
151
+ attr_accessor :current_namespace
152
+
153
+ if Sinatra::VERSION > '1.0' or Sinatra::Base.respond_to? :filters # master is still 1.0
154
+ def filter!(type, base = self.class)
155
+ super
156
+ if type == :after and base == self.class and singleton_class.filters and singleton_class.after_filters
157
+ singleton_class.after_filters.each { |b| instance_eval(&b) }
158
+ end
159
+ end
160
+ else
161
+ def after_filter!(base = self.class)
162
+ super
163
+ if base == self.class and singleton_class.after_filters
164
+ singleton_class.after_filters.each { |b| instance_eval(&b) }
165
+ end
166
+ end
167
+ end
168
+
169
+ def error_block!(*keys)
170
+ keys.detect do |key|
171
+ base = current_namespace || self.class
172
+ while base.respond_to? :errors
173
+ if block = base.errors[key]
174
+ # found a handler, eval and return result
175
+ return instance_eval(&block)
176
+ else
177
+ base = base.respond_to?(:base) ? base.base : base.superclass
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+
102
184
  def make_namespace(mod, options = {})
103
185
  Sinatra::Namespace.make_namespace mod, options.merge(:base => self)
104
186
  end
@@ -108,6 +190,7 @@ module Sinatra
108
190
  @namespaces ||= {}
109
191
  @namespaces[prefix] ||= namespace prefix, false
110
192
  @namespaces[prefix].class_eval(&block) if block
193
+ @namespaces[prefix]
111
194
  else
112
195
  mod = make_namespace Module.new, :prefix => prefix
113
196
  mod.class_eval(&block) if block
@@ -1,6 +1,8 @@
1
1
  require File.expand_path("../../spec_helper", __FILE__)
2
2
 
3
3
  describe Sinatra::Namespace do
4
+ it_should_behave_like 'sinatra'
5
+
4
6
  [:get, :head, :post, :put, :delete].each do |verb|
5
7
  describe "HTTP #{verb.to_s.upcase}" do
6
8
  before :each do
@@ -20,7 +22,7 @@ describe Sinatra::Namespace do
20
22
  browse_route(verb, "/foo/bar").body.should == "baz" unless verb == :head
21
23
  end
22
24
 
23
- it "should allowes adding routes with no path" do
25
+ it "should allows adding routes with no path" do
24
26
  app.namespace "/foo" do
25
27
  send(verb) { "bar" }
26
28
  end
@@ -28,6 +30,18 @@ describe Sinatra::Namespace do
28
30
  browse_route(verb, "/foo").body.should == "bar" unless verb == :head
29
31
  end
30
32
 
33
+ it "allows nesting" do
34
+ app.namespace "/foo" do
35
+ namespace "/bar" do
36
+ namespace "/baz" do
37
+ send(verb) { 'foobarbaz' }
38
+ end
39
+ end
40
+ end
41
+ browse_route(verb, "/foo/bar/baz").should be_ok
42
+ browse_route(verb, "/foo/bar/baz").body.should == "foobarbaz" unless verb == :head
43
+ end
44
+
31
45
  it "allows regular expressions" do
32
46
  app.namespace %r{/\d\d} do
33
47
  send(verb) { "foo" }
@@ -48,6 +62,28 @@ describe Sinatra::Namespace do
48
62
  end
49
63
  end
50
64
 
65
+ describe :filters do
66
+ it 'should trigger before filters for namespaces' do
67
+ app.before { settings.set :foo, 0 }
68
+ app.namespace('/foo') do
69
+ before { settings.set :foo, settings.foo + 1 }
70
+ send(verb) { }
71
+ end
72
+ browse_route(verb, '/foo').should be_ok
73
+ app.foo.should == 1
74
+ end
75
+ it 'should trigger after filters for namespaces' do
76
+ $foo = 0
77
+ app.after { $foo += 2 }
78
+ app.namespace('/foo') do
79
+ after { $foo += 1 }
80
+ send(verb) { }
81
+ end
82
+ browse_route(verb, '/foo').should be_ok
83
+ $foo.should == 3
84
+ end
85
+ end
86
+
51
87
  describe :make_namespace do
52
88
  it "extends modules make_namespace is called on" do
53
89
  mod = Module.new
@@ -181,4 +217,34 @@ describe Sinatra::Namespace do
181
217
 
182
218
  end
183
219
  end
220
+
221
+ describe :errors do
222
+ it "should allow custom error handlers with not found" do
223
+ app.namespace('/en') { always_activate }
224
+ app.namespace('/de') do
225
+ always_activate
226
+ not_found { 'nicht gefunden' }
227
+ end
228
+ get('/foo').status.should == 404
229
+ last_response.body.should_not == 'nicht gefunden'
230
+ get('/en/foo').status.should == 404
231
+ last_response.body.should_not == 'nicht gefunden'
232
+ get('/de/foo').status.should == 404
233
+ last_response.body.should == 'nicht gefunden'
234
+ end
235
+
236
+ it "should allow custom error handlers with error" do
237
+ app.namespace('/en') { always_activate }
238
+ app.namespace('/de') do
239
+ always_activate
240
+ error(404) { 'nicht gefunden' }
241
+ end
242
+ get('/foo').status.should == 404
243
+ last_response.body.should_not == 'nicht gefunden'
244
+ get('/en/foo').status.should == 404
245
+ last_response.body.should_not == 'nicht gefunden'
246
+ get('/de/foo').status.should == 404
247
+ last_response.body.should == 'nicht gefunden'
248
+ end
249
+ end
184
250
  end
@@ -1,2 +1,2 @@
1
- require "sinatra/rspec"
1
+ require "sinatra/rspec/shared"
2
2
  require "sinatra/namespace"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinatra-namespace
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
4
+ hash: 11
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 4
9
- - 1
10
- version: 0.4.1
8
+ - 5
9
+ - 0
10
+ version: 0.5.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Konstantin Haase
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-06-04 00:00:00 +02:00
18
+ date: 2010-07-09 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -26,12 +26,12 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- hash: 15
29
+ hash: 11
30
30
  segments:
31
31
  - 0
32
- - 4
32
+ - 5
33
33
  - 0
34
- version: 0.4.0
34
+ version: 0.5.0
35
35
  type: :runtime
36
36
  version_requirements: *id001
37
37
  - !ruby/object:Gem::Dependency
@@ -42,12 +42,12 @@ dependencies:
42
42
  requirements:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
- hash: 15
45
+ hash: 11
46
46
  segments:
47
47
  - 0
48
- - 4
48
+ - 5
49
49
  - 0
50
- version: 0.4.0
50
+ version: 0.5.0
51
51
  type: :runtime
52
52
  version_requirements: *id002
53
53
  - !ruby/object:Gem::Dependency
@@ -58,12 +58,12 @@ dependencies:
58
58
  requirements:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
- hash: 15
61
+ hash: 11
62
62
  segments:
63
63
  - 0
64
- - 4
64
+ - 5
65
65
  - 0
66
- version: 0.4.0
66
+ version: 0.5.0
67
67
  type: :development
68
68
  version_requirements: *id003
69
69
  - !ruby/object:Gem::Dependency