spec/praxis-blueprints/blueprint_spec.rb in praxis-blueprints-2.0.1 vs spec/praxis-blueprints/blueprint_spec.rb in praxis-blueprints-2.1
- old
+ new
@@ -169,32 +169,57 @@
end
end
context '.describe' do
+ let(:shallow ) { false }
+ let(:example_object) { nil }
+
before do
- expect(blueprint_class.attribute.type).to receive(:describe).and_return(type_describe)
+ expect(blueprint_class.attribute.type).to receive(:describe).with(shallow, example: example_object).and_call_original #.and_return(type_describe)
end
- let(:type_describe){ {name: "Fake", id: "From Struct attr", other: "type attribute"} }
context 'for non-shallow descriptions' do
subject(:output){ blueprint_class.describe }
+
its([:name]){ should eq(blueprint_class.name)}
its([:id]){ should eq(blueprint_class.id)}
- its([:other]){ should eq("type attribute")}
its([:views]){ should be_kind_of(Hash)}
it 'should contain the an entry for each view' do
subject[:views].keys.should include(:default, :current, :extended, :master)
end
end
context 'for shallow descriptions' do
+ let(:shallow) { true }
+
it 'should not include views' do
blueprint_class.describe(true).key?(:views).should be(false)
end
end
+
+ context 'with an example' do
+ let(:example) { blueprint_class.example }
+ let(:example_object) { example.object }
+ let(:shallow) { false }
+
+ subject(:output) { blueprint_class.describe(false, example: example) }
+
+ it 'outputs examples for leaf values using the provided example' do
+ output[:attributes][:name][:example].should eq example.name
+ output[:attributes][:age][:example].should eq example.age
+
+ output[:attributes][:full_name].should_not have_key(:example)
+ output[:attributes][:aliases].should_not have_key(:example)
+
+ parents_attributes = output[:attributes][:parents][:type][:attributes]
+ parents_attributes[:father][:example].should eq example.parents.father
+ parents_attributes[:mother][:example].should eq example.parents.mother
+ end
+ end
end
+
context '.validate' do
let(:hash) { {name: 'bob'} }
let(:person) { Person.load(hash) }
subject(:errors) { person.validate }
@@ -205,219 +230,219 @@
context 'with invalid sub-attribute' do
let(:hash) { {name: 'bob', address: {state: "ME"}} }
it { should have(1).item }
its(:first) { should =~ /Attribute \$.address.state/ }
- end
+ end
- context 'for objects of the wrong type' do
- it 'raises an error' do
- expect {
- Person.validate(Object.new)
- }.to raise_error(ArgumentError, /Error validating .* as Person for an object of type Object/)
- end
- end
- end
+ context 'for objects of the wrong type' do
+ it 'raises an error' do
+ expect {
+ Person.validate(Object.new)
+ }.to raise_error(ArgumentError, /Error validating .* as Person for an object of type Object/)
+ end
+ end
+ end
- context '.load' do
- let(:hash) do
- {
- :name => 'Bob',
- :full_name => {:first => 'Robert', :last => 'Robertson'},
- :address => {:street => 'main', :state => 'OR'}
- }
- end
- subject(:person) { Person.load(hash) }
+ context '.load' do
+ let(:hash) do
+ {
+ :name => 'Bob',
+ :full_name => {:first => 'Robert', :last => 'Robertson'},
+ :address => {:street => 'main', :state => 'OR'}
+ }
+ end
+ subject(:person) { Person.load(hash) }
- it { should be_kind_of(Person) }
+ it { should be_kind_of(Person) }
- context 'recursively loading sub-attributes' do
- context 'for a Blueprint' do
- subject(:address) { person.address }
- it { should be_kind_of(Address) }
- end
- context 'for an Attributor::Model' do
- subject(:full_name) { person.full_name }
- it { should be_kind_of(FullName) }
- end
- end
+ context 'recursively loading sub-attributes' do
+ context 'for a Blueprint' do
+ subject(:address) { person.address }
+ it { should be_kind_of(Address) }
+ end
+ context 'for an Attributor::Model' do
+ subject(:full_name) { person.full_name }
+ it { should be_kind_of(FullName) }
+ end
+ end
- end
+ end
- context 'decorators' do
- let(:name) { 'Soren II' }
+ context 'decorators' do
+ let(:name) { 'Soren II' }
- let(:object) { Person.example.object }
- subject(:person) { Person.new(object, decorators) }
+ let(:object) { Person.example.object }
+ subject(:person) { Person.new(object, decorators) }
- context 'as a hash' do
- let(:decorators) { {name: name} }
- it do
- pers = person
- # binding.pry
- pers.name.should eq('Soren II')
- end
+ context 'as a hash' do
+ let(:decorators) { {name: name} }
+ it do
+ pers = person
+ # binding.pry
+ pers.name.should eq('Soren II')
+ end
- its(:name) { should be(name) }
+ its(:name) { should be(name) }
- context 'an additional instance with the equivalent hash' do
- subject(:additional_person) { Person.new(object, {name: name}) }
- it { should_not be person }
- end
+ context 'an additional instance with the equivalent hash' do
+ subject(:additional_person) { Person.new(object, {name: name}) }
+ it { should_not be person }
+ end
- context 'an additional instance with the same hash object' do
- subject(:additional_person) { Person.new(object, decorators) }
- it { should_not be person }
- end
+ context 'an additional instance with the same hash object' do
+ subject(:additional_person) { Person.new(object, decorators) }
+ it { should_not be person }
+ end
- context 'an instance of the same object without decorators' do
- subject(:additional_person) { Person.new(object) }
- it { should_not be person }
- end
- end
+ context 'an instance of the same object without decorators' do
+ subject(:additional_person) { Person.new(object) }
+ it { should_not be person }
+ end
+ end
- context 'as an object' do
- let(:decorators) { double("decorators", name: name) }
- its(:name) { should be(name) }
+ context 'as an object' do
+ let(:decorators) { double("decorators", name: name) }
+ its(:name) { should be(name) }
- context 'an additional instance with the same object' do
- subject(:additional_person) { Person.new(object, decorators) }
- it { should_not be person }
- end
- end
+ context 'an additional instance with the same object' do
+ subject(:additional_person) { Person.new(object, decorators) }
+ it { should_not be person }
+ end
+ end
- end
+ end
- context 'with a provided :reference option on attributes' do
- context 'that does not match the value set on the class' do
+ context 'with a provided :reference option on attributes' do
+ context 'that does not match the value set on the class' do
- subject(:mismatched_reference) do
- Class.new(Praxis::Blueprint) do
- self.reference = Class.new(Praxis::Blueprint)
- attributes(reference: Class.new(Praxis::Blueprint)) {}
- end
- end
+ subject(:mismatched_reference) do
+ Class.new(Praxis::Blueprint) do
+ self.reference = Class.new(Praxis::Blueprint)
+ attributes(reference: Class.new(Praxis::Blueprint)) {}
+ end
+ end
- it 'should raise an error' do
- expect {
- mismatched_reference.attributes
- }.to raise_error
- end
+ it 'should raise an error' do
+ expect {
+ mismatched_reference.attributes
+ }.to raise_error
+ end
- end
- end
+ end
+ end
- context '.example' do
- context 'with some attribute values provided' do
- let(:name) { 'Sir Bobbert' }
- subject(:person) { Person.example(name: name) }
- its(:name) { should eq(name) }
- end
- end
+ context '.example' do
+ context 'with some attribute values provided' do
+ let(:name) { 'Sir Bobbert' }
+ subject(:person) { Person.example(name: name) }
+ its(:name) { should eq(name) }
+ end
+ end
- context '.render' do
- let(:person) { Person.example }
- it 'is an alias to dump' do
- rendered = Person.render(person, view: :default)
- dumped = Person.dump(person, view: :default)
- expect(rendered).to eq(dumped)
- end
- end
+ context '.render' do
+ let(:person) { Person.example }
+ it 'is an alias to dump' do
+ rendered = Person.render(person, view: :default)
+ dumped = Person.dump(person, view: :default)
+ expect(rendered).to eq(dumped)
+ end
+ end
- context '#render' do
- let(:person) { Person.example }
- let(:view_name) { :default }
- let(:render_opts) { {} }
- subject(:output) { person.render(view: view_name, **render_opts) }
+ context '#render' do
+ let(:person) { Person.example }
+ let(:view_name) { :default }
+ let(:render_opts) { {} }
+ subject(:output) { person.render(view: view_name, **render_opts) }
- context 'caches rendered views' do
- it 'in the instance, by view name' do
- person.instance_variable_get(:@rendered_views)[view_name].should be_nil
- person.render(view: view_name)
- cached = person.instance_variable_get(:@rendered_views)[view_name]
- cached.should_not be_nil
- end
+ context 'caches rendered views' do
+ it 'in the instance, by view name' do
+ person.instance_variable_get(:@rendered_views)[view_name].should be_nil
+ person.render(view: view_name)
+ cached = person.instance_variable_get(:@rendered_views)[view_name]
+ cached.should_not be_nil
+ end
- it 'and does not re-render a view if one is already cached' do
- rendered1 = person.render(view: view_name)
- rendered2 = person.render(view: view_name)
- rendered1.should be(rendered2)
- end
+ it 'and does not re-render a view if one is already cached' do
+ rendered1 = person.render(view: view_name)
+ rendered2 = person.render(view: view_name)
+ rendered1.should be(rendered2)
+ end
- context 'even when :fields are specified' do
- let(:render_opts) { {fields: {email: nil, age: nil, address: {street: nil, state: nil}}} }
+ context 'even when :fields are specified' do
+ let(:render_opts) { {fields: {email: nil, age: nil, address: {street: nil, state: nil}}} }
- it 'caches the output in a different key than just the view_name' do
- plain_view_render = person.render(view: view_name)
- fields_render = person.render(view: view_name, **render_opts)
- plain_view_render.should_not be(fields_render)
- end
+ it 'caches the output in a different key than just the view_name' do
+ plain_view_render = person.render(view: view_name)
+ fields_render = person.render(view: view_name, **render_opts)
+ plain_view_render.should_not be(fields_render)
+ end
- it 'it still caches the object if rendered for the same fields' do
- rendered1 = person.render(view: view_name, **render_opts)
- rendered2 = person.render(view: view_name, **render_opts)
- rendered1.should be(rendered2)
- end
+ it 'it still caches the object if rendered for the same fields' do
+ rendered1 = person.render(view: view_name, **render_opts)
+ rendered2 = person.render(view: view_name, **render_opts)
+ rendered1.should be(rendered2)
+ end
- it 'it still caches the object if rendered for the same fields (even from an "equivalent" hash)' do
- rendered1 = person.render(view: view_name, **render_opts)
+ it 'it still caches the object if rendered for the same fields (even from an "equivalent" hash)' do
+ rendered1 = person.render(view: view_name, **render_opts)
- equivalent_render_opts = { fields: {age: nil, address: {state: nil, street: nil}, email: nil} }
- rendered2 = person.render(view: view_name, **equivalent_render_opts)
+ equivalent_render_opts = { fields: {age: nil, address: {state: nil, street: nil}, email: nil} }
+ rendered2 = person.render(view: view_name, **equivalent_render_opts)
- rendered1.should be(rendered2)
- end
- end
+ rendered1.should be(rendered2)
+ end
+ end
- end
+ end
- context 'with a sub-attribute that is a blueprint' do
+ context 'with a sub-attribute that is a blueprint' do
- it { should have_key(:name) }
- it { should have_key(:address) }
- it 'renders the sub-attribute correctly' do
- output[:address].should have_key(:street)
- output[:address].should have_key(:state)
- end
+ it { should have_key(:name) }
+ it { should have_key(:address) }
+ it 'renders the sub-attribute correctly' do
+ output[:address].should have_key(:street)
+ output[:address].should have_key(:state)
+ end
- it 'reports a dump error with the appropriate context' do
- person.address.should_receive(:state).and_raise("Kaboom")
- expect {
- person.render(view: view_name, context: ['special_root'])
- }.to raise_error(/Error while dumping attribute state of type Address for context special_root.address. Reason: .*Kaboom/)
- end
- end
+ it 'reports a dump error with the appropriate context' do
+ person.address.should_receive(:state).and_raise("Kaboom")
+ expect {
+ person.render(view: view_name, context: ['special_root'])
+ }.to raise_error(/Error while dumping attribute state of type Address for context special_root.address. Reason: .*Kaboom/)
+ end
+ end
- context 'with sub-attribute that is an Attributor::Model' do
- it { should have_key(:full_name) }
- it 'renders the model correctly' do
- output[:full_name].should be_kind_of(Hash)
- output[:full_name].should have_key(:first)
- output[:full_name].should have_key(:last)
- end
- end
+ context 'with sub-attribute that is an Attributor::Model' do
+ it { should have_key(:full_name) }
+ it 'renders the model correctly' do
+ output[:full_name].should be_kind_of(Hash)
+ output[:full_name].should have_key(:first)
+ output[:full_name].should have_key(:last)
+ end
+ end
- context 'using the `fields` option' do
- context 'as a hash' do
- subject(:output) { person.render(view: view_name, fields: {address: { state: nil} } ) }
- it 'should only have the address rendered' do
- output.keys.should == [:address]
- end
- it 'address should only have state' do
- output[:address].keys.should == [:state]
- end
- end
- context 'as a simple array' do
- subject(:output) { person.render(view: view_name, fields: [:address] ) }
- it 'accepts it as the list of top-level attributes to be rendered' do
- output.keys.should == [:address]
- end
- end
- end
- end
+ context 'using the `fields` option' do
+ context 'as a hash' do
+ subject(:output) { person.render(view: view_name, fields: {address: { state: nil} } ) }
+ it 'should only have the address rendered' do
+ output.keys.should == [:address]
+ end
+ it 'address should only have state' do
+ output[:address].keys.should == [:state]
+ end
+ end
+ context 'as a simple array' do
+ subject(:output) { person.render(view: view_name, fields: [:address] ) }
+ it 'accepts it as the list of top-level attributes to be rendered' do
+ output.keys.should == [:address]
+ end
+ end
+ end
+ end
-end
+ end