modular_routes 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5341830eca8ac468d9bf1843691214bf42e7806a9dedee7aa363227b39f2fb1a
4
- data.tar.gz: d0ce8a5bd66d31555ab827efafaec86e512939ba8c21470e6738ede33da9a200
3
+ metadata.gz: 735442d6f4629c4b130223eeffdc78e817d2dc183acb01cf541a2174411cf02b
4
+ data.tar.gz: 9d03465ec7092e08236ece0e73f3fd90d6cf43832ea581e7c0f465f072f4cc7c
5
5
  SHA512:
6
- metadata.gz: f8ad0fa09d007407fb020109a93b33d7cf6c6b21a041759d5c556b76cb15cfd8c109ea10dac1b9d670d52cee9d1ff43dfe0c9357e88cdcffea3b92a46032d11a
7
- data.tar.gz: c4581eede9b12a585ae8d409ad91a5405e4fbf4b040187aa1a41cd94f3599346c5ab0d5e53b709a4d2a37a11f6a93965e1c25da6c2098a1297295efdf7bcb3a2
6
+ metadata.gz: 4ebb16561f04f2e6648ea42a7eb29cb2077f8fd6b0e8bf35a28e655d7d39cd0983e9d181612e7d52305bd73acd659157de400929e16d8801148d64dc197767b7
7
+ data.tar.gz: 3c7f422084864aaf10ea89fbe62bd55158d4947df249f07c4e111b3fb2fb4de40c82453984e92d5a837a7242ec200573f15282def879cf7a9f078496e4c20da7
data/CHANGELOG.md CHANGED
@@ -1,3 +1,30 @@
1
+ ## [v0.3.0] - 2021-08-30
2
+
3
+ **NEW**
4
+
5
+ - `root` helper will raise a syntax error indicating that it should be used outside of `modular_routes` block.
6
+
7
+ - `concern` and `concerns` support:
8
+
9
+ ```ruby
10
+ modular_routes do
11
+ concern :commentable do
12
+ resource :comments
13
+ end
14
+
15
+ concern :activatable do
16
+ member do
17
+ put :activate
18
+ put :deactivate
19
+ end
20
+ end
21
+
22
+ resources :articles, concerns: :activatable do
23
+ concerns :commentable
24
+ end
25
+ end
26
+ ```
27
+
1
28
  ## [v0.2.0] - 2021-07-21
2
29
 
3
30
  **REMOVED**
@@ -9,11 +36,11 @@
9
36
  - `modular_routes` helper was added to fix the problems encountered on the previous helper. Check the example below:
10
37
 
11
38
  ```ruby
12
- modular_routes do
13
- resources :books
39
+ modular_routes do
40
+ resources :books
14
41
 
15
- get :about, to: "about#index"
16
- end
42
+ get :about, to: "about#index"
43
+ end
17
44
  ```
18
45
 
19
46
  The idea was to bring simplicity and proximity to what you already write in your routes file.
@@ -21,9 +48,9 @@
21
48
  - `namespace` support`
22
49
 
23
50
  ```ruby
24
- namespace :v1 do
25
- resources :books
26
- end
51
+ namespace :v1 do
52
+ resources :books
53
+ end
27
54
  ```
28
55
 
29
56
  It falls back to Rails default behavior.
@@ -31,13 +58,13 @@
31
58
  - `scope` support
32
59
 
33
60
  ```ruby
34
- scope :v1 do
35
- resources :books
36
- end
61
+ scope :v1 do
62
+ resources :books
63
+ end
37
64
 
38
- scope module: :v1 do
39
- resources :books
40
- end
65
+ scope module: :v1 do
66
+ resources :books
67
+ end
41
68
  ```
42
69
 
43
70
  It falls back to Rails default behavior. In this example it recognizes `/v1/books` and `/books` expecting `BooksController` and `V1::BooksController` respectively.
@@ -45,11 +72,11 @@
45
72
  - Nested resources support
46
73
 
47
74
  ```ruby
48
- modular_routes do
49
- resources :books do
50
- resources :comments
51
- end
75
+ modular_routes do
76
+ resources :books do
77
+ resources :comments
52
78
  end
79
+ end
53
80
  ```
54
81
 
55
82
  It recognizes paths like `/books/1/comments/2`.
@@ -57,9 +84,9 @@
57
84
  - Standalone (non-resourceful) routes
58
85
 
59
86
  ```ruby
60
- modular_routes do
61
- get :about, to: "about#index"
62
- end
87
+ modular_routes do
88
+ get :about, to: "about#index"
89
+ end
63
90
  ```
64
91
 
65
92
  It expects `About::IndexController` to exist in `controllers/about/index_controller.rb`. They don't belong to a resourceful scope.
data/README.md CHANGED
@@ -71,7 +71,7 @@ end
71
71
 
72
72
  The reason I don't like this approach is that you can end up with a lot of code that are not related to each other in the same file. You can still have it all organized but I believe that it could be better.
73
73
 
74
- [DHH](http://jeromedalbert.com/how-dhh-organizes-his-rails-controllers/) prefers to keep the RESTful actions (index, new, edit, show, create, update, destroy) inside the same controller and the custom ones in dedicated controllers.
74
+ [DHH](http://jeromedalbert.com/how-dhh-organizes-his-rails-controllers/) prefers to keep the RESTful actions (index, new, edit, show, create, update, destroy) inside the same controller and the custom ones in dedicated controllers but represented as RESTful actions.
75
75
 
76
76
  One way of representing that would be
77
77
 
@@ -79,8 +79,8 @@ One way of representing that would be
79
79
  # routes.rb
80
80
 
81
81
  resources :articles do
82
- get :stats, on: :collection, controller: 'articles/stats'
83
- post :archive, on: :member, controller: 'articles/archive'
82
+ get :stats, on: :collection, to: 'articles/stats#show'
83
+ post :archive, on: :member, to: 'articles/archive#create'
84
84
  end
85
85
 
86
86
  # articles_controller.rb
@@ -100,14 +100,14 @@ end
100
100
  # articles/archive_controller.rb
101
101
 
102
102
  class Articles::ArchiveController
103
- def archive
103
+ def create
104
104
  end
105
105
  end
106
106
 
107
107
  # articles/stats_controller.rb
108
108
 
109
109
  class Articles::StatsController
110
- def stats
110
+ def show
111
111
  end
112
112
  end
113
113
  ```
@@ -263,7 +263,7 @@ The output routes for the code above would be
263
263
  | GET | /articles/:id/edit | articles/edit#call | edit_articles_path(:id) |
264
264
  | PATCH/PUT | /articles/:id | articles/update#call | articles_path(:id) |
265
265
  | DELETE | /articles/:id | articles/destroy#call | articles_path(:id) |
266
- | POST | /articles/stats | articles/stats#call | stats_articles_path(:id) |
266
+ | POST | /articles/stats | articles/stats#call | stats_articles_path |
267
267
  | POST | /articles/:id/archive | articles/archive#call | archive_article_path(:id) |
268
268
 
269
269
  ### Restricting routes
@@ -314,15 +314,15 @@ end
314
314
 
315
315
  The output routes for that would be
316
316
 
317
- | HTTP Verb | Path | Controller#Action | Named Route Helper |
318
- | --------- | -------------------------------- | -------------------------- | ------------------------------- |
319
- | GET | /books/:book_id/reviews | books/reviews/index#call | books_reviews_path |
320
- | GET | /books/:book_id/reviews/new | books/reviews/new#call | new_articles_reviews_path |
321
- | POST | /books/:book_id/reviews | books/reviews/create#call | books_reviews_path |
322
- | GET | /books/:book_id/reviews/:id | books/reviews/show#call | books_reviews_path(:id) |
323
- | GET | /books/:book_id/reviews/:id/edit | books/reviews/edit#call | edit_articles_reviews_path(:id) |
324
- | PATCH/PUT | /books/:book_id/reviews/:id | books/reviews/update#call | books_reviews_path(:id) |
325
- | DELETE | /books/:book_id/reviews/:id | books/reviews/destroy#call | books_reviews_path(:id) |
317
+ | HTTP Verb | Path | Controller#Action | Named Route Helper |
318
+ | --------- | -------------------------------- | -------------------------- | -------------------------- |
319
+ | GET | /books/:book_id/reviews | books/reviews/index#call | book_reviews_path |
320
+ | GET | /books/:book_id/reviews/new | books/reviews/new#call | new_book_review_path |
321
+ | POST | /books/:book_id/reviews | books/reviews/create#call | book_reviews_path |
322
+ | GET | /books/:book_id/reviews/:id | books/reviews/show#call | book_review_path(:id) |
323
+ | GET | /books/:book_id/reviews/:id/edit | books/reviews/edit#call | edit_book_review_path(:id) |
324
+ | PATCH/PUT | /books/:book_id/reviews/:id | books/reviews/update#call | book_review_path(:id) |
325
+ | DELETE | /books/:book_id/reviews/:id | books/reviews/destroy#call | book_review_path(:id) |
326
326
 
327
327
  ### Non-resourceful routes (standalone)
328
328
 
@@ -374,15 +374,60 @@ modular_routes do
374
374
  end
375
375
  ```
376
376
 
377
- | HTTP Verb | Path | Controller#Action | Named Route Helper |
378
- | --------- | ------------------ | --------------------- | ------------------- |
379
- | GET | /v1/books | v1/books/index#call | books_path |
380
- | GET | /v1/books/new | v1/books/new#call | new_book_path |
381
- | POST | /v1/books | v1/books/create#call | books_path |
382
- | GET | /v1/books/:id | v1/books/show#call | book_path(:id) |
383
- | GET | /v1/books/:id/edit | v1/books/edit#call | edit_book_path(:id) |
384
- | PATCH/PUT | /v1/books/:id | v1/books/update#call | book_path(:id) |
385
- | DELETE | /v1/books/:id | v1/books/destroy#call | book_path(:id) |
377
+ | HTTP Verb | Path | Controller#Action | Named Route Helper |
378
+ | --------- | ------------------ | --------------------- | ---------------------- |
379
+ | GET | /v1/books | v1/books/index#call | v1_books_path |
380
+ | GET | /v1/books/new | v1/books/new#call | new_v1_book_path |
381
+ | POST | /v1/books | v1/books/create#call | v1_books_path |
382
+ | GET | /v1/books/:id | v1/books/show#call | v1_book_path(:id) |
383
+ | GET | /v1/books/:id/edit | v1/books/edit#call | edit_v1_book_path(:id) |
384
+ | PATCH/PUT | /v1/books/:id | v1/books/update#call | v1_book_path(:id) |
385
+ | DELETE | /v1/books/:id | v1/books/destroy#call | v1_book_path(:id) |
386
+
387
+ ### Routing concerns
388
+
389
+ When you want to reuse route declarations that are usually associated with a common behavior, you can use concerns declaring blocks like:
390
+
391
+ ```ruby
392
+ concern :commentable do
393
+ resource :comments
394
+ end
395
+
396
+ concern :activatable do
397
+ member do
398
+ put :activate
399
+ put :deactivate
400
+ end
401
+ end
402
+ ```
403
+
404
+ To use it you can pass it through resource(s) options or calling `concerns` helper inside of a resource(s) block:
405
+
406
+ ```ruby
407
+ resources :articles, concerns: :commentable
408
+
409
+ resources :articles, concerns: [:activatable]
410
+
411
+ # or
412
+
413
+ resources :articles, concerns: :activatable do
414
+ concerns :commentable
415
+ end
416
+ ```
417
+
418
+ The output of that would be:
419
+
420
+ | HTTP Verb | Path | Controller#Action | Named Route Helper |
421
+ | --------- | --------------------------------------- | ------------------------------ | ------------------------------------------- |
422
+ | GET | /articles/:id/activate | articles/activate#call | activate_article_path |
423
+ | GET | /articles/:id/deactivate | articles/deactivate#call | deactivate_article_path |
424
+ | GET | /articles/:article_id/comments | articles/comments/index#call | article_comments_path(:article_id) |
425
+ | GET | /articles/:article_id/comments/new | articles/comments/new#call | new_article_comment_path (:article_id) |
426
+ | POST | /articles/:article_id/comments | articles/comments/create#call | article_comments_path(:article_id) |
427
+ | GET | /articles/:article_id/comments/:id | articles/comments/show#call | article_comment_path(:article_id, :id) |
428
+ | GET | /articles/:article_id/comments/:id/edit | articles/comments/edit#call | edit_article_comment_path(:article_id, :id) |
429
+ | PATCH/PUT | /articles/:article_id/comments/:id | articles/comments/update#call | article_comment_path(:article_id, :id) |
430
+ | DELETE | /articles/:article_id/comments/:id | articles/comments/destroy#call | article_comment_path(:article_id, :id) |
386
431
 
387
432
  ### API mode
388
433
 
@@ -25,6 +25,19 @@ module ModularRoutes
25
25
  end
26
26
  end
27
27
 
28
+ def root(*, **)
29
+ raise SyntaxError, "You must call `root` outside of `modular_routes` block"
30
+ end
31
+
32
+ def concerns(names)
33
+ raise SyntaxError, "You must call `concerns` inside of a resource block" unless current_scope
34
+
35
+ Array(names).each do |name|
36
+ concern = Routable.for(:concerns, name)
37
+ current_scope.add(concern)
38
+ end
39
+ end
40
+
28
41
  def collection(&block)
29
42
  apply_inner_scope(:collection, &block)
30
43
  end
@@ -41,6 +54,10 @@ module ModularRoutes
41
54
  apply_scopable(:namespace, namespace_name, options, &block)
42
55
  end
43
56
 
57
+ def concern(concern_name, **options, &block)
58
+ apply_scopable(:concern, concern_name, options, &block)
59
+ end
60
+
44
61
  def scope(*args, **options, &block)
45
62
  apply_scopable(:scope, args, options, &block)
46
63
  end
@@ -80,7 +97,7 @@ module ModularRoutes
80
97
  block&.call
81
98
 
82
99
  @scopes.pop
83
- @routes.unshift(scopable) unless current_scope
100
+ @routes.push(scopable) unless current_scope
84
101
  end
85
102
 
86
103
  private def apply_inner_scope(type)
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ModularRoutes
4
+ module Routable
5
+ class Concerns
6
+ def initialize(name)
7
+ @name = name
8
+ end
9
+
10
+ def apply(mapper)
11
+ mapper.concerns(@name)
12
+ end
13
+ end
14
+
15
+ private_constant :Concerns
16
+ end
17
+ end
@@ -7,6 +7,7 @@ module ModularRoutes
7
7
  when :standalone then Standalone.new(*args)
8
8
  when :non_restful then NonRestful.new(*args)
9
9
  when :restful then Restful.new(*args)
10
+ when :concerns then Concerns.new(*args)
10
11
  else raise NotImplementedError
11
12
  end
12
13
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ModularRoutes
4
+ module Scopable
5
+ class Concern
6
+ def initialize(name, options)
7
+ @name = name
8
+ @options = options.except(:api_only)
9
+
10
+ @children = []
11
+ end
12
+
13
+ def add(route_or_scope)
14
+ @children << route_or_scope
15
+ end
16
+
17
+ def resource?
18
+ true
19
+ end
20
+
21
+ def apply(mapper)
22
+ block = proc do
23
+ @children.each { |route_or_scope| route_or_scope.apply(mapper) }
24
+ end
25
+
26
+ mapper.concern(@name, block)
27
+ end
28
+ end
29
+
30
+ private_constant :Concern
31
+ end
32
+ end
@@ -13,6 +13,7 @@ module ModularRoutes
13
13
  @api_only = options.delete(:api_only)
14
14
  @only = options.delete(:only) { default_actions }
15
15
  @except = options.delete(:except)
16
+ @concerns = Array(options.delete(:concerns))
16
17
  @options = { module: name, only: [] }.merge(options)
17
18
  end
18
19
 
@@ -31,6 +32,8 @@ module ModularRoutes
31
32
  def apply(mapper)
32
33
  mapper.public_send(resource_type, @name, @options) do
33
34
  @children.each { |route_or_scope| route_or_scope.apply(mapper) }
35
+
36
+ apply_concerns(mapper)
34
37
  end
35
38
 
36
39
  apply_restful_actions(mapper)
@@ -55,6 +58,12 @@ module ModularRoutes
55
58
  Routable.for(:restful, action, self).apply(mapper)
56
59
  end
57
60
  end
61
+
62
+ private def apply_concerns(mapper)
63
+ @concerns.each do |concern|
64
+ Routable.for(:concerns, concern).apply(mapper)
65
+ end
66
+ end
58
67
  end
59
68
 
60
69
  private_constant :Resource
@@ -8,6 +8,7 @@ module ModularRoutes
8
8
  when :resources then Resource.new(*args)
9
9
  when :resource then SingleResource.new(*args)
10
10
  when :scope then Scope.new(*args)
11
+ when :concern then Concern.new(*args)
11
12
  else raise NotImplementedError
12
13
  end
13
14
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ModularRoutes
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
@@ -5,10 +5,12 @@ require "action_dispatch"
5
5
  require_relative "modular_routes/builder"
6
6
  require_relative "modular_routes/extension"
7
7
  require_relative "modular_routes/routable"
8
+ require_relative "modular_routes/routable/concerns"
8
9
  require_relative "modular_routes/routable/non_restful"
9
10
  require_relative "modular_routes/routable/restful"
10
11
  require_relative "modular_routes/routable/standalone"
11
12
  require_relative "modular_routes/scopable"
13
+ require_relative "modular_routes/scopable/concern"
12
14
  require_relative "modular_routes/scopable/namespace"
13
15
  require_relative "modular_routes/scopable/resource"
14
16
  require_relative "modular_routes/scopable/scope"
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
 
17
17
  spec.metadata["homepage_uri"] = spec.homepage
18
18
  spec.metadata["source_code_uri"] = spec.homepage
19
- spec.metadata["changelog_uri"] = spec.homepage
19
+ spec.metadata["changelog_uri"] = "https://github.com/vitoravelino/modular_routes/blob/main/CHANGELOG.md"
20
20
 
21
21
  # Specify which files should be added to the gem when it is released.
22
22
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: modular_routes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vítor Avelino
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-21 00:00:00.000000000 Z
11
+ date: 2021-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -148,10 +148,12 @@ files:
148
148
  - lib/modular_routes/builder.rb
149
149
  - lib/modular_routes/extension.rb
150
150
  - lib/modular_routes/routable.rb
151
+ - lib/modular_routes/routable/concerns.rb
151
152
  - lib/modular_routes/routable/non_restful.rb
152
153
  - lib/modular_routes/routable/restful.rb
153
154
  - lib/modular_routes/routable/standalone.rb
154
155
  - lib/modular_routes/scopable.rb
156
+ - lib/modular_routes/scopable/concern.rb
155
157
  - lib/modular_routes/scopable/namespace.rb
156
158
  - lib/modular_routes/scopable/resource.rb
157
159
  - lib/modular_routes/scopable/scope.rb
@@ -163,7 +165,7 @@ licenses: []
163
165
  metadata:
164
166
  homepage_uri: https://github.com/vitoravelino/modular_routes
165
167
  source_code_uri: https://github.com/vitoravelino/modular_routes
166
- changelog_uri: https://github.com/vitoravelino/modular_routes
168
+ changelog_uri: https://github.com/vitoravelino/modular_routes/blob/main/CHANGELOG.md
167
169
  post_install_message:
168
170
  rdoc_options: []
169
171
  require_paths: