dao 4.4.4 → 4.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}
|