draper/lib/draper/collection_decorator.rb

97 lines
2.5 KiB
Ruby
Raw Normal View History

2011-10-20 05:43:48 +00:00
module Draper
class CollectionDecorator
2011-10-20 05:43:48 +00:00
include Enumerable
include ViewHelpers
2011-10-20 05:43:48 +00:00
2012-10-31 23:19:33 +00:00
attr_accessor :source, :options, :decorator_class
protected :options, :options=
alias_method :to_source, :source
delegate :as_json, *(Array.instance_methods - Object.instance_methods), to: :decorated_collection
# @param source collection to decorate
# @param [Hash] options (optional)
# @option options [Class, Symbol] :with the class used to decorate
# items, or `:infer` to call each item's `decorate` method instead
# @option options [Hash] :context context available to each item's decorator
def initialize(source, options = {})
@source = source
@decorator_class = options.delete(:with) || self.class.inferred_decorator_class
options.assert_valid_keys(:with, :context)
@options = options
2012-08-30 13:00:37 +00:00
end
class << self
alias_method :decorate, :new
2011-10-20 05:43:48 +00:00
end
def decorated_collection
@decorated_collection ||= source.collect {|item| decorate_item(item) }
2011-10-20 05:43:48 +00:00
end
2012-10-31 23:52:55 +00:00
def find(*args, &block)
if block_given?
2012-10-31 23:52:55 +00:00
decorated_collection.find(*args, &block)
else
2012-10-31 23:52:55 +00:00
decorator_class.find(*args)
end
end
2012-10-31 23:19:50 +00:00
def method_missing(method, *args, &block)
source.send(method, *args, &block)
2011-10-20 05:43:48 +00:00
end
def respond_to?(method, include_private = false)
super || source.respond_to?(method, include_private)
end
2012-02-13 15:24:31 +00:00
2011-12-07 15:18:06 +00:00
def kind_of?(klass)
2012-10-31 23:19:50 +00:00
super || source.kind_of?(klass)
2011-12-07 15:18:06 +00:00
end
alias_method :is_a?, :kind_of?
def ==(other)
source == (other.respond_to?(:source) ? other.source : other)
end
2011-10-20 05:43:48 +00:00
def to_s
2012-10-31 23:19:33 +00:00
"#<CollectionDecorator of #{decorator_class} for #{source.inspect}>"
2011-10-20 05:43:48 +00:00
end
2012-05-12 08:40:04 +00:00
# Accessor for `:context` option
def context
options.fetch(:context, {})
end
# Setter for `:context` option
def context=(input)
options[:context] = input
each {|item| item.context = input } unless respond_to?(:loaded?) && !loaded?
2012-05-08 15:44:50 +00:00
end
2012-10-31 23:19:33 +00:00
protected
def decorate_item(item)
if decorator_class == :infer
item.decorate(context: context)
else
decorator_class.decorate(item, context: context)
end
end
2012-10-31 23:19:33 +00:00
def self.inferred_decorator_class
2012-11-01 01:38:16 +00:00
decorator_name = "#{name.chomp("Decorator").singularize}Decorator"
decorator_uninferrable if decorator_name == name
decorator_name.constantize
rescue NameError
2012-11-01 01:38:16 +00:00
decorator_uninferrable
end
def self.decorator_uninferrable
2012-11-01 00:16:09 +00:00
raise Draper::UninferrableDecoratorError.new(self)
end
2011-10-20 05:43:48 +00:00
end
end