dao 4.4.4 → 4.6.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README +2 -0
- data/dao.gemspec +9 -6
- data/lib/dao.rb +20 -11
- data/lib/dao/api/call.rb +1 -1
- data/lib/dao/conducer.rb +152 -106
- data/lib/dao/conducer/active_model.rb +8 -1
- data/lib/dao/conducer/collection.rb +4 -0
- data/lib/dao/conducer/controller_support.rb +8 -4
- data/lib/dao/conducer/nav_support.rb +2 -1
- data/lib/dao/conducer/view_support.rb +8 -4
- data/lib/dao/errors.rb +114 -48
- data/lib/dao/form.rb +113 -91
- data/lib/dao/rails.rb +4 -0
- data/lib/dao/rails/lib/generators/dao/templates/dao.css +11 -21
- data/lib/dao/rails/lib/generators/dao/templates/dao_helper.rb +17 -43
- data/lib/dao/route.rb +4 -3
- data/lib/dao/upload.rb +27 -5
- data/lib/dao/validations.rb +0 -1
- data/lib/dao/validations/validator.rb +5 -1
- data/test/conducer_test.rb +56 -9
- data/test/errors_test.rb +81 -0
- data/test/form_test.rb +123 -0
- data/test/helper.rb +11 -0
- data/test/support_test.rb +0 -1
- data/test/validations_test.rb +29 -8
- metadata +96 -28
@@ -35,7 +35,14 @@ module Dao
|
|
35
35
|
|
36
36
|
def default_model_name
|
37
37
|
return model_name_for('Conducer') if self == Dao::Conducer
|
38
|
-
|
38
|
+
|
39
|
+
suffixes = /(Conducer|Resource|Importer|Presenter|Conductor|Cell)\Z/o
|
40
|
+
|
41
|
+
name = self.name.to_s
|
42
|
+
name.sub!(suffixes, '') unless name.sub(suffixes, '').blank?
|
43
|
+
name.sub!(/(:|_)+$/, '')
|
44
|
+
|
45
|
+
model_name_for(name)
|
39
46
|
end
|
40
47
|
|
41
48
|
def collection_name
|
@@ -18,10 +18,14 @@ module Dao
|
|
18
18
|
def set_controller(controller)
|
19
19
|
@controller = controller
|
20
20
|
ensure
|
21
|
-
default_url_options
|
22
|
-
|
23
|
-
|
24
|
-
@action = Action.new(@controller.send(:action_name).to_s, self)
|
21
|
+
if defined?(default_url_options)
|
22
|
+
[:protocol, :host, :port].each{|attr| default_url_options[attr] = @controller.request.send(attr)}
|
23
|
+
end
|
24
|
+
@action = Action.new((@controller.send(:action_name) || :index).to_s, self)
|
25
|
+
end
|
26
|
+
|
27
|
+
def request
|
28
|
+
@controller.send(:request) if @controller
|
25
29
|
end
|
26
30
|
|
27
31
|
##
|
@@ -6,11 +6,15 @@ module Dao
|
|
6
6
|
|
7
7
|
class << Conducer
|
8
8
|
include Tagz.globally
|
9
|
-
end
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
def install_routes!
|
11
|
+
url_helpers = Rails.application.try(:routes).try(:url_helpers)
|
12
|
+
include(url_helpers) if url_helpers
|
13
|
+
include(ActionView::Helpers) if defined?(ActionView::Helpers)
|
14
|
+
extend(url_helpers) if url_helpers
|
15
|
+
extend(ActionView::Helpers) if defined?(ActionView::Helpers)
|
16
|
+
end
|
17
|
+
end
|
14
18
|
end
|
15
19
|
end
|
16
20
|
end
|
data/lib/dao/errors.rb
CHANGED
@@ -113,31 +113,21 @@ module Dao
|
|
113
113
|
alias_method('add_to_base', 'add')
|
114
114
|
alias_method('add_to_base!', 'add!')
|
115
115
|
|
116
|
-
def relay(
|
117
|
-
|
118
|
-
when other.respond_to?(:each)
|
119
|
-
other.each do |key, messages|
|
120
|
-
Array(messages).each do |message|
|
121
|
-
add(key, message, options = {})
|
122
|
-
end
|
123
|
-
end
|
124
|
-
when other.respond_to?(:each_pair)
|
125
|
-
other.each_pair do |key, messages|
|
126
|
-
Array(messages).each do |message|
|
127
|
-
add(key, message, options = {})
|
128
|
-
end
|
129
|
-
end
|
116
|
+
def relay(*args)
|
117
|
+
options = args.size > 1 ? Map.options_for!(args) : Map.new
|
130
118
|
|
131
|
-
|
132
|
-
Array(other).flatten.each_slice(2) do |key, messages|
|
133
|
-
Array(messages).each do |message|
|
134
|
-
add(key, message, options = {})
|
135
|
-
end
|
136
|
-
end
|
119
|
+
prefix = Array(options.delete(:prefix))
|
137
120
|
|
138
|
-
|
139
|
-
|
121
|
+
args.flatten.compact.each do |source|
|
122
|
+
errors = source.respond_to?(:errors) ? source.errors : source
|
123
|
+
|
124
|
+
errors.each do |*argv|
|
125
|
+
msgs = Array(argv.pop)
|
126
|
+
key = prefix + Array(argv.pop)
|
127
|
+
msgs.each{|msg| add(Array(options[:key] || key), msg, options)}
|
128
|
+
end
|
140
129
|
end
|
130
|
+
|
141
131
|
self
|
142
132
|
end
|
143
133
|
|
@@ -181,7 +171,9 @@ module Dao
|
|
181
171
|
index = keys.pop
|
182
172
|
key = keys
|
183
173
|
value = value.to_s
|
174
|
+
|
184
175
|
next if value.strip.empty?
|
176
|
+
|
185
177
|
if key == Global
|
186
178
|
global_messages.push([key, value])
|
187
179
|
else
|
@@ -200,6 +192,18 @@ module Dao
|
|
200
192
|
end
|
201
193
|
end
|
202
194
|
|
195
|
+
def flatten
|
196
|
+
hash = Hash.new
|
197
|
+
|
198
|
+
depth_first_each do |keys, value|
|
199
|
+
index = keys.pop
|
200
|
+
hash[keys] ||= []
|
201
|
+
hash[keys].push("#{ value }")
|
202
|
+
end
|
203
|
+
|
204
|
+
hash
|
205
|
+
end
|
206
|
+
|
203
207
|
def each_full_message
|
204
208
|
full_messages.each{|msg| yield msg}
|
205
209
|
end
|
@@ -212,6 +216,14 @@ module Dao
|
|
212
216
|
select{|message| not message.strip.empty?}
|
213
217
|
end
|
214
218
|
|
219
|
+
def global
|
220
|
+
reject{|k, v| k != Global}
|
221
|
+
end
|
222
|
+
|
223
|
+
def local
|
224
|
+
reject{|k, v| k == Global}
|
225
|
+
end
|
226
|
+
|
215
227
|
# html generation methods
|
216
228
|
#
|
217
229
|
def to_html(*args)
|
@@ -222,50 +234,104 @@ module Dao
|
|
222
234
|
if block
|
223
235
|
define_method(:to_html, &block)
|
224
236
|
else
|
225
|
-
|
237
|
+
errors_to_html(*args)
|
226
238
|
end
|
227
239
|
end
|
228
240
|
|
229
|
-
def Errors.
|
241
|
+
def Errors.errors_to_html(*args)
|
242
|
+
::Errors2Html.to_html(*args)
|
243
|
+
end
|
244
|
+
|
245
|
+
def to_s(format = :html, *args, &block)
|
246
|
+
case format.to_s
|
247
|
+
when /html/
|
248
|
+
to_html(*args, &block)
|
249
|
+
|
250
|
+
when /text/
|
251
|
+
to_text(*args, &block)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
class KeyPrefixer
|
256
|
+
attr_accessor :object
|
257
|
+
attr_accessor :prefix
|
258
|
+
attr_accessor :global
|
259
|
+
|
260
|
+
def initialize(object)
|
261
|
+
@object = object
|
262
|
+
|
263
|
+
@prefix =
|
264
|
+
if @object && @object.respond_to?(:model_name)
|
265
|
+
@object.model_name.underscore
|
266
|
+
else
|
267
|
+
nil
|
268
|
+
end
|
269
|
+
|
270
|
+
@global = Array(Global)
|
271
|
+
end
|
272
|
+
|
273
|
+
def prefix(key)
|
274
|
+
is_global_key = key == @global || Array(key) == @global
|
275
|
+
|
276
|
+
if @prefix
|
277
|
+
if is_global_key
|
278
|
+
@prefix
|
279
|
+
else
|
280
|
+
["#{ @prefix }.#{ key[0] }", *key[1..-1]]
|
281
|
+
end
|
282
|
+
else
|
283
|
+
if is_global_key
|
284
|
+
'global'
|
285
|
+
else
|
286
|
+
key
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def key_prefixer
|
293
|
+
@key_prefixer ||= KeyPrefixer.new(object)
|
294
|
+
end
|
295
|
+
|
296
|
+
def prefix_key(key)
|
297
|
+
key_prefixer.prefix(key)
|
298
|
+
end
|
299
|
+
|
300
|
+
def Errors.to_hash(*args)
|
230
301
|
error = args.shift
|
231
302
|
options = Map.options_for!(args)
|
232
303
|
errors = [error, *args].flatten.compact
|
233
304
|
|
234
|
-
|
235
|
-
|
236
|
-
emap = Map.new
|
305
|
+
map = Map.new
|
237
306
|
|
238
307
|
errors.each do |e|
|
239
308
|
e.full_messages.each do |key, message|
|
240
|
-
|
241
|
-
|
309
|
+
k = e.key_prefixer.prefix(key)
|
310
|
+
|
311
|
+
map.set(k, []) unless map.has?(k)
|
312
|
+
map.get(k).push("#{ message }")
|
242
313
|
end
|
243
314
|
end
|
244
315
|
|
245
|
-
|
246
|
-
|
247
|
-
div_(:class => "dao errors summary"){
|
248
|
-
__
|
249
|
-
|
250
|
-
h3_(:class => "caption"){ "We're so sorry, but can you please fix the following errors?" }
|
251
|
-
__
|
316
|
+
map.to_hash
|
317
|
+
end
|
252
318
|
|
253
|
-
|
254
|
-
|
255
|
-
|
319
|
+
def to_hash
|
320
|
+
Errors.to_hash(self)
|
321
|
+
end
|
256
322
|
|
257
|
-
|
323
|
+
def Errors.errors_to_text(*args)
|
324
|
+
hash = to_hash(*args)
|
258
325
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
}
|
326
|
+
if hash.empty?
|
327
|
+
nil
|
328
|
+
else
|
329
|
+
hash.to_yaml
|
330
|
+
end
|
265
331
|
end
|
266
332
|
|
267
|
-
def
|
268
|
-
|
333
|
+
def to_text
|
334
|
+
Errors.errors_to_text(self)
|
269
335
|
end
|
270
336
|
end
|
271
337
|
end
|
data/lib/dao/form.rb
CHANGED
@@ -11,9 +11,20 @@ module Dao
|
|
11
11
|
|
12
12
|
# builder stuff for compatibity with rails' form_for()
|
13
13
|
#
|
14
|
-
class Builder
|
14
|
+
class Builder < Form
|
15
15
|
def Builder.new(object_name, object, view, options, block)
|
16
|
-
|
16
|
+
if object.respond_to?(:form)
|
17
|
+
|
18
|
+
html = options[:html] || {}
|
19
|
+
html[:class] ||= 'dao'
|
20
|
+
unless html[:class] =~ /(\s|\A)dao(\Z|\s)/o
|
21
|
+
html[:class] << ' dao dao-form'
|
22
|
+
end
|
23
|
+
|
24
|
+
object.form
|
25
|
+
else
|
26
|
+
raise ArgumentError, object.class.name
|
27
|
+
end
|
17
28
|
end
|
18
29
|
end
|
19
30
|
|
@@ -69,14 +80,17 @@ module Dao
|
|
69
80
|
|
70
81
|
fattr(:name) do
|
71
82
|
name =
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
'
|
83
|
+
case
|
84
|
+
when @object.respond_to?(:form_name)
|
85
|
+
@object.form_name
|
86
|
+
when @object.respond_to?(:name)
|
87
|
+
@object.name
|
88
|
+
when @object.instance_variable_defined?('@form_name')
|
89
|
+
@object.instance_variable_get('@form_name')
|
90
|
+
when @object.instance_variable_defined?('@name')
|
91
|
+
@object.instance_variable_get('@name')
|
92
|
+
else
|
93
|
+
:form
|
80
94
|
end
|
81
95
|
|
82
96
|
case name
|
@@ -107,28 +121,24 @@ module Dao
|
|
107
121
|
end
|
108
122
|
end
|
109
123
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
if @object.respond_to?(:status)
|
114
|
-
throw :status, @object.status
|
115
|
-
end
|
116
|
-
if @object.instance_variable_defined?('@status')
|
117
|
-
throw :status, @object.instance_variable_get('@status')
|
118
|
-
end
|
119
|
-
Status.new
|
120
|
-
end
|
124
|
+
# support for rails' forms...
|
125
|
+
#
|
126
|
+
fattr(:multipart){ true }
|
121
127
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
+
%w( [] []= get set has has? ).each do |method|
|
129
|
+
class_eval <<-__
|
130
|
+
def #{ method }(*args, &block)
|
131
|
+
attributes.#{ method }(*args, &block)
|
132
|
+
end
|
133
|
+
__
|
128
134
|
end
|
129
135
|
|
130
136
|
# html generation methods
|
131
137
|
#
|
138
|
+
def element(which, *args, &block)
|
139
|
+
send(which, *args, &block)
|
140
|
+
end
|
141
|
+
|
132
142
|
def form(*args, &block)
|
133
143
|
options = args.extract_options!.to_options!
|
134
144
|
keys = args.flatten
|
@@ -153,11 +163,11 @@ module Dao
|
|
153
163
|
options = args.extract_options!.to_options!
|
154
164
|
keys = args.flatten
|
155
165
|
|
156
|
-
|
157
|
-
|
166
|
+
block ||=
|
167
|
+
proc do
|
168
|
+
options.delete(:content) ||
|
169
|
+
options.delete(:value) ||
|
158
170
|
keys.map{|key| key.to_s.titleize}.join(' ')
|
159
|
-
else
|
160
|
-
block ? block.call() : (options.delete(:content) || options.delete(:value))
|
161
171
|
end
|
162
172
|
|
163
173
|
id = options.delete(:id) || id_for(keys + [:label])
|
@@ -165,7 +175,7 @@ module Dao
|
|
165
175
|
error = error_for(keys, options.delete(:error))
|
166
176
|
target = options.delete(:for) || id_for(keys)
|
167
177
|
|
168
|
-
label_(options_for(options, :for => target, :class => klass, :id => id, :data_error => error))
|
178
|
+
label_(options_for(options, :for => target, :class => klass, :id => id, :data_error => error), &block)
|
169
179
|
end
|
170
180
|
|
171
181
|
def input(*args, &block)
|
@@ -210,14 +220,11 @@ module Dao
|
|
210
220
|
klass = class_for(keys, options.delete(:class))
|
211
221
|
error = error_for(keys, options.delete(:error))
|
212
222
|
|
213
|
-
value =
|
214
|
-
|
215
|
-
|
216
|
-
else
|
217
|
-
block ? block.call(attributes.get(keys)) : options.delete(:value)
|
218
|
-
end
|
223
|
+
value = options.has_key?(:value) ? options.delete(:value) : value_for(attributes, keys)
|
224
|
+
|
225
|
+
content = (block ? block.call : (options.delete(:content) || 'Submit'))
|
219
226
|
|
220
|
-
button_(options_for(options, :type => type, :name => name, :value => value, :class => klass, :id => id, :data_error => error)){}
|
227
|
+
button_(options_for(options, :type => type, :name => name, :value => value, :class => klass, :id => id, :data_error => error)){ content }
|
221
228
|
end
|
222
229
|
|
223
230
|
def radio_button(*args, &block)
|
@@ -257,7 +264,7 @@ module Dao
|
|
257
264
|
values = options.delete(:values) || options.delete(:checked)
|
258
265
|
|
259
266
|
unless options.has_key?(:checked)
|
260
|
-
checked =
|
267
|
+
checked = Coerce.boolean(attributes.get(keys))
|
261
268
|
options[:checked] = checked if checked
|
262
269
|
end
|
263
270
|
|
@@ -336,29 +343,22 @@ module Dao
|
|
336
343
|
keys = args.flatten
|
337
344
|
|
338
345
|
name = options.delete(:name) || name_for(keys)
|
339
|
-
|
340
|
-
blank = options.delete(:blank)
|
346
|
+
values = options.delete(:values) || options.delete(:options) || options.delete(:from)
|
341
347
|
|
342
|
-
|
343
|
-
|
344
|
-
options.delete(:selected)
|
345
|
-
else
|
346
|
-
value_for(attributes, keys)
|
347
|
-
end
|
348
|
+
has_blank = options.has_key?(:blank) && options[:blank] != false
|
349
|
+
blank = options.delete(:blank)
|
348
350
|
|
349
351
|
id = options.delete(:id) || id_for(keys)
|
350
352
|
klass = class_for(keys, options.delete(:class))
|
351
353
|
error = error_for(keys, options.delete(:error))
|
352
354
|
|
353
|
-
|
354
|
-
|
355
|
-
if from.nil?
|
355
|
+
if values.nil?
|
356
356
|
key = keys.map{|key| "#{ key }"}
|
357
357
|
key.last << "_options"
|
358
|
-
|
358
|
+
values = attributes.get(*key) if attributes.has?(*key)
|
359
359
|
end
|
360
360
|
|
361
|
-
list = Array(
|
361
|
+
list = Array(values).map{|value| value.dup rescue value} # ensure list is dup'd
|
362
362
|
|
363
363
|
case list.first
|
364
364
|
when Hash, Array
|
@@ -369,52 +369,68 @@ module Dao
|
|
369
369
|
list.map!{|element| [element, element]}
|
370
370
|
end
|
371
371
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
372
|
+
if has_blank
|
373
|
+
case blank
|
374
|
+
when false
|
375
|
+
blank = nil
|
376
|
+
when nil, true
|
377
|
+
blank = [nil, nil]
|
378
|
+
else
|
379
|
+
blank = [Array(blank).first, '']
|
380
|
+
end
|
379
381
|
end
|
380
382
|
|
381
383
|
selected_value =
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
key = [:id, 'id', :value, 'value'].detect{|k| selected.has_key?(k)}
|
387
|
-
key ? selected[key] : selected
|
388
|
-
else
|
389
|
-
selected
|
384
|
+
if options.has_key?(:selected)
|
385
|
+
options.delete(:selected)
|
386
|
+
else
|
387
|
+
value_for(attributes, keys)
|
390
388
|
end
|
391
389
|
|
392
390
|
select_(options_for(options, :name => name, :class => klass, :id => id, :data_error => error)){
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
content, value, selected, *ignored = returned
|
399
|
-
when Hash
|
400
|
-
content = returned[:content]
|
401
|
-
value = returned[:value]
|
402
|
-
selected = returned[:selected]
|
403
|
-
else
|
404
|
-
content = returned
|
405
|
-
value = returned
|
406
|
-
selected = nil
|
407
|
-
end
|
408
|
-
|
409
|
-
value ||= content
|
391
|
+
if blank
|
392
|
+
content = blank.first || ''
|
393
|
+
value = blank.last
|
394
|
+
value.nil? ? option_(){ content } : option_(:value => value){ content }
|
395
|
+
end
|
410
396
|
|
411
|
-
|
412
|
-
|
397
|
+
unless list.empty?
|
398
|
+
list.each do |pair|
|
399
|
+
returned = block ? Dao.call(block, :call, pair.first, pair.last, selected_value) : pair
|
400
|
+
|
401
|
+
opts = Map.new
|
402
|
+
selected = nil
|
403
|
+
|
404
|
+
case returned
|
405
|
+
when Array
|
406
|
+
content, value, selected, *ignored = returned
|
407
|
+
if value.is_a?(Hash)
|
408
|
+
map = Map.for(value)
|
409
|
+
value = map.delete(:value)
|
410
|
+
selected = map.delete(:selected)
|
411
|
+
opts.update(map)
|
412
|
+
end
|
413
|
+
|
414
|
+
when Hash
|
415
|
+
content = returned[:content]
|
416
|
+
value = returned[:value]
|
417
|
+
selected = returned[:selected]
|
418
|
+
|
419
|
+
else
|
420
|
+
content = returned
|
421
|
+
value = returned
|
422
|
+
selected = nil
|
423
|
+
end
|
424
|
+
|
425
|
+
if selected.nil?
|
426
|
+
selected = (value.to_s == selected_value.to_s)
|
427
|
+
end
|
428
|
+
|
429
|
+
opts[:value] = (value.nil? ? content : value)
|
430
|
+
opts[:selected] = Coerce.boolean(selected) if selected
|
431
|
+
|
432
|
+
option_(opts){ content }
|
413
433
|
end
|
414
|
-
|
415
|
-
opts = {:value => value}
|
416
|
-
opts[:selected] = !!selected if selected
|
417
|
-
option_(opts){ content }
|
418
434
|
end
|
419
435
|
}
|
420
436
|
end
|
@@ -521,6 +537,7 @@ module Dao
|
|
521
537
|
|
522
538
|
def options_for(*hashes)
|
523
539
|
map = Map.new
|
540
|
+
|
524
541
|
hashes.flatten.each do |h|
|
525
542
|
case((data = h.delete(:data) || h.delete('data')))
|
526
543
|
when Hash
|
@@ -533,6 +550,11 @@ module Dao
|
|
533
550
|
map[attr_for(k)] = v unless v.nil?
|
534
551
|
end
|
535
552
|
end
|
553
|
+
|
554
|
+
%w( readonly disabled autofocus checked multiple ).each do |attr|
|
555
|
+
map.delete(attr) unless Coerce.boolean(map[attr])
|
556
|
+
end
|
557
|
+
|
536
558
|
map
|
537
559
|
end
|
538
560
|
|