Open
Description
Hi.
I found out that Fog::Collection donsn't do lazy_load
while being converted by Kernel.Array
method that implicitly called by several Array methods.
For example, Array#concat
converts its operand by Array()
and Fog::Collection instance passed to Array#concat
won't do lazy_load
so an empty array will be concatinated.
This causes making flat_map
(this internally uses Array#concat
to gather the results) over Fog::Collections generate empty results.
It works well by manually calling all
to load explicitly.
This is intentional? I think this behavior is bit confusable IMHO.
require "bundler/inline"
gemfile do
source "https://rubygems.org"
gem "fog-core"
gem "minitest"
gem "minitest-reporters"
end
require "securerandom"
require "minitest/unit"
require "minitest/autorun"
ENV["MINITEST_REPORTER"] ||= "SpecReporter"
Minitest::Reporters.use!
def simulate_fetch(n)
n.times.map do
{ 'id' => SecureRandom.uuid, 'value' => Time.now.iso8601 }
end
end
class Foo < Fog::Model
identity :id
attribute :value
end
class FooCollection < Fog::Collection
model Foo
def initialize(fetch_size)
super()
@fetch_size = fetch_size
end
# Roughly same implementation with
# https://github.com/fog/fog-aws/blob/e0d9ad4a1a78f46634c51e80583281b389c5212e/lib/fog/aws/models/storage/versions.rb#L12-L20
#
# `lazy_load` will call `all`
# https://github.com/fog/fog-core/blob/e359e66ddd81e7b0811bc0ff00b133722fb49ef8/lib/fog/core/collection.rb#L111
def all(options = {})
data = simulate_fetch @fetch_size
load data
end
def new(attr = {})
$count = $count.to_i + 1
super
end
end
class Test < MiniTest::Unit::TestCase
def test_fetch
a = FooCollection.new 1
b = FooCollection.new 2
assert_equal 1, a.size
assert_equal 2, b.size
end
def test_concat
a = FooCollection.new 1
b = FooCollection.new 2
result = a.concat b
assert_equal 3, result.size
end
def test_flat_map
a = FooCollection.new 1
b = FooCollection.new 2
result = [a, b].flat_map { |item| item }
assert_equal 3, result.size
end
def test_flat_map_2
a = FooCollection.new 1
b = FooCollection.new 2
result = [a, b].each(&:all).flat_map { |item| item }
assert_equal 3, result.size
end
def setup
puts ">> $count = #{$count}"
end
def teardown
puts "<< $count = #{$count}"
end
end
__END__
$ ruby test.rb
MiniTest::Unit::TestCase is now Minitest::Test. From test.rb:52:in `<main>'
Started with run options --seed 36760
Test
>> $count =
<< $count = 3
test_fetch PASS (0.00s)
>> $count = 3
<< $count = 3
test_flat_map FAIL (0.00s)
Expected: 3
Actual: 0
test.rb:75:in `test_flat_map'
>> $count = 3
<< $count = 6
test_flat_map_2 PASS (0.00s)
>> $count = 6
<< $count = 7
test_concat FAIL (0.00s)
Expected: 3
Actual: 1
test.rb:66:in `test_concat'
Finished in 0.00171s
4 tests, 5 assertions, 2 failures, 0 errors, 0 skips