hanami-router 2.0.0.alpha1 → 2.0.0.alpha2

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.
@@ -1,427 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "hanami/utils/string"
4
- require "hanami/utils/path_prefix"
5
- require "hanami/utils/class_attribute"
6
- require "hanami/routing/resource/nested"
7
-
8
- module Hanami
9
- module Routing
10
- class Resource
11
- # Action for RESTful resource
12
- #
13
- # @since 0.1.0
14
- #
15
- # @api private
16
- #
17
- # @see Hanami::Router#resource
18
- class Action
19
- include Utils::ClassAttribute
20
-
21
- # Nested routes separator
22
- #
23
- # @api private
24
- # @since 0.4.0
25
- NESTED_ROUTES_SEPARATOR = "/"
26
-
27
- # Ruby namespace where lookup for default subclasses.
28
- #
29
- # @api private
30
- # @since 0.1.0
31
- class_attribute :namespace
32
- self.namespace = Resource
33
-
34
- # Accepted HTTP verb
35
- #
36
- # @api private
37
- # @since 0.1.0
38
- class_attribute :verb
39
- self.verb = :get
40
-
41
- # Separator for named routes
42
- #
43
- # @api private
44
- # @since 0.2.0
45
- class_attribute :named_route_separator
46
- self.named_route_separator = "_"
47
-
48
- # Generate an action for the given router
49
- #
50
- # @param router [Hanami::Router]
51
- # @param action [Hanami::Routing::Resource::Action]
52
- # @param options [Hash]
53
- # @param resource [Hanami::Routing::Resource, Hanami::Routing::Resources]
54
- #
55
- # @api private
56
- #
57
- # @since 0.1.0
58
- def self.generate(router, action, options = {}, resource = nil)
59
- class_for(action).new(router, options, resource)
60
- end
61
-
62
- # Initialize an action
63
- #
64
- # @param router [Hanami::Router]
65
- # @param options [Hash]
66
- # @param resource [Hanami::Routing::Resource, Hanami::Routing::Resources]
67
- # @param blk [Proc]
68
- #
69
- # @api private
70
- #
71
- # @since 0.1.0
72
- def initialize(router, options = {}, resource = nil, &blk)
73
- @router = router
74
- @options = options
75
- @resource = resource
76
- generate(&blk)
77
- end
78
-
79
- # Generate an action for the given router
80
- #
81
- # @param blk [Proc]
82
- #
83
- # @api private
84
- #
85
- # @since 0.1.0
86
- def generate(&blk)
87
- @router.send verb, path, to: endpoint, as: as, namespace: namespace, configuration: configuration
88
- instance_eval(&blk) if block_given?
89
- end
90
-
91
- # Resource name
92
- #
93
- # @return [String]
94
- #
95
- # @api private
96
- # @since 0.1.0
97
- #
98
- # @example
99
- # require 'hanami/router'
100
- #
101
- # Hanami::Router.new do
102
- # resource 'identity'
103
- # end
104
- #
105
- # # 'identity' is the name passed in the @options
106
- def resource_name
107
- @resource_name ||= @options[:name].to_s
108
- end
109
-
110
- # Prefix
111
- #
112
- # @api private
113
- # @since 2.0.0
114
- def prefix
115
- @prefix ||= Utils::PathPrefix.new(@options[:prefix])
116
- end
117
-
118
- # Namespace
119
- #
120
- # @api private
121
- # @since 2.0.0
122
- def namespace
123
- @namespace ||= @options[:namespace]
124
- end
125
-
126
- # Configuration
127
- #
128
- # @api private
129
- # @since 2.0.0
130
- def configuration
131
- @configuration ||= @options[:configuration]
132
- end
133
-
134
- # Load a subclass, according to the given action name
135
- #
136
- # @param action [String] the action name
137
- #
138
- # @example
139
- # Hanami::Routing::Resource::Action.send(:class_for, 'New') # =>
140
- # Hanami::Routing::Resource::New
141
- #
142
- # @api private
143
- # @since 0.1.0
144
- def self.class_for(action)
145
- Utils::Class.load!(Utils::String.classify(action), namespace)
146
- end
147
-
148
- private_class_method :class_for
149
-
150
- # Accepted HTTP verb
151
- #
152
- # @see Hanami::Routing::Resource::Action.verb
153
- #
154
- # @api private
155
- # @since 0.1.0
156
- def verb
157
- self.class.verb
158
- end
159
-
160
- # The prefixed relative URL
161
- #
162
- # @example
163
- # require "hanami/router"
164
- #
165
- # Hanami::Router.new do
166
- # resources "flowers"
167
- #
168
- # prefix "animals" do
169
- # resources "mammals"
170
- # end
171
- # end
172
- #
173
- # # It will generate paths like "/flowers", "/flowers/:id" ..
174
- # # It will generate paths like "/animals/mammals", "/animals/mammals/:id" ..
175
- #
176
- # @api private
177
- # @since 0.1.0
178
- def path
179
- rest_path
180
- end
181
-
182
- # The URL relative path
183
- #
184
- # @example
185
- # '/flowers'
186
- # '/flowers/new'
187
- # '/flowers/:id'
188
- #
189
- # @api private
190
- # @since 0.1.0
191
- def rest_path
192
- prefix.join(_nested_rest_path || resource_name.to_s)
193
- end
194
-
195
- # The prefixed name of the action within the whole context of the router.
196
- #
197
- # @example
198
- # require "hanami/router"
199
- #
200
- # Hanami::Router.new do
201
- # resources "flowers"
202
- #
203
- # prefix "animals" do
204
- # resources "mammals"
205
- # end
206
- # end
207
- #
208
- # # It will generate named routes like :flowers, :new_flowers ..
209
- # # It will generate named routes like :animals_mammals, :animals_new_mammals ..
210
- #
211
- # @api private
212
- # @since 0.1.0
213
- def as
214
- prefix.relative_join(_singularized_as, self.class.named_route_separator).to_sym
215
- end
216
-
217
- # The name of the RESTful action.
218
- #
219
- # @example
220
- # 'index'
221
- # 'new'
222
- # 'create'
223
- #
224
- # @api private
225
- # @since 0.1.0
226
- def action_name
227
- Utils::String.transform(self.class.name, :demodulize, :downcase)
228
- end
229
-
230
- # A string that represents the endpoint to be loaded.
231
- # It is composed by controller and action name.
232
- #
233
- # @see Hanami::Routing::Resource::Action#separator
234
- #
235
- # @example
236
- # 'flowers#index'
237
- #
238
- # @api private
239
- # @since 0.1.0
240
- def endpoint
241
- [controller_name, action_name].join separator
242
- end
243
-
244
- # Separator between controller and action name
245
- #
246
- # @see Hanami::Routing::EndpointResolver#separator
247
- #
248
- # @example
249
- # '#' # default
250
- #
251
- # @api private
252
- # @since 0.1.0
253
- def separator
254
- @options[:separator]
255
- end
256
-
257
- # Resource controller name
258
- #
259
- # @example
260
- # Hanami::Router.new do
261
- # resources 'flowers', controller: 'rocks'
262
- # end
263
- #
264
- # # It will mount path 'flowers/new' to Rocks::New instead of Flowers::New
265
- # # Same for other action names
266
- #
267
- # @api private
268
- # @since 0.4.0
269
- def controller_name
270
- @options[:controller] || resource_name
271
- end
272
-
273
- private
274
-
275
- # Singularize as (helper route)
276
- #
277
- # @api private
278
- # @since 0.4.0
279
- def _singularized_as
280
- name = @options[:as] ? @options[:as].to_s : resource_name
281
- name.split(NESTED_ROUTES_SEPARATOR).map do |n|
282
- @router.inflector.singularize(n)
283
- end
284
- end
285
-
286
- # Create nested rest path
287
- #
288
- # @api private
289
- # @since 0.4.0
290
- def _nested_rest_path
291
- Nested.new(resource_name, @resource).to_path
292
- end
293
- end
294
-
295
- # Collection action
296
- # It implements #collection within a #resource block.
297
- #
298
- # @api private
299
- # @since 0.1.0
300
- # @see Hanami::Router#resource
301
- class CollectionAction < Action
302
- # @since 0.1.0
303
- # @api private
304
- def generate(&blk)
305
- instance_eval(&blk) if block_given?
306
- end
307
-
308
- # @since 0.1.0
309
- # @api private
310
- def method_missing(method_name, *args) # rubocop:disable Style/MethodMissingSuper
311
- verb = method_name
312
- action_name = Utils::PathPrefix.new(args.first).relative_join(nil)
313
-
314
- @router.__send__ verb, path(action_name),
315
- to: endpoint(action_name), as: as(action_name),
316
- namespace: namespace, configuration: configuration
317
- end
318
-
319
- def respond_to_missing?(method_name, include_all)
320
- @router.respond_to?(method_name, include_all)
321
- end
322
-
323
- private
324
-
325
- # @since 0.1.0
326
- # @api private
327
- def path(action_name)
328
- rest_path.join(action_name)
329
- end
330
-
331
- # @since 0.1.0
332
- # @api private
333
- def endpoint(action_name)
334
- [controller_name, action_name].join separator
335
- end
336
-
337
- # @since 0.1.0
338
- # @api private
339
- def as(action_name)
340
- [action_name, super()].join(self.class.named_route_separator).to_sym
341
- end
342
- end
343
-
344
- # Collection action
345
- # It implements #member within a #resource block.
346
- #
347
- # @api private
348
- # @since 0.1.0
349
- # @see Hanami::Router#resource
350
- class MemberAction < CollectionAction
351
- end
352
-
353
- # Implementation of common methods for concrete member actions
354
- #
355
- # @api private
356
- # @since 0.1.0
357
- module DefaultMemberAction
358
- private
359
-
360
- # @since 0.1.0
361
- # @api private
362
- def path
363
- rest_path.join(action_name)
364
- end
365
-
366
- # @since 0.1.0
367
- # @api private
368
- def as
369
- [action_name, super].join(self.class.named_route_separator).to_sym
370
- end
371
- end
372
-
373
- # New action
374
- #
375
- # @api private
376
- # @since 0.1.0
377
- # @see Hanami::Router#resource
378
- class New < Action
379
- include DefaultMemberAction
380
- end
381
-
382
- # Create action
383
- #
384
- # @api private
385
- # @since 0.1.0
386
- # @see Hanami::Router#resource
387
- class Create < Action
388
- self.verb = :post
389
- end
390
-
391
- # Show action
392
- #
393
- # @api private
394
- # @since 0.1.0
395
- # @see Hanami::Router#resource
396
- class Show < Action
397
- end
398
-
399
- # Edit action
400
- #
401
- # @api private
402
- # @since 0.1.0
403
- # @see Hanami::Router#resource
404
- class Edit < Action
405
- include DefaultMemberAction
406
- end
407
-
408
- # Update action
409
- #
410
- # @api private
411
- # @since 0.1.0
412
- # @see Hanami::Router#resource
413
- class Update < Action
414
- self.verb = :patch
415
- end
416
-
417
- # Destroy action
418
- #
419
- # @api private
420
- # @since 0.1.0
421
- # @see Hanami::Router#resource
422
- class Destroy < Action
423
- self.verb = :delete
424
- end
425
- end
426
- end
427
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Hanami
4
- module Routing
5
- class Resource
6
- # Helper class to calculate nested path
7
- #
8
- # @api private
9
- # @since 0.4.0
10
- class Nested
11
- # @api private
12
- # @since 0.4.0
13
- SEPARATOR = "/"
14
-
15
- # @api private
16
- # @since 0.4.0
17
- def initialize(resource_name, resource)
18
- @resource_name = resource_name.to_s.split(SEPARATOR)
19
- @resource = resource
20
- @path = []
21
- _calculate(@resource_name.dup, @resource)
22
- end
23
-
24
- # @api private
25
- # @since 0.4.0
26
- def to_path
27
- @path.reverse!.pop
28
- @resource_name.zip(@path).flatten.join
29
- end
30
-
31
- private
32
-
33
- # @api private
34
- # @since 0.4.0
35
- def _calculate(param_wildcard, resource = nil)
36
- return if resource.nil?
37
-
38
- @path << resource.wildcard_param(param_wildcard.pop)
39
- _calculate(param_wildcard, resource.parent)
40
- end
41
- end
42
- end
43
- end
44
- end