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