require_relative '../spec_helper' describe 'Base' do class FooClass include ::Plotrb::Base end class BarClass end class BazClass end describe 'ClassMethods' do let(:foo) { Class.new { include ::Plotrb::Base } } describe '.attributes' do it 'has attributes' do foo.respond_to?(:attributes).should be_true end end describe '.add_attributes' do before(:each) do foo.class_eval { add_attributes :foo_foo } end it 'keeps track of all attributes defined for class' do foo.attributes.should match_array([:foo_foo]) end it 'adds setter method for the attribute' do bar = foo.new bar.foo_foo = 1 bar.instance_variable_get(:@foo_foo).should == 1 end end end describe '#attributes' do let(:foo) { FooClass.new } before(:each) do foo.singleton_class.class_eval { add_attributes :foo_foo } end it 'tracks both class-defined and instance-defined attributes' do foo.add_attributes(:bar_bar) foo.attributes.should match_array([:foo_foo, :bar_bar]) end end describe '#set_attribuets' do let(:foo) { FooClass.new } it 'creates attributes and sets values' do foo.set_attributes(a: 1, b: 2) foo.attributes.should match_array([:a, :b]) foo.instance_variable_get(:@a).should == 1 foo.instance_variable_get(:@b).should == 2 end end describe '#add_attributes' do let(:foo) { FooClass.new } let(:bar) { FooClass.new } before(:each) do FooClass.add_attributes(:foo_class) end it 'adds attributes to specific instance only' do foo.add_attributes(:foo_foo) bar.add_attributes(:bar_bar) foo.attributes.should match_array([:foo_class, :foo_foo]) bar.attributes.should match_array([:foo_class, :bar_bar]) end end describe '#defined_attributes' do let(:foo) { FooClass.new } it 'only returns non-nil attributes' do foo.set_attributes(a: 1, b: 2, c: nil) foo.defined_attributes.should match_array([:a, :b]) end end describe '#collect_attributes' do let(:foo) { FooClass.new } let(:bar) { BarClass.new } let(:baz) { BazClass.new } before(:each) do foo.add_attributes(:attr) foo.stub(:attribute_post_processing) end it 'recursively collects attributes' do BarClass.any_instance.stub(:respond_to?).with(:collect_attributes). and_return(true) BarClass.any_instance.stub(:collect_attributes).and_return('bar_values') foo.attr = bar foo.collect_attributes.should == { 'attr' => 'bar_values' } end it 'collects attributes of each of the array element' do BarClass.any_instance.stub(:respond_to?).with(:collect_attributes). and_return(true) BazClass.any_instance.stub(:respond_to?).with(:collect_attributes). and_return(true) BarClass.any_instance.stub(:collect_attributes).and_return('bar_values') BazClass.any_instance.stub(:collect_attributes).and_return('baz_values') foo.attr = [bar, baz] foo.collect_attributes.should == { 'attr' => %w(bar_values baz_values)} end end describe '#define_boolean_attribute' do let(:foo) { FooClass.new } before(:each) do foo.define_boolean_attribute(:bar) end it 'creates setter' do foo.respond_to?(:bar).should be_true end it 'sets attribute to true when called' do foo.bar foo.instance_variable_get('@bar').should == true end it 'creates getter' do foo.respond_to?(:bar?).should be_true end end describe '#define_single_val_attribute' do let(:foo) { FooClass.new } context 'when no proc is provided' do before(:each) do foo.define_single_val_attribute(:bar) end it 'creates setter and getter' do foo.respond_to?(:bar).should be_true end it 'acts as getter when no argument is provided' do foo.should_receive(:instance_variable_get).with('@bar') foo.bar end it 'sets value of the attribute if provided' do foo.should_receive(:instance_variable_set).with('@bar', 1) foo.bar(1) end it 'raises error if more than one value is given' do expect { foo.bar(1,2,3) }.to raise_error(ArgumentError) end end context 'when a proc is provided' do it 'process the value before assigning to the attribute' do p = lambda { |x| x + 1} foo.define_single_val_attribute(:bar, p) foo.bar(1) foo.bar.should == 2 end it 'raises error if condition check fails in proc' do p = lambda { |x| if x > 0 x + 1 else raise ArgumentError end } foo.define_single_val_attribute(:bar, p) foo.bar(1) foo.bar.should == 2 expect { foo.bar(0) }.to raise_error(ArgumentError) end end end describe '#define_multi_val_attribute' do let(:foo) { FooClass.new } context 'when no proc is provided' do before(:each) do foo.define_multi_val_attribute(:bar) end it 'creates setter and getter' do foo.respond_to?(:bar).should be_true end it 'acts as getter when no argument is provided' do foo.should_receive(:instance_variable_get).with('@bar') foo.bar end it 'sets single value of the attribute if provided' do foo.should_receive(:instance_variable_set).with('@bar', [1]) foo.bar(1) end it 'sets array of values' do foo.should_receive(:instance_variable_set).with('@bar', [1, 2, 3]) foo.bar([1, 2, 3]) end it 'sets multiple values' do foo.should_receive(:instance_variable_set).with('@bar', [1, 2, 3]) foo.bar(1,2,3) end end context 'when a proc is provided' do it 'process the values before assigning to the attribute' do p = lambda { |*x| x.each { |v| v + 1 } } foo.define_multi_val_attribute(:bar, p) foo.bar(1,2,3) foo.bar.should == [1, 2, 3] end it 'is able to check argument size' do p = lambda { |x, y, z| [x + 1, y + 1, z + 1] } foo.define_multi_val_attribute(:bar, p) foo.bar(1,2,3) foo.bar.should == [2, 3, 4] expect { foo.bar(1,2,3,4) }.to raise_error(ArgumentError) end end end describe '#classify' do let(:foo) { Class.new { extend ::Plotrb::Base } } it 'classifies string' do foo.classify('visualization').should == 'Visualization' end it 'changes snake_case to CamelCase' do foo.classify('foo_bar').should == 'FooBar' end it 'changes snake_case to camelCaseInJson' do foo.classify('foo_bar_baz', :json).should == 'fooBarBaz' end end describe 'Hash' do describe '#reverse_merge' do it 'should respond to reverse_merge' do Hash.new.respond_to?(:reverse_merge).should be_true end it 'reverse merges hash' do hash = {a: 1, b: 2} default = {a:2, c:3} hash.reverse_merge(default).should == {a: 1, b: 2, c: 3} end end describe '#collect_attributes' do it 'should respond to collect_attributes' do Hash.new.respond_to?(:collect_attributes).should be_true end it 'recursively collects attributes' do hash = {foo: FooClass.new, bar: BarClass.new} FooClass.any_instance.stub(:collect_attributes).and_return('foo_value') BarClass.any_instance.stub(:collect_attributes).and_return('bar_value') hash.collect_attributes.should == {'foo' => 'foo_value', 'bar' => 'bar_value'} end end end end