gorillib 0.4.0pre → 0.4.1pre
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.
- 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
|