lotus-router 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -29,6 +29,13 @@ module Lotus
29
29
  class_attribute :verb
30
30
  self.verb = :get
31
31
 
32
+ # Separator for named routes
33
+ #
34
+ # @api private
35
+ # @since 0.2.0
36
+ class_attribute :named_route_separator
37
+ self.named_route_separator = '_'.freeze
38
+
32
39
  # Generate an action for the given router
33
40
  #
34
41
  # @param router [Lotus::Router]
@@ -85,12 +92,12 @@ module Lotus
85
92
  @options[:name]
86
93
  end
87
94
 
88
- # Path prefix
95
+ # Namespace
89
96
  #
90
97
  # @api private
91
- # @since 0.1.0
92
- def prefix
93
- @prefix ||= Utils::PathPrefix.new @options[:prefix]
98
+ # @since 0.2.0
99
+ def namespace
100
+ @namespace ||= Utils::PathPrefix.new @options[:namespace]
94
101
  end
95
102
 
96
103
  private
@@ -118,7 +125,7 @@ module Lotus
118
125
  self.class.verb
119
126
  end
120
127
 
121
- # The prefixed URL relative path
128
+ # The namespaced URL relative path
122
129
  #
123
130
  # @example
124
131
  # require 'lotus/router'
@@ -126,7 +133,7 @@ module Lotus
126
133
  # Lotus::Router.new do
127
134
  # resources 'flowers'
128
135
  #
129
- # prefix 'animals' do
136
+ # namespace 'animals' do
130
137
  # resources 'mammals'
131
138
  # end
132
139
  # end
@@ -137,7 +144,7 @@ module Lotus
137
144
  # @api private
138
145
  # @since 0.1.0
139
146
  def path
140
- prefix.join(rest_path)
147
+ rest_path
141
148
  end
142
149
 
143
150
  # The URL relative path
@@ -150,10 +157,10 @@ module Lotus
150
157
  # @api private
151
158
  # @since 0.1.0
152
159
  def rest_path
153
- "/#{ resource_name }"
160
+ namespace.join(resource_name)
154
161
  end
155
162
 
156
- # The prefixed name of the action within the whole context of the router.
163
+ # The namespaced name of the action within the whole context of the router.
157
164
  #
158
165
  # @example
159
166
  # require 'lotus/router'
@@ -161,7 +168,7 @@ module Lotus
161
168
  # Lotus::Router.new do
162
169
  # resources 'flowers'
163
170
  #
164
- # prefix 'animals' do
171
+ # namespace 'animals' do
165
172
  # resources 'mammals'
166
173
  # end
167
174
  # end
@@ -172,19 +179,7 @@ module Lotus
172
179
  # @api private
173
180
  # @since 0.1.0
174
181
  def as
175
- prefix.relative_join(named_route, '_').to_sym
176
- end
177
-
178
- # The name of the action within the whole context of the router.
179
- #
180
- # @example
181
- # :flowers
182
- # :new_flowers
183
- #
184
- # @api private
185
- # @since 0.1.0
186
- def named_route
187
- resource_name
182
+ namespace.relative_join(resource_name, self.class.named_route_separator).to_sym
188
183
  end
189
184
 
190
185
  # The name of the RESTful action.
@@ -240,22 +235,25 @@ module Lotus
240
235
  end
241
236
 
242
237
  protected
243
- def method_missing(m, *args, &blk)
244
- verb, path, _ = m, *args
245
- @router.send verb, path(path), to: endpoint(path), as: as(path)
238
+ def method_missing(m, *args)
239
+ verb = m
240
+ action_name = Utils::PathPrefix.new(args.first).relative_join(nil)
241
+
242
+ @router.__send__ verb, path(action_name),
243
+ to: endpoint(action_name), as: as(action_name)
246
244
  end
247
245
 
248
246
  private
249
- def path(path)
250
- prefix.join(path)
247
+ def path(action_name)
248
+ rest_path.join(action_name)
251
249
  end
252
250
 
253
- def endpoint(path)
254
- [ resource_name, path ].join separator
251
+ def endpoint(action_name)
252
+ [ resource_name, action_name ].join separator
255
253
  end
256
254
 
257
- def as(path)
258
- Utils::PathPrefix.new(path).relative_join(resource_name, '_').to_sym
255
+ def as(action_name)
256
+ [ action_name, super() ].join(self.class.named_route_separator).to_sym
259
257
  end
260
258
  end
261
259
 
@@ -274,12 +272,12 @@ module Lotus
274
272
  # @since 0.1.0
275
273
  module DefaultMemberAction
276
274
  private
277
- def rest_path
278
- "/#{ resource_name }/#{ action_name }"
275
+ def path
276
+ rest_path.join(action_name)
279
277
  end
280
278
 
281
- def named_route
282
- "#{ action_name }_#{ resource_name }"
279
+ def as
280
+ [ action_name, super ].join(self.class.named_route_separator).to_sym
283
281
  end
284
282
  end
285
283
 
@@ -18,6 +18,13 @@ module Lotus
18
18
  # @api private
19
19
  # @since 0.1.0
20
20
  self.namespace = Resources
21
+
22
+ # Id route variable
23
+ #
24
+ # @since 0.2.0
25
+ # @api private
26
+ class_attribute :identifier
27
+ self.identifier = ':id'.freeze
21
28
  end
22
29
 
23
30
  # Collection action
@@ -37,8 +44,8 @@ module Lotus
37
44
  # @see Lotus::Router#resources
38
45
  class MemberAction < Resource::MemberAction
39
46
  private
40
- def path(path)
41
- prefix.join("/:id/#{ path }")
47
+ def path(action_name)
48
+ rest_path.join(Action.identifier, action_name)
42
49
  end
43
50
  end
44
51
 
@@ -48,8 +55,8 @@ module Lotus
48
55
  # @since 0.1.0
49
56
  module DefaultMemberAction
50
57
  private
51
- def rest_path
52
- "/#{ resource_name }/:id"
58
+ def path
59
+ rest_path.join(Action.identifier)
53
60
  end
54
61
  end
55
62
 
@@ -96,8 +103,8 @@ module Lotus
96
103
  include DefaultMemberAction
97
104
 
98
105
  private
99
- def rest_path
100
- "#{ super }/#{ action_name }"
106
+ def path
107
+ super.join(action_name)
101
108
  end
102
109
  end
103
110
 
@@ -44,6 +44,15 @@ module Lotus
44
44
  self
45
45
  end
46
46
 
47
+ # Introspect the given route to understand if there is a wrapped
48
+ # Lotus::Router
49
+ #
50
+ # @since 0.2.0
51
+ # @api private
52
+ def nested_router
53
+ dest.routes if dest.respond_to?(:routes)
54
+ end
55
+
47
56
  private
48
57
  def to=(dest = nil, &blk)
49
58
  self.to dest, &blk
@@ -0,0 +1,168 @@
1
+ require 'lotus/utils/path_prefix'
2
+
3
+ module Lotus
4
+ module Routing
5
+ # Routes inspector
6
+ #
7
+ # @since 0.2.0
8
+ class RoutesInspector
9
+ # Default route formatter
10
+ #
11
+ # @since 0.2.0
12
+ # @api private
13
+ FORMATTER = "%<name>20s %<methods>-10s %<path>-30s %<endpoint>-30s\n".freeze
14
+
15
+ # Default HTTP methods separator
16
+ #
17
+ # @since 0.2.0
18
+ # @api private
19
+ HTTP_METHODS_SEPARATOR = ', '.freeze
20
+
21
+ # Instantiate a new inspector
22
+ #
23
+ # @return [Lotus::Routing::RoutesInspector] the new instance
24
+ #
25
+ # @since 0.2.0
26
+ # @api private
27
+ def initialize(routes)
28
+ @routes = routes
29
+ end
30
+
31
+ # Return a formatted string that describes all the routes
32
+ #
33
+ # @param formatter [String] the optional formatter for a route
34
+ # @param base_path [String] the base path of a nested route
35
+ #
36
+ # @return [String] routes pretty print
37
+ #
38
+ # @since 0.2.0
39
+ #
40
+ # @see Lotus::Routing::RoutesInspector::FORMATTER
41
+ #
42
+ # @example Default formatter
43
+ # require 'lotus/router'
44
+ #
45
+ # router = Lotus::Router.new do
46
+ # get '/', to: 'home#index'
47
+ # get '/login', to: 'sessions#new', as: :login
48
+ # post '/login', to: 'sessions#create'
49
+ # delete '/logout', to: 'sessions#destroy', as: :logout
50
+ # end
51
+ #
52
+ # puts router.inspector.to_s
53
+ # # => GET, HEAD / Home::Index
54
+ # login GET, HEAD /login Sessions::New
55
+ # POST /login Sessions::Create
56
+ # logout GET, HEAD /logout Sessions::Destroy
57
+ #
58
+ # @example Custom formatter
59
+ # require 'lotus/router'
60
+ #
61
+ # router = Lotus::Router.new do
62
+ # get '/', to: 'home#index'
63
+ # get '/login', to: 'sessions#new', as: :login
64
+ # post '/login', to: 'sessions#create'
65
+ # delete '/logout', to: 'sessions#destroy', as: :logout
66
+ # end
67
+ #
68
+ # formatter = "| %{methods} | %{name} | %{path} | %{endpoint} |\n"
69
+ #
70
+ # puts router.inspector.to_s(formatter)
71
+ # # => | GET, HEAD | | / | Home::Index |
72
+ # | GET, HEAD | login | /login | Sessions::New |
73
+ # | POST | | /login | Sessions::Create |
74
+ # | GET, HEAD | logout | /logout | Sessions::Destroy |
75
+ #
76
+ # @example Nested routes
77
+ # require 'lotus/router'
78
+ #
79
+ # class AdminLotusApp
80
+ # def call(env)
81
+ # end
82
+ # def routes
83
+ # Lotus::Router.new {
84
+ # get '/home', to: 'home#index'
85
+ # }
86
+ # end
87
+ # end
88
+ #
89
+ # router = Lotus::Router.new {
90
+ # get '/fakeroute', to: 'fake#index'
91
+ # mount AdminLotusApp, at: '/admin'
92
+ # mount Lotus::Router.new {
93
+ # get '/posts', to: 'posts#index'
94
+ # mount Lotus::Router.new {
95
+ # get '/comments', to: 'comments#index'
96
+ # }, at: '/second_mount'
97
+ # }, at: '/api'
98
+ # }
99
+ #
100
+ # formatter = "| %{methods} | %{name} | %{path} | %{endpoint} |\n"
101
+ #
102
+ # puts router.inspector.to_s(formatter)
103
+ # # => | GET, HEAD | | /fakeroute | Fake::Index |
104
+ # | GET, HEAD | | /admin/home | Home::Index |
105
+ # | GET, HEAD | | /api/posts | Posts::Index |
106
+ # | GET, HEAD | | /api/second_mount/comments | Comments::Index |
107
+ def to_s(formatter = FORMATTER, base_path = nil)
108
+ base_path = Utils::PathPrefix.new(base_path)
109
+ result = ''
110
+
111
+ # TODO refactoring: replace conditional with polymorphism
112
+ # We're exposing too much knowledge from Routing::Route:
113
+ # #path_for_generation and #base_path
114
+ @routes.each do |route|
115
+ result << if router = route.nested_router
116
+ inspect_router(formatter, router, route, base_path)
117
+ else
118
+ inspect_route(formatter, route, base_path)
119
+ end
120
+ end
121
+
122
+ result
123
+ end
124
+
125
+ private
126
+
127
+ # Returns a string representation of the given route
128
+ #
129
+ # @param formatter [String] the template for the output
130
+ # @param route [Lotus::Routing::Route] a route
131
+ # @param base_path [Lotus::Utils::PathPrefix] the base path
132
+ #
133
+ # @return [String] serialized route
134
+ #
135
+ # @since 0.2.0
136
+ # @api private
137
+ #
138
+ # @see Lotus::Routing::RoutesInspector#FORMATTER
139
+ # @see Lotus::Routing::RoutesInspector#to_s
140
+ def inspect_route(formatter, route, base_path)
141
+ formatter % Hash[
142
+ name: route.name,
143
+ methods: route.request_methods.to_a.join(HTTP_METHODS_SEPARATOR),
144
+ path: base_path.join(route.path_for_generation),
145
+ endpoint: route.dest.inspect
146
+ ]
147
+ end
148
+
149
+ # Returns a string representation of the given router
150
+ #
151
+ # @param formatter [String] the template for the output
152
+ # @param router [Lotus::Router] a router
153
+ # @param route [Lotus::Routing::Route] a route
154
+ # @param base_path [Lotus::Utils::PathPrefix] the base path
155
+ #
156
+ # @return [String] serialized routes from router
157
+ #
158
+ # @since 0.2.0
159
+ # @api private
160
+ #
161
+ # @see Lotus::Routing::RoutesInspector#FORMATTER
162
+ # @see Lotus::Routing::RoutesInspector#to_s
163
+ def inspect_router(formatter, router, route, base_path)
164
+ router.inspector.to_s(formatter, base_path.join(route.path_for_generation))
165
+ end
166
+ end
167
+ end
168
+ end
data/lotus-router.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Lotus::Router::VERSION
9
9
  spec.authors = ['Luca Guidi']
10
10
  spec.email = ['me@lucaguidi.com']
11
- spec.description = %q{HTTP Router for Lotus}
12
- spec.summary = %q{Ruby HTTP Router for Lotus}
11
+ spec.description = %q{Rack compatible HTTP router for Ruby}
12
+ spec.summary = %q{Rack compatible HTTP router for Ruby and Lotus}
13
13
  spec.homepage = 'http://lotusrb.org'
14
14
  spec.license = 'MIT'
15
15
 
@@ -17,9 +17,10 @@ Gem::Specification.new do |spec|
17
17
  spec.executables = []
18
18
  spec.test_files = spec.files.grep(%r{^(test)/})
19
19
  spec.require_paths = ['lib']
20
+ spec.required_ruby_version = '>= 2.0.0'
20
21
 
21
- spec.add_dependency 'http_router', '~> 0'
22
- spec.add_dependency 'lotus-utils', '~> 0'
22
+ spec.add_dependency 'http_router', '~> 0.11'
23
+ spec.add_dependency 'lotus-utils', '~> 0.3', '>= 0.3.2'
23
24
 
24
25
  spec.add_development_dependency 'bundler', '~> 1.5'
25
26
  spec.add_development_dependency 'minitest', '~> 5'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lotus-router
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-23 00:00:00.000000000 Z
11
+ date: 2014-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http_router
@@ -16,28 +16,34 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '0.11'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '0.11'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: lotus-utils
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '0.3'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 0.3.2
34
37
  type: :runtime
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
38
41
  - - "~>"
39
42
  - !ruby/object:Gem::Version
40
- version: '0'
43
+ version: '0.3'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 0.3.2
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: bundler
43
49
  requirement: !ruby/object:Gem::Requirement
@@ -80,7 +86,7 @@ dependencies:
80
86
  - - "~>"
81
87
  - !ruby/object:Gem::Version
82
88
  version: '10'
83
- description: HTTP Router for Lotus
89
+ description: Rack compatible HTTP router for Ruby
84
90
  email:
85
91
  - me@lucaguidi.com
86
92
  executables: []
@@ -97,12 +103,16 @@ files:
97
103
  - lib/lotus/routing/endpoint_resolver.rb
98
104
  - lib/lotus/routing/http_router.rb
99
105
  - lib/lotus/routing/namespace.rb
106
+ - lib/lotus/routing/parsers.rb
107
+ - lib/lotus/routing/parsing/json_parser.rb
108
+ - lib/lotus/routing/parsing/parser.rb
100
109
  - lib/lotus/routing/resource.rb
101
110
  - lib/lotus/routing/resource/action.rb
102
111
  - lib/lotus/routing/resource/options.rb
103
112
  - lib/lotus/routing/resources.rb
104
113
  - lib/lotus/routing/resources/action.rb
105
114
  - lib/lotus/routing/route.rb
115
+ - lib/lotus/routing/routes_inspector.rb
106
116
  - lotus-router.gemspec
107
117
  homepage: http://lotusrb.org
108
118
  licenses:
@@ -116,7 +126,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
116
126
  requirements:
117
127
  - - ">="
118
128
  - !ruby/object:Gem::Version
119
- version: '0'
129
+ version: 2.0.0
120
130
  required_rubygems_version: !ruby/object:Gem::Requirement
121
131
  requirements:
122
132
  - - ">="
@@ -127,6 +137,6 @@ rubyforge_project:
127
137
  rubygems_version: 2.2.2
128
138
  signing_key:
129
139
  specification_version: 4
130
- summary: Ruby HTTP Router for Lotus
140
+ summary: Rack compatible HTTP router for Ruby and Lotus
131
141
  test_files: []
132
142
  has_rdoc: