From 3f52ef6cfce7ddcf82adc8105052dbece29060b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Hasi=C5=84ski?= Date: Sat, 28 Mar 2026 22:59:11 +0100 Subject: [PATCH] Fix Lazy#flat_map to handle non-enumerable block return values When the block passed to Lazy#flat_map returns a non-enumerable value (e.g. an Integer), mruby raised NoMethodError because it unconditionally called #each on the result. CRuby yields non-enumerable values directly. Use respond_to?(:each) to match CRuby behavior: iterate enumerable results, yield non-enumerable results as-is. --- mrbgems/mruby-enum-lazy/mrblib/lazy.rb | 11 ++++++----- mrbgems/mruby-enum-lazy/test/lazy.rb | 12 ++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-enum-lazy/mrblib/lazy.rb b/mrbgems/mruby-enum-lazy/mrblib/lazy.rb index 7506d7fc8..140faf65b 100644 --- a/mrbgems/mruby-enum-lazy/mrblib/lazy.rb +++ b/mrbgems/mruby-enum-lazy/mrblib/lazy.rb @@ -291,11 +291,12 @@ class Enumerator # def flat_map(&block) Lazy.new(self){|yielder, val| - ary = block.call(val) - # TODO: check ary is an Array - ary.each {|x| - yielder << x - } + result = block.call(val) + if result.respond_to?(:each) + result.each {|x| yielder << x } + else + yielder << result + end } end alias collect_concat flat_map diff --git a/mrbgems/mruby-enum-lazy/test/lazy.rb b/mrbgems/mruby-enum-lazy/test/lazy.rb index 5266f6f69..145c73caf 100644 --- a/mrbgems/mruby-enum-lazy/test/lazy.rb +++ b/mrbgems/mruby-enum-lazy/test/lazy.rb @@ -46,6 +46,18 @@ assert("Enumerator::Lazy#to_enum") do assert_equal [0*1, 2*3, 4*5, 6*7], lazy_enum.map { |a| a.first * a.last }.first(4) end +assert("Enumerator::Lazy#flat_map with arrays") do + assert_equal [1, 10, 2, 20, 3, 30], [1, 2, 3].lazy.flat_map {|x| [x, x*10]}.force +end + +assert("Enumerator::Lazy#flat_map with non-enumerable") do + assert_equal [1, 2, 3], [1, 2, 3].lazy.flat_map {|x| x}.force +end + +assert("Enumerator::Lazy#flat_map with enumerable") do + assert_equal [[1, 2], [3, 4]], [1, 3].lazy.flat_map {|x| [[x, x+1]]}.force +end + assert("Enumerator::Lazy#grep_v") do lazy_grep_v = (0..).lazy.grep_v(2..4) assert_kind_of Enumerator::Lazy, lazy_grep_v