dao 3.3.0 → 4.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/README +7 -0
  2. data/Rakefile +36 -17
  3. data/b.rb +38 -0
  4. data/dao.gemspec +41 -13
  5. data/lib/dao.rb +44 -13
  6. data/lib/dao/api.rb +1 -1
  7. data/lib/dao/api/context.rb +35 -45
  8. data/lib/dao/api/endpoints.rb +225 -91
  9. data/lib/dao/conducer.rb +437 -0
  10. data/lib/dao/conducer/attributes.rb +21 -0
  11. data/lib/dao/conducer/crud.rb +70 -0
  12. data/lib/dao/current.rb +66 -0
  13. data/lib/dao/db.rb +44 -5
  14. data/lib/dao/endpoint.rb +13 -1
  15. data/lib/dao/errors.rb +74 -59
  16. data/lib/dao/exceptions.rb +1 -2
  17. data/lib/dao/extractor.rb +68 -0
  18. data/lib/dao/form.rb +139 -46
  19. data/lib/dao/image_cache.rb +193 -0
  20. data/lib/dao/instance_exec.rb +1 -1
  21. data/lib/dao/name.rb +7 -0
  22. data/lib/dao/params.rb +16 -66
  23. data/lib/dao/rack.rb +3 -0
  24. data/lib/dao/rack/middleware.rb +5 -0
  25. data/lib/dao/rack/middleware/params_parser.rb +24 -0
  26. data/lib/dao/rails.rb +22 -5
  27. data/lib/dao/rails/lib/generators/dao/USAGE +2 -6
  28. data/lib/dao/rails/lib/generators/dao/dao_generator.rb +52 -7
  29. data/lib/dao/rails/lib/generators/dao/templates/api.rb +23 -7
  30. data/lib/dao/rails/lib/generators/dao/templates/api_controller.rb +24 -7
  31. data/lib/dao/rails/lib/generators/dao/templates/conducer.rb +64 -0
  32. data/lib/dao/rails/lib/generators/dao/templates/conducer_controller.rb +79 -0
  33. data/lib/dao/rails/lib/generators/dao/templates/dao.js +13 -6
  34. data/lib/dao/rails/lib/generators/dao/templates/dao_helper.rb +75 -11
  35. data/lib/dao/result.rb +1 -26
  36. data/lib/dao/slug.rb +37 -8
  37. data/lib/dao/status.rb +4 -0
  38. data/lib/dao/support.rb +155 -0
  39. data/lib/dao/validations.rb +48 -157
  40. data/lib/dao/validations/callback.rb +30 -0
  41. data/lib/dao/validations/common.rb +322 -320
  42. data/lib/dao/validations/validator.rb +219 -0
  43. data/test/active_model_conducer_lint_test.rb +19 -0
  44. data/test/api_test.rb +261 -0
  45. data/test/conducer_test.rb +205 -0
  46. data/test/db.yml +9 -0
  47. data/test/form_test.rb +42 -0
  48. data/test/support_test.rb +52 -0
  49. data/test/testing.rb +145 -24
  50. data/test/validations_test.rb +156 -0
  51. metadata +138 -21
  52. data/TODO +0 -33
  53. data/a.rb +0 -80
  54. data/db/dao.yml +0 -5
  55. data/lib/dao/api/interfaces.rb +0 -306
  56. data/lib/dao/interface.rb +0 -28
  57. data/lib/dao/presenter.rb +0 -129
  58. data/lib/dao/rails/lib/generators/dao/api_generator.rb +0 -3
  59. data/lib/dao/validations/base.rb +0 -68
  60. 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
@@ -0,0 +1,9 @@
1
+ ---
2
+ foos:
3
+ "1":
4
+ k: :v
5
+ id: "1"
6
+ "2":
7
+ k: :v
8
+ id: "2"
9
+ t: 2011-09-14 19:40:02.939163 -06:00
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
- def Testing(*args, &block)
14
- Class.new(Test::Unit::TestCase) do
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 self.testing_subclass_count
25
- @@testing_subclass_count = '0' unless defined?(@@testing_subclass_count)
26
- @@testing_subclass_count
27
+ def initialize(name, *args)
28
+ @name = name
27
29
  end
28
30
 
29
- self.testing_subclass_count.succ!
30
- slug = slug_for(*args).gsub(%r/-/,'_')
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
- def self.testing(*args, &block)
43
- method = ["test", testno, slug_for(*args)].delete_if{|part| part.empty?}.join('_')
44
- define_method("test_#{ testno }_#{ slug_for(*args) }", &block)
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
- alias_method '__assert__', 'assert'
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
- module_eval &block
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