Class: Utopia::Content

Inherits:
Object
  • Object
show all
Defined in:
lib/utopia/content.rb,
lib/utopia/content/link.rb,
lib/utopia/content/node.rb,
lib/utopia/content/tags.rb,
lib/utopia/content/links.rb,
lib/utopia/content/markup.rb,
lib/utopia/content/document.rb,
lib/utopia/content/response.rb,
lib/utopia/content/namespace.rb

Overview

A middleware which serves dynamically generated content based on markup files.

Defined Under Namespace

Modules: Namespace, Tags Classes: Document, Link, Links, MarkupParser, Node, Response, SymbolicHash, UnbalancedTagError

Constant Summary collapse

CONTENT_NAMESPACE =
'content'.freeze
UTOPIA_NAMESPACE =
'utopia'.freeze
DEFERRED_TAG_NAME =
'utopia:deferred'.freeze
CONTENT_TAG_NAME =
'utopia:content'.freeze
XNODE_EXTENSION =

The file extension for markup nodes on disk.

'.xnode'
INDEX =
"index"
Tag =
XRB::Tag
EXPIRES =

Compatibility with older versions of rack:

'expires'.freeze
CACHE_CONTROL =
'cache-control'.freeze
CONTENT_TYPE =
'content-type'.freeze
NO_CACHE =
'no-cache'.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, root: Utopia::default_root, namespaces: {}) ⇒ Content

Returns a new instance of Content.

Parameters:

  • root (String) (defaults to: Utopia::default_root)

    The content root where pages will be generated from.

  • namespaces (Hash<String,Library>) (defaults to: {})

    Tag namespaces for dynamic tag lookup.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/utopia/content.rb', line 30

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

Instance Attribute Details

#rootObject (readonly)

Returns the value of attribute root.



58
59
60
# File 'lib/utopia/content.rb', line 58

def root
  @root
end

Instance Method Details

#call(env) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/utopia/content.rb', line 105

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

#fetch_template(path) ⇒ Object



65
66
67
68
69
# File 'lib/utopia/content.rb', line 65

def fetch_template(path)
	@template_cache.fetch_or_store(path.to_s) do
		XRB::Template.load_file(path)
	end
end

#freezeObject



48
49
50
51
52
53
54
55
56
# File 'lib/utopia/content.rb', line 48

def freeze
	return self if frozen?
	
	@root.freeze
	@namespaces.values.each(&:freeze)
	@namespaces.freeze
	
	super
end

TODO we should remove this method and expose ‘@links` directly.



61
62
63
# File 'lib/utopia/content.rb', line 61

def links(path, **options)
	@links.index(path, **options)
end

#lookup_node(path, locale = nil) ⇒ Object

Parameters:

  • 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
82
83
84
85
# File 'lib/utopia/content.rb', line 81

def lookup_node(path, locale = nil)
	resolve_link(
		@links.for(path, locale)
	)
end

#lookup_tag(qualified_name, node) ⇒ Object

Look up a named tag such as ‘<entry />` or `<content:page>…`



72
73
74
75
76
77
78
# File 'lib/utopia/content.rb', line 72

def lookup_tag(qualified_name, node)
	namespace, name = XRB::Tag.split(qualified_name)
	
	if library = @namespaces[namespace]
		library.call(name, node)
	end
end


87
88
89
90
91
92
93
# File 'lib/utopia/content.rb', line 87

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

#respond(link, request) ⇒ Object



95
96
97
98
99
100
101
102
103
# File 'lib/utopia/content.rb', line 95

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