ninja-model 0.4.2 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/.gitignore +19 -0
  2. data/Rakefile +0 -7
  3. data/autotest/discover.rb +1 -0
  4. data/lib/ninja_model.rb +22 -26
  5. data/lib/ninja_model/adapters.rb +33 -43
  6. data/lib/ninja_model/adapters/abstract_adapter.rb +2 -10
  7. data/lib/ninja_model/adapters/adapter_manager.rb +17 -10
  8. data/lib/ninja_model/adapters/adapter_pool.rb +15 -17
  9. data/lib/ninja_model/adapters/adapter_specification.rb +3 -3
  10. data/lib/ninja_model/associations.rb +25 -106
  11. data/lib/ninja_model/associations/association_proxy.rb +119 -1
  12. data/lib/ninja_model/associations/belongs_to_association.rb +5 -1
  13. data/lib/ninja_model/attribute.rb +130 -0
  14. data/lib/ninja_model/{attributes.rb → attribute_methods.rb} +21 -42
  15. data/lib/ninja_model/base.rb +23 -20
  16. data/lib/ninja_model/callbacks.rb +2 -11
  17. data/lib/ninja_model/identity.rb +6 -11
  18. data/lib/ninja_model/persistence.rb +15 -30
  19. data/lib/ninja_model/predicate.rb +4 -4
  20. data/lib/ninja_model/rails_ext/active_record.rb +187 -0
  21. data/lib/ninja_model/railtie.rb +14 -8
  22. data/lib/ninja_model/reflection.rb +7 -14
  23. data/lib/ninja_model/relation.rb +5 -3
  24. data/lib/ninja_model/relation/finder_methods.rb +4 -8
  25. data/lib/ninja_model/relation/spawn_methods.rb +1 -1
  26. data/lib/ninja_model/validation.rb +6 -23
  27. data/lib/ninja_model/version.rb +1 -1
  28. data/ninja-model.gemspec +28 -0
  29. data/spec/ninja_model/adapters/abstract_adapter_spec.rb +45 -0
  30. data/spec/ninja_model/adapters/adapter_manager_spec.rb +69 -0
  31. data/spec/ninja_model/adapters/adapter_pool_spec.rb +210 -48
  32. data/spec/ninja_model/adapters_spec.rb +77 -0
  33. data/spec/ninja_model/attribute_methods_spec.rb +95 -0
  34. data/spec/ninja_model/attribute_spec.rb +129 -0
  35. data/spec/ninja_model/base_spec.rb +4 -52
  36. data/spec/ninja_model/identity_spec.rb +16 -32
  37. data/spec/ninja_model/persistence_spec.rb +130 -4
  38. data/spec/ninja_model/predicate_spec.rb +40 -6
  39. data/spec/ninja_model/query_methods_spec.rb +76 -74
  40. data/spec/ninja_model/reflection_spec.rb +63 -0
  41. data/spec/ninja_model/relation_spec.rb +213 -20
  42. data/spec/ninja_model/symbol_spec.rb +19 -0
  43. data/spec/ninja_model/validation_spec.rb +18 -0
  44. data/spec/spec_helper.rb +9 -0
  45. data/spec/support/matchers/convert.rb +30 -0
  46. metadata +85 -63
  47. data/lib/ninja_model/associations/active_record_proxy.rb +0 -53
  48. data/lib/ninja_model/associations/ninja_model_proxy.rb +0 -46
  49. data/lib/ninja_model/configuration.rb +0 -20
  50. data/lib/ninja_model/errors.rb +0 -5
  51. data/lib/ninja_model/log_subscriber.rb +0 -18
  52. data/lib/ninja_model/scoping.rb +0 -50
  53. data/spec/ninja_model/attributes_spec.rb +0 -85
  54. data/spec/ninja_model/scoping_spec.rb +0 -40
@@ -1,13 +1,47 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe NinjaModel::Predicate do
4
- before(:each) do
5
- @pred = NinjaModel::Predicate.new(:var, :ge)
4
+ before { @pred = NinjaModel::Predicate.new(:var, :ge) }
5
+ subject { @pred }
6
+ it { should respond_to(:value=) }
7
+ its(:has_value?) { should be_false }
8
+ its(:attribute) { should eql(:var) }
9
+ its(:meth) { should eql(:ge) }
10
+
11
+ it 'should have a value after update' do
12
+ subject.value = 'valued'
13
+ subject.has_value?.should be_true
6
14
  end
7
15
 
8
- it { @pred.has_value?.should be_false }
9
- it 'should have value after update' do
10
- @pred.value = 'value'
11
- @pred.has_value?.should be_true
16
+ describe 'test' do
17
+ context 'with a @value of 1' do
18
+ def expectations
19
+ { :eq => false, :ne => true, :gt => true, :gte => true, :lt => false, :lte => false }
20
+ end
21
+ NinjaModel::Predicate::PREDICATES.each do |p|
22
+ if p.eql?(:in)
23
+ subject { NinjaModel::Predicate.new(:var, :in, 1) }
24
+ describe ':in 2' do
25
+ specify { lambda { subject.test(2) }.should raise_error }
26
+ end
27
+ else
28
+ describe ":#{p} 2" do
29
+ specify { NinjaModel::Predicate.new(:var, p, 1).test(2).should eql(expectations[p]) }
30
+ end
31
+ end
32
+ end
33
+ end
12
34
  end
13
35
  end
36
+
37
+ #describe NinjaModel::Predicate do
38
+ # before(:each) do
39
+ # @pred = NinjaModel::Predicate.new(:var, :ge)
40
+ # end
41
+ #
42
+ # it { @pred.has_value?.should be_false }
43
+ # it 'should have value after update' do
44
+ # @pred.value = 'value'
45
+ # @pred.has_value?.should be_true
46
+ # end
47
+ #end
@@ -1,76 +1,78 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe NinjaModel::QueryMethods do
4
- before(:each) do
5
- @model = mock('model')
6
- @attribute = NinjaModel::Attribute.new(:valid, :integer, @model, {})
7
- @model.stubs(:model_attributes).returns({:valid => @attribute}.with_indifferent_access)
8
- @rel = NinjaModel::Relation.new(@model)
9
- end
10
-
11
- describe 'order' do
12
- it 'should update the relations\'s order_values' do
13
- new_rel = @rel.order(:new_order)
14
- new_rel.ordering.first.should eql(:new_order)
15
- end
16
- end
17
-
18
- describe 'where' do
19
- it 'should update the relation\'s where_values' do
20
- new_rel = @rel.where(:valid => 2)
21
- new_rel.predicates.first.should be_kind_of(NinjaModel::Predicate)
22
- new_rel.predicates.first.value.should eql(2)
23
- end
24
- end
25
-
26
- describe 'limit' do
27
- it 'should update the relation\'s limit' do
28
- new_rel = @rel.limit(5)
29
- new_rel.limit_value.should eql(5)
30
- end
31
- end
32
-
33
- describe 'build_predicates' do
34
- it 'should reject a string' do
35
- lambda { @rel.send :build_predicates, 'foo < 1' }.should raise_error(ArgumentError)
36
- end
37
-
38
- describe 'with an array' do
39
- it 'should return an array of NinjaModel::Predicates' do
40
- res = @rel.send :build_predicates, [{:valid => 1}]
41
- res.should be_kind_of(Array)
42
- res.first.should be_kind_of(NinjaModel::Predicate)
43
- res.first.value.should eql(1)
44
- end
45
- end
46
- describe 'with a hash' do
47
- it 'should handle a valid symbol' do
48
- res = @rel.send :build_predicates, {:valid => 1}
49
- res.should be_kind_of(Array)
50
- res.first.should be_kind_of(NinjaModel::Predicate)
51
- res.first.value.should eql(1)
52
- end
53
-
54
- it 'should reject an invalid symbol' do
55
- lambda { @rel.send :build_predicates, {:invalid => 2} }.should raise_error(ArgumentError)
56
- end
57
-
58
- it 'should handle a predicate' do
59
- rel = NinjaModel::Predicate.new(:valid, :eq)
60
- res = @rel.send :build_predicates, {rel => 1}
61
- res.should be_kind_of(Array)
62
- res.first.should be_kind_of(NinjaModel::Predicate)
63
- res.first.value.should eql(1)
64
- end
65
- it 'should reject an unkrecognized key' do
66
- lambda { @rel.send :build_predicates, {'bad' => 12} }.should raise_error(ArgumentError)
67
- end
68
- end
69
-
70
- it 'should reject an unprocessable argument' do
71
- lambda { @rel.send :build_predicates, 5 }.should raise_error(ArgumentError)
72
- end
73
-
74
- end
75
-
76
- end
3
+ #describe NinjaModel::QueryMethods do
4
+ # class FakeModel < NinjaModel::Base
5
+ # attribute :valid, :integer, 1
6
+ # end
7
+ #
8
+ # before(:each) do
9
+ # @model = FakeModel
10
+ # @rel = NinjaModel::Relation.new(@model)
11
+ # end
12
+ #
13
+ # describe 'order' do
14
+ # it 'should update the relations\'s order_values' do
15
+ # new_rel = @rel.order(:new_order)
16
+ # new_rel.ordering.first.should eql(:new_order)
17
+ # end
18
+ # end
19
+ #
20
+ # describe 'where' do
21
+ # it 'should update the relation\'s where_values' do
22
+ # new_rel = @rel.where(:valid => 2)
23
+ # new_rel.predicates.first.should be_kind_of(NinjaModel::Predicate)
24
+ # new_rel.predicates.first.value.should eql(2)
25
+ # end
26
+ # end
27
+ #
28
+ # describe 'limit' do
29
+ # it 'should update the relation\'s limit' do
30
+ # new_rel = @rel.limit(5)
31
+ # new_rel.limit_value.should eql(5)
32
+ # end
33
+ # end
34
+ #
35
+ # describe 'build_predicates' do
36
+ # it 'should reject a string' do
37
+ # lambda { @rel.send :build_predicates, 'foo < 1' }.should raise_error(ArgumentError)
38
+ # end
39
+ #
40
+ # describe 'with an array' do
41
+ # it 'should return an array of NinjaModel::Predicates' do
42
+ # res = @rel.send :build_predicates, [{:valid => 1}]
43
+ # res.should be_kind_of(Array)
44
+ # res.first.should be_kind_of(NinjaModel::Predicate)
45
+ # res.first.value.should eql(1)
46
+ # end
47
+ # end
48
+ # describe 'with a hash' do
49
+ # it 'should handle a valid symbol' do
50
+ # res = @rel.send :build_predicates, {:valid => 1}
51
+ # res.should be_kind_of(Array)
52
+ # res.first.should be_kind_of(NinjaModel::Predicate)
53
+ # res.first.value.should eql(1)
54
+ # end
55
+ #
56
+ # it 'should reject an invalid symbol' do
57
+ # lambda { @rel.send :build_predicates, {:invalid => 2} }.should raise_error(ArgumentError)
58
+ # end
59
+ #
60
+ # it 'should handle a predicate' do
61
+ # rel = NinjaModel::Predicate.new(:valid, :eq)
62
+ # res = @rel.send :build_predicates, {rel => 1}
63
+ # res.should be_kind_of(Array)
64
+ # res.first.should be_kind_of(NinjaModel::Predicate)
65
+ # res.first.value.should eql(1)
66
+ # end
67
+ # it 'should reject an unkrecognized key' do
68
+ # lambda { @rel.send :build_predicates, {'bad' => 12} }.should raise_error(ArgumentError)
69
+ # end
70
+ # end
71
+ #
72
+ # it 'should reject an unprocessable argument' do
73
+ # lambda { @rel.send :build_predicates, 5 }.should raise_error(ArgumentError)
74
+ # end
75
+ #
76
+ # end
77
+ #
78
+ #end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+ describe NinjaModel::Reflection do
3
+ class BareModel
4
+ end
5
+ class ReflectionModel < NinjaModel::Base
6
+ attribute :test, :string
7
+ end
8
+ class TargetModel < NinjaModel::Base
9
+ attribute :test2, :string
10
+ end
11
+
12
+ subject { ReflectionModel }
13
+ it { should respond_to(:create_reflection) }
14
+
15
+ describe 'ninja_model?' do
16
+ specify { NinjaModel::Base.ninja_model?(:has_one, :bare_model).should be_false }
17
+ specify { NinjaModel::Base.ninja_model?(:has_one, :reflection_model).should be_true }
18
+ end
19
+
20
+ describe 'create_reflection' do
21
+ it 'should store the reflections on the class' do
22
+ @klass = Class.new(NinjaModel::Base)
23
+ @reflection = @klass.create_reflection(:has_one, :target_model, {}, @klass)
24
+ @klass.reflections.should eql(:target_model => @reflection)
25
+ end
26
+
27
+ it 'should return a reflection for a particular association' do
28
+ @klass = Class.new(NinjaModel::Base)
29
+ @reflection = @klass.create_reflection(:has_one, :target_model, {}, @klass)
30
+ @klass.reflect_on_association(:target_model).should eql(@reflection)
31
+ end
32
+
33
+ context 'has_one' do
34
+ subject { ReflectionModel.create_reflection(:has_one, :target_model, {}, ReflectionModel) }
35
+ its(:class_name) { should eql('TargetModel') }
36
+ its(:klass) { should eql(TargetModel) }
37
+ its(:collection?) { should be_false }
38
+ its(:primary_key_name) { should eql('reflection_model_id') }
39
+ its(:association_foreign_key) { should eql('target_model_id') }
40
+ its(:belongs_to?) { should be_false }
41
+ end
42
+
43
+ context 'has_many' do
44
+ subject { ReflectionModel.create_reflection(:has_many, :target_models, {}, ReflectionModel) }
45
+ its(:class_name) { should eql('TargetModel') }
46
+ its(:klass) { should eql(TargetModel) }
47
+ its(:collection?) { should be_true }
48
+ its(:primary_key_name) { should eql('reflection_model_id') }
49
+ its(:association_foreign_key) { should eql('target_model_id') }
50
+ its(:belongs_to?) { should be_false }
51
+ end
52
+
53
+ context 'belongs_to' do
54
+ subject { TargetModel.create_reflection(:belongs_to, :reflection_model, {}, TargetModel) }
55
+ its(:class_name) { should eql('ReflectionModel') }
56
+ its(:klass) { should eql(ReflectionModel) }
57
+ its(:collection?) { should be_false }
58
+ its(:primary_key_name) { should eql('reflection_model_id') }
59
+ its(:association_foreign_key) { should eql('reflection_model_id') }
60
+ its(:belongs_to?) { should be_true }
61
+ end
62
+ end
63
+ end
@@ -1,26 +1,219 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe NinjaModel::Relation do
4
- describe 'with an instance' do
5
- before(:each) do
6
- @model = mock('NinjaModel')
7
- @model.stubs(:adapter => stub('NinjaAdapter', :read => 'object_list'))
8
- @rel = NinjaModel::Relation.new(@model)
9
- end
10
- it { @rel.should respond_to(:klass) }
11
- it { @rel.should respond_to(:loaded?) }
12
- it { @rel.should respond_to(:limit_value) }
13
- it { @rel.limit_value.should be_nil }
14
- it { @rel.should respond_to(:offset_value) }
15
- it { @rel.offset_value.should be_nil }
16
- it { @rel.should respond_to(:ordering) }
17
- it { @rel.ordering.should eql([]) }
18
- it { @rel.should respond_to(:predicates) }
19
- it { @rel.predicates.should eql([]) }
20
- it { @rel.loaded?.should be_false }
21
-
22
- it 'should try to read when to_a is called' do
23
- @rel.to_a.should eql('object_list')
4
+ class RelationModel < NinjaModel::Base
5
+ attribute :id, :integer, :primary_key => true
6
+ attribute :attr1, :integer
7
+ attribute :attr2, :string
8
+
9
+ scope :foo, where(:attr2 => 'foo')
10
+ end
11
+
12
+ before {
13
+ @rel = NinjaModel::Relation.new(RelationModel)
14
+ @adapter = mock('Adapter')
15
+ @adapter.stubs(:read).returns(['foo'])
16
+ RelationModel.stubs(:adapter).returns(@adapter)
17
+ }
18
+ subject { @rel }
19
+ it { should respond_to(:to_a) }
20
+ it { should respond_to(:scoping) }
21
+ it { should respond_to(:size) }
22
+ it { should respond_to(:blank?) }
23
+ it { should respond_to(:empty?) }
24
+ it { should respond_to(:order) }
25
+ it { should respond_to(:where) }
26
+ it { should respond_to(:limit) }
27
+ its(:loaded?) { should be_false }
28
+ its(:limit_value) { should be_nil }
29
+ its(:offset_value) { should be_nil }
30
+ its(:ordering) { should be_blank }
31
+ its(:predicates) { should be_blank }
32
+ its(:inspect) { should eql(['foo'].inspect) }
33
+
34
+ it 'should respond to array methods' do
35
+ subject.expects(:to_a).returns([])
36
+ subject.flatten
37
+ end
38
+
39
+ it 'should respond to scopes' do
40
+ subject.expects(:merge)
41
+ subject.foo
42
+ end
43
+
44
+ it 'should raise NoMethodError for a true invalid method' do
45
+ lambda { subject.blarg }.should raise_error(NoMethodError)
46
+ end
47
+
48
+ describe 'first' do
49
+ context 'with no arguments' do
50
+ it 'should call find_first' do
51
+ @rel.expects(:find_first)
52
+ @rel.first
53
+ end
54
+ end
55
+ context 'with find arguments' do
56
+ it 'should update the relation and return the first record' do
57
+ @rel.expects(:apply_finder_options).with(:arg1 => 1).returns(@rel)
58
+ @rel.first(:arg1 => 1)
59
+ end
60
+ end
61
+ end
62
+
63
+ describe 'all' do
64
+ context 'with no arguments' do
65
+ it 'should call to_a' do
66
+ @rel.expects(:to_a)
67
+ @rel.all
68
+ end
69
+ context 'when chained to a find_first' do
70
+ it 'should reuse the cached records' do
71
+ @rel.all
72
+ @rel.expects(:to_a).never
73
+ @rel.find(:first)
74
+ end
75
+ end
76
+ end
77
+
78
+ context 'with arguments' do
79
+ it 'should update the relation and call to_a' do
80
+ @rel.expects(:apply_finder_options).with(:arg1 => 1)
81
+ @rel.all(:arg1 => 1)
82
+ end
83
+ end
84
+ end
85
+
86
+ describe 'find' do
87
+ context 'with no args' do
88
+ it 'should raise RecordNotFound' do
89
+ lambda { subject.find }.should raise_error(NinjaModel::RecordNotFound)
90
+ end
91
+ end
92
+ context 'with an id arg' do
93
+ it 'should call find_one' do
94
+ subject.expects(:find_one).with(1)
95
+ subject.find(1)
96
+ end
97
+ it 'add the primary key to the relation' do
98
+ subject.expects(:where).with(:id => 1).returns(subject)
99
+ subject.find(1)
100
+ end
101
+ end
102
+ context 'with :all as the arg' do
103
+ it 'should call :all' do
104
+ subject.expects(:all)
105
+ subject.find(:all)
106
+ end
107
+ end
108
+ context 'with an array of ids' do
109
+ it 'should raise NotImplementedError' do
110
+ lambda { subject.find([1, 2, 3]) }.should raise_error(NotImplementedError)
111
+ end
112
+ end
113
+ context 'with query arguments' do
114
+ it 'should update the relation' do
115
+ subject.expects(:apply_finder_options).with(:arg1 => 2).returns(@rel)
116
+ subject.find(:first, :arg1 => 2)
117
+ end
118
+ end
119
+ end
120
+
121
+ describe 'exists?' do
122
+ it 'should add the where predicate for the id' do
123
+ @rel.expects(:where).with(:id => 3).returns(@rel)
124
+ @rel.exists?(3)
125
+ end
126
+ end
127
+
128
+ describe 'order' do
129
+ it 'should update the ordering' do
130
+ @rel2 = @rel.order(:attr1 => :desc).order(:attr2 => :asc)
131
+ @rel2.ordering.should eql([{:attr1 => :desc}, {:attr2 => :asc}])
132
+ end
133
+ end
134
+
135
+ describe 'where' do
136
+ it 'should merge the predicates' do
137
+ @rel2 = @rel.where(:attr1 => 1).where(:attr2 => 'foo')
138
+ @rel2.predicates.length.should eql(2)
139
+ end
140
+ it 'should accept a hash' do
141
+ @rel2 = @rel.where(:attr1 => 1)
142
+ @pred = @rel2.predicates.first
143
+ @pred.attribute.should eql(:attr1)
144
+ @pred.meth.should eql(:eq)
145
+ @pred.value.should eql(1)
146
+ end
147
+ it 'should accept an array' do
148
+ @rel2 = @rel.where([{:attr1 => 1}, {:attr2 => 'foo'}])
149
+ @pred = @rel2.predicates.first
150
+ @pred.attribute.should eql(:attr1)
151
+ @pred.meth.should eql(:eq)
152
+ @pred.value.should eql(1)
153
+ @pred = @rel2.predicates.last
154
+ @pred.attribute.should eql(:attr2)
155
+ @pred.meth.should eql(:eq)
156
+ @pred.value.should eql('foo')
157
+ end
158
+ it 'should accept a Predicate' do
159
+ @pred = NinjaModel::Predicate.new(:attr1, :ne, 3)
160
+ @rel2 = @rel.where(@pred)
161
+ @rel2.predicates.first.attribute.should eql(:attr1)
162
+ @rel2.predicates.first.meth.should eql(:ne)
163
+ @rel2.predicates.first.value.should eql(3)
164
+ end
165
+ it 'should accept a predicate symbol' do
166
+ @rel2 = @rel.where(:attr1.gt => 2)
167
+ @rel2.predicates.first.attribute.should eql(:attr1)
168
+ @rel2.predicates.first.meth.should eql(:gt)
169
+ @rel2.predicates.first.value.should eql(2)
170
+ end
171
+ it 'should raise an exception for an invalid attribute' do
172
+ lambda { @rel.where(:attr3 => 4) }.should raise_error(ArgumentError)
173
+ end
174
+ it 'should raise an error for an unsupported argument' do
175
+ lambda { @rel.where(1) }.should raise_error(ArgumentError)
176
+ end
177
+ it 'should raise an error for a string' do
178
+ lambda { @rel.where('attr4 = 5') }.should raise_error(ArgumentError)
179
+ end
180
+ it 'should raise an error for an unsupported hash key' do
181
+ lambda { @rel.where(1 => 34) }.should raise_error(ArgumentError)
182
+ end
183
+ end
184
+
185
+ describe 'limit' do
186
+ it 'should update the limit value' do
187
+ @rel2 = @rel.limit(5)
188
+ @rel2.limit_value.should eql(5)
189
+ @rel2 = @rel2.limit(10)
190
+ @rel2.limit_value.should eql(10)
191
+ end
192
+ end
193
+
194
+ describe 'when triggered' do
195
+ it 'should read from the adapter' do
196
+ @adapter.expects(:read)
197
+ subject.to_a
198
+ end
199
+ it 'should be loaded' do
200
+ subject.to_a
201
+ subject.loaded?.should be_true
202
+ end
203
+ it 'should not access the adapter when triggered a second time' do
204
+ subject.to_a
205
+ @adapter.expects(:read).never
206
+ subject.to_a
207
+ end
208
+ context 'with a valid result' do
209
+ before {
210
+ @records = [mock('Record')]
211
+ @adapter.stubs(:read).returns(@records)
212
+ }
213
+ its(:to_a) { should eql(@records) }
214
+ its(:size) { should eql(1) }
215
+ its(:blank?) { should be_false }
216
+ its(:empty?) { should be_false }
24
217
  end
25
218
  end
26
219
  end