parent
807a50cfa5
commit
4b933ef39d
16
README.md
16
README.md
|
@ -82,7 +82,7 @@ class ArticleDecorator < Draper::Decorator
|
|||
end
|
||||
|
||||
def published_at
|
||||
source.published_at.strftime("%A, %B %e")
|
||||
object.published_at.strftime("%A, %B %e")
|
||||
end
|
||||
end
|
||||
```
|
||||
|
@ -173,12 +173,12 @@ never have to type `h.` again.
|
|||
|
||||
When writing decorator methods you'll usually need to access the wrapped model.
|
||||
While you may choose to use delegation ([covered below](#delegating-methods))
|
||||
for convenience, you can always use the `source` (or its alias `model`):
|
||||
for convenience, you can always use the `object` (or its alias `model`):
|
||||
|
||||
```ruby
|
||||
class ArticleDecorator < Draper::Decorator
|
||||
def published_at
|
||||
source.published_at.strftime("%A, %B %e")
|
||||
object.published_at.strftime("%A, %B %e")
|
||||
end
|
||||
end
|
||||
```
|
||||
|
@ -250,7 +250,7 @@ Some pagination gems add methods to `ActiveRecord::Relation`. For example,
|
|||
[Kaminari](https://github.com/amatsuda/kaminari)'s `paginate` helper method
|
||||
requires the collection to implement `current_page`, `total_pages`, and
|
||||
`limit_value`. To expose these on a collection decorator, you can delegate to
|
||||
the `source`:
|
||||
the `object`:
|
||||
|
||||
```ruby
|
||||
class PaginatingDecorator < Draper::CollectionDecorator
|
||||
|
@ -260,7 +260,7 @@ end
|
|||
|
||||
The `delegate` method used here is the same as that added by [Active
|
||||
Support](http://api.rubyonrails.org/classes/Module.html#method-i-delegate),
|
||||
except that the `:to` option is not required; it defaults to `:source` when
|
||||
except that the `:to` option is not required; it defaults to `:object` when
|
||||
omitted.
|
||||
|
||||
[will_paginate](https://github.com/mislav/will_paginate) needs you to
|
||||
|
@ -444,7 +444,7 @@ end
|
|||
### Delegating Methods
|
||||
|
||||
When your decorator calls `delegate_all`, any method called on the decorator not
|
||||
defined in the decorator itself will be delegated to the decorated source. This
|
||||
defined in the decorator itself will be delegated to the decorated object. This
|
||||
is a very permissive interface.
|
||||
|
||||
If you want to strictly control which methods are called within views, you can
|
||||
|
@ -456,8 +456,8 @@ class ArticleDecorator < Draper::Decorator
|
|||
end
|
||||
```
|
||||
|
||||
We omit the `:to` argument here as it defaults to the `source` object. You could
|
||||
choose to delegate methods to other places like this:
|
||||
We omit the `:to` argument here as it defaults to the `object` being decorated.
|
||||
You could choose to delegate methods to other places like this:
|
||||
|
||||
```ruby
|
||||
class ArticleDecorator < Draper::Decorator
|
||||
|
|
|
@ -18,7 +18,7 @@ module Draper
|
|||
|
||||
# @private
|
||||
def delegatable?(method)
|
||||
source.respond_to?(method)
|
||||
object.respond_to?(method)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
|
|
@ -15,7 +15,7 @@ module Draper
|
|||
array_methods = Array.instance_methods - Object.instance_methods
|
||||
delegate :==, :as_json, *array_methods, to: :decorated_collection
|
||||
|
||||
# @param [Enumerable] source
|
||||
# @param [Enumerable] object
|
||||
# collection to decorate.
|
||||
# @option options [Class, nil] :with (nil)
|
||||
# the decorator class used to decorate each item. When `nil`, each item's
|
||||
|
@ -23,9 +23,9 @@ module Draper
|
|||
# @option options [Hash] :context ({})
|
||||
# extra data to be stored in the collection decorator and used in
|
||||
# user-defined methods, and passed to each item's decorator.
|
||||
def initialize(source, options = {})
|
||||
def initialize(object, options = {})
|
||||
options.assert_valid_keys(:with, :context)
|
||||
@source = source
|
||||
@object = object
|
||||
@decorator_class = options[:with]
|
||||
@context = options.fetch(:context, {})
|
||||
end
|
||||
|
@ -36,7 +36,7 @@ module Draper
|
|||
|
||||
# @return [Array] the decorated items.
|
||||
def decorated_collection
|
||||
@decorated_collection ||= source.map{|item| decorate_item(item)}
|
||||
@decorated_collection ||= object.map{|item| decorate_item(item)}
|
||||
end
|
||||
|
||||
# Delegated to the decorated collection when using the block form
|
||||
|
@ -47,12 +47,12 @@ module Draper
|
|||
decorated_collection.find(*args, &block)
|
||||
else
|
||||
ActiveSupport::Deprecation.warn("Using ActiveRecord's `find` on a CollectionDecorator is deprecated. Call `find` on a model, and then decorate the result", caller)
|
||||
decorate_item(source.find(*args))
|
||||
decorate_item(object.find(*args))
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#<#{self.class.name} of #{decorator_class || "inferred decorators"} for #{source.inspect}>"
|
||||
"#<#{self.class.name} of #{decorator_class || "inferred decorators"} for #{object.inspect}>"
|
||||
end
|
||||
|
||||
def context=(value)
|
||||
|
@ -80,7 +80,7 @@ module Draper
|
|||
protected
|
||||
|
||||
# @return the collection being decorated.
|
||||
attr_reader :source
|
||||
attr_reader :object
|
||||
|
||||
# Decorates the given item.
|
||||
def decorate_item(item)
|
||||
|
|
|
@ -73,7 +73,7 @@ module Draper
|
|||
#
|
||||
# @return [Boolean]
|
||||
def ===(other)
|
||||
super || (other.respond_to?(:source) && super(other.source))
|
||||
super || (other.respond_to?(:object) && super(other.object))
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ module Draper
|
|||
# @private
|
||||
def self.test_for_decorator(object, other)
|
||||
other.respond_to?(:decorated?) && other.decorated? &&
|
||||
other.respond_to?(:source) && test(object, other.source)
|
||||
other.respond_to?(:object) && test(object, other.object)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,7 +25,7 @@ module Draper
|
|||
attr_reader :factory, :owner, :association, :scope
|
||||
|
||||
def decorate
|
||||
associated = owner.source.send(association)
|
||||
associated = owner.object.send(association)
|
||||
associated = associated.send(scope) if scope
|
||||
|
||||
@decorated = factory.decorate(associated, context_args: owner.context)
|
||||
|
|
|
@ -8,9 +8,10 @@ module Draper
|
|||
include ActiveModel::Serializers::Xml
|
||||
|
||||
# @return the object being decorated.
|
||||
attr_reader :source
|
||||
alias_method :model, :source
|
||||
alias_method :to_source, :source
|
||||
attr_reader :object
|
||||
alias_method :model, :object
|
||||
alias_method :source, :object # TODO: deprecate this
|
||||
alias_method :to_source, :object # TODO: deprecate this
|
||||
|
||||
# @return [Hash] extra data to be used in user-defined methods.
|
||||
attr_accessor :context
|
||||
|
@ -21,16 +22,16 @@ module Draper
|
|||
# decorator to an instance of itself will create a decorator with the same
|
||||
# source as the original, rather than redecorating the other instance.
|
||||
#
|
||||
# @param [Object] source
|
||||
# @param [Object] object
|
||||
# object to decorate.
|
||||
# @option options [Hash] :context ({})
|
||||
# extra data to be stored in the decorator and used in user-defined
|
||||
# methods.
|
||||
def initialize(source, options = {})
|
||||
def initialize(object, options = {})
|
||||
options.assert_valid_keys(:context)
|
||||
@source = source
|
||||
@object = object
|
||||
@context = options.fetch(:context, {})
|
||||
handle_multiple_decoration(options) if source.instance_of?(self.class)
|
||||
handle_multiple_decoration(options) if object.instance_of?(self.class)
|
||||
end
|
||||
|
||||
class << self
|
||||
|
@ -126,22 +127,22 @@ module Draper
|
|||
# maps to `ProductsDecorator`), but otherwise defaults to
|
||||
# {Draper::CollectionDecorator}.
|
||||
#
|
||||
# @param [Object] source
|
||||
# @param [Object] object
|
||||
# collection to decorate.
|
||||
# @option options [Class, nil] :with (self)
|
||||
# the decorator class used to decorate each item. When `nil`, it is
|
||||
# inferred from each item.
|
||||
# @option options [Hash] :context
|
||||
# extra data to be stored in the collection decorator.
|
||||
def self.decorate_collection(source, options = {})
|
||||
def self.decorate_collection(object, options = {})
|
||||
options.assert_valid_keys(:with, :context)
|
||||
collection_decorator_class.new(source, options.reverse_merge(with: self))
|
||||
collection_decorator_class.new(object, options.reverse_merge(with: self))
|
||||
end
|
||||
|
||||
# @return [Array<Class>] the list of decorators that have been applied to
|
||||
# the object.
|
||||
def applied_decorators
|
||||
chain = source.respond_to?(:applied_decorators) ? source.applied_decorators : []
|
||||
chain = object.respond_to?(:applied_decorators) ? object.applied_decorators : []
|
||||
chain << self.class
|
||||
end
|
||||
|
||||
|
@ -159,29 +160,29 @@ module Draper
|
|||
true
|
||||
end
|
||||
|
||||
# Compares the source with a possibly-decorated object.
|
||||
# Compares the source object with a possibly-decorated object.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def ==(other)
|
||||
Draper::Decoratable::Equality.test(source, other)
|
||||
Draper::Decoratable::Equality.test(object, other)
|
||||
end
|
||||
|
||||
# Checks if `self.kind_of?(klass)` or `source.kind_of?(klass)`
|
||||
# Checks if `self.kind_of?(klass)` or `object.kind_of?(klass)`
|
||||
#
|
||||
# @param [Class] klass
|
||||
def kind_of?(klass)
|
||||
super || source.kind_of?(klass)
|
||||
super || object.kind_of?(klass)
|
||||
end
|
||||
alias_method :is_a?, :kind_of?
|
||||
|
||||
# Checks if `self.instance_of?(klass)` or `source.instance_of?(klass)`
|
||||
# Checks if `self.instance_of?(klass)` or `object.instance_of?(klass)`
|
||||
#
|
||||
# @param [Class] klass
|
||||
def instance_of?(klass)
|
||||
super || source.instance_of?(klass)
|
||||
super || object.instance_of?(klass)
|
||||
end
|
||||
|
||||
# In case source is nil
|
||||
# In case object is nil
|
||||
delegate :present?, :blank?
|
||||
|
||||
# ActiveModel compatibility
|
||||
|
@ -190,10 +191,10 @@ module Draper
|
|||
self
|
||||
end
|
||||
|
||||
# @return [Hash] the source's attributes, sliced to only include those
|
||||
# @return [Hash] the object's attributes, sliced to only include those
|
||||
# implemented by the decorator.
|
||||
def attributes
|
||||
source.attributes.select {|attribute, _| respond_to?(attribute) }
|
||||
object.attributes.select {|attribute, _| respond_to?(attribute) }
|
||||
end
|
||||
|
||||
# ActiveModel compatibility
|
||||
|
@ -233,9 +234,9 @@ module Draper
|
|||
end
|
||||
|
||||
def handle_multiple_decoration(options)
|
||||
if source.applied_decorators.last == self.class
|
||||
@context = source.context unless options.has_key?(:context)
|
||||
@source = source.source
|
||||
if object.applied_decorators.last == self.class
|
||||
@context = object.context unless options.has_key?(:context)
|
||||
@object = object.object
|
||||
else
|
||||
warn "Reapplying #{self.class} decorator to target that is already decorated with it. Call stack:\n#{caller(1).join("\n")}"
|
||||
end
|
||||
|
|
|
@ -2,12 +2,12 @@ module Draper
|
|||
module Delegation
|
||||
# @overload delegate(*methods, options = {})
|
||||
# Overrides {http://api.rubyonrails.org/classes/Module.html#method-i-delegate Module.delegate}
|
||||
# to make `:source` the default delegation target.
|
||||
# to make `:object` the default delegation target.
|
||||
#
|
||||
# @return [void]
|
||||
def delegate(*methods)
|
||||
options = methods.extract_options!
|
||||
super *methods, options.reverse_merge(to: :source)
|
||||
super *methods, options.reverse_merge(to: :object)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,7 +18,7 @@ module Draper
|
|||
# Decorates an object, inferring whether to create a singular or collection
|
||||
# decorator from the type of object passed.
|
||||
#
|
||||
# @param [Object] source
|
||||
# @param [Object] object
|
||||
# object to decorate.
|
||||
# @option options [Hash] context
|
||||
# extra data to be stored in the decorator. Overrides any context passed
|
||||
|
@ -26,9 +26,9 @@ module Draper
|
|||
# @option options [Object, Array] context_args (nil)
|
||||
# argument(s) to be passed to the context proc.
|
||||
# @return [Decorator, CollectionDecorator] the decorated object.
|
||||
def decorate(source, options = {})
|
||||
return nil if source.nil?
|
||||
Worker.new(decorator_class, source).call(options.reverse_merge(default_options))
|
||||
def decorate(object, options = {})
|
||||
return nil if object.nil?
|
||||
Worker.new(decorator_class, object).call(options.reverse_merge(default_options))
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -37,32 +37,32 @@ module Draper
|
|||
|
||||
# @private
|
||||
class Worker
|
||||
def initialize(decorator_class, source)
|
||||
def initialize(decorator_class, object)
|
||||
@decorator_class = decorator_class
|
||||
@source = source
|
||||
@object = object
|
||||
end
|
||||
|
||||
def call(options)
|
||||
update_context options
|
||||
decorator.call(source, options)
|
||||
decorator.call(object, options)
|
||||
end
|
||||
|
||||
def decorator
|
||||
return decorator_method(decorator_class) if decorator_class
|
||||
return source_decorator if decoratable?
|
||||
return object_decorator if decoratable?
|
||||
return decorator_method(Draper::CollectionDecorator) if collection?
|
||||
raise Draper::UninferrableDecoratorError.new(source.class)
|
||||
raise Draper::UninferrableDecoratorError.new(object.class)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :decorator_class, :source
|
||||
attr_reader :decorator_class, :object
|
||||
|
||||
def source_decorator
|
||||
def object_decorator
|
||||
if collection?
|
||||
->(source, options) { source.decorator_class.decorate_collection(source, options.reverse_merge(with: nil))}
|
||||
->(object, options) { object.decorator_class.decorate_collection(object, options.reverse_merge(with: nil))}
|
||||
else
|
||||
->(source, options) { source.decorate(options) }
|
||||
->(object, options) { object.decorate(options) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -75,11 +75,11 @@ module Draper
|
|||
end
|
||||
|
||||
def collection?
|
||||
source.respond_to?(:first)
|
||||
object.respond_to?(:first)
|
||||
end
|
||||
|
||||
def decoratable?
|
||||
source.respond_to?(:decorate)
|
||||
object.respond_to?(:decorate)
|
||||
end
|
||||
|
||||
def update_context(options)
|
||||
|
|
|
@ -11,7 +11,7 @@ class <%= class_name %>
|
|||
#
|
||||
# def created_at
|
||||
# helpers.content_tag :span, class: 'time' do
|
||||
# source.created_at.strftime("%a %m/%d/%y")
|
||||
# object.created_at.strftime("%a %m/%d/%y")
|
||||
# end
|
||||
# end
|
||||
|
||||
|
|
|
@ -84,8 +84,8 @@ module Draper
|
|||
collection = [Product.new, Product.new]
|
||||
decorator = CollectionDecorator.new(collection)
|
||||
|
||||
decorator.zip collection do |item, source|
|
||||
expect(item.source).to be source
|
||||
decorator.zip collection do |item, object|
|
||||
expect(item.object).to be object
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -109,8 +109,8 @@ module Draper
|
|||
describe ".delegate" do
|
||||
protect_class ProductsDecorator
|
||||
|
||||
it "defaults the :to option to :source" do
|
||||
Object.should_receive(:delegate).with(:foo, :bar, to: :source)
|
||||
it "defaults the :to option to :object" do
|
||||
Object.should_receive(:delegate).with(:foo, :bar, to: :object)
|
||||
ProductsDecorator.delegate :foo, :bar
|
||||
end
|
||||
|
||||
|
@ -131,12 +131,12 @@ module Draper
|
|||
end
|
||||
|
||||
context "without a block" do
|
||||
it "decorates source.find" do
|
||||
source = []
|
||||
it "decorates object.find" do
|
||||
object = []
|
||||
found = stub(decorate: :decorated)
|
||||
decorator = CollectionDecorator.new(source)
|
||||
decorator = CollectionDecorator.new(object)
|
||||
|
||||
source.should_receive(:find).and_return(found)
|
||||
object.should_receive(:find).and_return(found)
|
||||
ActiveSupport::Deprecation.silence do
|
||||
expect(decorator.find(1)).to be :decorated
|
||||
end
|
||||
|
@ -162,17 +162,17 @@ module Draper
|
|||
end
|
||||
|
||||
describe "#==" do
|
||||
context "when comparing to a collection decorator with the same source" do
|
||||
context "when comparing to a collection decorator with the same object" do
|
||||
it "returns true" do
|
||||
source = [Product.new, Product.new]
|
||||
decorator = CollectionDecorator.new(source)
|
||||
other = ProductsDecorator.new(source)
|
||||
object = [Product.new, Product.new]
|
||||
decorator = CollectionDecorator.new(object)
|
||||
other = ProductsDecorator.new(object)
|
||||
|
||||
expect(decorator == other).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "when comparing to a collection decorator with a different source" do
|
||||
context "when comparing to a collection decorator with a different object" do
|
||||
it "returns false" do
|
||||
decorator = CollectionDecorator.new([Product.new, Product.new])
|
||||
other = ProductsDecorator.new([Product.new, Product.new])
|
||||
|
@ -183,9 +183,9 @@ module Draper
|
|||
|
||||
context "when comparing to a collection of the same items" do
|
||||
it "returns true" do
|
||||
source = [Product.new, Product.new]
|
||||
decorator = CollectionDecorator.new(source)
|
||||
other = source.dup
|
||||
object = [Product.new, Product.new]
|
||||
decorator = CollectionDecorator.new(object)
|
||||
other = object.dup
|
||||
|
||||
expect(decorator == other).to be_true
|
||||
end
|
||||
|
@ -201,10 +201,10 @@ module Draper
|
|||
end
|
||||
|
||||
context "when the decorated collection has been modified" do
|
||||
it "is no longer equal to the source" do
|
||||
source = [Product.new, Product.new]
|
||||
decorator = CollectionDecorator.new(source)
|
||||
other = source.dup
|
||||
it "is no longer equal to the object" do
|
||||
object = [Product.new, Product.new]
|
||||
decorator = CollectionDecorator.new(object)
|
||||
other = object.dup
|
||||
|
||||
decorator << Product.new.decorate
|
||||
expect(decorator == other).to be_false
|
||||
|
|
|
@ -10,7 +10,7 @@ module Draper
|
|||
decorator = product.decorate
|
||||
|
||||
expect(decorator).to be_a ProductDecorator
|
||||
expect(decorator.source).to be product
|
||||
expect(decorator.object).to be product
|
||||
end
|
||||
|
||||
it "accepts context" do
|
||||
|
@ -89,19 +89,19 @@ module Draper
|
|||
end
|
||||
|
||||
it "is true for a decorated instance" do
|
||||
decorator = double(source: Product.new)
|
||||
decorator = double(object: Product.new)
|
||||
|
||||
expect(Product === decorator).to be_true
|
||||
end
|
||||
|
||||
it "is true for a decorated derived instance" do
|
||||
decorator = double(source: Class.new(Product).new)
|
||||
decorator = double(object: Class.new(Product).new)
|
||||
|
||||
expect(Product === decorator).to be_true
|
||||
end
|
||||
|
||||
it "is false for a decorated unrelated instance" do
|
||||
decorator = double(source: Model.new)
|
||||
decorator = double(object: Model.new)
|
||||
|
||||
expect(Product === decorator).to be_false
|
||||
end
|
||||
|
|
|
@ -43,8 +43,8 @@ module Draper
|
|||
Factory.stub new: factory
|
||||
associated = double
|
||||
owner_context = {foo: "bar"}
|
||||
source = double(association: associated)
|
||||
owner = double(source: source, context: owner_context)
|
||||
object = double(association: associated)
|
||||
owner = double(object: object, context: owner_context)
|
||||
decorated_association = DecoratedAssociation.new(owner, :association, {})
|
||||
decorated = double
|
||||
|
||||
|
@ -55,7 +55,7 @@ module Draper
|
|||
it "memoizes" do
|
||||
factory = double
|
||||
Factory.stub new: factory
|
||||
owner = double(source: double(association: double), context: {})
|
||||
owner = double(object: double(association: double), context: {})
|
||||
decorated_association = DecoratedAssociation.new(owner, :association, {})
|
||||
decorated = double
|
||||
|
||||
|
@ -69,8 +69,8 @@ module Draper
|
|||
factory = double
|
||||
Factory.stub new: factory
|
||||
scoped = double
|
||||
source = double(association: double(applied_scope: scoped))
|
||||
owner = double(source: source, context: {})
|
||||
object = double(association: double(applied_scope: scoped))
|
||||
owner = double(object: object, context: {})
|
||||
decorated_association = DecoratedAssociation.new(owner, :association, scope: :applied_scope)
|
||||
decorated = double
|
||||
|
||||
|
|
|
@ -41,15 +41,15 @@ module Draper
|
|||
|
||||
describe "the generated method" do
|
||||
it "decorates the instance variable" do
|
||||
source = double
|
||||
object = double
|
||||
factory = double
|
||||
Factory.stub new: factory
|
||||
|
||||
controller_class.decorates_assigned :article
|
||||
controller = controller_class.new
|
||||
controller.instance_variable_set "@article", source
|
||||
controller.instance_variable_set "@article", object
|
||||
|
||||
factory.should_receive(:decorate).with(source, context_args: controller).and_return(:decorated)
|
||||
factory.should_receive(:decorate).with(object, context_args: controller).and_return(:decorated)
|
||||
expect(controller.article).to be :decorated
|
||||
end
|
||||
|
||||
|
|
|
@ -17,11 +17,11 @@ module Draper
|
|||
end
|
||||
end
|
||||
|
||||
it "sets the source" do
|
||||
source = Model.new
|
||||
decorator = Decorator.new(source)
|
||||
it "sets the object" do
|
||||
object = Model.new
|
||||
decorator = Decorator.new(object)
|
||||
|
||||
expect(decorator.source).to be source
|
||||
expect(decorator.object).to be object
|
||||
end
|
||||
|
||||
it "stores context" do
|
||||
|
@ -32,12 +32,12 @@ module Draper
|
|||
end
|
||||
|
||||
context "when decorating an instance of itself" do
|
||||
it "applies to the source instead" do
|
||||
source = Model.new
|
||||
decorated = Decorator.new(source)
|
||||
it "applies to the object instead" do
|
||||
object = Model.new
|
||||
decorated = Decorator.new(object)
|
||||
redecorated = Decorator.new(decorated)
|
||||
|
||||
expect(redecorated.source).to be source
|
||||
expect(redecorated.object).to be object
|
||||
end
|
||||
|
||||
context "with context" do
|
||||
|
@ -65,7 +65,7 @@ module Draper
|
|||
decorated = OtherDecorator.new(Model.new)
|
||||
redecorated = Decorator.new(decorated)
|
||||
|
||||
expect(redecorated.source).to be decorated
|
||||
expect(redecorated.object).to be decorated
|
||||
end
|
||||
|
||||
context "when it has been applied previously" do
|
||||
|
@ -85,7 +85,7 @@ module Draper
|
|||
Object.any_instance.stub(:warn)
|
||||
redecorated = Decorator.decorate(decorated)
|
||||
|
||||
expect(redecorated.source).to be decorated
|
||||
expect(redecorated.object).to be decorated
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -116,10 +116,10 @@ module Draper
|
|||
|
||||
context "without a custom collection decorator" do
|
||||
it "creates a CollectionDecorator using itself for each item" do
|
||||
source = [Model.new]
|
||||
object = [Model.new]
|
||||
|
||||
CollectionDecorator.should_receive(:new).with(source, with: Decorator)
|
||||
Decorator.decorate_collection(source)
|
||||
CollectionDecorator.should_receive(:new).with(object, with: Decorator)
|
||||
Decorator.decorate_collection(object)
|
||||
end
|
||||
|
||||
it "passes options to the collection decorator" do
|
||||
|
@ -132,10 +132,10 @@ module Draper
|
|||
|
||||
context "with a custom collection decorator" do
|
||||
it "creates a custom collection decorator using itself for each item" do
|
||||
source = [Model.new]
|
||||
object = [Model.new]
|
||||
|
||||
ProductsDecorator.should_receive(:new).with(source, with: ProductDecorator)
|
||||
ProductDecorator.decorate_collection(source)
|
||||
ProductsDecorator.should_receive(:new).with(object, with: ProductDecorator)
|
||||
ProductDecorator.decorate_collection(object)
|
||||
end
|
||||
|
||||
it "passes options to the collection decorator" do
|
||||
|
@ -319,14 +319,35 @@ module Draper
|
|||
end
|
||||
end
|
||||
|
||||
describe "#source" do
|
||||
describe "#object" do
|
||||
it "returns the wrapped object" do
|
||||
source = Model.new
|
||||
decorator = Decorator.new(source)
|
||||
object = Model.new
|
||||
decorator = Decorator.new(object)
|
||||
|
||||
expect(decorator.source).to be source
|
||||
expect(decorator.model).to be source
|
||||
expect(decorator.to_source).to be source
|
||||
expect(decorator.object).to be object
|
||||
expect(decorator.model).to be object
|
||||
expect(decorator.to_source).to be object
|
||||
end
|
||||
|
||||
it "is aliased to #model" do
|
||||
object = Model.new
|
||||
decorator = Decorator.new(object)
|
||||
|
||||
expect(decorator.model).to be object
|
||||
end
|
||||
|
||||
it "is aliased to #source" do
|
||||
object = Model.new
|
||||
decorator = Decorator.new(object)
|
||||
|
||||
expect(decorator.source).to be object
|
||||
end
|
||||
|
||||
it "is aliased to #to_source" do
|
||||
object = Model.new
|
||||
decorator = Decorator.new(object)
|
||||
|
||||
expect(decorator.to_source).to be object
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -339,7 +360,7 @@ module Draper
|
|||
end
|
||||
|
||||
describe "#to_param" do
|
||||
it "delegates to the source" do
|
||||
it "delegates to the object" do
|
||||
decorator = Decorator.new(double(to_param: :delegated))
|
||||
|
||||
expect(decorator.to_param).to be :delegated
|
||||
|
@ -347,7 +368,7 @@ module Draper
|
|||
end
|
||||
|
||||
describe "#present?" do
|
||||
it "delegates to the source" do
|
||||
it "delegates to the object" do
|
||||
decorator = Decorator.new(double(present?: :delegated))
|
||||
|
||||
expect(decorator.present?).to be :delegated
|
||||
|
@ -355,7 +376,7 @@ module Draper
|
|||
end
|
||||
|
||||
describe "#blank?" do
|
||||
it "delegates to the source" do
|
||||
it "delegates to the object" do
|
||||
decorator = Decorator.new(double(blank?: :delegated))
|
||||
|
||||
expect(decorator.blank?).to be :delegated
|
||||
|
@ -363,7 +384,7 @@ module Draper
|
|||
end
|
||||
|
||||
describe "#to_partial_path" do
|
||||
it "delegates to the source" do
|
||||
it "delegates to the object" do
|
||||
decorator = Decorator.new(double(to_partial_path: :delegated))
|
||||
|
||||
expect(decorator.to_partial_path).to be :delegated
|
||||
|
@ -371,7 +392,7 @@ module Draper
|
|||
end
|
||||
|
||||
describe "#attributes" do
|
||||
it "returns only the source's attributes that are implemented by the decorator" do
|
||||
it "returns only the object's attributes that are implemented by the decorator" do
|
||||
decorator = Decorator.new(double(attributes: {foo: "bar", baz: "qux"}))
|
||||
decorator.stub(:foo)
|
||||
|
||||
|
@ -388,35 +409,35 @@ module Draper
|
|||
end
|
||||
|
||||
describe "#==" do
|
||||
it "works for a source that does not include Decoratable" do
|
||||
source = Object.new
|
||||
decorator = Decorator.new(source)
|
||||
it "works for a object that does not include Decoratable" do
|
||||
object = Object.new
|
||||
decorator = Decorator.new(object)
|
||||
|
||||
expect(decorator).to eq Decorator.new(source)
|
||||
expect(decorator).to eq Decorator.new(object)
|
||||
end
|
||||
|
||||
it "works for a multiply-decorated source that does not include Decoratable" do
|
||||
source = Object.new
|
||||
decorator = Decorator.new(source)
|
||||
it "works for a multiply-decorated object that does not include Decoratable" do
|
||||
object = Object.new
|
||||
decorator = Decorator.new(object)
|
||||
|
||||
expect(decorator).to eq ProductDecorator.new(Decorator.new(source))
|
||||
expect(decorator).to eq ProductDecorator.new(Decorator.new(object))
|
||||
end
|
||||
|
||||
it "is true when source #== is true" do
|
||||
source = Model.new
|
||||
decorator = Decorator.new(source)
|
||||
other = double(source: Model.new)
|
||||
it "is true when object #== is true" do
|
||||
object = Model.new
|
||||
decorator = Decorator.new(object)
|
||||
other = double(object: Model.new)
|
||||
|
||||
source.should_receive(:==).with(other).and_return(true)
|
||||
object.should_receive(:==).with(other).and_return(true)
|
||||
expect(decorator == other).to be_true
|
||||
end
|
||||
|
||||
it "is false when source #== is false" do
|
||||
source = Model.new
|
||||
decorator = Decorator.new(source)
|
||||
other = double(source: Model.new)
|
||||
it "is false when object #== is false" do
|
||||
object = Model.new
|
||||
decorator = Decorator.new(object)
|
||||
other = double(object: Model.new)
|
||||
|
||||
source.should_receive(:==).with(other).and_return(false)
|
||||
object.should_receive(:==).with(other).and_return(false)
|
||||
expect(decorator == other).to be_false
|
||||
end
|
||||
|
||||
|
@ -441,8 +462,8 @@ module Draper
|
|||
describe ".delegate" do
|
||||
protect_class Decorator
|
||||
|
||||
it "defaults the :to option to :source" do
|
||||
Object.should_receive(:delegate).with(:foo, :bar, to: :source)
|
||||
it "defaults the :to option to :object" do
|
||||
Object.should_receive(:delegate).with(:foo, :bar, to: :object)
|
||||
Decorator.delegate :foo, :bar
|
||||
end
|
||||
|
||||
|
@ -458,7 +479,7 @@ module Draper
|
|||
before { Decorator.delegate_all }
|
||||
|
||||
describe "#method_missing" do
|
||||
it "delegates missing methods that exist on the source" do
|
||||
it "delegates missing methods that exist on the object" do
|
||||
decorator = Decorator.new(double(hello_world: :delegated))
|
||||
|
||||
expect(decorator.hello_world).to be :delegated
|
||||
|
@ -473,9 +494,9 @@ module Draper
|
|||
end
|
||||
|
||||
it "passes blocks to delegated methods" do
|
||||
source = Model.new
|
||||
source.stub(:hello_world).and_return{|*args, &block| block.call}
|
||||
decorator = Decorator.new(source)
|
||||
object = Model.new
|
||||
object.stub(:hello_world).and_return{|*args, &block| block.call}
|
||||
decorator = Decorator.new(object)
|
||||
|
||||
expect(decorator.hello_world{:yielded}).to be :yielded
|
||||
end
|
||||
|
@ -487,21 +508,21 @@ module Draper
|
|||
end
|
||||
|
||||
it "delegates already-delegated methods" do
|
||||
source = Class.new{ delegate :bar, to: :foo }.new
|
||||
source.stub foo: double(bar: :delegated)
|
||||
decorator = Decorator.new(source)
|
||||
object = Class.new{ delegate :bar, to: :foo }.new
|
||||
object.stub foo: double(bar: :delegated)
|
||||
decorator = Decorator.new(object)
|
||||
|
||||
expect(decorator.bar).to be :delegated
|
||||
end
|
||||
|
||||
it "does not delegate private methods" do
|
||||
source = Class.new{ private; def hello_world; end }.new
|
||||
decorator = Decorator.new(source)
|
||||
object = Class.new{ private; def hello_world; end }.new
|
||||
decorator = Decorator.new(object)
|
||||
|
||||
expect{decorator.hello_world}.to raise_error NoMethodError
|
||||
end
|
||||
|
||||
it "does not delegate methods that do not exist on the source" do
|
||||
it "does not delegate methods that do not exist on the object" do
|
||||
decorator = Decorator.new(Model.new)
|
||||
|
||||
expect(decorator.methods).not_to include :hello_world
|
||||
|
@ -542,7 +563,7 @@ module Draper
|
|||
expect(decorator).to respond_to :hello_world
|
||||
end
|
||||
|
||||
it "returns true for the source's methods" do
|
||||
it "returns true for the object's methods" do
|
||||
decorator = Decorator.new(double(hello_world: :delegated))
|
||||
|
||||
expect(decorator).to respond_to :hello_world
|
||||
|
@ -556,9 +577,9 @@ module Draper
|
|||
expect(decorator.respond_to?(:hello_world, true)).to be_true
|
||||
end
|
||||
|
||||
it "returns false for the source's private methods" do
|
||||
source = Class.new{private; def hello_world; end}.new
|
||||
decorator = Decorator.new(source)
|
||||
it "returns false for the object's private methods" do
|
||||
object = Class.new{private; def hello_world; end}.new
|
||||
decorator = Decorator.new(object)
|
||||
|
||||
expect(decorator.respond_to?(:hello_world, true)).to be_false
|
||||
end
|
||||
|
@ -596,8 +617,8 @@ module Draper
|
|||
|
||||
describe "#respond_to_missing?" do
|
||||
it "allows #method to be called on delegated methods" do
|
||||
source = Class.new{def hello_world; end}.new
|
||||
decorator = Decorator.new(source)
|
||||
object = Class.new{def hello_world; end}.new
|
||||
decorator = Decorator.new(object)
|
||||
|
||||
expect { decorator.method(:hello_world) }.not_to raise_error NameError
|
||||
expect(decorator.method(:hello_world)).not_to be_nil
|
||||
|
|
|
@ -15,7 +15,7 @@ module Draper
|
|||
end
|
||||
|
||||
describe "#decorate" do
|
||||
context "when source is nil" do
|
||||
context "when object is nil" do
|
||||
it "returns nil" do
|
||||
factory = Factory.new
|
||||
|
||||
|
@ -31,12 +31,12 @@ module Draper
|
|||
expect(factory.decorate(double)).to be :decorated
|
||||
end
|
||||
|
||||
it "passes the source to the worker" do
|
||||
it "passes the object to the worker" do
|
||||
factory = Factory.new
|
||||
source = double
|
||||
object = double
|
||||
|
||||
Factory::Worker.should_receive(:new).with(anything(), source).and_return(->(*){})
|
||||
factory.decorate(source)
|
||||
Factory::Worker.should_receive(:new).with(anything(), object).and_return(->(*){})
|
||||
factory.decorate(object)
|
||||
end
|
||||
|
||||
context "when the :with option was given" do
|
||||
|
@ -95,13 +95,13 @@ module Draper
|
|||
|
||||
describe "#call" do
|
||||
it "calls the decorator method" do
|
||||
source = double
|
||||
object = double
|
||||
options = {foo: "bar"}
|
||||
worker = Factory::Worker.new(double, source)
|
||||
worker = Factory::Worker.new(double, object)
|
||||
decorator = ->(*){}
|
||||
worker.stub decorator: decorator
|
||||
|
||||
decorator.should_receive(:call).with(source, options).and_return(:decorated)
|
||||
decorator.should_receive(:call).with(object, options).and_return(:decorated)
|
||||
expect(worker.call(options)).to be :decorated
|
||||
end
|
||||
|
||||
|
@ -159,7 +159,7 @@ module Draper
|
|||
end
|
||||
|
||||
describe "#decorator" do
|
||||
context "for a singular source" do
|
||||
context "for a singular object" do
|
||||
context "when decorator_class is specified" do
|
||||
it "returns the .decorate method from the decorator" do
|
||||
decorator_class = Class.new(Decorator)
|
||||
|
@ -170,21 +170,21 @@ module Draper
|
|||
end
|
||||
|
||||
context "when decorator_class is unspecified" do
|
||||
context "and the source is decoratable" do
|
||||
it "returns the source's #decorate method" do
|
||||
source = double
|
||||
context "and the object is decoratable" do
|
||||
it "returns the object's #decorate method" do
|
||||
object = double
|
||||
options = {foo: "bar"}
|
||||
worker = Factory::Worker.new(nil, source)
|
||||
worker = Factory::Worker.new(nil, object)
|
||||
|
||||
source.should_receive(:decorate).with(options).and_return(:decorated)
|
||||
expect(worker.decorator.call(source, options)).to be :decorated
|
||||
object.should_receive(:decorate).with(options).and_return(:decorated)
|
||||
expect(worker.decorator.call(object, options)).to be :decorated
|
||||
end
|
||||
end
|
||||
|
||||
context "and the source is not decoratable" do
|
||||
context "and the object is not decoratable" do
|
||||
it "raises an error" do
|
||||
source = double
|
||||
worker = Factory::Worker.new(nil, source)
|
||||
object = double
|
||||
worker = Factory::Worker.new(nil, object)
|
||||
|
||||
expect{worker.decorator}.to raise_error UninferrableDecoratorError
|
||||
end
|
||||
|
@ -192,7 +192,7 @@ module Draper
|
|||
end
|
||||
end
|
||||
|
||||
context "for a collection source" do
|
||||
context "for a collection object" do
|
||||
context "when decorator_class is a CollectionDecorator" do
|
||||
it "returns the .decorate method from the collection decorator" do
|
||||
decorator_class = Class.new(CollectionDecorator)
|
||||
|
@ -212,20 +212,20 @@ module Draper
|
|||
end
|
||||
|
||||
context "when decorator_class is unspecified" do
|
||||
context "and the source is decoratable" do
|
||||
it "returns the .decorate_collection method from the source's decorator" do
|
||||
source = []
|
||||
context "and the object is decoratable" do
|
||||
it "returns the .decorate_collection method from the object's decorator" do
|
||||
object = []
|
||||
decorator_class = Class.new(Decorator)
|
||||
source.stub decorator_class: decorator_class
|
||||
source.stub decorate: nil
|
||||
worker = Factory::Worker.new(nil, source)
|
||||
object.stub decorator_class: decorator_class
|
||||
object.stub decorate: nil
|
||||
worker = Factory::Worker.new(nil, object)
|
||||
|
||||
decorator_class.should_receive(:decorate_collection).with(source, foo: "bar", with: nil).and_return(:decorated)
|
||||
expect(worker.decorator.call(source, foo: "bar")).to be :decorated
|
||||
decorator_class.should_receive(:decorate_collection).with(object, foo: "bar", with: nil).and_return(:decorated)
|
||||
expect(worker.decorator.call(object, foo: "bar")).to be :decorated
|
||||
end
|
||||
end
|
||||
|
||||
context "and the source is not decoratable" do
|
||||
context "and the object is not decoratable" do
|
||||
it "returns the .decorate method from CollectionDecorator" do
|
||||
worker = Factory::Worker.new(nil, [])
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ module Draper
|
|||
Product.stub(:find).and_return(found)
|
||||
decorator = ProductDecorator.find(1)
|
||||
expect(decorator).to be_a ProductDecorator
|
||||
expect(decorator.source).to be found
|
||||
expect(decorator.object).to be found
|
||||
end
|
||||
|
||||
it "passes context to the decorator" do
|
||||
|
@ -39,7 +39,7 @@ module Draper
|
|||
Product.stub(:find_by_name).and_return(found)
|
||||
decorator = ProductDecorator.find_by_name("apples")
|
||||
expect(decorator).to be_a ProductDecorator
|
||||
expect(decorator.source).to be found
|
||||
expect(decorator.object).to be found
|
||||
end
|
||||
|
||||
it "proxies complex ProductDecorators" do
|
||||
|
@ -127,7 +127,7 @@ module Draper
|
|||
Product.stub(:first).and_return(first)
|
||||
decorator = ProductDecorator.first
|
||||
expect(decorator).to be_a ProductDecorator
|
||||
expect(decorator.source).to be first
|
||||
expect(decorator.object).to be first
|
||||
end
|
||||
|
||||
it "passes context to the decorator" do
|
||||
|
@ -150,7 +150,7 @@ module Draper
|
|||
Product.stub(:last).and_return(last)
|
||||
decorator = ProductDecorator.last
|
||||
expect(decorator).to be_a ProductDecorator
|
||||
expect(decorator.source).to be last
|
||||
expect(decorator.object).to be last
|
||||
end
|
||||
|
||||
it "passes context to the decorator" do
|
||||
|
|
|
@ -15,7 +15,7 @@ class PostDecorator < Draper::Decorator
|
|||
end
|
||||
|
||||
def path_with_model
|
||||
h.post_path(source)
|
||||
h.post_path(object)
|
||||
end
|
||||
|
||||
def path_with_id
|
||||
|
@ -23,7 +23,7 @@ class PostDecorator < Draper::Decorator
|
|||
end
|
||||
|
||||
def url_with_model
|
||||
h.post_url(source)
|
||||
h.post_url(object)
|
||||
end
|
||||
|
||||
def url_with_id
|
||||
|
|
|
@ -9,8 +9,8 @@ Draper::ViewContext.test_strategy :fast
|
|||
Post = Struct.new(:id) { extend ActiveModel::Naming }
|
||||
|
||||
describe PostDecorator do
|
||||
let(:decorator) { PostDecorator.new(source) }
|
||||
let(:source) { Post.new(42) }
|
||||
let(:decorator) { PostDecorator.new(object) }
|
||||
let(:object) { Post.new(42) }
|
||||
|
||||
it "can use built-in helpers" do
|
||||
expect(decorator.truncated).to eq "Once upon a..."
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe PostDecorator do
|
||||
let(:decorator) { PostDecorator.new(source) }
|
||||
let(:source) { Post.create }
|
||||
let(:decorator) { PostDecorator.new(object) }
|
||||
let(:object) { Post.create }
|
||||
|
||||
it "can use built-in helpers" do
|
||||
expect(decorator.truncated).to eq "Once upon a..."
|
||||
|
@ -17,23 +17,23 @@ describe PostDecorator do
|
|||
end
|
||||
|
||||
it "can use path helpers with its model" do
|
||||
expect(decorator.path_with_model).to eq "/en/posts/#{source.id}"
|
||||
expect(decorator.path_with_model).to eq "/en/posts/#{object.id}"
|
||||
end
|
||||
|
||||
it "can use path helpers with its id" do
|
||||
expect(decorator.path_with_id).to eq "/en/posts/#{source.id}"
|
||||
expect(decorator.path_with_id).to eq "/en/posts/#{object.id}"
|
||||
end
|
||||
|
||||
it "can use url helpers with its model" do
|
||||
expect(decorator.url_with_model).to eq "http://www.example.com:12345/en/posts/#{source.id}"
|
||||
expect(decorator.url_with_model).to eq "http://www.example.com:12345/en/posts/#{object.id}"
|
||||
end
|
||||
|
||||
it "can use url helpers with its id" do
|
||||
expect(decorator.url_with_id).to eq "http://www.example.com:12345/en/posts/#{source.id}"
|
||||
expect(decorator.url_with_id).to eq "http://www.example.com:12345/en/posts/#{object.id}"
|
||||
end
|
||||
|
||||
it "can be passed implicitly to url_for" do
|
||||
expect(decorator.link).to eq "<a href=\"/en/posts/#{source.id}\">#{source.id}</a>"
|
||||
expect(decorator.link).to eq "<a href=\"/en/posts/#{object.id}\">#{object.id}</a>"
|
||||
end
|
||||
|
||||
it "serializes overriden attributes" do
|
||||
|
|
|
@ -8,32 +8,32 @@ shared_examples_for "decoration-aware #==" do |subject|
|
|||
end
|
||||
|
||||
it "is true for a decorated version of itself" do
|
||||
decorated = double(source: subject, decorated?: true)
|
||||
decorated = double(object: subject, decorated?: true)
|
||||
|
||||
expect(subject == decorated).to be_true
|
||||
end
|
||||
|
||||
it "is false for a decorated other object" do
|
||||
decorated = double(source: Object.new, decorated?: true)
|
||||
decorated = double(object: Object.new, decorated?: true)
|
||||
|
||||
expect(subject == decorated).to be_false
|
||||
end
|
||||
|
||||
it "is false for a decoratable object with a `source` association" do
|
||||
decoratable = double(source: subject, decorated?: false)
|
||||
it "is false for a decoratable object with a `object` association" do
|
||||
decoratable = double(object: subject, decorated?: false)
|
||||
|
||||
expect(subject == decoratable).to be_false
|
||||
end
|
||||
|
||||
it "is false for an undecoratable object with a `source` association" do
|
||||
undecoratable = double(source: subject)
|
||||
it "is false for an undecoratable object with a `object` association" do
|
||||
undecoratable = double(object: subject)
|
||||
|
||||
expect(subject == undecoratable).to be_false
|
||||
end
|
||||
|
||||
it "is true for a multiply-decorated version of itself" do
|
||||
decorated = double(source: subject, decorated?: true)
|
||||
redecorated = double(source: decorated, decorated?: true)
|
||||
decorated = double(object: subject, decorated?: true)
|
||||
redecorated = double(object: decorated, decorated?: true)
|
||||
|
||||
expect(subject == redecorated).to be_true
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue