utopia 2.30.2 → 2.31.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/bake/utopia/server.rb +1 -1
- data/bake/utopia/site.rb +3 -3
- data/context/getting-started.md +93 -0
- data/context/index.yaml +32 -0
- data/context/integrating-with-javascript.md +75 -0
- data/context/middleware.md +157 -0
- data/context/server-setup.md +116 -0
- data/context/updating-utopia.md +69 -0
- data/context/what-is-xnode.md +41 -0
- data/lib/utopia/content/document.rb +39 -37
- data/lib/utopia/content/link.rb +1 -2
- data/lib/utopia/content/links.rb +2 -2
- data/lib/utopia/content/markup.rb +10 -10
- data/lib/utopia/content/middleware.rb +195 -0
- data/lib/utopia/content/namespace.rb +1 -1
- data/lib/utopia/content/node.rb +1 -1
- data/lib/utopia/content/response.rb +1 -1
- data/lib/utopia/content/tags.rb +1 -1
- data/lib/utopia/content.rb +4 -186
- data/lib/utopia/controller/actions.md +8 -8
- data/lib/utopia/controller/actions.rb +1 -1
- data/lib/utopia/controller/base.rb +4 -4
- data/lib/utopia/controller/middleware.rb +133 -0
- data/lib/utopia/controller/respond.rb +2 -46
- data/lib/utopia/controller/responder.rb +103 -0
- data/lib/utopia/controller/rewrite.md +2 -2
- data/lib/utopia/controller/rewrite.rb +1 -1
- data/lib/utopia/controller/variables.rb +11 -5
- data/lib/utopia/controller.rb +4 -126
- data/lib/utopia/exceptions/mailer.rb +4 -4
- data/lib/utopia/extensions/array_split.rb +2 -2
- data/lib/utopia/extensions/date_comparisons.rb +3 -3
- data/lib/utopia/import_map.rb +374 -0
- data/lib/utopia/localization/middleware.rb +173 -0
- data/lib/utopia/localization/wrapper.rb +52 -0
- data/lib/utopia/localization.rb +4 -202
- data/lib/utopia/path.rb +26 -11
- data/lib/utopia/redirection.rb +2 -2
- data/lib/utopia/session/lazy_hash.rb +1 -1
- data/lib/utopia/session/middleware.rb +218 -0
- data/lib/utopia/session/serialization.rb +1 -1
- data/lib/utopia/session.rb +4 -205
- data/lib/utopia/static/local_file.rb +19 -19
- data/lib/utopia/static/middleware.rb +120 -0
- data/lib/utopia/static/mime_types.rb +1 -1
- data/lib/utopia/static.rb +4 -108
- data/lib/utopia/version.rb +1 -1
- data/lib/utopia.rb +1 -0
- data/readme.md +7 -0
- data/releases.md +7 -0
- data/setup/site/config.ru +1 -1
- data.tar.gz.sig +0 -0
- metadata +31 -4
- metadata.gz.sig +0 -0
- data/lib/utopia/locale.rb +0 -29
- data/lib/utopia/responder.rb +0 -59
data/lib/utopia/static.rb
CHANGED
|
@@ -3,116 +3,12 @@
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
4
|
# Copyright, 2009-2025, by Samuel Williams.
|
|
5
5
|
|
|
6
|
-
require_relative "middleware"
|
|
7
|
-
require_relative "localization"
|
|
8
|
-
|
|
9
|
-
require_relative "static/local_file"
|
|
10
|
-
require_relative "static/mime_types"
|
|
11
|
-
|
|
12
|
-
require "traces/provider"
|
|
6
|
+
require_relative "static/middleware"
|
|
13
7
|
|
|
14
8
|
module Utopia
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
# @param root [String] The root directory to serve files from.
|
|
20
|
-
# @param types [Array] The mime-types (and file extensions) to recognize/serve.
|
|
21
|
-
# @param cache_control [String] The cache-control header to set for static content.
|
|
22
|
-
def initialize(app, root: Utopia::default_root, types: MIME_TYPES[:default], cache_control: DEFAULT_CACHE_CONTROL)
|
|
23
|
-
@app = app
|
|
24
|
-
@root = root
|
|
25
|
-
|
|
26
|
-
@extensions = MimeTypeLoader.extensions_for(types)
|
|
27
|
-
|
|
28
|
-
@cache_control = cache_control
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def freeze
|
|
32
|
-
return self if frozen?
|
|
33
|
-
|
|
34
|
-
@root.freeze
|
|
35
|
-
@extensions.freeze
|
|
36
|
-
@cache_control.freeze
|
|
37
|
-
|
|
38
|
-
super
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def fetch_file(path)
|
|
42
|
-
# We need file_path to be an absolute path for X-Sendfile to work correctly.
|
|
43
|
-
file_path = File.join(@root, path.components)
|
|
44
|
-
|
|
45
|
-
if File.exist?(file_path)
|
|
46
|
-
return LocalFile.new(@root, path)
|
|
47
|
-
else
|
|
48
|
-
return nil
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
attr :extensions
|
|
53
|
-
|
|
54
|
-
LAST_MODIFIED = "Last-Modified".freeze
|
|
55
|
-
CONTENT_TYPE = HTTP::CONTENT_TYPE
|
|
56
|
-
CACHE_CONTROL = HTTP::CACHE_CONTROL
|
|
57
|
-
ETAG = "ETag".freeze
|
|
58
|
-
ACCEPT_RANGES = "Accept-Ranges".freeze
|
|
59
|
-
|
|
60
|
-
def response_headers_for(file, content_type)
|
|
61
|
-
if @cache_control.respond_to?(:call)
|
|
62
|
-
cache_control = @cache_control.call(file)
|
|
63
|
-
else
|
|
64
|
-
cache_control = @cache_control
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
{
|
|
68
|
-
LAST_MODIFIED => file.mtime_date,
|
|
69
|
-
CONTENT_TYPE => content_type,
|
|
70
|
-
CACHE_CONTROL => cache_control,
|
|
71
|
-
ETAG => file.etag,
|
|
72
|
-
ACCEPT_RANGES => "bytes"
|
|
73
|
-
}
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def respond(env, path_info, extension)
|
|
77
|
-
path = Path[path_info].simplify
|
|
78
|
-
|
|
79
|
-
if locale = env[Localization::CURRENT_LOCALE_KEY]
|
|
80
|
-
path.last.insert(path.last.rindex(".") || -1, ".#{locale}")
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
if file = fetch_file(path)
|
|
84
|
-
response_headers = self.response_headers_for(file, @extensions[extension])
|
|
85
|
-
|
|
86
|
-
if file.modified?(env)
|
|
87
|
-
return file.serve(env, response_headers)
|
|
88
|
-
else
|
|
89
|
-
return [304, response_headers, []]
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def call(env)
|
|
95
|
-
path_info = env[Rack::PATH_INFO]
|
|
96
|
-
extension = File.extname(path_info)
|
|
97
|
-
|
|
98
|
-
if @extensions.key?(extension.downcase)
|
|
99
|
-
if response = self.respond(env, path_info, extension)
|
|
100
|
-
return response
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# else if no file was found:
|
|
105
|
-
return @app.call(env)
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
Traces::Provider(Static) do
|
|
110
|
-
def respond(env, path_info, extension)
|
|
111
|
-
attributes = {
|
|
112
|
-
path_info: path_info,
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
Traces.trace("utopia.static.respond", attributes: attributes) {super}
|
|
9
|
+
module Static
|
|
10
|
+
def self.new(...)
|
|
11
|
+
Middleware.new(...)
|
|
116
12
|
end
|
|
117
13
|
end
|
|
118
14
|
end
|
data/lib/utopia/version.rb
CHANGED
data/lib/utopia.rb
CHANGED
data/readme.md
CHANGED
|
@@ -31,6 +31,13 @@ Please see the [project documentation](https://socketry.github.io/utopia/) for m
|
|
|
31
31
|
|
|
32
32
|
Please see the [project releases](https://socketry.github.io/utopia/releases/index) for all releases.
|
|
33
33
|
|
|
34
|
+
### v2.31.0
|
|
35
|
+
|
|
36
|
+
- Add agent context.
|
|
37
|
+
- Better simplification of relative paths, e.g. `../../foo` is not modified to `foo`.
|
|
38
|
+
- Move top level classes into `class Middleware` in their respective namespaces.
|
|
39
|
+
- Move `Utopia::Responder` into `Utopia::Controller` layer.
|
|
40
|
+
|
|
34
41
|
### v2.30.1
|
|
35
42
|
|
|
36
43
|
- Minor compatibility fixes.
|
data/releases.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Releases
|
|
2
2
|
|
|
3
|
+
## v2.31.0
|
|
4
|
+
|
|
5
|
+
- Add agent context.
|
|
6
|
+
- Better simplification of relative paths, e.g. `../../foo` is not modified to `foo`.
|
|
7
|
+
- Move top level classes into `class Middleware` in their respective namespaces.
|
|
8
|
+
- Move `Utopia::Responder` into `Utopia::Controller` layer.
|
|
9
|
+
|
|
3
10
|
## v2.30.1
|
|
4
11
|
|
|
5
12
|
- Minor compatibility fixes.
|
data/setup/site/config.ru
CHANGED
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: utopia
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.31.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -169,6 +169,20 @@ dependencies:
|
|
|
169
169
|
- - ">="
|
|
170
170
|
- !ruby/object:Gem::Version
|
|
171
171
|
version: '0'
|
|
172
|
+
- !ruby/object:Gem::Dependency
|
|
173
|
+
name: protocol-url
|
|
174
|
+
requirement: !ruby/object:Gem::Requirement
|
|
175
|
+
requirements:
|
|
176
|
+
- - "~>"
|
|
177
|
+
- !ruby/object:Gem::Version
|
|
178
|
+
version: '0.4'
|
|
179
|
+
type: :runtime
|
|
180
|
+
prerelease: false
|
|
181
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
182
|
+
requirements:
|
|
183
|
+
- - "~>"
|
|
184
|
+
- !ruby/object:Gem::Version
|
|
185
|
+
version: '0.4'
|
|
172
186
|
- !ruby/object:Gem::Dependency
|
|
173
187
|
name: rack
|
|
174
188
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -250,12 +264,20 @@ files:
|
|
|
250
264
|
- bake/utopia/shell.rb
|
|
251
265
|
- bake/utopia/site.rb
|
|
252
266
|
- bake/utopia/static.rb
|
|
267
|
+
- context/getting-started.md
|
|
268
|
+
- context/index.yaml
|
|
269
|
+
- context/integrating-with-javascript.md
|
|
270
|
+
- context/middleware.md
|
|
271
|
+
- context/server-setup.md
|
|
272
|
+
- context/updating-utopia.md
|
|
273
|
+
- context/what-is-xnode.md
|
|
253
274
|
- lib/utopia.rb
|
|
254
275
|
- lib/utopia/content.rb
|
|
255
276
|
- lib/utopia/content/document.rb
|
|
256
277
|
- lib/utopia/content/link.rb
|
|
257
278
|
- lib/utopia/content/links.rb
|
|
258
279
|
- lib/utopia/content/markup.rb
|
|
280
|
+
- lib/utopia/content/middleware.rb
|
|
259
281
|
- lib/utopia/content/namespace.rb
|
|
260
282
|
- lib/utopia/content/node.rb
|
|
261
283
|
- lib/utopia/content/response.rb
|
|
@@ -264,7 +286,9 @@ files:
|
|
|
264
286
|
- lib/utopia/controller/actions.md
|
|
265
287
|
- lib/utopia/controller/actions.rb
|
|
266
288
|
- lib/utopia/controller/base.rb
|
|
289
|
+
- lib/utopia/controller/middleware.rb
|
|
267
290
|
- lib/utopia/controller/respond.rb
|
|
291
|
+
- lib/utopia/controller/responder.rb
|
|
268
292
|
- lib/utopia/controller/rewrite.md
|
|
269
293
|
- lib/utopia/controller/rewrite.rb
|
|
270
294
|
- lib/utopia/controller/variables.rb
|
|
@@ -274,20 +298,23 @@ files:
|
|
|
274
298
|
- lib/utopia/extensions/array_split.rb
|
|
275
299
|
- lib/utopia/extensions/date_comparisons.rb
|
|
276
300
|
- lib/utopia/http.rb
|
|
277
|
-
- lib/utopia/
|
|
301
|
+
- lib/utopia/import_map.rb
|
|
278
302
|
- lib/utopia/localization.rb
|
|
303
|
+
- lib/utopia/localization/middleware.rb
|
|
304
|
+
- lib/utopia/localization/wrapper.rb
|
|
279
305
|
- lib/utopia/middleware.rb
|
|
280
306
|
- lib/utopia/path.rb
|
|
281
307
|
- lib/utopia/path/matcher.rb
|
|
282
308
|
- lib/utopia/redirection.rb
|
|
283
|
-
- lib/utopia/responder.rb
|
|
284
309
|
- lib/utopia/session.rb
|
|
285
310
|
- lib/utopia/session/lazy_hash.rb
|
|
311
|
+
- lib/utopia/session/middleware.rb
|
|
286
312
|
- lib/utopia/session/serialization.rb
|
|
287
313
|
- lib/utopia/setup.rb
|
|
288
314
|
- lib/utopia/shell.rb
|
|
289
315
|
- lib/utopia/static.rb
|
|
290
316
|
- lib/utopia/static/local_file.rb
|
|
317
|
+
- lib/utopia/static/middleware.rb
|
|
291
318
|
- lib/utopia/static/mime_types.rb
|
|
292
319
|
- lib/utopia/version.rb
|
|
293
320
|
- license.md
|
|
@@ -339,7 +366,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
339
366
|
- !ruby/object:Gem::Version
|
|
340
367
|
version: '0'
|
|
341
368
|
requirements: []
|
|
342
|
-
rubygems_version: 3.
|
|
369
|
+
rubygems_version: 3.7.2
|
|
343
370
|
specification_version: 4
|
|
344
371
|
summary: Utopia is a framework for building dynamic content-driven websites.
|
|
345
372
|
test_files: []
|
metadata.gz.sig
CHANGED
|
Binary file
|
data/lib/utopia/locale.rb
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2015-2025, by Samuel Williams.
|
|
5
|
-
|
|
6
|
-
module Utopia
|
|
7
|
-
# A structured representation of locale based on RFC3066.
|
|
8
|
-
Locale = Struct.new(:language, :country, :variant) do
|
|
9
|
-
def to_s
|
|
10
|
-
to_a.compact.join("-")
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def self.dump(instance)
|
|
14
|
-
if instance
|
|
15
|
-
instance.to_s
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def self.load(instance)
|
|
20
|
-
if instance.is_a? String
|
|
21
|
-
self.new(*instance.split("-", 3))
|
|
22
|
-
elsif instance.is_a? Array
|
|
23
|
-
return self.new(*instance)
|
|
24
|
-
elsif instance.is_a? self
|
|
25
|
-
return instance.frozen? ? instance : instance.dup
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
data/lib/utopia/responder.rb
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2020-2025, by Samuel Williams.
|
|
5
|
-
|
|
6
|
-
require_relative "middleware"
|
|
7
|
-
|
|
8
|
-
module Utopia
|
|
9
|
-
class Responder
|
|
10
|
-
Handler = Struct.new(:content_type, :block) do
|
|
11
|
-
def split(*arguments)
|
|
12
|
-
self.content_type.split(*arguments)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def call(context, request, media_range, *arguments, **options)
|
|
16
|
-
context.instance_exec(media_range, *arguments, **options, &self.block)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
Responds = Struct.new(:responder, :context, :request) do
|
|
21
|
-
# @todo Refactor `object` -> `*arguments`...
|
|
22
|
-
def with(object, **options)
|
|
23
|
-
responder.call(context, request, object, **options)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def initialize
|
|
28
|
-
@handlers = HTTP::Accept::MediaTypes::Map.new
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
attr :handlers
|
|
32
|
-
|
|
33
|
-
def freeze
|
|
34
|
-
@handlers.freeze
|
|
35
|
-
|
|
36
|
-
super
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def call(context, request, *arguments, **options)
|
|
40
|
-
# Parse the list of browser preferred content types and return ordered by priority:
|
|
41
|
-
media_types = HTTP::Accept::MediaTypes.browser_preferred_media_types(request.env)
|
|
42
|
-
|
|
43
|
-
handler, media_range = @handlers.for(media_types)
|
|
44
|
-
|
|
45
|
-
if handler
|
|
46
|
-
handler.call(context, request, media_range, *arguments, **options)
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Add a converter for the specified content type. Call the block with the response content if the request accepts the specified content_type.
|
|
51
|
-
def handle(content_type, &block)
|
|
52
|
-
@handlers << Handler.new(content_type, block)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def respond_to(context, request)
|
|
56
|
-
Responds.new(self, context, request)
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|