diff --git a/lib/decorates_before_rendering.rb b/lib/decorates_before_rendering.rb index 3fc7f00..a6dbae7 100644 --- a/lib/decorates_before_rendering.rb +++ b/lib/decorates_before_rendering.rb @@ -13,10 +13,27 @@ require 'active_support/core_ext/class/attribute' # # @thing_1 and @thing_2 will be decorated right before a rendering occurs. # +# You can also specify the decorator you wish to use for a particular instance variable: +# +# class StuffController < ApplicationController +# include DecoratesBeforeRendering +# +# decorates :thing_1, :with => ThingListDecorator +# decorates :thing_2 +# end +# +# @thing_1 will be a ThingListDecorator (or contain them), and @thing_2 will be a Thing2Decorator. +# module DecoratesBeforeRendering module ClassMethods def decorates(*unsigiled_ivar_names) - self.__ivars_to_decorate__ = unsigiled_ivar_names.map { |i| "@#{i}" } + options = {} + if unsigiled_ivar_names.last.instance_of?(::Hash) + options = unsigiled_ivar_names.pop + end + + self.__ivars_to_decorate__ ||= [] + self.__ivars_to_decorate__ << [ unsigiled_ivar_names.map { |i| "@#{i}" }, options ] end end @@ -30,16 +47,20 @@ private def __decorate_ivars__ ivars_to_decorate = self.class.__ivars_to_decorate__ - return if ivars_to_decorate.nil? + return if ivars_to_decorate.nil? or ivars_to_decorate.empty? - ivars_to_decorate.each do |ivar_name| - ivar = instance_variable_get(ivar_name) - instance_variable_set(ivar_name, __decorator_for__(ivar)) unless ivar.nil? + ivars_to_decorate.each do |ivar_names, options| + ivar_names.each do |ivar_name| + if ivar = instance_variable_get(ivar_name) + decorator = (options[:with] || __decorator_for__(ivar)).decorate(ivar) + instance_variable_set(ivar_name, decorator) + end + end end end def __decorator_for__(ivar) - __decorator_name_for__(ivar).constantize.decorate(ivar) + __decorator_name_for__(ivar).constantize end def __decorator_name_for__(ivar) diff --git a/spec/decorates_before_rendering_spec.rb b/spec/decorates_before_rendering_spec.rb index 8b746b5..13a11ad 100644 --- a/spec/decorates_before_rendering_spec.rb +++ b/spec/decorates_before_rendering_spec.rb @@ -1,12 +1,14 @@ require_relative '../lib/decorates_before_rendering' 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 @@ -27,16 +29,17 @@ describe DecoratesBeforeRendering do Class.new(superclass) do include DecoratesBeforeRendering - attr_reader :ivar + attr_reader :ivar, :ivars - def initialize(sentinel, ivar) + def initialize(sentinel, ivar, ivars = nil) super(sentinel) @ivar = ivar + @ivars = ivars end end end - let(:instance) { klass.new(sentinel, ivar) } + let(:instance) { klass.new(sentinel, ivar, ivars) } let(:args) { double('*args') } context "no ivars" do @@ -92,5 +95,19 @@ describe DecoratesBeforeRendering do subclass_instance.render(args) end end + + context "Specify a different decorator class for an automatic decorator" do + it "should function correctly" do + klass.decorates(:ivars, :with => MyOtherCompletelyFakeModelDecorator) + klass.decorates(:ivar) + subclass_instance = Class.new(klass).new(sentinel, ivar, ivars) + sentinel.should_receive(:render).with(args) + MyOtherCompletelyFakeModelDecorator.should_receive(:decorate).with(ivars) + MyCompletelyFakeModelDecorator.should_receive(:decorate).with(ivar) + ivar.stub_chain(:class, :model_name => 'MyCompletelyFakeModel') + subclass_instance.render(args) + end + end end end +