lotus-router 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.coveralls.yml +2 -0
- data/.gitignore +5 -13
- data/.travis.yml +5 -0
- data/.yardopts +3 -0
- data/Gemfile +10 -3
- data/README.md +470 -6
- data/Rakefile +10 -1
- data/benchmarks/callable +23 -0
- data/benchmarks/named_routes +72 -0
- data/benchmarks/resource +44 -0
- data/benchmarks/resources +58 -0
- data/benchmarks/routes +67 -0
- data/benchmarks/run.sh +11 -0
- data/benchmarks/utils.rb +56 -0
- data/lib/lotus-router.rb +1 -0
- data/lib/lotus/router.rb +752 -3
- data/lib/lotus/router/version.rb +2 -2
- data/lib/lotus/routing/endpoint.rb +114 -0
- data/lib/lotus/routing/endpoint_resolver.rb +251 -0
- data/lib/lotus/routing/http_router.rb +130 -0
- data/lib/lotus/routing/namespace.rb +86 -0
- data/lib/lotus/routing/resource.rb +73 -0
- data/lib/lotus/routing/resource/action.rb +340 -0
- data/lib/lotus/routing/resource/options.rb +48 -0
- data/lib/lotus/routing/resources.rb +40 -0
- data/lib/lotus/routing/resources/action.rb +123 -0
- data/lib/lotus/routing/route.rb +53 -0
- data/lotus-router.gemspec +16 -12
- data/test/fixtures.rb +193 -0
- data/test/integration/client_error_test.rb +16 -0
- data/test/integration/pass_on_response_test.rb +13 -0
- data/test/named_routes_test.rb +123 -0
- data/test/namespace_test.rb +289 -0
- data/test/new_test.rb +67 -0
- data/test/redirect_test.rb +33 -0
- data/test/resource_test.rb +128 -0
- data/test/resources_test.rb +136 -0
- data/test/routing/endpoint_resolver_test.rb +110 -0
- data/test/routing/resource/options_test.rb +36 -0
- data/test/routing_test.rb +99 -0
- data/test/test_helper.rb +32 -0
- data/test/version_test.rb +7 -0
- metadata +102 -10
@@ -0,0 +1,48 @@
|
|
1
|
+
module Lotus
|
2
|
+
module Routing
|
3
|
+
class Resource
|
4
|
+
# Options for RESTFul resource(s)
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
# @since 0.1.0
|
8
|
+
#
|
9
|
+
# @see Lotus::Router#resource
|
10
|
+
# @see Lotus::Router#resources
|
11
|
+
class Options < Hash
|
12
|
+
# @api private
|
13
|
+
# @since 0.1.0
|
14
|
+
attr_reader :actions
|
15
|
+
|
16
|
+
# Initialize the options for:
|
17
|
+
# * Lotus::Router#resource
|
18
|
+
# * Lotus::Router#resources
|
19
|
+
#
|
20
|
+
# @param actions [Array<Symbol>] the name of the actions
|
21
|
+
# @param options [Hash]
|
22
|
+
# @option options [Hash] :only white list of the default actions
|
23
|
+
# @option options [Hash] :except black list of the default actions
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
# @since 0.1.0
|
27
|
+
#
|
28
|
+
# @see Lotus::Routing::Resource
|
29
|
+
# @see Lotus::Routing::Resources
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
# require 'lotus/router'
|
33
|
+
#
|
34
|
+
# Lotus::Router.new do
|
35
|
+
# resources 'articles', only: [:index]
|
36
|
+
# resource 'profile', except: [:new, :create, :destroy]
|
37
|
+
# end
|
38
|
+
def initialize(actions, options = {})
|
39
|
+
only = Array(options.delete(:only) || actions)
|
40
|
+
except = Array(options.delete(:except))
|
41
|
+
@actions = ( actions & only ) - except
|
42
|
+
|
43
|
+
merge! options
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'lotus/routing/resource'
|
2
|
+
require 'lotus/routing/resources/action'
|
3
|
+
|
4
|
+
module Lotus
|
5
|
+
module Routing
|
6
|
+
# Set of RESTful resources routes
|
7
|
+
# Implementation of Lotus::Router#resources
|
8
|
+
#
|
9
|
+
# @since 0.1.0
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
#
|
13
|
+
# @see Lotus::Router#resources
|
14
|
+
class Resources < Resource
|
15
|
+
# Set of default routes
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
# @since 0.1.0
|
19
|
+
self.actions = [:index, :new, :create, :show, :edit, :update, :destroy]
|
20
|
+
|
21
|
+
# Action class
|
22
|
+
#
|
23
|
+
# @api private
|
24
|
+
# @since 0.1.0
|
25
|
+
self.action = Resources::Action
|
26
|
+
|
27
|
+
# Member action class
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
# @since 0.1.0
|
31
|
+
self.member = Resources::MemberAction
|
32
|
+
|
33
|
+
# Collection action class
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
# @since 0.1.0
|
37
|
+
self.collection = Resources::CollectionAction
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'lotus/utils/string'
|
2
|
+
require 'lotus/utils/path_prefix'
|
3
|
+
require 'lotus/routing/resource'
|
4
|
+
|
5
|
+
module Lotus
|
6
|
+
module Routing
|
7
|
+
class Resources < Resource
|
8
|
+
# Action for RESTful resources
|
9
|
+
#
|
10
|
+
# @since 0.1.0
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
#
|
14
|
+
# @see Lotus::Router#resources
|
15
|
+
class Action < Resource::Action
|
16
|
+
# Ruby namespace where lookup for default subclasses.
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
# @since 0.1.0
|
20
|
+
self.namespace = Resources
|
21
|
+
end
|
22
|
+
|
23
|
+
# Collection action
|
24
|
+
# It implements #collection within a #resources block.
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
# @since 0.1.0
|
28
|
+
# @see Lotus::Router#resources
|
29
|
+
class CollectionAction < Resource::CollectionAction
|
30
|
+
end
|
31
|
+
|
32
|
+
# Member action
|
33
|
+
# It implements #member within a #resources block.
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
# @since 0.1.0
|
37
|
+
# @see Lotus::Router#resources
|
38
|
+
class MemberAction < Resource::MemberAction
|
39
|
+
private
|
40
|
+
def path(path)
|
41
|
+
prefix.join("/:id/#{ path }")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Implementation of common methods for concrete member actions
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
# @since 0.1.0
|
49
|
+
module DefaultMemberAction
|
50
|
+
private
|
51
|
+
def rest_path
|
52
|
+
"/#{ resource_name }/:id"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Index action
|
57
|
+
#
|
58
|
+
# @api private
|
59
|
+
# @since 0.1.0
|
60
|
+
# @see Lotus::Router#resources
|
61
|
+
class Index < Action
|
62
|
+
self.verb = :get
|
63
|
+
end
|
64
|
+
|
65
|
+
# New action
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
# @since 0.1.0
|
69
|
+
# @see Lotus::Router#resources
|
70
|
+
class New < Resource::New
|
71
|
+
end
|
72
|
+
|
73
|
+
# Create action
|
74
|
+
#
|
75
|
+
# @api private
|
76
|
+
# @since 0.1.0
|
77
|
+
# @see Lotus::Router#resources
|
78
|
+
class Create < Resource::Create
|
79
|
+
end
|
80
|
+
|
81
|
+
# Show action
|
82
|
+
#
|
83
|
+
# @api private
|
84
|
+
# @since 0.1.0
|
85
|
+
# @see Lotus::Router#resources
|
86
|
+
class Show < Resource::Show
|
87
|
+
include DefaultMemberAction
|
88
|
+
end
|
89
|
+
|
90
|
+
# Edit action
|
91
|
+
#
|
92
|
+
# @api private
|
93
|
+
# @since 0.1.0
|
94
|
+
# @see Lotus::Router#resources
|
95
|
+
class Edit < Resource::Edit
|
96
|
+
include DefaultMemberAction
|
97
|
+
|
98
|
+
private
|
99
|
+
def rest_path
|
100
|
+
"#{ super }/#{ action_name }"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Update action
|
105
|
+
#
|
106
|
+
# @api private
|
107
|
+
# @since 0.1.0
|
108
|
+
# @see Lotus::Router#resources
|
109
|
+
class Update < Resource::Update
|
110
|
+
include DefaultMemberAction
|
111
|
+
end
|
112
|
+
|
113
|
+
# Destroy action
|
114
|
+
#
|
115
|
+
# @api private
|
116
|
+
# @since 0.1.0
|
117
|
+
# @see Lotus::Router#resources
|
118
|
+
class Destroy < Resource::Destroy
|
119
|
+
include DefaultMemberAction
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'http_router/route'
|
2
|
+
|
3
|
+
module Lotus
|
4
|
+
module Routing
|
5
|
+
# Entry of the routing system
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
#
|
9
|
+
# @since 0.1.0
|
10
|
+
#
|
11
|
+
# @see http://rdoc.info/gems/http_router/HttpRouter/Route
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# require 'lotus/router'
|
15
|
+
#
|
16
|
+
# router = Lotus::Router.new
|
17
|
+
# router.get('/', to: endpoint) # => #<Lotus::Routing::Route:0x007f83083ba028 ...>
|
18
|
+
class Route < HttpRouter::Route
|
19
|
+
# Asks the given resolver to return an endpoint that will be associated
|
20
|
+
# with the other options.
|
21
|
+
#
|
22
|
+
# @param resolver [Lotus::Routing::EndpointResolver, #resolve] this may change
|
23
|
+
# according to the :resolve option passed to Lotus::Router#initialize.
|
24
|
+
#
|
25
|
+
# @param options [Hash] options to customize the route
|
26
|
+
# @option options [Symbol] :as the name we want to use for the route
|
27
|
+
#
|
28
|
+
# @since 0.1.0
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
#
|
32
|
+
# @see Lotus::Router#initialize
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# require 'lotus/router'
|
36
|
+
#
|
37
|
+
# router = Lotus::Router.new
|
38
|
+
# router.get('/', to: endpoint, as: :home_page).name # => :home_page
|
39
|
+
#
|
40
|
+
# router.path(:home_page) # => '/'
|
41
|
+
def generate(resolver, options = {}, &endpoint)
|
42
|
+
self.to = resolver.resolve(options, &endpoint)
|
43
|
+
self.name = options[:as].to_sym if options[:as]
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def to=(dest = nil, &blk)
|
49
|
+
self.to dest, &blk
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lotus-router.gemspec
CHANGED
@@ -4,20 +4,24 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'lotus/router/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'lotus-router'
|
8
8
|
spec.version = Lotus::Router::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.
|
12
|
-
spec.
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
9
|
+
spec.authors = ['Luca Guidi']
|
10
|
+
spec.email = ['me@lucaguidi.com']
|
11
|
+
spec.description = %q{HTTP Router for Lotus}
|
12
|
+
spec.summary = %q{Ruby HTTP Router for Lotus}
|
13
|
+
spec.homepage = 'http://lotusrb.org'
|
14
|
+
spec.license = 'MIT'
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
17
|
-
spec.executables =
|
18
|
-
spec.test_files = spec.files.grep(%r{^(test
|
19
|
-
spec.require_paths = [
|
17
|
+
spec.executables = []
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.
|
22
|
-
spec.
|
21
|
+
spec.add_dependency 'http_router', '~> 0'
|
22
|
+
spec.add_dependency 'lotus-utils', '~> 0'
|
23
|
+
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
25
|
+
spec.add_development_dependency 'minitest', '~> 5'
|
26
|
+
spec.add_development_dependency 'rake', '~> 10'
|
23
27
|
end
|
data/test/fixtures.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
class TestEndpoint
|
2
|
+
def call(env)
|
3
|
+
'Hi from TestEndpoint!'
|
4
|
+
end
|
5
|
+
end #TestEndpoint
|
6
|
+
|
7
|
+
class TestController
|
8
|
+
class Show
|
9
|
+
def call(env)
|
10
|
+
'Hi from Test::Show!'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end #TestController
|
14
|
+
|
15
|
+
class TestApp
|
16
|
+
class TestEndpoint
|
17
|
+
def call(env)
|
18
|
+
'Hi from TestApp::TestEndpoint!'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Test2Controller
|
23
|
+
class Show
|
24
|
+
def call(env)
|
25
|
+
'Hi from TestApp::Test2Controller::Show!'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end # TestApp
|
30
|
+
|
31
|
+
class AvatarController
|
32
|
+
class New
|
33
|
+
def call(env)
|
34
|
+
[200, {}, ['Avatar::New']]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Create
|
39
|
+
def call(env)
|
40
|
+
[200, {}, ['Avatar::Create']]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Show
|
45
|
+
def call(env)
|
46
|
+
[200, {}, ['Avatar::Show']]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Edit
|
51
|
+
def call(env)
|
52
|
+
[200, {}, ['Avatar::Edit']]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Update
|
57
|
+
def call(env)
|
58
|
+
[200, {}, ['Avatar::Update']]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Destroy
|
63
|
+
def call(env)
|
64
|
+
[200, {}, ['Avatar::Destroy']]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end # AvatarController
|
68
|
+
|
69
|
+
class ProfileController
|
70
|
+
class Show
|
71
|
+
def call(env)
|
72
|
+
[200, {}, ['Profile::Show']]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class New
|
77
|
+
def call(env)
|
78
|
+
[200, {}, ['Profile::New']]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class Create
|
83
|
+
def call(env)
|
84
|
+
[200, {}, ['Profile::Create']]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Edit
|
89
|
+
def call(env)
|
90
|
+
[200, {}, ['Profile::Edit']]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class Update
|
95
|
+
def call(env)
|
96
|
+
[200, {}, ['Profile::Update']]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class Destroy
|
101
|
+
def call(env)
|
102
|
+
[200, {}, ['Profile::Destroy']]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class Activate
|
107
|
+
def call(env)
|
108
|
+
[200, {}, ['Profile::Activate']]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
class Keys
|
113
|
+
def call(env)
|
114
|
+
[200, {}, ['Profile::Keys']]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end # ProfileController
|
118
|
+
|
119
|
+
class FlowersController
|
120
|
+
class Index
|
121
|
+
def call(env)
|
122
|
+
[200, {}, ['Flowers::Index']]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class New
|
127
|
+
def call(env)
|
128
|
+
[200, {}, ['Flowers::New']]
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class Create
|
133
|
+
def call(env)
|
134
|
+
[200, {}, ['Flowers::Create']]
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class Show
|
139
|
+
def call(env)
|
140
|
+
[200, {}, ['Flowers::Show ' + env['router.params'][:id]]]
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class Edit
|
145
|
+
def call(env)
|
146
|
+
[200, {}, ['Flowers::Edit ' + env['router.params'][:id]]]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class Update
|
151
|
+
def call(env)
|
152
|
+
[200, {}, ['Flowers::Update ' + env['router.params'][:id]]]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class Destroy
|
157
|
+
def call(env)
|
158
|
+
[200, {}, ['Flowers::Destroy ' + env['router.params'][:id]]]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end # FlowersController
|
162
|
+
|
163
|
+
class KeyboardsController
|
164
|
+
class Index
|
165
|
+
def call(env)
|
166
|
+
[200, {}, ['Keyboards::Index']]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class Create
|
171
|
+
def call(env)
|
172
|
+
[200, {}, ['Keyboards::Create']]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
class Edit
|
177
|
+
def call(env)
|
178
|
+
[200, {}, ['Keyboards::Edit ' + env['router.params'][:id]]]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
class Search
|
183
|
+
def call(env)
|
184
|
+
[200, {}, ['Keyboards::Search']]
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
class Screenshot
|
189
|
+
def call(env)
|
190
|
+
[200, {}, ['Keyboards::Screenshot ' + env['router.params'][:id]]]
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end # KeyboardsController
|