Skip to content

Commit

Permalink
Prefer Decorator#source to #model
Browse files Browse the repository at this point in the history
This is both for consistency with CollectionDecorator, and also
recognises the fact that the source might actually be another
decorator, not a model.

Got rid of `#wrapped_object`, how many aliases do we really need?
  • Loading branch information
haines committed Nov 1, 2012
1 parent dc53646 commit 1e84fcb
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 31 deletions.
46 changes: 23 additions & 23 deletions lib/draper/decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ class Decorator
include ActiveModelSupport
include Draper::ViewHelpers

attr_accessor :model, :options
attr_accessor :source, :options

alias_method :model, :source
alias_method :to_source, :source

# Initialize a new decorator instance by passing in
# an instance of the source class. Pass in an optional
Expand All @@ -18,13 +21,13 @@ class Decorator
# you will get a warning if the same decorator appears at
# multiple places in the chain.
#
# @param [Object] input instance to wrap
# @param [Object] source object to decorate
# @param [Hash] options (optional)
def initialize(input, options = {})
input.to_a if input.respond_to?(:to_a) # forces evaluation of a lazy query from AR
self.model = input
self.options = options
handle_multiple_decoration if input.is_a?(Draper::Decorator)
def initialize(source, options = {})
source.to_a if source.respond_to?(:to_a) # forces evaluation of a lazy query from AR

This comment has been minimized.

Copy link
@nashby

nashby Jan 15, 2013

Member

@haines I think we don't need to_a as we use separate class for collections, right?

This comment has been minimized.

Copy link
@steveklabnik

steveklabnik Jan 15, 2013

Member

Yeah, not now, probably.

This comment has been minimized.

Copy link
@haines

haines Jan 15, 2013

Author Contributor

Agreed! Let's ditch it.

@source = source
@options = options
handle_multiple_decoration if source.is_a?(Draper::Decorator)
end

# Adds ActiveRecord finder methods to the decorator class. The
Expand All @@ -49,7 +52,7 @@ def self.has_finders(options = {})
# :scope The scope to apply to the association
def self.decorates_association(association_symbol, options = {})
define_method(association_symbol) do
orig_association = model.send(association_symbol)
orig_association = source.send(association_symbol)

return orig_association if orig_association.nil? || orig_association == []
return decorated_associations[association_symbol] if decorated_associations[association_symbol]
Expand Down Expand Up @@ -142,7 +145,7 @@ def self.decorate(input, options = {})
#
# @return [Array] list of decorator classes
def applied_decorators
chain = model.respond_to?(:applied_decorators) ? model.applied_decorators : []
chain = source.respond_to?(:applied_decorators) ? source.applied_decorators : []
chain << self.class
end

Expand All @@ -166,32 +169,32 @@ def decorator
#
# @return [Boolean] true if other's model == self's model
def ==(other)
@model == (other.respond_to?(:model) ? other.model : other)
source == (other.respond_to?(:source) ? other.source : other)
end

def kind_of?(klass)
super || model.kind_of?(klass)
super || source.kind_of?(klass)
end
alias_method :is_a?, :kind_of?

def respond_to?(method, include_private = false)
super || (allow?(method) && model.respond_to?(method, include_private))
super || (allow?(method) && source.respond_to?(method, include_private))
end

# We always want to delegate present, in case we decorate a nil object.
#
# I don't like the idea of decorating a nil object, but we'll deal with
# that later.
def present?
model.present?
source.present?
end

def method_missing(method, *args, &block)
super unless allow?(method)

if model.respond_to?(method)
if source.respond_to?(method)
self.class.send :define_method, method do |*args, &blokk|
model.send method, *args, &blokk
source.send method, *args, &blokk
end

send method, *args, &block
Expand All @@ -212,9 +215,6 @@ def context=(input)
options[:context] = input
end

alias_method :wrapped_object, :model
alias_method :source, :model
alias_method :to_source, :model

private

Expand All @@ -227,16 +227,16 @@ def allow?(method)
end

def handle_multiple_decoration
if model.instance_of?(self.class)
self.model = model.model
elsif model.decorated_with?(self.class)
if source.instance_of?(self.class)
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")}"
end
end

def find_association_reflection(association)
if model.class.respond_to?(:reflect_on_association)
model.class.reflect_on_association(association)
if source.class.respond_to?(:reflect_on_association)
source.class.reflect_on_association(association)
end
end

Expand Down
12 changes: 4 additions & 8 deletions spec/draper/decorator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -352,17 +352,13 @@
end
end

describe "#model" do
describe "#source" do
it "returns the wrapped object" do
subject.model.should be source
end

it "is aliased to #wrapped_object" do
subject.wrapped_object.should be source
subject.source.should be source
end

it "is aliased to #source" do
subject.source.should be source
it "is aliased to #model" do
subject.model.should be source
end

it "is aliased to #to_source" do
Expand Down

0 comments on commit 1e84fcb

Please sign in to comment.