runo 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/_parser.rb +2 -2
- data/lib/_path.rb +2 -2
- data/lib/_storage/file.rb +1 -1
- data/lib/_storage/sequel.rb +2 -2
- data/lib/_widget/submit.rb +1 -1
- data/lib/meta/id.rb +1 -1
- data/lib/meta/timestamp.rb +1 -1
- data/lib/runo.rb +3 -3
- data/lib/scalar/checkbox.rb +2 -2
- data/lib/scalar/file.rb +1 -1
- data/lib/scalar/img.rb +1 -1
- data/lib/scalar/password.rb +2 -2
- data/lib/scalar/radio.rb +2 -2
- data/lib/scalar/select.rb +2 -2
- data/lib/scalar/text.rb +1 -1
- data/lib/scalar/textarea.rb +1 -1
- data/lib/set/dynamic.rb +1 -1
- data/lib/set/static.rb +2 -2
- data/lib/set/static_folder.rb +3 -3
- data/skel/skin/examples/index.html +0 -2
- data/skel/skin/index.html +0 -2
- data/t/skin/foo/qux/index.html +8 -0
- data/t/skin/foo/qux/moo/index.html +6 -0
- data/t/test_runo.rb +26 -0
- data/t/test_runo_call.rb +5 -10
- metadata +5 -3
data/lib/_parser.rb
CHANGED
@@ -86,7 +86,7 @@ module Runo::Parser
|
|
86
86
|
s = StringScanner.new html
|
87
87
|
until s.eos?
|
88
88
|
if s.scan /\$\((\w+)(?:\s+|\s*=\s*)([\w\-]+)\s*/m
|
89
|
-
out << block.call(s[1], {:klass => s[2]}.merge(scan_tokens
|
89
|
+
out << block.call(s[1], {:klass => s[2]}.merge(scan_tokens(s)))
|
90
90
|
else
|
91
91
|
out << s.scan(/.+?(?=\$|\w|<|\z)/m)
|
92
92
|
end
|
@@ -180,7 +180,7 @@ module Runo::Parser
|
|
180
180
|
'default' => item_meta,
|
181
181
|
},
|
182
182
|
}
|
183
|
-
(inner_html =~ /\A\s*<!--(.+?)-->/m) ? sd.merge(scan_tokens
|
183
|
+
(inner_html =~ /\A\s*<!--(.+?)-->/m) ? sd.merge(scan_tokens(StringScanner.new($1))) : sd
|
184
184
|
end
|
185
185
|
|
186
186
|
def parse_token(prefix, token, meta = {})
|
data/lib/_path.rb
CHANGED
@@ -19,9 +19,9 @@ module Runo::Path
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def base_of(path)
|
22
|
-
base = Runo::Set::Static::Folder.root.item(
|
22
|
+
base = Runo::Set::Static::Folder.root.item steps_of(path)
|
23
23
|
if base.is_a? Runo::Set::Static::Folder
|
24
|
-
base.item
|
24
|
+
base.item('main') || base.find {|item| item.is_a? Runo::Set::Dynamic } || base
|
25
25
|
else
|
26
26
|
base
|
27
27
|
end
|
data/lib/_storage/file.rb
CHANGED
@@ -11,7 +11,7 @@ require 'fileutils'
|
|
11
11
|
class Runo::Storage::File < Runo::Storage
|
12
12
|
|
13
13
|
def self.traverse(dir = '/', root = Runo['storage']['File']['data_dir'], &block)
|
14
|
-
::Dir.glob(::File.join
|
14
|
+
::Dir.glob(::File.join(root, dir, '*')).sort.collect {|file|
|
15
15
|
ftype = ::File.ftype file
|
16
16
|
base_name = ::File.basename file
|
17
17
|
id, ext = base_name.split('.', 2)
|
data/lib/_storage/sequel.rb
CHANGED
@@ -76,7 +76,7 @@ class Runo::Storage::Sequel < Runo::Storage
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def delete(id)
|
79
|
-
@dataset.filter(_conds
|
79
|
+
@dataset.filter(_conds(id)).delete &&
|
80
80
|
@dataset.grep(:full_name, _full_name("#{id}-%")).and(~:ext => 'yaml').delete &&
|
81
81
|
id
|
82
82
|
end
|
@@ -88,7 +88,7 @@ class Runo::Storage::Sequel < Runo::Storage
|
|
88
88
|
private
|
89
89
|
|
90
90
|
def _select_by_id(conds)
|
91
|
-
@dataset.filter(_conds
|
91
|
+
@dataset.filter(_conds(conds[:id])).collect {|v| _id v[:full_name] }
|
92
92
|
end
|
93
93
|
|
94
94
|
def _select_by_d(conds)
|
data/lib/_widget/submit.rb
CHANGED
@@ -36,7 +36,7 @@ _html
|
|
36
36
|
|
37
37
|
def _g_submit_preview_delete(arg)
|
38
38
|
if (
|
39
|
-
permit_get?(arg.merge
|
39
|
+
permit_get?(arg.merge(:action => :delete)) &&
|
40
40
|
collect_item(arg[:conds]).find {|item| item[:id] !~ Runo::REX::ID_NEW } &&
|
41
41
|
arg[:orig_action] != :preview
|
42
42
|
)
|
data/lib/meta/id.rb
CHANGED
@@ -16,7 +16,7 @@ class Runo::Meta::Id < Runo::Field
|
|
16
16
|
if (my[:max].to_i > 0) && (val.size > my[:max])
|
17
17
|
[_('too long: %{max} characters maximum') % {:max => my[:max]}]
|
18
18
|
elsif (my[:min].to_i == 1) && val.empty?
|
19
|
-
[_
|
19
|
+
[_('mandatory')]
|
20
20
|
elsif (my[:min].to_i > 0) && (val.size < my[:min])
|
21
21
|
[_('too short: %{min} characters minimum') % {:min => my[:min]}]
|
22
22
|
elsif val !~ /\A#{Runo::REX::ID_SHORT}\z/
|
data/lib/meta/timestamp.rb
CHANGED
data/lib/runo.rb
CHANGED
@@ -110,7 +110,7 @@ class Runo
|
|
110
110
|
Runo.current[:session] = env['rack.session']
|
111
111
|
|
112
112
|
if Runo.transaction[tid].is_a? Runo::Field
|
113
|
-
base = Runo.transaction[tid].item
|
113
|
+
base = Runo.transaction[tid].item Runo::Path.steps_of(path.sub(/\A.*#{Runo::REX::TID}/, ''))
|
114
114
|
else
|
115
115
|
base = Runo::Path.base_of path
|
116
116
|
end
|
@@ -271,10 +271,10 @@ class Runo
|
|
271
271
|
:action => Runo::Path.action_of(req.path_info),
|
272
272
|
:sub_action => Runo::Path.sub_action_of(req.path_info),
|
273
273
|
}
|
274
|
-
params.merge!(
|
274
|
+
params.merge! rebuild_params(req.params)
|
275
275
|
|
276
276
|
params[:conds] ||= {}
|
277
|
-
params[:conds].merge!
|
277
|
+
params[:conds].merge! Runo::Path.conds_of(req.path_info)
|
278
278
|
|
279
279
|
params
|
280
280
|
end
|
data/lib/scalar/checkbox.rb
CHANGED
@@ -19,9 +19,9 @@ class Runo::Checkbox < Runo::Field
|
|
19
19
|
|
20
20
|
def errors
|
21
21
|
if val.empty?
|
22
|
-
my[:mandatory] ? [_
|
22
|
+
my[:mandatory] ? [_('mandatory')] : []
|
23
23
|
else
|
24
|
-
(val - my[:options]).empty? ? [] : [_
|
24
|
+
(val - my[:options]).empty? ? [] : [_('no such option')]
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
data/lib/scalar/file.rb
CHANGED
@@ -54,7 +54,7 @@ class Runo::File < Runo::Field
|
|
54
54
|
elsif (my[:max].to_i > 0) && (val['size'].to_i > my[:max])
|
55
55
|
[_('too large: %{max} bytes maximum') % {:max => my[:max]}]
|
56
56
|
elsif (my[:min].to_i == 1) && val['size'].to_i < 1
|
57
|
-
[_
|
57
|
+
[_('mandatory')]
|
58
58
|
elsif (my[:min].to_i > 0) && (val['size'].to_i < my[:min])
|
59
59
|
[_('too small: %{min} bytes minimum') % {:min => my[:min]}]
|
60
60
|
else
|
data/lib/scalar/img.rb
CHANGED
data/lib/scalar/password.rb
CHANGED
@@ -16,7 +16,7 @@ class Runo::Password < Runo::Field
|
|
16
16
|
elsif (my[:max].to_i > 0) && (@size > my[:max])
|
17
17
|
[_('too long: %{max} characters maximum') % {:max => my[:max]}]
|
18
18
|
elsif (my[:min].to_i == 1) && (@size == 0)
|
19
|
-
[_
|
19
|
+
[_('mandatory')]
|
20
20
|
elsif (my[:min].to_i > 0) && (@size < my[:min])
|
21
21
|
[_('too short: %{min} characters minimum') % {:min => my[:min]}]
|
22
22
|
else
|
@@ -44,7 +44,7 @@ _html
|
|
44
44
|
@val = v
|
45
45
|
when :create, :update
|
46
46
|
if v.is_a?(::String) && !v.empty?
|
47
|
-
salt = ('a'..'z').to_a[rand
|
47
|
+
salt = ('a'..'z').to_a[rand(26)] + ('a'..'z').to_a[rand(26)]
|
48
48
|
@size = v.size
|
49
49
|
@val = v.crypt salt
|
50
50
|
elsif @val.nil?
|
data/lib/scalar/radio.rb
CHANGED
@@ -13,9 +13,9 @@ class Runo::Radio < Runo::Field
|
|
13
13
|
|
14
14
|
def errors
|
15
15
|
if val.empty?
|
16
|
-
my[:mandatory] ? [_
|
16
|
+
my[:mandatory] ? [_('mandatory')] : []
|
17
17
|
else
|
18
|
-
my[:options].include?(val) ? [] : [_
|
18
|
+
my[:options].include?(val) ? [] : [_('no such option')]
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
data/lib/scalar/select.rb
CHANGED
@@ -13,11 +13,11 @@ class Runo::Select < Runo::Field
|
|
13
13
|
|
14
14
|
def errors
|
15
15
|
if my[:mandatory] && val.empty?
|
16
|
-
[_
|
16
|
+
[_('mandatory')]
|
17
17
|
elsif my[:options].include?(val) || val.empty?
|
18
18
|
[]
|
19
19
|
else
|
20
|
-
[_
|
20
|
+
[_('no such option')]
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
data/lib/scalar/text.rb
CHANGED
@@ -14,7 +14,7 @@ class Runo::Text < Runo::Field
|
|
14
14
|
if (my[:max].to_i > 0) && (val.size > my[:max])
|
15
15
|
[_('too long: %{max} characters maximum') % {:max => my[:max]}]
|
16
16
|
elsif (my[:min].to_i == 1) && val.empty?
|
17
|
-
[_
|
17
|
+
[_('mandatory')]
|
18
18
|
elsif (my[:min].to_i > 0) && (val.size < my[:min])
|
19
19
|
[_('too short: %{min} characters minimum') % {:min => my[:min]}]
|
20
20
|
else
|
data/lib/scalar/textarea.rb
CHANGED
@@ -9,7 +9,7 @@ class Runo::Textarea < Runo::Field
|
|
9
9
|
if (my[:max].to_i > 0) && (val.size > my[:max])
|
10
10
|
[_('too long: %{max} characters maximum') % {:max => my[:max]}]
|
11
11
|
elsif (my[:min].to_i == 1) && val.empty?
|
12
|
-
[_
|
12
|
+
[_('mandatory')]
|
13
13
|
elsif (my[:min].to_i > 0) && (val.size < my[:min])
|
14
14
|
[_('too short: %{min} characters minimum') % {:min => my[:min]}]
|
15
15
|
else
|
data/lib/set/dynamic.rb
CHANGED
data/lib/set/static.rb
CHANGED
@@ -11,7 +11,7 @@ class Runo::Set::Static < Runo::Field
|
|
11
11
|
|
12
12
|
def initialize(meta = {})
|
13
13
|
@meta = meta
|
14
|
-
@meta.merge!(Runo::Parser.parse_html
|
14
|
+
@meta.merge!(Runo::Parser.parse_html(meta[:html])) if meta[:html]
|
15
15
|
@meta[:item] ||= {}
|
16
16
|
@item_object = {}
|
17
17
|
end
|
@@ -87,7 +87,7 @@ _html
|
|
87
87
|
def collect_item(conds = {}, &block)
|
88
88
|
items = my[:item].keys
|
89
89
|
items &= conds[:id].to_a if conds[:id] # select item(s) by id
|
90
|
-
items.collect {|id|
|
90
|
+
items.sort.collect {|id|
|
91
91
|
item = @item_object[id] ||= Runo::Field.instance(
|
92
92
|
my[:item][id].merge(:id => id, :parent => self)
|
93
93
|
)
|
data/lib/set/static_folder.rb
CHANGED
@@ -14,11 +14,11 @@ class Runo::Set::Static::Folder < Runo::Set::Static
|
|
14
14
|
meta[:html] = load_html(meta[:dir], meta[:parent])
|
15
15
|
super
|
16
16
|
|
17
|
-
::Dir.glob(::File.join
|
17
|
+
::Dir.glob(::File.join(Runo['skin_dir'], my[:html_dir].to_s, '*.html')).each {|f|
|
18
18
|
action = ::File.basename(f, '.*').intern
|
19
19
|
merge_tmpl(@meta, Runo::Parser.parse_html(::File.read(f), action)) if action != :index
|
20
20
|
}
|
21
|
-
::Dir.glob(::File.join
|
21
|
+
::Dir.glob(::File.join(Runo['skin_dir'], my[:html_dir].to_s, '*.xml')).each {|f|
|
22
22
|
action = ::File.basename(f, '.*').intern
|
23
23
|
merge_tmpl(@meta, Runo::Parser.parse_xml(::File.read(f), action)) if action != :index
|
24
24
|
}
|
@@ -59,7 +59,7 @@ class Runo::Set::Static::Folder < Runo::Set::Static
|
|
59
59
|
return sd.instance_eval { collect_item(conds, &block) }
|
60
60
|
elsif (
|
61
61
|
conds[:id] =~ /\A\w+\z/ &&
|
62
|
-
::File.directory?(::File.join
|
62
|
+
::File.directory?(::File.join(Runo['skin_dir'], my[:dir], conds[:id]))
|
63
63
|
)
|
64
64
|
my[:item][conds[:id]] = {:klass => 'set-static-folder'}
|
65
65
|
end
|
data/skel/skin/index.html
CHANGED
@@ -27,8 +27,6 @@
|
|
27
27
|
This is your homepage of the Runo app.<br />
|
28
28
|
You can play with <a href="./examples/">the examples</a> before making your first Runo app.
|
29
29
|
</p>
|
30
|
-
<div id="main" class="app-blog"></div>
|
31
|
-
<!-- $(main.action_create) -->
|
32
30
|
</div>
|
33
31
|
|
34
32
|
<div id="right" class="column">
|
data/t/test_runo.rb
CHANGED
@@ -350,6 +350,18 @@ class TC_Runo < Test::Unit::TestCase
|
|
350
350
|
"Runo::Path.base_of should return the item('main') if the given steps point at a folder"
|
351
351
|
)
|
352
352
|
|
353
|
+
sd = Runo::Path.base_of '/foo/qux/index.html'
|
354
|
+
assert_instance_of(
|
355
|
+
Runo::Set::Dynamic,
|
356
|
+
sd,
|
357
|
+
"Runo::Path.base_of should return an available set_dynamic if there is no 'main' in the folder"
|
358
|
+
)
|
359
|
+
assert_equal(
|
360
|
+
'-foo-qux-abc',
|
361
|
+
sd[:full_name],
|
362
|
+
"Runo::Path.base_of should return the first set_dynamic if there is no 'main' in the folder"
|
363
|
+
)
|
364
|
+
|
353
365
|
sd = Runo::Path.base_of '/foo/bar/20091120_0001/comment/index.html'
|
354
366
|
assert_instance_of(
|
355
367
|
Runo::Text,
|
@@ -376,6 +388,20 @@ class TC_Runo < Test::Unit::TestCase
|
|
376
388
|
)
|
377
389
|
end
|
378
390
|
|
391
|
+
def test_base_of_empty_folder
|
392
|
+
f = Runo::Path.base_of '/foo/qux/moo/index.html'
|
393
|
+
assert_instance_of(
|
394
|
+
Runo::Set::Static::Folder,
|
395
|
+
f,
|
396
|
+
'Runo::Path.base_of should return an folder if there is no SD in it'
|
397
|
+
)
|
398
|
+
assert_equal(
|
399
|
+
'-foo-qux-moo',
|
400
|
+
f[:full_name],
|
401
|
+
'Runo::Path.base_of should return an folder if there is no SD in it'
|
402
|
+
)
|
403
|
+
end
|
404
|
+
|
379
405
|
def test_path_of
|
380
406
|
assert_equal(
|
381
407
|
'20091224/123/',
|
data/t/test_runo_call.rb
CHANGED
@@ -1136,29 +1136,24 @@ _html
|
|
1136
1136
|
'Runo#call should return both the base path and tid at :done'
|
1137
1137
|
)
|
1138
1138
|
|
1139
|
-
|
1140
|
-
|
1139
|
+
location = res.headers['Location']
|
1140
|
+
location =~ Runo::REX::PATH_ID
|
1141
|
+
new_id = sprintf('%.8d_%.4d', $1, $2)
|
1141
1142
|
|
1142
|
-
res = Rack::MockRequest.new(@runo).get
|
1143
|
-
res.headers['Location']
|
1144
|
-
)
|
1143
|
+
res = Rack::MockRequest.new(@runo).get location
|
1145
1144
|
assert_match(
|
1146
1145
|
/created 1 entry\./,
|
1147
1146
|
res.body,
|
1148
1147
|
'Runo#call should include the current message'
|
1149
1148
|
)
|
1150
1149
|
|
1151
|
-
res = Rack::MockRequest.new(@runo).get
|
1152
|
-
"http://example.com/#{tid}/#{new_id}index.html"
|
1153
|
-
)
|
1150
|
+
res = Rack::MockRequest.new(@runo).get location
|
1154
1151
|
assert_no_match(
|
1155
1152
|
/created 1 entry\./,
|
1156
1153
|
res.body,
|
1157
1154
|
'Runo#call should not include the message twice'
|
1158
1155
|
)
|
1159
1156
|
|
1160
|
-
res.headers['Location'] =~ Runo::REX::PATH_ID
|
1161
|
-
new_id = sprintf('%.8d_%.4d', $1, $2)
|
1162
1157
|
res = Rack::MockRequest.new(@runo).post(
|
1163
1158
|
'http://example.com/t_store/main/update.html',
|
1164
1159
|
{
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 2
|
9
|
+
version: 0.1.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Akira FUNAI
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-07-
|
17
|
+
date: 2010-07-10 00:00:00 +09:00
|
18
18
|
default_executable: runo
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -247,6 +247,8 @@ files:
|
|
247
247
|
- t/skin/foo/index.html
|
248
248
|
- t/skin/foo/index.yaml
|
249
249
|
- t/skin/foo/not_css/foo.css
|
250
|
+
- t/skin/foo/qux/index.html
|
251
|
+
- t/skin/foo/qux/moo/index.html
|
250
252
|
- t/skin/foo/sub-20100306_0001.yaml
|
251
253
|
- t/skin/index.yaml
|
252
254
|
- t/skin/t_attachment/index.html
|