lennarb 0.1.6 → 0.2.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.
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2023, by Aristóteles Coutinho.
5
-
6
- module Lenna
7
- class Router
8
- # This class is responsible for matching the request path
9
- # to an endpoint and executing the endpoint action.
10
- #
11
- # @private Since `v0.1.0`
12
- #
13
- # This will match the request path to an endpoint and execute
14
- # the endpoint action.
15
- #
16
- class RouteMatcher
17
- # @parameter root_node [Lenna::Node] The root node
18
- #
19
- def initialize(root_node) = @root_node = root_node
20
-
21
- # This method will match the request path to an endpoint and execute
22
- # the endpoint action.
23
- #
24
- # @parameter req [Lenna::Request] The request object
25
- # @parameter res [Lenna::Response] The response object
26
- # @return [Lenna::Response] The response object
27
- #
28
- def match_and_execute_route(req, res)
29
- params = {}
30
- path_parts = split_path(req.path_info)
31
- endpoint = find_endpoint(@root_node, path_parts, params)
32
-
33
- if endpoint && (action = endpoint[req.request_method])
34
- req.assign_params(params)
35
- action.call(req, res)
36
- else
37
- res.not_found
38
- end
39
- end
40
-
41
- private
42
-
43
- def split_path(path) = path.split('/').reject(&:empty?)
44
-
45
- # @parameter node [Lenna::Node] The node to search
46
- # @parameter parts [Array] The path parts
47
- # @parameter params [Hash] The params hash
48
- #
49
- # @return [Lenna::Node] The node that matches the path
50
- #
51
- # This method is recursive.
52
- #
53
- def find_endpoint(node, parts, params)
54
- return node.endpoint if parts.empty?
55
-
56
- part = parts.shift
57
- child_node = node.children[part]
58
-
59
- if child_node.nil? && (placeholder_node = node.children[:placeholder])
60
- params[placeholder_node.placeholder_name] = part
61
- child_node = placeholder_node
62
- end
63
-
64
- find_endpoint(child_node, parts, params) if child_node
65
- end
66
- end
67
- end
68
- end
data/lib/lenna/router.rb DELETED
@@ -1,205 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2023, by Aristóteles Coutinho.
5
-
6
- require 'erb'
7
- require 'json'
8
-
9
- # External dependencies
10
- require 'rack'
11
-
12
- # Internal dependencies
13
- require 'lenna/middleware/app'
14
- require 'lenna/middleware/default/error_handler'
15
- require 'lenna/middleware/default/logging'
16
- require 'lenna/router/builder'
17
- require 'lenna/router/cache'
18
- require 'lenna/router/namespace_stack'
19
- require 'lenna/router/request'
20
- require 'lenna/router/response'
21
- require 'lenna/router/route_matcher'
22
-
23
- module Lenna
24
- # The Node struct is used to represent a node in the tree of routes.
25
- #
26
- # @attr children [Hash] the children of the node
27
- # @attr endpoint [String] the endpoint of the node
28
- # @attr placeholder_name [String] the name of the placeholder
29
- # @attr placeholder [Bool] whether the node is a placeholder
30
- #
31
- Node =
32
- ::Struct.new(:children, :endpoint, :placeholder_name, :placeholder) do
33
- def initialize(children = {}, endpoint = nil, placeholder_name = nil)
34
- super(children, endpoint, placeholder_name, !placeholder_name.nil?)
35
- end
36
- end
37
- public_constant :Node
38
-
39
- # The router class is responsible for adding routes and calling the
40
- # middleware chain for each request.
41
- #
42
- # @private
43
- #
44
- class Router
45
- # @return [Node] the root node of the tree of routes
46
- #
47
- attr_reader :root_node
48
-
49
- # @return [Route::Cache] the cache of routes
50
- #
51
- attr_reader :cache
52
-
53
- # @return [Route::NamespaceStack] the stack of namespaces
54
- #
55
- attr_reader :namespace_stack
56
-
57
- # @return [MiddlewareManager] the middleware manager
58
- #
59
- attr_reader :middleware_manager
60
-
61
- # @return [Route::Builder] the route builder
62
- #
63
- attr_reader :roter_builder
64
-
65
- # This method is used to initialize the router.
66
- # By default, it uses the App middleware and the Cache.
67
- #
68
- # @return [void]
69
- #
70
- def initialize(
71
- middleware_manager: Middleware::App.instance,
72
- cache: Cache.new
73
- )
74
- @cache = cache
75
- @root_node = Node.new({}, nil)
76
- @middleware_manager = middleware_manager
77
- @namespace_stack = NamespaceStack.new
78
- @roter_builder = Builder.new(@root_node)
79
- end
80
-
81
- # This method is used to add a namespace to the routes.
82
- #
83
- # @parameter prefix [String] the prefix to be used
84
- # @parameter block [Proc] the block to be executed
85
- #
86
- # @return [void]
87
- #
88
- # @public `Since v0.1.0`
89
- #
90
- # see {Route::NamespaceStack#push}
91
- #
92
- # ex.
93
- #
94
- # namespace '/api' do |route|
95
- # route.get '/users' do
96
- # # ...
97
- # end
98
- # end
99
- #
100
- def namespace(prefix, &block)
101
- @namespace_stack.push(prefix)
102
- block.call(self)
103
- @namespace_stack.pop
104
- end
105
-
106
- # This method is used to add a middleware to the middleware manager.
107
- #
108
- # See {MiddlewareManager#use}
109
- #
110
- # @public `Since v0.1.0`
111
- #
112
- #
113
- # @parameter middlewares [Array] the middlewares to be used
114
- #
115
- # @return [void]
116
- #
117
- def use(*middlewares) = @middleware_manager.use(middlewares)
118
-
119
- # Proxy methods to add routes
120
- #
121
- # @parameter path [String] the path to be matched
122
- # @parameter * [Array] the middlewares to be used
123
- # @yield { ... } the block to be executed
124
- #
125
- # @return [void]
126
- #
127
- # see {#add_route}
128
- #
129
- # @public `Since v0.1`
130
- def get(path, *, &) = add_route(::Rack::GET, path, *, &)
131
- def put(path, *, &) = add_route(::Rack::PUT, path, *, &)
132
- def post(path, *, &) = add_route(::Rack::POST, path, *, &)
133
- def delete(path, *, &) = add_route(::Rack::DELETE, path, *, &)
134
-
135
- def call(env) = dup.call!(env)
136
-
137
- # This method is used to call the middleware chain for each request.
138
- # It also sets the RACK_ENV to development if it is not set.
139
- #
140
- # @parameter env [Hash] the Rack env
141
- #
142
- # @return [Array] the Lennarb::Response
143
- #
144
- def call!(env)
145
- middleware_pipeline = @middleware_manager.fetch_or_build_middleware_chain(
146
- method(:process_request),
147
- [
148
- Middleware::Default::Logging,
149
- Middleware::Default::ErrorHandler
150
- ]
151
- )
152
-
153
- req = Request.new(env)
154
- res = Response.new
155
-
156
- middleware_pipeline.call(req, res)
157
-
158
- res.finish
159
- end
160
-
161
- private
162
-
163
- # This method is used to add a route to the tree of routes.
164
- #
165
- # @parameter http_method [Rack::Method] the http method to be used
166
- # @parameter path [String] the path to be matched
167
- # @parameter middlewares [Array] the middlewares to be used
168
- # @parameter action [Proc] the action to be executed
169
- #
170
- # see {MiddlewareManager#build_middleware_chain}
171
- # see {Route::Cache#add}
172
- # see {Route::Builder#call}
173
- # see {Route::NamespaceStack#current_prefix}
174
- #
175
- # @return [void]
176
- #
177
- def add_route(http_method, path, *middlewares, &action)
178
- full_path = @namespace_stack.current_prefix + path
179
-
180
- middleware_chain = @middleware_manager.fetch_or_build_middleware_chain(
181
- action,
182
- middlewares,
183
- http_method:,
184
- path:
185
- )
186
-
187
- @roter_builder.call(http_method, full_path, middleware_chain, @cache)
188
- end
189
-
190
- # This method is used to process the request.
191
- #
192
- # It uses the Route::Matcher to match the request to a route and
193
- # execute the action.
194
- #
195
- # @parameter req [Request] the request
196
- # @parameter res [Response] the response
197
- #
198
- # @return [void]
199
- #
200
- def process_request(req, res)
201
- @route_matcher ||= RouteMatcher.new(@root_node)
202
- @route_matcher.match_and_execute_route(req, res)
203
- end
204
- end
205
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2023, by Aristóteles Coutinho.
5
-
6
- module Lennarb
7
- # The ArrayExtensions module is used to add the wrap method to the Array
8
- # class.
9
- #
10
- # @public Since `v0.1.0`
11
- #
12
- module ArrayExtensions
13
- # Wraps the object in an array if it is not already an array.
14
- #
15
- # @param object [Object] the object to wrap
16
- #
17
- # @return [Array] the wrapped object
18
- #
19
- def wrap(object)
20
- if object.nil?
21
- []
22
- elsif object.respond_to?(:to_ary)
23
- object.to_ary || [object]
24
- else
25
- [object]
26
- end
27
- end
28
- end
29
- end
30
-
31
- Array.extend(Lennarb::ArrayExtensions)