spec/gorillib/model_spec.rb in gorillib-0.4.0pre vs spec/gorillib/model_spec.rb in gorillib-0.4.1pre
- old
+ new
@@ -2,93 +2,110 @@
require 'model_test_helpers'
require 'gorillib/model'
describe Gorillib::Model, :model_spec => true do
+ let(:smurf_class) do
+ class Gorillib::Test::Smurf
+ include Gorillib::Model
+ field :smurfiness, Integer
+ field :weapon, Symbol
+ end
+ Gorillib::Test::Smurf
+ end
+ let(:poppa_smurf ){ smurf_class.receive(:name => 'Poppa Smurf', :smurfiness => 9, :weapon => 'staff') }
+ let(:smurfette ){ smurf_class.receive(:name => 'Smurfette', :smurfiness => 11, :weapon => 'charm') }
- let(:simple_model){ class Gorillib::Test::TestClass ; include Gorillib::Model ; field :my_field, Whatever ; self ; end }
- let(:anon_class){ Class.new{ include Gorillib::Model ; field :my_field, :whatever } }
- let(:example_inst){ subject.receive(:my_field => 69) }
- let(:example_val){ mock('example val') }
-
- let(:complex_class) do
- class Gorillib::Test::ComplexModel
+ let(:simple_model) do
+ class Gorillib::Test::SimpleModel
include Gorillib::Model
field :my_field, :whatever
field :str_field, String
field :sym_field, Symbol
self
end
end
- let(:complex_subclass){ Gorillib::Test::TestSubclass = Class.new(complex_class){ field :zyzzyva, Integer; field :acme, Integer } }
+ let(:subclassed_model) do
+ class Gorillib::Test::SubclassedModel < simple_model ; field :zyzzyva, Integer; field :acme, Integer ; end
+ Gorillib::Test::SubclassedModel
+ end
+ let(:nested_model) do
+ smurf_class = self.smurf_class
+ Gorillib::Test::NestedModel = Class.new(simple_model){ field :smurf, smurf_class }
+ Gorillib::Test::NestedModel
+ end
- subject{ complex_class }
+ let(:described_class){ simple_model }
+ let(:example_inst){ described_class.receive(:my_field => 69) }
+ #
+ # IT BEHAVES LIKE A MODEL
+ # (maybe you wouldn't notice if it was just one little line)
+ #
+ it_behaves_like 'a model'
+
+ # --------------------------------------------------------------------------
+
context 'examples' do
- let(:nested_class){ Class.new(complex_class){ field :another_model, self } }
it 'type-converts values' do
- obj = complex_class.receive({
+ obj = simple_model.receive({
:my_field => 'accepted as-is', :str_field => :bob, :sym_field => 'converted_to_sym'
})
obj.attributes.should == { :my_field => 'accepted as-is', :str_field => 'bob', :sym_field=>:converted_to_sym }
end
it 'handles nested structures' do
- obj = nested_class.receive({ :my_field => 69 })
- obj.attributes.should == { :my_field => 69, :str_field => nil, :sym_field=>nil, :another_model => nil }
- deep_obj = nested_class.receive(:my_field => 111, :str_field => 'deep, man',
- :another_model => { :my_field => 69, :another_model => nil })
- deep_obj.attributes.should == { :my_field => 111, :str_field => 'deep, man', :sym_field=>nil, :another_model => obj }
+ deep_obj = nested_model.receive(:str_field => 'deep, man', :smurf => poppa_smurf.attributes)
+ deep_obj.attributes.should == { :str_field => 'deep, man', :smurf => poppa_smurf, :sym_field=>nil, :my_field => nil, }
end
end
context ".field" do
- subject{ simple_model }
it "describes an attribute" do
- example_inst.attributes.should == { :my_field => 69 }
+ example_inst.compact_attributes.should == { :my_field => 69 }
example_inst.write_attribute(:my_field, 3).should == 3
- example_inst.attributes.should == { :my_field => 3 }
+ example_inst.compact_attributes.should == { :my_field => 3 }
example_inst.read_attribute(:my_field).should == 3
end
it 'inherits fields from its parent class, even if they are added later' do
- complex_class.field_names.should == [:my_field, :str_field, :sym_field]
- complex_subclass.field_names.should == [:my_field, :str_field, :sym_field, :zyzzyva, :acme]
- complex_class.field :banksy, String
- complex_class.field_names.should == [:my_field, :str_field, :sym_field, :banksy ]
- complex_subclass.field_names.should == [:my_field, :str_field, :sym_field, :banksy, :zyzzyva, :acme]
+ simple_model.field_names.should == [:my_field, :str_field, :sym_field]
+ subclassed_model.field_names.should == [:my_field, :str_field, :sym_field, :zyzzyva, :acme]
+ simple_model.field :banksy, String
+ simple_model.field_names.should == [:my_field, :str_field, :sym_field, :banksy ]
+ subclassed_model.field_names.should == [:my_field, :str_field, :sym_field, :banksy, :zyzzyva, :acme]
end
it "supplies a reader method #foo to call read_attribute(:foo)" do
- example_inst.should_receive(:read_attribute).with(:my_field).and_return(example_val)
- example_inst.my_field.should == example_val
+ example_inst.should_receive(:read_attribute).with(:my_field).and_return(mock_val)
+ example_inst.my_field.should == mock_val
end
it "supplies a writer method #foo= to call write_attribute(:foo)" do
- example_inst.should_receive(:write_attribute).with(:my_field, example_val)
- (example_inst.my_field = example_val).should == example_val
+ example_inst.should_receive(:write_attribute).with(:my_field, mock_val)
+ (example_inst.my_field = mock_val).should == mock_val
end
it "supplies a receiver method #receive_foo to call write_attribute(:foo) and return self" do
- example_inst.should_receive(:write_attribute).with(:my_field, example_val)
- (example_inst.receive_my_field(example_val)).should == example_inst
+ example_inst.should_receive(:write_attribute).with(:my_field, mock_val)
+ (example_inst.receive_my_field(mock_val)).should == example_inst
end
it "sets visibility of reader with :reader => ()" do
- subject.field :test_field, Integer, :reader => :private, :writer => false
- subject.public_instance_methods.should_not include(:test_field)
- subject.private_instance_methods.should include(:test_field)
- subject.public_instance_methods.should_not include(:test_field=)
- subject.private_instance_methods.should_not include(:test_field=)
+ described_class.field :test_field, Integer, :reader => :private, :writer => false
+ described_class.public_instance_methods.should_not include(:test_field)
+ described_class.private_instance_methods.should include(:test_field)
+ described_class.public_instance_methods.should_not include(:test_field=)
+ described_class.private_instance_methods.should_not include(:test_field=)
end
end
context '.field' do
- subject{ complex_class.new }
+ subject{ described_class.new }
let(:sample_val){ 'bob' }
let(:raw_val){ :bob }
it_behaves_like 'a model field', :str_field
end
context '#attributes' do
it "maps field names to attribute values" do
- example_inst = subject.receive({:my_field=>7, :str_field=>'yo', :sym_field=>:sup})
+ example_inst = simple_model.receive({:my_field=>7, :str_field=>'yo', :sym_field=>:sup})
example_inst.attributes.should == {:my_field=>7, :str_field=>'yo', :sym_field=>:sup}
end
it "includes all field names, set and unset" do
example_inst.attributes.should == {:my_field=>69, :str_field=>nil, :sym_field=>nil}
example_inst.receive!(:my_field=>7, :str_field=>'yo')
@@ -99,12 +116,12 @@
example_inst.should_receive(:read_attribute).with(:str_field).and_return('str')
example_inst.should_receive(:read_attribute).with(:sym_field).and_return('sym')
example_inst.attributes.should == {:my_field=>'int', :str_field=>'str', :sym_field=>'sym'}
end
it "is an empty hash if there are no fields" do
- subject = Class.new{ include Gorillib::Model }
- subject.new.attributes.should == {}
+ model_with_no_fields = Class.new{ include Gorillib::Model }
+ model_with_no_fields.new.attributes.should == {}
end
end
context '#unset_attribute' do
it "unsets the attribute" do
@@ -114,13 +131,10 @@
end
it "if set, returns the former value" do
example_inst.unset_attribute(:my_field ).should == 69
example_inst.unset_attribute(:str_field).should == nil
end
- it "raises an error if the field does not exist" do
- ->{ example_inst.unset_attribute(:fnord) }.should raise_error(Gorillib::Model::UnknownFieldError, /unknown field: fnord/)
- end
end
context '#update_attributes' do
it "consumes a map from field names to new values" do
example_inst.attributes.should == {:my_field=>69, :str_field=>nil, :sym_field=>nil}
@@ -158,123 +172,91 @@
example_inst.receive! 'my_field'=>7, :str_field=>'yo'
end
end
context '#== -- two models are equal if' do
- let(:subklass){ Class.new(subject) }
- let(:obj_2){ subject.receive(:my_field => 69) }
+ let(:subklass){ Class.new(described_class) }
+ let(:obj_2){ described_class.receive(:my_field => 69) }
let(:obj_3){ subklass.receive(:my_field => 69) }
it 'they have the same class' do
example_inst.attributes.should == obj_2.attributes
example_inst.attributes.should == obj_3.attributes
example_inst.should == obj_2
example_inst.should_not == obj_3
end
it 'and the same attributes' do
example_inst.attributes.should == obj_2.attributes
- example_inst.should == obj_2
+ example_inst.should == obj_2
obj_2.my_field = 100
example_inst.should_not == obj_2
end
end
context ".fields" do
it 'is a hash of Gorillib::Model::Field objects' do
- subject.fields.keys.should == [:my_field, :str_field, :sym_field]
- subject.fields.values.each{|f| f.should be_a(Gorillib::Model::Field) }
- subject.fields.values.map(&:name).should == [:my_field, :str_field, :sym_field]
+ described_class.fields.keys.should == [:my_field, :str_field, :sym_field]
+ described_class.fields.values.each{|f| f.should be_a(Gorillib::Model::Field) }
+ described_class.fields.values.map(&:name).should == [:my_field, :str_field, :sym_field]
end
end
context '.has_field?' do
it 'is true if the field exists' do
- complex_class.has_field?( :my_field).should be_true
- complex_subclass.has_field?(:my_field).should be_true
- complex_subclass.has_field?(:zyzzyva ).should be_true
+ simple_model.has_field?( :my_field).should be_true
+ subclassed_model.has_field?(:my_field).should be_true
+ subclassed_model.has_field?(:zyzzyva ).should be_true
end
it 'is false if it does not exist' do
- complex_class.has_field?( :zyzzyva).should be_false
- complex_class.has_field?( :fnord ).should be_false
- complex_subclass.has_field?(:fnord ).should be_false
+ simple_model.has_field?( :zyzzyva).should be_false
+ simple_model.has_field?( :fnord ).should be_false
+ subclassed_model.has_field?(:fnord ).should be_false
end
end
context '.field_names' do
it 'lists fields in order by class, then in order added' do
- subject.field_names.should == [:my_field, :str_field, :sym_field]
- complex_subclass.field_names.should == [:my_field, :str_field, :sym_field, :zyzzyva, :acme]
- subject.field :banksy, String
- subject.field_names.should == [:my_field, :str_field, :sym_field, :banksy ]
- complex_subclass.field_names.should == [:my_field, :str_field, :sym_field, :banksy, :zyzzyva, :acme]
+ described_class.field_names.should == [:my_field, :str_field, :sym_field]
+ subclassed_model.field_names.should == [:my_field, :str_field, :sym_field, :zyzzyva, :acme]
+ described_class.field :banksy, String
+ described_class.field_names.should == [:my_field, :str_field, :sym_field, :banksy ]
+ subclassed_model.field_names.should == [:my_field, :str_field, :sym_field, :banksy, :zyzzyva, :acme]
end
end
context '.typename' do
it 'has a typename that matches its underscored class name' do
- subject.typename.should == 'gorillib.test.complex_model'
+ described_class.typename.should == 'gorillib.test.simple_model'
end
end
- context '.receive' do
- it 'creates a new instance' do
- obj = example_inst
- subject.should_receive(:new).with().and_return(obj)
- result = subject.receive(:my_field => 12)
- result.should equal(obj)
- result.my_field.should == 12
- end
- it 'calls receive! to set the attributes, and returns the object' do
- obj = example_inst
- subject.should_receive(:new).with().and_return(obj)
- obj.should_receive(:receive!).with(:my_field => 12)
- subject.receive(:my_field => 12).should equal(obj)
- end
-
- it 'uses the given type if the _type attribute is a factory' do
- obj = complex_class.receive(:my_field => 12, :acme => 3, :_type => complex_subclass)
- obj.should be_a(complex_subclass)
- end
-
- it 'complains if the given type is not right' do
- mock_factory = mock ; mock_factory.stub(:receive! => {}, :receive => mock, :new => mock_factory)
- mock_factory.should_receive(:<=).and_return(false)
- complex_class.should_receive(:warn).with(/doesn't match type/)
- complex_class.receive(:my_field => 12, :acme => 3, :_type => mock_factory)
- end
-
- it 'uses the given type if the _type attribute is a typename' do
- complex_subclass.typename.should == 'gorillib.test.test_subclass'
- obj = complex_class.receive(:my_field => 12, :acme => 3, :_type => 'gorillib.test.test_subclass')
- obj.should be_a(complex_subclass)
- end
- end
-
describe Gorillib::Model::NamedSchema do
- subject{ simple_model }
context ".meta_module" do
+ 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= ]}
+ let(:anon_class){ Class.new{ include Gorillib::Model ; field :my_field, :whatever } }
+
it "is named for the class (if the class is named)" do
- subject.send(:meta_module).should == Meta::Gorillib::Test::TestClassType
+ described_class.send(:meta_module).should == Meta::Gorillib::Test::SimpleModelType
end
it "is anonymous if the class is anonymous" do
anon_class.name.should be_nil
anon_class.send(:meta_module).should be_a(Module)
anon_class.send(:meta_module).name.should be_nil
end
it "carries the field-specfic accessor and receive methods" do
- subject.send(:meta_module).public_instance_methods.sort.should == [:my_field, :my_field=, :receive_my_field]
- anon_class.send(:meta_module).public_instance_methods.sort.should == [:my_field, :my_field=, :receive_my_field]
+ described_class.send(:meta_module).public_instance_methods.sort.should == basic_field_names
+ anon_class.send(:meta_module).public_instance_methods.sort.should == [:my_field, :my_field=, :receive_my_field]
end
it "is injected right after the Gorillib::Model module" do
- subject.ancestors.first(4).should == [subject, Meta::Gorillib::Test::TestClassType, Gorillib::Model, Object]
- subject.should < Meta::Gorillib::Test::TestClassType
+ described_class.ancestors.first(4).should == [described_class, Meta::Gorillib::Test::SimpleModelType, Gorillib::Model, Object]
+ described_class.should < Meta::Gorillib::Test::SimpleModelType
end
it "retrieves an existing named module if one exists" do
Gorillib::Test.should_not be_const_defined(:TestClass)
- module Meta::Gorillib::Test::TestClassType ; def kilroy_was_here() '23 skidoo' ; end ; end
- subject.send(:meta_module).public_instance_methods.sort.should == [:kilroy_was_here, :my_field, :my_field=, :receive_my_field]
- Gorillib::Test.should be_const_defined(:TestClass)
- subject.send(:meta_module).should == Meta::Gorillib::Test::TestClassType
+ module Meta::Gorillib::Test::SimpleModelType ; def kilroy_was_here() '23 skidoo' ; end ; end
+ described_class.send(:meta_module).public_instance_methods.sort.should == (basic_field_names + [:kilroy_was_here]).sort
+ Gorillib::Test.should be_const_defined(:SimpleModel)
+ described_class.send(:meta_module).should == Meta::Gorillib::Test::SimpleModelType
end
end
end
end