gorillib 0.4.0pre → 0.4.1pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/CHANGELOG.md +36 -1
  2. data/Gemfile +23 -19
  3. data/Guardfile +1 -1
  4. data/Rakefile +31 -31
  5. data/TODO.md +2 -30
  6. data/VERSION +1 -1
  7. data/examples/builder/ironfan.rb +4 -4
  8. data/gorillib.gemspec +40 -25
  9. data/lib/gorillib/array/average.rb +13 -0
  10. data/lib/gorillib/array/sorted_median.rb +11 -0
  11. data/lib/gorillib/array/sorted_percentile.rb +11 -0
  12. data/lib/gorillib/array/sorted_sample.rb +12 -0
  13. data/lib/gorillib/builder.rb +8 -14
  14. data/lib/gorillib/collection/has_collection.rb +31 -31
  15. data/lib/gorillib/collection/list_collection.rb +58 -0
  16. data/lib/gorillib/collection/model_collection.rb +63 -0
  17. data/lib/gorillib/collection.rb +57 -85
  18. data/lib/gorillib/logger/log.rb +26 -22
  19. data/lib/gorillib/model/base.rb +52 -39
  20. data/lib/gorillib/model/doc_string.rb +15 -0
  21. data/lib/gorillib/model/factories.rb +56 -61
  22. data/lib/gorillib/model/lint.rb +24 -0
  23. data/lib/gorillib/model/serialization.rb +12 -2
  24. data/lib/gorillib/model/validate.rb +2 -2
  25. data/lib/gorillib/pathname.rb +21 -6
  26. data/lib/gorillib/some.rb +2 -0
  27. data/lib/gorillib/type/extended.rb +0 -2
  28. data/lib/gorillib/type/url.rb +9 -0
  29. data/lib/gorillib/utils/console.rb +4 -1
  30. data/notes/HOWTO.md +22 -0
  31. data/notes/bucket.md +155 -0
  32. data/notes/builder.md +170 -0
  33. data/notes/collection.md +81 -0
  34. data/notes/factories.md +86 -0
  35. data/notes/model-overlay.md +209 -0
  36. data/notes/model.md +135 -0
  37. data/notes/structured-data-classes.md +127 -0
  38. data/spec/array/average_spec.rb +24 -0
  39. data/spec/array/sorted_median_spec.rb +18 -0
  40. data/spec/array/sorted_percentile_spec.rb +24 -0
  41. data/spec/array/sorted_sample_spec.rb +28 -0
  42. data/spec/gorillib/builder_spec.rb +46 -28
  43. data/spec/gorillib/collection_spec.rb +195 -10
  44. data/spec/gorillib/model/lint_spec.rb +28 -0
  45. data/spec/gorillib/model/record/factories_spec.rb +27 -13
  46. data/spec/gorillib/model/serialization_spec.rb +3 -5
  47. data/spec/gorillib/model_spec.rb +86 -104
  48. data/spec/spec_helper.rb +2 -1
  49. data/spec/support/gorillib_test_helpers.rb +83 -7
  50. data/spec/support/model_test_helpers.rb +9 -28
  51. metadata +52 -44
  52. data/lib/gorillib/configurable.rb +0 -28
  53. data/spec/gorillib/configurable_spec.rb +0 -62
  54. 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 'uses a factory directly' do
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 == ff
28
- Gorillib::Factory(Gorillib::Factory::SymbolFactory).should == Gorillib::Factory::SymbolFactory
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 == Gorillib::Factory::SymbolFactory
32
- Gorillib::Factory(:identical).should == Gorillib::Factory::IdenticalFactory
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 == Gorillib::Factory::SymbolFactory
36
- Gorillib::Factory(String).should == Gorillib::Factory::StringFactory
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 == described_class
95
+ Gorillib::Factory(key).should be_a(described_class)
90
96
  end
91
- Gorillib::Factory.send(:factories).to_hash.select{|key,val| val == described_class }.keys.should == keys
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 Gorillib::Factory::IdenticalFactory do
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
- it_behaves_like :it_is_registered_as, :identical, :whatever
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 ::Whatever do
185
- it{ described_class.should equal(Gorillib::Factory::IdenticalFactory) }
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)
@@ -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){ class Gorillib::Test::TestClass ; include Gorillib::Model ; field :my_field, Whatever ; self ; end }
9
- let(:anon_class){ Class.new{ include Gorillib::Model ; field :my_field, :whatever } }
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(:complex_subclass){ Gorillib::Test::TestSubclass = Class.new(complex_class){ field :zyzzyva, Integer; field :acme, Integer } }
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
- subject{ complex_class }
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 = complex_class.receive({
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
- obj = nested_class.receive({ :my_field => 69 })
36
- obj.attributes.should == { :my_field => 69, :str_field => nil, :sym_field=>nil, :another_model => nil }
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.attributes.should == { :my_field => 69 }
63
+ example_inst.compact_attributes.should == { :my_field => 69 }
47
64
  example_inst.write_attribute(:my_field, 3).should == 3
48
- example_inst.attributes.should == { :my_field => 3 }
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
- complex_class.field_names.should == [:my_field, :str_field, :sym_field]
53
- complex_subclass.field_names.should == [:my_field, :str_field, :sym_field, :zyzzyva, :acme]
54
- complex_class.field :banksy, String
55
- complex_class.field_names.should == [:my_field, :str_field, :sym_field, :banksy ]
56
- complex_subclass.field_names.should == [:my_field, :str_field, :sym_field, :banksy, :zyzzyva, :acme]
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(example_val)
61
- example_inst.my_field.should == example_val
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, example_val)
65
- (example_inst.my_field = example_val).should == example_val
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, example_val)
69
- (example_inst.receive_my_field(example_val)).should == example_inst
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
- subject.field :test_field, Integer, :reader => :private, :writer => false
73
- subject.public_instance_methods.should_not include(:test_field)
74
- subject.private_instance_methods.should include(:test_field)
75
- subject.public_instance_methods.should_not include(:test_field=)
76
- subject.private_instance_methods.should_not include(:test_field=)
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{ complex_class.new }
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 = subject.receive({:my_field=>7, :str_field=>'yo', :sym_field=>:sup})
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
- subject = Class.new{ include Gorillib::Model }
105
- subject.new.attributes.should == {}
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(subject) }
164
- let(:obj_2){ subject.receive(:my_field => 69) }
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 == obj_2
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
- subject.fields.keys.should == [:my_field, :str_field, :sym_field]
184
- subject.fields.values.each{|f| f.should be_a(Gorillib::Model::Field) }
185
- subject.fields.values.map(&:name).should == [:my_field, :str_field, :sym_field]
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
- complex_class.has_field?( :my_field).should be_true
192
- complex_subclass.has_field?(:my_field).should be_true
193
- complex_subclass.has_field?(:zyzzyva ).should be_true
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
- complex_class.has_field?( :zyzzyva).should be_false
197
- complex_class.has_field?( :fnord ).should be_false
198
- complex_subclass.has_field?(:fnord ).should be_false
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
- subject.field_names.should == [:my_field, :str_field, :sym_field]
205
- complex_subclass.field_names.should == [:my_field, :str_field, :sym_field, :zyzzyva, :acme]
206
- subject.field :banksy, String
207
- subject.field_names.should == [:my_field, :str_field, :sym_field, :banksy ]
208
- complex_subclass.field_names.should == [:my_field, :str_field, :sym_field, :banksy, :zyzzyva, :acme]
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
- subject.typename.should == 'gorillib.test.complex_model'
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
- subject.send(:meta_module).should == Meta::Gorillib::Test::TestClassType
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
- subject.send(:meta_module).public_instance_methods.sort.should == [:my_field, :my_field=, :receive_my_field]
265
- anon_class.send(:meta_module).public_instance_methods.sort.should == [:my_field, :my_field=, :receive_my_field]
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
- subject.ancestors.first(4).should == [subject, Meta::Gorillib::Test::TestClassType, Gorillib::Model, Object]
269
- subject.should < Meta::Gorillib::Test::TestClassType
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::TestClassType ; def kilroy_was_here() '23 skidoo' ; end ; end
274
- subject.send(:meta_module).public_instance_methods.sort.should == [:kilroy_was_here, :my_field, :my_field=, :receive_my_field]
275
- Gorillib::Test.should be_const_defined(:TestClass)
276
- subject.send(:meta_module).should == Meta::Gorillib::Test::TestClassType
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 "raises an error if the field does not exist" do
18
- ->{ subject.read_attribute(:fnord) }.should raise_error(Gorillib::Model::UnknownFieldError, /unknown field: 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 "raises an error if the field does not exist" do
31
- ->{ subject.write_attribute(:fnord, 8) }.should raise_error(Gorillib::Model::UnknownFieldError, /unknown field: fnord/)
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 "raises an error if the field does not exist" do
48
- ->{ subject.attribute_set?(:fnord) }.should raise_error(Gorillib::Model::UnknownFieldError, /unknown field: 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(:smurf_klass) do
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
- field :name, Symbol, :default => ->{ "#{owner? ? owner.name : ''} engine"}
32
- field :carburetor, Symbol, :default => :stock
33
- field :volume, Integer, :doc => 'displacement volume, in in^3'
34
- field :cylinders, Integer
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
- field :name, Symbol
46
- field :make_model, String
47
- field :year, Integer
48
- field :doors, Integer
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