Handle multiple decorators' options consistently

This commit is contained in:
Andrew Haines 2012-11-07 21:48:42 +00:00
parent 30104b0fc0
commit c10bf791e0
2 changed files with 27 additions and 29 deletions

View File

@ -126,10 +126,7 @@ module Draper
# @param [Object] input instance(s) to wrap
# @param [Hash] options options to be passed to the decorator
def self.decorate(input, options = {})
if input.instance_of?(self)
input.options = options unless options.empty?
return input
elsif input.respond_to?(:each) && !input.is_a?(Struct) && (!defined?(Sequel) || !input.is_a?(Sequel::Model))
if input.respond_to?(:each) && !input.is_a?(Struct) && (!defined?(Sequel) || !input.is_a?(Sequel::Model))
Draper::CollectionDecorator.new(input, options.reverse_merge(with: self))
else
new(input, options)
@ -232,6 +229,7 @@ module Draper
def handle_multiple_decoration
if source.instance_of?(self.class)
self.options = source.options if options.empty?
self.source = source.source
elsif source.decorated_with?(self.class)
warn "Reapplying #{self.class} decorator to target that is already decorated with it. Call stack:\n#{caller(1).join("\n")}"

View File

@ -7,14 +7,30 @@ describe Draper::Decorator do
let(:non_active_model_source){ NonActiveModelProduct.new }
describe "#initialize" do
it "does not re-apply on instances of itself" do
product_decorator = ProductDecorator.new(source)
ProductDecorator.new(product_decorator).model.should be_instance_of Product
context "when decorating an instance of itself" do
it "does not redecorate" do
decorator = ProductDecorator.new(source)
ProductDecorator.new(decorator).source.should be source
end
context "when options are supplied" do
it "overwrites existing options" do
decorator = ProductDecorator.new(source, role: :admin)
ProductDecorator.new(decorator, role: :user).options.should == {role: :user}
end
end
context "when no options are supplied" do
it "preserves existing options" do
decorator = ProductDecorator.new(source, role: :admin)
ProductDecorator.new(decorator).options.should == {role: :admin}
end
end
end
it "allows decorating other decorators" do
product_decorator = ProductDecorator.new(source)
SpecificProductDecorator.new(product_decorator).model.should be product_decorator
it "decorates other decorators" do
decorator = ProductDecorator.new(source)
SpecificProductDecorator.new(decorator).source.should be decorator
end
it "warns if target is already decorated with the same decorator class" do
@ -70,25 +86,9 @@ describe Draper::Decorator do
context "when given a single source object" do
let(:source) { Product.new }
it { should be_instance_of(Draper::Decorator) }
context "when the input is already decorated" do
it "does not perform double-decoration" do
decorated = ProductDecorator.decorate(source)
ProductDecorator.decorate(decorated).object_id.should == decorated.object_id
end
it "overwrites options with provided options" do
first_run = ProductDecorator.decorate(source, context: {role: :user})
second_run = ProductDecorator.decorate(first_run, context: {role: :admin})
second_run.context[:role].should == :admin
end
it "leaves existing options if none are supplied" do
first_run = ProductDecorator.decorate(source, context: {role: :user})
second_run = ProductDecorator.decorate(first_run)
second_run.context[:role].should == :user
end
it "aliases .new" do
ProductDecorator.should_receive(:new).with(source, {some: "options"}).and_return(:a_new_decorator)
ProductDecorator.decorate(source, some: "options").should be :a_new_decorator
end
end
end