lennarb 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)