Merge pull request #397 from haines/collection_decorator

Change behaviour of CollectionDecorator
This commit is contained in:
Steve Klabnik 2012-12-26 19:42:26 -08:00
commit 04d779615c
6 changed files with 34 additions and 80 deletions

View File

@ -16,7 +16,7 @@ module Draper
# @option options [Hash] :context context available to each item's decorator
def initialize(source, options = {})
options.assert_valid_keys(:with, :context)
@source = source
@source = source.dup.freeze
@decorator_class = options[:with]
@context = options.fetch(:context, {})
end
@ -26,7 +26,7 @@ module Draper
end
def decorated_collection
@decorated_collection ||= source.collect {|item| decorate_item(item) }
@decorated_collection ||= source.map{|item| decorate_item(item)}.freeze
end
def find(*args, &block)
@ -37,19 +37,6 @@ module Draper
end
end
def method_missing(method, *args, &block)
source.send(method, *args, &block)
end
def respond_to?(method, include_private = false)
super || source.respond_to?(method, include_private)
end
def kind_of?(klass)
super || source.kind_of?(klass)
end
alias_method :is_a?, :kind_of?
def ==(other)
source == (other.respond_to?(:source) ? other.source : other)
end

View File

@ -16,6 +16,27 @@ describe Draper::CollectionDecorator do
subject.map{|item| item.source}.should == source
end
describe "#source" do
it "duplicates the source collection" do
subject.source.should == source
subject.source.should_not be source
end
it "is frozen" do
subject.source.should be_frozen
end
it "is aliased to #to_source" do
subject.to_source.should == source
end
end
describe "#decorated_collection" do
it "is frozen" do
subject.decorated_collection.should be_frozen
end
end
context "with context" do
subject { Draper::CollectionDecorator.new(source, with: ProductDecorator, context: {some: 'context'}) }
@ -81,16 +102,6 @@ describe Draper::CollectionDecorator do
end
end
describe "#source" do
it "returns the source collection" do
subject.source.should be source
end
it "is aliased to #to_source" do
subject.to_source.should be source
end
end
describe "item decoration" do
subject { subject_class.new(source, options) }
let(:decorator_classes) { subject.decorated_collection.map(&:class) }
@ -140,6 +151,7 @@ describe Draper::CollectionDecorator do
describe "#find" do
context "with a block" do
it "decorates Enumerable#find" do
subject.stub decorated_collection: []
subject.decorated_collection.should_receive(:find)
subject.find {|p| p.title == "title" }
end
@ -196,36 +208,15 @@ describe Draper::CollectionDecorator do
describe "#to_ary" do
# required for `render @collection` in Rails
it "delegates to the decorated collection" do
subject.decorated_collection.should_receive(:to_ary).and_return(:an_array)
subject.stub decorated_collection: double(to_ary: :an_array)
subject.to_ary.should == :an_array
end
end
describe "#respond_to?" do
it "returns true for its own methods" do
subject.should respond_to :decorated_collection
end
it "returns true for the wrapped collection's methods" do
source.stub(:respond_to?).with(:whatever, true).and_return(true)
subject.respond_to?(:whatever, true).should be_true
end
end
context "Array methods" do
describe "#include?" do
it "delegates to the decorated collection" do
subject.decorated_collection.should_receive(:include?).with(:something).and_return(true)
subject.should include :something
end
end
describe "#[]" do
it "delegates to the decorated collection" do
subject.decorated_collection.should_receive(:[]).with(42).and_return(:something)
subject[42].should == :something
end
end
it "delegates array methods to the decorated collection" do
subject.stub decorated_collection: []
subject.decorated_collection.should_receive(:[]).with(42).and_return(:the_answer)
subject[42].should == :the_answer
end
describe "#==" do
@ -262,30 +253,6 @@ describe Draper::CollectionDecorator do
end
end
it "pretends to be the source class" do
subject.kind_of?(source.class).should be_true
subject.is_a?(source.class).should be_true
end
it "is still its own class" do
subject.kind_of?(subject.class).should be_true
subject.is_a?(subject.class).should be_true
end
describe "#method_missing" do
before do
class << source
def page_number
42
end
end
end
it "proxies unknown methods to the source collection" do
subject.page_number.should == 42
end
end
describe "#to_s" do
subject { Draper::CollectionDecorator.new(source, options) }
let(:source) { ["a", "b", "c"] }

View File

@ -150,7 +150,7 @@ describe Draper::Decoratable do
decorator.should be_a Draper::CollectionDecorator
decorator.decorator_class.should be WidgetDecorator
decorator.source.should be Product.scoped
decorator.source.should == Product.scoped
end
it "accepts context" do

View File

@ -88,7 +88,7 @@ describe Draper::DecoratedAssociation do
it "applies the scope before decoration" do
scoped = [:scoped]
associated.should_receive(:foo).and_return(scoped)
decorated_association.call.source.should be scoped
decorated_association.call.source.should == scoped
end
end
end

View File

@ -94,7 +94,7 @@ describe Draper::Decorator do
it "returns a collection decorator" do
subject.should be_a Draper::CollectionDecorator
subject.source.should be source
subject.source.should == source
end
it "uses itself as the item decorator by default" do

View File

@ -64,7 +64,7 @@ describe Draper::Finders do
describe ".find_all_by_" do
it "proxies to the model class" do
Product.should_receive(:find_all_by_name_and_size).with("apples", "large")
Product.should_receive(:find_all_by_name_and_size).with("apples", "large").and_return([])
ProductDecorator.find_all_by_name_and_size("apples", "large")
end
@ -73,7 +73,7 @@ describe Draper::Finders do
Product.stub(:find_all_by_name).and_return(found)
decorator = ProductDecorator.find_all_by_name("apples")
decorator.should be_a Draper::CollectionDecorator
decorator.source.should be found
decorator.source.should == found
end
end