sinatra-trails 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,312 @@
1
+ sinatra-trails
2
+ --------------
3
+
4
+ Is a very thin Rails inspired route naming DSL for using with Sinatra apps.
5
+ It doesn't monkeypatch or overrides any Sinatra::Base methods
6
+ It provides helpers for generating routes for resources and single resource, namespaces and named routes.
7
+
8
+ Instalation
9
+ ----------
10
+
11
+ $ [sudo] gem install sinatra-trails
12
+
13
+ Usage
14
+ ----
15
+
16
+ Basic
17
+ =====
18
+
19
+ Named routes are generated with map, not passing :to option sets the path to be the same as the name:
20
+
21
+ require 'sinatra/trails'
22
+
23
+ class MyApp < Sinatra::Base
24
+ register Sinatra::Trails
25
+
26
+ map :dashboard # => '/dashboard'
27
+ map :home, :to => '/' # => '/'
28
+ map :post, :to => '/posts/:id' # => '/posts/:id'
29
+ end
30
+
31
+ MyApp.print_routes
32
+ # prints
33
+ # dashboard => /dashboard
34
+ # home => /
35
+ # post => /posts/:id
36
+
37
+ Routes can be define beforehand:
38
+
39
+ map :dashboard
40
+
41
+ # GET '/dashboard'
42
+ get route_for(:dashboard) do
43
+ ...
44
+ end
45
+
46
+ Or when defining the action:
47
+
48
+ # GET '/dashboard'
49
+ get map(:dashboard) do
50
+ ...
51
+ end
52
+
53
+ All defined routes will be available in the views and action blocks:
54
+
55
+ get map(:posts, :to => '/posts/:id') do
56
+ ...
57
+ end
58
+
59
+ get map(:dashboard) do
60
+ path_for(:dashboard) # => '/dashboard'
61
+ url_for(:dashboard) # => 'http://www.example.com/dashboard'
62
+ path_for(:dashboard, :option => 'hi') # => '/dashboard?option=hi'
63
+ # all required params must be meet, an object can be passed to meet :id but it must respond to #to_param
64
+ path_for(:posts, 1) # => '/posts/1'
65
+ end
66
+
67
+
68
+ Namespaces
69
+ ==========
70
+
71
+ Pasing a symbol namespaces both the path and the route name:
72
+
73
+ namespace :admin do
74
+ map(:dashboard)
75
+ end
76
+
77
+ route_for(:admin_dashboard) # => '/admin/dashboard'
78
+
79
+ Passing a string only namespaces the path:
80
+
81
+ namespace 'admin' do
82
+ map(:dashboard)
83
+ end
84
+
85
+ route_for(:dashboard) # => '/admin/dashboard'
86
+
87
+ Passing nil to namespace only sets a context:
88
+
89
+ namespace nil do
90
+ map(:dashboard)
91
+ end
92
+
93
+ route_for(:dashboard) # => '/dashboard'
94
+
95
+
96
+ Resources
97
+ =========
98
+
99
+ Restful routes for plural resources can be generated as follows, inside the resource
100
+ definition block a route can be accessed by its name as a method call or using the path_for method:
101
+
102
+ resources :users do
103
+ # GET /users
104
+ get users do
105
+ ...
106
+ end
107
+
108
+ # POST /users
109
+ post users do
110
+ ...
111
+ end
112
+
113
+ # GET /users/new
114
+ get new_user do
115
+ ...
116
+ end
117
+
118
+ # GET /users/:id
119
+ get user do
120
+ ...
121
+ end
122
+
123
+ # GET /users/:id/edit
124
+ get edit_user do
125
+ ...
126
+ end
127
+
128
+ # PUT /users/:id
129
+ put user do
130
+ ...
131
+ end
132
+
133
+ # DELETE /users/:id
134
+ delete user do
135
+ ...
136
+ end
137
+ end
138
+
139
+ It is important to note that the order in wich the sinatra action blocks are defined is important.
140
+ in this case `get(new_user)` must be defined before `get(user)`
141
+
142
+ As with previous examples routes can be defined beforehand:
143
+
144
+ resources :users
145
+ # GET '/users'
146
+ get path_for(:users) do
147
+ ...
148
+ end
149
+
150
+
151
+ Nested Resources
152
+ ================
153
+
154
+ Resources can be nested in a similar way as with Rails nested resources:
155
+
156
+ resources :users do
157
+ ...
158
+ resources :comments do
159
+ # GET /users/:user_id/comments
160
+ get user_comments do
161
+ ...
162
+ end
163
+
164
+ # GET /users/:user_id/comments/:id
165
+ get user_comment do
166
+ ...
167
+ end
168
+ end
169
+ end
170
+
171
+ print_routes
172
+ # users => /users
173
+ # new_user => /users/new
174
+ # user => /users/:id
175
+ # edit_user => /users/:id/edit
176
+ # user_comments => /users/:user_id/comments
177
+ # new_user_comment => /users/:user_id/comments/new
178
+ # user_comment => /users/:user_id/comments/:id
179
+ # edit_user_comment => /users/:user_id/comments/:id/edit
180
+
181
+
182
+ And for actions that don't need to load the parent resource the route generation can be shallow:
183
+
184
+ resources :users, :shallow => true do
185
+ resources :comments
186
+ end
187
+
188
+ print_routes
189
+ # users => /users
190
+ # new_user => /users/new
191
+ # user => /users/:id
192
+ # edit_user => /users/:id/edit
193
+ # user_comments => /users/:user_id/comments
194
+ # new_user_comment => /users/:user_id/comments/new
195
+ # comment => /comments/:id
196
+ # edit_comment => /comments/:id/edit
197
+
198
+ There's an alternative way of generating routes for nested resources:
199
+
200
+ resources :users => {:posts => :comments}, :shallow => true do
201
+ ...
202
+ end
203
+ print_routes
204
+ # users => /users
205
+ # new_user => /users/new
206
+ # user => /users/:id
207
+ # edit_user => /users/:id/edit
208
+ # user_posts => /users/:user_id/posts
209
+ # new_user_post => /users/:user_id/posts/new
210
+ # post => /posts/:id
211
+ # edit_post => /posts/:id/edit
212
+ # post_comments => /posts/:post_id/comments
213
+ # new_post_comment => /posts/:post_id/comments/new
214
+ # comment => /comments/:id
215
+ # edit_comment => /comments/:id/edit
216
+
217
+ Some keys to the params hash are added when routes are defined using sinatra-trails:
218
+
219
+ params[:resource] # the name of the resource in REST actions
220
+ params[:action] # the name of the action in REST actions
221
+ params[:namespace] # the name of the current namespace
222
+
223
+
224
+ Singleton Resource
225
+ =================
226
+
227
+ Same principles apply for singleton resource:
228
+
229
+ resource :user
230
+ print_routes
231
+ # user => /user
232
+ # new_user => /user/new
233
+ # edit_user => /user/edit
234
+
235
+
236
+ Before and After Filters
237
+ ========================
238
+
239
+ Defining a filter within a context (namespace, resources, resource) without passing any path will execute that filter for
240
+ all actions defined in that context:
241
+
242
+ namespace :admin do
243
+ before do
244
+ @admin = true
245
+ end
246
+
247
+ get map(:dashboard) do
248
+ @admin # => true
249
+ end
250
+ end
251
+
252
+ get map(:home, :to => '/') do
253
+ @admin # => nil
254
+ end
255
+
256
+
257
+ Within a context named routes, strings or regexps can be used as arguments for before and after filters:
258
+
259
+ resources :users do
260
+ before new_user, edit_user do
261
+ end
262
+ end
263
+
264
+ A symbol can be passed to the filter definition and it will be lazily evaluated against the routes within the context:
265
+
266
+ namespace :admin do
267
+ before :dashboard do
268
+ ...
269
+ end
270
+
271
+ get map(:dashboard) do
272
+ ...
273
+ end
274
+ end
275
+
276
+
277
+ Accessing Routes from Outside the App
278
+ =====================================
279
+
280
+ On registering Sinatra::Trails a dynamic module for the Sinatra app is created and it is assigned to the constant `Routes`
281
+ including that module in another class gives that class access to the app's paths, a single class can access paths for
282
+ several Sinatra apps:
283
+
284
+ class MyApp < Sinatra::Base
285
+ register Sinatra::Trails
286
+
287
+ get map(:users) do
288
+ ...
289
+ end
290
+
291
+ get map(:user, :to => '/users/:id') do
292
+ ...
293
+ end
294
+ end
295
+
296
+ class OtherApp < Sinatra::Base
297
+ include MyApp::Routes
298
+
299
+ get 'index' do
300
+ redirect to path_for(:users)
301
+ end
302
+ end
303
+
304
+ class User < Sequel::Model
305
+ include MyApp::Routes
306
+
307
+ def to_param() id end
308
+
309
+ def route
310
+ path_for(:user, self) # => '/users/1'
311
+ end
312
+ end
@@ -1,5 +1,5 @@
1
1
  module Sinatra
2
2
  module Trails
3
- VERSION = "0.0.5"
3
+ VERSION = "0.0.6"
4
4
  end
5
5
  end
@@ -89,10 +89,7 @@ module Sinatra
89
89
  @actual_keys ||= routes.map{ |m| m.keys }.flatten
90
90
  end
91
91
 
92
- def keys
93
- self
94
- end
95
-
92
+ def keys() self end
96
93
  def any?() actual_keys.any? end
97
94
  def zip(arr) actual_keys.zip(arr) end
98
95
  end
@@ -108,8 +105,8 @@ module Sinatra
108
105
  end
109
106
 
110
107
  def map name, opts = {}, &block
111
- path = opts.delete(:to) || name
112
- route = Route.new(path, name, [*ancestors, self], self)
108
+ path = opts.delete(:to) || name
109
+ route = Route.new(path, name.to_sym, [*ancestors, self], self)
113
110
  instance_eval &block if block_given?
114
111
  route
115
112
  end
@@ -131,6 +128,12 @@ module Sinatra
131
128
  @sinatra_app.before ScopeMatcher.new(self, args), opts, &block
132
129
  end
133
130
 
131
+ def after *args, &block
132
+ # TODO: no specs
133
+ opts = Hash === args.last ? args.pop : {}
134
+ @sinatra_app.after ScopeMatcher.new(self, args), opts, &block
135
+ end
136
+
134
137
  def generate_routes! &block
135
138
  instance_eval &block if block_given?
136
139
  @routes
@@ -242,7 +245,6 @@ module Sinatra
242
245
 
243
246
  def map action
244
247
  ancestors = [*self.ancestors, plural_name, action]
245
-
246
248
  ancestors[0, ancestors.size - 2] = ancestors[0..-3].reject{ |ancestor| Resource === ancestor } if opts[:shallow]
247
249
  Route.new([plural_name, action], action.to_s, ancestors, self)
248
250
  end
@@ -13,7 +13,7 @@ describe 'trails' do
13
13
  describe 'basic' do
14
14
  before :all do
15
15
  app.map :home, :to => '/'
16
- app.map :dashboard
16
+ app.map 'dashboard'
17
17
  app.map :edit_user, :to => '/users/:id/edit'
18
18
  end
19
19
 
@@ -166,7 +166,6 @@ describe 'trails' do
166
166
  app.resources :users do
167
167
  map(:confirm)
168
168
  end
169
- puts app.print_routes
170
169
  end
171
170
  it_should_behave_like 'generates routes for users'
172
171
  it { app.route_for(:users_confirm).should == '/users/confirm' }
@@ -314,17 +313,29 @@ describe 'trails' do
314
313
  end
315
314
 
316
315
  describe 'single resource' do
317
- before :all do
318
- app.resource :user => :profile
319
- end
320
- it { app.route_for(:user).should == '/user' }
321
- it { app.route_for(:new_user).should == '/user/new' }
322
- it { app.route_for(:edit_user).should == '/user/edit' }
323
- it { app.route_for(:user_profile).should == '/user/profile' }
324
- it { app.route_for(:new_user_profile).should == '/user/profile/new' }
325
- it { app.route_for(:edit_user_profile).should == '/user/profile/edit' }
316
+ describe 'basic' do
317
+ before :all do
318
+ app.resource :user => :profile
319
+ end
320
+ it { app.route_for(:user).should == '/user' }
321
+ it { app.route_for(:new_user).should == '/user/new' }
322
+ it { app.route_for(:edit_user).should == '/user/edit' }
323
+ it { app.route_for(:user_profile).should == '/user/profile' }
324
+ it { app.route_for(:new_user_profile).should == '/user/profile/new' }
325
+ it { app.route_for(:edit_user_profile).should == '/user/profile/edit' }
326
+ end
327
+
328
+ describe 'as namespace' do
329
+ before :all do
330
+ app.resource :user do
331
+ map(:confirm)
332
+ end
333
+ end
334
+ it { app.route_for(:user_confirm).should == '/user/confirm' }
335
+ end
326
336
  end
327
337
 
338
+
328
339
  describe 'finding route for scope' do
329
340
  before :all do
330
341
  @scope = Sinatra::Trails::Scope.new(app, :admin)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinatra-trails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,12 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-05 00:00:00.000000000Z
12
+ date: 2011-11-29 00:00:00.000000000 -06:00
13
+ default_executable:
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: sinatra
16
- requirement: &2156534160 !ruby/object:Gem::Requirement
17
+ requirement: &70095708882740 !ruby/object:Gem::Requirement
17
18
  none: false
18
19
  requirements:
19
20
  - - ! '>='
@@ -21,10 +22,10 @@ dependencies:
21
22
  version: '0'
22
23
  type: :runtime
23
24
  prerelease: false
24
- version_requirements: *2156534160
25
+ version_requirements: *70095708882740
25
26
  - !ruby/object:Gem::Dependency
26
27
  name: i18n
27
- requirement: &2156533740 !ruby/object:Gem::Requirement
28
+ requirement: &70095708881640 !ruby/object:Gem::Requirement
28
29
  none: false
29
30
  requirements:
30
31
  - - ! '>='
@@ -32,10 +33,10 @@ dependencies:
32
33
  version: '0'
33
34
  type: :runtime
34
35
  prerelease: false
35
- version_requirements: *2156533740
36
+ version_requirements: *70095708881640
36
37
  - !ruby/object:Gem::Dependency
37
38
  name: activesupport
38
- requirement: &2156533240 !ruby/object:Gem::Requirement
39
+ requirement: &70095708880780 !ruby/object:Gem::Requirement
39
40
  none: false
40
41
  requirements:
41
42
  - - ! '>='
@@ -43,10 +44,10 @@ dependencies:
43
44
  version: '3.0'
44
45
  type: :runtime
45
46
  prerelease: false
46
- version_requirements: *2156533240
47
+ version_requirements: *70095708880780
47
48
  - !ruby/object:Gem::Dependency
48
49
  name: rake
49
- requirement: &2156532820 !ruby/object:Gem::Requirement
50
+ requirement: &70095708880260 !ruby/object:Gem::Requirement
50
51
  none: false
51
52
  requirements:
52
53
  - - ! '>='
@@ -54,10 +55,10 @@ dependencies:
54
55
  version: '0'
55
56
  type: :development
56
57
  prerelease: false
57
- version_requirements: *2156532820
58
+ version_requirements: *70095708880260
58
59
  - !ruby/object:Gem::Dependency
59
60
  name: rspec
60
- requirement: &2156532360 !ruby/object:Gem::Requirement
61
+ requirement: &70095708879500 !ruby/object:Gem::Requirement
61
62
  none: false
62
63
  requirements:
63
64
  - - ! '>='
@@ -65,10 +66,10 @@ dependencies:
65
66
  version: '0'
66
67
  type: :development
67
68
  prerelease: false
68
- version_requirements: *2156532360
69
+ version_requirements: *70095708879500
69
70
  - !ruby/object:Gem::Dependency
70
71
  name: rack-test
71
- requirement: &2156555720 !ruby/object:Gem::Requirement
72
+ requirement: &70095708878680 !ruby/object:Gem::Requirement
72
73
  none: false
73
74
  requirements:
74
75
  - - ! '>='
@@ -76,7 +77,7 @@ dependencies:
76
77
  version: '0'
77
78
  type: :development
78
79
  prerelease: false
79
- version_requirements: *2156555720
80
+ version_requirements: *70095708878680
80
81
  description: A named routes Sinatra DSL inspired by Rails routing
81
82
  email:
82
83
  - macarui@gmail.com
@@ -87,12 +88,14 @@ files:
87
88
  - .gitignore
88
89
  - .rspec
89
90
  - Gemfile
91
+ - README.rdoc
90
92
  - Rakefile
91
93
  - lib/sinatra/trails.rb
92
94
  - lib/sinatra/trails/version.rb
93
95
  - spec/route_generation_spec.rb
94
96
  - spec/spec_helper.rb
95
97
  - trails.gemspec
98
+ has_rdoc: true
96
99
  homepage: http://github.com/maca/trails
97
100
  licenses: []
98
101
  post_install_message:
@@ -113,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
116
  version: '0'
114
117
  requirements: []
115
118
  rubyforge_project: sinatra-trails
116
- rubygems_version: 1.8.8
119
+ rubygems_version: 1.6.2
117
120
  signing_key:
118
121
  specification_version: 3
119
122
  summary: A named routes Sinatra DSL inspired by Rails routing