sinatra-rroute 0.0.1 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 38d10acac3a5452cbbce30a6290ea0e381b5a6c0
4
- data.tar.gz: fae34365023bd7529d861cfb82f35e1eaacd6eba
3
+ metadata.gz: 540d92d8facd0fc96d90dbd1ebc535e452f1fd02
4
+ data.tar.gz: 16f27c900d637268d325a4ad7e18c35686aff6da
5
5
  SHA512:
6
- metadata.gz: bff81eca8b56be9a0b66d08197268040e419f5beead89550918ec961946233b9a079472b069bfb28eb39f8b7a46e96bb9de9df5af93d94272f3c225e0f0a3d34
7
- data.tar.gz: f3acaf70bdf9f67240eae87693cef2535548cd835aac1a87ce289cec3c6c1d9ccad47ff1a1df4a461fb0326377ab73da36ba924d919bf13a1844228d2eaae076
6
+ metadata.gz: 5db8fe0b35667a730b571c68783d69f35f56d01103c766182971e8abbd2df5f97fa91e8c3a09c0a26a7cc55b909dba19e1a0aca269bad0b37f72db19dee8eefd
7
+ data.tar.gz: 7736ecdaab8375ea1756aa1611c7e20581d728e9789229349c638ade0c7132bd94b25fc8dbe572597831ba5a62d7910de4378db97ba09aa99ace99c10ebe85bb
data/README.md CHANGED
@@ -1,8 +1,14 @@
1
1
  # Sinatra-rroute
2
2
 
3
- Sinatra-rroute provides Rails-like routes for Sinatra. Using one of the `gget`/`ppost`/`ddelete`/... methods, a route is assigned a name, is mapped to a controller-like method and has a mask to be used by the provided `path` helper function. The `path` helper takes the name of a route, a set of keyword-value mappings, applies them to the mask and gives back the route with each keyword replaced by the associated value.
3
+ Sinatra-rroute provides Rails-like routes for Sinatra. Using one of the
4
+ `gget`/`ppost`/`ddelete`/... methods, a route is assigned a name, is mapped
5
+ to a controller-like method and has a mask to be used by the provided
6
+ `path` helper function. The `path` helper takes the name of a route, a set
7
+ of keyword-value mappings, applies them to the mask and gives back the
8
+ route with each keyword replaced by the associated value.
4
9
 
5
- Routes can also be namespaced. Namespaces can be nested. There can be multiple namespaces per app.
10
+ Routes can also be namespaced. Namespaces can be nested. There can be
11
+ multiple namespaces per app.
6
12
 
7
13
  ## Setup
8
14
 
@@ -22,7 +28,8 @@ Routes can also be namespaced. Namespaces can be nested. There can be multiple n
22
28
 
23
29
  ### Route Mapping
24
30
 
25
- Mapping routes to controller-like methods works by calling one of the sinatra-rroute mapping methods like so:
31
+ Mapping routes to controller-like methods works by calling one of the
32
+ sinatra-rroute mapping methods like so:
26
33
 
27
34
  # This will call Sinatra's `get' method behind the scenes.
28
35
  gget '/[uU]ser/:name/:age/?' => :user_info, :as =>
@@ -32,9 +39,16 @@ Mapping routes to controller-like methods works by calling one of the sinatra-rr
32
39
  ppost '/[uU]ser/new/:name/:age/?' => :create_user, :as =>
33
40
  :new_user, :mask => '/user/new/:name/:age/'
34
41
 
35
- The above examples will map GET requests for routes matching the RegEx `'/[uU]ser/:name/:age/?'` to the function `user_info` and POST requests to the route matching the RegEx `'/[uU]ser/new/:name/:age/?'` to the function :create_user. The first route can be referenced as `user`, the second one as `new_user`.
42
+ The above examples will map GET requests for routes matching the RegEx
43
+ `'/[uU]ser/:name/:age/?'` to the function `user_info` and POST requests to
44
+ the route matching the RegEx `'/[uU]ser/new/:name/:age/?'` to the function
45
+ :create_user. The first route can be referenced as `user`, the second one
46
+ as `new_user`.
36
47
 
37
- Here are all the supported mapping methods and their associated HTTP methods (all of them have the same signature, e.g. `gget('/route/regex/?' => :controller_method, :as => :route_name, :mask => '/route/mask/')`):
48
+ Here are all the supported mapping methods and their associated HTTP
49
+ methods (all of them have the same signature, e.g.
50
+ `gget('/route/regex/?' => :controller_method, :as => :route_name, :mask =>
51
+ '/route/mask/')`):
38
52
 
39
53
 
40
54
  | Rroute Method | HTTP Method |
@@ -51,18 +65,61 @@ Here are all the supported mapping methods and their associated HTTP methods (al
51
65
  | ttrace | TRACE |
52
66
  | cconnect | CONNECT |
53
67
 
54
- *The validity of some of those HTTP methods may be debatable, but it is nice to have them, nonetheless, in case you might need them one day.*
68
+ *The validity of some of those HTTP methods may be debatable, but it is
69
+ nice to have them, nonetheless, in case you might need them one day.*
55
70
 
56
- If you do not want to map routes to methods, but still give them names and masks, you can use the `mmap` function in combination with Sinatra's built-in `get`/`post`/`delete`/... functions:
71
+ If you do not want to map routes to methods, but still give them names and
72
+ masks, you can use the `mmap` function in combination with Sinatra's
73
+ built-in `get`/`post`/`delete`/... functions:
57
74
 
58
75
  # Signature: mmap(regex, mask, name)
59
76
  get mmap('/user/:name/?', '/user/:name/', :user_info) do
60
77
  # ...
61
78
  end
62
79
 
80
+ **Referencing controllers...**
81
+
82
+ ...works in two ways. Either they are referenced using
83
+ symbols for simple class/module level or global controllers or they are
84
+ referenced using strings representing nested controllers similar to the
85
+ `:to` option of Rails' `get`/`post`/... routing methods:
86
+
87
+ # Symbol reference
88
+ gget '/[uU]ser/:name/:age/?' => :user_info, :as =>
89
+ :user, :mask => '/user/:name/:age/'
90
+
91
+ # String reference to nested controller (instance method)
92
+ gget '/[uU]ser/:name/:age/?' => 'Very::Deeply::Nested#controller',
93
+ :as => :user, :mask => '/user/:name/:age/'
94
+
95
+ # String reference to nested controller (class method)
96
+ gget '/[uU]ser/:name/:age/?' => 'Very::Deeply::Nested::controller',
97
+ :as => :user, :mask => '/user/:name/:age/'
98
+
99
+ String references can point to either instance methods or class methods.
100
+ For instance methods, the class is automatically instanciated and the
101
+ method is called on this anonymous instance. So arguments can not be
102
+ supplied for this instance (this would arguably be bad controller design
103
+ anyway). Unlike with Rails,
104
+
105
+ - case is significant in string references
106
+ (`'UpperCase::DeeplyNested::controller'`), but
107
+ - strings can reference arbitrarily deeply nested controllers
108
+ (`'One::Two::Three::Four::Five::Six::Seven#controller'`).
109
+
110
+ Have in mind, that for sinatra-rroute to be able to reach controllers,
111
+ the controllers already have to be defined, i.e. modules/classes have to be
112
+ required *before* being referenced in a `gget`/`ppost`/`mmap` call.
113
+
63
114
  ### Namespacing
64
115
 
65
- Sinatra-rroute comes with a `nnamespace` method which takes the name of a namespace and a block. Each route specified using one of the sinatra-rroute mapping functions (`gget`/`ppost`/`ddelete`/, also `mmap`) inside the block will be prefixed by the specified namespace prefix. Sinatra's built-in `get`/`post`/`delete`/... functions can be used within a namespace block, but are *not* affected by the namespacing. Namespaces can be nested. *Prefixes do have to specify leading and/or trailing slashes explicitely!*
116
+ Sinatra-rroute comes with a `nnamespace` method which takes the name of a
117
+ namespace and a block. Each route specified using one of the sinatra-rroute
118
+ mapping functions (`gget`/`ppost`/`ddelete`/, also `mmap`) inside the block
119
+ will be prefixed by the specified namespace prefix. Sinatra's built-in
120
+ `get`/`post`/`delete`/... functions can be used within a namespace block,
121
+ but are *not* affected by the namespacing. Namespaces can be nested.
122
+ *Prefixes do have to specify leading and/or trailing slashes explicitely!*
66
123
 
67
124
  Here is an example:
68
125
 
@@ -82,7 +139,10 @@ Here is an example:
82
139
 
83
140
  ### Route Helper
84
141
 
85
- Sinatra-rroute comes with a `path` helper function. It takes the name of a route and a hash of key-value mappings and returns the path for that route according to its mask. Each "token" in a mask will be replaced by the value for the specified key in the mapping.
142
+ Sinatra-rroute comes with a `path` helper function. It takes the name of a
143
+ route and a hash of key-value mappings and returns the path for that route
144
+ according to its mask. Each "token" in a mask will be replaced by the value
145
+ for the specified key in the mapping.
86
146
 
87
147
  # Specify a route mapping.
88
148
  gget '/[uU]ser/:name/:age/?' => :user_info, :as =>
@@ -90,7 +150,8 @@ Sinatra-rroute comes with a `path` helper function. It takes the name of a route
90
150
 
91
151
  # Redirect to this route.
92
152
  get '/friend/:name/:age/?' do
93
- redirect to(path(:user, :name => params[:name], :age => params[:age]))
153
+ redirect to(path(:user, :name => params[:name], :age =>
154
+ params[:age]))
94
155
  end
95
156
 
96
157
  # Generate a link for the route in the view.
@@ -98,23 +159,36 @@ Sinatra-rroute comes with a `path` helper function. It takes the name of a route
98
159
  # This will render the following link:
99
160
  # <a href="/user/John/32/">Get user info</a>
100
161
 
101
- The helper can be used in your view files as well as in your controller/model/application. It is handy for links, redirecting etc.
162
+ The helper can be used in your view files as well as in your
163
+ controller/model/application. It is handy for links, redirecting etc.
102
164
 
103
165
  ### Accessing Routes
104
166
 
105
- The full hash of all route-method mappings is attached to your Sinatra app's `settings` object available through the `settings.app_paths` variable.
167
+ The full hash of all route-method mappings is attached to your Sinatra
168
+ app's `settings` object available through the `settings.app_paths`
169
+ variable.
106
170
 
107
- *Note*: The full list of all routes is only available after the last call of one of the sinatra-rroute mapping methods, of course.
171
+ *Note*: The full list of all routes is only available after the last call
172
+ of one of the sinatra-rroute mapping methods, of course.
108
173
 
109
- *Note*: When mixing sinatra-rroute mapping methods (`gget`/`ppost`/`delete`/`mmap`/...) and Sinatra's built-in `get`/`post`/`delete`/... the routes defined using the Sinatra built-ins will *not* show up in `settings.app_paths`!
174
+ *Note*: When mixing sinatra-rroute mapping methods
175
+ (`gget`/`ppost`/`delete`/`mmap`/...) and Sinatra's built-in
176
+ `get`/`post`/`delete`/... the routes defined using the Sinatra built-ins
177
+ will *not* show up in `settings.app_paths`!
110
178
 
111
179
  ## Mixing With Sinatra and Other Extensions
112
180
 
113
- Sinatra's built-in `get`/`post`/`delete`/... functions as well as other route-related extensions do work fine in combination with sinatra-rroute as long as they do not
181
+ Sinatra's built-in `get`/`post`/`delete`/... functions as well as other
182
+ route-related extensions do work fine in combination with sinatra-rroute as
183
+ long as they do not
114
184
 
115
185
  - clash with sinatra-rroute's function names,
116
- - fiddle with the `settings.app_paths` variable of your Sinatra app or
117
- - redefine/overload Sinatra's built-in `get`/`post`/`delete` functions without letting sinatra-rroute know.
186
+ - fiddle with the `settings.app_paths` variable of your Sinatra app,
187
+ - redefine/overload Sinatra's built-in `get`/`post`/`delete` functions
188
+ without letting sinatra-rroute know or
189
+ - redefine/overload/fiddle with the
190
+ `rroute_call_nested_controller_from_string` method which handles nested
191
+ controller references.
118
192
 
119
193
  ## *What about the weird method names?*
120
194
 
@@ -122,4 +196,6 @@ The names are
122
196
 
123
197
  - concise (as short as possible),
124
198
  - consistent (same name generatiion scheme) and
125
- - unobtrusive (they do not interfere with or overload Sinatra's and Rack's built-in routing methods, they also do not interfere with other Sinatra extensions).
199
+ - unobtrusive (they do not interfere with or overload Sinatra's and Rack's
200
+ built-in routing methods, they also do not interfere with other Sinatra
201
+ extensions).
@@ -40,6 +40,51 @@ module Sinatra
40
40
  end
41
41
  path
42
42
  end
43
+
44
+ # @visibility private
45
+ #
46
+ # Take the string representation of a nested instance method or of
47
+ # a class method and call the method.
48
+ #
49
+ # Notes:
50
+ #
51
+ # - The name is chosen to be long and unique enough to not be
52
+ # accidentially overwritten
53
+ # - Arguments are not supported as the methods to use this function
54
+ # on are controllers.
55
+ # - Unlike the `:to' option of Rails' `match' method (used by
56
+ # `get'/`post'/...), strings are case-sensitive.
57
+ # - Unlike the `:to' option of Rails' `match' method
58
+ # methods can be arbitrarily deeply nested.
59
+ #
60
+ # @param [String] string String representation of a method
61
+ #
62
+ # @example
63
+ #
64
+ # # Instance method
65
+ # rroute_call_nested_controller_from_string(
66
+ # 'Very::Deeply::Nested#controller')
67
+ #
68
+ # # Class method
69
+ # rroute_call_nested_controller_from_string(
70
+ # 'Very::Deeply::Nested::controller')
71
+ #
72
+ # @return [nil] Nothing.
73
+ def rroute_call_nested_controller_from_string(string)
74
+ method_sep = '#'
75
+ nesting_sep = '::'
76
+ if string =~ %r{#{method_sep}}
77
+ tokens = string.split(method_sep)
78
+ const = Kernel.const_get(tokens[0])
79
+ method = tokens[-1]
80
+ const.new.send(method.to_sym)
81
+ else
82
+ tokens = string.split(nesting_sep)
83
+ const = Kernel.const_get(tokens[0..-2].join(nesting_sep))
84
+ method = tokens[-1]
85
+ const.send(method.to_sym)
86
+ end
87
+ end
43
88
  end
44
89
  end
45
90
 
@@ -108,7 +153,8 @@ module Sinatra
108
153
  settings.app_prefixes.join
109
154
  controller = nil
110
155
  if mapping.values[0] != nil
111
- controller = mapping.values[0].to_sym
156
+ # controller = mapping.values[0].to_sym
157
+ controller = mapping.values[0]
112
158
  end
113
159
  if mapping.keys[0].class == Regexp
114
160
  mapping_regex = mapping.keys[0]
@@ -399,7 +445,14 @@ module Sinatra
399
445
  # Adapt the RegEx representation.
400
446
  value[:regex] = value[:regex].source
401
447
  send(value[:http_method],
402
- value[:regex]) { send value[:controller] }
448
+ value[:regex]) do
449
+ if value[:controller].class == Symbol
450
+ send value[:controller]
451
+ else
452
+ rroute_call_nested_controller_from_string(value[:controller]
453
+ .to_s)
454
+ end
455
+ end
403
456
  end
404
457
  end
405
458
  end
@@ -1,5 +1,5 @@
1
1
  module Sinatra
2
2
  module Rroute
3
- VERSION = "0.0.1"
3
+ VERSION = "0.1.0"
4
4
  end
5
5
  end
@@ -0,0 +1 @@
1
+ require_relative 'nested'
@@ -0,0 +1,17 @@
1
+ class TestApp < Sinatra::Base
2
+
3
+ module Nested
4
+ class Controller
5
+ class Reference
6
+ def controller
7
+ 'I am nested controller. 95475e78-f2c9-11e3-ba43-60eb69544a6d'
8
+ end
9
+
10
+ def self.another_controller
11
+ 'I am also nested 98985e7e-f2c9-11e3-b9d9-60eb69544a6d'
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ end
@@ -80,6 +80,26 @@ request" do
80
80
  end
81
81
  end
82
82
 
83
+ describe "#gget (3)" do
84
+ it "successfully dispatches a GET request and defines a route mask
85
+ (using a nested controller reference - instance method)" do
86
+ get '/nested/controller/references'
87
+ expect(last_response).to be_ok
88
+ expect(last_response.body)
89
+ .to include('95475e78-f2c9-11e3-ba43-60eb69544a6d')
90
+ end
91
+ end
92
+
93
+ describe "#gget (4)" do
94
+ it "successfully dispatches a GET request and defines a route mask
95
+ (using a nested controller reference - class method)" do
96
+ get '/nested/controller/references/another/one'
97
+ expect(last_response).to be_ok
98
+ expect(last_response.body)
99
+ .to include('98985e7e-f2c9-11e3-b9d9-60eb69544a6d')
100
+ end
101
+ end
102
+
83
103
  describe "#ppost" do
84
104
  it "successfully dispatches a POST request and defines a route mask" do
85
105
  post "/user/new/#{@user[:name]}/#{@user[:age]}/"
@@ -190,4 +190,19 @@ class TestApp < Sinatra::Base
190
190
  get mmap('/generate/paths/?', 'generate/paths/', :build_paths) do
191
191
  'Paths have been generated.'
192
192
  end
193
+
194
+ # Nested controller references
195
+
196
+ require 'controllers/init'
197
+
198
+ # Instance method
199
+ gget '/nested/controller/references' =>
200
+ 'TestApp::Nested::Controller::Reference#controller', :as =>
201
+ :nested_controller_reference, :mask => '/nested/controller/references'
202
+
203
+ # Class method
204
+ gget '/nested/controller/references/another/one' =>
205
+ 'TestApp::Nested::Controller::Reference::another_controller', :as =>
206
+ :another_nested_controller_reference, :mask =>
207
+ '/nested/controller/references/another/one'
193
208
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinatra-rroute
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - nounch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-25 00:00:00.000000000 Z
11
+ date: 2014-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -65,6 +65,8 @@ files:
65
65
  - lib/sinatra/rroute.rb
66
66
  - lib/sinatra/rroute/version.rb
67
67
  - rroute.gemspec
68
+ - spec/controllers/init.rb
69
+ - spec/controllers/nested.rb
68
70
  - spec/rroute_spec.rb
69
71
  - spec/test_app.rb
70
72
  homepage: ''
@@ -92,6 +94,8 @@ signing_key:
92
94
  specification_version: 4
93
95
  summary: Rails-style routes with names, namespaces and `path' helper.
94
96
  test_files:
97
+ - spec/controllers/init.rb
98
+ - spec/controllers/nested.rb
95
99
  - spec/rroute_spec.rb
96
100
  - spec/test_app.rb
97
101
  has_rdoc: