Generalize to pass an options hash to decorators

This commit is contained in:
Jeff Felchner 2011-11-09 19:02:23 -06:00
parent 78b200a84f
commit 03910877d0
4 changed files with 47 additions and 47 deletions

View File

@ -15,15 +15,15 @@ module Draper
# Initialize a new decorator instance by passing in # Initialize a new decorator instance by passing in
# an instance of the source class. Pass in an optional # an instance of the source class. Pass in an optional
# context is stored for later use. # context inside the options hash is stored for later use.
# #
# @param [Object] instance to wrap # @param [Object] instance to wrap
# @param [Object] context (optional) # @param [Hash] options (optional)
def initialize(input, context = {}) def initialize(input, options = {})
input.inspect # forces evaluation of a lazy query from AR input.inspect # forces evaluation of a lazy query from AR
self.class.model_class = input.class if model_class.nil? self.class.model_class = input.class if model_class.nil?
@model = input @model = input
self.context = context self.context = options.fetch(:context, {})
end end
# Proxies to the class specified by `decorates` to automatically # Proxies to the class specified by `decorates` to automatically
@ -31,8 +31,8 @@ module Draper
# #
# @param [Symbol or String] id to lookup # @param [Symbol or String] id to lookup
# @return [Object] instance of this decorator class # @return [Object] instance of this decorator class
def self.find(input, context = {}) def self.find(input, options = {})
self.new(model_class.find(input), context) self.new(model_class.find(input), options)
end end
# Typically called within a decorator definition, this method # Typically called within a decorator definition, this method
@ -43,7 +43,7 @@ module Draper
# But they don't have to match in name, so a `EmployeeDecorator` # But they don't have to match in name, so a `EmployeeDecorator`
# class could call `decorates :person` to wrap instances of `Person` # class could call `decorates :person` to wrap instances of `Person`
# #
# This is primarilly set so the `.find` method knows which class # This is primarilly set so the `.find` method knows which class
# to query. # to query.
# #
# @param [Symbol] class_name snakecase name of the decorated class, like `:product` # @param [Symbol] class_name snakecase name of the decorated class, like `:product`
@ -83,7 +83,7 @@ module Draper
# Initialize a new decorator instance by passing in # Initialize a new decorator instance by passing in
# an instance of the source class. Pass in an optional # an instance of the source class. Pass in an optional
# context is stored for later use. # context into the options hash is stored for later use.
# #
# When passing in a single object, using `.decorate` is # When passing in a single object, using `.decorate` is
# identical to calling `.new`. However, `.decorate` can # identical to calling `.new`. However, `.decorate` can
@ -91,31 +91,31 @@ module Draper
# individually decorated objects. # individually decorated objects.
# #
# @param [Object] instance(s) to wrap # @param [Object] instance(s) to wrap
# @param [Object] context (optional) # @param [Hash] options (optional)
def self.decorate(input, context = {}) def self.decorate(input, options = {})
input.respond_to?(:each) ? Draper::DecoratedEnumerableProxy.new(input, self, context) : new(input, context) input.respond_to?(:each) ? Draper::DecoratedEnumerableProxy.new(input, self, options) : new(input, options)
end
# Fetch all instances of the decorated class and decorate them.
#
# @param [Object] context (optional)
# @return [Draper::DecoratedEnumerableProxy]
def self.all(context = {})
Draper::DecoratedEnumerableProxy.new(model_class.all, self, context)
end
def self.first(context = {})
decorate(model_class.first, context)
end end
def self.last(context = {}) # Fetch all instances of the decorated class and decorate them.
decorate(model_class.last, context) #
# @param [Hash] options (optional)
# @return [Draper::DecoratedEnumerableProxy]
def self.all(options = {})
Draper::DecoratedEnumerableProxy.new(model_class.all, self, options)
end
def self.first(options = {})
decorate(model_class.first, options)
end
def self.last(options = {})
decorate(model_class.last, options)
end end
# Access the helpers proxy to call built-in and user-defined # Access the helpers proxy to call built-in and user-defined
# Rails helpers. Aliased to `.h` for convinience. # Rails helpers. Aliased to `.h` for convinience.
# #
# @return [Object] proxy # @return [Object] proxy
def helpers def helpers
self.class.helpers self.class.helpers
end end
@ -124,13 +124,13 @@ module Draper
# Access the helpers proxy to call built-in and user-defined # Access the helpers proxy to call built-in and user-defined
# Rails helpers from a class context. # Rails helpers from a class context.
# #
# @return [Object] proxy # @return [Object] proxy
class << self class << self
def helpers def helpers
Draper::ViewContext.current Draper::ViewContext.current
end end
alias :h :helpers alias :h :helpers
end end
# Fetch the original wrapped model. # Fetch the original wrapped model.
# #
@ -141,7 +141,7 @@ module Draper
# Delegates == to the decorated models # Delegates == to the decorated models
# #
# @return [Boolean] true if other's model == self's model # @return [Boolean] true if other's model == self's model
def ==(other) def ==(other)
@model == (other.respond_to?(:model) ? other.model : other) @model == (other.respond_to?(:model) ? other.model : other)
end end
@ -165,11 +165,11 @@ module Draper
super super
end end
end end
def self.method_missing(method, *args, &block) def self.method_missing(method, *args, &block)
model_class.send(method, *args, &block) model_class.send(method, *args, &block)
end end
def self.respond_to?(method, include_private = false) def self.respond_to?(method, include_private = false)
super || model_class.respond_to?(method) super || model_class.respond_to?(method)
end end
@ -177,6 +177,6 @@ module Draper
private private
def allow?(method) def allow?(method)
(!allowed? || allowed.include?(method) || FORCED_PROXY.include?(method)) && !denied.include?(method) (!allowed? || allowed.include?(method) || FORCED_PROXY.include?(method)) && !denied.include?(method)
end end
end end
end end

View File

@ -2,16 +2,16 @@ module Draper
class DecoratedEnumerableProxy class DecoratedEnumerableProxy
include Enumerable include Enumerable
def initialize(collection, klass, context) def initialize(collection, klass, options = {})
@wrapped_collection, @klass, @context = collection, klass, context @wrapped_collection, @klass, @options = collection, klass, options
end end
def each(&block) def each(&block)
@wrapped_collection.each { |member| block.call(@klass.new(member, @context)) } @wrapped_collection.each { |member| block.call(@klass.new(member, @options)) }
end end
def to_ary def to_ary
@wrapped_collection.map { |member| @klass.new(member, @context) } @wrapped_collection.map { |member| @klass.new(member, @options) }
end end
def method_missing (method, *args, &block) def method_missing (method, *args, &block)

View File

@ -1,14 +1,14 @@
module Draper::ModelSupport module Draper::ModelSupport
def decorator def decorator(options = {})
@decorator ||= "#{self.class.name}Decorator".constantize.decorate(self) @decorator ||= "#{self.class.name}Decorator".constantize.decorate(self, options)
block_given? ? yield(@decorator) : @decorator block_given? ? yield(@decorator) : @decorator
end end
alias :decorate :decorator alias :decorate :decorator
module ClassMethods module ClassMethods
def decorate(context = {}) def decorate(options = {})
@decorator_proxy ||= "#{model_name}Decorator".constantize.decorate(self.scoped) @decorator_proxy ||= "#{model_name}Decorator".constantize.decorate(self.scoped, options)
block_given? ? yield(@decorator_proxy) : @decorator_proxy block_given? ? yield(@decorator_proxy) : @decorator_proxy
end end
end end

View File

@ -135,7 +135,7 @@ describe Draper::Base do
end end
it "should accept and store a context" do it "should accept and store a context" do
pd = ProductDecorator.find(1, :admin) pd = ProductDecorator.find(1, :context => :admin)
pd.context.should == :admin pd.context.should == :admin
end end
end end
@ -164,7 +164,7 @@ describe Draper::Base do
context "with a context" do context "with a context" do
let(:context) {{ :some => 'data' }} let(:context) {{ :some => 'data' }}
subject { Draper::Base.decorate(source, context) } subject { Draper::Base.decorate(source, :context => context) }
context "when given a collection of source objects" do context "when given a collection of source objects" do
let(:source) { [Product.new, Product.new] } let(:source) { [Product.new, Product.new] }
@ -189,7 +189,7 @@ describe Draper::Base do
subject.should == other subject.should == other
end end
end end
context 'position accessors' do context 'position accessors' do
[:first, :last].each do |method| [:first, :last].each do |method|
context "##{method}" do context "##{method}" do
@ -202,9 +202,9 @@ describe Draper::Base do
end end
it "should accept an optional context" do it "should accept an optional context" do
ProductDecorator.send(method, :admin).context.should == :admin ProductDecorator.send(method, :context => :admin).context.should == :admin
end end
end end
end end
end end
@ -273,9 +273,9 @@ describe Draper::Base do
it "should return a decorated collection" do it "should return a decorated collection" do
ProductDecorator.all.first.should be_instance_of ProductDecorator ProductDecorator.all.first.should be_instance_of ProductDecorator
end end
it "should accept a context" do it "should accept a context" do
collection = ProductDecorator.all(:admin) collection = ProductDecorator.all(:context => :admin)
collection.first.context.should == :admin collection.first.context.should == :admin
end end
end end