utopia 0.12.6 → 1.0.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/.travis.yml +6 -2
- data/Gemfile +6 -0
- data/README.md +48 -14
- data/Rakefile +5 -0
- data/bin/utopia +132 -15
- data/lib/utopia.rb +13 -10
- data/lib/utopia/content.rb +140 -0
- data/lib/utopia/content/link.rb +124 -0
- data/lib/utopia/content/links.rb +228 -0
- data/lib/utopia/content/node.rb +387 -0
- data/lib/utopia/content/processor.rb +128 -0
- data/lib/utopia/content/tag.rb +102 -0
- data/lib/utopia/controller.rb +137 -0
- data/lib/utopia/controller/action.rb +112 -0
- data/lib/utopia/controller/base.rb +174 -0
- data/lib/utopia/{middleware/controller → controller}/variables.rb +36 -38
- data/lib/utopia/exception_handler.rb +79 -0
- data/lib/utopia/extensions/array.rb +2 -2
- data/lib/utopia/localization.rb +143 -0
- data/lib/utopia/mail_exceptions.rb +136 -0
- data/lib/utopia/middleware.rb +7 -22
- data/lib/utopia/path.rb +150 -60
- data/lib/utopia/redirector.rb +152 -0
- data/lib/utopia/{extensions/hash.rb → session.rb} +4 -6
- data/lib/utopia/session/encrypted_cookie.rb +46 -48
- data/lib/utopia/{middleware/directory_index.rb → session/lazy_hash.rb} +44 -27
- data/lib/utopia/static.rb +255 -0
- data/lib/utopia/tags/deferred.rb +12 -8
- data/lib/utopia/tags/environment.rb +18 -6
- data/lib/utopia/tags/node.rb +12 -8
- data/lib/utopia/tags/override.rb +12 -12
- data/lib/utopia/version.rb +1 -1
- data/setup/.bowerrc +3 -0
- data/{lib/utopia/setup → setup}/Gemfile +1 -1
- data/setup/Rakefile +4 -0
- data/{lib/utopia/setup → setup}/cache/head/readme.txt +0 -0
- data/{lib/utopia/setup → setup}/cache/meta/readme.txt +0 -0
- data/setup/config.ru +64 -0
- data/{lib/utopia/setup → setup}/lib/readme.txt +0 -0
- data/{lib/utopia/setup → setup}/pages/_heading.xnode +0 -0
- data/{lib/utopia/setup → setup}/pages/_page.xnode +1 -1
- data/{lib/utopia/setup → setup}/pages/_static/icon.png +0 -0
- data/setup/pages/_static/site.css +70 -0
- data/{lib/utopia/setup → setup}/pages/errors/exception.xnode +0 -0
- data/{lib/utopia/setup → setup}/pages/errors/file-not-found.xnode +0 -0
- data/{lib/utopia/setup → setup}/pages/links.yaml +0 -0
- data/setup/pages/welcome/index.xnode +17 -0
- data/{lib/utopia/setup → setup}/public/readme.txt +0 -0
- data/spec/utopia/content/link_spec.rb +108 -0
- data/spec/utopia/content/links/foo/index.xnode +0 -0
- data/spec/utopia/content/links/foo/links.yaml +2 -0
- data/spec/utopia/content/links/foo/test.de.xnode +0 -0
- data/spec/utopia/content/links/foo/test.en.xnode +0 -0
- data/spec/utopia/content/links/links.yaml +9 -0
- data/spec/utopia/content/links/welcome.xnode +0 -0
- data/spec/utopia/content/localized/five/index.en.xnode +0 -0
- data/spec/utopia/content/localized/four/index.en.xnode +0 -0
- data/spec/utopia/content/localized/four/index.zh.xnode +0 -0
- data/spec/utopia/content/localized/four/links.yaml +4 -0
- data/spec/utopia/content/localized/links.yaml +16 -0
- data/spec/utopia/content/localized/one.xnode +0 -0
- data/spec/utopia/content/localized/three/index.xnode +0 -0
- data/spec/utopia/content/localized/two.en.xnode +0 -0
- data/spec/utopia/content/localized/two.zh.xnode +0 -0
- data/spec/utopia/content/node/ordered/first.xnode +0 -0
- data/spec/utopia/content/node/ordered/index.xnode +0 -0
- data/spec/utopia/content/node/ordered/links.yaml +4 -0
- data/spec/utopia/content/node/ordered/second.xnode +0 -0
- data/spec/utopia/content/node/related/foo.en.xnode +0 -0
- data/spec/utopia/content/node/related/foo.ja.xnode +0 -0
- data/spec/utopia/content/node/related/links.yaml +4 -0
- data/spec/utopia/content/node_spec.rb +63 -0
- data/spec/utopia/{middleware/content_spec.rb → content/processor_spec.rb} +34 -23
- data/spec/utopia/content_spec.rb +87 -0
- data/spec/utopia/content_spec.ru +10 -0
- data/spec/utopia/{middleware/controller_spec.rb → controller_spec.rb} +61 -16
- data/spec/utopia/controller_spec.ru +4 -0
- data/spec/utopia/extensions_spec.rb +6 -17
- data/spec/utopia/localization_spec.rb +60 -0
- data/spec/utopia/localization_spec.ru +11 -0
- data/{lib/utopia/tags.rb → spec/utopia/middleware_spec.rb} +8 -14
- data/spec/utopia/{middleware/content_root → pages}/_heading.xnode +0 -0
- data/spec/utopia/pages/content/_show-value.xnode +1 -0
- data/spec/utopia/pages/content/test-partial.xnode +1 -0
- data/spec/utopia/pages/controller/controller.rb +28 -0
- data/spec/utopia/pages/controller/index.xnode +1 -0
- data/spec/utopia/pages/controller/nested/controller.rb +4 -0
- data/spec/utopia/{middleware/content_root → pages}/index.xnode +0 -0
- data/spec/utopia/pages/localized.de.txt +1 -0
- data/spec/utopia/pages/localized.en.txt +1 -0
- data/spec/utopia/pages/localized.jp.txt +1 -0
- data/spec/utopia/pages/node/index.xnode +1 -0
- data/spec/utopia/pages/test.txt +1 -0
- data/spec/utopia/path_spec.rb +109 -0
- data/spec/utopia/rack_spec.rb +2 -0
- data/spec/utopia/session_spec.rb +82 -0
- data/spec/utopia/session_spec.ru +20 -0
- data/spec/utopia/spec_helper.rb +16 -0
- data/{lib/utopia/extensions/string.rb → spec/utopia/static_spec.rb} +24 -15
- data/spec/utopia/static_spec.ru +4 -0
- data/utopia.gemspec +3 -3
- metadata +138 -54
- data/lib/utopia/extensions/regexp.rb +0 -33
- data/lib/utopia/link.rb +0 -288
- data/lib/utopia/middleware/all.rb +0 -33
- data/lib/utopia/middleware/content.rb +0 -157
- data/lib/utopia/middleware/content/node.rb +0 -386
- data/lib/utopia/middleware/content/processor.rb +0 -123
- data/lib/utopia/middleware/controller.rb +0 -130
- data/lib/utopia/middleware/controller/action.rb +0 -121
- data/lib/utopia/middleware/controller/base.rb +0 -184
- data/lib/utopia/middleware/exception_handler.rb +0 -80
- data/lib/utopia/middleware/localization.rb +0 -147
- data/lib/utopia/middleware/localization/name.rb +0 -69
- data/lib/utopia/middleware/mail_exceptions.rb +0 -138
- data/lib/utopia/middleware/redirector.rb +0 -146
- data/lib/utopia/middleware/requester.rb +0 -126
- data/lib/utopia/middleware/static.rb +0 -295
- data/lib/utopia/setup.rb +0 -60
- data/lib/utopia/setup/config.ru +0 -47
- data/lib/utopia/setup/pages/_static/background.png +0 -0
- data/lib/utopia/setup/pages/_static/site.css +0 -48
- data/lib/utopia/setup/pages/welcome/index.xnode +0 -7
- data/lib/utopia/tag.rb +0 -105
- data/lib/utopia/tags/all.rb +0 -34
|
@@ -1,33 +0,0 @@
|
|
|
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 'pathname'
|
|
22
|
-
|
|
23
|
-
warn "require 'utopia/middleware/all' is deprecated. Require 'utopia' instead."
|
|
24
|
-
|
|
25
|
-
Pathname.new(__FILE__).dirname.entries.each do |path|
|
|
26
|
-
next unless /\.rb$/ === path.to_s
|
|
27
|
-
|
|
28
|
-
name = File.basename(path.to_s, ".rb")
|
|
29
|
-
|
|
30
|
-
if name != "all"
|
|
31
|
-
require "utopia/middleware/#{name}"
|
|
32
|
-
end
|
|
33
|
-
end
|
|
@@ -1,157 +0,0 @@
|
|
|
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 'utopia/middleware'
|
|
22
|
-
require 'utopia/link'
|
|
23
|
-
require 'utopia/path'
|
|
24
|
-
require 'utopia/tags'
|
|
25
|
-
|
|
26
|
-
require 'utopia/middleware/content/node'
|
|
27
|
-
require 'utopia/middleware/content/processor'
|
|
28
|
-
require 'trenni/template'
|
|
29
|
-
|
|
30
|
-
module Utopia
|
|
31
|
-
module Middleware
|
|
32
|
-
|
|
33
|
-
class Content
|
|
34
|
-
def initialize(app, options = {})
|
|
35
|
-
@app = app
|
|
36
|
-
|
|
37
|
-
@root = File.expand_path(options[:root] || Utopia::Middleware::default_root)
|
|
38
|
-
|
|
39
|
-
# Set to hash to enable caching
|
|
40
|
-
@nodes = {}
|
|
41
|
-
@files = nil
|
|
42
|
-
|
|
43
|
-
@tags = options[:tags] || {}
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
attr :root
|
|
47
|
-
attr :passthrough
|
|
48
|
-
|
|
49
|
-
def fetch_xml(path)
|
|
50
|
-
read_file = lambda { Trenni::Template.load(path) }
|
|
51
|
-
|
|
52
|
-
if @files
|
|
53
|
-
@files.fetch(path) do |key|
|
|
54
|
-
@files[key] = read_file.call
|
|
55
|
-
end
|
|
56
|
-
else
|
|
57
|
-
read_file.call
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Look up a named tag such as <entry />
|
|
62
|
-
def lookup_tag(name, parent_path)
|
|
63
|
-
if @tags.key? name
|
|
64
|
-
return @tags[name]
|
|
65
|
-
elsif Utopia::Tags.all.key? name
|
|
66
|
-
return Utopia::Tags.all[name]
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
if String === name && name.index("/")
|
|
70
|
-
name = Path.create(name)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
if Path === name
|
|
74
|
-
name = parent_path + name
|
|
75
|
-
name_path = name.components.dup
|
|
76
|
-
name_path[-1] += ".xnode"
|
|
77
|
-
else
|
|
78
|
-
name_path = name + ".xnode"
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
parent_path.ascend do |dir|
|
|
82
|
-
tag_path = File.join(root, dir.components, name_path)
|
|
83
|
-
|
|
84
|
-
if File.exist? tag_path
|
|
85
|
-
return Node.new(self, dir + name, parent_path + name, tag_path)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
if String === name_path
|
|
89
|
-
tag_path = File.join(root, dir.components, "_" + name_path)
|
|
90
|
-
|
|
91
|
-
if File.exist? tag_path
|
|
92
|
-
return Node.new(self, dir + name, parent_path + name, tag_path)
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
return nil
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def lookup_node(request_path)
|
|
101
|
-
name = request_path.basename
|
|
102
|
-
name_xnode = name + ".xnode"
|
|
103
|
-
|
|
104
|
-
node_path = File.join(@root, request_path.dirname.components, name_xnode)
|
|
105
|
-
|
|
106
|
-
if File.exist? node_path
|
|
107
|
-
return Node.new(self, request_path.dirname + name, request_path, node_path)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
return nil
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def call(env)
|
|
114
|
-
request = Rack::Request.new(env)
|
|
115
|
-
path = Path.create(request.path_info).to_absolute
|
|
116
|
-
|
|
117
|
-
# Check if the request is to a non-specific index.
|
|
118
|
-
name, extensions = path.basename.split(".", 2)
|
|
119
|
-
directory_path = File.join(@root, path.dirname.components, name)
|
|
120
|
-
|
|
121
|
-
if File.directory? directory_path
|
|
122
|
-
if extensions
|
|
123
|
-
index_path = [name, "index.#{extensions}"]
|
|
124
|
-
else
|
|
125
|
-
index_path = [name, "index"]
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
return [307, {"Location" => path.dirname.join(index_path).to_s}, []]
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
# Otherwise look up the node
|
|
132
|
-
node = lookup_node(path)
|
|
133
|
-
|
|
134
|
-
if node
|
|
135
|
-
if request.head?
|
|
136
|
-
return [200, {}, []]
|
|
137
|
-
else
|
|
138
|
-
response = Rack::Response.new
|
|
139
|
-
|
|
140
|
-
attributes = {}
|
|
141
|
-
|
|
142
|
-
if request.controller
|
|
143
|
-
attributes = request.controller.to_hash
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
node.process!(request, response, attributes)
|
|
147
|
-
|
|
148
|
-
return response.finish
|
|
149
|
-
end
|
|
150
|
-
else
|
|
151
|
-
return @app.call(env)
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
end
|
|
157
|
-
end
|
|
@@ -1,386 +0,0 @@
|
|
|
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 'set'
|
|
22
|
-
|
|
23
|
-
require 'utopia/middleware/content/processor'
|
|
24
|
-
require 'utopia/link'
|
|
25
|
-
|
|
26
|
-
module Utopia
|
|
27
|
-
|
|
28
|
-
module Middleware
|
|
29
|
-
class Content
|
|
30
|
-
class UnbalancedTagError < StandardError
|
|
31
|
-
def initialize(tag)
|
|
32
|
-
@tag = tag
|
|
33
|
-
|
|
34
|
-
super("Unbalanced tag #{tag.name}")
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
attr :tag
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
class Transaction
|
|
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
|
-
def binding
|
|
133
|
-
super
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def parse_xml(xml_data)
|
|
137
|
-
Processor.parse_xml(xml_data, self)
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
attr :request
|
|
141
|
-
attr :response
|
|
142
|
-
|
|
143
|
-
# Begin tags represents a list from outer to inner most tag.
|
|
144
|
-
# At any point in parsing xml, begin_tags is a list of the inner most tag,
|
|
145
|
-
# then the next outer tag, etc. This list is used for doing dependent lookups.
|
|
146
|
-
attr :begin_tags
|
|
147
|
-
|
|
148
|
-
# End tags represents a list of execution order. This is the order that end tags
|
|
149
|
-
# have appeared when evaluating nodes.
|
|
150
|
-
attr :end_tags
|
|
151
|
-
|
|
152
|
-
def attributes
|
|
153
|
-
return current.attributes
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def current
|
|
157
|
-
@begin_tags[-1]
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
def content
|
|
161
|
-
@end_tags[-1].content
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def parent
|
|
165
|
-
end_tags[-2]
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
def first
|
|
169
|
-
@begin_tags[0]
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def tag(name, attributes = {}, &block)
|
|
173
|
-
tag = Tag.new(name, attributes)
|
|
174
|
-
|
|
175
|
-
node = tag_begin(tag)
|
|
176
|
-
|
|
177
|
-
yield node if block_given?
|
|
178
|
-
|
|
179
|
-
tag_end(tag)
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
def tag_complete(tag, node = nil)
|
|
183
|
-
if tag.name == "content"
|
|
184
|
-
current.markup(content)
|
|
185
|
-
else
|
|
186
|
-
node ||= lookup(tag)
|
|
187
|
-
|
|
188
|
-
if node
|
|
189
|
-
tag_begin(tag, node)
|
|
190
|
-
tag_end(tag)
|
|
191
|
-
else
|
|
192
|
-
current.tag_complete(tag)
|
|
193
|
-
end
|
|
194
|
-
end
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
def tag_begin(tag, node = nil)
|
|
198
|
-
node ||= lookup(tag)
|
|
199
|
-
|
|
200
|
-
if node
|
|
201
|
-
state = State.new(tag, node)
|
|
202
|
-
@begin_tags << state
|
|
203
|
-
|
|
204
|
-
if node.respond_to? :tag_begin
|
|
205
|
-
node.tag_begin(self, state)
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
return node
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
current.tag_begin(tag)
|
|
212
|
-
|
|
213
|
-
return nil
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
def cdata(text)
|
|
217
|
-
current.cdata(text)
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
def deferred_tag(*args, &block)
|
|
221
|
-
if block_given?
|
|
222
|
-
current.defer(&block)
|
|
223
|
-
else
|
|
224
|
-
current.defer do
|
|
225
|
-
tag(*args)
|
|
226
|
-
end
|
|
227
|
-
end
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
def tag_end(tag = nil)
|
|
231
|
-
top = current
|
|
232
|
-
|
|
233
|
-
if top.tags.empty?
|
|
234
|
-
if top.node.respond_to? :tag_end
|
|
235
|
-
top.node.tag_end(self, top)
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
@end_tags << top
|
|
239
|
-
buffer = top.call(self)
|
|
240
|
-
|
|
241
|
-
@begin_tags.pop
|
|
242
|
-
@end_tags.pop
|
|
243
|
-
|
|
244
|
-
if current
|
|
245
|
-
current.markup(buffer)
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
return buffer
|
|
249
|
-
else
|
|
250
|
-
current.tag_end(tag)
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
return nil
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
def render_node(node, attributes = {})
|
|
257
|
-
state = State.new(attributes, node)
|
|
258
|
-
@begin_tags << state
|
|
259
|
-
|
|
260
|
-
return tag_end
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
# Takes an instance of Tag
|
|
264
|
-
def lookup(tag)
|
|
265
|
-
result = tag
|
|
266
|
-
node = nil
|
|
267
|
-
|
|
268
|
-
@begin_tags.reverse_each do |state|
|
|
269
|
-
result = state.lookup(result)
|
|
270
|
-
|
|
271
|
-
node ||= state.node if state.node.respond_to? :lookup
|
|
272
|
-
|
|
273
|
-
return result if Node === result
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
@end_tags.reverse_each do |state|
|
|
277
|
-
return state.node.lookup(result) if state.node.respond_to? :lookup
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
return nil
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
def method_missing(name, *args)
|
|
284
|
-
@begin_tags.reverse_each do |state|
|
|
285
|
-
if state.node.respond_to? name
|
|
286
|
-
return state.node.send(name, *args)
|
|
287
|
-
end
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
super
|
|
291
|
-
end
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
class Node
|
|
295
|
-
def initialize(controller, uri_path, request_path, file_path)
|
|
296
|
-
@controller = controller
|
|
297
|
-
|
|
298
|
-
@uri_path = uri_path
|
|
299
|
-
@request_path = request_path
|
|
300
|
-
@file_path = file_path
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
attr :request_path
|
|
304
|
-
attr :uri_path
|
|
305
|
-
attr :file_path
|
|
306
|
-
|
|
307
|
-
def link
|
|
308
|
-
return Link.new(:file, uri_path)
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
def lookup_node(path)
|
|
312
|
-
@controller.lookup_node(path)
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
def local_path(path = ".", base = nil)
|
|
316
|
-
path = Path.create(path)
|
|
317
|
-
root = Pathname.new(@controller.root)
|
|
318
|
-
|
|
319
|
-
if path.absolute?
|
|
320
|
-
return root.join(*path.components)
|
|
321
|
-
else
|
|
322
|
-
base ||= uri_path.dirname
|
|
323
|
-
return root.join(*(base + path).components)
|
|
324
|
-
end
|
|
325
|
-
end
|
|
326
|
-
|
|
327
|
-
def lookup(tag)
|
|
328
|
-
from_path = parent_path
|
|
329
|
-
|
|
330
|
-
# If the current node is called 'foo', we can't lookup 'foo' in the current directory or we will likely have infinite recursion.
|
|
331
|
-
if tag.name == @uri_path.basename
|
|
332
|
-
from_path = from_path.dirname
|
|
333
|
-
end
|
|
334
|
-
|
|
335
|
-
return @controller.lookup_tag(tag.name, from_path)
|
|
336
|
-
end
|
|
337
|
-
|
|
338
|
-
def parent_path
|
|
339
|
-
uri_path.dirname
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
def links(path = ".", options = {}, &block)
|
|
343
|
-
path = uri_path.dirname + Path.create(path)
|
|
344
|
-
links = Links.index(@controller.root, path, options)
|
|
345
|
-
|
|
346
|
-
if block_given?
|
|
347
|
-
links.each &block
|
|
348
|
-
else
|
|
349
|
-
links
|
|
350
|
-
end
|
|
351
|
-
end
|
|
352
|
-
|
|
353
|
-
def related_links
|
|
354
|
-
name = @uri_path.basename.split(".").first
|
|
355
|
-
links = Links.index(@controller.root, uri_path.dirname, :name => name, :indices => true)
|
|
356
|
-
end
|
|
357
|
-
|
|
358
|
-
def siblings_path
|
|
359
|
-
name = @uri_path.basename.split(".").first
|
|
360
|
-
|
|
361
|
-
if name == "index"
|
|
362
|
-
@uri_path.dirname(2)
|
|
363
|
-
else
|
|
364
|
-
@uri_path.dirname
|
|
365
|
-
end
|
|
366
|
-
end
|
|
367
|
-
|
|
368
|
-
def sibling_links(options = {})
|
|
369
|
-
return Links.index(@controller.root, siblings_path, options)
|
|
370
|
-
end
|
|
371
|
-
|
|
372
|
-
def call(transaction, state)
|
|
373
|
-
xml_data = @controller.fetch_xml(@file_path).result(transaction.binding)
|
|
374
|
-
|
|
375
|
-
transaction.parse_xml(xml_data)
|
|
376
|
-
end
|
|
377
|
-
|
|
378
|
-
def process!(request, response, attributes = {})
|
|
379
|
-
transaction = Transaction.new(request, response)
|
|
380
|
-
response.write(transaction.render_node(self, attributes))
|
|
381
|
-
end
|
|
382
|
-
end
|
|
383
|
-
|
|
384
|
-
end
|
|
385
|
-
end
|
|
386
|
-
end
|