Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pretend to be instance_of?(source.class) #417

Merged
merged 2 commits into from
Jan 13, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions lib/draper/decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def initialize(source, options = {})
source.to_a if source.respond_to?(:to_a) # forces evaluation of a lazy query from AR
@source = source
@context = options.fetch(:context, {})
handle_multiple_decoration(options) if source.is_a?(Draper::Decorator)
handle_multiple_decoration(options) if source.instance_of?(self.class)
end

class << self
Expand Down Expand Up @@ -188,13 +188,21 @@ def ==(other)
source == (other.respond_to?(:source) ? other.source : other)
end

# @overload kind_of?(class)
# Checks if `self.kind_of?(class)` or `source.kind_of?(class)`
# Checks if `self.kind_of?(klass)` or `source.kind_of?(klass)`
#
# @param [Class] klass
def kind_of?(klass)
super || source.kind_of?(klass)
end
alias_method :is_a?, :kind_of?

# Checks if `self.instance_of?(klass)` or `source.instance_of?(klass)`
#
# @param [Class] klass
def instance_of?(klass)
super || source.instance_of?(klass)
end

# Delegated to the source object, in case it is `nil`.
def present?
source.present?
Expand Down Expand Up @@ -304,10 +312,10 @@ def self.allow?(method)
end

def handle_multiple_decoration(options)
if source.instance_of?(self.class)
if source.applied_decorators.last == self.class
@context = source.context unless options.has_key?(:context)
@source = source.source
elsif source.decorated_with?(self.class)
else
warn "Reapplying #{self.class} decorator to target that is already decorated with it. Call stack:\n#{caller(1).join("\n")}"
end
end
Expand Down
42 changes: 29 additions & 13 deletions spec/draper/decorator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,29 @@
end
end

it "decorates other decorators" do
decorator = ProductDecorator.new(source)
SpecificProductDecorator.new(decorator).source.should be decorator
end
context "when decorating other decorators" do
it "redecorates" 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
warning_message = nil
Object.any_instance.stub(:warn) { |message| warning_message = message }
context "when the same decorator has been applied earlier in the chain" do
let(:decorator) { SpecificProductDecorator.new(ProductDecorator.new(Product.new)) }

it "warns" do
warning_message = nil
Object.any_instance.stub(:warn) {|message| warning_message = message }

expect{ProductDecorator.new(decorator)}.to change{warning_message}
warning_message.should =~ /ProductDecorator/
warning_message.should include caller(1).first
end

deep_decorator = SpecificProductDecorator.new(ProductDecorator.new(Product.new))
expect {
ProductDecorator.new(deep_decorator)
}.to change { warning_message }
warning_message.should =~ /ProductDecorator/
warning_message.should include caller(1).first
it "redecorates" do
Object.any_instance.stub(:warn)
ProductDecorator.new(decorator).source.should be decorator
end
end
end
end

Expand Down Expand Up @@ -696,6 +704,14 @@
subject.is_a?(subject.class).should be_true
end

it "pretends to be an instance of the source class" do
subject.instance_of?(source.class).should be_true
end

it "is still an instance of its own class" do
subject.instance_of?(subject.class).should be_true
end

describe ".decorates_finders" do
it "extends the Finders module" do
ProductDecorator.should be_a_kind_of Draper::Finders
Expand Down
1 change: 0 additions & 1 deletion spec/dummy/spec/models/post_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
subject { Post.first }

it "is true for other instances' decorators" do
pending if Rails.version.start_with?("3.0")
other = Post.first
subject.should_not be other
(subject == other.decorate).should be_true
Expand Down