utopia 2.11.1 → 2.12.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
- data/Gemfile +2 -0
- data/Rakefile +2 -0
- data/benchmarks/call_vs_check.rb +2 -0
- data/benchmarks/const_vs_hash.rb +2 -0
- data/benchmarks/hash_vs_openstruct.rb +2 -0
- data/benchmarks/string_vs_symbol.rb +2 -0
- data/benchmarks/struct_vs_class.rb +2 -0
- data/documentation/Gemfile +1 -0
- data/documentation/Rakefile +1 -0
- data/documentation/config.ru +1 -0
- data/documentation/config/environment.rb +1 -0
- data/documentation/pages/wiki/controller.rb +1 -0
- data/documentation/spec/website_context.rb +1 -0
- data/documentation/spec/website_spec.rb +1 -0
- data/lib/utopia.rb +2 -0
- data/lib/utopia/command.rb +2 -0
- data/lib/utopia/command/environment.rb +2 -0
- data/lib/utopia/command/server.rb +2 -0
- data/lib/utopia/command/site.rb +2 -0
- data/lib/utopia/content.rb +10 -1
- data/lib/utopia/content/document.rb +2 -0
- data/lib/utopia/content/link.rb +2 -0
- data/lib/utopia/content/links.rb +160 -124
- data/lib/utopia/content/markup.rb +2 -0
- data/lib/utopia/content/namespace.rb +2 -0
- data/lib/utopia/content/node.rb +6 -3
- data/lib/utopia/content/response.rb +2 -0
- data/lib/utopia/content/tags.rb +2 -0
- data/lib/utopia/content_length.rb +2 -0
- data/lib/utopia/controller.rb +2 -0
- data/lib/utopia/controller/actions.rb +2 -0
- data/lib/utopia/controller/base.rb +2 -0
- data/lib/utopia/controller/respond.rb +2 -0
- data/lib/utopia/controller/rewrite.rb +2 -0
- data/lib/utopia/controller/variables.rb +2 -0
- data/lib/utopia/exceptions.rb +2 -0
- data/lib/utopia/exceptions/handler.rb +2 -0
- data/lib/utopia/exceptions/mailer.rb +2 -0
- data/lib/utopia/extensions/array_split.rb +2 -0
- data/lib/utopia/extensions/date_comparisons.rb +2 -0
- data/lib/utopia/http.rb +2 -0
- data/lib/utopia/locale.rb +2 -0
- data/lib/utopia/localization.rb +2 -0
- data/lib/utopia/logger.rb +2 -0
- data/lib/utopia/middleware.rb +2 -0
- data/lib/utopia/path.rb +2 -0
- data/lib/utopia/path/matcher.rb +2 -0
- data/lib/utopia/redirection.rb +2 -0
- data/lib/utopia/session.rb +2 -0
- data/lib/utopia/session/lazy_hash.rb +2 -0
- data/lib/utopia/session/serialization.rb +2 -0
- data/lib/utopia/setup.rb +2 -0
- data/lib/utopia/static.rb +2 -0
- data/lib/utopia/static/local_file.rb +2 -0
- data/lib/utopia/static/mime_types.rb +2 -0
- data/lib/utopia/version.rb +3 -1
- data/setup/site/Gemfile +1 -0
- data/setup/site/Rakefile +1 -0
- data/setup/site/config.ru +1 -0
- data/setup/site/config/environment.rb +1 -0
- data/setup/site/falcon.rb +1 -0
- data/setup/site/spec/spec_helper.rb +1 -0
- data/setup/site/spec/website_context.rb +1 -0
- data/setup/site/spec/website_spec.rb +1 -0
- data/setup/site/tasks/deploy.rake +1 -0
- data/setup/site/tasks/development.rake +1 -0
- data/setup/site/tasks/environment.rake +1 -0
- data/setup/site/tasks/log.rake +1 -0
- data/setup/site/tasks/static.rake +1 -0
- data/setup/site/tasks/yarn.rake +1 -0
- data/spec/mock_node.rb +1 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/utopia/command_spec.rb +2 -0
- data/spec/utopia/content/document_spec.rb +2 -0
- data/spec/utopia/content/link_spec.rb +1 -0
- data/spec/utopia/content/links_spec.rb +21 -21
- data/spec/utopia/content/markup_spec.rb +1 -0
- data/spec/utopia/content/namespace_spec.rb +2 -0
- data/spec/utopia/content/node_spec.rb +2 -0
- data/spec/utopia/content/response_spec.rb +2 -0
- data/spec/utopia/content/tags_spec.rb +2 -0
- data/spec/utopia/content_spec.rb +2 -0
- data/spec/utopia/content_spec.ru +1 -0
- data/spec/utopia/controller/actions_spec.rb +1 -0
- data/spec/utopia/controller/middleware_spec.rb +1 -0
- data/spec/utopia/controller/middleware_spec.ru +1 -0
- data/spec/utopia/controller/middleware_spec/controller/controller.rb +1 -0
- data/spec/utopia/controller/middleware_spec/controller/nested/controller.rb +1 -0
- data/spec/utopia/controller/middleware_spec/redirect/controller.rb +1 -0
- data/spec/utopia/controller/middleware_spec/redirect/test/controller.rb +1 -0
- data/spec/utopia/controller/respond_spec.rb +1 -0
- data/spec/utopia/controller/respond_spec.ru +1 -0
- data/spec/utopia/controller/respond_spec/api/controller.rb +1 -0
- data/spec/utopia/controller/respond_spec/errors/controller.rb +1 -0
- data/spec/utopia/controller/respond_spec/html/controller.rb +1 -0
- data/spec/utopia/controller/respond_spec/rewrite/controller.rb +1 -0
- data/spec/utopia/controller/rewrite_spec.rb +1 -0
- data/spec/utopia/controller/sequence_spec.rb +2 -1
- data/spec/utopia/controller/variables_spec.rb +1 -0
- data/spec/utopia/controller/websocket_spec.rb +1 -0
- data/spec/utopia/controller/websocket_spec.ru +1 -0
- data/spec/utopia/controller/websocket_spec/server/controller.rb +1 -0
- data/spec/utopia/exceptions/handler_spec.rb +1 -0
- data/spec/utopia/exceptions/handler_spec.ru +1 -0
- data/spec/utopia/exceptions/handler_spec/controller.rb +1 -0
- data/spec/utopia/exceptions/mailer_spec.rb +1 -0
- data/spec/utopia/exceptions/mailer_spec.ru +1 -0
- data/spec/utopia/extensions_spec.rb +2 -0
- data/spec/utopia/http/status_spec.rb +2 -0
- data/spec/utopia/locale_spec.rb +2 -0
- data/spec/utopia/localization_spec.rb +2 -0
- data/spec/utopia/localization_spec.ru +1 -0
- data/spec/utopia/localization_spec/controller.rb +1 -0
- data/spec/utopia/middleware_spec.rb +2 -0
- data/spec/utopia/path/matcher_spec.rb +1 -0
- data/spec/utopia/path_spec.rb +1 -0
- data/spec/utopia/performance_spec.rb +2 -0
- data/spec/utopia/performance_spec/config.ru +1 -0
- data/spec/utopia/performance_spec/pages/api/controller.rb +1 -0
- data/spec/utopia/rack_helper.rb +2 -0
- data/spec/utopia/redirection_spec.rb +2 -0
- data/spec/utopia/redirection_spec.ru +1 -0
- data/spec/utopia/session_spec.rb +2 -0
- data/spec/utopia/session_spec.ru +1 -0
- data/spec/utopia/setup_spec.rb +2 -0
- data/spec/utopia/static_spec.rb +2 -0
- data/spec/utopia/static_spec.ru +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9f1ccbf6d14948ea0dba9dc444126117dcecfec2723bd6bda6278c8cb61e33f2
|
|
4
|
+
data.tar.gz: 5d3bceb49b3e9d08bb7a88720445238b3fd6603afdc2862c918afae33ebd70b0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 45e93d16075a9f89a49fe3f1797ce2e337fb95abdc5a286b9d85c88320920ce020e14285f80f48bc5c25d7f1b45d5378a05157c7bd7354a9f5b5787a2b5b413f
|
|
7
|
+
data.tar.gz: d9cbdaf061fc4d22e6657318adb33e59d6df1b1b07e93150f705b481e0561a6dfd376c0afbecc3a946203dd9c3b05ae05f6c5b932bc54f6f2c345afc630a1d0c
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
data/benchmarks/call_vs_check.rb
CHANGED
data/benchmarks/const_vs_hash.rb
CHANGED
data/documentation/Gemfile
CHANGED
data/documentation/Rakefile
CHANGED
data/documentation/config.ru
CHANGED
data/lib/utopia.rb
CHANGED
data/lib/utopia/command.rb
CHANGED
data/lib/utopia/command/site.rb
CHANGED
data/lib/utopia/content.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
|
2
4
|
#
|
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
@@ -21,6 +23,7 @@
|
|
|
21
23
|
require_relative 'middleware'
|
|
22
24
|
require_relative 'localization'
|
|
23
25
|
|
|
26
|
+
require_relative 'content/links'
|
|
24
27
|
require_relative 'content/node'
|
|
25
28
|
require_relative 'content/markup'
|
|
26
29
|
require_relative 'content/tags'
|
|
@@ -46,6 +49,8 @@ module Utopia
|
|
|
46
49
|
@template_cache = Concurrent::Map.new
|
|
47
50
|
@node_cache = Concurrent::Map.new
|
|
48
51
|
|
|
52
|
+
@links = Links.new(@root)
|
|
53
|
+
|
|
49
54
|
@namespaces = namespaces
|
|
50
55
|
|
|
51
56
|
# Default content namespace for dynamic path based lookup:
|
|
@@ -67,6 +72,10 @@ module Utopia
|
|
|
67
72
|
|
|
68
73
|
attr :root
|
|
69
74
|
|
|
75
|
+
def links(path, **options)
|
|
76
|
+
@links.index(path, options)
|
|
77
|
+
end
|
|
78
|
+
|
|
70
79
|
def fetch_template(path)
|
|
71
80
|
@template_cache.fetch_or_store(path.to_s) do
|
|
72
81
|
Trenni::MarkupTemplate.load_file(path)
|
|
@@ -112,7 +121,7 @@ module Utopia
|
|
|
112
121
|
end
|
|
113
122
|
|
|
114
123
|
locale = env[Localization::CURRENT_LOCALE_KEY]
|
|
115
|
-
if link =
|
|
124
|
+
if link = @links.for(path, locale)
|
|
116
125
|
if link.path and node = lookup_node(link.path)
|
|
117
126
|
attributes = request.env.fetch(VARIABLES_KEY, {}).to_hash
|
|
118
127
|
|
data/lib/utopia/content/link.rb
CHANGED
data/lib/utopia/content/links.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
|
2
4
|
#
|
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
@@ -20,15 +22,35 @@
|
|
|
20
22
|
|
|
21
23
|
require_relative 'link'
|
|
22
24
|
|
|
25
|
+
require 'concurrent/map'
|
|
26
|
+
|
|
23
27
|
module Utopia
|
|
24
28
|
class Content
|
|
25
29
|
# The file extension for markup nodes on disk.
|
|
26
30
|
XNODE_EXTENSION = '.xnode'.freeze
|
|
27
31
|
|
|
28
|
-
# Represents a list of {Link} instances relating to the structure of the content. They are formed from the `links.yaml` file and the actual directory structure on disk.
|
|
29
32
|
class Links
|
|
30
33
|
def self.for(root, path, locale = nil)
|
|
31
|
-
|
|
34
|
+
warn "Using uncached links metadata!"
|
|
35
|
+
self.new(root).for(path, locale)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.index(root, path, **options)
|
|
39
|
+
warn "Using uncached links metadata!"
|
|
40
|
+
self.new(root).index(path, **options)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
XNODE_FILTER = /^(.+)#{Regexp.escape XNODE_EXTENSION}$/
|
|
44
|
+
INDEX_XNODE_FILTER = /^(index(\..+)*)#{Regexp.escape XNODE_EXTENSION}$/
|
|
45
|
+
|
|
46
|
+
def initialize(root)
|
|
47
|
+
@root = root
|
|
48
|
+
|
|
49
|
+
@cache = Concurrent::Map.new
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def for(path, locale = nil)
|
|
53
|
+
links = Resolved.new(self, path.dirname)
|
|
32
54
|
|
|
33
55
|
links.lookup(path.last, locale)
|
|
34
56
|
end
|
|
@@ -42,10 +64,10 @@ module Utopia
|
|
|
42
64
|
:display => :display,
|
|
43
65
|
}
|
|
44
66
|
|
|
45
|
-
def
|
|
67
|
+
def index(path, **options)
|
|
46
68
|
options = DEFAULT_INDEX_OPTIONS.merge(options)
|
|
47
69
|
|
|
48
|
-
ordered =
|
|
70
|
+
ordered = Resolved.new(self, path, options).ordered
|
|
49
71
|
|
|
50
72
|
# This option filters a link based on the display parameter.
|
|
51
73
|
if display_key = options[:display]
|
|
@@ -81,152 +103,166 @@ module Utopia
|
|
|
81
103
|
return ordered
|
|
82
104
|
end
|
|
83
105
|
|
|
84
|
-
|
|
85
|
-
INDEX_XNODE_FILTER = /^(index(\..+)*)#{Regexp.escape XNODE_EXTENSION}$/
|
|
86
|
-
LINKS_YAML = "links.yaml"
|
|
87
|
-
|
|
88
|
-
DEFAULT_OPTIONS = {
|
|
89
|
-
:directories => true,
|
|
90
|
-
:files => true,
|
|
91
|
-
:virtuals => true,
|
|
92
|
-
:indices => true,
|
|
93
|
-
}
|
|
106
|
+
attr :root
|
|
94
107
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
108
|
+
# Represents a list of {Link} instances relating to the structure of the content. They are formed from the `links.yaml` file and the actual directory structure on disk.
|
|
109
|
+
class Resolved
|
|
110
|
+
DEFAULT_OPTIONS = {
|
|
111
|
+
:directories => true,
|
|
112
|
+
:files => true,
|
|
113
|
+
:virtuals => true,
|
|
114
|
+
:indices => true,
|
|
115
|
+
}
|
|
100
116
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
117
|
+
def initialize(links, top = Path.root, options = DEFAULT_OPTIONS)
|
|
118
|
+
raise ArgumentError.new("top path must be absolute") unless top.absolute?
|
|
119
|
+
|
|
120
|
+
@links = links
|
|
121
|
+
|
|
122
|
+
@top = top
|
|
123
|
+
@options = options
|
|
124
|
+
|
|
125
|
+
# top.components.first == '', but this isn't a problem here.
|
|
126
|
+
@path = File.join(links.root, top.components)
|
|
127
|
+
|
|
128
|
+
@ordered = []
|
|
129
|
+
@named = Hash.new{|h,k| h[k] = []}
|
|
130
|
+
|
|
131
|
+
if File.directory? @path
|
|
132
|
+
@metadata = links.metadata(@path)
|
|
133
|
+
|
|
134
|
+
load_links(@metadata.dup) do |link|
|
|
135
|
+
@ordered << link
|
|
136
|
+
@named[link.name] << link
|
|
137
|
+
end
|
|
138
|
+
else
|
|
139
|
+
@metadata = {}
|
|
140
|
+
end
|
|
141
|
+
end
|
|
104
142
|
|
|
105
|
-
|
|
106
|
-
|
|
143
|
+
attr :top
|
|
144
|
+
attr :ordered
|
|
145
|
+
attr :named
|
|
107
146
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
147
|
+
def each(locale)
|
|
148
|
+
return to_enum(:each, locale) unless block_given?
|
|
149
|
+
|
|
150
|
+
ordered.each do |links|
|
|
151
|
+
yield links.find{|link| link.locale == locale}
|
|
112
152
|
end
|
|
113
153
|
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
attr :top
|
|
117
|
-
attr :ordered
|
|
118
|
-
attr :named
|
|
119
|
-
|
|
120
|
-
def each(locale)
|
|
121
|
-
return to_enum(:each, locale) unless block_given?
|
|
122
154
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def lookup(name, locale = nil)
|
|
129
|
-
# This allows generic links to serve any locale requested.
|
|
130
|
-
if links = @named[name]
|
|
131
|
-
links.find{|link| link.locale == locale} || links.find{|link| link.locale == nil}
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
private
|
|
136
|
-
|
|
137
|
-
def self.symbolize_keys(hash)
|
|
138
|
-
# Second level attributes should be symbolic:
|
|
139
|
-
hash.each do |key, info|
|
|
140
|
-
hash[key] = info.each_with_object({}) { |(k,v),result| result[k.to_sym] = v }
|
|
155
|
+
def lookup(name, locale = nil)
|
|
156
|
+
# This allows generic links to serve any locale requested.
|
|
157
|
+
if links = @named[name]
|
|
158
|
+
links.find{|link| link.locale == locale} || links.find{|link| link.locale == nil}
|
|
159
|
+
end
|
|
141
160
|
end
|
|
142
161
|
|
|
143
|
-
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def self.metadata(path)
|
|
147
|
-
links_path = File.join(path, LINKS_YAML)
|
|
162
|
+
private
|
|
148
163
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
else
|
|
152
|
-
{}
|
|
164
|
+
def indices(path, &block)
|
|
165
|
+
Dir.entries(path).select{|filename| filename.match(INDEX_XNODE_FILTER)}
|
|
153
166
|
end
|
|
154
167
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
def indices(path, &block)
|
|
159
|
-
Dir.entries(path).select{|filename| filename.match(INDEX_XNODE_FILTER)}
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
def load_indices(name, path, metadata)
|
|
163
|
-
directory_metadata = metadata.delete(name) || {}
|
|
164
|
-
indices_metadata = Links.metadata(path)
|
|
165
|
-
|
|
166
|
-
indices_count = 0
|
|
167
|
-
|
|
168
|
-
indices(path).each do |filename|
|
|
169
|
-
index_name = File.basename(filename, XNODE_EXTENSION)
|
|
170
|
-
# Values in indices_metadata will override values in directory_metadata:
|
|
171
|
-
index_metadata = directory_metadata.merge(indices_metadata[index_name] || {})
|
|
168
|
+
def load_indices(name, path, metadata)
|
|
169
|
+
directory_metadata = metadata.delete(name) || {}
|
|
170
|
+
indices_metadata = @links.metadata(path)
|
|
172
171
|
|
|
173
|
-
|
|
172
|
+
indices_count = 0
|
|
174
173
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
174
|
+
indices(path).each do |filename|
|
|
175
|
+
index_name = File.basename(filename, XNODE_EXTENSION)
|
|
176
|
+
# Values in indices_metadata will override values in directory_metadata:
|
|
177
|
+
index_metadata = directory_metadata.merge(indices_metadata[index_name] || {})
|
|
178
|
+
|
|
179
|
+
directory_link = Link.new(:directory, @top + [name, index_name], index_metadata)
|
|
180
|
+
|
|
181
|
+
# Merge metadata from foo.en into foo/index.en
|
|
182
|
+
if directory_link.locale
|
|
183
|
+
localized_key = "#{directory_link.name}.#{directory_link.locale}"
|
|
184
|
+
if localized_metadata = metadata.delete(localized_key)
|
|
185
|
+
directory_link.info.update(localized_metadata)
|
|
186
|
+
end
|
|
180
187
|
end
|
|
188
|
+
|
|
189
|
+
yield directory_link
|
|
190
|
+
|
|
191
|
+
indices_count += 1
|
|
181
192
|
end
|
|
182
193
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
194
|
+
if indices_count == 0
|
|
195
|
+
# Specify a nil uri if no index could be found for the directory:
|
|
196
|
+
yield Link.new(:directory, top + [name], {:uri => nil}.merge(directory_metadata))
|
|
197
|
+
end
|
|
186
198
|
end
|
|
187
199
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
200
|
+
def entries(path)
|
|
201
|
+
Dir.entries(path).reject{|filename| filename.match(/^[\._]/)}
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def load_links(metadata, &block)
|
|
205
|
+
# Load all metadata for a given path:
|
|
206
|
+
metadata = @metadata.dup
|
|
207
|
+
|
|
208
|
+
# Check all entries in the given directory:
|
|
209
|
+
entries(@path).each do |filename|
|
|
210
|
+
path = File.join(@path, filename)
|
|
211
|
+
|
|
212
|
+
# There are two types of filelinks based links:
|
|
213
|
+
# 1/ Named files, e.g. foo.xnode, name=foo
|
|
214
|
+
# 2/ Directories, e.g. bar/index.xnode, name=bar
|
|
215
|
+
if File.directory?(path) and @options[:directories]
|
|
216
|
+
load_indices(filename, path, metadata, &block)
|
|
217
|
+
elsif filename.match(INDEX_XNODE_FILTER) and @options[:indices] == false
|
|
218
|
+
metadata.delete($1) # We don't include indices in the list of pages.
|
|
219
|
+
elsif filename.match(XNODE_FILTER) and @options[:files]
|
|
220
|
+
yield Link.new(:file, @top + $1, metadata.delete($1))
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
if @options[:virtuals]
|
|
225
|
+
# After processing all directory entries, we are left with virtual entries in the metadata:
|
|
226
|
+
metadata.each do |name, info|
|
|
227
|
+
virtual_link = Link.new(:virtual, name, info)
|
|
228
|
+
|
|
229
|
+
# Given a virtual named such as "welcome.cn", merge it with metadata from "welcome" if it exists:
|
|
230
|
+
if virtual_metadata = @metadata[virtual_link.name]
|
|
231
|
+
virtual_link.info.update(virtual_metadata)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
yield virtual_link
|
|
235
|
+
end
|
|
236
|
+
end
|
|
191
237
|
end
|
|
192
238
|
end
|
|
193
239
|
|
|
194
|
-
def
|
|
195
|
-
|
|
240
|
+
def metadata(path)
|
|
241
|
+
@cache.fetch_or_store(path.to_s) do
|
|
242
|
+
load(path).freeze
|
|
243
|
+
end
|
|
196
244
|
end
|
|
197
245
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
path = File.join(@path, filename)
|
|
205
|
-
|
|
206
|
-
# There are two types of filesystem based links:
|
|
207
|
-
# 1/ Named files, e.g. foo.xnode, name=foo
|
|
208
|
-
# 2/ Directories, e.g. bar/index.xnode, name=bar
|
|
209
|
-
if File.directory?(path) and @options[:directories]
|
|
210
|
-
load_indices(filename, path, metadata, &block)
|
|
211
|
-
elsif filename.match(INDEX_XNODE_FILTER) and @options[:indices] == false
|
|
212
|
-
metadata.delete($1) # We don't include indices in the list of pages.
|
|
213
|
-
elsif filename.match(XNODE_FILTER) and @options[:files]
|
|
214
|
-
yield Link.new(:file, @top + $1, metadata.delete($1))
|
|
215
|
-
end
|
|
246
|
+
private
|
|
247
|
+
|
|
248
|
+
def symbolize_keys(hash)
|
|
249
|
+
# Second level attributes should be symbolic:
|
|
250
|
+
hash.each do |key, info|
|
|
251
|
+
hash[key] = info.each_with_object({}) { |(k,v),result| result[k.to_sym] = v }
|
|
216
252
|
end
|
|
217
253
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
254
|
+
return hash
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
LINKS_YAML = "links.yaml"
|
|
258
|
+
|
|
259
|
+
def load(path)
|
|
260
|
+
yaml_path = File.join(path, LINKS_YAML)
|
|
261
|
+
|
|
262
|
+
if File.exist?(yaml_path) && data = YAML::load_file(yaml_path)
|
|
263
|
+
return symbolize_keys(data)
|
|
264
|
+
else
|
|
265
|
+
return {}
|
|
230
266
|
end
|
|
231
267
|
end
|
|
232
268
|
end
|