lib/draper/decorator.rb in draper-1.0.0.beta1 vs lib/draper/decorator.rb in draper-1.0.0.beta2
- old
+ new
@@ -32,22 +32,40 @@
class << self
alias_method :decorate, :new
end
- # Adds ActiveRecord finder methods to the decorator class. The
- # methods return decorated models, so that you can use
- # `ProductDecorator.find(id)` instead of
+ # Specify the class that this class decorates.
+ #
+ # @param [String, Symbol, Class] Class or name of class to decorate.
+ def self.decorates(klass)
+ @source_class = klass.to_s.classify.constantize
+ end
+
+ # @return [Class] The source class corresponding to this
+ # decorator class
+ def self.source_class
+ @source_class ||= inferred_source_class
+ end
+
+ # Checks whether this decorator class has a corresponding
+ # source class
+ def self.source_class?
+ source_class
+ rescue Draper::UninferrableSourceError
+ false
+ end
+
+ # Automatically decorates ActiveRecord finder methods, so that
+ # you can use `ProductDecorator.find(id)` instead of
# `ProductDecorator.decorate(Product.find(id))`.
#
- # If the `:for` option is not supplied, the model class will be
- # inferred from the decorator class.
+ # The model class to be found is defined by `decorates` or
+ # inferred from the decorator class name.
#
- # @option options [Class, Symbol] :for The model class to find
- def self.has_finders(options = {})
+ def self.decorates_finders
extend Draper::Finders
- self.finder_class = options[:for] || name.chomp("Decorator")
end
# Typically called within a decorator definition, this method causes
# the assocation to be decorated when it is retrieved.
#
@@ -143,41 +161,75 @@
def 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) && 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?
source.present?
end
+ # For ActiveModel compatibilty
+ def to_model
+ self
+ end
+
+ # For ActiveModel compatibility
+ def to_param
+ source.to_param
+ end
+
def method_missing(method, *args, &block)
- if allow?(method) && source.respond_to?(method)
+ if delegatable_method?(method)
self.class.define_proxy(method)
send(method, *args, &block)
else
super
end
end
- # For ActiveModel compatibilty
- def to_model
- self
+ def respond_to?(method, include_private = false)
+ super || delegatable_method?(method)
end
- # For ActiveModel compatibility
- def to_param
- source.to_param
+ def self.method_missing(method, *args, &block)
+ if delegatable_method?(method)
+ source_class.send(method, *args, &block)
+ else
+ super
+ end
end
+ def self.respond_to?(method, include_private = false)
+ super || delegatable_method?(method)
+ end
+
private
+
+ def delegatable_method?(method)
+ allow?(method) && source.respond_to?(method)
+ end
+
+ def self.delegatable_method?(method)
+ source_class? && source_class.respond_to?(method)
+ end
+
+ def self.inferred_source_class
+ uninferrable_source if name.nil? || name.demodulize !~ /.+Decorator$/
+
+ begin
+ name.chomp("Decorator").constantize
+ rescue NameError
+ uninferrable_source
+ end
+ end
+
+ def self.uninferrable_source
+ raise Draper::UninferrableSourceError.new(self)
+ end
def self.define_proxy(method)
define_method(method) do |*args, &block|
source.send(method, *args, &block)
end