gorillib 0.4.0pre → 0.4.1pre
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +36 -1
- data/Gemfile +23 -19
- data/Guardfile +1 -1
- data/Rakefile +31 -31
- data/TODO.md +2 -30
- data/VERSION +1 -1
- data/examples/builder/ironfan.rb +4 -4
- data/gorillib.gemspec +40 -25
- data/lib/gorillib/array/average.rb +13 -0
- data/lib/gorillib/array/sorted_median.rb +11 -0
- data/lib/gorillib/array/sorted_percentile.rb +11 -0
- data/lib/gorillib/array/sorted_sample.rb +12 -0
- data/lib/gorillib/builder.rb +8 -14
- data/lib/gorillib/collection/has_collection.rb +31 -31
- data/lib/gorillib/collection/list_collection.rb +58 -0
- data/lib/gorillib/collection/model_collection.rb +63 -0
- data/lib/gorillib/collection.rb +57 -85
- data/lib/gorillib/logger/log.rb +26 -22
- data/lib/gorillib/model/base.rb +52 -39
- data/lib/gorillib/model/doc_string.rb +15 -0
- data/lib/gorillib/model/factories.rb +56 -61
- data/lib/gorillib/model/lint.rb +24 -0
- data/lib/gorillib/model/serialization.rb +12 -2
- data/lib/gorillib/model/validate.rb +2 -2
- data/lib/gorillib/pathname.rb +21 -6
- data/lib/gorillib/some.rb +2 -0
- data/lib/gorillib/type/extended.rb +0 -2
- data/lib/gorillib/type/url.rb +9 -0
- data/lib/gorillib/utils/console.rb +4 -1
- data/notes/HOWTO.md +22 -0
- data/notes/bucket.md +155 -0
- data/notes/builder.md +170 -0
- data/notes/collection.md +81 -0
- data/notes/factories.md +86 -0
- data/notes/model-overlay.md +209 -0
- data/notes/model.md +135 -0
- data/notes/structured-data-classes.md +127 -0
- data/spec/array/average_spec.rb +24 -0
- data/spec/array/sorted_median_spec.rb +18 -0
- data/spec/array/sorted_percentile_spec.rb +24 -0
- data/spec/array/sorted_sample_spec.rb +28 -0
- data/spec/gorillib/builder_spec.rb +46 -28
- data/spec/gorillib/collection_spec.rb +195 -10
- data/spec/gorillib/model/lint_spec.rb +28 -0
- data/spec/gorillib/model/record/factories_spec.rb +27 -13
- data/spec/gorillib/model/serialization_spec.rb +3 -5
- data/spec/gorillib/model_spec.rb +86 -104
- data/spec/spec_helper.rb +2 -1
- data/spec/support/gorillib_test_helpers.rb +83 -7
- data/spec/support/model_test_helpers.rb +9 -28
- metadata +52 -44
- data/lib/gorillib/configurable.rb +0 -28
- data/spec/gorillib/configurable_spec.rb +0 -62
- data/spec/support/shared_examples/included_module.rb +0 -20
@@ -22,18 +22,24 @@ describe '', :model_spec => true do
|
|
22
22
|
ff = Gorillib::Factory( ->(obj){ "bob says #{obj}" } )
|
23
23
|
ff.receive(3).should == "bob says 3"
|
24
24
|
end
|
25
|
-
it '
|
25
|
+
it 'returns anything that responds to #receive directly' do
|
26
|
+
ff = Object.new ; ff.define_singleton_method(:receive){}
|
27
|
+
Gorillib::Factory(ff).should equal(ff)
|
28
|
+
end
|
29
|
+
it 'returns a factory directly' do
|
26
30
|
ff = Gorillib::Factory::SymbolFactory.new
|
27
|
-
Gorillib::Factory(ff).should
|
28
|
-
|
31
|
+
Gorillib::Factory(ff).should equal(ff)
|
32
|
+
end
|
33
|
+
it 'does not look up factory **classes**' do
|
34
|
+
->{ Gorillib::Factory(Gorillib::Factory::SymbolFactory) }.should raise_error(ArgumentError, /Don\'t know which factory makes/)
|
29
35
|
end
|
30
36
|
it 'looks up factories by typename' do
|
31
|
-
Gorillib::Factory(:symbol ).should
|
32
|
-
Gorillib::Factory(:identical).should ==
|
37
|
+
Gorillib::Factory(:symbol ).should be_a(Gorillib::Factory::SymbolFactory)
|
38
|
+
Gorillib::Factory(:identical).should == (::Whatever)
|
33
39
|
end
|
34
40
|
it 'looks up factories by class' do
|
35
|
-
Gorillib::Factory(Symbol).should
|
36
|
-
Gorillib::Factory(String).should
|
41
|
+
Gorillib::Factory(Symbol).should be_a(Gorillib::Factory::SymbolFactory)
|
42
|
+
Gorillib::Factory(String).should be_a(Gorillib::Factory::StringFactory)
|
37
43
|
end
|
38
44
|
it 'calls Gorillib::Factory.receive' do
|
39
45
|
x = mock
|
@@ -86,9 +92,10 @@ describe '', :model_spec => true do
|
|
86
92
|
shared_examples_for :it_is_registered_as do |*keys|
|
87
93
|
it "the factory for #{keys}" do
|
88
94
|
keys.each do |key|
|
89
|
-
Gorillib::Factory(key).should
|
95
|
+
Gorillib::Factory(key).should be_a(described_class)
|
90
96
|
end
|
91
|
-
Gorillib::Factory
|
97
|
+
its_factory = Gorillib::Factory(keys.first)
|
98
|
+
Gorillib::Factory.send(:factories).to_hash.select{|key,val| val.equal?(its_factory) }.keys.should == keys
|
92
99
|
end
|
93
100
|
end
|
94
101
|
|
@@ -177,12 +184,19 @@ describe '', :model_spec => true do
|
|
177
184
|
its(:typename){ should == :boolean }
|
178
185
|
end
|
179
186
|
|
180
|
-
describe
|
187
|
+
describe ::Whatever do
|
181
188
|
it_behaves_like :it_considers_native, true, false, nil, 3, '', 'a string', :a_symbol, [], {}, ->(){ 'a proc' }, Module.new, Complex(1,3), Object.new
|
182
|
-
|
189
|
+
it "it is itself the factory for :identical and :whatever" do
|
190
|
+
keys = [Whatever, :identical, :whatever]
|
191
|
+
keys.each do |key|
|
192
|
+
Gorillib::Factory(key).should equal(described_class)
|
193
|
+
end
|
194
|
+
its_factory = ::Whatever
|
195
|
+
Gorillib::Factory.send(:factories).to_hash.select{|key,val| val.equal?(its_factory) }.keys.should == keys
|
196
|
+
end
|
183
197
|
end
|
184
|
-
describe ::
|
185
|
-
it{ described_class.should equal(
|
198
|
+
describe Gorillib::Factory::IdenticalFactory do
|
199
|
+
it{ described_class.should equal(Whatever) }
|
186
200
|
end
|
187
201
|
|
188
202
|
describe Gorillib::Factory::ModuleFactory do
|
@@ -1,8 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'model_test_helpers'
|
3
3
|
|
4
|
-
require 'json'
|
5
|
-
|
6
4
|
require 'multi_json'
|
7
5
|
#
|
8
6
|
require 'gorillib/model'
|
@@ -17,13 +15,13 @@ describe Gorillib::Model, :model_spec => true do
|
|
17
15
|
end
|
18
16
|
let :wired_garage_hash do
|
19
17
|
{ :cars => [
|
20
|
-
{:name=>:wildcat, :make_model=>"Buick Wildcat", :year=>1968, :doors=>2, :engine=>{:name=>" engine", :carburetor=>:stock, :volume=>455, :cylinders=>8, :owner=>nil}},
|
21
|
-
{:name=>:ford_39, :make_model=>"Ford Tudor Sedan", :year=>1939, :doors=>2, :engine=>nil}, ] }
|
18
|
+
{:name=>:wildcat, :make_model=>"Buick Wildcat", :year=>1968, :doors=>2, :engine=>{:name=>" engine", :carburetor=>:stock, :volume=>455, :cylinders=>8, :owner=>nil, :_type => "gorillib.test.engine"}, :_type => "gorillib.test.car"},
|
19
|
+
{:name=>:ford_39, :make_model=>"Ford Tudor Sedan", :year=>1939, :doors=>2, :engine=>nil, :_type => "gorillib.test.car"}, ], :_type => "gorillib.test.garage" }
|
22
20
|
end
|
23
21
|
|
24
22
|
describe 'to_json' do
|
25
23
|
it 'recursively serializes' do
|
26
|
-
MultiJson.load(wildcat.to_json).should == {"name"=>"wildcat","make_model"=>"Buick Wildcat","year"=>1968,"doors"=>2,"engine"=>{"name"=>" engine","carburetor"=>"stock","volume"=>455,"cylinders"=>8,"owner"=>nil}}
|
24
|
+
MultiJson.load(wildcat.to_json).should == {"name"=>"wildcat","make_model"=>"Buick Wildcat","year"=>1968,"doors"=>2,"engine"=>{"name"=>" engine","carburetor"=>"stock","volume"=>455,"cylinders"=>8,"owner"=>nil,"_type"=>"gorillib.test.engine"},"_type"=>"gorillib.test.car"}
|
27
25
|
end
|
28
26
|
it 'recursively serializes' do
|
29
27
|
subject.to_json.should == MultiJson.dump(wired_garage_hash)
|
data/spec/gorillib/model_spec.rb
CHANGED
@@ -4,14 +4,19 @@ require 'model_test_helpers'
|
|
4
4
|
require 'gorillib/model'
|
5
5
|
|
6
6
|
describe Gorillib::Model, :model_spec => true do
|
7
|
+
let(:smurf_class) do
|
8
|
+
class Gorillib::Test::Smurf
|
9
|
+
include Gorillib::Model
|
10
|
+
field :smurfiness, Integer
|
11
|
+
field :weapon, Symbol
|
12
|
+
end
|
13
|
+
Gorillib::Test::Smurf
|
14
|
+
end
|
15
|
+
let(:poppa_smurf ){ smurf_class.receive(:name => 'Poppa Smurf', :smurfiness => 9, :weapon => 'staff') }
|
16
|
+
let(:smurfette ){ smurf_class.receive(:name => 'Smurfette', :smurfiness => 11, :weapon => 'charm') }
|
7
17
|
|
8
|
-
let(:simple_model)
|
9
|
-
|
10
|
-
let(:example_inst){ subject.receive(:my_field => 69) }
|
11
|
-
let(:example_val){ mock('example val') }
|
12
|
-
|
13
|
-
let(:complex_class) do
|
14
|
-
class Gorillib::Test::ComplexModel
|
18
|
+
let(:simple_model) do
|
19
|
+
class Gorillib::Test::SimpleModel
|
15
20
|
include Gorillib::Model
|
16
21
|
field :my_field, :whatever
|
17
22
|
field :str_field, String
|
@@ -19,66 +24,78 @@ describe Gorillib::Model, :model_spec => true do
|
|
19
24
|
self
|
20
25
|
end
|
21
26
|
end
|
22
|
-
let(:
|
27
|
+
let(:subclassed_model) do
|
28
|
+
class Gorillib::Test::SubclassedModel < simple_model ; field :zyzzyva, Integer; field :acme, Integer ; end
|
29
|
+
Gorillib::Test::SubclassedModel
|
30
|
+
end
|
31
|
+
let(:nested_model) do
|
32
|
+
smurf_class = self.smurf_class
|
33
|
+
Gorillib::Test::NestedModel = Class.new(simple_model){ field :smurf, smurf_class }
|
34
|
+
Gorillib::Test::NestedModel
|
35
|
+
end
|
23
36
|
|
24
|
-
|
37
|
+
let(:described_class){ simple_model }
|
38
|
+
let(:example_inst){ described_class.receive(:my_field => 69) }
|
39
|
+
|
40
|
+
#
|
41
|
+
# IT BEHAVES LIKE A MODEL
|
42
|
+
# (maybe you wouldn't notice if it was just one little line)
|
43
|
+
#
|
44
|
+
it_behaves_like 'a model'
|
45
|
+
|
46
|
+
# --------------------------------------------------------------------------
|
25
47
|
|
26
48
|
context 'examples' do
|
27
|
-
let(:nested_class){ Class.new(complex_class){ field :another_model, self } }
|
28
49
|
it 'type-converts values' do
|
29
|
-
obj =
|
50
|
+
obj = simple_model.receive({
|
30
51
|
:my_field => 'accepted as-is', :str_field => :bob, :sym_field => 'converted_to_sym'
|
31
52
|
})
|
32
53
|
obj.attributes.should == { :my_field => 'accepted as-is', :str_field => 'bob', :sym_field=>:converted_to_sym }
|
33
54
|
end
|
34
55
|
it 'handles nested structures' do
|
35
|
-
|
36
|
-
|
37
|
-
deep_obj = nested_class.receive(:my_field => 111, :str_field => 'deep, man',
|
38
|
-
:another_model => { :my_field => 69, :another_model => nil })
|
39
|
-
deep_obj.attributes.should == { :my_field => 111, :str_field => 'deep, man', :sym_field=>nil, :another_model => obj }
|
56
|
+
deep_obj = nested_model.receive(:str_field => 'deep, man', :smurf => poppa_smurf.attributes)
|
57
|
+
deep_obj.attributes.should == { :str_field => 'deep, man', :smurf => poppa_smurf, :sym_field=>nil, :my_field => nil, }
|
40
58
|
end
|
41
59
|
end
|
42
60
|
|
43
61
|
context ".field" do
|
44
|
-
subject{ simple_model }
|
45
62
|
it "describes an attribute" do
|
46
|
-
example_inst.
|
63
|
+
example_inst.compact_attributes.should == { :my_field => 69 }
|
47
64
|
example_inst.write_attribute(:my_field, 3).should == 3
|
48
|
-
example_inst.
|
65
|
+
example_inst.compact_attributes.should == { :my_field => 3 }
|
49
66
|
example_inst.read_attribute(:my_field).should == 3
|
50
67
|
end
|
51
68
|
it 'inherits fields from its parent class, even if they are added later' do
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
69
|
+
simple_model.field_names.should == [:my_field, :str_field, :sym_field]
|
70
|
+
subclassed_model.field_names.should == [:my_field, :str_field, :sym_field, :zyzzyva, :acme]
|
71
|
+
simple_model.field :banksy, String
|
72
|
+
simple_model.field_names.should == [:my_field, :str_field, :sym_field, :banksy ]
|
73
|
+
subclassed_model.field_names.should == [:my_field, :str_field, :sym_field, :banksy, :zyzzyva, :acme]
|
57
74
|
end
|
58
75
|
|
59
76
|
it "supplies a reader method #foo to call read_attribute(:foo)" do
|
60
|
-
example_inst.should_receive(:read_attribute).with(:my_field).and_return(
|
61
|
-
example_inst.my_field.should ==
|
77
|
+
example_inst.should_receive(:read_attribute).with(:my_field).and_return(mock_val)
|
78
|
+
example_inst.my_field.should == mock_val
|
62
79
|
end
|
63
80
|
it "supplies a writer method #foo= to call write_attribute(:foo)" do
|
64
|
-
example_inst.should_receive(:write_attribute).with(:my_field,
|
65
|
-
(example_inst.my_field =
|
81
|
+
example_inst.should_receive(:write_attribute).with(:my_field, mock_val)
|
82
|
+
(example_inst.my_field = mock_val).should == mock_val
|
66
83
|
end
|
67
84
|
it "supplies a receiver method #receive_foo to call write_attribute(:foo) and return self" do
|
68
|
-
example_inst.should_receive(:write_attribute).with(:my_field,
|
69
|
-
(example_inst.receive_my_field(
|
85
|
+
example_inst.should_receive(:write_attribute).with(:my_field, mock_val)
|
86
|
+
(example_inst.receive_my_field(mock_val)).should == example_inst
|
70
87
|
end
|
71
88
|
it "sets visibility of reader with :reader => ()" do
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
89
|
+
described_class.field :test_field, Integer, :reader => :private, :writer => false
|
90
|
+
described_class.public_instance_methods.should_not include(:test_field)
|
91
|
+
described_class.private_instance_methods.should include(:test_field)
|
92
|
+
described_class.public_instance_methods.should_not include(:test_field=)
|
93
|
+
described_class.private_instance_methods.should_not include(:test_field=)
|
77
94
|
end
|
78
95
|
end
|
79
96
|
|
80
97
|
context '.field' do
|
81
|
-
subject{
|
98
|
+
subject{ described_class.new }
|
82
99
|
let(:sample_val){ 'bob' }
|
83
100
|
let(:raw_val){ :bob }
|
84
101
|
it_behaves_like 'a model field', :str_field
|
@@ -86,7 +103,7 @@ describe Gorillib::Model, :model_spec => true do
|
|
86
103
|
|
87
104
|
context '#attributes' do
|
88
105
|
it "maps field names to attribute values" do
|
89
|
-
example_inst =
|
106
|
+
example_inst = simple_model.receive({:my_field=>7, :str_field=>'yo', :sym_field=>:sup})
|
90
107
|
example_inst.attributes.should == {:my_field=>7, :str_field=>'yo', :sym_field=>:sup}
|
91
108
|
end
|
92
109
|
it "includes all field names, set and unset" do
|
@@ -101,8 +118,8 @@ describe Gorillib::Model, :model_spec => true do
|
|
101
118
|
example_inst.attributes.should == {:my_field=>'int', :str_field=>'str', :sym_field=>'sym'}
|
102
119
|
end
|
103
120
|
it "is an empty hash if there are no fields" do
|
104
|
-
|
105
|
-
|
121
|
+
model_with_no_fields = Class.new{ include Gorillib::Model }
|
122
|
+
model_with_no_fields.new.attributes.should == {}
|
106
123
|
end
|
107
124
|
end
|
108
125
|
|
@@ -116,9 +133,6 @@ describe Gorillib::Model, :model_spec => true do
|
|
116
133
|
example_inst.unset_attribute(:my_field ).should == 69
|
117
134
|
example_inst.unset_attribute(:str_field).should == nil
|
118
135
|
end
|
119
|
-
it "raises an error if the field does not exist" do
|
120
|
-
->{ example_inst.unset_attribute(:fnord) }.should raise_error(Gorillib::Model::UnknownFieldError, /unknown field: fnord/)
|
121
|
-
end
|
122
136
|
end
|
123
137
|
|
124
138
|
context '#update_attributes' do
|
@@ -160,8 +174,8 @@ describe Gorillib::Model, :model_spec => true do
|
|
160
174
|
end
|
161
175
|
|
162
176
|
context '#== -- two models are equal if' do
|
163
|
-
let(:subklass){ Class.new(
|
164
|
-
let(:obj_2){
|
177
|
+
let(:subklass){ Class.new(described_class) }
|
178
|
+
let(:obj_2){ described_class.receive(:my_field => 69) }
|
165
179
|
let(:obj_3){ subklass.receive(:my_field => 69) }
|
166
180
|
|
167
181
|
it 'they have the same class' do
|
@@ -172,7 +186,7 @@ describe Gorillib::Model, :model_spec => true do
|
|
172
186
|
end
|
173
187
|
it 'and the same attributes' do
|
174
188
|
example_inst.attributes.should == obj_2.attributes
|
175
|
-
example_inst.should
|
189
|
+
example_inst.should == obj_2
|
176
190
|
obj_2.my_field = 100
|
177
191
|
example_inst.should_not == obj_2
|
178
192
|
end
|
@@ -180,80 +194,48 @@ describe Gorillib::Model, :model_spec => true do
|
|
180
194
|
|
181
195
|
context ".fields" do
|
182
196
|
it 'is a hash of Gorillib::Model::Field objects' do
|
183
|
-
|
184
|
-
|
185
|
-
|
197
|
+
described_class.fields.keys.should == [:my_field, :str_field, :sym_field]
|
198
|
+
described_class.fields.values.each{|f| f.should be_a(Gorillib::Model::Field) }
|
199
|
+
described_class.fields.values.map(&:name).should == [:my_field, :str_field, :sym_field]
|
186
200
|
end
|
187
201
|
end
|
188
202
|
|
189
203
|
context '.has_field?' do
|
190
204
|
it 'is true if the field exists' do
|
191
|
-
|
192
|
-
|
193
|
-
|
205
|
+
simple_model.has_field?( :my_field).should be_true
|
206
|
+
subclassed_model.has_field?(:my_field).should be_true
|
207
|
+
subclassed_model.has_field?(:zyzzyva ).should be_true
|
194
208
|
end
|
195
209
|
it 'is false if it does not exist' do
|
196
|
-
|
197
|
-
|
198
|
-
|
210
|
+
simple_model.has_field?( :zyzzyva).should be_false
|
211
|
+
simple_model.has_field?( :fnord ).should be_false
|
212
|
+
subclassed_model.has_field?(:fnord ).should be_false
|
199
213
|
end
|
200
214
|
end
|
201
215
|
|
202
216
|
context '.field_names' do
|
203
217
|
it 'lists fields in order by class, then in order added' do
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
218
|
+
described_class.field_names.should == [:my_field, :str_field, :sym_field]
|
219
|
+
subclassed_model.field_names.should == [:my_field, :str_field, :sym_field, :zyzzyva, :acme]
|
220
|
+
described_class.field :banksy, String
|
221
|
+
described_class.field_names.should == [:my_field, :str_field, :sym_field, :banksy ]
|
222
|
+
subclassed_model.field_names.should == [:my_field, :str_field, :sym_field, :banksy, :zyzzyva, :acme]
|
209
223
|
end
|
210
224
|
end
|
211
225
|
|
212
226
|
context '.typename' do
|
213
227
|
it 'has a typename that matches its underscored class name' do
|
214
|
-
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
context '.receive' do
|
219
|
-
it 'creates a new instance' do
|
220
|
-
obj = example_inst
|
221
|
-
subject.should_receive(:new).with().and_return(obj)
|
222
|
-
result = subject.receive(:my_field => 12)
|
223
|
-
result.should equal(obj)
|
224
|
-
result.my_field.should == 12
|
225
|
-
end
|
226
|
-
it 'calls receive! to set the attributes, and returns the object' do
|
227
|
-
obj = example_inst
|
228
|
-
subject.should_receive(:new).with().and_return(obj)
|
229
|
-
obj.should_receive(:receive!).with(:my_field => 12)
|
230
|
-
subject.receive(:my_field => 12).should equal(obj)
|
231
|
-
end
|
232
|
-
|
233
|
-
it 'uses the given type if the _type attribute is a factory' do
|
234
|
-
obj = complex_class.receive(:my_field => 12, :acme => 3, :_type => complex_subclass)
|
235
|
-
obj.should be_a(complex_subclass)
|
236
|
-
end
|
237
|
-
|
238
|
-
it 'complains if the given type is not right' do
|
239
|
-
mock_factory = mock ; mock_factory.stub(:receive! => {}, :receive => mock, :new => mock_factory)
|
240
|
-
mock_factory.should_receive(:<=).and_return(false)
|
241
|
-
complex_class.should_receive(:warn).with(/doesn't match type/)
|
242
|
-
complex_class.receive(:my_field => 12, :acme => 3, :_type => mock_factory)
|
243
|
-
end
|
244
|
-
|
245
|
-
it 'uses the given type if the _type attribute is a typename' do
|
246
|
-
complex_subclass.typename.should == 'gorillib.test.test_subclass'
|
247
|
-
obj = complex_class.receive(:my_field => 12, :acme => 3, :_type => 'gorillib.test.test_subclass')
|
248
|
-
obj.should be_a(complex_subclass)
|
228
|
+
described_class.typename.should == 'gorillib.test.simple_model'
|
249
229
|
end
|
250
230
|
end
|
251
231
|
|
252
232
|
describe Gorillib::Model::NamedSchema do
|
253
|
-
subject{ simple_model }
|
254
233
|
context ".meta_module" do
|
234
|
+
let(:basic_field_names){ [ :my_field, :my_field=, :receive_my_field, :receive_str_field, :receive_sym_field, :str_field, :str_field=, :sym_field, :sym_field= ]}
|
235
|
+
let(:anon_class){ Class.new{ include Gorillib::Model ; field :my_field, :whatever } }
|
236
|
+
|
255
237
|
it "is named for the class (if the class is named)" do
|
256
|
-
|
238
|
+
described_class.send(:meta_module).should == Meta::Gorillib::Test::SimpleModelType
|
257
239
|
end
|
258
240
|
it "is anonymous if the class is anonymous" do
|
259
241
|
anon_class.name.should be_nil
|
@@ -261,19 +243,19 @@ describe Gorillib::Model, :model_spec => true do
|
|
261
243
|
anon_class.send(:meta_module).name.should be_nil
|
262
244
|
end
|
263
245
|
it "carries the field-specfic accessor and receive methods" do
|
264
|
-
|
265
|
-
anon_class.send(:meta_module).public_instance_methods.sort.should
|
246
|
+
described_class.send(:meta_module).public_instance_methods.sort.should == basic_field_names
|
247
|
+
anon_class.send(:meta_module).public_instance_methods.sort.should == [:my_field, :my_field=, :receive_my_field]
|
266
248
|
end
|
267
249
|
it "is injected right after the Gorillib::Model module" do
|
268
|
-
|
269
|
-
|
250
|
+
described_class.ancestors.first(4).should == [described_class, Meta::Gorillib::Test::SimpleModelType, Gorillib::Model, Object]
|
251
|
+
described_class.should < Meta::Gorillib::Test::SimpleModelType
|
270
252
|
end
|
271
253
|
it "retrieves an existing named module if one exists" do
|
272
254
|
Gorillib::Test.should_not be_const_defined(:TestClass)
|
273
|
-
module Meta::Gorillib::Test::
|
274
|
-
|
275
|
-
Gorillib::Test.should be_const_defined(:
|
276
|
-
|
255
|
+
module Meta::Gorillib::Test::SimpleModelType ; def kilroy_was_here() '23 skidoo' ; end ; end
|
256
|
+
described_class.send(:meta_module).public_instance_methods.sort.should == (basic_field_names + [:kilroy_was_here]).sort
|
257
|
+
Gorillib::Test.should be_const_defined(:SimpleModel)
|
258
|
+
described_class.send(:meta_module).should == Meta::Gorillib::Test::SimpleModelType
|
277
259
|
end
|
278
260
|
end
|
279
261
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -12,8 +12,9 @@ $LOAD_PATH.unshift(GORILLIB_ROOT_DIR('lib'))
|
|
12
12
|
$LOAD_PATH.unshift(GORILLIB_ROOT_DIR('spec/support'))
|
13
13
|
require 'gorillib_test_helpers'
|
14
14
|
Dir[GORILLIB_ROOT_DIR('spec/support/matchers/*.rb')].each {|f| require f}
|
15
|
-
Dir[GORILLIB_ROOT_DIR('spec/support/shared_examples/*.rb')].each {|f| require f}
|
16
15
|
|
17
16
|
RSpec.configure do |config|
|
18
17
|
include Gorillib::TestHelpers
|
18
|
+
|
19
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
19
20
|
end
|
@@ -1,6 +1,83 @@
|
|
1
1
|
require 'gorillib/utils/capture_output'
|
2
2
|
require 'gorillib/utils/nuke_constants'
|
3
3
|
|
4
|
+
shared_examples_for 'a model' do
|
5
|
+
|
6
|
+
context 'initialize' do
|
7
|
+
it "has no required args" do
|
8
|
+
obj = smurf_class.new
|
9
|
+
obj.compact_attributes.should == {}
|
10
|
+
end
|
11
|
+
it "takes the last hashlike arg as the attributes" do
|
12
|
+
obj = smurf_class.new :smurfiness => 3, :weapon => :smurfchucks
|
13
|
+
obj.compact_attributes.should == { :smurfiness => 3, :weapon => :smurfchucks }
|
14
|
+
end
|
15
|
+
it "takes all preceding args as positional, clobbering values set in attrs" do
|
16
|
+
obj = smurf_class.new 7, :smurfing_stars
|
17
|
+
obj.compact_attributes.should == { :smurfiness => 7, :weapon => :smurfing_stars }
|
18
|
+
obj = smurf_class.new 7, :smurfing_stars, :smurfiness => 3, :weapon => :smurfchucks
|
19
|
+
obj.compact_attributes.should == { :smurfiness => 7, :weapon => :smurfing_stars }
|
20
|
+
end
|
21
|
+
it "does nothing special with a nil positional arg -- it clobbers anything there setting the attribute to nil" do
|
22
|
+
obj = smurf_class.new nil, :smurfiness => 3
|
23
|
+
obj.compact_attributes.should == { :smurfiness => nil }
|
24
|
+
end
|
25
|
+
it "raises an error if too many positional args are given" do
|
26
|
+
->{ smurf_class.new 7, :smurfing_stars, :azrael }.should raise_error(ArgumentError, /wrong number of arguments.*3.*0\.\.2/)
|
27
|
+
end
|
28
|
+
it "always takes the last hash arg as the attrs -- even if it is in the positional slot of a hash field" do
|
29
|
+
smurf_class.field :hashie, Hash
|
30
|
+
obj = smurf_class.new({:smurfiness => 3, :weapon => :smurfchucks})
|
31
|
+
obj.compact_attributes.should == { :smurfiness => 3, :weapon => :smurfchucks }
|
32
|
+
obj = smurf_class.new(3, :smurfchucks, { :weapon => :bastard_smurf })
|
33
|
+
obj.compact_attributes.should == { :smurfiness => 3, :weapon => :smurfchucks }
|
34
|
+
obj = smurf_class.new(3, :smurfchucks, {:this => :that}, { :weapon => :bastard_smurf })
|
35
|
+
obj.compact_attributes.should == { :smurfiness => 3, :weapon => :smurfchucks, :hashie => {:this => :that} }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'receive' do
|
40
|
+
let(:my_attrs){ { :smurfiness => 900, :weapon => :wood_smurfer } }
|
41
|
+
let(:subklass){ class ::Gorillib::Test::SubSmurf < smurf_class ; end ; ::Gorillib::Test::SubSmurf }
|
42
|
+
|
43
|
+
it "returns nil if given a single nil arg" do
|
44
|
+
smurf_class.receive(nil).should == nil
|
45
|
+
end
|
46
|
+
it "returns the object if given a single object of the model class" do
|
47
|
+
smurf_class.receive(poppa_smurf).should equal(poppa_smurf)
|
48
|
+
end
|
49
|
+
it "raises an error if the attributes are not hashlike" do
|
50
|
+
->{ smurf_class.receive('DURRRR') }.should raise_error(ArgumentError, /attributes .* like a hash: "DURRRR"/)
|
51
|
+
end
|
52
|
+
context "with hashlike args," do
|
53
|
+
before{ Gorillib::Factory.send(:factories).reject!{|th, type| th.to_s =~ /gorillib\.test/ }}
|
54
|
+
|
55
|
+
it "instantiates the object, passing it the attrs and block" do
|
56
|
+
my_attrs = { :smurfiness => 900, :weapon => :wood_smurfer }
|
57
|
+
smurf_class.should_receive(:new).with(my_attrs)
|
58
|
+
smurf_class.receive(my_attrs)
|
59
|
+
end
|
60
|
+
it "retrieves the right factory if :_type is present" do
|
61
|
+
my_attrs = self.my_attrs.merge(:_type => 'gorillib.test.smurf')
|
62
|
+
smurf_class.should_receive(:new).with(my_attrs)
|
63
|
+
smurf_class.receive(my_attrs)
|
64
|
+
end
|
65
|
+
it "retrieves the right factory if :_type is present" do
|
66
|
+
my_attrs = self.my_attrs.merge(:_type => 'gorillib.test.sub_smurf')
|
67
|
+
subklass.should_receive(:new).with(my_attrs)
|
68
|
+
smurf_class.receive(my_attrs)
|
69
|
+
end
|
70
|
+
it 'complains if the given type is not right' do
|
71
|
+
mock_factory = mock ; mock_factory.stub(:receive! => {}, :receive => mock, :new => mock_factory)
|
72
|
+
mock_factory.should_receive(:<=).and_return(false)
|
73
|
+
smurf_class.should_receive(:warn).with(/factory .* is not a type of Gorillib::Test::Smurf/)
|
74
|
+
smurf_class.receive(:my_field => 12, :acme => 3, :_type => mock_factory)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
4
81
|
shared_examples_for "a model field" do |field_name|
|
5
82
|
it('gives the model a field'){ subject.class.should have_field(field_name) }
|
6
83
|
|
@@ -10,12 +87,11 @@ shared_examples_for "a model field" do |field_name|
|
|
10
87
|
subject.read_attribute(field_name).should == sample_val
|
11
88
|
end
|
12
89
|
it "if unset, calls #read_unset_attribute" do
|
13
|
-
mock_val = mock
|
14
90
|
subject.should_receive(:read_unset_attribute).with(field_name).and_return(mock_val)
|
15
91
|
subject.read_attribute(field_name).should == mock_val
|
16
92
|
end
|
17
|
-
it "
|
18
|
-
->{ subject.read_attribute(:fnord) }.
|
93
|
+
it "does **not** raise an error if the field does not exist (require 'model/lint' if you want it to)" do
|
94
|
+
->{ subject.read_attribute(:fnord) }.should_not raise_error(Gorillib::Model::UnknownFieldError, /unknown field: fnord/)
|
19
95
|
end
|
20
96
|
end
|
21
97
|
|
@@ -27,8 +103,8 @@ shared_examples_for "a model field" do |field_name|
|
|
27
103
|
it('returns the new value') do
|
28
104
|
subject.write_attribute(field_name, sample_val).should == sample_val
|
29
105
|
end
|
30
|
-
it "
|
31
|
-
->{ subject.write_attribute(:fnord, 8) }.
|
106
|
+
it "does **not** raise an error if the field does not exist (require 'model/lint' if you want it to)" do
|
107
|
+
->{ subject.write_attribute(:fnord, 8) }.should_not raise_error(Gorillib::Model::UnknownFieldError, /unknown field: fnord/)
|
32
108
|
end
|
33
109
|
end
|
34
110
|
|
@@ -44,8 +120,8 @@ shared_examples_for "a model field" do |field_name|
|
|
44
120
|
it('is false if never written') do
|
45
121
|
subject.attribute_set?(field_name).should be_false
|
46
122
|
end
|
47
|
-
it "
|
48
|
-
->{ subject.attribute_set?(:fnord) }.
|
123
|
+
it "does **not** raise an error if the field does not exist (require 'model/lint' if you want it to)" do
|
124
|
+
->{ subject.attribute_set?(:fnord) }.should_not raise_error(Gorillib::Model::UnknownFieldError, /unknown field: fnord/)
|
49
125
|
end
|
50
126
|
end
|
51
127
|
|
@@ -4,34 +4,15 @@ module Meta ; module Gorillib ; module Test ; end ; end ; end
|
|
4
4
|
shared_context 'model', :model_spec => true do
|
5
5
|
after(:each){ Gorillib::Test.nuke_constants ; Meta::Gorillib::Test.nuke_constants }
|
6
6
|
|
7
|
-
let(:
|
8
|
-
class Gorillib::Test::Smurf
|
9
|
-
include Gorillib::Model
|
10
|
-
|
11
|
-
field :smurfiness, Integer
|
12
|
-
field :weapon, Symbol
|
13
|
-
end
|
14
|
-
Gorillib::Test::Smurf
|
15
|
-
end
|
16
|
-
|
17
|
-
let(:smurfette_klass) do
|
18
|
-
class Gorillib::Test::Smurfette < smurf_klass
|
19
|
-
field :blondness, Boolean
|
20
|
-
end
|
21
|
-
Gorillib::Test::Smurfette
|
22
|
-
end
|
23
|
-
|
24
|
-
let(:poppa_smurf ){ smurf_klass.receive(:name => 'Poppa Smurf', :smurfiness => 9, :weapon => 'staff') }
|
25
|
-
let(:smurfette ){ smurf_klass.receive(:name => 'Smurfette', :smurfiness => 11, :weapon => 'charm') }
|
26
|
-
let(:generic_smurf){ smurf_klass.receive(:name => 'Generic Smurf', :smurfiness => 2, :weapon => 'fists') }
|
7
|
+
let(:mock_val){ mock('mock value') }
|
27
8
|
|
28
9
|
let(:engine_class) do
|
29
10
|
class Gorillib::Test::Engine
|
30
11
|
include Gorillib::Builder
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
12
|
+
magic :name, Symbol, :default => ->{ "#{owner? ? owner.name : ''} engine"}
|
13
|
+
magic :carburetor, Symbol, :default => :stock
|
14
|
+
magic :volume, Integer, :doc => 'displacement volume, in in^3'
|
15
|
+
magic :cylinders, Integer
|
35
16
|
member :owner, Whatever
|
36
17
|
self
|
37
18
|
end
|
@@ -42,10 +23,10 @@ shared_context 'model', :model_spec => true do
|
|
42
23
|
engine_class
|
43
24
|
class Gorillib::Test::Car
|
44
25
|
include Gorillib::Builder
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
26
|
+
magic :name, Symbol
|
27
|
+
magic :make_model, String
|
28
|
+
magic :year, Integer
|
29
|
+
magic :doors, Integer
|
49
30
|
member :engine, Gorillib::Test::Engine
|
50
31
|
self
|
51
32
|
end
|