runo 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. data/README.rdoc +1 -118
  2. data/bin/runo +4 -29
  3. data/lib/dummy.rb +0 -0
  4. metadata +12 -278
  5. data/lib/_error.rb +0 -14
  6. data/lib/_field.rb +0 -260
  7. data/lib/_i18n.rb +0 -144
  8. data/lib/_parser.rb +0 -256
  9. data/lib/_path.rb +0 -86
  10. data/lib/_storage/_storage.rb +0 -215
  11. data/lib/_storage/file.rb +0 -201
  12. data/lib/_storage/sequel.rb +0 -174
  13. data/lib/_storage/temp.rb +0 -73
  14. data/lib/_widget/action_create.rb +0 -23
  15. data/lib/_widget/action_login.rb +0 -22
  16. data/lib/_widget/action_signup.rb +0 -16
  17. data/lib/_widget/action_update.rb +0 -16
  18. data/lib/_widget/crumb.rb +0 -24
  19. data/lib/_widget/done.rb +0 -16
  20. data/lib/_widget/login.rb +0 -25
  21. data/lib/_widget/me.rb +0 -31
  22. data/lib/_widget/message.rb +0 -51
  23. data/lib/_widget/navi.rb +0 -88
  24. data/lib/_widget/submit.rb +0 -49
  25. data/lib/_widget/view_ym.rb +0 -77
  26. data/lib/_workflow/_workflow.rb +0 -89
  27. data/lib/_workflow/attachment.rb +0 -50
  28. data/lib/_workflow/blog.rb +0 -28
  29. data/lib/_workflow/contact.rb +0 -23
  30. data/lib/_workflow/forum.rb +0 -26
  31. data/lib/_workflow/register.rb +0 -39
  32. data/lib/meta/_meta.rb +0 -20
  33. data/lib/meta/group.rb +0 -19
  34. data/lib/meta/id.rb +0 -59
  35. data/lib/meta/owner.rb +0 -21
  36. data/lib/meta/timestamp.rb +0 -118
  37. data/lib/runo.rb +0 -396
  38. data/lib/scalar/checkbox.rb +0 -68
  39. data/lib/scalar/file.rb +0 -144
  40. data/lib/scalar/img.rb +0 -112
  41. data/lib/scalar/password.rb +0 -58
  42. data/lib/scalar/radio.rb +0 -47
  43. data/lib/scalar/select.rb +0 -47
  44. data/lib/scalar/text.rb +0 -38
  45. data/lib/scalar/textarea.rb +0 -35
  46. data/lib/scalar/textarea_pre.rb +0 -14
  47. data/lib/scalar/textarea_wiki.rb +0 -173
  48. data/lib/set/_set.rb +0 -196
  49. data/lib/set/dynamic.rb +0 -177
  50. data/lib/set/static.rb +0 -102
  51. data/lib/set/static_folder.rb +0 -96
  52. data/locale/en/index.po +0 -242
  53. data/locale/index.pot +0 -243
  54. data/locale/ja/index.po +0 -242
  55. data/locale/lazy_parser.rb +0 -54
  56. data/skel/config.ru +0 -27
  57. data/skel/skin/_users/00000000_frank-avatar.jpg +0 -0
  58. data/skel/skin/_users/00000000_frank-avatar_small.jpg +0 -0
  59. data/skel/skin/_users/00000000_frank.yaml +0 -12
  60. data/skel/skin/_users/00000000_root-avatar.jpg +0 -0
  61. data/skel/skin/_users/00000000_root-avatar_small.jpg +0 -0
  62. data/skel/skin/_users/00000000_root.yaml +0 -11
  63. data/skel/skin/_users/css/users.css +0 -21
  64. data/skel/skin/_users/css/users.less +0 -25
  65. data/skel/skin/_users/done.html +0 -42
  66. data/skel/skin/_users/index.html +0 -46
  67. data/skel/skin/_users/index.yaml +0 -3
  68. data/skel/skin/_users/summary.html +0 -40
  69. data/skel/skin/css/base.css +0 -93
  70. data/skel/skin/css/base.less +0 -139
  71. data/skel/skin/css/coax.css +0 -199
  72. data/skel/skin/css/coax.less +0 -244
  73. data/skel/skin/examples/blog/20091214_0001.yaml +0 -8
  74. data/skel/skin/examples/blog/20100630_0001.yaml +0 -8
  75. data/skel/skin/examples/blog/20100630_0002.yaml +0 -14
  76. data/skel/skin/examples/blog/20100701_0001.yaml +0 -8
  77. data/skel/skin/examples/blog/20100701_0002-a-20100701_0001-f.jpg +0 -0
  78. data/skel/skin/examples/blog/20100701_0002-a-20100701_0001-f_small.jpg +0 -0
  79. data/skel/skin/examples/blog/20100701_0002.yaml +0 -19
  80. data/skel/skin/examples/blog/frank/20100701_0001.yaml +0 -10
  81. data/skel/skin/examples/blog/frank/index.yaml +0 -4
  82. data/skel/skin/examples/blog/index.html +0 -51
  83. data/skel/skin/examples/blog/rss.xml +0 -18
  84. data/skel/skin/examples/contact/20100701_0001-file.txt +0 -1
  85. data/skel/skin/examples/contact/20100701_0001.yaml +0 -15
  86. data/skel/skin/examples/contact/20100701_0002.yaml +0 -8
  87. data/skel/skin/examples/contact/20100701_0003.yaml +0 -9
  88. data/skel/skin/examples/contact/index.html +0 -47
  89. data/skel/skin/examples/contact/js/contact.js +0 -13
  90. data/skel/skin/examples/contact/summary.html +0 -54
  91. data/skel/skin/examples/forum/20100701_0001.yaml +0 -41
  92. data/skel/skin/examples/forum/20100701_0002.yaml +0 -25
  93. data/skel/skin/examples/forum/index.html +0 -68
  94. data/skel/skin/examples/forum/summary.html +0 -47
  95. data/skel/skin/examples/index.html +0 -73
  96. data/skel/skin/index.html +0 -39
  97. data/skel/skin/js/base.js +0 -50
  98. data/t/locale/de/index.po +0 -19
  99. data/t/locale/en-GB/index.po +0 -25
  100. data/t/locale/ja/index.po +0 -30
  101. data/t/skin/_users/00000000_test.yaml +0 -3
  102. data/t/skin/_users/index.html +0 -13
  103. data/t/skin/foo/20091120_0001.yaml +0 -7
  104. data/t/skin/foo/bar/20091120_0001.yaml +0 -5
  105. data/t/skin/foo/bar/index.yaml +0 -5
  106. data/t/skin/foo/baz/css/baz.css +0 -1
  107. data/t/skin/foo/css/foo.css +0 -1
  108. data/t/skin/foo/index.html +0 -14
  109. data/t/skin/foo/index.yaml +0 -7
  110. data/t/skin/foo/not_css/foo.css +0 -1
  111. data/t/skin/foo/qux/index.html +0 -8
  112. data/t/skin/foo/qux/moo/index.html +0 -6
  113. data/t/skin/foo/sub-20100306_0001.yaml +0 -3
  114. data/t/skin/index.yaml +0 -3
  115. data/t/skin/t_attachment/index.html +0 -13
  116. data/t/skin/t_contact/done.html +0 -6
  117. data/t/skin/t_contact/index.html +0 -9
  118. data/t/skin/t_file/index.html +0 -16
  119. data/t/skin/t_img/index.html +0 -14
  120. data/t/skin/t_img/test.jpg +0 -0
  121. data/t/skin/t_select/index.html +0 -9
  122. data/t/skin/t_store/index.html +0 -9
  123. data/t/skin/t_summary/20100326_0001.yaml +0 -3
  124. data/t/skin/t_summary/create.html +0 -9
  125. data/t/skin/t_summary/index.html +0 -9
  126. data/t/skin/t_summary/summary.html +0 -9
  127. data/t/t.rb +0 -27
  128. data/t/test_checkbox.rb +0 -273
  129. data/t/test_field.rb +0 -330
  130. data/t/test_file.rb +0 -900
  131. data/t/test_id.rb +0 -215
  132. data/t/test_img.rb +0 -328
  133. data/t/test_meta.rb +0 -57
  134. data/t/test_parser.rb +0 -1516
  135. data/t/test_password.rb +0 -188
  136. data/t/test_radio.rb +0 -226
  137. data/t/test_role.rb +0 -249
  138. data/t/test_runo.rb +0 -768
  139. data/t/test_runo_call.rb +0 -1281
  140. data/t/test_runo_i18n.rb +0 -325
  141. data/t/test_select.rb +0 -182
  142. data/t/test_set_complex.rb +0 -527
  143. data/t/test_set_dynamic.rb +0 -1504
  144. data/t/test_set_folder.rb +0 -515
  145. data/t/test_set_permit.rb +0 -246
  146. data/t/test_set_static.rb +0 -468
  147. data/t/test_storage.rb +0 -915
  148. data/t/test_text.rb +0 -125
  149. data/t/test_textarea.rb +0 -138
  150. data/t/test_timestamp.rb +0 -473
  151. data/t/test_workflow.rb +0 -367
@@ -1,20 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- # Author:: Akira FUNAI
4
- # Copyright:: Copyright (c) 2009 Akira FUNAI
5
-
6
- module Runo::Meta
7
-
8
- def post(action, v = nil)
9
- super
10
- my[:parent][klass_id] = val if my[:parent]
11
- self
12
- end
13
-
14
- private
15
-
16
- def klass_id
17
- self.class.to_s[/\w+$/].downcase.intern
18
- end
19
-
20
- end
@@ -1,19 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- # Author:: Akira FUNAI
4
- # Copyright:: Copyright (c) 2009 Akira FUNAI
5
-
6
- class Runo::Meta::Group < Runo::Field
7
-
8
- include Runo::Meta
9
-
10
- private
11
-
12
- def _post(action, v)
13
- if action == :load
14
- @val = val_cast v
15
- end
16
- nil
17
- end
18
-
19
- end
@@ -1,59 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- # Author:: Akira FUNAI
4
- # Copyright:: Copyright (c) 2009-2010 Akira FUNAI
5
-
6
- class Runo::Meta::Id < Runo::Field
7
-
8
- # not include Runo::Meta as this is SHORT_ID, not a full id.
9
-
10
- def initialize(meta = {})
11
- meta[:size] = $&.to_i if meta[:tokens] && meta[:tokens].first =~ /^\d+$/
12
- super
13
- end
14
-
15
- def errors
16
- if (my[:max].to_i > 0) && (val.size > my[:max])
17
- [_('too long: %{max} characters maximum') % {:max => my[:max]}]
18
- elsif (my[:min].to_i == 1) && val.empty?
19
- [_('mandatory')]
20
- elsif (my[:min].to_i > 0) && (val.size < my[:min])
21
- [_('too short: %{min} characters minimum') % {:min => my[:min]}]
22
- elsif val !~ /\A#{Runo::REX::ID_SHORT}\z/
23
- [_('malformatted id')]
24
- elsif (
25
- my[:parent] &&
26
- my[:parent][:id] !~ /00000000_#{val}$/ &&
27
- my[:parent][:parent].is_a?(Runo::Set::Dynamic) &&
28
- my[:parent][:parent].item(val)
29
- )
30
- [_('duplicate id: %{id}') % {:id => val}]
31
- else
32
- []
33
- end
34
- end
35
-
36
- private
37
-
38
- def _g_create(arg)
39
- new_id? ? <<_html.chomp : _g_default(arg)
40
- <span class="#{_g_class arg}"><input type="text" name="#{my[:short_name]}" value="#{Runo::Field.h val}" size="#{my[:size]}" />#{_g_errors arg}</span>
41
- _html
42
- end
43
- alias :_g_update :_g_create
44
-
45
- def new_id?
46
- find_ancestor {|i| i[:id] =~ Runo::REX::ID_NEW } ? true : false
47
- end
48
-
49
- def _post(action, v)
50
- if action == :load || ([:create, :update].include?(action) && new_id?)
51
- @val = val_cast v
52
- end
53
- end
54
-
55
- def val_cast(v)
56
- v.to_s
57
- end
58
-
59
- end
@@ -1,21 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- # Author:: Akira FUNAI
4
- # Copyright:: Copyright (c) 2009 Akira FUNAI
5
-
6
- class Runo::Meta::Owner < Runo::Field
7
-
8
- include Runo::Meta
9
-
10
- private
11
-
12
- def _post(action, v)
13
- if action == :load
14
- @val = val_cast v
15
- elsif action == :create
16
- @val = Runo.client
17
- end
18
- nil
19
- end
20
-
21
- end
@@ -1,118 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- # Author:: Akira FUNAI
4
- # Copyright:: Copyright (c) 2009 Akira FUNAI
5
-
6
- require 'time'
7
-
8
- class Runo::Meta::Timestamp < Runo::Field
9
-
10
- include Runo::Meta
11
-
12
- REX_DATE = /\A(\d+).(\d+).(\d+)(?:[T\s](\d+):(\d+)(?::(\d+))?)?\z/
13
-
14
- def initialize(meta = {})
15
- meta[:size] = $&.to_i if meta[:tokens] && meta[:tokens].find {|t| t =~ /^\d+$/ }
16
- meta[:can_edit] = true if Array(meta[:tokens]).include? 'can_edit'
17
- meta[:can_update] = true if Array(meta[:tokens]).include? 'can_update'
18
- super
19
- end
20
-
21
- def errors
22
- if @date_str.nil?
23
- []
24
- elsif @date_str =~ REX_DATE
25
- (Time.local($1, $2, $3, $4, $5, $6) rescue nil) ? [] : ['out of range']
26
- else
27
- ['wrong format']
28
- end
29
- end
30
-
31
- private
32
-
33
- def _g_default(arg)
34
- _date val['published']
35
- end
36
- alias :_g_published :_g_default
37
-
38
- def _g_rfc2822(arg)
39
- val['published'].rfc2822
40
- end
41
-
42
- def _g_created(arg)
43
- _date val['created']
44
- end
45
-
46
- def _g_updated(arg)
47
- _date val['updated']
48
- end
49
-
50
- def _date(time)
51
- time.is_a?(::Time) ? time.strftime(_('%Y-%m-%dT%H:%M:%S')) : 'n/a'
52
- end
53
-
54
- def _g_create(arg)
55
- <<_html.chomp if my[:can_edit]
56
- <span class="#{_g_class arg}"><input type="text" name="#{my[:short_name]}" value="" size="#{my[:size]}" /></span>
57
- _html
58
- end
59
-
60
- def _g_update(arg)
61
- if my[:can_edit]
62
- v = @date_str
63
- v ||= val['published'].is_a?(::Time) ? val['published'].strftime('%Y-%m-%d %H:%M:%S') : ''
64
- <<_html.chomp
65
- <span class="#{_g_class arg}"><input type="text" name="#{my[:short_name]}" value="#{Runo::Field.h v}" size="#{my[:size]}" />#{_g_errors arg}</span>
66
- _html
67
- elsif my[:can_update] && !find_ancestor {|f| f[:id] =~ Runo::REX::ID_NEW }
68
- <<_html
69
- <span class="#{_g_class arg}">
70
- <input type="checkbox" id="timestamp_#{my[:short_name]}" name="#{my[:short_name]}" value="true" />
71
- <label for="timestamp_#{my[:short_name]}">#{_ 'update the timestamp'}</label>
72
- #{_g_errors arg}</span>
73
- _html
74
- end
75
- end
76
-
77
- def _post(action, v)
78
- case action
79
- when :load
80
- @val = val_cast v
81
- when :create
82
- now = Time.now
83
- @val = {
84
- 'created' => now,
85
- 'updated' => now,
86
- 'published' => now,
87
- }
88
- if my[:can_edit] && v['published'].is_a?(::Time)
89
- @val['published'] = v['published']
90
- else
91
- nil # do not set @action
92
- end
93
- when :update
94
- @val['updated'] = Time.now
95
- if my[:can_edit] && v['published'].is_a?(::Time)
96
- @val['published'] = v['published']
97
- elsif my[:can_update] && v['published'] == :same_as_updated
98
- @val['published'] = @val['updated']
99
- else
100
- nil # do not set @action
101
- end
102
- end
103
- end
104
-
105
- def val_cast(v)
106
- if v.is_a? ::Hash
107
- v
108
- elsif v == 'true'
109
- {'published' => :same_as_updated}
110
- elsif v.is_a?(::String) && !v.empty?
111
- @date_str = v
112
- (v =~ REX_DATE && t = (Time.local($1, $2, $3, $4, $5, $6) rescue nil)) ? {'published' => t} : {}
113
- else
114
- {}
115
- end
116
- end
117
-
118
- end
@@ -1,396 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- # Author:: Akira FUNAI
4
- # Copyright:: Copyright (c) 2009 Akira FUNAI
5
-
6
- class Runo
7
-
8
- lib_dir = ::File.dirname __FILE__
9
-
10
- require "#{lib_dir}/_i18n.rb"
11
- I18n.bindtextdomain('index', ::File.expand_path('../locale', lib_dir))
12
-
13
- Dir["#{lib_dir}/_*.rb"].sort.each {|file| require file }
14
- Dir["#{lib_dir}/[a-z]*/*.rb"].sort.each {|file| require file }
15
- Dir["#{lib_dir}/_*/*.rb"].sort.each {|file| require file }
16
-
17
- module REX
18
- ID_SHORT = /[a-z][a-z0-9]*/
19
- ID = /^(\d{8})_(\d{4,}|#{ID_SHORT})/
20
- ID_NEW = /^_\d/
21
- COND = /^(.+?)=(.+)$/
22
- COND_D = /^(19\d\d|2\d\d\d|9999)\d{0,4}$/
23
- PATH_ID = /\/((?:19|2\d)\d{6})\/(\d+)/
24
- TID = /\d{10}\.\d+/
25
- DIR_STATIC = /css|js|img|imgs|image|images/
26
- end
27
-
28
- def self.config(config)
29
- @config = config
30
- end
31
-
32
- def self.[](name)
33
- @config ||= {}
34
- @config[name]
35
- end
36
-
37
- def self.current
38
- Thread.current
39
- end
40
-
41
- def self.session
42
- self.current[:session] || ($fake_session ||= {})
43
- end
44
-
45
- def self.transaction
46
- self.session[:transaction] ||= {}
47
- end
48
-
49
- def self.client
50
- self.session[:client] ||= 'nobody'
51
- end
52
-
53
- def self.client=(id)
54
- self.session[:client] = id
55
- end
56
-
57
- def self.token
58
- self.session[:token] ||= rand(36 ** 32).to_s(36)
59
- end
60
-
61
- def self.base
62
- self.current[:base]
63
- end
64
-
65
- def self.uri
66
- self.current[:uri]
67
- end
68
-
69
- def self.libdir
70
- ::File.dirname __FILE__
71
- end
72
-
73
- def self.static(env)
74
- @static ||= Rack::Directory.new Runo['skin_dir']
75
- response = @static.call env
76
-
77
- if response.first == 404
78
- until ::File.readable? ::File.join(
79
- Runo['skin_dir'],
80
- env['PATH_INFO'].sub(%r{(/#{Runo::REX::DIR_STATIC}/).*}, '\\1')
81
- )
82
- env['PATH_INFO'].sub!(%r{/[^/]+(?=/#{Runo::REX::DIR_STATIC}/)}, '') || break
83
- end
84
- @static.call env
85
- else
86
- response
87
- end
88
- end
89
-
90
- def call(env)
91
- uri = "#{env['rack.url_scheme']}://#{env['HTTP_HOST']}#{env['SCRIPT_NAME']}"
92
- req = Rack::Request.new env
93
- method = req.request_method.downcase
94
- params = params_from_request req
95
- path = req.path_info
96
- tid = Runo::Path.tid_of path
97
-
98
- static_path = ::File.expand_path path
99
- return Runo.static(env) if (
100
- static_path =~ %r{/#{Runo::REX::DIR_STATIC}/} &&
101
- static_path !~ %r{/#{Runo::REX::TID}/} &&
102
- static_path !~ %r{/#{Runo::REX::ID.to_s.sub('^','')}/}
103
- )
104
-
105
- Runo::I18n.lang = env['HTTP_ACCEPT_LANGUAGE']
106
-
107
- Runo.current[:env] = env
108
- Runo.current[:uri] = uri
109
- Runo.current[:req] = req
110
- Runo.current[:session] = env['rack.session']
111
-
112
- if Runo.transaction[tid].is_a? Runo::Field
113
- base = Runo.transaction[tid].item Runo::Path.steps_of(path.sub(/\A.*#{Runo::REX::TID}/, ''))
114
- else
115
- base = Runo::Path.base_of path
116
- end
117
- return response_not_found unless base
118
-
119
- base[:tid] = tid
120
- Runo.current[:base] = base
121
-
122
- begin
123
- if params[:action] == :logout && params[:token] == Runo.token
124
- logout(base, params)
125
- elsif method == 'get'
126
- get(base, params)
127
- elsif params[:action] == :login
128
- login(base, params)
129
- elsif params[:action] == :preview
130
- preview(base, params)
131
- elsif params[:token] != Runo.token
132
- response_forbidden(:body => 'invalid token')
133
- elsif Runo.transaction[tid] && !Runo.transaction[tid].is_a?(Runo::Field)
134
- response_unprocessable_entity(:body => 'transaction expired')
135
- else
136
- begin
137
- post(base, params)
138
- rescue Runo::Error::Forbidden
139
- response_forbidden
140
- end
141
- end
142
- rescue Runo::Error::Forbidden
143
- if params[:action] && Runo.client == 'nobody'
144
- params[:dest_action] = (method == 'post') ? :index : params[:action]
145
- params[:action] = :login
146
- end
147
- response_unprocessable_entity(:body => _get(base, params)) rescue response_forbidden
148
- # TODO: rescue Error::System etc.
149
- end
150
- end
151
-
152
- private
153
-
154
- def login(base, params)
155
- user = Runo::Set::Static::Folder.root.item('_users', 'main', params['id'].to_s)
156
- if user && params['pw'].to_s.crypt(user.val('password')) == user.val('password')
157
- Runo.client = params['id']
158
- else
159
- Runo.client = nil
160
- raise Runo::Error::Forbidden
161
- end
162
- path = Runo::Path.path_of params[:conds]
163
- action = (params['dest_action'] =~ /\A\w+\z/) ? params['dest_action'] : 'index'
164
- response_see_other(
165
- :location => "#{Runo.uri}#{base[:path]}/#{path}#{action}.html"
166
- )
167
- end
168
-
169
- def logout(base, params)
170
- Runo.client = nil
171
- path = Runo::Path.path_of params[:conds]
172
- response_see_other(
173
- :location => "#{Runo.uri}#{base[:path]}/#{path}index.html"
174
- )
175
- end
176
-
177
- def get(base, params)
178
- if base.is_a? Runo::File
179
- body = (params[:sub_action] == :small) ? base.thumbnail : base.body
180
- response_ok(
181
- :headers => {
182
- 'Content-Type' => base.val['type'],
183
- 'Content-Length' => body.to_s.size.to_s,
184
- },
185
- :body => body
186
- )
187
- else
188
- response_ok :body => _get(base, params)
189
- end
190
- end
191
-
192
- def preview(base, params)
193
- Runo.transaction[base[:tid]] ||= base if base[:tid] =~ Runo::REX::TID
194
-
195
- base.update params
196
- if base.commit(:temp) || params[:sub_action] == :delete
197
- id_step = result_step(base, params)
198
- action = "preview_#{params[:sub_action]}"
199
- response_see_other(
200
- :location => "#{Runo.uri}/#{base[:tid]}/#{id_step}#{action}.html"
201
- )
202
- else
203
- params = {:action => :update}
204
- params[:conds] = {:id => base.errors.keys}
205
- return response_unprocessable_entity(:body => _get(base, params))
206
- end
207
- end
208
-
209
- def post(base, params)
210
- Runo.transaction[base[:tid]] ||= base if base[:tid] =~ Runo::REX::TID
211
-
212
- base.update params
213
- if params[:status]
214
- if base[:folder].commit :persistent
215
- Runo.transaction[base[:tid]] = result_summary base
216
- action = base.workflow.next_action base
217
- id_step = result_step(base, params) if base[:parent] == base[:folder] && action != :done
218
- response_see_other(
219
- :location => "#{Runo.uri}/#{base[:tid]}#{base[:path]}/#{id_step}#{action}.html"
220
- )
221
- else
222
- params = {:action => :update}
223
- params[:conds] = {:id => base.errors.keys}
224
- response_unprocessable_entity :body => _get(base, params)
225
- end
226
- else
227
- base.commit :temp
228
- id_step = result_step(base, params)
229
- response_see_other(
230
- :location => "#{Runo.uri}/#{base[:tid]}/#{id_step}update.html"
231
- )
232
- end
233
- end
234
-
235
- def result_summary(base)
236
- (base.result || {}).values.inject({}) {|summary, item|
237
- item_result = item.result.is_a?(::Symbol) ? item.result : :update
238
- summary[item_result] = summary[item_result].to_i + 1
239
- summary
240
- }
241
- end
242
-
243
- def result_step(base, params)
244
- if base.result
245
- id = base.result.values.collect {|item| item[:id] }
246
- else
247
- id = params.keys.select {|id|
248
- id.is_a?(::String) && (id[Runo::REX::ID] || id[Runo::REX::ID_NEW])
249
- }
250
- end
251
- Runo::Path.path_of(:id => id)
252
- end
253
-
254
- def _get(f, params)
255
- params[:action] ||= f.default_action
256
- until f.is_a? Runo::Set::Static::Folder
257
- params = {
258
- :action => (f.default_action == :read) ? :read : nil,
259
- :sub_action => f.send(:summary?, params) ? nil : (params[:sub_action] || :detail),
260
- f[:id] => params,
261
- }
262
- params[:conds] = {:id => f[:id]} if f[:parent].is_a? Runo::Set::Dynamic
263
- f = f[:parent]
264
- end if f.is_a? Runo::Set::Dynamic
265
-
266
- f.get params
267
- end
268
-
269
- def params_from_request(req)
270
- params = {
271
- :action => Runo::Path.action_of(req.path_info),
272
- :sub_action => Runo::Path.sub_action_of(req.path_info),
273
- }
274
- params.merge! rebuild_params(req.params)
275
-
276
- params[:conds] ||= {}
277
- params[:conds].merge! Runo::Path.conds_of(req.path_info)
278
-
279
- params
280
- end
281
-
282
- def rebuild_params(src)
283
- src.keys.sort.reverse.inject({}) {|params, key|
284
- name, special = key.split('.', 2)
285
- steps = name.split '-'
286
-
287
- if special
288
- special_id, special_val = special.split('-', 2)
289
- else
290
- item_id = steps.pop
291
- end
292
-
293
- hash = steps.inject(params) {|v, k| v[k] ||= {} }
294
- val = src[key]
295
-
296
- if special_id == 'action'
297
- action, sub_action = (special_val || val).split('_', 2)
298
- hash[:action] = action.intern
299
- hash[:sub_action] = sub_action.intern if sub_action
300
- elsif special_id == 'status'
301
- hash[:status] = (special_val || val).intern
302
- elsif special_id == 'conds'
303
- hash[:conds] ||= {}
304
- hash[:conds][special_val.intern] = val
305
- elsif hash[item_id].is_a? ::Hash
306
- hash[item_id][:self] = val
307
- elsif item_id == '_token'
308
- hash[:token] = val
309
- else
310
- hash[item_id] = val
311
- end
312
-
313
- params
314
- }
315
- end
316
-
317
- def response_ok(result = {})
318
- body = result[:body].to_s
319
- return response_not_found(result) if body.empty?
320
- [
321
- 200,
322
- (
323
- result[:headers] ||
324
- {
325
- 'Content-Type' => 'text/html',
326
- 'Content-Length' => body.size.to_s,
327
- }
328
- ),
329
- [body],
330
- ]
331
- end
332
-
333
- def response_no_content(result = {})
334
- [
335
- 204,
336
- (result[:headers] || {}),
337
- []
338
- ]
339
- end
340
-
341
- def response_see_other(result = {})
342
- body = <<_html
343
- <a href="#{result[:location]}">see other</a>
344
- _html
345
- [
346
- 303,
347
- {
348
- 'Content-Type' => 'text/html',
349
- 'Content-Length' => body.size.to_s,
350
- 'Location' => result[:location],
351
- },
352
- [body]
353
- ]
354
- end
355
-
356
- def response_forbidden(result = {})
357
- body = result[:body] || 'Forbidden'
358
- [
359
- 403,
360
- {
361
- 'Content-Type' => 'text/html',
362
- 'Content-Length' => body.size.to_s,
363
- },
364
- [body],
365
- ]
366
- end
367
-
368
- def response_not_found(result = {})
369
- body = result[:body] || 'Not Found'
370
- [
371
- 404,
372
- {
373
- 'Content-Type' => 'text/html',
374
- 'Content-Length' => body.size.to_s,
375
- },
376
- [body]
377
- ]
378
- end
379
-
380
- def response_unprocessable_entity(result = {})
381
- body = result[:body].to_s
382
- return response_not_found(result) if body.empty?
383
- [
384
- 422,
385
- (
386
- result[:headers] ||
387
- {
388
- 'Content-Type' => 'text/html',
389
- 'Content-Length' => body.size.to_s,
390
- }
391
- ),
392
- [body],
393
- ]
394
- end
395
-
396
- end