Skip to content

Commit a1ce655

Browse files
committed
Use nested class for middleware.
1 parent 4996be3 commit a1ce655

31 files changed

+935
-914
lines changed

lib/utopia/content.rb

Lines changed: 4 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -3,194 +3,12 @@
33
# Released under the MIT License.
44
# Copyright, 2009-2025, by Samuel Williams.
55

6-
require_relative "middleware"
7-
require_relative "localization"
8-
9-
require_relative "content/links"
10-
require_relative "content/node"
11-
require_relative "content/markup"
12-
require_relative "content/tags"
13-
14-
require "xrb/template"
15-
16-
require "concurrent/map"
17-
18-
require "traces/provider"
6+
require_relative "content/middleware"
197

208
module Utopia
21-
# A middleware which serves dynamically generated content based on markup files.
22-
class Content
23-
CONTENT_NAMESPACE = "content".freeze
24-
UTOPIA_NAMESPACE = "utopia".freeze
25-
DEFERRED_TAG_NAME = "utopia:deferred".freeze
26-
CONTENT_TAG_NAME = "utopia:content".freeze
27-
28-
# @param root [String] The content root where pages will be generated from.
29-
# @param namespaces [Hash<String,Library>] Tag namespaces for dynamic tag lookup.
30-
def initialize(app, root: Utopia::default_root, namespaces: {})
31-
@app = app
32-
@root = root
33-
34-
@template_cache = Concurrent::Map.new
35-
@node_cache = Concurrent::Map.new
36-
37-
@links = Links.new(@root)
38-
39-
@namespaces = namespaces
40-
41-
# Default content namespace for dynamic path based lookup:
42-
@namespaces[CONTENT_NAMESPACE] ||= self.method(:content_tag)
43-
44-
# The core namespace for utopia specific functionality:
45-
@namespaces[UTOPIA_NAMESPACE] ||= Tags
46-
end
47-
48-
def freeze
49-
return self if frozen?
50-
51-
@root.freeze
52-
@namespaces.values.each(&:freeze)
53-
@namespaces.freeze
54-
55-
super
56-
end
57-
58-
attr :root
59-
60-
# TODO we should remove this method and expose `@links` directly.
61-
def links(path, **options)
62-
@links.index(path, **options)
63-
end
64-
65-
def fetch_template(path)
66-
@template_cache.fetch_or_store(path.to_s) do
67-
XRB::Template.load_file(path)
68-
end
69-
end
70-
71-
# Look up a named tag such as `<entry />` or `<content:page>...`
72-
def lookup_tag(qualified_name, node)
73-
namespace, name = XRB::Tag.split(qualified_name)
74-
75-
if library = @namespaces[namespace]
76-
library.call(name, node)
77-
end
78-
end
79-
80-
# @param path [Path] the request path is an absolute uri path, e.g. `/foo/bar`. If an xnode file exists on disk for this exact path, it is instantiated, otherwise nil.
81-
def lookup_node(path, locale = nil)
82-
resolve_link(
83-
@links.for(path, locale)
84-
)
85-
end
86-
87-
def resolve_link(link)
88-
if full_path = link&.full_path(@root)
89-
if File.exist?(full_path)
90-
return Node.new(self, link.path, link.path, full_path)
91-
end
92-
end
93-
end
94-
95-
def respond(link, request)
96-
if node = resolve_link(link)
97-
attributes = request.env.fetch(VARIABLES_KEY, {}).to_hash
98-
99-
return node.process!(request, attributes)
100-
elsif redirect_uri = link[:uri]
101-
return [307, {HTTP::LOCATION => redirect_uri}, []]
102-
end
103-
end
104-
105-
def call(env)
106-
request = Rack::Request.new(env)
107-
path = Path.create(request.path_info)
108-
109-
# Check if the request is to a non-specific index. This only works for requests with a given name:
110-
basename = path.basename
111-
directory_path = File.join(@root, path.dirname.components, basename)
112-
113-
# If the request for /foo/bar is actually a directory, rewrite it to /foo/bar/index:
114-
if File.directory? directory_path
115-
index_path = [basename, INDEX]
116-
117-
return [307, {HTTP::LOCATION => path.dirname.join(index_path).to_s}, []]
118-
end
119-
120-
locale = env[Localization::CURRENT_LOCALE_KEY]
121-
if link = @links.for(path, locale)
122-
if response = self.respond(link, request)
123-
return response
124-
end
125-
end
126-
127-
return @app.call(env)
128-
end
129-
130-
private
131-
132-
def lookup_content(name, parent_path)
133-
if String === name && name.index("/")
134-
name = Path.create(name)
135-
end
136-
137-
if Path === name
138-
name = parent_path + name
139-
name_path = name.components.dup
140-
name_path[-1] += XNODE_EXTENSION
141-
else
142-
name_path = name + XNODE_EXTENSION
143-
end
144-
145-
components = parent_path.components.dup
146-
147-
while components.any?
148-
tag_path = File.join(@root, components, name_path)
149-
150-
if File.exist? tag_path
151-
return Node.new(self, Path[components] + name, parent_path + name, tag_path)
152-
end
153-
154-
if String === name_path
155-
tag_path = File.join(@root, components, "_" + name_path)
156-
157-
if File.exist? tag_path
158-
return Node.new(self, Path[components] + name, parent_path + name, tag_path)
159-
end
160-
end
161-
162-
components.pop
163-
end
164-
165-
return nil
166-
end
167-
168-
def content_tag(name, node)
169-
full_path = node.parent_path + name
170-
171-
name = full_path.pop
172-
173-
# If the current node is called 'foo', we can't lookup 'foo' in the current directory or we will have infinite recursion.
174-
while full_path.last == name
175-
full_path.pop
176-
end
177-
178-
cache_key = full_path + name
179-
180-
@node_cache.fetch_or_store(cache_key) do
181-
lookup_content(name, full_path)
182-
end
183-
end
184-
end
185-
186-
Traces::Provider(Content) do
187-
def respond(link, request)
188-
attributes = {
189-
"link.key" => link.key,
190-
"link.href" => link.href
191-
}
192-
193-
Traces.trace("utopia.content.respond", attributes: attributes) {super}
9+
module Content
10+
def self.new(...)
11+
Middleware.new(...)
19412
end
19513
end
19614
end

lib/utopia/content/document.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
require_relative "markup"
99

1010
module Utopia
11-
class Content
11+
module Content
12+
DEFERRED_TAG_NAME = "utopia:deferred".freeze
13+
1214
# This error is raised if a tag doesn't match up when parsing.
1315
class UnbalancedTagError < StandardError
1416
def initialize(tag)

lib/utopia/content/link.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111
require "xrb/strings"
1212

1313
require_relative "../path"
14-
require_relative "../locale"
1514

1615
module Utopia
17-
class Content
16+
module Content
1817
# Represents a link to some content with associated metadata.
1918
class Link
2019
# @param kind [Symbol] the kind of link.

lib/utopia/content/links.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
require "concurrent/map"
99

1010
module Utopia
11-
class Content
11+
module Content
1212
# The file extension for markup nodes on disk.
1313
XNODE_EXTENSION = ".xnode"
1414
INDEX = "index"

lib/utopia/content/markup.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
require "xrb/tag"
1010

1111
module Utopia
12-
class Content
12+
module Content
1313
Tag = XRB::Tag
1414

1515
# A hash which forces all keys to be symbols and fails with KeyError when strings are used.

0 commit comments

Comments
 (0)