dao 3.3.0 → 4.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +7 -0
- data/Rakefile +36 -17
- data/b.rb +38 -0
- data/dao.gemspec +41 -13
- data/lib/dao.rb +44 -13
- data/lib/dao/api.rb +1 -1
- data/lib/dao/api/context.rb +35 -45
- data/lib/dao/api/endpoints.rb +225 -91
- data/lib/dao/conducer.rb +437 -0
- data/lib/dao/conducer/attributes.rb +21 -0
- data/lib/dao/conducer/crud.rb +70 -0
- data/lib/dao/current.rb +66 -0
- data/lib/dao/db.rb +44 -5
- data/lib/dao/endpoint.rb +13 -1
- data/lib/dao/errors.rb +74 -59
- data/lib/dao/exceptions.rb +1 -2
- data/lib/dao/extractor.rb +68 -0
- data/lib/dao/form.rb +139 -46
- data/lib/dao/image_cache.rb +193 -0
- data/lib/dao/instance_exec.rb +1 -1
- data/lib/dao/name.rb +7 -0
- data/lib/dao/params.rb +16 -66
- data/lib/dao/rack.rb +3 -0
- data/lib/dao/rack/middleware.rb +5 -0
- data/lib/dao/rack/middleware/params_parser.rb +24 -0
- data/lib/dao/rails.rb +22 -5
- data/lib/dao/rails/lib/generators/dao/USAGE +2 -6
- data/lib/dao/rails/lib/generators/dao/dao_generator.rb +52 -7
- data/lib/dao/rails/lib/generators/dao/templates/api.rb +23 -7
- data/lib/dao/rails/lib/generators/dao/templates/api_controller.rb +24 -7
- data/lib/dao/rails/lib/generators/dao/templates/conducer.rb +64 -0
- data/lib/dao/rails/lib/generators/dao/templates/conducer_controller.rb +79 -0
- data/lib/dao/rails/lib/generators/dao/templates/dao.js +13 -6
- data/lib/dao/rails/lib/generators/dao/templates/dao_helper.rb +75 -11
- data/lib/dao/result.rb +1 -26
- data/lib/dao/slug.rb +37 -8
- data/lib/dao/status.rb +4 -0
- data/lib/dao/support.rb +155 -0
- data/lib/dao/validations.rb +48 -157
- data/lib/dao/validations/callback.rb +30 -0
- data/lib/dao/validations/common.rb +322 -320
- data/lib/dao/validations/validator.rb +219 -0
- data/test/active_model_conducer_lint_test.rb +19 -0
- data/test/api_test.rb +261 -0
- data/test/conducer_test.rb +205 -0
- data/test/db.yml +9 -0
- data/test/form_test.rb +42 -0
- data/test/support_test.rb +52 -0
- data/test/testing.rb +145 -24
- data/test/validations_test.rb +156 -0
- metadata +138 -21
- data/TODO +0 -33
- data/a.rb +0 -80
- data/db/dao.yml +0 -5
- data/lib/dao/api/interfaces.rb +0 -306
- data/lib/dao/interface.rb +0 -28
- data/lib/dao/presenter.rb +0 -129
- data/lib/dao/rails/lib/generators/dao/api_generator.rb +0 -3
- data/lib/dao/validations/base.rb +0 -68
- data/test/dao_test.rb +0 -506
@@ -0,0 +1,205 @@
|
|
1
|
+
Testing Dao::Conducer do
|
2
|
+
##
|
3
|
+
#
|
4
|
+
testing 'that base classes can be constructed and named' do
|
5
|
+
new_foo_conducer_class()
|
6
|
+
end
|
7
|
+
|
8
|
+
##
|
9
|
+
#
|
10
|
+
testing 'that basic validations/errors work' do
|
11
|
+
c =
|
12
|
+
assert{
|
13
|
+
new_foo_conducer_class do
|
14
|
+
validates_presence_of :bar
|
15
|
+
validates_presence_of :foo, :bar
|
16
|
+
end
|
17
|
+
}
|
18
|
+
|
19
|
+
o = assert{ c.new }
|
20
|
+
assert{ !o.valid? }
|
21
|
+
|
22
|
+
assert{ !Array(o.errors.get(:bar)).empty? }
|
23
|
+
assert{ !Array(o.errors.get(:foo, :bar)).empty? }
|
24
|
+
|
25
|
+
o.attributes.set :foo, :bar, 42
|
26
|
+
assert{ !o.valid? }
|
27
|
+
|
28
|
+
assert{ Array(o.errors.get(:foo, :bar)).empty? }
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
#
|
33
|
+
testing 'that basic form elements work' do
|
34
|
+
c =
|
35
|
+
assert{
|
36
|
+
new_foo_conducer_class do
|
37
|
+
validates_presence_of :bar
|
38
|
+
end
|
39
|
+
}
|
40
|
+
|
41
|
+
o = assert{ c.new }
|
42
|
+
assert{ o.form }
|
43
|
+
assert{ o.form.input(:foo) }
|
44
|
+
assert{ o.form.input(:bar) }
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
#
|
49
|
+
context 'class endpoint' do
|
50
|
+
testing '.new' do
|
51
|
+
c = assert{ new_foo_conducer_class }
|
52
|
+
controller = assert{ Dao.mock_controller }
|
53
|
+
|
54
|
+
check = proc do |args|
|
55
|
+
params = args.detect{|arg| arg.is_a?(Hash)} || {}
|
56
|
+
o = assert{ c.new(*args) }
|
57
|
+
assert{ o.is_a?(Dao::Conducer) }
|
58
|
+
assert{ o.attributes =~ params }
|
59
|
+
assert{ o.controller.is_a?(ActionController::Base) }
|
60
|
+
end
|
61
|
+
|
62
|
+
[
|
63
|
+
{},
|
64
|
+
{:k => :v},
|
65
|
+
nil,
|
66
|
+
].each do |params|
|
67
|
+
check[ [params] ]
|
68
|
+
check[ [controller, params] ]
|
69
|
+
check[ [params, controller] ]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
testing '.all' do
|
74
|
+
c = assert{ new_foo_conducer_class }
|
75
|
+
assert{ c.all().is_a?(Array) }
|
76
|
+
assert{ c.all(nil).is_a?(Array) }
|
77
|
+
assert{ c.all({}).is_a?(Array) }
|
78
|
+
end
|
79
|
+
|
80
|
+
testing '.find' do
|
81
|
+
c = assert{ new_foo_conducer_class }
|
82
|
+
o = assert{ c.new }
|
83
|
+
assert{ c.find(o.id).is_a?(Dao::Conducer) }
|
84
|
+
end
|
85
|
+
|
86
|
+
testing '.model_name' do
|
87
|
+
c = assert{ new_foo_conducer_class }
|
88
|
+
assert{ c.model_name }
|
89
|
+
o = assert{ c.new }
|
90
|
+
assert{ o.model_name }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'current' do
|
95
|
+
testing 'class and instance endpoints' do
|
96
|
+
c = assert{ new_foo_conducer_class }
|
97
|
+
o = c.new
|
98
|
+
%w(
|
99
|
+
current_controller
|
100
|
+
current_request
|
101
|
+
current_response
|
102
|
+
current_session
|
103
|
+
current_user
|
104
|
+
).each do |method|
|
105
|
+
assert{ o.respond_to?(method) }
|
106
|
+
assert{ c.respond_to?(method) }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'instance endpoint' do
|
112
|
+
testing '#save' do
|
113
|
+
params = {:k => :v}
|
114
|
+
o = assert{ new_foo_conducer(params) }
|
115
|
+
assert{ o.save }
|
116
|
+
id = assert{ o.id }
|
117
|
+
assert{ db.foos.find(id)[:k] == o.attributes[:k] }
|
118
|
+
assert{ id == o.id }
|
119
|
+
assert{ o.attributes =~ params.merge(:id => id) }
|
120
|
+
end
|
121
|
+
|
122
|
+
testing '#update_attributes' do
|
123
|
+
params = {:k => :v}
|
124
|
+
o = assert{ new_foo_conducer(params) }
|
125
|
+
t = Time.now
|
126
|
+
assert{ o.update_attributes :t => t }
|
127
|
+
assert{ o.save }
|
128
|
+
id = assert{ o.id }
|
129
|
+
assert{ db.foos.find(id).id == o.id }
|
130
|
+
assert{ db.foos.find(id) =~ params.merge(:id => id, :t => t) }
|
131
|
+
end
|
132
|
+
|
133
|
+
testing '#destroy' do
|
134
|
+
params = {:k => :v}
|
135
|
+
o = assert{ new_foo_conducer(params) }
|
136
|
+
assert{ o.save }
|
137
|
+
id = assert{ o.id }
|
138
|
+
assert{ db.foos.find(id).id == o.id }
|
139
|
+
assert{ o.destroy }
|
140
|
+
assert{ db.foos.find(id).nil? }
|
141
|
+
end
|
142
|
+
|
143
|
+
testing '#to_param' do
|
144
|
+
o = assert{ new_foo_conducer() }
|
145
|
+
assert{ o.to_param.nil? }
|
146
|
+
o.id = 42
|
147
|
+
assert{ o.to_param }
|
148
|
+
end
|
149
|
+
|
150
|
+
testing '#errors' do
|
151
|
+
o = assert{ new_foo_conducer() }
|
152
|
+
assert{ o.errors.respond_to?(:[]) }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
|
158
|
+
protected
|
159
|
+
def new_foo_conducer_class(&block)
|
160
|
+
name = 'FooConducer'
|
161
|
+
c = assert{ Class.new(Dao::Conducer){ self.name = name; crud! } }
|
162
|
+
assert{ c.name == 'FooConducer' }
|
163
|
+
assert{ c.model_name == 'Foo' }
|
164
|
+
assert{ c.table_name == 'foos' && c.collection_name == 'foos' }
|
165
|
+
assert{ c.module_eval(&block); true } if block
|
166
|
+
c
|
167
|
+
end
|
168
|
+
|
169
|
+
def new_foo_conducer(*args, &block)
|
170
|
+
assert{ new_foo_conducer_class(&block).new(*args) }
|
171
|
+
end
|
172
|
+
|
173
|
+
prepare do
|
174
|
+
$db = Dao::Db.new(:path => 'test/db.yml')
|
175
|
+
Dao::Db.instance = $db
|
176
|
+
collection = $db['foos']
|
177
|
+
%w( a b c ).each do |name|
|
178
|
+
collection.save(
|
179
|
+
:name => name, :created_at => Time.now.to_f, :a => %w( x y z ), :h => {:k => :v}
|
180
|
+
)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
cleanup do
|
185
|
+
$db = Dao::Db.new(:path => 'test/db.yml')
|
186
|
+
$db.rm_f
|
187
|
+
end
|
188
|
+
|
189
|
+
def db
|
190
|
+
$db
|
191
|
+
end
|
192
|
+
|
193
|
+
def collection
|
194
|
+
$db[:foos]
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
BEGIN {
|
200
|
+
testdir = File.dirname(File.expand_path(__FILE__))
|
201
|
+
rootdir = File.dirname(testdir)
|
202
|
+
libdir = File.join(rootdir, 'lib')
|
203
|
+
require File.join(libdir, 'dao')
|
204
|
+
require File.join(testdir, 'testing')
|
205
|
+
}
|
data/test/db.yml
ADDED
data/test/form_test.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
Testing Dao::Form do
|
2
|
+
testing '.new' do
|
3
|
+
form = new_form()
|
4
|
+
form = new_named_form()
|
5
|
+
end
|
6
|
+
|
7
|
+
testing 'name_for' do
|
8
|
+
assert{ Dao::Form.name_for(:foo, :a, :b) == 'dao[foo][a.b]' }
|
9
|
+
assert{ new_form.name_for(:a, :b) == 'dao[form][a.b]' }
|
10
|
+
assert{ new_named_form.name_for(:a, :b) == 'dao[name][a.b]' }
|
11
|
+
assert{ new_named_form(:foo).name_for(:a, :b) == 'dao[foo][a.b]' }
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
def new_form
|
16
|
+
assert{ Dao::Form.new }
|
17
|
+
end
|
18
|
+
|
19
|
+
def new_named_form(name = 'name')
|
20
|
+
object = Object.new
|
21
|
+
class << object
|
22
|
+
%w[ name attributes errors ].each{|attr_name| attr_accessor(attr_name)}
|
23
|
+
attr_accessor :name
|
24
|
+
end
|
25
|
+
object.name = name
|
26
|
+
object.attributes = Map.new
|
27
|
+
object.errors = Dao::Errors.new
|
28
|
+
assert{ Dao::Form.new(object) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
BEGIN {
|
35
|
+
testdir = File.dirname(File.expand_path(__FILE__))
|
36
|
+
rootdir = File.dirname(testdir)
|
37
|
+
libdir = File.join(rootdir, 'lib')
|
38
|
+
|
39
|
+
require File.join(libdir, 'dao')
|
40
|
+
require File.join(testdir, 'testing')
|
41
|
+
require File.join(testdir, 'helper')
|
42
|
+
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
Testing Dao::Conducer do
|
2
|
+
testing 'that dao has a root' do
|
3
|
+
assert{ Dao.respond_to?(:root) }
|
4
|
+
assert{ Dao.root }
|
5
|
+
end
|
6
|
+
|
7
|
+
testing 'that dao can build a mock controller' do
|
8
|
+
controller = assert{ Dao.mock_controller }
|
9
|
+
assert{ controller.url_for '/' }
|
10
|
+
end
|
11
|
+
|
12
|
+
testing 'that dao can mark the current_controller' do
|
13
|
+
assert{ Dao.current_controller = Dao.mock_controller }
|
14
|
+
end
|
15
|
+
|
16
|
+
testing 'that dao can pre-process parameters' do
|
17
|
+
params = Map.new(
|
18
|
+
'dao' => {
|
19
|
+
'foos' => {
|
20
|
+
'k' => 'v',
|
21
|
+
'array.0' => '0',
|
22
|
+
'array.1' => '1'
|
23
|
+
},
|
24
|
+
|
25
|
+
'bars' => {
|
26
|
+
'a' => 'b',
|
27
|
+
'hash.k' => 'v'
|
28
|
+
}
|
29
|
+
}
|
30
|
+
)
|
31
|
+
|
32
|
+
assert{ Dao.normalize_parameters(params) }
|
33
|
+
assert{ params[:dao] = :normalized }
|
34
|
+
|
35
|
+
assert{ params[:foos].is_a?(Hash) }
|
36
|
+
assert{ params[:foos][:k] == 'v' }
|
37
|
+
assert{ params[:foos][:array] == %w( 0 1 ) }
|
38
|
+
|
39
|
+
assert{ params[:bars].is_a?(Hash) }
|
40
|
+
assert{ params[:bars][:a] == 'b' }
|
41
|
+
assert{ params[:bars][:hash] == {'k' => 'v'} }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
BEGIN {
|
47
|
+
testdir = File.dirname(File.expand_path(__FILE__))
|
48
|
+
rootdir = File.dirname(testdir)
|
49
|
+
libdir = File.join(rootdir, 'lib')
|
50
|
+
require File.join(libdir, 'dao')
|
51
|
+
require File.join(testdir, 'testing')
|
52
|
+
}
|
data/test/testing.rb
CHANGED
@@ -10,43 +10,125 @@ $:.unshift(testdir) unless $:.include?(testdir)
|
|
10
10
|
$:.unshift(libdir) unless $:.include?(libdir)
|
11
11
|
$:.unshift(rootdir) unless $:.include?(rootdir)
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
def self.slug_for(*args)
|
13
|
+
class Testing
|
14
|
+
class Slug < ::String
|
15
|
+
def Slug.for(*args)
|
17
16
|
string = args.flatten.compact.join('-')
|
18
17
|
words = string.to_s.scan(%r/\w+/)
|
19
18
|
words.map!{|word| word.gsub %r/[^0-9a-zA-Z_-]/, ''}
|
20
19
|
words.delete_if{|word| word.nil? or word.strip.empty?}
|
21
|
-
words.join('-').downcase
|
20
|
+
new(words.join('-').downcase)
|
22
21
|
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Context
|
25
|
+
attr_accessor :name
|
23
26
|
|
24
|
-
def
|
25
|
-
|
26
|
-
@@testing_subclass_count
|
27
|
+
def initialize(name, *args)
|
28
|
+
@name = name
|
27
29
|
end
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
name = ['TESTING', '%03d' % self.testing_subclass_count, slug].delete_if{|part| part.empty?}.join('_')
|
32
|
-
name = name.upcase!
|
33
|
-
const_set(:Name, name)
|
34
|
-
def self.name() const_get(:Name) end
|
35
|
-
|
36
|
-
def self.testno()
|
37
|
-
'%05d' % (@testno ||= 0)
|
38
|
-
ensure
|
39
|
-
@testno += 1
|
31
|
+
def to_s
|
32
|
+
Slug.for(name)
|
40
33
|
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def Testing(*args, &block)
|
38
|
+
Class.new(::Test::Unit::TestCase) do
|
39
|
+
|
40
|
+
## class methods
|
41
|
+
#
|
42
|
+
class << self
|
43
|
+
def contexts
|
44
|
+
@contexts ||= []
|
45
|
+
end
|
46
|
+
|
47
|
+
def context(*args, &block)
|
48
|
+
return contexts.last if(args.empty? and block.nil?)
|
41
49
|
|
42
|
-
|
43
|
-
|
44
|
-
|
50
|
+
context = Testing::Context.new(*args)
|
51
|
+
contexts.push(context)
|
52
|
+
|
53
|
+
begin
|
54
|
+
block.call(context)
|
55
|
+
ensure
|
56
|
+
contexts.pop
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def slug_for(*args)
|
61
|
+
string = [context, args].flatten.compact.join('-')
|
62
|
+
words = string.to_s.scan(%r/\w+/)
|
63
|
+
words.map!{|word| word.gsub %r/[^0-9a-zA-Z_-]/, ''}
|
64
|
+
words.delete_if{|word| word.nil? or word.strip.empty?}
|
65
|
+
words.join('-').downcase.sub(/_$/, '')
|
66
|
+
end
|
67
|
+
|
68
|
+
def name() const_get(:Name) end
|
69
|
+
|
70
|
+
def testno()
|
71
|
+
'%05d' % (@testno ||= 0)
|
72
|
+
ensure
|
73
|
+
@testno += 1
|
74
|
+
end
|
75
|
+
|
76
|
+
def testing(*args, &block)
|
77
|
+
method = ["test", testno, slug_for(*args)].delete_if{|part| part.empty?}.join('_')
|
78
|
+
define_method(method, &block)
|
79
|
+
end
|
80
|
+
|
81
|
+
def test(*args, &block)
|
82
|
+
testing(*args, &block)
|
83
|
+
end
|
84
|
+
|
85
|
+
def setup(&block)
|
86
|
+
define_method(:setup, &block) if block
|
87
|
+
end
|
88
|
+
|
89
|
+
def teardown(&block)
|
90
|
+
define_method(:teardown, &block) if block
|
91
|
+
end
|
92
|
+
|
93
|
+
def prepare(&block)
|
94
|
+
@prepare ||= []
|
95
|
+
@prepare.push(block) if block
|
96
|
+
@prepare
|
97
|
+
end
|
98
|
+
|
99
|
+
def cleanup(&block)
|
100
|
+
@cleanup ||= []
|
101
|
+
@cleanup.push(block) if block
|
102
|
+
@cleanup
|
103
|
+
end
|
45
104
|
end
|
46
105
|
|
47
|
-
|
106
|
+
## configure the subclass!
|
107
|
+
#
|
108
|
+
const_set(:Testno, '0')
|
109
|
+
slug = slug_for(*args).gsub(%r/-/,'_')
|
110
|
+
name = ['TESTING', '%03d' % const_get(:Testno), slug].delete_if{|part| part.empty?}.join('_')
|
111
|
+
name = name.upcase!
|
112
|
+
const_set(:Name, name)
|
113
|
+
const_set(:Missing, Object.new.freeze)
|
114
|
+
|
115
|
+
## instance methods
|
116
|
+
#
|
117
|
+
alias_method('__assert__', 'assert')
|
48
118
|
|
49
119
|
def assert(*args, &block)
|
120
|
+
if args.size == 1 and args.first.is_a?(Hash)
|
121
|
+
options = args.first
|
122
|
+
expected = getopt(:expected, options){ missing }
|
123
|
+
actual = getopt(:actual, options){ missing }
|
124
|
+
if expected == missing and actual == missing
|
125
|
+
actual, expected, *ignored = options.to_a.flatten
|
126
|
+
end
|
127
|
+
expected = expected.call() if expected.respond_to?(:call)
|
128
|
+
actual = actual.call() if actual.respond_to?(:call)
|
129
|
+
assert_equal(expected, actual)
|
130
|
+
end
|
131
|
+
|
50
132
|
if block
|
51
133
|
label = "assert(#{ args.join(' ') })"
|
52
134
|
result = nil
|
@@ -61,6 +143,23 @@ def Testing(*args, &block)
|
|
61
143
|
end
|
62
144
|
end
|
63
145
|
|
146
|
+
def missing
|
147
|
+
self.class.const_get(:Missing)
|
148
|
+
end
|
149
|
+
|
150
|
+
def getopt(opt, hash, options = nil, &block)
|
151
|
+
[opt.to_s, opt.to_s.to_sym].each do |key|
|
152
|
+
return hash[key] if hash.has_key?(key)
|
153
|
+
end
|
154
|
+
default =
|
155
|
+
if block
|
156
|
+
block.call
|
157
|
+
else
|
158
|
+
options.is_a?(Hash) ? options[:default] : nil
|
159
|
+
end
|
160
|
+
return default
|
161
|
+
end
|
162
|
+
|
64
163
|
def subclass_of exception
|
65
164
|
class << exception
|
66
165
|
def ==(other) super or self > other end
|
@@ -68,7 +167,29 @@ def Testing(*args, &block)
|
|
68
167
|
exception
|
69
168
|
end
|
70
169
|
|
71
|
-
|
170
|
+
##
|
171
|
+
#
|
172
|
+
module_eval(&block)
|
173
|
+
|
174
|
+
self.setup()
|
175
|
+
self.prepare.each{|b| b.call()}
|
176
|
+
|
177
|
+
at_exit{
|
178
|
+
self.teardown()
|
179
|
+
self.cleanup.each{|b| b.call()}
|
180
|
+
}
|
181
|
+
|
72
182
|
self
|
73
183
|
end
|
74
184
|
end
|
185
|
+
|
186
|
+
|
187
|
+
if $0 == __FILE__
|
188
|
+
|
189
|
+
Testing 'Testing' do
|
190
|
+
testing('foo'){ assert true }
|
191
|
+
test{ assert true }
|
192
|
+
p instance_methods.grep(/test/)
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|