lennarb 0.1.0 → 0.1.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -9
- data/lib/lenna/router/request.rb +1 -1
- data/lib/lenna/router/response.rb +163 -141
- data/lib/lennarb/array_extensions.rb +17 -0
- data/lib/lennarb/version.rb +7 -0
- data/lib/lennarb.rb +5 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0e10a539894e1cf41bcebf4c01b086092d36779b1b8aebada8eabc717552348
|
4
|
+
data.tar.gz: 86afa28d62c0b532e08027df8a1847bc4a72b36347388b11f4c6f7aef8c2d345
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0539b0de41e1de79c84a89204c67931dcf0b015a2401db8bece03ef66e8fc5b7e74c87527bb431d1ec447998b067738bb41127f68917d0dbcfd44ff973294935'
|
7
|
+
data.tar.gz: 88820bc3511a72fda57ef39fac259c69cc632dcb3ad0d9faa4b3514327603cc78cd6e5b6531b4c632a109901883e5ca642fa13904ab8e6445cecea466edde298
|
data/CHANGELOG.md
CHANGED
@@ -4,26 +4,26 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
-
## [
|
7
|
+
## [Released]
|
8
8
|
|
9
|
-
|
10
|
-
- New feature for the next release.
|
9
|
+
## [0.1.1] - 2023-23-11
|
11
10
|
|
12
11
|
### Added
|
13
|
-
-
|
12
|
+
- Introduced `Array.wrap` extension to the `Array` class for more reliable conversion of objects to arrays within the Lennarb router environment. This method ensures consistent array wrapping of single objects and `nil` values.
|
14
13
|
|
15
14
|
### Changed
|
16
|
-
-
|
15
|
+
- Refactored the `put_header` method to use the `Array.wrap` method for more predictable header value handling.
|
16
|
+
- Renamed methods to have a consistent `assign_` prefix to standardize the API interface:
|
17
|
+
- `put_header` to `assign_header`
|
18
|
+
- `write_body` to `assign_body`
|
19
|
+
- `set_params` to `assign_params`
|
20
|
+
- `update_status` to `assign_status`
|
17
21
|
|
18
22
|
### Deprecated
|
19
|
-
- Example feature that will be removed in future releases.
|
20
23
|
|
21
24
|
### Removed
|
22
|
-
- Example feature that was removed.
|
23
25
|
|
24
26
|
### Fixed
|
25
|
-
- Example bug fix.
|
26
27
|
|
27
28
|
### Security
|
28
|
-
- Example security fix.
|
29
29
|
|
data/lib/lenna/router/request.rb
CHANGED
@@ -4,51 +4,41 @@ module Lenna
|
|
4
4
|
class Router
|
5
5
|
# The Response class is responsible for managing the response.
|
6
6
|
#
|
7
|
-
# @attr
|
8
|
-
# @attr
|
9
|
-
# @attr
|
10
|
-
# @attr params
|
7
|
+
# @attr headers [Hash] the response headers
|
8
|
+
# @attr body [Array(String)] the response body
|
9
|
+
# @attr status [Integer] the response status
|
10
|
+
# @attr params [Hash] the response params
|
11
11
|
class Response
|
12
|
-
|
13
|
-
|
12
|
+
private attr_writer :body, :headers, :status, :params
|
13
|
+
public attr_reader :body, :headers, :status, :params
|
14
14
|
|
15
|
-
# Initialize the Response
|
16
15
|
def initialize(headers = {}, status = 200, body = [])
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
@
|
16
|
+
@params = {}
|
17
|
+
@body = body
|
18
|
+
@status = status
|
19
|
+
@headers = headers
|
21
20
|
end
|
22
21
|
|
22
|
+
# This method will set the response status.
|
23
|
+
#
|
24
|
+
# @param value [Integer] the response status
|
25
|
+
#
|
26
|
+
# @return [void]
|
27
|
+
#
|
23
28
|
# @api public
|
24
|
-
|
25
|
-
def status = fetch_status
|
26
|
-
|
27
|
-
# @api public
|
28
|
-
# @param status [Integer] the response status
|
29
|
-
# @return [void]
|
30
|
-
def put_status(value) = status!(value)
|
31
|
-
|
32
|
-
# @api public
|
33
|
-
# @return [Array(String)] the body value
|
34
|
-
def body = fetch_body
|
29
|
+
def assign_status(value) = put_status(value)
|
35
30
|
|
36
|
-
#
|
31
|
+
# Thi method set the body value.
|
32
|
+
#
|
37
33
|
# @param value [Array(String)] the body value
|
34
|
+
#
|
38
35
|
# @return [void]
|
39
|
-
|
40
|
-
|
41
|
-
# @api public
|
42
|
-
# @param header [String] the header name
|
43
|
-
# @return [String] the header value
|
44
|
-
# @note This method will get the header value.
|
45
|
-
def header(key) = fetch_header(key)
|
46
|
-
|
36
|
+
#
|
47
37
|
# @api public
|
48
|
-
|
49
|
-
def headers = fetch_headers
|
38
|
+
def assign_body(value) = put_body(value)
|
50
39
|
|
51
|
-
#
|
40
|
+
# This method will set the header value.
|
41
|
+
#
|
52
42
|
# @param header [String] the header name
|
53
43
|
# @param value [String] the header value
|
54
44
|
# @return [void]
|
@@ -56,18 +46,21 @@ module Lenna
|
|
56
46
|
# If the header already exists, then the value will
|
57
47
|
# be appended to the header.
|
58
48
|
#
|
49
|
+
# @api public
|
50
|
+
#
|
59
51
|
# @example
|
60
|
-
#
|
52
|
+
# assign_header('X-Request-Id', '123')
|
61
53
|
# # => '123'
|
62
54
|
#
|
63
|
-
#
|
55
|
+
# assign_header('X-Request-Id', '456')
|
64
56
|
# # => ['123', '456']
|
65
57
|
#
|
66
|
-
#
|
58
|
+
# assign_header('X-Request-Id', ['456', '789'])
|
67
59
|
# # => ['123', '456', '789']
|
68
|
-
def
|
60
|
+
def assign_header(key, value) = put_header(key, value)
|
69
61
|
|
70
62
|
# Add multiple headers.
|
63
|
+
#
|
71
64
|
# @param headers [Hash] the headers
|
72
65
|
# @return [void]
|
73
66
|
# @note This method will add the headers.
|
@@ -80,49 +73,66 @@ module Lenna
|
|
80
73
|
# 'X-Request-Id' => '123'
|
81
74
|
# }
|
82
75
|
#
|
83
|
-
def
|
76
|
+
def assign_headers(headers)
|
84
77
|
headers => ::Hash
|
85
78
|
|
86
79
|
headers.each { |key, value| put_header(key, value) }
|
87
80
|
end
|
88
81
|
|
82
|
+
# This method will get the content type.
|
83
|
+
#
|
84
|
+
# @return [String] the content type
|
85
|
+
#
|
89
86
|
# @api public
|
87
|
+
def content_type = @headers['Content-Type']
|
88
|
+
|
89
|
+
# This method will delete the header.
|
90
90
|
# @param header [String] the header name
|
91
|
+
#
|
91
92
|
# @return [void]
|
92
|
-
#
|
93
|
+
#
|
94
|
+
# @api public
|
93
95
|
def remove_header(key) = delete_header(key)
|
94
96
|
|
95
|
-
#
|
97
|
+
# This method will get the redirect location.
|
98
|
+
#
|
96
99
|
# @param value [String] the key of the cookie
|
100
|
+
#
|
97
101
|
# @return [String] the cookie
|
98
|
-
#
|
102
|
+
#
|
103
|
+
# @api public
|
99
104
|
def cookie(value)
|
100
105
|
value => ::String
|
101
106
|
|
102
|
-
|
107
|
+
@headers['Set-Cookie']
|
103
108
|
.then { |cookie| cookie.split('; ') }
|
104
109
|
.then { |cookie| cookie.find { |c| c.start_with?("#{value}=") } }
|
105
110
|
.then { |cookie| cookie.split('=').last }
|
106
111
|
end
|
107
112
|
|
108
|
-
#
|
113
|
+
# This method will set the cookie.
|
114
|
+
#
|
109
115
|
# @param key [String] the key of the cookie
|
110
116
|
# @param value [String] the value of the cookie
|
117
|
+
#
|
111
118
|
# @return [void]
|
112
|
-
#
|
113
|
-
|
119
|
+
#
|
120
|
+
# @api public
|
121
|
+
def assign_cookie(key, value)
|
114
122
|
key => ::String
|
115
123
|
value => ::String
|
116
124
|
|
117
125
|
cookie = "#{key}=#{value}"
|
118
126
|
|
119
|
-
|
127
|
+
put_header('Set-Cookie', cookie)
|
120
128
|
end
|
121
129
|
|
122
|
-
#
|
130
|
+
# This method will get all the cookies.
|
131
|
+
#
|
123
132
|
# @return [Hash] the cookies
|
133
|
+
# @api public
|
124
134
|
def cookies
|
125
|
-
|
135
|
+
@headers['Set-Cookie']
|
126
136
|
.then { |cookie| cookie.split('; ') }
|
127
137
|
.each_with_object({}) do |cookie, acc|
|
128
138
|
key, value = cookie.split('=')
|
@@ -131,82 +141,93 @@ module Lenna
|
|
131
141
|
end
|
132
142
|
end
|
133
143
|
|
134
|
-
#
|
144
|
+
# This method will set redirect location. The status will be set to 302.
|
145
|
+
#
|
135
146
|
# @param location [String] the redirect location
|
136
|
-
# @param status [Integer] the redirect status
|
147
|
+
# @param status [Integer] the redirect status, default is 302.
|
148
|
+
#
|
137
149
|
# @return [void]
|
138
|
-
#
|
139
|
-
#
|
150
|
+
#
|
151
|
+
# @api public
|
140
152
|
def redirect(location, status: 302)
|
141
153
|
location => ::String
|
142
154
|
|
143
|
-
|
144
|
-
|
155
|
+
put_header('Location', location)
|
156
|
+
put_status(status)
|
145
157
|
|
146
158
|
finish!
|
147
159
|
rescue ::NoMatchingPatternError
|
148
160
|
raise ::ArgumentError, 'location must be a string'
|
149
161
|
end
|
150
162
|
|
151
|
-
#
|
163
|
+
# This method will finish the response.
|
164
|
+
#
|
152
165
|
# @return [void]
|
153
|
-
#
|
154
|
-
def finish = finish!
|
155
|
-
|
166
|
+
#
|
156
167
|
# @api public
|
157
|
-
|
158
|
-
# @note This method will set
|
159
|
-
# the response content type.
|
160
|
-
def content_type = header('Content-Type')
|
168
|
+
def finish = finish!
|
161
169
|
|
162
|
-
#
|
170
|
+
# This method will set the response content type.
|
171
|
+
#
|
163
172
|
# @param type [String] the response content type
|
164
173
|
# @param charset [Hash] the response charset
|
174
|
+
#
|
165
175
|
# @return [void]
|
166
|
-
|
176
|
+
#
|
177
|
+
# @api public
|
178
|
+
def assign_content_type(type, charset: nil)
|
167
179
|
type => ::String
|
168
180
|
|
169
181
|
case charset
|
170
|
-
in ::String then
|
171
|
-
|
182
|
+
in ::String then put_header(
|
183
|
+
'Content-Type',
|
184
|
+
"#{type}; charset=#{charset}"
|
185
|
+
)
|
186
|
+
else put_header('Content-Type', type)
|
172
187
|
end
|
173
188
|
rescue ::NoMatchingPatternError
|
174
189
|
raise ::ArgumentError, 'type must be a string'
|
175
190
|
end
|
176
191
|
|
177
|
-
#
|
192
|
+
# This method will set the response data and finish the response.
|
193
|
+
#
|
178
194
|
# @param data [Hash, Array] the response data
|
195
|
+
#
|
179
196
|
# @return [void]
|
180
|
-
#
|
181
|
-
#
|
197
|
+
#
|
198
|
+
# @api public
|
182
199
|
def json(data:, status: 200)
|
183
200
|
data => ::Array | ::Hash
|
184
201
|
|
185
|
-
|
186
|
-
|
187
|
-
|
202
|
+
put_status(status)
|
203
|
+
put_header('Content-Type', 'application/json')
|
204
|
+
put_body(data.to_json)
|
188
205
|
|
189
206
|
finish!
|
190
207
|
end
|
191
208
|
|
192
209
|
# Set the response content type to text/html.
|
210
|
+
#
|
193
211
|
# @param str [String] the response body
|
212
|
+
#
|
194
213
|
# @return [void]
|
214
|
+
#
|
215
|
+
# @api public
|
195
216
|
def html(str = nil, status: 200)
|
196
|
-
|
197
|
-
|
198
|
-
|
217
|
+
put_status(status)
|
218
|
+
put_header('Content-Type', 'text/html')
|
219
|
+
put_body(str)
|
199
220
|
|
200
221
|
finish!
|
201
222
|
end
|
202
223
|
|
224
|
+
# This method will render the template.
|
225
|
+
#
|
203
226
|
# @param template_nam [String] the template name
|
204
227
|
# @param path [String] the template path, default is 'views'
|
205
228
|
# @param locals [Hash] the template locals
|
229
|
+
#
|
206
230
|
# @return [void | Exception]
|
207
|
-
# @note This method will render the template.
|
208
|
-
# The template engine is determined by the
|
209
|
-
# file extension.
|
210
231
|
#
|
211
232
|
# @example
|
212
233
|
# render('index')
|
@@ -245,112 +266,113 @@ module Lenna
|
|
245
266
|
end
|
246
267
|
|
247
268
|
# Helper methods for the response.
|
248
|
-
#
|
269
|
+
#
|
249
270
|
# @return [void]
|
250
|
-
#
|
271
|
+
#
|
272
|
+
# @api public
|
273
|
+
#
|
274
|
+
# @see #render
|
275
|
+
# @see #finish!
|
251
276
|
def not_found
|
252
|
-
|
253
|
-
|
277
|
+
put_body(['Not Found'])
|
278
|
+
put_status(404)
|
279
|
+
|
254
280
|
finish!
|
255
281
|
end
|
256
282
|
|
257
283
|
private
|
258
284
|
|
259
|
-
#
|
285
|
+
# This method will get the response status.
|
286
|
+
#
|
260
287
|
# @return [Integer] the response status
|
261
|
-
#
|
262
|
-
def fetch_status = _status
|
263
|
-
|
288
|
+
#
|
264
289
|
# @api private
|
265
|
-
|
266
|
-
# @note This method will get the response status.
|
267
|
-
def status!(value)
|
290
|
+
def put_status(value)
|
268
291
|
value => ::Integer
|
269
292
|
|
270
|
-
self.
|
293
|
+
self.status = value
|
271
294
|
rescue ::NoMatchingPatternError
|
272
295
|
raise ::ArgumentError, 'status must be an integer'
|
273
296
|
end
|
274
297
|
|
275
|
-
#
|
276
|
-
#
|
277
|
-
def fetch_body = _body
|
278
|
-
|
279
|
-
# @api private
|
298
|
+
# This method will set the body.
|
299
|
+
#
|
280
300
|
# @param body [Array(String)] the body to be used
|
281
301
|
# @return [void]
|
282
|
-
|
283
|
-
|
284
|
-
body => ::String | ::Array
|
302
|
+
def put_body(value)
|
303
|
+
value => ::String | ::Array
|
285
304
|
|
286
305
|
case value
|
287
|
-
in ::String then
|
288
|
-
in ::Array then
|
306
|
+
in ::String then @body = [value]
|
307
|
+
in ::Array then @body = value
|
289
308
|
end
|
290
309
|
rescue ::NoMatchingPatternError
|
291
310
|
raise ::ArgumentError, 'body must be a string or an array'
|
292
311
|
end
|
293
312
|
|
294
|
-
# @api private
|
295
|
-
# @param header [String] the header name
|
296
|
-
# @return [String] the header value
|
297
|
-
# @note This method will get the header value.
|
298
|
-
def fetch_header(header) = _headers[header]
|
299
|
-
|
300
|
-
# @api private
|
301
|
-
# @return [Hash] the response headers
|
302
|
-
def fetch_headers = _headers
|
303
|
-
|
304
|
-
# @api private
|
305
313
|
# @param key [String] the header name
|
306
314
|
# @param value [String] the value to be used
|
315
|
+
#
|
307
316
|
# @return [void]
|
308
|
-
|
309
|
-
|
310
|
-
# be appended to the header.
|
311
|
-
def header!(key, value)
|
312
|
-
key => ::String
|
313
|
-
value => ::String | ::Array
|
317
|
+
def put_header(key, value)
|
318
|
+
raise ::ArgumentError, 'key must be a string' unless key.is_a?(::String)
|
314
319
|
|
315
|
-
|
316
|
-
|
317
|
-
case value
|
318
|
-
in ::String then _headers[key] = [*header_value, value].uniq.join(', ')
|
319
|
-
in ::Array then _headers[key] = [*header_value, *value].uniq.join(', ')
|
320
|
+
unless value.is_a?(::String) || value.is_a?(::Array)
|
321
|
+
raise ::ArgumentError, 'value must be a string or an array'
|
320
322
|
end
|
321
|
-
|
322
|
-
|
323
|
+
|
324
|
+
header_value = @headers[key]
|
325
|
+
|
326
|
+
new_values = ::Array.wrap(value)
|
327
|
+
existing_values = ::Array.wrap(header_value)
|
328
|
+
|
329
|
+
@headers[key] = (existing_values + new_values).uniq.join(', ')
|
323
330
|
end
|
324
331
|
|
325
|
-
# @api private
|
326
332
|
# @param key [String] the header name
|
333
|
+
#
|
327
334
|
# @return [void]
|
328
|
-
|
329
|
-
def delete_header(key) = _headers.delete(key)
|
335
|
+
def delete_header(key) = @headers.delete(key)
|
330
336
|
|
331
|
-
# @api private
|
332
337
|
# @param value [String] the redirect location
|
338
|
+
#
|
333
339
|
# @return [void]
|
334
340
|
def location!(value)
|
335
341
|
value => ::String
|
336
342
|
|
337
|
-
|
343
|
+
put_header('Location', value)
|
338
344
|
end
|
339
345
|
|
340
|
-
#
|
341
|
-
#
|
342
|
-
# @return [String] the size of the content
|
343
|
-
# @note This method will get the size of the content.
|
344
|
-
def content_length!(value) = header!('Content-Length', value)
|
345
|
-
|
346
|
-
# @api private
|
346
|
+
# This method will finish the response.
|
347
|
+
#
|
347
348
|
# @return [void]
|
348
|
-
# @note This method will finish the response.
|
349
349
|
def finish!
|
350
|
-
|
351
|
-
|
350
|
+
default_router_header!
|
351
|
+
default_content_length! unless @headers['Content-Length']
|
352
|
+
default_html_content_type! unless @headers['Content-Type']
|
353
|
+
|
354
|
+
[@status, @headers, @body]
|
355
|
+
end
|
352
356
|
|
353
|
-
|
357
|
+
# This method will set the response default html content type.
|
358
|
+
#
|
359
|
+
# @return [void]
|
360
|
+
def default_html_content_type!
|
361
|
+
put_header('Content-Type', 'text/html')
|
362
|
+
end
|
363
|
+
|
364
|
+
# This method will set the response default content length.
|
365
|
+
#
|
366
|
+
# @return [void]
|
367
|
+
def default_content_length!
|
368
|
+
put_header('Content-Length', @body.join.size.to_s)
|
369
|
+
end
|
370
|
+
|
371
|
+
# This method will set the response default router header.
|
372
|
+
#
|
373
|
+
# @return [void]
|
374
|
+
def default_router_header!
|
375
|
+
put_header('Server', "Lennarb VERSION #{::Lennarb::VERSION}")
|
354
376
|
end
|
355
377
|
end
|
356
378
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lennarb
|
4
|
+
module ArrayExtensions
|
5
|
+
def wrap(object)
|
6
|
+
if object.nil?
|
7
|
+
[]
|
8
|
+
elsif object.respond_to?(:to_ary)
|
9
|
+
object.to_ary || [object]
|
10
|
+
else
|
11
|
+
[object]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Array.extend(Lennarb::ArrayExtensions)
|
data/lib/lennarb.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lennarb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aristóteles Coutinho
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-11-
|
11
|
+
date: 2023-11-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -141,6 +141,8 @@ files:
|
|
141
141
|
- lib/lenna/router/response.rb
|
142
142
|
- lib/lenna/router/route_matcher.rb
|
143
143
|
- lib/lennarb.rb
|
144
|
+
- lib/lennarb/array_extensions.rb
|
145
|
+
- lib/lennarb/version.rb
|
144
146
|
homepage: https://rubygems.org/gems/lennarb
|
145
147
|
licenses:
|
146
148
|
- MIT
|