add support for decorate_collection for Draper 1.0
This commit is contained in:
parent
17be15a2e4
commit
83a36a2282
|
@ -25,11 +25,22 @@ require 'active_support/concern'
|
||||||
#
|
#
|
||||||
# @thing_1 will be a ThingListDecorator (or contain them), and @thing_2 will be a Thing2Decorator.
|
# @thing_1 will be a ThingListDecorator (or contain them), and @thing_2 will be a Thing2Decorator.
|
||||||
#
|
#
|
||||||
|
# For Draper 1.0 and above, collection elements are no longer decorated with
|
||||||
|
# Decorator.decorate(collection), but with Decorator.decorate_collection(collection).
|
||||||
|
# Specify that you want to decorate a collection, and with what decorator, with this syntax:
|
||||||
|
#
|
||||||
|
# class StuffController < ApplicationController
|
||||||
|
# include DecoratesBeforeRendering
|
||||||
|
#
|
||||||
|
# decorates_collection :things_1, :with => ThingListDecorator
|
||||||
|
# end
|
||||||
|
#
|
||||||
module DecoratesBeforeRendering
|
module DecoratesBeforeRendering
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
included do
|
included do
|
||||||
class_attribute :__decorates__, :instance_writer => false
|
class_attribute :__decorates__, :instance_writer => false
|
||||||
|
class_attribute :__decorates_collection__, :instance_writer => false
|
||||||
|
|
||||||
class_eval do
|
class_eval do
|
||||||
def self.decorates(*args)
|
def self.decorates(*args)
|
||||||
|
@ -38,6 +49,15 @@ module DecoratesBeforeRendering
|
||||||
self.__decorates__ ||= []
|
self.__decorates__ ||= []
|
||||||
self.__decorates__ << [ args.map { |i| "@#{i}" }, options ]
|
self.__decorates__ << [ args.map { |i| "@#{i}" }, options ]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.decorates_collection(*args)
|
||||||
|
options = args.extract_options!
|
||||||
|
|
||||||
|
raise ArgumentError, ":with is required for now" if !options[:with]
|
||||||
|
|
||||||
|
self.__decorates_collection__ ||= []
|
||||||
|
self.__decorates_collection__ << [ args.map { |i| "@#{i}" }, options ]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -49,17 +69,33 @@ module DecoratesBeforeRendering
|
||||||
private
|
private
|
||||||
|
|
||||||
def __decorate_ivars__
|
def __decorate_ivars__
|
||||||
return if __decorates__.nil? || __decorates__.empty?
|
return if (__decorates__.nil? || __decorates__.empty?) and
|
||||||
|
(__decorates_collection__.nil? || __decorates_collection__.empty?)
|
||||||
|
|
||||||
__decorates__.each do |ivar_names, options|
|
if !__decorates__.nil?
|
||||||
ivar_names.each do |ivar_name|
|
__decorate_ivar_names__(__decorates__) do |ivar_name, ivar, options|
|
||||||
ivar = instance_variable_get(ivar_name)
|
|
||||||
if ivar
|
|
||||||
decorator = options.key?(:with) ? options.fetch(:with) : __decorator_for__(ivar)
|
decorator = options.key?(:with) ? options.fetch(:with) : __decorator_for__(ivar)
|
||||||
decorated = decorator.decorate(ivar)
|
decorated = decorator.decorate(ivar)
|
||||||
instance_variable_set(ivar_name, decorated)
|
instance_variable_set(ivar_name, decorated)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if !__decorates_collection__.nil?
|
||||||
|
__decorate_ivar_names__(__decorates_collection__) do |ivar_name, ivar, options|
|
||||||
|
decorated = options.fetch(:with).decorate_collection(ivar)
|
||||||
|
instance_variable_set(ivar_name, decorated)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def __decorate_ivar_names__(ivars)
|
||||||
|
ivars.each do |ivar_names, options|
|
||||||
|
ivar_names.each do |ivar_name|
|
||||||
|
ivar = instance_variable_get(ivar_name)
|
||||||
|
if ivar
|
||||||
|
yield ivar_name, ivar, options
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,6 @@ class MyCompletelyFakeModelDecorator; end
|
||||||
class MyOtherCompletelyFakeModelDecorator; end
|
class MyOtherCompletelyFakeModelDecorator; end
|
||||||
|
|
||||||
describe DecoratesBeforeRendering do
|
describe DecoratesBeforeRendering do
|
||||||
# NOTE: these are married together, so they're tested together.
|
|
||||||
describe '::decorates + #render' do
|
|
||||||
let(:sentinel) { double(:sentinel) }
|
let(:sentinel) { double(:sentinel) }
|
||||||
let(:ivar) { double('@ivar') }
|
let(:ivar) { double('@ivar') }
|
||||||
let(:ivars) { double('@ivars') }
|
let(:ivars) { double('@ivars') }
|
||||||
|
@ -42,6 +40,8 @@ describe DecoratesBeforeRendering do
|
||||||
let(:instance) { klass.new(sentinel, ivar, ivars) }
|
let(:instance) { klass.new(sentinel, ivar, ivars) }
|
||||||
let(:args) { double('*args') }
|
let(:args) { double('*args') }
|
||||||
|
|
||||||
|
# NOTE: these are married together, so they're tested together.
|
||||||
|
describe '::decorates + #render' do
|
||||||
context "no ivars" do
|
context "no ivars" do
|
||||||
it 'should render' do
|
it 'should render' do
|
||||||
sentinel.should_receive(:render).with(args)
|
sentinel.should_receive(:render).with(args)
|
||||||
|
@ -109,5 +109,22 @@ describe DecoratesBeforeRendering do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# for draper >= 1.0
|
||||||
|
describe "#decorates_collection + #render" do
|
||||||
|
it "requires decorator class (for now)" do
|
||||||
|
expect {
|
||||||
|
klass.decorates_collection(:ivars)
|
||||||
|
}.to raise_error(ArgumentError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should decorate collection and render" do
|
||||||
|
klass.decorates_collection(:ivars, :with => MyCompletelyFakeModelDecorator)
|
||||||
|
subclass_instance = Class.new(klass).new(sentinel, ivar, ivars)
|
||||||
|
sentinel.should_receive(:render).with(args)
|
||||||
|
MyCompletelyFakeModelDecorator.should_receive(:decorate_collection).with(ivars)
|
||||||
|
subclass_instance.render(args)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue