ninja-model 0.4.2 → 0.5.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 (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