dao 3.3.0 → 4.2.1

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.
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