ruby_routes 2.1.0 → 2.3.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +232 -162
  3. data/lib/ruby_routes/constant.rb +137 -18
  4. data/lib/ruby_routes/lru_strategies/hit_strategy.rb +31 -4
  5. data/lib/ruby_routes/lru_strategies/miss_strategy.rb +21 -0
  6. data/lib/ruby_routes/node.rb +82 -41
  7. data/lib/ruby_routes/radix_tree/finder.rb +164 -0
  8. data/lib/ruby_routes/radix_tree/inserter.rb +98 -0
  9. data/lib/ruby_routes/radix_tree.rb +83 -142
  10. data/lib/ruby_routes/route/check_helpers.rb +109 -0
  11. data/lib/ruby_routes/route/constraint_validator.rb +159 -0
  12. data/lib/ruby_routes/route/param_support.rb +202 -0
  13. data/lib/ruby_routes/route/path_builder.rb +86 -0
  14. data/lib/ruby_routes/route/path_generation.rb +102 -0
  15. data/lib/ruby_routes/route/query_helpers.rb +56 -0
  16. data/lib/ruby_routes/route/segment_compiler.rb +163 -0
  17. data/lib/ruby_routes/route/small_lru.rb +96 -17
  18. data/lib/ruby_routes/route/validation_helpers.rb +151 -0
  19. data/lib/ruby_routes/route/warning_helpers.rb +54 -0
  20. data/lib/ruby_routes/route.rb +121 -451
  21. data/lib/ruby_routes/route_set/cache_helpers.rb +174 -0
  22. data/lib/ruby_routes/route_set/collection_helpers.rb +127 -0
  23. data/lib/ruby_routes/route_set.rb +126 -148
  24. data/lib/ruby_routes/router/build_helpers.rb +100 -0
  25. data/lib/ruby_routes/router/builder.rb +96 -0
  26. data/lib/ruby_routes/router/http_helpers.rb +135 -0
  27. data/lib/ruby_routes/router/resource_helpers.rb +137 -0
  28. data/lib/ruby_routes/router/scope_helpers.rb +109 -0
  29. data/lib/ruby_routes/router.rb +196 -179
  30. data/lib/ruby_routes/segment.rb +28 -8
  31. data/lib/ruby_routes/segments/base_segment.rb +40 -4
  32. data/lib/ruby_routes/segments/dynamic_segment.rb +48 -12
  33. data/lib/ruby_routes/segments/static_segment.rb +43 -7
  34. data/lib/ruby_routes/segments/wildcard_segment.rb +56 -12
  35. data/lib/ruby_routes/string_extensions.rb +52 -15
  36. data/lib/ruby_routes/url_helpers.rb +106 -24
  37. data/lib/ruby_routes/utility/inflector_utility.rb +35 -0
  38. data/lib/ruby_routes/utility/key_builder_utility.rb +179 -0
  39. data/lib/ruby_routes/utility/method_utility.rb +137 -0
  40. data/lib/ruby_routes/utility/path_utility.rb +89 -0
  41. data/lib/ruby_routes/utility/route_utility.rb +49 -0
  42. data/lib/ruby_routes/version.rb +3 -1
  43. data/lib/ruby_routes.rb +68 -11
  44. metadata +30 -7
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../constant'
4
+
5
+ module RubyRoutes
6
+ class Router
7
+ # BuildHelpers
8
+ #
9
+ # Small, focused utilities used while constructing routes and routers.
10
+ module BuildHelpers
11
+ # Build the router from recorded calls.
12
+ #
13
+ # This method creates a new `Router` instance, validates the recorded calls,
14
+ # finalizes the router (making it immutable), and returns the frozen instance.
15
+ #
16
+ # @return [Router] The finalized router.
17
+ def build
18
+ router = Router.new
19
+ validate_calls(@recorded_calls)
20
+ router.freeze
21
+ router.finalize!
22
+ router
23
+ end
24
+
25
+ # Build route options.
26
+ #
27
+ # This method creates a copy of the base options and conditionally adds
28
+ # the `:via` and `:to` keys if they are not already present or need to be overridden.
29
+ #
30
+ # @param base_options [Hash] The base options for the route.
31
+ # @param via_sym [Symbol, nil] The HTTP method (e.g., `:get`, `:post`).
32
+ # @param to_string [String, nil] The controller#action string (e.g., `"users#index"`).
33
+ # @return [Hash] The updated route options.
34
+ def build_route_options(base_options, via_sym = nil, to_string = nil)
35
+ force_via = !via_sym.nil? && base_options[:via] != via_sym
36
+ add_to = !to_string.nil? && !base_options.key?(:to)
37
+ return base_options unless force_via || add_to
38
+
39
+ options_copy = base_options.dup
40
+ options_copy[:via] = via_sym if force_via
41
+ options_copy[:to] = to_string if add_to
42
+ options_copy
43
+ end
44
+
45
+ # Helper: Build collection routes inside a resource scope.
46
+ #
47
+ # This method defines routes for collection-level actions (e.g., `index`, `new`, `create`)
48
+ # within the scope of a resource.
49
+ #
50
+ # @param opts [Hash] The options to apply to the routes.
51
+ # @param to_index [String] The controller#action string for the `index` action.
52
+ # @param to_new [String] The controller#action string for the `new` action.
53
+ # @param to_create [String] The controller#action string for the `create` action.
54
+ # @return [void]
55
+ def build_collection_routes(opts, to_index, to_new, to_create)
56
+ add_route('', build_route_options(opts, :get, to_index))
57
+ add_route('/new', build_route_options(opts, :get, to_new))
58
+ add_route('', build_route_options(opts, :post, to_create))
59
+ end
60
+
61
+ # Helper: Build member routes inside a resource scope.
62
+ #
63
+ # This method defines routes for member-level actions (e.g., `show`, `edit`, `update`, `destroy`)
64
+ # within the scope of a resource.
65
+ #
66
+ # @param opts [Hash] The options to apply to the routes.
67
+ # @param to_show [String] The controller#action string for the `show` action.
68
+ # @param to_edit [String] The controller#action string for the `edit` action.
69
+ # @param to_update [String] The controller#action string for the `update` action.
70
+ # @param to_destroy [String] The controller#action string for the `destroy` action.
71
+ # @return [void]
72
+ def build_member_routes(opts, to_show, to_edit, to_update, to_destroy)
73
+ add_route('/:id', build_route_options(opts, :get, to_show))
74
+ add_route('/:id/edit', build_route_options(opts, :get, to_edit))
75
+ add_route('/:id', opts.merge(via: %i[put patch], to: to_update))
76
+ add_route('/:id', build_route_options(opts, :delete, to_destroy))
77
+ end
78
+
79
+ private
80
+
81
+ # Validate the recorded calls.
82
+ #
83
+ # This method ensures that all recorded calls use valid router methods
84
+ # as defined in `RubyRoutes::Constant::RECORDED_METHODS`.
85
+ #
86
+ # @param recorded_calls [Array<Array(Symbol, Array, Proc|NilClass)>]
87
+ # The recorded calls to validate.
88
+ # @raise [ArgumentError] If any recorded call uses an invalid method.
89
+ # @return [void]
90
+ def validate_calls(recorded_calls)
91
+ allowed_router_methods = RubyRoutes::Constant::RECORDED_METHODS
92
+ recorded_calls.each do |(router_method, _arguments, _definition_block)|
93
+ unless router_method.is_a?(Symbol) && allowed_router_methods.include?(router_method)
94
+ raise ArgumentError, "Invalid router method: #{router_method.inspect}"
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../constant'
4
+ require_relative 'build_helpers'
5
+
6
+ module RubyRoutes
7
+ class Router
8
+ # Builder
9
+ #
10
+ # Records routing DSL invocations without mutating a live Router.
11
+ # Later, `#build` replays the recorded calls on a fresh Router,
12
+ # finalizes it (immutability), and returns the frozen instance.
13
+ #
14
+ # Benefits:
15
+ # - Decouples route declaration time from Router instantiation.
16
+ # - Enables reuse (same blueprint -> multiple routers).
17
+ # - Safe to construct on boot and share across threads after build.
18
+ #
19
+ # Usage:
20
+ # builder = RubyRoutes::Router::Builder.new do
21
+ # namespace :api do
22
+ # resources :users
23
+ # end
24
+ # get '/health', to: 'system#health'
25
+ # end
26
+ # router = builder.build # finalized (router.frozen? == true)
27
+ #
28
+ # Supported DSL methods are mirrored here. Blocks are stored as Procs;
29
+ # serialization of blocks is not supported.
30
+ #
31
+ # @api internal
32
+ class Builder
33
+ include RubyRoutes::Router::BuildHelpers
34
+
35
+ # Array of recorded calls: [method_symbol, args_array, block].
36
+ #
37
+ # Each tuple contains:
38
+ # - The method name (as a Symbol).
39
+ # - The arguments (as an Array).
40
+ # - The block (as a Proc or `nil`).
41
+ #
42
+ # @return [Array<Array(Symbol, Array, Proc|NilClass)>]
43
+ # A snapshot of the recorded calls to avoid external mutation.
44
+ def recorded_calls
45
+ @recorded_calls.dup.freeze
46
+ end
47
+
48
+ # Initialize the Builder.
49
+ #
50
+ # This method initializes the `@recorded_calls` array and optionally
51
+ # evaluates the provided block in the context of the Builder instance.
52
+ #
53
+ # @yield [definition_block] Runs the routing DSL in a recording context (optional).
54
+ # @return [void]
55
+ def initialize(&definition_block)
56
+ @recorded_calls = []
57
+ instance_eval(&definition_block) if definition_block
58
+ end
59
+
60
+ # ---- DSL Recording -------------------------------------------------
61
+ # Dynamically define methods for all DSL methods specified in
62
+ # `RubyRoutes::Constant::RECORDED_METHODS`. Each method records its
63
+ # invocation (method name, arguments, and block) in `@recorded_calls`.
64
+ #
65
+ # @param *arguments [Array] The arguments passed to the DSL method.
66
+ # @param definition_block [Proc, nil] The block passed to the DSL method.
67
+ # @return [nil]
68
+ RubyRoutes::Constant::RECORDED_METHODS.each do |method_name|
69
+ define_method(method_name) do |*arguments, &definition_block|
70
+ @recorded_calls << [__method__, arguments, definition_block]
71
+ nil
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ # Validate the recorded calls.
78
+ #
79
+ # This method ensures that all recorded calls use valid router methods
80
+ # as defined in `RubyRoutes::Constant::RECORDED_METHODS`.
81
+ #
82
+ # @param recorded_calls [Array<Array(Symbol, Array, Proc|NilClass)>]
83
+ # The recorded calls to validate.
84
+ # @raise [ArgumentError] If any recorded call uses an invalid method.
85
+ # @return [void]
86
+ def validate_calls(recorded_calls)
87
+ allowed_router_methods = RubyRoutes::Constant::RECORDED_METHODS
88
+ recorded_calls.each do |(router_method, _arguments, _definition_block)|
89
+ unless router_method.is_a?(Symbol) && allowed_router_methods.include?(router_method)
90
+ raise ArgumentError, "Invalid router method: #{router_method.inspect}"
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'build_helpers'
4
+ require_relative 'scope_helpers'
5
+ require_relative 'resource_helpers'
6
+
7
+ module RubyRoutes
8
+ class Router
9
+ # HttpHelpers
10
+ #
11
+ # DSL methods exposing HTTP verb helpers (`get`, `post`, `put`, `patch`, `delete`, `match`)
12
+ # and small wiring helpers. Resource- and nested-related logic is delegated
13
+ # to `Router::ResourceHelpers` to keep this module focused.
14
+ #
15
+ # This module provides methods to define routes for various HTTP verbs, apply
16
+ # scopes, and manage route definitions. It also includes helper methods for
17
+ # defining singular resource routes.
18
+ module HttpHelpers
19
+ include RubyRoutes::Router::BuildHelpers
20
+ include RubyRoutes::Router::ScopeHelpers
21
+ include RubyRoutes::Router::ResourceHelpers
22
+
23
+ # ---- HTTP Verb Helpers -------------------------------------------------
24
+
25
+ # Define a GET route.
26
+ #
27
+ # @param path [String] The path for the route.
28
+ # @param options [Hash] The options for the route.
29
+ # @return [Router] Returns self for chaining.
30
+ def get(path, options = {})
31
+ add_route(path, build_route_options(options, :get))
32
+ self
33
+ end
34
+
35
+ # Define a POST route.
36
+ #
37
+ # @param path [String] The path for the route.
38
+ # @param options [Hash] The options for the route.
39
+ # @return [Router] Returns self for chaining.
40
+ def post(path, options = {})
41
+ add_route(path, build_route_options(options, :post))
42
+ self
43
+ end
44
+
45
+ # Define a PUT route.
46
+ #
47
+ # @param path [String] The path for the route.
48
+ # @param options [Hash] The options for the route.
49
+ # @return [Router] Returns self for chaining.
50
+ def put(path, options = {})
51
+ add_route(path, build_route_options(options, :put))
52
+ self
53
+ end
54
+
55
+ # Define a PATCH route.
56
+ #
57
+ # @param path [String] The path for the route.
58
+ # @param options [Hash] The options for the route.
59
+ # @return [Router] Returns self for chaining.
60
+ def patch(path, options = {})
61
+ add_route(path, build_route_options(options, :patch))
62
+ self
63
+ end
64
+
65
+ # Define a DELETE route.
66
+ #
67
+ # @param path [String] The path for the route.
68
+ # @param options [Hash] The options for the route.
69
+ # @return [Router] Returns self for chaining.
70
+ def delete(path, options = {})
71
+ add_route(path, build_route_options(options, :delete))
72
+ self
73
+ end
74
+
75
+ # Define a route for multiple HTTP methods.
76
+ #
77
+ # @param path [String] The path for the route.
78
+ # @param options [Hash] The options for the route.
79
+ # - `:via` [Array<Symbol>] The HTTP methods to allow (e.g., `[:get, :post]`).
80
+ # @raise [ArgumentError] If `:via` is not provided or is empty.
81
+ # @return [Router] Returns self for chaining.
82
+ def match(path, options = {})
83
+ via = options[:via]
84
+ raise ArgumentError, 'match requires :via (e.g., via: [:get, :post])' if via.nil? || Array(via).empty?
85
+
86
+ add_route(path, options)
87
+ self
88
+ end
89
+
90
+ private
91
+
92
+ # Add a route to the router.
93
+ #
94
+ # This method applies the current scope to the route and defines it using
95
+ # the route utilities.
96
+ #
97
+ # @param path [String] The path for the route.
98
+ # @param options [Hash] The options for the route.
99
+ # @return [void]
100
+ def add_route(path, options = {})
101
+ ensure_unfrozen!
102
+ scoped = apply_scope(path, options)
103
+ @route_utils.define(scoped[:path], scoped)
104
+ end
105
+
106
+ # Ensure the router is not frozen.
107
+ #
108
+ # @raise [RuntimeError] If the router is frozen.
109
+ # @return [void]
110
+ def ensure_unfrozen!
111
+ raise 'Router finalized (immutable)' if @frozen
112
+ end
113
+
114
+ # Define routes for a singular resource.
115
+ #
116
+ # This method defines routes for a singular resource (e.g., `/profile`),
117
+ # including standard RESTful actions like `show`, `new`, `create`, `edit`,
118
+ # `update`, and `destroy`.
119
+ #
120
+ # @param singular [String] The name of the singular resource.
121
+ # @param controller [String] The name of the controller handling the resource.
122
+ # @param options [Hash] Additional options for the routes.
123
+ # @return [void]
124
+ def define_singular_routes(singular, controller, options)
125
+ get "/#{singular}", options.merge(to: "#{controller}#show")
126
+ get "/#{singular}/new", options.merge(to: "#{controller}#new")
127
+ post "/#{singular}", options.merge(to: "#{controller}#create")
128
+ get "/#{singular}/edit", options.merge(to: "#{controller}#edit")
129
+ put "/#{singular}", options.merge(to: "#{controller}#update")
130
+ patch "/#{singular}", options.merge(to: "#{controller}#update")
131
+ delete "/#{singular}", options.merge(to: "#{controller}#destroy")
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'build_helpers'
4
+
5
+ module RubyRoutes
6
+ class Router
7
+ # ResourceHelpers: resource / nested-resource related helpers extracted
8
+ # from HttpHelpers to reduce method length and ABC complexity.
9
+ #
10
+ # This module provides methods for defining RESTful routes for resources,
11
+ # handling nested resources, and generating metadata for resource paths
12
+ # and controller actions.
13
+ module ResourceHelpers
14
+ include RubyRoutes::Router::BuildHelpers
15
+
16
+ private
17
+
18
+ # Define RESTful routes for a resource.
19
+ #
20
+ # @param resource_name [Symbol, String] The name of the resource.
21
+ # @param options [Hash] Options for customizing the resource routes.
22
+ # - `:path` [String] Custom path for the resource.
23
+ # - `:controller` [String] Custom controller name.
24
+ # - `:nested` [Symbol, String] Name of the nested resource.
25
+ # @param nested_block [Proc] A block for defining nested routes.
26
+ # @return [void]
27
+ def define_resource_routes(resource_name, options = {}, &nested_block)
28
+ meta = resource_meta(resource_name, options)
29
+ opts = prepare_options(options)
30
+
31
+ push_scope(path: "/#{meta[:resource_path]}") do
32
+ build_routes(opts, meta)
33
+ handle_nested_option(options, opts)
34
+ apply_nested_block(nested_block)
35
+ end
36
+ end
37
+
38
+ # Prepare options by removing the `:to` key if present.
39
+ #
40
+ # @param options [Hash] The options hash.
41
+ # @return [Hash] The prepared options.
42
+ def prepare_options(options)
43
+ options.key?(:to) ? options.dup.tap { |h| h.delete(:to) } : options
44
+ end
45
+
46
+ # Build collection and member routes for a resource.
47
+ #
48
+ # @param opts [Hash] The options hash.
49
+ # @param meta [Hash] The resource metadata.
50
+ # @return [void]
51
+ def build_routes(opts, meta)
52
+ build_collection_routes(opts, meta[:to_index], meta[:to_new], meta[:to_create])
53
+ build_member_routes(opts, meta[:to_show], meta[:to_edit], meta[:to_update], meta[:to_destroy])
54
+ end
55
+
56
+ # Apply a nested block of routes within the scope of a resource.
57
+ #
58
+ # @param nested_block [Proc] The block defining nested routes.
59
+ # @return [void]
60
+ def apply_nested_block(nested_block)
61
+ return unless nested_block
62
+
63
+ push_scope(path: '/:id') { instance_eval(&nested_block) }
64
+ end
65
+
66
+ # Prepare resource metadata (path/controller/action strings).
67
+ #
68
+ # @param resource_name [Symbol, String] The name of the resource.
69
+ # @param options [Hash] Options for customizing the resource metadata.
70
+ # @return [Hash] The resource metadata.
71
+ def resource_meta(resource_name, options)
72
+ base_name = resource_name.to_s
73
+ resource_path = options[:path] ? options[:path].to_s : RubyRoutes::Utility::InflectorUtility.pluralize(base_name)
74
+ controller = options[:controller] || RubyRoutes::Utility::InflectorUtility.pluralize(base_name)
75
+ build_meta_hash(resource_path, controller)
76
+ end
77
+
78
+ # Build a metadata hash for a resource.
79
+ #
80
+ # @param resource_path [String] The resource path.
81
+ # @param controller [String] The controller name.
82
+ # @return [Hash] The metadata hash.
83
+ def build_meta_hash(resource_path, controller)
84
+ actions = %w[index new create show edit update destroy]
85
+ meta_hash = actions.each_with_object({}) do |action, hash|
86
+ hash[:"to_#{action}"] = "#{controller}##{action}"
87
+ end
88
+
89
+ meta_hash.merge(
90
+ resource_path: resource_path,
91
+ controller: controller
92
+ )
93
+ end
94
+
95
+ # Handle the `nested:` shorthand option for resources.
96
+ #
97
+ # @param options [Hash] The options hash.
98
+ # @param opts [Hash] The prepared options hash.
99
+ # @return [void]
100
+ def handle_nested_option(options, opts)
101
+ return unless options[:nested]
102
+
103
+ nested_name = options[:nested].to_s
104
+ nested_path = RubyRoutes::Utility::InflectorUtility.pluralize(nested_name)
105
+ build_nested_routes(nested_path, opts)
106
+ end
107
+
108
+ # Build nested resource routes.
109
+ #
110
+ # @param nested_path [String] The path for the nested resource.
111
+ # @param opts [Hash] The options hash.
112
+ # @return [void]
113
+ def build_nested_routes(nested_path, opts)
114
+ push_scope(path: '/:id') do
115
+ push_scope(path: "/#{nested_path}") do
116
+ add_nested_routes(nested_path, opts)
117
+ end
118
+ end
119
+ end
120
+
121
+ # Add routes for a nested resource.
122
+ #
123
+ # @param nested_path [String] The path for the nested resource.
124
+ # @param opts [Hash] The options hash.
125
+ # @return [void]
126
+ def add_nested_routes(nested_path, opts)
127
+ add_route('', build_route_options(opts, :get, "#{nested_path}#index"))
128
+ add_route('/new', build_route_options(opts, :get, "#{nested_path}#new"))
129
+ add_route('', build_route_options(opts, :post, "#{nested_path}#create"))
130
+ add_route('/:nested_id', build_route_options(opts, :get, "#{nested_path}#show"))
131
+ add_route('/:nested_id/edit', build_route_options(opts, :get, "#{nested_path}#edit"))
132
+ add_route('/:nested_id', opts.merge(via: %i[put patch], to: "#{nested_path}#update"))
133
+ add_route('/:nested_id', build_route_options(opts, :delete, "#{nested_path}#destroy"))
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyRoutes
4
+ class Router
5
+ # ScopeHelpers: encapsulate scope application logic
6
+ #
7
+ # This module provides methods for managing and applying scopes in the routing DSL.
8
+ # Scopes allow you to define nested paths, modules, defaults, and constraints
9
+ # that apply to a group of routes.
10
+ module ScopeHelpers
11
+ private
12
+
13
+ # Push a scope onto the scope stack.
14
+ #
15
+ # This method temporarily adds a scope entry to the scope stack, executes the
16
+ # given block, and ensures the scope is removed afterward.
17
+ #
18
+ # @param scope_entry [Hash] The scope entry to push onto the stack.
19
+ # @yield The block to execute within the scope.
20
+ # @return [void]
21
+ def push_scope(scope_entry)
22
+ ensure_unfrozen!
23
+ return unless block_given?
24
+
25
+ @scope_stack.push(scope_entry)
26
+
27
+ begin
28
+ yield
29
+ ensure
30
+ @scope_stack.pop
31
+ end
32
+ end
33
+
34
+ # Apply all scopes to the given path and options.
35
+ #
36
+ # This method iterates through the scope stack in reverse order, applying
37
+ # path, module, defaults, and constraints from each scope to the given path
38
+ # and options.
39
+ #
40
+ # @param path [String] The base path to apply scopes to.
41
+ # @param options [Hash] The options to apply scopes to.
42
+ # @return [Hash] The scoped options, including the updated path.
43
+ def apply_scope(path, options)
44
+ scoped_options = options.dup
45
+ scoped_path = path.to_s.dup
46
+
47
+ @scope_stack.reverse_each do |scope|
48
+ apply_path_scope(scope, scoped_path)
49
+ apply_module_scope(scope, scoped_options)
50
+ apply_defaults_scope(scope, scoped_options)
51
+ apply_constraints_scope(scope, scoped_options)
52
+ end
53
+
54
+ scoped_options[:path] = scoped_path
55
+ scoped_options
56
+ end
57
+
58
+ # Apply the path from a scope to the given path.
59
+ #
60
+ # @param scope [Hash] The scope containing the path.
61
+ # @param scoped_path [String] The path to prepend the scope's path to.
62
+ # @return [void]
63
+ def apply_path_scope(scope, scoped_path)
64
+ scoped_path.prepend(scope[:path]) if scope[:path]
65
+ end
66
+
67
+ # Apply the module from a scope to the given options.
68
+ #
69
+ # This method updates the `:to` or `:controller` option to include the module
70
+ # from the scope.
71
+ #
72
+ # @param scope [Hash] The scope containing the module.
73
+ # @param scoped_options [Hash] The options to update with the module.
74
+ # @return [void]
75
+ def apply_module_scope(scope, scoped_options)
76
+ return unless scope[:module]
77
+
78
+ if scoped_options[:to]
79
+ controller, action = scoped_options[:to].to_s.split('#', 2)
80
+ scoped_options[:to] = "#{scope[:module]}/#{controller}##{action}"
81
+ elsif scoped_options[:controller]
82
+ scoped_options[:controller].prepend("#{scope[:module]}/")
83
+ end
84
+ end
85
+
86
+ # Apply the defaults from a scope to the given options.
87
+ #
88
+ # @param scope [Hash] The scope containing the defaults.
89
+ # @param scoped_options [Hash] The options to update with the defaults.
90
+ # @return [void]
91
+ def apply_defaults_scope(scope, scoped_options)
92
+ return unless scope[:defaults]
93
+
94
+ scoped_options[:defaults] = (scoped_options[:defaults] || {}).merge(scope[:defaults])
95
+ end
96
+
97
+ # Apply the constraints from a scope to the given options.
98
+ #
99
+ # @param scope [Hash] The scope containing the constraints.
100
+ # @param scoped_options [Hash] The options to update with the constraints.
101
+ # @return [void]
102
+ def apply_constraints_scope(scope, scoped_options)
103
+ return unless scope[:constraints]
104
+
105
+ scoped_options[:constraints] = (scoped_options[:constraints] || {}).merge(scope[:constraints])
106
+ end
107
+ end
108
+ end
109
+ end