utopia 1.1.1 → 1.1.2
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/README.md +3 -3
- data/lib/utopia/content.rb +11 -7
- data/lib/utopia/content/links.rb +4 -1
- data/lib/utopia/content/node.rb +4 -272
- data/lib/utopia/content/processor.rb +1 -2
- data/lib/utopia/content/transaction.rb +295 -0
- data/lib/utopia/controller.rb +8 -6
- data/lib/utopia/path.rb +5 -21
- data/lib/utopia/version.rb +1 -1
- data/materials/utopia.png +0 -0
- data/materials/utopia.svg +25 -0
- data/utopia.gemspec +2 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d2e3b4571e1608dc18393ab64c06466768a317fb
|
4
|
+
data.tar.gz: 570850efbb213cd4991dbfcbb05af634cb7b393e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89d4c62731b34d5d7092b9eae18b8230ece7e0ed5afb0a4f6e899515f92e8064adeba3be65456ff0f205b32c532d986d6b25f9703e2e05e95a7803c44fe592f4
|
7
|
+
data.tar.gz: be1417acf04b2bbf7bc0e1060200db741884771275cf41604eb8ac8bbf67bb94a29634b3bdf38f500bf4d46e8d538e5b7880d813ef4bbf124e473d63a8bd5842
|
data/README.md
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
# Utopia
|
1
|
+
# 
|
2
2
|
|
3
3
|
Utopia is a website generation framework which provides a robust set of tools
|
4
4
|
to build highly complex dynamic websites. It uses the filesystem heavily for
|
5
5
|
content and provides functions for interacting with files and directories as
|
6
6
|
structure representing the website.
|
7
7
|
|
8
|
-
[](http://travis-ci.org/ioquatix/utopia)
|
9
|
+
[](https://codeclimate.com/github/ioquatix/utopia)
|
10
10
|
[](https://coveralls.io/r/ioquatix/utopia)
|
11
11
|
|
12
12
|
## Installation
|
data/lib/utopia/content.rb
CHANGED
@@ -26,17 +26,21 @@ require_relative 'content/processor'
|
|
26
26
|
|
27
27
|
require 'trenni/template'
|
28
28
|
|
29
|
+
require 'concurrent/map'
|
30
|
+
|
29
31
|
module Utopia
|
30
32
|
class Content
|
31
33
|
INDEX = 'index'.freeze
|
32
34
|
|
33
35
|
def initialize(app, **options)
|
34
36
|
@app = app
|
35
|
-
|
37
|
+
|
36
38
|
@root = File.expand_path(options[:root] || Utopia::default_root)
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
|
40
|
+
if options[:cache_templates]
|
41
|
+
@templates = Concurrent::Map.new
|
42
|
+
end
|
43
|
+
|
40
44
|
@tags = options.fetch(:tags, {})
|
41
45
|
end
|
42
46
|
|
@@ -45,14 +49,14 @@ module Utopia
|
|
45
49
|
|
46
50
|
def fetch_xml(path)
|
47
51
|
if @templates
|
48
|
-
@templates.
|
49
|
-
|
52
|
+
@templates.fetch_or_store(path.to_s) do
|
53
|
+
Trenni::Template.load(path)
|
50
54
|
end
|
51
55
|
else
|
52
56
|
Trenni::Template.load(path)
|
53
57
|
end
|
54
58
|
end
|
55
|
-
|
59
|
+
|
56
60
|
# Look up a named tag such as <entry />
|
57
61
|
def lookup_tag(name, parent_path)
|
58
62
|
if @tags.key? name
|
data/lib/utopia/content/links.rb
CHANGED
@@ -90,10 +90,13 @@ module Utopia
|
|
90
90
|
:indices => true,
|
91
91
|
}
|
92
92
|
|
93
|
-
def initialize(root, top = Path.
|
93
|
+
def initialize(root, top = Path.root, options = DEFAULT_OPTIONS)
|
94
|
+
raise ArgumentError.new("top path must be absolute") unless top.absolute?
|
95
|
+
|
94
96
|
@top = top
|
95
97
|
@options = options
|
96
98
|
|
99
|
+
# top.components.first == '', but this isn't a problem here.
|
97
100
|
@path = File.join(root, top.components)
|
98
101
|
@metadata = self.class.metadata(@path)
|
99
102
|
|
data/lib/utopia/content/node.rb
CHANGED
@@ -18,282 +18,14 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
-
require 'set'
|
22
|
-
|
23
21
|
require_relative 'processor'
|
24
22
|
require_relative 'links'
|
23
|
+
require_relative 'transaction'
|
24
|
+
|
25
|
+
require 'pathname'
|
25
26
|
|
26
27
|
module Utopia
|
27
28
|
class Content
|
28
|
-
class UnbalancedTagError < StandardError
|
29
|
-
def initialize(tag)
|
30
|
-
@tag = tag
|
31
|
-
|
32
|
-
super("Unbalanced tag #{tag.name}")
|
33
|
-
end
|
34
|
-
|
35
|
-
attr :tag
|
36
|
-
end
|
37
|
-
|
38
|
-
# A single request through content middleware.
|
39
|
-
class Transaction
|
40
|
-
# The state of a single tag being rendered.
|
41
|
-
class State
|
42
|
-
def initialize(tag, node)
|
43
|
-
@node = node
|
44
|
-
|
45
|
-
@buffer = StringIO.new
|
46
|
-
@overrides = {}
|
47
|
-
|
48
|
-
@tags = []
|
49
|
-
@attributes = tag.to_hash
|
50
|
-
|
51
|
-
@content = nil
|
52
|
-
@deferred = []
|
53
|
-
end
|
54
|
-
|
55
|
-
attr :attributes
|
56
|
-
attr :overrides
|
57
|
-
attr :content
|
58
|
-
attr :node
|
59
|
-
attr :tags
|
60
|
-
|
61
|
-
attr :deferred
|
62
|
-
|
63
|
-
def defer(value = nil, &block)
|
64
|
-
@deferred << block
|
65
|
-
|
66
|
-
Tag.closed("deferred", :id => @deferred.size - 1).to_html
|
67
|
-
end
|
68
|
-
|
69
|
-
def [](key)
|
70
|
-
@attributes[key.to_s]
|
71
|
-
end
|
72
|
-
|
73
|
-
def call(transaction)
|
74
|
-
@content = @buffer.string
|
75
|
-
@buffer = StringIO.new
|
76
|
-
|
77
|
-
if node.respond_to? :call
|
78
|
-
node.call(transaction, self)
|
79
|
-
else
|
80
|
-
transaction.parse_xml(@content)
|
81
|
-
end
|
82
|
-
|
83
|
-
return @buffer.string
|
84
|
-
end
|
85
|
-
|
86
|
-
def lookup(tag)
|
87
|
-
if override = @overrides[tag.name]
|
88
|
-
if override.respond_to? :call
|
89
|
-
return override.call(tag)
|
90
|
-
elsif String === override
|
91
|
-
return Tag.new(override, tag.attributes)
|
92
|
-
else
|
93
|
-
return override
|
94
|
-
end
|
95
|
-
else
|
96
|
-
return tag
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def cdata(text)
|
101
|
-
@buffer.write(text)
|
102
|
-
end
|
103
|
-
|
104
|
-
def markup(text)
|
105
|
-
cdata(text)
|
106
|
-
end
|
107
|
-
|
108
|
-
def tag_complete(tag)
|
109
|
-
tag.write_full_html(@buffer)
|
110
|
-
end
|
111
|
-
|
112
|
-
def tag_begin(tag)
|
113
|
-
@tags << tag
|
114
|
-
tag.write_open_html(@buffer)
|
115
|
-
end
|
116
|
-
|
117
|
-
def tag_end(tag)
|
118
|
-
raise UnbalancedTagError(tag) unless @tags.pop.name == tag.name
|
119
|
-
|
120
|
-
tag.write_close_html(@buffer)
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def initialize(request, response)
|
125
|
-
@begin_tags = []
|
126
|
-
@end_tags = []
|
127
|
-
|
128
|
-
@request = request
|
129
|
-
@response = response
|
130
|
-
end
|
131
|
-
|
132
|
-
attr :request
|
133
|
-
attr :response
|
134
|
-
|
135
|
-
# A helper method for accessing controller variables from view:
|
136
|
-
def controller
|
137
|
-
@request.env[VARIABLES_KEY]
|
138
|
-
end
|
139
|
-
|
140
|
-
def parse_xml(xml_data)
|
141
|
-
Processor.parse_xml(xml_data, self)
|
142
|
-
end
|
143
|
-
|
144
|
-
# Begin tags represents a list from outer to inner most tag.
|
145
|
-
# At any point in parsing xml, begin_tags is a list of the inner most tag,
|
146
|
-
# then the next outer tag, etc. This list is used for doing dependent lookups.
|
147
|
-
attr :begin_tags
|
148
|
-
|
149
|
-
# End tags represents a list of execution order. This is the order that end tags
|
150
|
-
# have appeared when evaluating nodes.
|
151
|
-
attr :end_tags
|
152
|
-
|
153
|
-
def attributes
|
154
|
-
return current.attributes
|
155
|
-
end
|
156
|
-
|
157
|
-
def current
|
158
|
-
@begin_tags[-1]
|
159
|
-
end
|
160
|
-
|
161
|
-
def content
|
162
|
-
@end_tags[-1].content
|
163
|
-
end
|
164
|
-
|
165
|
-
def parent
|
166
|
-
end_tags[-2]
|
167
|
-
end
|
168
|
-
|
169
|
-
def first
|
170
|
-
@begin_tags[0]
|
171
|
-
end
|
172
|
-
|
173
|
-
def tag(name, attributes = {}, &block)
|
174
|
-
tag = Tag.new(name, attributes)
|
175
|
-
|
176
|
-
node = tag_begin(tag)
|
177
|
-
|
178
|
-
yield node if block_given?
|
179
|
-
|
180
|
-
tag_end(tag)
|
181
|
-
end
|
182
|
-
|
183
|
-
def tag_complete(tag, node = nil)
|
184
|
-
if tag.name == "content"
|
185
|
-
current.markup(content)
|
186
|
-
else
|
187
|
-
node ||= lookup(tag)
|
188
|
-
|
189
|
-
if node
|
190
|
-
tag_begin(tag, node)
|
191
|
-
tag_end(tag)
|
192
|
-
else
|
193
|
-
current.tag_complete(tag)
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
def tag_begin(tag, node = nil)
|
199
|
-
node ||= lookup(tag)
|
200
|
-
|
201
|
-
if node
|
202
|
-
state = State.new(tag, node)
|
203
|
-
@begin_tags << state
|
204
|
-
|
205
|
-
if node.respond_to? :tag_begin
|
206
|
-
node.tag_begin(self, state)
|
207
|
-
end
|
208
|
-
|
209
|
-
return node
|
210
|
-
end
|
211
|
-
|
212
|
-
current.tag_begin(tag)
|
213
|
-
|
214
|
-
return nil
|
215
|
-
end
|
216
|
-
|
217
|
-
def cdata(text)
|
218
|
-
current.cdata(text)
|
219
|
-
end
|
220
|
-
|
221
|
-
def partial(*args, &block)
|
222
|
-
if block_given?
|
223
|
-
current.defer(&block)
|
224
|
-
else
|
225
|
-
current.defer do
|
226
|
-
tag(*args)
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
alias deferred_tag partial
|
232
|
-
|
233
|
-
def tag_end(tag = nil)
|
234
|
-
top = current
|
235
|
-
|
236
|
-
if top.tags.empty?
|
237
|
-
if top.node.respond_to? :tag_end
|
238
|
-
top.node.tag_end(self, top)
|
239
|
-
end
|
240
|
-
|
241
|
-
@end_tags << top
|
242
|
-
buffer = top.call(self)
|
243
|
-
|
244
|
-
@begin_tags.pop
|
245
|
-
@end_tags.pop
|
246
|
-
|
247
|
-
if current
|
248
|
-
current.markup(buffer)
|
249
|
-
end
|
250
|
-
|
251
|
-
return buffer
|
252
|
-
else
|
253
|
-
current.tag_end(tag)
|
254
|
-
end
|
255
|
-
|
256
|
-
return nil
|
257
|
-
end
|
258
|
-
|
259
|
-
def render_node(node, attributes = {})
|
260
|
-
state = State.new(attributes, node)
|
261
|
-
@begin_tags << state
|
262
|
-
|
263
|
-
return tag_end
|
264
|
-
end
|
265
|
-
|
266
|
-
# Takes an instance of Tag
|
267
|
-
def lookup(tag)
|
268
|
-
result = tag
|
269
|
-
node = nil
|
270
|
-
|
271
|
-
@begin_tags.reverse_each do |state|
|
272
|
-
result = state.lookup(result)
|
273
|
-
|
274
|
-
node ||= state.node if state.node.respond_to? :lookup
|
275
|
-
|
276
|
-
return result if Node === result
|
277
|
-
end
|
278
|
-
|
279
|
-
@end_tags.reverse_each do |state|
|
280
|
-
return state.node.lookup(result) if state.node.respond_to? :lookup
|
281
|
-
end
|
282
|
-
|
283
|
-
return nil
|
284
|
-
end
|
285
|
-
|
286
|
-
def method_missing(name, *args)
|
287
|
-
@begin_tags.reverse_each do |state|
|
288
|
-
if state.node.respond_to? name
|
289
|
-
return state.node.send(name, *args)
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
|
-
super
|
294
|
-
end
|
295
|
-
end
|
296
|
-
|
297
29
|
class Node
|
298
30
|
def initialize(controller, uri_path, request_path, file_path)
|
299
31
|
@controller = controller
|
@@ -385,4 +117,4 @@ module Utopia
|
|
385
117
|
end
|
386
118
|
end
|
387
119
|
end
|
388
|
-
end
|
120
|
+
end
|
@@ -49,8 +49,7 @@ module Utopia
|
|
49
49
|
attr :closing_tag
|
50
50
|
|
51
51
|
def to_s
|
52
|
-
"Unbalanced Tag Error. "
|
53
|
-
"Line #{@starting_line[:line_number]}: #{@current_tag} has been closed by #{@closing_tag} on line #{@ending_line[:line_number]}!"
|
52
|
+
"Unbalanced Tag Error. Line #{@starting_line[:line_number]}: #{@current_tag} has been closed by #{@closing_tag} on line #{@ending_line[:line_number]}!"
|
54
53
|
end
|
55
54
|
end
|
56
55
|
|
@@ -0,0 +1,295 @@
|
|
1
|
+
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
require_relative 'processor'
|
22
|
+
require_relative 'links'
|
23
|
+
|
24
|
+
module Utopia
|
25
|
+
class Content
|
26
|
+
class UnbalancedTagError < StandardError
|
27
|
+
def initialize(tag)
|
28
|
+
@tag = tag
|
29
|
+
|
30
|
+
super("Unbalanced tag #{tag.name}")
|
31
|
+
end
|
32
|
+
|
33
|
+
attr :tag
|
34
|
+
end
|
35
|
+
|
36
|
+
# A single request through content middleware.
|
37
|
+
class Transaction
|
38
|
+
# The state of a single tag being rendered.
|
39
|
+
class State
|
40
|
+
def initialize(tag, node)
|
41
|
+
@node = node
|
42
|
+
|
43
|
+
@buffer = StringIO.new
|
44
|
+
@overrides = {}
|
45
|
+
|
46
|
+
@tags = []
|
47
|
+
@attributes = tag.to_hash
|
48
|
+
|
49
|
+
@content = nil
|
50
|
+
@deferred = []
|
51
|
+
end
|
52
|
+
|
53
|
+
attr :attributes
|
54
|
+
attr :overrides
|
55
|
+
attr :content
|
56
|
+
attr :node
|
57
|
+
attr :tags
|
58
|
+
|
59
|
+
attr :deferred
|
60
|
+
|
61
|
+
def defer(value = nil, &block)
|
62
|
+
@deferred << block
|
63
|
+
|
64
|
+
Tag.closed("deferred", :id => @deferred.size - 1).to_html
|
65
|
+
end
|
66
|
+
|
67
|
+
def [](key)
|
68
|
+
@attributes[key.to_s]
|
69
|
+
end
|
70
|
+
|
71
|
+
def call(transaction)
|
72
|
+
@content = @buffer.string
|
73
|
+
@buffer = StringIO.new
|
74
|
+
|
75
|
+
if node.respond_to? :call
|
76
|
+
node.call(transaction, self)
|
77
|
+
else
|
78
|
+
transaction.parse_xml(@content)
|
79
|
+
end
|
80
|
+
|
81
|
+
return @buffer.string
|
82
|
+
end
|
83
|
+
|
84
|
+
def lookup(tag)
|
85
|
+
if override = @overrides[tag.name]
|
86
|
+
if override.respond_to? :call
|
87
|
+
return override.call(tag)
|
88
|
+
elsif String === override
|
89
|
+
return Tag.new(override, tag.attributes)
|
90
|
+
else
|
91
|
+
return override
|
92
|
+
end
|
93
|
+
else
|
94
|
+
return tag
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def cdata(text)
|
99
|
+
@buffer.write(text)
|
100
|
+
end
|
101
|
+
|
102
|
+
def markup(text)
|
103
|
+
cdata(text)
|
104
|
+
end
|
105
|
+
|
106
|
+
def tag_complete(tag)
|
107
|
+
tag.write_full_html(@buffer)
|
108
|
+
end
|
109
|
+
|
110
|
+
def tag_begin(tag)
|
111
|
+
@tags << tag
|
112
|
+
tag.write_open_html(@buffer)
|
113
|
+
end
|
114
|
+
|
115
|
+
def tag_end(tag)
|
116
|
+
raise UnbalancedTagError(tag) unless @tags.pop.name == tag.name
|
117
|
+
|
118
|
+
tag.write_close_html(@buffer)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def initialize(request, response)
|
123
|
+
@begin_tags = []
|
124
|
+
@end_tags = []
|
125
|
+
|
126
|
+
@request = request
|
127
|
+
@response = response
|
128
|
+
end
|
129
|
+
|
130
|
+
attr :request
|
131
|
+
attr :response
|
132
|
+
|
133
|
+
# A helper method for accessing controller variables from view:
|
134
|
+
def controller
|
135
|
+
@request.env[VARIABLES_KEY]
|
136
|
+
end
|
137
|
+
|
138
|
+
def parse_xml(xml_data)
|
139
|
+
Processor.parse_xml(xml_data, self)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Begin tags represents a list from outer to inner most tag.
|
143
|
+
# At any point in parsing xml, begin_tags is a list of the inner most tag,
|
144
|
+
# then the next outer tag, etc. This list is used for doing dependent lookups.
|
145
|
+
attr :begin_tags
|
146
|
+
|
147
|
+
# End tags represents a list of execution order. This is the order that end tags
|
148
|
+
# have appeared when evaluating nodes.
|
149
|
+
attr :end_tags
|
150
|
+
|
151
|
+
def attributes
|
152
|
+
return current.attributes
|
153
|
+
end
|
154
|
+
|
155
|
+
def current
|
156
|
+
@begin_tags[-1]
|
157
|
+
end
|
158
|
+
|
159
|
+
def content
|
160
|
+
@end_tags[-1].content
|
161
|
+
end
|
162
|
+
|
163
|
+
def parent
|
164
|
+
end_tags[-2]
|
165
|
+
end
|
166
|
+
|
167
|
+
def first
|
168
|
+
@begin_tags[0]
|
169
|
+
end
|
170
|
+
|
171
|
+
def tag(name, attributes = {}, &block)
|
172
|
+
tag = Tag.new(name, attributes)
|
173
|
+
|
174
|
+
node = tag_begin(tag)
|
175
|
+
|
176
|
+
yield node if block_given?
|
177
|
+
|
178
|
+
tag_end(tag)
|
179
|
+
end
|
180
|
+
|
181
|
+
def tag_complete(tag, node = nil)
|
182
|
+
if tag.name == "content"
|
183
|
+
current.markup(content)
|
184
|
+
else
|
185
|
+
node ||= lookup(tag)
|
186
|
+
|
187
|
+
if node
|
188
|
+
tag_begin(tag, node)
|
189
|
+
tag_end(tag)
|
190
|
+
else
|
191
|
+
current.tag_complete(tag)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def tag_begin(tag, node = nil)
|
197
|
+
node ||= lookup(tag)
|
198
|
+
|
199
|
+
if node
|
200
|
+
state = State.new(tag, node)
|
201
|
+
@begin_tags << state
|
202
|
+
|
203
|
+
if node.respond_to? :tag_begin
|
204
|
+
node.tag_begin(self, state)
|
205
|
+
end
|
206
|
+
|
207
|
+
return node
|
208
|
+
end
|
209
|
+
|
210
|
+
current.tag_begin(tag)
|
211
|
+
|
212
|
+
return nil
|
213
|
+
end
|
214
|
+
|
215
|
+
def cdata(text)
|
216
|
+
current.cdata(text)
|
217
|
+
end
|
218
|
+
|
219
|
+
def partial(*args, &block)
|
220
|
+
if block_given?
|
221
|
+
current.defer(&block)
|
222
|
+
else
|
223
|
+
current.defer do
|
224
|
+
tag(*args)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
alias deferred_tag partial
|
230
|
+
|
231
|
+
def tag_end(tag = nil)
|
232
|
+
top = current
|
233
|
+
|
234
|
+
if top.tags.empty?
|
235
|
+
if top.node.respond_to? :tag_end
|
236
|
+
top.node.tag_end(self, top)
|
237
|
+
end
|
238
|
+
|
239
|
+
@end_tags << top
|
240
|
+
buffer = top.call(self)
|
241
|
+
|
242
|
+
@begin_tags.pop
|
243
|
+
@end_tags.pop
|
244
|
+
|
245
|
+
if current
|
246
|
+
current.markup(buffer)
|
247
|
+
end
|
248
|
+
|
249
|
+
return buffer
|
250
|
+
else
|
251
|
+
current.tag_end(tag)
|
252
|
+
end
|
253
|
+
|
254
|
+
return nil
|
255
|
+
end
|
256
|
+
|
257
|
+
def render_node(node, attributes = {})
|
258
|
+
state = State.new(attributes, node)
|
259
|
+
@begin_tags << state
|
260
|
+
|
261
|
+
return tag_end
|
262
|
+
end
|
263
|
+
|
264
|
+
# Takes an instance of Tag
|
265
|
+
def lookup(tag)
|
266
|
+
result = tag
|
267
|
+
node = nil
|
268
|
+
|
269
|
+
@begin_tags.reverse_each do |state|
|
270
|
+
result = state.lookup(result)
|
271
|
+
|
272
|
+
node ||= state.node if state.node.respond_to? :lookup
|
273
|
+
|
274
|
+
return result if Node === result
|
275
|
+
end
|
276
|
+
|
277
|
+
@end_tags.reverse_each do |state|
|
278
|
+
return state.node.lookup(result) if state.node.respond_to? :lookup
|
279
|
+
end
|
280
|
+
|
281
|
+
return nil
|
282
|
+
end
|
283
|
+
|
284
|
+
def method_missing(name, *args)
|
285
|
+
@begin_tags.reverse_each do |state|
|
286
|
+
if state.node.respond_to? name
|
287
|
+
return state.node.send(name, *args)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
super
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
data/lib/utopia/controller.rb
CHANGED
@@ -27,6 +27,8 @@ require_relative 'controller/base'
|
|
27
27
|
|
28
28
|
require_relative 'controller/rewrite'
|
29
29
|
|
30
|
+
require 'concurrent/map'
|
31
|
+
|
30
32
|
module Utopia
|
31
33
|
module Controllers
|
32
34
|
def self.class_name_for_controller(controller)
|
@@ -48,18 +50,18 @@ module Utopia
|
|
48
50
|
def initialize(app, **options)
|
49
51
|
@app = app
|
50
52
|
@root = options[:root] || Utopia::default_root
|
51
|
-
|
52
|
-
@controllers = {}
|
53
53
|
|
54
|
-
|
54
|
+
if options[:cache_controllers]
|
55
|
+
@controllers = Concurrent::Map.new
|
56
|
+
end
|
55
57
|
end
|
56
58
|
|
57
59
|
attr :app
|
58
60
|
|
59
61
|
def lookup_controller(path)
|
60
|
-
if @
|
61
|
-
|
62
|
-
|
62
|
+
if @controllers
|
63
|
+
@controllers.fetch_or_store(path.to_s) do
|
64
|
+
load_controller_file(path)
|
63
65
|
end
|
64
66
|
else
|
65
67
|
return load_controller_file(path)
|
data/lib/utopia/path.rb
CHANGED
@@ -82,6 +82,10 @@ module Utopia
|
|
82
82
|
super
|
83
83
|
end
|
84
84
|
|
85
|
+
def self.root
|
86
|
+
self.new([''])
|
87
|
+
end
|
88
|
+
|
85
89
|
# Returns the length of the prefix which is shared by two strings.
|
86
90
|
def self.prefix_length(a, b)
|
87
91
|
[a.size, b.size].min.times{|i| return i if a[i] != b[i]}
|
@@ -115,19 +119,7 @@ module Utopia
|
|
115
119
|
def self.[] path
|
116
120
|
self.create(path)
|
117
121
|
end
|
118
|
-
|
119
|
-
# Expand a relative path relative to a root.
|
120
|
-
def self.expand(path, root)
|
121
|
-
case path
|
122
|
-
when Path
|
123
|
-
return path.expand(root)
|
124
|
-
when String
|
125
|
-
return path if path.start_with?('/')
|
126
|
-
end
|
127
|
-
|
128
|
-
Path[path].expand(root)
|
129
|
-
end
|
130
|
-
|
122
|
+
|
131
123
|
def self.split(path)
|
132
124
|
case path
|
133
125
|
when Path
|
@@ -198,14 +190,6 @@ module Utopia
|
|
198
190
|
to_str
|
199
191
|
end
|
200
192
|
|
201
|
-
def match(pattern)
|
202
|
-
to_str.match(pattern)
|
203
|
-
end
|
204
|
-
|
205
|
-
def =~ (pattern)
|
206
|
-
to_str =~ pattern
|
207
|
-
end
|
208
|
-
|
209
193
|
def to_a
|
210
194
|
@components
|
211
195
|
end
|
data/lib/utopia/version.rb
CHANGED
Binary file
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!-- Generator: Adobe Illustrator 15.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
3
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
4
|
+
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
5
|
+
width="420px" height="76.993px" viewBox="0 0 420 76.993" enable-background="new 0 0 420 76.993" xml:space="preserve">
|
6
|
+
<g>
|
7
|
+
<rect y="-0.246" fill="#F79433" width="420" height="74.246"/>
|
8
|
+
<rect y="54" fill="#4E8DD8" width="420" height="23"/>
|
9
|
+
<g>
|
10
|
+
<path fill="#FFFFFF" d="M74.365,68.163c2.379-2.981,4.189-6.661,5.131-10.939C80.41,53.068,81,48.311,81,43.083V0H18v43.083
|
11
|
+
c0,2.53,0.245,5.133,0.409,7.734c0.168,2.678,0.676,5.308,1.35,7.814c0.683,2.545,1.746,4.979,3.079,7.235
|
12
|
+
c1.368,2.315,3.276,4.356,5.631,6.066c2.328,1.69,5.265,3.045,8.711,4.016C38.803,76.408,40.609,77,42.555,77h13.91
|
13
|
+
c3.083,0,5.82-1.018,8.163-1.926C68.686,73.504,71.962,71.177,74.365,68.163z"/>
|
14
|
+
<polygon fill="#FFFFFF" points="151,18 151,0 88,-0.021 88,18 110.334,18 110.354,77 128.354,77 128.334,18 "/>
|
15
|
+
<path fill="#FFFFFF" d="M229.753,38.499c0-21.224-17.046-38.492-38-38.492s-38,17.269-38,38.492c0,21.227,17.046,38.494,38,38.494
|
16
|
+
S229.753,59.726,229.753,38.499z"/>
|
17
|
+
<path fill="#FFFFFF" d="M269.219,49c9.755,0,17.248-1.989,22.27-6.155c5.107-4.234,7.697-10.532,7.697-18.841
|
18
|
+
c0-3.135-0.394-5.739-1.171-8.158c-0.782-2.434-1.891-4.749-3.294-6.559c-1.407-1.811-3.11-3.328-5.065-4.526
|
19
|
+
c-1.903-1.165-4.019-2.116-6.289-2.833c-2.247-0.709-4.658-1.216-7.167-1.502C273.727,0.145,271.165,0,268.584,0H239v77h18V49
|
20
|
+
H269.219z"/>
|
21
|
+
<rect x="305" fill="#FFFFFF" width="18" height="77"/>
|
22
|
+
<polygon fill="#FFFFFF" points="362.936,0 333.343,77 409.529,77 378.159,0 "/>
|
23
|
+
</g>
|
24
|
+
</g>
|
25
|
+
</svg>
|
data/utopia.gemspec
CHANGED
@@ -30,6 +30,8 @@ Gem::Specification.new do |spec|
|
|
30
30
|
|
31
31
|
spec.add_dependency "mail", "~> 2.6.1"
|
32
32
|
|
33
|
+
spec.add_dependency "concurrent-ruby", "~> 1.0.0.pre5"
|
34
|
+
|
33
35
|
spec.add_development_dependency "bundler", "~> 1.3"
|
34
36
|
spec.add_development_dependency "rspec", "~> 3.1.0"
|
35
37
|
spec.add_development_dependency "puma"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: utopia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: trenni
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 2.6.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: concurrent-ruby
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.0.0.pre5
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.0.0.pre5
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: bundler
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -162,6 +176,7 @@ files:
|
|
162
176
|
- lib/utopia/content/node.rb
|
163
177
|
- lib/utopia/content/processor.rb
|
164
178
|
- lib/utopia/content/tag.rb
|
179
|
+
- lib/utopia/content/transaction.rb
|
165
180
|
- lib/utopia/controller.rb
|
166
181
|
- lib/utopia/controller/action.rb
|
167
182
|
- lib/utopia/controller/base.rb
|
@@ -187,6 +202,8 @@ files:
|
|
187
202
|
- lib/utopia/tags/node.rb
|
188
203
|
- lib/utopia/tags/override.rb
|
189
204
|
- lib/utopia/version.rb
|
205
|
+
- materials/utopia.png
|
206
|
+
- materials/utopia.svg
|
190
207
|
- setup/.bowerrc
|
191
208
|
- setup/server/git/hooks/post-receive
|
192
209
|
- setup/site/Gemfile
|