runo 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +19 -0
- data/README.rdoc +120 -0
- data/bin/runo +35 -0
- data/lib/_error.rb +14 -0
- data/lib/_field.rb +260 -0
- data/lib/_i18n.rb +141 -0
- data/lib/_parser.rb +243 -0
- data/lib/_path.rb +86 -0
- data/lib/_storage/_storage.rb +213 -0
- data/lib/_storage/file.rb +200 -0
- data/lib/_storage/sequel.rb +174 -0
- data/lib/_storage/temp.rb +73 -0
- data/lib/_widget/action_create.rb +23 -0
- data/lib/_widget/action_login.rb +22 -0
- data/lib/_widget/action_signup.rb +16 -0
- data/lib/_widget/action_update.rb +16 -0
- data/lib/_widget/crumb.rb +24 -0
- data/lib/_widget/done.rb +16 -0
- data/lib/_widget/login.rb +25 -0
- data/lib/_widget/me.rb +31 -0
- data/lib/_widget/message.rb +51 -0
- data/lib/_widget/navi.rb +88 -0
- data/lib/_widget/submit.rb +49 -0
- data/lib/_widget/view_ym.rb +77 -0
- data/lib/_workflow/_workflow.rb +89 -0
- data/lib/_workflow/attachment.rb +50 -0
- data/lib/_workflow/blog.rb +28 -0
- data/lib/_workflow/contact.rb +23 -0
- data/lib/_workflow/forum.rb +26 -0
- data/lib/_workflow/register.rb +39 -0
- data/lib/meta/_meta.rb +20 -0
- data/lib/meta/group.rb +19 -0
- data/lib/meta/id.rb +59 -0
- data/lib/meta/owner.rb +21 -0
- data/lib/meta/timestamp.rb +118 -0
- data/lib/runo.rb +396 -0
- data/lib/scalar/checkbox.rb +68 -0
- data/lib/scalar/file.rb +144 -0
- data/lib/scalar/img.rb +112 -0
- data/lib/scalar/password.rb +58 -0
- data/lib/scalar/radio.rb +47 -0
- data/lib/scalar/select.rb +47 -0
- data/lib/scalar/text.rb +38 -0
- data/lib/scalar/textarea.rb +35 -0
- data/lib/scalar/textarea_pre.rb +14 -0
- data/lib/scalar/textarea_wiki.rb +173 -0
- data/lib/set/_set.rb +195 -0
- data/lib/set/dynamic.rb +177 -0
- data/lib/set/static.rb +102 -0
- data/lib/set/static_folder.rb +96 -0
- data/locale/en/index.po +242 -0
- data/locale/index.pot +243 -0
- data/locale/ja/index.po +242 -0
- data/locale/lazy_parser.rb +54 -0
- data/skel/config.ru +27 -0
- data/skel/skin/_users/00000000_frank-avatar.jpg +0 -0
- data/skel/skin/_users/00000000_frank-avatar_small.jpg +0 -0
- data/skel/skin/_users/00000000_frank.yaml +12 -0
- data/skel/skin/_users/00000000_root-avatar.jpg +0 -0
- data/skel/skin/_users/00000000_root-avatar_small.jpg +0 -0
- data/skel/skin/_users/00000000_root.yaml +11 -0
- data/skel/skin/_users/css/users.css +21 -0
- data/skel/skin/_users/css/users.less +25 -0
- data/skel/skin/_users/done.html +42 -0
- data/skel/skin/_users/index.html +46 -0
- data/skel/skin/_users/index.yaml +3 -0
- data/skel/skin/_users/summary.html +40 -0
- data/skel/skin/css/base.css +93 -0
- data/skel/skin/css/base.less +139 -0
- data/skel/skin/css/coax.css +199 -0
- data/skel/skin/css/coax.less +244 -0
- data/skel/skin/examples/blog/20091214_0001.yaml +8 -0
- data/skel/skin/examples/blog/20100630_0001.yaml +8 -0
- data/skel/skin/examples/blog/20100630_0002.yaml +14 -0
- data/skel/skin/examples/blog/20100701_0001.yaml +8 -0
- data/skel/skin/examples/blog/20100701_0002-a-20100701_0001-f.jpg +0 -0
- data/skel/skin/examples/blog/20100701_0002-a-20100701_0001-f_small.jpg +0 -0
- data/skel/skin/examples/blog/20100701_0002.yaml +19 -0
- data/skel/skin/examples/blog/frank/20100701_0001.yaml +10 -0
- data/skel/skin/examples/blog/frank/index.yaml +4 -0
- data/skel/skin/examples/blog/index.html +51 -0
- data/skel/skin/examples/blog/rss.xml +18 -0
- data/skel/skin/examples/contact/20100701_0001-file.txt +1 -0
- data/skel/skin/examples/contact/20100701_0001.yaml +15 -0
- data/skel/skin/examples/contact/20100701_0002.yaml +8 -0
- data/skel/skin/examples/contact/20100701_0003.yaml +9 -0
- data/skel/skin/examples/contact/index.html +47 -0
- data/skel/skin/examples/contact/js/contact.js +13 -0
- data/skel/skin/examples/contact/summary.html +54 -0
- data/skel/skin/examples/forum/20100701_0001.yaml +41 -0
- data/skel/skin/examples/forum/20100701_0002.yaml +25 -0
- data/skel/skin/examples/forum/index.html +68 -0
- data/skel/skin/examples/forum/summary.html +47 -0
- data/skel/skin/examples/index.html +75 -0
- data/skel/skin/index.html +41 -0
- data/skel/skin/js/base.js +50 -0
- data/t/locale/de/index.po +19 -0
- data/t/locale/en-GB/index.po +25 -0
- data/t/locale/ja/index.po +30 -0
- data/t/skin/_users/00000000_test.yaml +3 -0
- data/t/skin/_users/index.html +13 -0
- data/t/skin/foo/20091120_0001.yaml +7 -0
- data/t/skin/foo/bar/20091120_0001.yaml +5 -0
- data/t/skin/foo/bar/index.yaml +5 -0
- data/t/skin/foo/baz/css/baz.css +1 -0
- data/t/skin/foo/css/foo.css +1 -0
- data/t/skin/foo/index.html +14 -0
- data/t/skin/foo/index.yaml +7 -0
- data/t/skin/foo/not_css/foo.css +1 -0
- data/t/skin/foo/sub-20100306_0001.yaml +3 -0
- data/t/skin/index.yaml +3 -0
- data/t/skin/t_attachment/index.html +13 -0
- data/t/skin/t_contact/done.html +6 -0
- data/t/skin/t_contact/index.html +9 -0
- data/t/skin/t_file/index.html +16 -0
- data/t/skin/t_img/index.html +14 -0
- data/t/skin/t_img/test.jpg +0 -0
- data/t/skin/t_select/index.html +9 -0
- data/t/skin/t_store/index.html +9 -0
- data/t/skin/t_summary/20100326_0001.yaml +3 -0
- data/t/skin/t_summary/create.html +9 -0
- data/t/skin/t_summary/index.html +9 -0
- data/t/skin/t_summary/summary.html +9 -0
- data/t/t.rb +27 -0
- data/t/test_checkbox.rb +273 -0
- data/t/test_field.rb +330 -0
- data/t/test_file.rb +900 -0
- data/t/test_id.rb +215 -0
- data/t/test_img.rb +328 -0
- data/t/test_meta.rb +57 -0
- data/t/test_parser.rb +1266 -0
- data/t/test_password.rb +188 -0
- data/t/test_radio.rb +226 -0
- data/t/test_role.rb +249 -0
- data/t/test_runo.rb +742 -0
- data/t/test_runo_call.rb +1286 -0
- data/t/test_runo_i18n.rb +318 -0
- data/t/test_select.rb +182 -0
- data/t/test_set_complex.rb +527 -0
- data/t/test_set_dynamic.rb +1504 -0
- data/t/test_set_folder.rb +515 -0
- data/t/test_set_permit.rb +246 -0
- data/t/test_set_static.rb +445 -0
- data/t/test_storage.rb +915 -0
- data/t/test_text.rb +125 -0
- data/t/test_textarea.rb +138 -0
- data/t/test_timestamp.rb +473 -0
- data/t/test_workflow.rb +367 -0
- metadata +345 -0
data/lib/_i18n.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Author:: Akira FUNAI
|
4
|
+
# Copyright:: Copyright (c) 2009 Akira FUNAI
|
5
|
+
|
6
|
+
module Runo::I18n
|
7
|
+
|
8
|
+
class Msgstr < String
|
9
|
+
def %(*args)
|
10
|
+
if args.first.is_a? ::Hash
|
11
|
+
self.gsub(/%\{(\w+)\}/) { args.first[$1.intern].to_s }
|
12
|
+
else
|
13
|
+
::String.new(self.gsub(/%\{(\w+)\}/, '%s')) % args
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module REX
|
19
|
+
COMMENT = %r{^\s*\#}
|
20
|
+
COMMENT_FUZZY = %r{^\s*\#\,\s*fuzzy}
|
21
|
+
MSGID = %r{^\s*msgid\s*"(.*?[^\\])"}
|
22
|
+
MSGSTR = %r{^\s*msgstr\s*"(.*?[^\\])"}
|
23
|
+
MSGSTR_PLURAL = %r{^\s*msgstr\[(\d+)\]\s*"(.*?[^\\])"}
|
24
|
+
PLURAL_EXPRESSION = %r{
|
25
|
+
^"Plural-Forms:.*plural=
|
26
|
+
((?:
|
27
|
+
n(?=\s*(?:[\+\-\%]|==|!=|>|<|>=|<=))|
|
28
|
+
[\d\s\+\-\%\(\)\?\:]+|
|
29
|
+
==|!=|>|<|>=|<=|&&|\|\|)+).*"
|
30
|
+
}xi
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.lang
|
34
|
+
Thread.current[:lang] || []
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.lang=(http_accept_language)
|
38
|
+
Thread.current[:msg] = nil
|
39
|
+
tokens = http_accept_language.to_s.split(/,/)
|
40
|
+
Thread.current[:lang] = tokens.sort_by {|t| # rfc3282
|
41
|
+
[
|
42
|
+
(t =~ /q=([\d\.]+)/) ? $1.to_f : 1.0,
|
43
|
+
-tokens.index(t)
|
44
|
+
]
|
45
|
+
}.reverse.collect {|i|
|
46
|
+
if i =~ /([a-z]{1,8})(-[a-z]{1,8})?/i # rfc2616
|
47
|
+
$2 ? ($1.downcase + $2.upcase) : $1.downcase
|
48
|
+
end
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.domain
|
53
|
+
@@domain ||= 'index'
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.domain=(domain)
|
57
|
+
@@domain = domain
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.po_dir
|
61
|
+
@@po_dir ||= ::File.expand_path('../locale', ::File.dirname(__FILE__))
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.po_dir=(po_dir)
|
65
|
+
@@po_dir = po_dir
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.bindtextdomain(domain, po_dir)
|
69
|
+
self.domain = domain
|
70
|
+
self.po_dir = po_dir
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.msg
|
74
|
+
@@msg ||= {}
|
75
|
+
@@msg[self.lang] ||= self.find_msg
|
76
|
+
Thread.current[:msg] ||= @@msg[self.lang]
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.find_msg(lang = self.lang)
|
80
|
+
lang.each {|range|
|
81
|
+
[
|
82
|
+
range,
|
83
|
+
range.sub(/-.*/, ''),
|
84
|
+
].uniq.each {|r|
|
85
|
+
po_file = ::File.join(self.po_dir, r, "#{self.domain}.po")
|
86
|
+
return open(po_file) {|f| self.parse_msg f } if ::File.readable? po_file
|
87
|
+
return {} if r == 'en' # default
|
88
|
+
}
|
89
|
+
}
|
90
|
+
{}
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.parse_msg(f)
|
94
|
+
msg = {}
|
95
|
+
msgid = nil
|
96
|
+
f.each_line {|line|
|
97
|
+
case line
|
98
|
+
when REX::COMMENT_FUZZY
|
99
|
+
msgid = :skip_next
|
100
|
+
when REX::COMMENT
|
101
|
+
next
|
102
|
+
when REX::PLURAL_EXPRESSION
|
103
|
+
msg[:plural] = instance_eval "Proc.new {|n| #{$1} }"
|
104
|
+
when REX::MSGID
|
105
|
+
msgid = (msgid == :skip_next) ? :skip : $1
|
106
|
+
when REX::MSGSTR_PLURAL
|
107
|
+
if msgid.is_a? ::String
|
108
|
+
msg[msgid] = [] unless msg[msgid].is_a? ::Array
|
109
|
+
msg[msgid][$1.to_i] = $2
|
110
|
+
end
|
111
|
+
when REX::MSGSTR
|
112
|
+
msg[msgid] = $1 if msgid.is_a? ::String
|
113
|
+
end
|
114
|
+
}
|
115
|
+
msg
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.merge_msg!(m)
|
119
|
+
m.delete :plural
|
120
|
+
Thread.current[:msg] = self.msg.merge m
|
121
|
+
end
|
122
|
+
|
123
|
+
module_function
|
124
|
+
|
125
|
+
def _(msgid)
|
126
|
+
Runo::I18n::Msgstr.new(Runo::I18n.msg[msgid].to_a.first || msgid)
|
127
|
+
end
|
128
|
+
|
129
|
+
def n_(msgid, msgid_plural, n)
|
130
|
+
msgstrs = Runo::I18n.msg[msgid].is_a?(::Array) ? Runo::I18n.msg[msgid] : [msgid, msgid_plural]
|
131
|
+
case v = Runo::I18n.msg[:plural] ? Runo::I18n.msg[:plural].call(n) : (n != 1)
|
132
|
+
when true
|
133
|
+
Runo::I18n::Msgstr.new msgstrs[1]
|
134
|
+
when false
|
135
|
+
Runo::I18n::Msgstr.new msgstrs[0]
|
136
|
+
else
|
137
|
+
Runo::I18n::Msgstr.new msgstrs[v.to_i]
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
data/lib/_parser.rb
ADDED
@@ -0,0 +1,243 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Author:: Akira FUNAI
|
4
|
+
# Copyright:: Copyright (c) 2009 Akira FUNAI
|
5
|
+
|
6
|
+
module Runo::Parser
|
7
|
+
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def parse_html(html, action = :index, xml = false)
|
11
|
+
item = {}
|
12
|
+
|
13
|
+
html = gsub_block(html, 'runo-\w+') {|open, inner, close|
|
14
|
+
id = open[/id="(.+?)"/i, 1] || 'main'
|
15
|
+
item[id] = parse_block(open, inner, close, action, xml)
|
16
|
+
"$(#{id})"
|
17
|
+
}
|
18
|
+
html = gsub_action_tmpl(html) {|id, act, open, inner, close|
|
19
|
+
id ||= 'main'
|
20
|
+
if item[id]
|
21
|
+
item[id][:tmpl] ||= {}
|
22
|
+
inner = gsub_action_tmpl(inner) {|i, a, *t|
|
23
|
+
item[id][:tmpl][a] = t.join
|
24
|
+
"$(.#{a})"
|
25
|
+
}
|
26
|
+
item[id][:tmpl][act] = open + inner + close
|
27
|
+
"$(#{id}.#{act})"
|
28
|
+
else
|
29
|
+
open + inner + close
|
30
|
+
end
|
31
|
+
}
|
32
|
+
item.each {|id, meta|
|
33
|
+
m = Proc.new {|a| html.include?("$(#{id}.#{a})") || meta[:tmpl][action].include?("$(.#{a})") }
|
34
|
+
supplement_sd(meta[:tmpl][action], meta[:workflow], m)
|
35
|
+
html.sub!("$(#{id})", "$(#{id}.message)\\&") unless (
|
36
|
+
meta[:workflow] == 'attachment' || m.call('message')
|
37
|
+
)
|
38
|
+
} unless xml
|
39
|
+
|
40
|
+
html = gsub_scalar(html) {|id, meta|
|
41
|
+
item[id] = meta
|
42
|
+
"$(#{id})"
|
43
|
+
}
|
44
|
+
html.gsub!(/\s*class=".*?"/,'') if xml
|
45
|
+
|
46
|
+
meta = scrape_meta html
|
47
|
+
meta.merge(
|
48
|
+
:label => meta[:label] || scrape_label(html),
|
49
|
+
:item => item,
|
50
|
+
:tmpl => {action => html}
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_xml(html, action = :index)
|
55
|
+
parse_html(html, action, xml = true)
|
56
|
+
end
|
57
|
+
|
58
|
+
def gsub_action_tmpl(html, &block)
|
59
|
+
rex_klass = /(?:\w+\-)?(?:action|view|navi|submit|done)\w*/
|
60
|
+
gsub_block(html, rex_klass) {|open, inner, close|
|
61
|
+
klass = open[/class=(?:"|"[^"]*?\s)(#{rex_klass})(?:"|\s)/, 1]
|
62
|
+
id, action = (klass =~ /-/) ? klass.split('-', 2) : [nil, klass]
|
63
|
+
block.call(id, action.intern, open, inner, close)
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def gsub_block(html, class_name, &block)
|
68
|
+
rex_open_tag = /\s*<(\w+)[^>]+?class=(?:"|"[^"]*?\s)#{class_name}(?:"|\s).*?>\n?/i
|
69
|
+
out = ''
|
70
|
+
s = StringScanner.new html
|
71
|
+
until s.eos?
|
72
|
+
if s.scan rex_open_tag
|
73
|
+
open_tag = s[0]
|
74
|
+
inner_html, close_tag = scan_inner_html(s, s[1])
|
75
|
+
close_tag << "\n" if s.scan /\n/
|
76
|
+
out << block.call(open_tag, inner_html, close_tag)
|
77
|
+
else
|
78
|
+
out << s.scan(/.+?(?=\t| |<|\z)/m)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
out
|
82
|
+
end
|
83
|
+
|
84
|
+
def gsub_scalar(html, &block)
|
85
|
+
out = ''
|
86
|
+
s = StringScanner.new html
|
87
|
+
until s.eos?
|
88
|
+
if s.scan /\$\((\w+)(?:\s+|\s*=\s*)([\w\-]+)\s*/m
|
89
|
+
out << block.call(s[1], {:klass => s[2]}.merge(scan_tokens s))
|
90
|
+
else
|
91
|
+
out << s.scan(/.+?(?=\$|\w|<|\z)/m)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
out
|
95
|
+
end
|
96
|
+
|
97
|
+
def scrape_meta(html)
|
98
|
+
meta = {}
|
99
|
+
html.gsub!(/(?:^\s+)?<meta[^>]*name="runo-([^"]+)[^>]*content="([^"]+).*?>\n?/i) {
|
100
|
+
meta[$1.intern] = $2.include?(',') ? $2.split(/\s*,\s*/) : $2
|
101
|
+
''
|
102
|
+
}
|
103
|
+
meta
|
104
|
+
end
|
105
|
+
|
106
|
+
def scrape_label(html)
|
107
|
+
if html.sub!(/\A((?:[^<]*<!--)?[^<]*<[^>]*title=")([^"]+)/, '\\1')
|
108
|
+
label_plural = $2.to_s.split(/,/).collect {|s| s.strip }
|
109
|
+
label_plural *= 4 if label_plural.size == 1
|
110
|
+
label = label_plural.first
|
111
|
+
Runo::I18n.msg[label] ||= label_plural
|
112
|
+
label
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def supplement_sd(tmpl, workflow, m)
|
117
|
+
tmpl << '$(.navi)' unless m.call 'navi'
|
118
|
+
unless workflow == 'attachment'
|
119
|
+
tmpl << '$(.submit)' unless m.call 'submit'
|
120
|
+
tmpl << '$(.action_create)' unless m.call 'action_create'
|
121
|
+
end
|
122
|
+
tmpl
|
123
|
+
end
|
124
|
+
|
125
|
+
def supplement_ss(tmpl, action)
|
126
|
+
if action == :summary
|
127
|
+
tmpl.sub!(
|
128
|
+
/\$\(.*?\)/m,
|
129
|
+
'<a href="$(.uri_detail)">\&</a>'
|
130
|
+
) unless tmpl.include? '$(.uri_detail)'
|
131
|
+
else
|
132
|
+
tmpl.sub!(
|
133
|
+
/\$\([^\.]*?\)/m,
|
134
|
+
'$(.a_update)\&</a>'
|
135
|
+
) unless tmpl.include? '$(.action_update)'
|
136
|
+
tmpl.sub!(
|
137
|
+
/.*\$\(.*?\)/m,
|
138
|
+
'\&$(.hidden)'
|
139
|
+
) unless tmpl.include? '$(.hidden)'
|
140
|
+
end
|
141
|
+
tmpl
|
142
|
+
end
|
143
|
+
|
144
|
+
def parse_block(open_tag, inner_html, close_tag, action = :index, xml = false)
|
145
|
+
open_tag.sub!(/id=".*?"/i, 'id="@(name)"')
|
146
|
+
workflow = open_tag[/class=(?:"|".*?\s)runo-(\w+)/, 1]
|
147
|
+
|
148
|
+
if inner_html =~ /<(\w+).+?class=(?:"|"[^"]*?\s)body(?:"|\s)/i
|
149
|
+
item_html = ''
|
150
|
+
sd_tmpl = gsub_block(inner_html, 'body') {|open, inner, close|
|
151
|
+
item_html = open + inner + close
|
152
|
+
'$()'
|
153
|
+
}
|
154
|
+
else
|
155
|
+
item_html = inner_html
|
156
|
+
sd_tmpl = '$()'
|
157
|
+
end
|
158
|
+
|
159
|
+
tmpl = {}
|
160
|
+
sd_tmpl = gsub_action_tmpl(sd_tmpl) {|id, act, open, inner, close|
|
161
|
+
inner = gsub_action_tmpl(inner) {|i, a, *t|
|
162
|
+
tmpl[a] = t.join
|
163
|
+
"$(.#{a})"
|
164
|
+
}
|
165
|
+
tmpl[act] = open + inner + close
|
166
|
+
"$(.#{act})"
|
167
|
+
}
|
168
|
+
|
169
|
+
tmpl[action] = "#{open_tag}#{sd_tmpl}#{close_tag}"
|
170
|
+
tmpl[action].gsub!(/\s*class=".*?"/,'') if xml
|
171
|
+
|
172
|
+
item_meta = Runo::Parser.parse_html(item_html, action, xml)
|
173
|
+
supplement_ss(item_meta[:tmpl][action], action) unless xml || workflow == 'attachment'
|
174
|
+
|
175
|
+
sd = {
|
176
|
+
:klass => 'set-dynamic',
|
177
|
+
:workflow => workflow.downcase,
|
178
|
+
:tmpl => tmpl,
|
179
|
+
:item => {
|
180
|
+
'default' => item_meta,
|
181
|
+
},
|
182
|
+
}
|
183
|
+
(inner_html =~ /\A\s*<!--(.+?)-->/m) ? sd.merge(scan_tokens StringScanner.new($1)) : sd
|
184
|
+
end
|
185
|
+
|
186
|
+
def parse_token(prefix, token, meta = {})
|
187
|
+
case prefix
|
188
|
+
when ':'
|
189
|
+
meta[:default] = token
|
190
|
+
when ';'
|
191
|
+
meta[:defaults] ||= []
|
192
|
+
meta[:defaults] << token
|
193
|
+
when ','
|
194
|
+
meta[:options] ||= []
|
195
|
+
meta[:options] << token
|
196
|
+
else
|
197
|
+
case token
|
198
|
+
when /^(-?\d+)?\.\.(-?\d+)?$/
|
199
|
+
meta[:min] = $1.to_i if $1
|
200
|
+
meta[:max] = $2.to_i if $2
|
201
|
+
when /^(\d+)\*(\d+)$/
|
202
|
+
meta[:width] = $1.to_i
|
203
|
+
meta[:height] = $2.to_i
|
204
|
+
else
|
205
|
+
meta[:tokens] ||= []
|
206
|
+
meta[:tokens] << token
|
207
|
+
end
|
208
|
+
end
|
209
|
+
meta
|
210
|
+
end
|
211
|
+
|
212
|
+
def scan_inner_html(s, name)
|
213
|
+
contents = ''
|
214
|
+
gen = 1
|
215
|
+
until s.eos? || (gen < 1)
|
216
|
+
contents << s.scan(/(.*?)(<#{name}|<\/#{name}>|\z)/m)
|
217
|
+
gen += 1 if s[2] == "<#{name}"
|
218
|
+
gen -= 1 if s[2] == "</#{name}>"
|
219
|
+
end
|
220
|
+
contents.gsub!(/\A\n+/, '')
|
221
|
+
contents.gsub!(/[\t ]*<\/#{name}>\z/, '')
|
222
|
+
[contents, $&]
|
223
|
+
end
|
224
|
+
|
225
|
+
def scan_tokens(s)
|
226
|
+
meta = {}
|
227
|
+
until s.eos? || s.scan(/\)/)
|
228
|
+
prefix = s[1] if s.scan /([:;,])?\s*/
|
229
|
+
if s.scan /(["'])(.*?)(\1|$)/
|
230
|
+
token = s[2]
|
231
|
+
elsif s.scan /[^\s\):;,]+/
|
232
|
+
token = s[0]
|
233
|
+
end
|
234
|
+
prefix ||= ',' if s.scan /(?=,)/ # 1st element of options
|
235
|
+
prefix ||= ';' if s.scan /(?=;)/ # 1st element of defaults
|
236
|
+
|
237
|
+
parse_token(prefix, token, meta)
|
238
|
+
s.scan /\s+/
|
239
|
+
end
|
240
|
+
meta
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
data/lib/_path.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Author:: Akira FUNAI
|
4
|
+
# Copyright:: Copyright (c) 2009 Akira FUNAI
|
5
|
+
|
6
|
+
module Runo::Path
|
7
|
+
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def tid_of(path)
|
11
|
+
path[Runo::REX::TID]
|
12
|
+
end
|
13
|
+
|
14
|
+
def steps_of(path)
|
15
|
+
_dirname(path).gsub(Runo::REX::PATH_ID, '').split('/').select {|step_or_cond|
|
16
|
+
step_or_cond != '' &&
|
17
|
+
step_or_cond !~ Regexp.union(Runo::REX::COND, Runo::REX::COND_D, Runo::REX::TID)
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def base_of(path)
|
22
|
+
base = Runo::Set::Static::Folder.root.item(steps_of path)
|
23
|
+
if base.is_a? Runo::Set::Static::Folder
|
24
|
+
base.item 'main'
|
25
|
+
else
|
26
|
+
base
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def conds_of(path)
|
31
|
+
dir = _dirname path.gsub(Runo::REX::PATH_ID, '')
|
32
|
+
conds = $& ? {:id => sprintf('%.8d_%.4d', $1, $2)} : {}
|
33
|
+
|
34
|
+
dir.split('/').inject(conds) {|conds, step_or_cond|
|
35
|
+
if step_or_cond =~ Runo::REX::COND
|
36
|
+
conds[$1.intern] = $2
|
37
|
+
elsif step_or_cond =~ Runo::REX::COND_D
|
38
|
+
conds[:d] = $&
|
39
|
+
end
|
40
|
+
conds
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def action_of(path)
|
45
|
+
a = _basename(path).to_s[/^[a-z]+/]
|
46
|
+
a.intern if a && a != 'index'
|
47
|
+
end
|
48
|
+
|
49
|
+
def sub_action_of(path)
|
50
|
+
a = _basename(path).to_s[/_([a-z]+)/, 1]
|
51
|
+
a.intern if a
|
52
|
+
end
|
53
|
+
|
54
|
+
def path_of(conds)
|
55
|
+
conds = {} unless conds.is_a? ::Hash
|
56
|
+
(
|
57
|
+
(conds.keys - [:order, :p, :id]) |
|
58
|
+
([:order, :p, :id] & conds.keys)
|
59
|
+
).collect {|cid|
|
60
|
+
if cid == :id
|
61
|
+
ids = Array(conds[:id]).collect {|id|
|
62
|
+
(id =~ /_(#{Runo::REX::ID_SHORT})$/) ? $1 : (id if Runo::REX::ID)
|
63
|
+
}.compact
|
64
|
+
if (ids.size == 1) && (ids.first =~ Runo::REX::ID)
|
65
|
+
'%s/%d/' % [$1, $2.to_i]
|
66
|
+
elsif ids.size > 0
|
67
|
+
"id=#{ids.join ','}/"
|
68
|
+
end
|
69
|
+
elsif cid == :d
|
70
|
+
conds[:id] ? '' : "#{conds[:d]}/"
|
71
|
+
else
|
72
|
+
"#{cid}=#{Array(conds[cid]).join ','}/"
|
73
|
+
end
|
74
|
+
}.join.sub(%r{/p=1/$}, '/')
|
75
|
+
end
|
76
|
+
|
77
|
+
def _dirname(path) # returns '/foo/bar/' for '/foo/bar/'
|
78
|
+
path[%r{^.*/}] || ''
|
79
|
+
end
|
80
|
+
|
81
|
+
def _basename(path) # returns nil for '/foo/bar/'
|
82
|
+
path[%r{[^/]+$}]
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|