class Middleware
A middleware which serves dynamically generated content based on markup files.
Definitions
def initialize(app, root: Utopia::default_root, namespaces: {})
Implementation
def initialize(app, root: Utopia::default_root, namespaces: {})
@app = app
@root = root
@template_cache = Concurrent::Map.new
@node_cache = Concurrent::Map.new
@links = Links.new(@root)
@namespaces = namespaces
# Default content namespace for dynamic path based lookup:
@namespaces[CONTENT_NAMESPACE] ||= self.method(:content_tag)
# The core namespace for utopia specific functionality:
@namespaces[UTOPIA_NAMESPACE] ||= Tags
end
def freeze
Freeze this object and its internal state.
Signature
-
returns
self This object.
Implementation
def freeze
return self if frozen?
@root.freeze
@namespaces.values.each(&:freeze)
@namespaces.freeze
super
end
def links(path, **options)
TODO we should remove this method and expose @links directly.
Implementation
def links(path, **options)
@links.index(path, **options)
end
def fetch_template(path)
Load and cache a content template.
Signature
-
parameter
pathUtopia::Path | String The path.
-
returns
XRB::Template The parsed template.
Implementation
def fetch_template(path)
@template_cache.fetch_or_store(path.to_s) do
XRB::Template.load_file(path)
end
end
def lookup_tag(qualified_name, node)
Look up a named tag such as <entry /> or <content:page>...
Implementation
def lookup_tag(qualified_name, node)
namespace, name = XRB::Tag.split(qualified_name)
if library = @namespaces[namespace]
library.call(name, node)
end
end
def lookup_node(path, locale = nil)
Implementation
def lookup_node(path, locale = nil)
resolve_link(
@links.for(path, locale)
)
end
def resolve_link(link)
Resolve a link to an existing content node.
Signature
-
parameter
linkUtopia::Content::Link The content link.
-
returns
Node | Nil The content node when its backing file exists.
Implementation
def resolve_link(link)
if full_path = link&.full_path(@root)
if File.exist?(full_path)
return Node.new(self, link.path, link.path, full_path)
end
end
end
def respond(link, request)
Respond.
Signature
-
parameter
linkUtopia::Content::Link The content link.
-
parameter
requestRack::Request The request.
-
returns
Array The response.
Implementation
def respond(link, request)
if node = resolve_link(link)
attributes = request.env.fetch(VARIABLES_KEY, {}).to_hash
return node.process!(request, attributes)
elsif redirect_uri = link[:uri]
return [307, {HTTP::LOCATION => redirect_uri}, []]
end
end
def call(env)
Serve or redirect filesystem-backed content, otherwise invoke the application.
Signature
-
parameter
envHash The Rack environment.
-
returns
Array The Rack response.
Implementation
def call(env)
request = Rack::Request.new(env)
path = Path.create(request.path_info)
# Check if the request is to a non-specific index. This only works for requests with a given name:
basename = path.basename
directory_path = File.join(@root, path.dirname.components, basename)
# If the request for /foo/bar is actually a directory, rewrite it to /foo/bar/index:
if File.directory? directory_path
index_path = [basename, INDEX]
return [307, {HTTP::LOCATION => path.dirname.join(index_path).to_s}, []]
end
locale = env[Localization::CURRENT_LOCALE_KEY]
if link = @links.for(path, locale)
if response = self.respond(link, request)
return response
end
end
return @app.call(env)
end