spec/blobject_spec.rb in blobject-0.2.3 vs spec/blobject_spec.rb in blobject-0.3.2

- old
+ new

@@ -1,155 +1,277 @@ -require 'spec_helper' +require 'spec/env' require 'blobject' describe Blobject do - - let(:blobject){Blobject.new} - - it 'should not be able to assign to a blobject outside of a modify block using =' do - expect { - blobject.name = 'hello' - - }.to raise_error + + def b + @b ||= Blobject.new end - - it 'should not be able to assign to a blobject outside of a modify block without =' do - expect { - blobject.name 'hello' - }.to raise_error - end + + it 'raises an error if the call is not a reader, writer or checker' do + + proc do + b.fish_for :salmon, :sole + end.must_raise NoMethodError + + proc do + b.checker_with_an_arg? :this_should_not_be_here + end.must_raise NoMethodError + + end + + it 'provides access tot he internal hash with #hash' do + assert b.hash.equal?(b.instance_variable_get :@hash) + end + + it 'sets values when calling a writer' do + b.number = 123 + assert_equal b.number, 123 + end + + it 'sets objects n levels deep' do + b.name.nickname.back_at_school = 'Richard Head' + assert_equal b.name.nickname.back_at_school, 'Richard Head' + end + + it 'does not result in a graph containing empty blobjects' do + b.fish.food + assert !b.fish?, 'should not have assigned an empty blobject' + end + + it 'turns hashes into blobjects when assigning' do - it 'should raise an error when call members that have not been assign' do + b.name = { christian: "Vinnie", surname: "Jones" } - expect { - blobject.meow - }.to raise_error(NoMethodError) + assert_instance_of Blobject, b.name + assert_equal b.name.christian, "Vinnie" + assert_equal b.name.surname, "Jones" end - - describe '#empty?' do - it 'should return true on an empty blobject' do - blobject.should be_empty - end + + describe 'respond_to?' do - it 'should return false on an non-empty blobject' do - blobject.modify { name "Barry" } - blobject.should_not be_empty + it 'returns true if the blobject has the corresponding member' do + b.name = 'jim' + assert b.respond_to?(:name) + assert b.respond_to?(:name=) + assert b.respond_to?(:name?) end - end - - describe '#modify' do - - it 'should store assignment of variables to any depth in the object graph' do - - b = blobject.modify do - variable 'hello' - deep.object.graph.member 123 + + it 'should return true if a prohibited attribute name is a defined method' do + def b.to_ary + 123 end - - blobject.variable.should == 'hello' - blobject.deep.object.graph.member.should == 123 + assert b.respond_to? :to_ary end - - it 'should not handle more than one parameter' do - expect { - blobject.modify do - name(1, 2) - end - }.to raise_error(NoMethodError) + + it 'should return false if the methods ends with a !' do + refute b.respond_to? :hello! end - - it 'should return an empty blobject when a non-existing member is called' do - blobject.modify do - b = name - name.should be_instance_of Blobject - name.should be_empty - end + + it 'returns true if the blobject has no corresponding member' do + b.name = 'jim' + assert b.respond_to?(:name) + assert b.respond_to?(:name=) + assert b.respond_to?(:name?) end - - it 'should allow assignment chaining' do - blobject.modify do - name.first('Barry').last('Watkins') - end - - blobject.name.first.should == 'Barry' - blobject.name.last.should == 'Watkins' + + it 'should return true if the blobject has the corresponding member but the accessor has not been memoized' do + b = Blobject.new :name => 'barry' + assert b.respond_to?(:name) + assert b.respond_to?(:name=) + assert b.respond_to?(:name?) end - - it 'should return self' do - rtn = blobject.modify {} - rtn.should equal blobject + + it 'returns false for :to_ary because that method is not allowed' do + refute Blobject.new.respond_to? :to_ary end + end + + describe 'to_hash' do + + it 'should recursively reify the blobject into a hash' do + b.name.first = 'barry' + b.number = 123456 + + h = b.to_hash + + assert_instance_of Hash, h + assert_instance_of Hash, h[:name] + assert_equal h[:number], 123456 + assert_equal h[:name][:first], 'barry' + end + end + + describe 'from_json' do - it 'should allow for nested modification blocks' do + describe 'array' do - blobject.modify do - - name.middle = 'mittens' - - # makes sure that previously assigned members can be modified with a block - - name do - first 'barry' - last 'mcdoodle' - end + it 'returns an array with blobjects not hashes' do + json = '[1, true, {"meaning": false}]' + array = Blobject.from_json json + + assert_instance_of Array, array + assert_equal array[0], 1 + assert_equal array[1], true + assert_instance_of Blobject, array[2] end + end + + describe 'json object' do - blobject.name.first.should == 'barry' - blobject.name.last.should == 'mcdoodle' - + it 'returns a blobject which' do + json = '{"name": {"first": "doogle"}}' + b = Blobject.from_json json + assert_equal b.name.first, 'doogle' + assert b.name? + + end end end - describe '#has_<name>' do - - it 'should return true when we have a member of name' do - blobject.modify {name 'barry'} - blobject.should have_name + describe 'initialize' do + it 'takes an initial value as a hash' do + b = Blobject.new :inner => {:nested => :hash}, :value => 12345 + assert_equal b.value, 12345 + assert b.inner? + assert_equal b.inner.nested, :hash end - - it 'should return false otherwise' do - blobject.should_not have_name + + it 'recurses through the initial hash turning hashes into blobjects' do + b = Blobject.new :name => {:first => 'doogle', :last => 'mcfoogle'} + assert_instance_of Blobject, b.name + assert_equal b.name.first, 'doogle' end + + it 'yields to a block with self as a parameter' do + b = Blobject.new do |b| + b.name = 'yield' + end + + assert_equal 'yield', b.name + end end - - describe '#[]' do - it 'allows get via hash like dereferencing' do - blobject.modify {name 'rod'} - blobject[:name].should == 'rod' + + describe 'checking' do + + it 'returns true if the attribute exists' do + b.fish = 'bass' + assert b.fish? end - - it 'nil should be returned for a key miss' do - blobject[:name].should == nil + + it 'returns false if the attribute does not exist' do + assert !b.fish? end - end - - describe '#[]=' do - it 'should relay to send' do - blobject.should_receive(:send).with(:name, 'barry') - blobject[:name] = 'barry' + + it 'does not indicate the boolean status of the value' do + b.fish = false + assert b.fish? end end - describe '#merge' do - let(:data) do - { :one => 1, - :rest => [2,3,4,5,6,{:number => 7},8,9,0], - :nested => { - :structure => 'of values' - } } + describe 'memoization' do + + it 'creates checker, reader and writer memoize methods after they are called the first time' do + + b.method_unlikely_already_to_be_defined = 123 + + b.methods.must_include :method_unlikely_already_to_be_defined + b.methods.must_include :method_unlikely_already_to_be_defined= + b.methods.must_include :method_unlikely_already_to_be_defined? + + b.another_method_unlikely_already_to_be_defined + + b.methods.must_include :another_method_unlikely_already_to_be_defined + b.methods.must_include :another_method_unlikely_already_to_be_defined= + b.methods.must_include :another_method_unlikely_already_to_be_defined? + + b.yet_another_method_unlikely_already_to_be_defined? + + b.methods.must_include :another_method_unlikely_already_to_be_defined + b.methods.must_include :another_method_unlikely_already_to_be_defined= + b.methods.must_include :another_method_unlikely_already_to_be_defined? end - - it 'should return self' do - blobject.merge({}).should equal blobject + + it 'does not redefine existing members' do + + def b.hello + 123 + end + + b.hello=456 + + assert_equal 123, b.hello + + def b.oink= v + @oink = v + end + + b.oink = 123 + + b.hash[:oink] = 456 + + def b.oink_value + @oink + end + + assert_equal 123, b.oink_value + end - - it 'should populate itself with the hash' do - blobject.merge data - blobject.one.should == 1 - blobject.rest[5].should be_instance_of(Blobject) - blobject.rest[5].number.should == 7 - blobject.nested.structure.should == 'of values' + describe 'memoized reader' do + it 'returns an empty blobject' do + + b.name.first = 'Harry' + + b = Blobject.new + + assert !b.name.nil? + + b.name.first = 'Barry' + + assert_equal b.name.first, 'Barry' + end end end -end + describe 'frozen blobject' do + + before :each do + list_element = Blobject.new + + b.name.first = 'barry' + b.data.list = [1, 2, 3, list_element] + b.data.inner_hash = {:inner => {:one => 1}} + + b.freeze + end + + it 'still provides access' do + refute_nil b.name.first + end + + it 'freezes the internal hash' do + assert b.hash.frozen? + end + + it 'allows access to existing attributes' do + assert_equal b.name.first, 'barry' + end + + it 'recursively freezes nested Blobjects' do + assert b.frozen? + assert b.name.frozen? + assert b.data.list[3].frozen? + assert b.data.inner_hash.frozen? + end + + it 'raises an error when trying to set an attribute' do + proc { b.hello = 123 }.must_raise RuntimeError + end + + it 'returns nil when trying to get an attribute' do + assert b.meow_face.nil?, 'method missing returned something' + # check again to test memoized method + assert b.meow_face.nil?, 'memoized method returned something' + end + end +end \ No newline at end of file