utopia 0.9.43 → 0.9.45
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/utopia/extensions/string.rb +4 -0
- data/lib/utopia/middleware/content.rb +2 -2
- data/lib/utopia/trenni.rb +127 -0
- data/lib/utopia/version.rb +1 -1
- data/lib/utopia/xnode/scanner.rb +11 -1
- metadata +5 -5
- data/lib/utopia/etanni.rb +0 -85
@@ -10,6 +10,10 @@ class String
|
|
10
10
|
gsub(HTML_ESCAPE_PATTERN){|c| HTML_ESCAPE[c]}
|
11
11
|
end
|
12
12
|
|
13
|
+
def to_quoted_string
|
14
|
+
'"' + self.gsub('"', '\\"').gsub(/\r/, "\\r").gsub(/\n/, "\\n") + '"'
|
15
|
+
end
|
16
|
+
|
13
17
|
def to_title
|
14
18
|
(" " + self).gsub(/[ \-_](.)/){" " + $1.upcase}.strip
|
15
19
|
end
|
@@ -8,7 +8,7 @@ require 'utopia/path'
|
|
8
8
|
require 'utopia/tags'
|
9
9
|
|
10
10
|
require 'utopia/middleware/content/node'
|
11
|
-
require 'utopia/
|
11
|
+
require 'utopia/trenni'
|
12
12
|
|
13
13
|
module Utopia
|
14
14
|
module Middleware
|
@@ -32,7 +32,7 @@ module Utopia
|
|
32
32
|
attr :passthrough
|
33
33
|
|
34
34
|
def fetch_xml(path)
|
35
|
-
read_file = lambda {
|
35
|
+
read_file = lambda { Trenni.new(File.read(path), path) }
|
36
36
|
|
37
37
|
if @files
|
38
38
|
@files.fetch(path) do
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# This file is part of the "Utopia Framework" project, and is licensed under the GNU AGPLv3.
|
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
|
+
class Buffer
|
10
|
+
def initialize
|
11
|
+
@parts = []
|
12
|
+
end
|
13
|
+
|
14
|
+
attr :parts
|
15
|
+
|
16
|
+
def text(text)
|
17
|
+
text = text.gsub('\\', '\\\\\\').gsub('@', '\\@')
|
18
|
+
|
19
|
+
@parts << "_out << %q@#{text}@ ; "
|
20
|
+
end
|
21
|
+
|
22
|
+
def expression(text)
|
23
|
+
@parts << "#{text} ; "
|
24
|
+
end
|
25
|
+
|
26
|
+
def output(text)
|
27
|
+
@parts << "_out << #{text} ; "
|
28
|
+
end
|
29
|
+
|
30
|
+
def code
|
31
|
+
parts = ['_out = [] ; '] + @parts + ['_out.join']
|
32
|
+
|
33
|
+
code = parts.join
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Scanner < StringScanner
|
38
|
+
def initialize(callback, string)
|
39
|
+
@callback = callback
|
40
|
+
super(string)
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse
|
44
|
+
until eos?
|
45
|
+
pos = self.pos
|
46
|
+
|
47
|
+
scan_text
|
48
|
+
scan_expression
|
49
|
+
|
50
|
+
if pos == self.pos
|
51
|
+
raise StandardError.new "Could not scan current input #{self.pos} #{eos?}!"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def scan_text
|
57
|
+
if scan_until(/(.*?)(?=\#\{|<\?r)/m) || scan(/(.*)\Z/m)
|
58
|
+
@callback.text(self[1]) if self[1].size > 0
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def scan_expression
|
63
|
+
if scan(/\#\{/)
|
64
|
+
done = false
|
65
|
+
code = ""
|
66
|
+
|
67
|
+
until eos? || done
|
68
|
+
if scan(/[^"'\{\}]+/m)
|
69
|
+
code << matched
|
70
|
+
end
|
71
|
+
|
72
|
+
if scan(/"(\\"|[^"])*"/m)
|
73
|
+
code << matched
|
74
|
+
end
|
75
|
+
|
76
|
+
if scan(/'(\\'|[^'])*'/m)
|
77
|
+
code << matched
|
78
|
+
end
|
79
|
+
|
80
|
+
if scan(/\{[^\}]*\}/m)
|
81
|
+
code << matched
|
82
|
+
end
|
83
|
+
|
84
|
+
if scan(/\}/)
|
85
|
+
done = true
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
if done
|
90
|
+
@callback.output(code)
|
91
|
+
else
|
92
|
+
raise StandardError.new "Could not find end of expression #{self}!"
|
93
|
+
end
|
94
|
+
elsif scan(/<\?r/)
|
95
|
+
if scan_until(/(.*?)\?>/m)
|
96
|
+
@callback.expression(self[1])
|
97
|
+
else
|
98
|
+
raise StandardError.new "Could not find end of expression #{self}!"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.load(path)
|
105
|
+
return self.new(File.read(path), path)
|
106
|
+
end
|
107
|
+
|
108
|
+
def initialize(template, filename = '<Trenni>')
|
109
|
+
@template = template
|
110
|
+
@filename = filename
|
111
|
+
compile!
|
112
|
+
end
|
113
|
+
|
114
|
+
def compile!(filename = @filename)
|
115
|
+
buffer = Buffer.new
|
116
|
+
scanner = Scanner.new(buffer, @template)
|
117
|
+
|
118
|
+
scanner.parse
|
119
|
+
|
120
|
+
@code = buffer.code
|
121
|
+
end
|
122
|
+
|
123
|
+
def result(binding)
|
124
|
+
eval(@code, binding, @filename)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
data/lib/utopia/version.rb
CHANGED
data/lib/utopia/xnode/scanner.rb
CHANGED
@@ -74,6 +74,8 @@ module Utopia
|
|
74
74
|
if scan(/</)
|
75
75
|
if scan(/\//)
|
76
76
|
scan_tag_normal(CLOSED_TAG)
|
77
|
+
elsif scan(/!\[CDATA\[/)
|
78
|
+
scan_tag_cdata
|
77
79
|
elsif scan(/!/)
|
78
80
|
scan_tag_comment
|
79
81
|
elsif scan(/\?/)
|
@@ -115,7 +117,15 @@ module Utopia
|
|
115
117
|
raise ScanError.new("Invalid tag!", self)
|
116
118
|
end
|
117
119
|
end
|
118
|
-
|
120
|
+
|
121
|
+
def scan_tag_cdata
|
122
|
+
if scan_until(/(.*?)\]\]>/m)
|
123
|
+
@callback.cdata(self[1].to_html)
|
124
|
+
else
|
125
|
+
raise ScanError.new("CDATA tag is not closed!", self)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
119
129
|
def scan_tag_comment
|
120
130
|
if scan(/--/)
|
121
131
|
if scan_until(/(.*?)-->/m)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: utopia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 97
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
|
-
-
|
10
|
-
version: 0.9.
|
9
|
+
- 45
|
10
|
+
version: 0.9.45
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Samuel Williams
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-02-09 00:00:00 +13:00
|
19
19
|
default_executable: utopia
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -99,7 +99,6 @@ extra_rdoc_files: []
|
|
99
99
|
files:
|
100
100
|
- ext/utopia/xnode/fast_scanner/extconf.rb
|
101
101
|
- ext/utopia/xnode/fast_scanner/parser.c
|
102
|
-
- lib/utopia/etanni.rb
|
103
102
|
- lib/utopia/extensions/array.rb
|
104
103
|
- lib/utopia/extensions/date.rb
|
105
104
|
- lib/utopia/extensions/hash.rb
|
@@ -147,6 +146,7 @@ files:
|
|
147
146
|
- lib/utopia/tags/override.rb
|
148
147
|
- lib/utopia/tags.rb
|
149
148
|
- lib/utopia/time_store.rb
|
149
|
+
- lib/utopia/trenni.rb
|
150
150
|
- lib/utopia/version.rb
|
151
151
|
- lib/utopia/xnode/processor.rb
|
152
152
|
- lib/utopia/xnode/scanner.rb
|
data/lib/utopia/etanni.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
# This file is part of the "Utopia Framework" project, and is licensed under the GNU AGPLv3.
|
2
|
-
# Copyright 2010 Samuel Williams. All rights reserved.
|
3
|
-
# See <utopia.rb> for licensing details.
|
4
|
-
|
5
|
-
# [Etanni] Copyright (c) 2008 Michael Fellinger <m.fellinger@gmail.com>
|
6
|
-
#
|
7
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
-
# of this software and associated documentation files (the "Software"), to
|
9
|
-
# deal in the Software without restriction, including without limitation the
|
10
|
-
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
11
|
-
# sell copies of the Software, and to permit persons to whom the Software is
|
12
|
-
# furnished to do so, subject to the following conditions:
|
13
|
-
#
|
14
|
-
# The above copyright notice and this permission notice shall be included in
|
15
|
-
# all copies or substantial portions of the Software.
|
16
|
-
#
|
17
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
20
|
-
# THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
21
|
-
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
22
|
-
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
-
|
24
|
-
require 'digest/md5'
|
25
|
-
|
26
|
-
module Utopia
|
27
|
-
|
28
|
-
class Etanni
|
29
|
-
SEPARATOR = Digest::MD5.hexdigest(Time.new.to_s)
|
30
|
-
START = "\n_out_ << <<#{SEPARATOR}.chomp!\n"
|
31
|
-
STOP = "\n#{SEPARATOR}\n"
|
32
|
-
REPLACEMENT = "#{STOP}\\1#{START}"
|
33
|
-
|
34
|
-
def initialize(template, compiled = false)
|
35
|
-
if compiled
|
36
|
-
@compiled = template
|
37
|
-
else
|
38
|
-
@template = template
|
39
|
-
compile!
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def compile!
|
44
|
-
temp = @template.dup
|
45
|
-
temp.strip!
|
46
|
-
temp.gsub!(/<\?r\s+(.*?)\s+\?>/m, REPLACEMENT)
|
47
|
-
@compiled = "_out_ = [<<#{SEPARATOR}.chomp!]\n#{temp}#{STOP}_out_"
|
48
|
-
end
|
49
|
-
|
50
|
-
def result(binding, filename = '<Etanni>')
|
51
|
-
eval(@compiled, binding, filename).join
|
52
|
-
end
|
53
|
-
|
54
|
-
attr :compiled
|
55
|
-
end
|
56
|
-
|
57
|
-
class TemplateCache
|
58
|
-
CACHE_PREFIX = ".cache."
|
59
|
-
CACHE_ENABLED = true
|
60
|
-
|
61
|
-
def self.cache_path(path)
|
62
|
-
File.join(File.dirname(path), CACHE_PREFIX + File.basename(path))
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.mtime(path)
|
66
|
-
File.symlink?(path) ? File.lstat(file_name).mtime : File.mtime(path)
|
67
|
-
end
|
68
|
-
|
69
|
-
def initialize(path, template_class = Etanni)
|
70
|
-
@path = path
|
71
|
-
@cache_path = TemplateCache.cache_path(@path)
|
72
|
-
|
73
|
-
if !File.exist?(@cache_path) || (TemplateCache.mtime(@path) > TemplateCache.mtime(@cache_path))
|
74
|
-
@template = template_class.new(File.read(@path))
|
75
|
-
File.open(@cache_path, "w") { |f| f.write(@template.compiled) }
|
76
|
-
else
|
77
|
-
@template = template_class.new(File.read(@cache_path), true)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def result(binding)
|
82
|
-
@template.result(binding, @cache_path)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|