utopia 0.10.0 → 0.11.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.
- data/.gitignore +17 -0
- data/.travis.yml +9 -0
- data/Gemfile +8 -0
- data/README.md +72 -0
- data/Rakefile +9 -0
- data/bin/utopia +42 -13
- data/lib/utopia/extensions/array.rb +19 -3
- data/lib/utopia/extensions/date.rb +19 -3
- data/lib/utopia/extensions/hash.rb +19 -3
- data/lib/utopia/extensions/maybe.rb +19 -0
- data/lib/utopia/extensions/rack.rb +21 -3
- data/lib/utopia/extensions/regexp.rb +19 -3
- data/lib/utopia/extensions/string.rb +19 -3
- data/lib/utopia/http.rb +56 -0
- data/lib/utopia/link.rb +19 -3
- data/lib/utopia/middleware/all.rb +19 -3
- data/lib/utopia/middleware/content/node.rb +21 -5
- data/lib/utopia/middleware/content/processor.rb +118 -0
- data/lib/utopia/middleware/content.rb +22 -7
- data/lib/utopia/middleware/controller.rb +19 -7
- data/lib/utopia/middleware/directory_index.rb +19 -3
- data/lib/utopia/middleware/localization/name.rb +19 -3
- data/lib/utopia/middleware/localization.rb +19 -3
- data/lib/utopia/middleware/logger.rb +19 -3
- data/lib/utopia/middleware/redirector.rb +19 -5
- data/lib/utopia/middleware/requester.rb +19 -3
- data/lib/utopia/middleware/static.rb +20 -6
- data/lib/utopia/middleware.rb +22 -5
- data/lib/utopia/path.rb +26 -6
- data/lib/utopia/session/encrypted_cookie.rb +19 -3
- data/lib/utopia/setup/Gemfile +8 -0
- data/lib/utopia/setup/config.ru +4 -13
- data/lib/utopia/setup.rb +25 -4
- data/lib/utopia/tag.rb +45 -24
- data/lib/utopia/tags/all.rb +19 -3
- data/lib/utopia/tags/deferred.rb +19 -3
- data/lib/utopia/tags/environment.rb +29 -0
- data/lib/utopia/tags/node.rb +19 -3
- data/lib/utopia/tags/override.rb +19 -3
- data/lib/utopia/tags.rb +19 -3
- data/lib/utopia/time_store.rb +19 -3
- data/lib/utopia/version.rb +20 -10
- data/lib/utopia.rb +20 -17
- data/test/content_root/_heading.xnode +1 -0
- data/test/content_root/index.xnode +1 -0
- data/test/test_content_middleware.rb +86 -0
- data/test/test_path.rb +32 -0
- data/utopia.gemspec +31 -0
- metadata +56 -42
- data/ext/utopia/xnode/fast_scanner/extconf.rb +0 -6
- data/ext/utopia/xnode/fast_scanner/parser.c +0 -289
- data/lib/utopia/http_status_codes.rb +0 -39
- data/lib/utopia/middleware/benchmark.rb +0 -29
- data/lib/utopia/middleware/filter.rb +0 -35
- data/lib/utopia/tags/env.rb +0 -13
- data/lib/utopia/tags/fortune.rb +0 -9
- data/lib/utopia/tags/gallery.rb +0 -275
- data/lib/utopia/tags/google_analytics.rb +0 -21
- data/lib/utopia/trenni.rb +0 -149
- data/lib/utopia/xnode/processor.rb +0 -86
- data/lib/utopia/xnode/scanner.rb +0 -159
- data/lib/utopia/xnode.rb +0 -6
data/lib/utopia/trenni.rb
DELETED
@@ -1,149 +0,0 @@
|
|
1
|
-
# This file is part of the "Utopia Framework" project, and is released under the MIT license.
|
2
|
-
# Copyright 2010 Samuel Williams. All rights reserved.
|
3
|
-
# See <utopia.rb> for licensing details.
|
4
|
-
|
5
|
-
require 'strscan'
|
6
|
-
|
7
|
-
module Utopia
|
8
|
-
class Trenni
|
9
|
-
# The output variable that will be used in templates:
|
10
|
-
OUT = '_out'
|
11
|
-
|
12
|
-
# Returns the output produced by calling the given block.
|
13
|
-
def self.capture(*args, &block)
|
14
|
-
out = eval(OUT, block.binding)
|
15
|
-
top = out.size
|
16
|
-
|
17
|
-
block.call *args
|
18
|
-
|
19
|
-
return out.pop(out.size - top).join
|
20
|
-
end
|
21
|
-
|
22
|
-
# Returns the buffer used for capturing output.
|
23
|
-
def self.buffer(binding)
|
24
|
-
eval(OUT, binding)
|
25
|
-
end
|
26
|
-
|
27
|
-
class Buffer
|
28
|
-
def initialize
|
29
|
-
@parts = []
|
30
|
-
end
|
31
|
-
|
32
|
-
attr :parts
|
33
|
-
|
34
|
-
def text(text)
|
35
|
-
text = text.gsub('\\', '\\\\\\').gsub('@', '\\@')
|
36
|
-
|
37
|
-
@parts << "#{OUT} << %q@#{text}@ ; "
|
38
|
-
end
|
39
|
-
|
40
|
-
def expression(text)
|
41
|
-
@parts << "#{text} ; "
|
42
|
-
end
|
43
|
-
|
44
|
-
def output(text)
|
45
|
-
@parts << "#{OUT} << (#{text}) ; "
|
46
|
-
end
|
47
|
-
|
48
|
-
def code
|
49
|
-
parts = ["#{OUT} = [] ; "] + @parts + ["#{OUT}.join"]
|
50
|
-
|
51
|
-
code = parts.join
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
class Scanner < StringScanner
|
56
|
-
TEXT = /([^<#]|<(?!\?r)|#(?!\{)){1,1024}/m
|
57
|
-
|
58
|
-
def initialize(callback, string)
|
59
|
-
@callback = callback
|
60
|
-
super(string)
|
61
|
-
end
|
62
|
-
|
63
|
-
def parse
|
64
|
-
until eos?
|
65
|
-
pos = self.pos
|
66
|
-
|
67
|
-
scan_text
|
68
|
-
scan_expression
|
69
|
-
|
70
|
-
if pos == self.pos
|
71
|
-
raise StandardError.new "Could not scan current input #{self.pos} #{eos?}!"
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def scan_text
|
77
|
-
if scan(TEXT)
|
78
|
-
@callback.text(matched)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def scan_expression
|
83
|
-
if scan(/\#\{/)
|
84
|
-
level = 1
|
85
|
-
code = ""
|
86
|
-
|
87
|
-
until eos? || level == 0
|
88
|
-
if scan(/[^"'\{\}]+/m)
|
89
|
-
code << matched
|
90
|
-
end
|
91
|
-
|
92
|
-
if scan(/"(\\"|[^"])*"/m)
|
93
|
-
code << matched
|
94
|
-
end
|
95
|
-
|
96
|
-
if scan(/'(\\'|[^'])*'/m)
|
97
|
-
code << matched
|
98
|
-
end
|
99
|
-
|
100
|
-
if scan(/\{/)
|
101
|
-
code << matched
|
102
|
-
level += 1
|
103
|
-
end
|
104
|
-
|
105
|
-
if scan(/\}/)
|
106
|
-
code << matched if level > 1
|
107
|
-
level -= 1
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
if level == 0
|
112
|
-
@callback.output(code)
|
113
|
-
else
|
114
|
-
raise StandardError.new "Could not find end of expression #{self}!"
|
115
|
-
end
|
116
|
-
elsif scan(/<\?r/)
|
117
|
-
if scan_until(/(.*?)\?>/m)
|
118
|
-
@callback.expression(self[1])
|
119
|
-
else
|
120
|
-
raise StandardError.new "Could not find end of expression #{self}!"
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def self.load(path)
|
127
|
-
return self.new(File.read(path), path)
|
128
|
-
end
|
129
|
-
|
130
|
-
def initialize(template, filename = '<Trenni>')
|
131
|
-
@template = template
|
132
|
-
@filename = filename
|
133
|
-
compile!
|
134
|
-
end
|
135
|
-
|
136
|
-
def compile!(filename = @filename)
|
137
|
-
buffer = Buffer.new
|
138
|
-
scanner = Scanner.new(buffer, @template)
|
139
|
-
|
140
|
-
scanner.parse
|
141
|
-
|
142
|
-
@code = buffer.code
|
143
|
-
end
|
144
|
-
|
145
|
-
def result(binding)
|
146
|
-
eval(@code, binding, @filename)
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
# This file is part of the "Utopia Framework" project, and is released under the MIT license.
|
2
|
-
# Copyright 2010 Samuel Williams. All rights reserved.
|
3
|
-
# See <utopia.rb> for licensing details.
|
4
|
-
|
5
|
-
require 'utopia/tag'
|
6
|
-
|
7
|
-
module Utopia
|
8
|
-
module XNode
|
9
|
-
OPENED_TAG = 0
|
10
|
-
CLOSED_TAG = 1
|
11
|
-
|
12
|
-
class UnbalancedTagError < StandardError
|
13
|
-
def initialize(scanner, start_pos, current_tag, closing_tag)
|
14
|
-
@scanner = scanner
|
15
|
-
@start_pos = start_pos
|
16
|
-
@current_tag = current_tag
|
17
|
-
@closing_tag = closing_tag
|
18
|
-
|
19
|
-
@starting_line = @scanner.calculate_line_number(@start_pos)
|
20
|
-
@ending_line = @scanner.calculate_line_number
|
21
|
-
end
|
22
|
-
|
23
|
-
def to_s
|
24
|
-
"UnbalancedTagError: Tag #{@current_tag} (line #{@starting_line[0]}: #{@starting_line[4]}) has been closed by #{@closing_tag} (line #{@ending_line[0]}: #{@ending_line[4]})."
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
class Processor
|
29
|
-
def initialize(content, delegate, options = {})
|
30
|
-
@delegate = delegate
|
31
|
-
@stack = []
|
32
|
-
|
33
|
-
@scanner = (options[:scanner] || Scanner).new(self, content)
|
34
|
-
end
|
35
|
-
|
36
|
-
def parse
|
37
|
-
@scanner.parse
|
38
|
-
end
|
39
|
-
|
40
|
-
def cdata(text)
|
41
|
-
@delegate.cdata(text)
|
42
|
-
end
|
43
|
-
|
44
|
-
def comment(text)
|
45
|
-
cdata("<!#{text}>")
|
46
|
-
end
|
47
|
-
|
48
|
-
def begin_tag(tag_name, begin_tag_type)
|
49
|
-
if begin_tag_type == OPENED_TAG
|
50
|
-
@stack << [Tag.new(tag_name, {}), @scanner.pos]
|
51
|
-
else
|
52
|
-
cur, pos = @stack.pop
|
53
|
-
|
54
|
-
if (tag_name != cur.name)
|
55
|
-
raise UnbalancedTagError.new(@scanner, pos, cur.name, tag_name)
|
56
|
-
end
|
57
|
-
|
58
|
-
@delegate.tag_end(cur)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def finish_tag(begin_tag_type, end_tag_type)
|
63
|
-
if begin_tag_type == OPENED_TAG # <...
|
64
|
-
if end_tag_type == CLOSED_TAG # <.../>
|
65
|
-
cur, pos = @stack.pop
|
66
|
-
cur.closed = true
|
67
|
-
|
68
|
-
@delegate.tag_complete(cur)
|
69
|
-
elsif end_tag_type == OPENED_TAG # <...>
|
70
|
-
cur, pos = @stack.last
|
71
|
-
|
72
|
-
@delegate.tag_begin(cur)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def attribute(name, value)
|
78
|
-
@stack.last[0].attributes[name] = value
|
79
|
-
end
|
80
|
-
|
81
|
-
def instruction(content)
|
82
|
-
cdata("<?#{content}?>")
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
data/lib/utopia/xnode/scanner.rb
DELETED
@@ -1,159 +0,0 @@
|
|
1
|
-
# This file is part of the "Utopia Framework" project, and is released under the MIT license.
|
2
|
-
# Copyright 2010 Samuel Williams. All rights reserved.
|
3
|
-
# See <utopia.rb> for licensing details.
|
4
|
-
|
5
|
-
require 'strscan'
|
6
|
-
require 'tempfile'
|
7
|
-
|
8
|
-
module Utopia
|
9
|
-
module XNode
|
10
|
-
class ScanError < StandardError
|
11
|
-
def initialize(message, scanner)
|
12
|
-
@message = message
|
13
|
-
|
14
|
-
@pos = scanner.pos
|
15
|
-
@line = scanner.calculate_line_number
|
16
|
-
end
|
17
|
-
|
18
|
-
def to_s
|
19
|
-
if @line
|
20
|
-
"Scan Error: #{@message} @ [#{@line[0]}:#{@line[2]}]: #{@line[4]}"
|
21
|
-
else
|
22
|
-
"Scan Error [#{@pos}]: #{@message}"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
class Scanner < StringScanner
|
28
|
-
CDATA = /[^<]+/m
|
29
|
-
# Parse an attribute in the form of key="value" or key.
|
30
|
-
ATTRIBUTE_NAME = /\s*([^\s=\/>]+)/um
|
31
|
-
ATTRIBUTE_VALUE = /=((['"])(.*?)\2)/um
|
32
|
-
|
33
|
-
def initialize(callback, string)
|
34
|
-
@callback = callback
|
35
|
-
super(string)
|
36
|
-
end
|
37
|
-
|
38
|
-
def calculate_line_number(at = pos)
|
39
|
-
line_no = 1
|
40
|
-
line_offset = offset = 0
|
41
|
-
|
42
|
-
string.lines.each do |line|
|
43
|
-
line_offset = offset
|
44
|
-
offset += line.size
|
45
|
-
|
46
|
-
if offset >= at
|
47
|
-
return [line_no, line_offset, at - line_offset, offset, line]
|
48
|
-
end
|
49
|
-
|
50
|
-
line_no += 1
|
51
|
-
end
|
52
|
-
|
53
|
-
return nil
|
54
|
-
end
|
55
|
-
|
56
|
-
def parse
|
57
|
-
until eos?
|
58
|
-
pos = self.pos
|
59
|
-
|
60
|
-
scan_cdata
|
61
|
-
scan_tag
|
62
|
-
|
63
|
-
if pos == self.pos
|
64
|
-
raise ScanError.new("Scanner didn't move", self)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def scan_cdata
|
70
|
-
if scan(CDATA)
|
71
|
-
@callback.cdata(matched)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def scan_tag
|
76
|
-
if scan(/</)
|
77
|
-
if scan(/\//)
|
78
|
-
scan_tag_normal(CLOSED_TAG)
|
79
|
-
elsif scan(/!\[CDATA\[/)
|
80
|
-
scan_tag_cdata
|
81
|
-
elsif scan(/!/)
|
82
|
-
scan_tag_comment
|
83
|
-
elsif scan(/\?/)
|
84
|
-
scan_tag_instruction
|
85
|
-
else
|
86
|
-
scan_tag_normal
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def scan_attributes
|
92
|
-
while scan(ATTRIBUTE_NAME)
|
93
|
-
name = self[1]
|
94
|
-
if scan(ATTRIBUTE_VALUE)
|
95
|
-
@callback.attribute(name, self[3])
|
96
|
-
else
|
97
|
-
@callback.attribute(name, nil)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def scan_tag_normal(begin_tag_type = OPENED_TAG)
|
103
|
-
if scan(/[^\s\/>]+/)
|
104
|
-
@callback.begin_tag(matched, begin_tag_type)
|
105
|
-
|
106
|
-
scan(/\s*/)
|
107
|
-
|
108
|
-
scan_attributes
|
109
|
-
|
110
|
-
scan(/\s*/)
|
111
|
-
|
112
|
-
if scan(/\/>/)
|
113
|
-
if begin_tag_type == CLOSED_TAG
|
114
|
-
raise ScanError.new("Tag cannot be closed at both ends!", self)
|
115
|
-
else
|
116
|
-
@callback.finish_tag(begin_tag_type, CLOSED_TAG)
|
117
|
-
end
|
118
|
-
elsif scan(/>/)
|
119
|
-
@callback.finish_tag(begin_tag_type, OPENED_TAG)
|
120
|
-
else
|
121
|
-
raise ScanError.new("Invalid characters in tag!", self)
|
122
|
-
end
|
123
|
-
else
|
124
|
-
raise ScanError.new("Invalid tag!", self)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def scan_tag_cdata
|
129
|
-
if scan_until(/(.*?)\]\]>/m)
|
130
|
-
@callback.cdata(self[1].to_html)
|
131
|
-
else
|
132
|
-
raise ScanError.new("CDATA tag is not closed!", self)
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def scan_tag_comment
|
137
|
-
if scan(/--/)
|
138
|
-
if scan_until(/(.*?)-->/m)
|
139
|
-
@callback.comment("--" + self[1] + "--")
|
140
|
-
else
|
141
|
-
raise ScanError.new("Comment is not closed!", self)
|
142
|
-
end
|
143
|
-
else
|
144
|
-
if scan_until(/(.*?)>/)
|
145
|
-
@callback.comment(self[1])
|
146
|
-
else
|
147
|
-
raise ScanError.new("Comment is not closed!", self)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def scan_tag_instruction
|
153
|
-
if scan_until(/(.*)\?>/)
|
154
|
-
@callback.instruction(self[1])
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
data/lib/utopia/xnode.rb
DELETED