Implemented decorated collection proxy
When decorating collections, returning an array or decorators for each element is not enough. Often the original collection is richer then an array, e.g. has pagination methods. This commit adds DecoratedEnumerableProxy that is returned when decorating a collection of models, and which proxies missing methods to the original wrapped collection.
This commit is contained in:
parent
f55962ddcb
commit
d85ab06a15
|
@ -93,7 +93,7 @@ module Draper
|
||||||
# @param [Object] instance(s) to wrap
|
# @param [Object] instance(s) to wrap
|
||||||
# @param [Object] context (optional)
|
# @param [Object] context (optional)
|
||||||
def self.decorate(input, context = {})
|
def self.decorate(input, context = {})
|
||||||
input.respond_to?(:each) ? input.map{|i| new(i, context)} : new(input, context)
|
input.respond_to?(:each) ? DecoratedEnumerableProxy.new(input, self, context) : new(input, context)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Access the helpers proxy to call built-in and user-defined
|
# Access the helpers proxy to call built-in and user-defined
|
||||||
|
@ -158,5 +158,32 @@ module Draper
|
||||||
specified = self.allowed || (model.public_methods.map{|s| s.to_sym} - denied.map{|s| s.to_sym})
|
specified = self.allowed || (model.public_methods.map{|s| s.to_sym} - denied.map{|s| s.to_sym})
|
||||||
(specified - self.public_methods.map{|s| s.to_sym}) + FORCED_PROXY
|
(specified - self.public_methods.map{|s| s.to_sym}) + FORCED_PROXY
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class DecoratedEnumerableProxy
|
||||||
|
include Enumerable
|
||||||
|
|
||||||
|
def initialize(collection, klass, context)
|
||||||
|
@wrapped_collection, @klass, @context = collection, klass, context
|
||||||
|
end
|
||||||
|
|
||||||
|
# Implementation of Enumerable#each that proxyes to the wrapped collection
|
||||||
|
def each(&block)
|
||||||
|
@wrapped_collection.each { |member| block.call(@klass.new(member, @context)) }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Implement to_arry so that render @decorated_collection is happy
|
||||||
|
def to_ary
|
||||||
|
@wrapped_collection.to_ary
|
||||||
|
end
|
||||||
|
|
||||||
|
def method_missing (meth, *args, &block)
|
||||||
|
@wrapped_collection.send(meth, *args, &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"#<DecoratedEnumerableProxy of #{@klass} for #{@wrapped_collection.inspect}>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -150,6 +150,7 @@ describe Draper::Base do
|
||||||
its(:context) { should eq(context) }
|
its(:context) { should eq(context) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context('.==') do
|
context('.==') do
|
||||||
|
@ -159,6 +160,32 @@ describe Draper::Base do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "collection decoration" do
|
||||||
|
|
||||||
|
# Implementation of #decorate that returns an array
|
||||||
|
# of decorated objects is insufficient to deal with
|
||||||
|
# situations where the original collection has been
|
||||||
|
# expanded with the use of modules (as often the case
|
||||||
|
# with paginator gems) or is just more complex then
|
||||||
|
# an array.
|
||||||
|
module Paginator; def page_number; "magic_value"; end; end
|
||||||
|
Array.send(:include, Paginator)
|
||||||
|
let(:paged_array) { [Product.new, Product.new] }
|
||||||
|
subject { ProductDecorator.decorate(paged_array) }
|
||||||
|
|
||||||
|
it "should proxy all calls to decorated collection" do
|
||||||
|
paged_array.page_number.should == "magic_value"
|
||||||
|
subject.page_number.should == "magic_value"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should support Rails partial lookup for a collection" do
|
||||||
|
# to support Rails render @collection the returned collection
|
||||||
|
# (or its proxy) should implement #to_ary.
|
||||||
|
subject.respond_to?(:to_ary).should be true
|
||||||
|
subject.to_a.first.should == ProductDecorator.decorate(paged_array.first)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "a sample usage with denies" do
|
describe "a sample usage with denies" do
|
||||||
let(:subject_with_denies){ DecoratorWithDenies.new(source) }
|
let(:subject_with_denies){ DecoratorWithDenies.new(source) }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue