syntropy 0.26 → 0.27
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 -0
- data/lib/syntropy/applets/builtin/default_error_handler.rb +11 -8
- data/lib/syntropy/errors.rb +4 -4
- data/lib/syntropy/module.rb +25 -21
- data/lib/syntropy/request_extensions.rb +36 -4
- data/lib/syntropy/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b84251781cfce3688f58c6f25a754b0699d97fe4a7c51f390b63635b45007960
|
4
|
+
data.tar.gz: 69e85137dcee6b399d3198303f9de4227b5276521a6c964eca5ac4954a9fb10f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd871276c35cd2a9c216f37ec1361794e34f489af71580a1da5cebef244830daf0e2bc4e418abe28623607e8da5693ead8074dd1f397ba9ea61afb0e4bcf7d96
|
7
|
+
data.tar.gz: 2b3ae1c3c4691d247357a8ec3d9f7e3da778c0fcdd7a94de84b2d83c94ffe75c7beb7ec7883976c2ca09b5c45225391b9322e28a32be9cc3a55acfc6d8c5ac9e
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
# 0.27 2025-10-21
|
2
|
+
|
3
|
+
- Use accept header (instead of user-agent) for rendering error page
|
4
|
+
- Add `Request#accept?` method
|
5
|
+
- Fix import path normalization, module method visibility
|
6
|
+
- Fix instantiation of Syntropy::Error
|
7
|
+
- Improve default error handler response
|
8
|
+
- Fix and enhance `Request#html_response`, `Request#json_response` methods
|
9
|
+
|
1
10
|
# 0.26 2025-10-21
|
2
11
|
|
3
12
|
- Add /.syntropy/req route for testing request headers
|
@@ -35,21 +35,24 @@ def transform_backtrace(backtrace)
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
38
|
+
def error_response_html(req, error)
|
39
39
|
status = Syntropy::Error.http_status(error)
|
40
40
|
backtrace = transform_backtrace(error.backtrace)
|
41
41
|
html = Papercraft.html(ErrorPage, error:, status:, backtrace:)
|
42
|
-
req.
|
42
|
+
req.html_response(html, ':status' => status)
|
43
43
|
end
|
44
44
|
|
45
45
|
def error_response_raw(req, error)
|
46
|
-
status =
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
status = Syntropy::Error.http_status(error)
|
47
|
+
response = {
|
48
|
+
class: error.class.to_s,
|
49
|
+
message: error.message,
|
50
|
+
backtrace: error.backtrace
|
51
|
+
}
|
52
|
+
req.json_pretty_response(response, ':status' => status)
|
50
53
|
end
|
51
54
|
|
52
55
|
export ->(req, error) {
|
53
|
-
req.
|
54
|
-
|
56
|
+
req.accept?('text/html') ?
|
57
|
+
error_response_html(req, error) : error_response_raw(req, error)
|
55
58
|
}
|
data/lib/syntropy/errors.rb
CHANGED
@@ -21,17 +21,17 @@ module Syntropy
|
|
21
21
|
# Creates an error with status 404 Not Found
|
22
22
|
#
|
23
23
|
# @return [Syntropy::Error]
|
24
|
-
def self.not_found(msg = '') = new(Status::NOT_FOUND
|
24
|
+
def self.not_found(msg = 'Not found') = new(msg, Status::NOT_FOUND)
|
25
25
|
|
26
26
|
# Creates an error with status 405 Method Not Allowed
|
27
27
|
#
|
28
28
|
# @return [Syntropy::Error]
|
29
|
-
def self.method_not_allowed(msg = '') = new(Status::METHOD_NOT_ALLOWED
|
29
|
+
def self.method_not_allowed(msg = 'Method not allowed') = new(msg, Status::METHOD_NOT_ALLOWED)
|
30
30
|
|
31
31
|
# Creates an error with status 418 I'm a teapot
|
32
32
|
#
|
33
33
|
# @return [Syntropy::Error]
|
34
|
-
def self.teapot(msg = '') = new(Status::TEAPOT
|
34
|
+
def self.teapot(msg = 'I\'m a teapot') = new(msg, Status::TEAPOT)
|
35
35
|
|
36
36
|
attr_reader :http_status
|
37
37
|
|
@@ -40,7 +40,7 @@ module Syntropy
|
|
40
40
|
# @param http_status [Integer, String] HTTP status
|
41
41
|
# @param msg [String] error message
|
42
42
|
# @return [void]
|
43
|
-
def initialize(
|
43
|
+
def initialize(msg = 'Internal server error', http_status = DEFAULT_STATUS)
|
44
44
|
super(msg)
|
45
45
|
@http_status = http_status
|
46
46
|
end
|
data/lib/syntropy/module.rb
CHANGED
@@ -116,7 +116,8 @@ module Syntropy
|
|
116
116
|
def clean_ref(ref)
|
117
117
|
return '/' if ref =~ /^index(\+)?$/
|
118
118
|
|
119
|
-
ref.gsub(/\/index(?:\+)?$/, '')
|
119
|
+
clean = ref.gsub(/\/index(?:\+)?$/, '')
|
120
|
+
clean == '' ? '/' : clean
|
120
121
|
end
|
121
122
|
|
122
123
|
# Transforms the given export value. If the value is nil, an exception is
|
@@ -180,10 +181,21 @@ module Syntropy
|
|
180
181
|
@app = env[:app]
|
181
182
|
@ref = env[:ref]
|
182
183
|
@logger = env[:logger]
|
184
|
+
@__dependencies__ = []
|
183
185
|
singleton_class.const_set(:MODULE, self)
|
184
186
|
end
|
185
187
|
|
186
|
-
attr_reader :__export_value__
|
188
|
+
attr_reader :__export_value__, :__dependencies__
|
189
|
+
|
190
|
+
# Returns a list of pages found at the given ref.
|
191
|
+
#
|
192
|
+
# @param ref [String] directory reference
|
193
|
+
# @return [Array] array of pages found in directory
|
194
|
+
def page_list(ref)
|
195
|
+
Syntropy.page_list(@env, ref)
|
196
|
+
end
|
197
|
+
|
198
|
+
private
|
187
199
|
|
188
200
|
# Exports the given value. This value will be used as the module's
|
189
201
|
# entrypoint. It can be any Ruby value, but for a route module would
|
@@ -195,23 +207,23 @@ module Syntropy
|
|
195
207
|
@__export_value__ = v
|
196
208
|
end
|
197
209
|
|
198
|
-
# Returns the list of module references imported by the module.
|
199
|
-
#
|
200
|
-
# @return [Array] array of module references
|
201
|
-
def __dependencies__
|
202
|
-
@__dependencies__ ||= []
|
203
|
-
end
|
204
|
-
|
205
210
|
# Imports the module corresponding to the given reference. The return value
|
206
211
|
# is the module's export value.
|
207
212
|
#
|
208
213
|
# @param ref [String] module reference
|
209
214
|
# @return [any] loaded dependency's export value
|
210
215
|
def import(ref)
|
211
|
-
|
212
|
-
@module_loader.load(
|
213
|
-
|
214
|
-
|
216
|
+
ref = normalize_import_ref(ref)
|
217
|
+
@module_loader.load(ref).tap { __dependencies__ << ref }
|
218
|
+
end
|
219
|
+
|
220
|
+
def normalize_import_ref(ref)
|
221
|
+
base = @ref == '' ? '/' : @ref
|
222
|
+
if ref =~ /^\//
|
223
|
+
ref
|
224
|
+
else
|
225
|
+
File.expand_path(File.join(File.dirname(base), ref))
|
226
|
+
end
|
215
227
|
end
|
216
228
|
|
217
229
|
# Creates and returns a Papercraft template created with the given block.
|
@@ -242,14 +254,6 @@ module Syntropy
|
|
242
254
|
raise
|
243
255
|
end
|
244
256
|
|
245
|
-
# Returns a list of pages found at the given ref.
|
246
|
-
#
|
247
|
-
# @param ref [String] directory reference
|
248
|
-
# @return [Array] array of pages found in directory
|
249
|
-
def page_list(ref)
|
250
|
-
Syntropy.page_list(@env, ref)
|
251
|
-
end
|
252
|
-
|
253
257
|
# Creates and returns a Syntropy app for the given environment. The app's
|
254
258
|
# environment is based on the module's env merged with the given parameters.
|
255
259
|
#
|
@@ -185,12 +185,28 @@ module Syntropy
|
|
185
185
|
raise Syntropy::Error.new(Qeweney::Status::BAD_REQUEST, 'Invalid form data')
|
186
186
|
end
|
187
187
|
|
188
|
-
def
|
189
|
-
respond(
|
188
|
+
def html_response(html, **headers)
|
189
|
+
respond(
|
190
|
+
html,
|
191
|
+
'Content-Type' => 'text/html; charset=utf-8',
|
192
|
+
**headers
|
193
|
+
)
|
190
194
|
end
|
191
195
|
|
192
|
-
def json_response(obj)
|
193
|
-
respond(
|
196
|
+
def json_response(obj, **headers)
|
197
|
+
respond(
|
198
|
+
JSON.dump(obj),
|
199
|
+
'Content-Type' => 'application/json; charset=utf-8',
|
200
|
+
**headers
|
201
|
+
)
|
202
|
+
end
|
203
|
+
|
204
|
+
def json_pretty_response(obj, **headers)
|
205
|
+
respond(
|
206
|
+
JSON.pretty_generate(obj),
|
207
|
+
'Content-Type' => 'application/json; charset=utf-8',
|
208
|
+
**headers
|
209
|
+
)
|
194
210
|
end
|
195
211
|
|
196
212
|
def browser?
|
@@ -198,8 +214,24 @@ module Syntropy
|
|
198
214
|
user_agent && user_agent =~ /^Mozilla\//
|
199
215
|
end
|
200
216
|
|
217
|
+
# Returns true if the accept header includes the given MIME type
|
218
|
+
#
|
219
|
+
# @param mime_type [String] MIME type
|
220
|
+
# @return [bool]
|
221
|
+
def accept?(mime_type)
|
222
|
+
accept = headers['accept']
|
223
|
+
return nil if !accept
|
224
|
+
|
225
|
+
@accept_parts ||= parse_accept_parts(accept)
|
226
|
+
@accept_parts.include?(mime_type)
|
227
|
+
end
|
228
|
+
|
201
229
|
private
|
202
230
|
|
231
|
+
def parse_accept_parts(accept)
|
232
|
+
accept.split(',').map { it.match(/^\s*([^\s;]+)/)[1] }
|
233
|
+
end
|
234
|
+
|
203
235
|
BOOL_REGEXP = /^(t|f|true|false|on|off|1|0|yes|no)$/
|
204
236
|
BOOL_TRUE_REGEXP = /^(t|true|on|1|yes)$/
|
205
237
|
INTEGER_REGEXP = /^[+-]?[0-9]+$/
|
data/lib/syntropy/version.rb
CHANGED