Optimization: Optimize CollectionDecorator Enumerable behavior (#707)
* Optimization: Prevent duplicate iteration * Don't delegate Enumerable instance methods since CollectionDecorator includes Enumerable itself
This commit is contained in:
parent
a1d854a7f4
commit
f6a7b17a8a
|
@ -15,7 +15,7 @@ module Draper
|
||||||
# to each item's decorator.
|
# to each item's decorator.
|
||||||
attr_accessor :context
|
attr_accessor :context
|
||||||
|
|
||||||
array_methods = Array.instance_methods - Object.instance_methods
|
array_methods = Array.instance_methods - Object.instance_methods - Enumerable.instance_methods
|
||||||
delegate :==, :as_json, *array_methods, to: :decorated_collection
|
delegate :==, :as_json, *array_methods, to: :decorated_collection
|
||||||
|
|
||||||
# @param [Enumerable] object
|
# @param [Enumerable] object
|
||||||
|
@ -42,6 +42,23 @@ module Draper
|
||||||
@decorated_collection ||= object.map{|item| decorate_item(item)}
|
@decorated_collection ||= object.map{|item| decorate_item(item)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Optimization to prevent unnecessary iteration (useful for larger collections).
|
||||||
|
# Iterates over the collection, decorating objects as it goes. If the decorated collection is
|
||||||
|
# already set, iterate over it instead.
|
||||||
|
def each(&block)
|
||||||
|
if @decorated_collection
|
||||||
|
@decorated_collection.each(&block)
|
||||||
|
else
|
||||||
|
@decorated_collection = []
|
||||||
|
object.each do |item|
|
||||||
|
decorated_item = decorate_item(item)
|
||||||
|
@decorated_collection << decorated_item
|
||||||
|
|
||||||
|
block.call(decorated_item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
delegate :find, to: :decorated_collection
|
delegate :find, to: :decorated_collection
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
|
|
|
@ -288,5 +288,38 @@ module Draper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#each" do
|
||||||
|
it "iterates over the collection, decorating as it goes" do
|
||||||
|
collection = [Product.new]
|
||||||
|
decorator = CollectionDecorator.new(collection)
|
||||||
|
|
||||||
|
expect(collection).to_not receive(:map)
|
||||||
|
decorator.each { |product| product.decorated? }
|
||||||
|
expect(decorator.instance_variable_get(:@decorated_collection)[0]).to be_decorated
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uses decorated_collection if already set" do
|
||||||
|
decorated_collection = double(:decorated_collection)
|
||||||
|
decorator = CollectionDecorator.new([])
|
||||||
|
decorator.instance_variable_set(:@decorated_collection, decorated_collection)
|
||||||
|
|
||||||
|
expect(decorated_collection).to receive(:each)
|
||||||
|
|
||||||
|
decorator.each
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Enumerable methods" do
|
||||||
|
it "doesn't delegate Enumerable methods to its decorated collection" do
|
||||||
|
decorated_collection = double(:decorated_collection)
|
||||||
|
decorator = CollectionDecorator.new([])
|
||||||
|
decorator.instance_variable_set(:@decorated_collection, decorated_collection)
|
||||||
|
|
||||||
|
expect(decorated_collection).to_not receive(:map)
|
||||||
|
|
||||||
|
decorator.map
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue