class Utopia::Content
A middleware which serves dynamically generated content based on markup files.
Constants
- CACHE_CONTROL
- CONTENT_NAMESPACE
- CONTENT_TAG_NAME
- CONTENT_TYPE
- DEFERRED_TAG_NAME
- EXPIRES
Compatibility with older versions of rack:
- INDEX
- NO_CACHE
- Tag
- UTOPIA_NAMESPACE
- XNODE_EXTENSION
The file extension for markup nodes on disk.
Attributes
root[R]
Public Class Methods
new(app, root: Utopia::default_root, namespaces: {})
click to toggle source
@param root [String] The content root where pages will be generated from. @param namespaces [Hash<String,Library>] Tag
namespaces for dynamic tag lookup.
# File lib/utopia/content.rb, line 45 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
Public Instance Methods
call(env)
click to toggle source
# File lib/utopia/content.rb, line 110 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 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 return @app.call(env) end
fetch_template(path)
click to toggle source
# File lib/utopia/content.rb, line 80 def fetch_template(path) @template_cache.fetch_or_store(path.to_s) do Trenni::MarkupTemplate.load_file(path) end end
freeze()
click to toggle source
Calls superclass method
# File lib/utopia/content.rb, line 63 def freeze return self if frozen? @root.freeze @namespaces.values.each(&:freeze) @namespaces.freeze super end
links(path, **options)
click to toggle source
TODO we should remove this method and expose `@links` directly.
# File lib/utopia/content.rb, line 76 def links(path, **options) @links.index(path, **options) end
lookup_node(path, locale = nil)
click to toggle source
@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.
# File lib/utopia/content.rb, line 96 def lookup_node(path, locale = nil) resolve_link( @links.for(path, locale) ) end
lookup_tag(qualified_name, node)
click to toggle source
Look up a named tag such as `<entry />` or `<content:page>…`
# File lib/utopia/content.rb, line 87 def lookup_tag(qualified_name, node) namespace, name = Trenni::Tag.split(qualified_name) if library = @namespaces[namespace] library.call(name, node) end end
resolve_link(link)
click to toggle source
# File lib/utopia/content.rb, line 102 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
Private Instance Methods
content_tag(name, node)
click to toggle source
# File lib/utopia/content.rb, line 177 def content_tag(name, node) full_path = node.parent_path + name name = full_path.pop # If the current node is called 'foo', we can't lookup 'foo' in the current directory or we will have infinite recursion. while full_path.last == name full_path.pop end cache_key = full_path + name @node_cache.fetch_or_store(cache_key) do lookup_content(name, full_path) end end
lookup_content(name, parent_path)
click to toggle source
# File lib/utopia/content.rb, line 141 def lookup_content(name, parent_path) if String === name && name.index('/') name = Path.create(name) end if Path === name name = parent_path + name name_path = name.components.dup name_path[-1] += XNODE_EXTENSION else name_path = name + XNODE_EXTENSION end components = parent_path.components.dup while components.any? tag_path = File.join(@root, components, name_path) if File.exist? tag_path return Node.new(self, Path[components] + name, parent_path + name, tag_path) end if String === name_path tag_path = File.join(@root, components, '_' + name_path) if File.exist? tag_path return Node.new(self, Path[components] + name, parent_path + name, tag_path) end end components.pop end return nil end