Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Support for decorating collection for Draper >= 1.0 #5

Merged
merged 1 commit into from

2 participants

@johnbintz
Collaborator

Draper upgrade to 1.0 left my automatic decorators all messed up. This pull request adds decorates_collection, which requires the class via :with and uses Draper's Decorator.decorate_collection method to do the decoration:

decorates_collection :users, :with => UserDecorator
@ohwillie
Owner

Hi @johnbintz, thanks for submitting this pull request. I haven't been monitoring the project so I gave you direct commit access.

@johnbintz
Collaborator

Works for me. Merging. I'll do my best to keep up on whatever issues may crop up!

@johnbintz johnbintz merged commit 03e3962 into from
@ohwillie
Owner

:thumbsup:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 17, 2013
  1. @johnbintz
This page is out of date. Refresh to see the latest.
View
46 lib/decorates_before_rendering.rb
@@ -25,11 +25,22 @@
#
# @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
extend ActiveSupport::Concern
included do
class_attribute :__decorates__, :instance_writer => false
+ class_attribute :__decorates_collection__, :instance_writer => false
class_eval do
def self.decorates(*args)
@@ -38,6 +49,15 @@ def self.decorates(*args)
self.__decorates__ ||= []
self.__decorates__ << [ args.map { |i| "@#{i}" }, options ]
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
@@ -49,15 +69,31 @@ def render(*args)
private
def __decorate_ivars__
- return if __decorates__.nil? || __decorates__.empty?
+ return if (__decorates__.nil? || __decorates__.empty?) and
+ (__decorates_collection__.nil? || __decorates_collection__.empty?)
+
+ if !__decorates__.nil?
+ __decorate_ivar_names__(__decorates__) do |ivar_name, ivar, options|
+ decorator = options.key?(:with) ? options.fetch(:with) : __decorator_for__(ivar)
+ decorated = decorator.decorate(ivar)
+ instance_variable_set(ivar_name, decorated)
+ 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
- __decorates__.each do |ivar_names, options|
+ 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
- decorator = options.key?(:with) ? options.fetch(:with) : __decorator_for__(ivar)
- decorated = decorator.decorate(ivar)
- instance_variable_set(ivar_name, decorated)
+ yield ivar_name, ivar, options
end
end
end
View
77 spec/decorates_before_rendering_spec.rb
@@ -4,44 +4,44 @@ class MyCompletelyFakeModelDecorator; end
class MyOtherCompletelyFakeModelDecorator; end
describe DecoratesBeforeRendering do
- # NOTE: these are married together, so they're tested together.
- describe '::decorates + #render' do
- let(:sentinel) { double(:sentinel) }
- let(:ivar) { double('@ivar') }
- let(:ivars) { double('@ivars') }
-
- # NOTE: This superclass is here so we know that the correct render gets
- # called. It can't be defined in the subclass, or else that one
- # will be the one that's used, as modules sit above their includers
- # in the class hierarchy.
- let(:superclass) do
- Class.new do
- def initialize(sentinel)
- @sentinel = sentinel
- end
-
- def render(*args)
- @sentinel.render(*args)
- end
+ let(:sentinel) { double(:sentinel) }
+ let(:ivar) { double('@ivar') }
+ let(:ivars) { double('@ivars') }
+
+ # NOTE: This superclass is here so we know that the correct render gets
+ # called. It can't be defined in the subclass, or else that one
+ # will be the one that's used, as modules sit above their includers
+ # in the class hierarchy.
+ let(:superclass) do
+ Class.new do
+ def initialize(sentinel)
+ @sentinel = sentinel
+ end
+
+ def render(*args)
+ @sentinel.render(*args)
end
end
- let(:klass) do
- Class.new(superclass) do
- include DecoratesBeforeRendering
+ end
+ let(:klass) do
+ Class.new(superclass) do
+ include DecoratesBeforeRendering
- attr_reader :ivar, :ivars
+ attr_reader :ivar, :ivars
- def initialize(sentinel, ivar, ivars = nil)
- super(sentinel)
+ def initialize(sentinel, ivar, ivars = nil)
+ super(sentinel)
- @ivar = ivar
- @ivars = ivars
- end
+ @ivar = ivar
+ @ivars = ivars
end
end
- let(:instance) { klass.new(sentinel, ivar, ivars) }
- let(:args) { double('*args') }
+ end
+ let(:instance) { klass.new(sentinel, ivar, ivars) }
+ let(:args) { double('*args') }
+ # NOTE: these are married together, so they're tested together.
+ describe '::decorates + #render' do
context "no ivars" do
it 'should render' do
sentinel.should_receive(:render).with(args)
@@ -109,5 +109,22 @@ def initialize(sentinel, ivar, ivars = nil)
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
Something went wrong with that request. Please try again.