Merge pull request #408 from haines/infer_collection_decorator

Infer collection decorator
This commit is contained in:
Steve Klabnik 2013-01-07 07:42:52 -08:00
commit 0b8d88fbe9
5 changed files with 58 additions and 22 deletions

View File

@ -41,7 +41,7 @@ module Draper
"inferred decorators" "inferred decorators"
end end
"#<CollectionDecorator of #{klass} for #{source.inspect}>" "#<#{self.class.name} of #{klass} for #{source.inspect}>"
end end
def context=(value) def context=(value)

View File

@ -141,7 +141,7 @@ module Draper
# @option options [Hash] :context context available to decorated items # @option options [Hash] :context context available to decorated items
def self.decorate_collection(source, options = {}) def self.decorate_collection(source, options = {})
options.assert_valid_keys(:with, :context) options.assert_valid_keys(:with, :context)
Draper::CollectionDecorator.new(source, options.reverse_merge(with: self)) collection_decorator_class.new(source, options.reverse_merge(with: self))
end end
# Get the chain of decorators applied to the object. # Get the chain of decorators applied to the object.
@ -218,6 +218,14 @@ module Draper
super || delegatable_method?(method) super || delegatable_method?(method)
end end
protected
def self.collection_decorator_class
collection_decorator_name.constantize
rescue NameError
Draper::CollectionDecorator
end
private private
def delegatable_method?(method) def delegatable_method?(method)
@ -228,20 +236,23 @@ module Draper
source_class? && source_class.respond_to?(method) source_class? && source_class.respond_to?(method)
end end
def self.inferred_source_class def self.source_name
uninferrable_source if name.nil? || name.demodulize !~ /.+Decorator$/ raise NameError if name.nil? || name.demodulize !~ /.+Decorator$/
name.chomp("Decorator")
begin
name.chomp("Decorator").constantize
rescue NameError
uninferrable_source
end
end end
def self.uninferrable_source def self.inferred_source_class
source_name.constantize
rescue NameError
raise Draper::UninferrableSourceError.new(self) raise Draper::UninferrableSourceError.new(self)
end end
def self.collection_decorator_name
plural = source_name.pluralize
raise NameError if plural == source_name
"#{plural}Decorator"
end
def self.define_proxy(method) def self.define_proxy(method)
define_method(method) do |*args, &block| define_method(method) do |*args, &block|
source.send(method, *args, &block) source.send(method, *args, &block)

View File

@ -248,7 +248,7 @@ describe Draper::CollectionDecorator do
let(:options) { {with: ProductDecorator} } let(:options) { {with: ProductDecorator} }
it "returns a string representation of the CollectionDecorator" do it "returns a string representation of the CollectionDecorator" do
subject.to_s.should == '#<CollectionDecorator of ProductDecorator for ["a", "b", "c"]>' subject.to_s.should == '#<Draper::CollectionDecorator of ProductDecorator for ["a", "b", "c"]>'
end end
end end
@ -256,7 +256,15 @@ describe Draper::CollectionDecorator do
let(:options) { {} } let(:options) { {} }
it "returns a string representation of the CollectionDecorator" do it "returns a string representation of the CollectionDecorator" do
subject.to_s.should == '#<CollectionDecorator of inferred decorators for ["a", "b", "c"]>' subject.to_s.should == '#<Draper::CollectionDecorator of inferred decorators for ["a", "b", "c"]>'
end
end
context "for a custom subclass" do
subject { ProductsDecorator.new(source) }
it "uses the custom class name" do
subject.to_s.should =~ /ProductsDecorator/
end end
end end
end end

View File

@ -76,7 +76,6 @@ describe Draper::Decorator do
end end
describe ".decorate_collection" do describe ".decorate_collection" do
subject { ProductDecorator.decorate_collection(source) }
let(:source) { [Product.new, Widget.new] } let(:source) { [Product.new, Widget.new] }
describe "options validation" do describe "options validation" do
@ -92,13 +91,30 @@ describe Draper::Decorator do
end end
end end
it "returns a collection decorator" do context "when a custom collection decorator does not exist" do
subject.should be_a Draper::CollectionDecorator subject { WidgetDecorator.decorate_collection(source) }
subject.should == source
it "returns a regular collection decorator" do
subject.should be_a Draper::CollectionDecorator
subject.should == source
end
it "uses itself as the item decorator by default" do
subject.each {|item| item.should be_a WidgetDecorator}
end
end end
it "uses itself as the item decorator by default" do context "when a custom collection decorator exists" do
subject.each {|item| item.should be_a ProductDecorator} subject { ProductDecorator.decorate_collection(source) }
it "returns the custom collection decorator" do
subject.should be_a ProductsDecorator
subject.should == source
end
it "uses itself as the item decorator by default" do
subject.each {|item| item.should be_a ProductDecorator}
end
end end
context "with context" do context "with context" do

View File

@ -49,7 +49,8 @@ class DummyApp
yield yield
Process.kill('KILL', out.pid) Process.kill("KILL", out.pid)
File.delete("tmp/pids/server.pid")
end end
end end
end end
@ -57,11 +58,11 @@ class DummyApp
private private
def root def root
File.expand_path('../../dummy', __FILE__) File.expand_path("../../dummy", __FILE__)
end end
def localhost def localhost
'127.0.0.1' "127.0.0.1"
end end
def port def port