lennarb 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|