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
data/lib/dao/rails.rb
CHANGED
@@ -27,6 +27,10 @@ if defined?(Rails)
|
|
27
27
|
#initializer "dao.middleware" do |app|
|
28
28
|
#app.middleware.use Dao::Middleware::ParamsParser
|
29
29
|
#end
|
30
|
+
|
31
|
+
config.after_initialize do
|
32
|
+
Dao::Conducer.install_routes!
|
33
|
+
end
|
30
34
|
|
31
35
|
# yes yes, this should probably be somewhere else...
|
32
36
|
#
|
@@ -1,28 +1,18 @@
|
|
1
|
-
/* dao errors */
|
1
|
+
/* dao form errors */
|
2
2
|
|
3
|
-
.
|
4
|
-
|
3
|
+
.errors-summary {
|
4
|
+
box-sizing: border-box;
|
5
5
|
width: 100%;
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
height: auto;
|
7
|
+
color: #666;
|
8
|
+
background-color: #fffff6;
|
9
|
+
padding: 1em;
|
9
10
|
}
|
10
|
-
|
11
|
-
.dao.errors .caption {
|
11
|
+
.errors-caption {
|
12
12
|
font-weight: bold;
|
13
|
-
color: #333;
|
14
|
-
font-style: italic;
|
15
|
-
text-align: left;
|
16
|
-
margin-bottom: 0.5em;
|
17
13
|
}
|
18
|
-
|
19
|
-
.dao.errors .title {
|
20
|
-
padding-left: 1em;
|
21
|
-
color: #666;
|
14
|
+
.errors-title {
|
22
15
|
}
|
23
|
-
|
24
|
-
.dao.errors .message {
|
25
|
-
font-style: italic;
|
26
|
-
font-weight: bold;
|
27
|
-
width: 100%;
|
16
|
+
.errors-message {
|
28
17
|
}
|
18
|
+
|
@@ -1,52 +1,27 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
module DaoHelper
|
3
3
|
def dao_form_for(*args, &block)
|
4
|
-
|
5
|
-
|
6
|
-
model = args.flatten.detect{|arg| arg.respond_to?(:persisted?)}
|
7
|
-
|
8
|
-
if model
|
9
|
-
first = args.shift
|
10
|
-
url = args.shift || options.delete(:url)
|
4
|
+
model = args.flatten.select{|arg| arg.respond_to?(:persisted?)}.last
|
11
5
|
|
12
|
-
|
13
|
-
html = dao_form_attrs(options)
|
14
|
-
|
15
|
-
options.clear
|
6
|
+
options = args.extract_options!.to_options!
|
16
7
|
|
17
|
-
|
18
|
-
method ||= :put
|
19
|
-
else
|
20
|
-
method ||= :post
|
21
|
-
end
|
8
|
+
options[:builder] = Dao::Form::Builder
|
22
9
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
when :post
|
28
|
-
url_for(:action => :create)
|
29
|
-
else
|
30
|
-
'./'
|
31
|
-
end
|
10
|
+
if options[:post] or model.blank?
|
11
|
+
options[:url] ||= (options.delete(:post) || request.fullpath)
|
12
|
+
options[:method] ||= :post
|
13
|
+
end
|
32
14
|
|
33
|
-
|
34
|
-
options[:html] = html.dup.merge(:method => method)
|
35
|
-
#options[:builder] = Dao::Form::Builder
|
15
|
+
args.push(options)
|
36
16
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
block.call(model.form)
|
42
|
-
end
|
43
|
-
else
|
44
|
-
args.push(request.fullpath) if args.empty?
|
45
|
-
args.push(dao_form_attrs(options))
|
46
|
-
form_tag(*args, &block)
|
17
|
+
if model.blank?
|
18
|
+
name = 'form'
|
19
|
+
model = Class.new(Dao::Conducer){ model_name(name) }.new(params[name])
|
20
|
+
args.unshift(model)
|
47
21
|
end
|
48
|
-
end
|
49
22
|
|
23
|
+
form_for(*args, &block)
|
24
|
+
end
|
50
25
|
alias_method(:dao_form, :dao_form_for)
|
51
26
|
|
52
27
|
def dao_form_attrs(*args)
|
@@ -92,11 +67,10 @@ module DaoHelper
|
|
92
67
|
|
93
68
|
@dao = api.send(mode, path, params)
|
94
69
|
@dao.route = request.fullpath
|
95
|
-
#@dao.mode = mode
|
96
70
|
|
97
|
-
|
98
|
-
@dao.error! unless @dao.status
|
99
|
-
|
71
|
+
unless options[:error!] == false
|
72
|
+
@dao.error! unless(@dao.status =~ or @dao.status == 420)
|
73
|
+
end
|
100
74
|
|
101
75
|
block ? block.call(@dao) : @dao
|
102
76
|
end
|
data/lib/dao/route.rb
CHANGED
@@ -20,7 +20,7 @@ module Dao
|
|
20
20
|
def pattern_for(route)
|
21
21
|
route = Path.absolute_path_for(route.to_s)
|
22
22
|
re = route.gsub(%r{/:[^/]+}, '/([^/]+)')
|
23
|
-
/#{ re }/
|
23
|
+
/#{ re }/iux
|
24
24
|
end
|
25
25
|
|
26
26
|
def path_for(route, params = {})
|
@@ -59,7 +59,8 @@ module Dao
|
|
59
59
|
|
60
60
|
def params_for(path)
|
61
61
|
match = pattern.match(path).to_a
|
62
|
-
|
62
|
+
|
63
|
+
unless match.empty?
|
63
64
|
map = Map.new
|
64
65
|
ignored = match.shift
|
65
66
|
@keys.each_with_index do |key, index|
|
@@ -79,7 +80,7 @@ module Dao
|
|
79
80
|
def match(name)
|
80
81
|
each do |route|
|
81
82
|
match = route.match(name)
|
82
|
-
return route
|
83
|
+
return route unless match.empty?
|
83
84
|
end
|
84
85
|
return nil
|
85
86
|
end
|
data/lib/dao/upload.rb
CHANGED
@@ -152,6 +152,13 @@ class Upload < ::Map
|
|
152
152
|
end
|
153
153
|
end
|
154
154
|
|
155
|
+
def path_for(arg)
|
156
|
+
[:original_path, :original_filename, :path, :filename, :pathname].
|
157
|
+
map{|msg| arg.send(msg).to_s if arg.respond_to?(msg)}.
|
158
|
+
compact.
|
159
|
+
first or raise("could not find path_for(#{ arg.inspect })")
|
160
|
+
end
|
161
|
+
|
155
162
|
alias_method('mount', 'new')
|
156
163
|
end
|
157
164
|
|
@@ -161,7 +168,7 @@ class Upload < ::Map
|
|
161
168
|
attr_accessor :hidden_key
|
162
169
|
attr_accessor :name
|
163
170
|
attr_accessor :value
|
164
|
-
|
171
|
+
attr_reader :path
|
165
172
|
attr_accessor :dirname
|
166
173
|
attr_accessor :basename
|
167
174
|
attr_accessor :io
|
@@ -192,6 +199,8 @@ class Upload < ::Map
|
|
192
199
|
end
|
193
200
|
|
194
201
|
def _set(value)
|
202
|
+
return unless value
|
203
|
+
|
195
204
|
value =
|
196
205
|
case
|
197
206
|
when value.is_a?(Hash)
|
@@ -216,6 +225,8 @@ class Upload < ::Map
|
|
216
225
|
url = @value ? File.join(Upload.url, @value) : @placeholder.url
|
217
226
|
|
218
227
|
update(:file => @io, :cache => @value, :url => url)
|
228
|
+
|
229
|
+
set_path(Upload.path_for(@io)) rescue nil
|
219
230
|
end
|
220
231
|
|
221
232
|
def _key
|
@@ -280,7 +291,7 @@ class Upload < ::Map
|
|
280
291
|
copied = false
|
281
292
|
|
282
293
|
Upload.rewind(io) do
|
283
|
-
src = io
|
294
|
+
src = Upload.path_for(io)
|
284
295
|
dst = path
|
285
296
|
|
286
297
|
strategies = [
|
@@ -305,15 +316,26 @@ class Upload < ::Map
|
|
305
316
|
end
|
306
317
|
|
307
318
|
def gcopen(path)
|
308
|
-
|
309
|
-
@dirname, @basename = File.split(@path)
|
310
|
-
@value = File.join(File.basename(@dirname), @basename).strip
|
319
|
+
set_path(path)
|
311
320
|
@io = open(@path, 'rb')
|
312
321
|
IOs[object_id] = @io.fileno
|
313
322
|
ObjectSpace.define_finalizer(self, Upload.method(:finalizer).to_proc)
|
314
323
|
@io
|
315
324
|
end
|
316
325
|
|
326
|
+
def set_path(path)
|
327
|
+
if path
|
328
|
+
@path = path.to_s.strip
|
329
|
+
@dirname, @basename = File.split(@path)
|
330
|
+
@value = File.join(File.basename(@dirname), @basename).strip
|
331
|
+
@path
|
332
|
+
else
|
333
|
+
@path, @dirname, @basename, @value = nil
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
alias_method('path=', 'set_path')
|
338
|
+
|
317
339
|
def inspect
|
318
340
|
{
|
319
341
|
Upload.name =>
|
data/lib/dao/validations.rb
CHANGED
@@ -17,7 +17,9 @@ module Dao
|
|
17
17
|
|
18
18
|
class << Validator
|
19
19
|
def mixin(*args, &block)
|
20
|
-
new(*args, &block).tap
|
20
|
+
new(*args, &block).tap do |validator|
|
21
|
+
validator.mixin = true
|
22
|
+
end
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
@@ -58,6 +60,8 @@ module Dao
|
|
58
60
|
@object.validator = self
|
59
61
|
end
|
60
62
|
|
63
|
+
@errors.object = @object
|
64
|
+
|
61
65
|
#@object.extend(InstanceExec) unless @object.respond_to?(:instance_exec)
|
62
66
|
end
|
63
67
|
|
data/test/conducer_test.rb
CHANGED
@@ -30,10 +30,39 @@ Testing Dao::Conducer do
|
|
30
30
|
assert{ c.models == [comment, post, user] }
|
31
31
|
assert{ c.model == comment }
|
32
32
|
assert{ c.model == c.conduces }
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
testing 'that the conduced model can be declared at the class level' do
|
37
|
+
user = User.new
|
38
|
+
post = Post.new
|
39
|
+
comment = Comment.new
|
40
|
+
params = {}
|
41
|
+
|
42
|
+
args = [comment, post, user, params]
|
43
|
+
|
44
|
+
c = new_conducer(*args){ conduces User }
|
33
45
|
|
34
|
-
assert{ c.
|
35
|
-
assert{ c.
|
36
|
-
assert{ c.model ==
|
46
|
+
assert{ c.models == [comment, post, user] }
|
47
|
+
assert{ c.model == user }
|
48
|
+
assert{ c.model == c.conduces }
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
testing 'that the conduced model can be declared at the instance level' do
|
53
|
+
user = User.new
|
54
|
+
post = Post.new
|
55
|
+
comment = Comment.new
|
56
|
+
params = {}
|
57
|
+
|
58
|
+
args = [comment, post, user, params]
|
59
|
+
|
60
|
+
c = new_conducer(*args)
|
61
|
+
|
62
|
+
c.conduces(user)
|
63
|
+
|
64
|
+
assert{ c.models == [user, comment, post] }
|
65
|
+
assert{ c.model == user }
|
37
66
|
assert{ c.model == c.conduces }
|
38
67
|
end
|
39
68
|
end
|
@@ -80,10 +109,10 @@ Testing Dao::Conducer do
|
|
80
109
|
assert{ c.instance_variable_get('@post') == post }
|
81
110
|
|
82
111
|
expected = Map.new
|
83
|
-
expected.
|
84
|
-
expected.
|
85
|
-
expected.
|
86
|
-
expected.
|
112
|
+
expected.add :user => user.attributes
|
113
|
+
expected.add :post => post.attributes
|
114
|
+
expected.add comment.attributes
|
115
|
+
expected.add params
|
87
116
|
|
88
117
|
assert{ c.attributes =~ expected }
|
89
118
|
assert{ c.instance_variable_get('@comment') == comment }
|
@@ -151,6 +180,15 @@ Testing Dao::Conducer do
|
|
151
180
|
end
|
152
181
|
end
|
153
182
|
|
183
|
+
#
|
184
|
+
testing 'that conducers *fold* in attributes' do
|
185
|
+
c = new_conducer
|
186
|
+
|
187
|
+
assert{ c.update_attributes :key => {:a => :b} }
|
188
|
+
assert{ c.update_attributes :key => {:nested => {:a => :b}} }
|
189
|
+
assert{ c.attributes =~ {:key => {:a => :b, :nested => {:a => :b}}} }
|
190
|
+
end
|
191
|
+
|
154
192
|
##
|
155
193
|
#
|
156
194
|
context :teh_default_save do
|
@@ -451,6 +489,8 @@ Testing Dao::Conducer do
|
|
451
489
|
|
452
490
|
#
|
453
491
|
testing 'that the default save uses the mounted _value and _clears it' do
|
492
|
+
begin
|
493
|
+
$pry=true
|
454
494
|
conducer_class =
|
455
495
|
new_conducer_class do
|
456
496
|
mount Dao::Upload, :up, :placeholder => '/images/foo.jpg'
|
@@ -461,7 +501,7 @@ Testing Dao::Conducer do
|
|
461
501
|
up = Upload.new(path)
|
462
502
|
comment = Comment.new
|
463
503
|
|
464
|
-
c = conducer_class.new( comment, :up => {:file =>
|
504
|
+
c = conducer_class.new( comment, :up => {:file => Upload.new(path)} )
|
465
505
|
|
466
506
|
upload = assert{ c.get(:up) }
|
467
507
|
assert{ upload.is_a?(Dao::Upload) }
|
@@ -476,6 +516,9 @@ Testing Dao::Conducer do
|
|
476
516
|
value_was_cleared = assert{ !test(?f, upload.path) }
|
477
517
|
|
478
518
|
assert{ test(?s, path) }
|
519
|
+
ensure
|
520
|
+
$pry=false
|
521
|
+
end
|
479
522
|
end
|
480
523
|
end
|
481
524
|
|
@@ -607,6 +650,10 @@ protected
|
|
607
650
|
def initialize(path)
|
608
651
|
super(IO.read(@path = path))
|
609
652
|
end
|
653
|
+
|
654
|
+
def dup
|
655
|
+
self.class.new(path)
|
656
|
+
end
|
610
657
|
end
|
611
658
|
|
612
659
|
class Model
|
@@ -670,7 +717,7 @@ protected
|
|
670
717
|
end
|
671
718
|
|
672
719
|
def inspect(*args, &block)
|
673
|
-
"#{ self.class.name }(
|
720
|
+
"#{ self.class.name }(#{ attributes.inspect.strip })"
|
674
721
|
end
|
675
722
|
|
676
723
|
def errors
|
data/test/errors_test.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
Testing Dao::Errors do
|
3
|
+
|
4
|
+
testing 'that conducer-less error objects scopes keys in a generic fashion' do
|
5
|
+
e = Dao::Errors.new
|
6
|
+
|
7
|
+
e.add 'is fucked'
|
8
|
+
e.add 'foo is fucked'
|
9
|
+
|
10
|
+
actual = e.to_text
|
11
|
+
|
12
|
+
expected = <<-__
|
13
|
+
---
|
14
|
+
global:
|
15
|
+
- is fucked
|
16
|
+
- foo is fucked
|
17
|
+
__
|
18
|
+
|
19
|
+
assert compress(actual) == compress(expected)
|
20
|
+
end
|
21
|
+
|
22
|
+
testing 'that conducer-based error objects scope keys in a model_name based fashion' do
|
23
|
+
c = new_foo_conducer
|
24
|
+
|
25
|
+
e = c.errors
|
26
|
+
|
27
|
+
e.add 'is fucked'
|
28
|
+
e.add 'foo is fucked'
|
29
|
+
e.add :first_name, 'is fucked'
|
30
|
+
e.add :last_name, 'is fucked'
|
31
|
+
|
32
|
+
actual = e.to_text
|
33
|
+
|
34
|
+
expected = <<-__
|
35
|
+
---
|
36
|
+
foo:
|
37
|
+
- is fucked
|
38
|
+
- foo is fucked
|
39
|
+
foo.first_name:
|
40
|
+
- is fucked
|
41
|
+
foo.last_name:
|
42
|
+
- is fucked
|
43
|
+
__
|
44
|
+
|
45
|
+
assert compress(actual) == compress(expected)
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
protected
|
51
|
+
def compress(string)
|
52
|
+
string.to_s.gsub(/\s/, '')
|
53
|
+
end
|
54
|
+
def new_foo_conducer_class(&block)
|
55
|
+
const = :FooConducer
|
56
|
+
Object.send(:remove_const, const) if Object.send(:const_defined?, const)
|
57
|
+
name = const.to_s
|
58
|
+
c = assert{ Class.new(Dao::Conducer){ self.name = name } }
|
59
|
+
Object.send(:const_set, const, c)
|
60
|
+
assert{ c.name == 'FooConducer' }
|
61
|
+
assert{ c.model_name == 'Foo' }
|
62
|
+
assert{ c.table_name == 'foos' && c.collection_name == 'foos' }
|
63
|
+
assert{ c.class_eval(&block); true } if block
|
64
|
+
c
|
65
|
+
end
|
66
|
+
alias_method :new_conducer_class, :new_foo_conducer_class
|
67
|
+
|
68
|
+
def new_foo_conducer(*args, &block)
|
69
|
+
assert{ new_foo_conducer_class(&block).new(*args) }
|
70
|
+
end
|
71
|
+
alias_method :new_conducer, :new_foo_conducer
|
72
|
+
end
|
73
|
+
|
74
|
+
BEGIN {
|
75
|
+
testdir = File.dirname(File.expand_path(__FILE__))
|
76
|
+
rootdir = File.dirname(testdir)
|
77
|
+
libdir = File.join(rootdir, 'lib')
|
78
|
+
require File.join(libdir, 'dao')
|
79
|
+
require File.join(testdir, 'testing')
|
80
|
+
require 'stringio'
|
81
|
+
}
|