utopia 0.9.17
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/utopia/xnode/fast_scanner/extconf.rb +6 -0
- data/ext/utopia/xnode/fast_scanner/parser.c +289 -0
- data/lib/utopia.rb +2 -0
- data/lib/utopia/etanni.rb +96 -0
- data/lib/utopia/extensions.rb +87 -0
- data/lib/utopia/link.rb +243 -0
- data/lib/utopia/middleware.rb +33 -0
- data/lib/utopia/middleware/all.rb +24 -0
- data/lib/utopia/middleware/benchmark.rb +47 -0
- data/lib/utopia/middleware/content.rb +139 -0
- data/lib/utopia/middleware/content/node.rb +363 -0
- data/lib/utopia/middleware/controller.rb +198 -0
- data/lib/utopia/middleware/directory_index.rb +54 -0
- data/lib/utopia/middleware/localization.rb +94 -0
- data/lib/utopia/middleware/localization/name.rb +64 -0
- data/lib/utopia/middleware/logger.rb +68 -0
- data/lib/utopia/middleware/redirector.rb +171 -0
- data/lib/utopia/middleware/requester.rb +116 -0
- data/lib/utopia/middleware/static.rb +186 -0
- data/lib/utopia/path.rb +193 -0
- data/lib/utopia/response_helper.rb +22 -0
- data/lib/utopia/session/encrypted_cookie.rb +115 -0
- data/lib/utopia/tag.rb +84 -0
- data/lib/utopia/tags.rb +32 -0
- data/lib/utopia/tags/all.rb +25 -0
- data/lib/utopia/tags/env.rb +24 -0
- data/lib/utopia/tags/fortune.rb +20 -0
- data/lib/utopia/tags/gallery.rb +175 -0
- data/lib/utopia/tags/google_analytics.rb +37 -0
- data/lib/utopia/tags/node.rb +24 -0
- data/lib/utopia/tags/override.rb +28 -0
- data/lib/utopia/time_store.rb +102 -0
- data/lib/utopia/version.rb +24 -0
- data/lib/utopia/xnode.rb +17 -0
- data/lib/utopia/xnode/processor.rb +97 -0
- data/lib/utopia/xnode/scanner.rb +153 -0
- metadata +168 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'utopia/tags'
|
17
|
+
|
18
|
+
Utopia::Tags.create("google_analytics") do |transaction, state|
|
19
|
+
html = <<EOF
|
20
|
+
<!-- Google Analytics -->
|
21
|
+
|
22
|
+
<script type="text/javascript">
|
23
|
+
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
24
|
+
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
25
|
+
</script>
|
26
|
+
<script type="text/javascript">
|
27
|
+
try {
|
28
|
+
var pageTracker = _gat._getTracker(#{state[:id].dump});
|
29
|
+
pageTracker._trackPageview();
|
30
|
+
} catch(err) {}</script>
|
31
|
+
|
32
|
+
<!-- Google Analytics -->
|
33
|
+
EOF
|
34
|
+
|
35
|
+
|
36
|
+
transaction.cdata(html)
|
37
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'utopia/tags'
|
17
|
+
|
18
|
+
Utopia::Tags.create("node") do |transaction, state|
|
19
|
+
path = Utopia::Path.create(state[:path])
|
20
|
+
|
21
|
+
node = transaction.lookup_node(path)
|
22
|
+
|
23
|
+
transaction.render_node(node)
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'utopia/tags'
|
17
|
+
|
18
|
+
class Utopia::Tags::Override
|
19
|
+
def self.tag_begin(transaction, state)
|
20
|
+
state.overrides[state[:name]] = state[:with]
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.call(transaction, state)
|
24
|
+
transaction.parse_xml(state.content)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Utopia::Tags.register("override", Utopia::Tags::Override)
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'set'
|
17
|
+
require 'csv'
|
18
|
+
|
19
|
+
module Utopia
|
20
|
+
|
21
|
+
# TimeStore is a very simple time oriented database. New entries
|
22
|
+
# are added in chronological order and it is not possible to change
|
23
|
+
# this behaviour, or remove old entries. It stores data in a CSV
|
24
|
+
# format into a directory where each file represents a week in the
|
25
|
+
# year.
|
26
|
+
#
|
27
|
+
# The design of this class is to enable efficient logging of data
|
28
|
+
# in a backup friendly file format (i.e. files older than one week
|
29
|
+
# are not touched).
|
30
|
+
#
|
31
|
+
# Due to the nature of CSV data, a header must be specified. This
|
32
|
+
# header can have columns added, but not removed. Columns not
|
33
|
+
# specified in the header will not be recorded.
|
34
|
+
#
|
35
|
+
class TimeStore
|
36
|
+
def initialize(path, header)
|
37
|
+
@path = path
|
38
|
+
|
39
|
+
header = header.collect{|name| name.to_s}
|
40
|
+
|
41
|
+
@header_path = File.join(@path, "header.csv")
|
42
|
+
|
43
|
+
if File.exist? @header_path
|
44
|
+
@header = File.read(@header_path).split(",")
|
45
|
+
else
|
46
|
+
@header = []
|
47
|
+
end
|
48
|
+
|
49
|
+
diff = (Set.new(header) + "time") - @header
|
50
|
+
|
51
|
+
if diff.size
|
52
|
+
@header += diff.to_a.sort
|
53
|
+
|
54
|
+
File.open(@header_path, "w") do |file|
|
55
|
+
file.write(@header.join(","))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
@last_path = nil
|
60
|
+
@last_file = nil
|
61
|
+
end
|
62
|
+
|
63
|
+
attr :header
|
64
|
+
|
65
|
+
def path_for_time(time)
|
66
|
+
return File.join(@path, time.strftime("%Y-%W") + ".csv")
|
67
|
+
end
|
68
|
+
|
69
|
+
def open(time, &block)
|
70
|
+
path = path_for_time(time)
|
71
|
+
|
72
|
+
if @last_path != path
|
73
|
+
if @last_file
|
74
|
+
@last_file.close
|
75
|
+
@last_file = nil
|
76
|
+
end
|
77
|
+
|
78
|
+
@last_file = File.open(path, "a")
|
79
|
+
@last_file.sync = true
|
80
|
+
@last_path = path
|
81
|
+
end
|
82
|
+
|
83
|
+
yield @last_file
|
84
|
+
|
85
|
+
#File.open(path_for_time(time), "a", &block)
|
86
|
+
end
|
87
|
+
|
88
|
+
def dump(values)
|
89
|
+
row = @header.collect{|key| values[key.to_sym]}
|
90
|
+
return CSV.generate_line(row)
|
91
|
+
end
|
92
|
+
|
93
|
+
def <<(values)
|
94
|
+
time = values[:time] = Time.now
|
95
|
+
|
96
|
+
open(time) do |file|
|
97
|
+
file.puts(dump(values))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright (c) 2009 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
module Utopia
|
17
|
+
module VERSION #:nodoc:
|
18
|
+
MAJOR = 0
|
19
|
+
MINOR = 9
|
20
|
+
TINY = 17
|
21
|
+
|
22
|
+
STRING = [MAJOR, MINOR, TINY].join('.')
|
23
|
+
end
|
24
|
+
end
|
data/lib/utopia/xnode.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'utopia/xnode/scanner'
|
17
|
+
require 'utopia/xnode/processor'
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'utopia/tag'
|
17
|
+
|
18
|
+
module Utopia
|
19
|
+
module XNode
|
20
|
+
OPENED_TAG = 0
|
21
|
+
CLOSED_TAG = 1
|
22
|
+
|
23
|
+
class UnbalancedTagError < StandardError
|
24
|
+
def initialize(scanner, start_pos, current_tag, closing_tag)
|
25
|
+
@scanner = scanner
|
26
|
+
@start_pos = start_pos
|
27
|
+
@current_tag = current_tag
|
28
|
+
@closing_tag = closing_tag
|
29
|
+
|
30
|
+
@starting_line = @scanner.calculate_line_number(@start_pos)
|
31
|
+
@ending_line = @scanner.calculate_line_number
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
"UnbalancedTagError: Tag #{@current_tag} (line #{@starting_line[0]}: #{@starting_line[4]}) has been closed by #{@closing_tag} (line #{@ending_line[0]}: #{@ending_line[4]})."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Processor
|
40
|
+
def initialize(content, delegate, options = {})
|
41
|
+
@delegate = delegate
|
42
|
+
@stack = []
|
43
|
+
|
44
|
+
@scanner = (options[:scanner] || Scanner).new(self, content)
|
45
|
+
end
|
46
|
+
|
47
|
+
def parse
|
48
|
+
@scanner.parse
|
49
|
+
end
|
50
|
+
|
51
|
+
def cdata(text)
|
52
|
+
# $stderr.puts "\tcdata: #{text}"
|
53
|
+
@delegate.cdata(text)
|
54
|
+
end
|
55
|
+
|
56
|
+
def comment(text)
|
57
|
+
cdata("<!#{text}>")
|
58
|
+
end
|
59
|
+
|
60
|
+
def begin_tag(tag_name, begin_tag_type)
|
61
|
+
# $stderr.puts "begin_tag: #{tag_name}, #{begin_tag_type}"
|
62
|
+
if begin_tag_type == OPENED_TAG
|
63
|
+
@stack << [Tag.new(tag_name, {}), @scanner.pos]
|
64
|
+
else
|
65
|
+
cur, pos = @stack.pop
|
66
|
+
|
67
|
+
if (tag_name != cur.name)
|
68
|
+
raise UnbalancedTagError.new(@scanner, pos, cur.name, tag_name)
|
69
|
+
end
|
70
|
+
|
71
|
+
@delegate.tag_end(cur)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def finish_tag(begin_tag_type, end_tag_type)
|
76
|
+
# $stderr.puts "finish_tag: #{begin_tag_type} #{end_tag_type}"
|
77
|
+
if begin_tag_type == OPENED_TAG # <...
|
78
|
+
if end_tag_type == CLOSED_TAG # <.../>
|
79
|
+
cur, pos = @stack.pop
|
80
|
+
cur.closed = true
|
81
|
+
|
82
|
+
@delegate.tag_complete(cur)
|
83
|
+
elsif end_tag_type == OPENED_TAG # <...>
|
84
|
+
cur, pos = @stack.last
|
85
|
+
|
86
|
+
@delegate.tag_begin(cur)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def attribute(name, value)
|
92
|
+
# $stderr.puts "\tattribute: #{name} = #{value}"
|
93
|
+
@stack.last[0].attributes[name] = value
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'strscan'
|
17
|
+
require 'tempfile'
|
18
|
+
|
19
|
+
module Utopia
|
20
|
+
module XNode
|
21
|
+
class ScanError < StandardError
|
22
|
+
def initialize(message, scanner)
|
23
|
+
@message = message
|
24
|
+
|
25
|
+
@pos = scanner.pos
|
26
|
+
@line = scanner.calculate_line_number
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
if @line
|
31
|
+
"Scan Error: #{@message} @ [#{@line[0]}:#{@line[2]}]: #{@line[4]}"
|
32
|
+
else
|
33
|
+
"Scan Error [#{@pos}]: #{@message}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Scanner < StringScanner
|
39
|
+
CDATA = /[^<]+/m
|
40
|
+
TAG_PARAMETER = /\s*([^\s=\/>]*)=((['"])(.*?)\3)/um
|
41
|
+
|
42
|
+
def initialize(callback, string)
|
43
|
+
@callback = callback
|
44
|
+
super(string)
|
45
|
+
end
|
46
|
+
|
47
|
+
def calculate_line_number(at = pos)
|
48
|
+
line_no = 1
|
49
|
+
line_offset = offset = 0
|
50
|
+
|
51
|
+
string.lines.each do |line|
|
52
|
+
line_offset = offset
|
53
|
+
offset += line.size
|
54
|
+
|
55
|
+
if offset >= at
|
56
|
+
return [line_no, line_offset, at - line_offset, offset, line]
|
57
|
+
end
|
58
|
+
|
59
|
+
line_no += 1
|
60
|
+
end
|
61
|
+
|
62
|
+
return nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse
|
66
|
+
until eos?
|
67
|
+
pos = self.pos
|
68
|
+
|
69
|
+
scan_cdata
|
70
|
+
scan_tag
|
71
|
+
|
72
|
+
if pos == self.pos
|
73
|
+
raise ScanError.new("Scanner didn't move", self)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def scan_cdata
|
79
|
+
if scan(CDATA)
|
80
|
+
@callback.cdata(matched)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def scan_tag
|
85
|
+
if scan(/</)
|
86
|
+
if scan(/\//)
|
87
|
+
scan_tag_normal(CLOSED_TAG)
|
88
|
+
elsif scan(/!/)
|
89
|
+
scan_tag_comment
|
90
|
+
elsif scan(/\?/)
|
91
|
+
scan_tag_instruction
|
92
|
+
else
|
93
|
+
scan_tag_normal
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def scan_attributes
|
99
|
+
while scan(TAG_PARAMETER)
|
100
|
+
@callback.attribute(self[1], self[4])
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def scan_tag_normal(begin_tag_type = OPENED_TAG)
|
105
|
+
if scan(/[^\s\/>]+/)
|
106
|
+
@callback.begin_tag(matched, begin_tag_type)
|
107
|
+
|
108
|
+
scan(/\s*/)
|
109
|
+
|
110
|
+
scan_attributes
|
111
|
+
|
112
|
+
scan(/\s*/)
|
113
|
+
|
114
|
+
if scan(/\/>/)
|
115
|
+
if begin_tag_type == CLOSED_TAG
|
116
|
+
raise ScanError.new("Tag cannot be closed at both ends!", self)
|
117
|
+
else
|
118
|
+
@callback.finish_tag(begin_tag_type, CLOSED_TAG)
|
119
|
+
end
|
120
|
+
elsif scan(/>/)
|
121
|
+
@callback.finish_tag(begin_tag_type, OPENED_TAG)
|
122
|
+
else
|
123
|
+
raise ScanError.new("Invalid characters in tag!", self)
|
124
|
+
end
|
125
|
+
else
|
126
|
+
raise ScanError.new("Invalid tag!", self)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def scan_tag_comment
|
131
|
+
if scan(/--/)
|
132
|
+
if scan_until(/(.*?)-->/m)
|
133
|
+
@callback.comment("--" + self[1] + "--")
|
134
|
+
else
|
135
|
+
raise ScanError.new("Comment is not closed!", self)
|
136
|
+
end
|
137
|
+
else
|
138
|
+
if scan_until(/(.*?)>/)
|
139
|
+
@callback.comment(self[1])
|
140
|
+
else
|
141
|
+
raise ScanError.new("Comment is not closed!", self)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def scan_tag_instruction
|
147
|
+
if scan_until(/(.*)\?>/)
|
148
|
+
@callback.instruction(self[1])
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|