diff options
Diffstat (limited to 'src/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy')
3 files changed, 223 insertions, 0 deletions
diff --git a/src/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/mrbgem.rake b/src/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/mrbgem.rake new file mode 100644 index 000000000..682134c41 --- /dev/null +++ b/src/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/mrbgem.rake @@ -0,0 +1,7 @@ +MRuby::Gem::Specification.new('mruby-enum-lazy') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Enumerator::Lazy class' + spec.add_dependency('mruby-enumerator', :core => 'mruby-enumerator') + spec.add_dependency('mruby-enum-ext', :core => 'mruby-enum-ext') +end diff --git a/src/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/mrblib/lazy.rb b/src/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/mrblib/lazy.rb new file mode 100644 index 000000000..c98681edf --- /dev/null +++ b/src/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/mrblib/lazy.rb @@ -0,0 +1,163 @@ +module Enumerable + + # = Enumerable#lazy implementation + # + # Enumerable#lazy returns an instance of Enumerator::Lazy. + # You can use it just like as normal Enumerable object, + # except these methods act as 'lazy': + # + # - map collect + # - select find_all + # - reject + # - grep + # - drop + # - drop_while + # - take_while + # - flat_map collect_concat + # - zip + def lazy + Enumerator::Lazy.new(self) + end +end + +class Enumerator + # == Acknowledgements + # + # Based on https://github.com/yhara/enumerable-lazy + # Inspired by https://github.com/antimon2/enumerable_lz + # http://jp.rubyist.net/magazine/?0034-Enumerable_lz (ja) + class Lazy < Enumerator + def initialize(obj, &block) + super(){|yielder| + begin + obj.each{|x| + if block + block.call(yielder, x) + else + yielder << x + end + } + rescue StopIteration + end + } + end + + def to_enum(meth=:each, *args, &block) + unless self.respond_to?(meth) + raise NoMethodError, "undefined method #{meth}" + end + lz = Lazy.new(self, &block) + lz.obj = self + lz.meth = meth + lz.args = args + lz + end + alias enum_for to_enum + + def map(&block) + Lazy.new(self){|yielder, val| + yielder << block.call(val) + } + end + alias collect map + + def select(&block) + Lazy.new(self){|yielder, val| + if block.call(val) + yielder << val + end + } + end + alias find_all select + + def reject(&block) + Lazy.new(self){|yielder, val| + unless block.call(val) + yielder << val + end + } + end + + def grep(pattern) + Lazy.new(self){|yielder, val| + if pattern === val + yielder << val + end + } + end + + def drop(n) + dropped = 0 + Lazy.new(self){|yielder, val| + if dropped < n + dropped += 1 + else + yielder << val + end + } + end + + def drop_while(&block) + dropping = true + Lazy.new(self){|yielder, val| + if dropping + if not block.call(val) + yielder << val + dropping = false + end + else + yielder << val + end + } + end + + def take(n) + if n == 0 + return Lazy.new(self){raise StopIteration} + end + taken = 0 + Lazy.new(self){|yielder, val| + yielder << val + taken += 1 + if taken >= n + raise StopIteration + end + } + end + + def take_while(&block) + Lazy.new(self){|yielder, val| + if block.call(val) + yielder << val + else + raise StopIteration + end + } + end + + def flat_map(&block) + Lazy.new(self){|yielder, val| + ary = block.call(val) + # TODO: check ary is an Array + ary.each{|x| + yielder << x + } + } + end + alias collect_concat flat_map + + def zip(*args, &block) + enums = [self] + args + Lazy.new(self){|yielder, val| + ary = enums.map{|e| e.next} + if block + yielder << block.call(ary) + else + yielder << ary + end + } + end + + alias force to_a + end +end diff --git a/src/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/test/lazy.rb b/src/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/test/lazy.rb new file mode 100644 index 000000000..940d070e8 --- /dev/null +++ b/src/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/test/lazy.rb @@ -0,0 +1,53 @@ +assert("Enumerator::Lazy") do + a = [1, 2] + assert_equal Enumerator::Lazy, a.lazy.class +end + +assert("Enumerator::Lazy laziness") do + a = Object.new + def a.each + return to_enum :each unless block_given? + self.b << 10 + yield 1 + self.b << 20 + yield 2 + self.b << 30 + yield 3 + self.b << 40 + yield 4 + self.b << 50 + yield 5 + end + def a.b(b=nil) + @b = b if b + @b + end + + a.b([]) + assert_equal [1,2], a.each.lazy.take(2).force + assert_equal [10,20], a.b + + a.b([]) + assert_equal [2,4], a.each.lazy.select{|x|x%2==0}.take(2).force + assert_equal [10,20,30,40], a.b + + a.b([]) + assert_equal [1], a.each.lazy.take_while{|x|x<2}.take(1).force + assert_equal [10], a.b + + a.b([]) + assert_equal [1], a.each.lazy.take_while{|x|x<2}.take(4).force + assert_equal [10,20], a.b +end + +assert("Enumrator::Lazy#to_enum") do + lazy_enum = (0..Float::INFINITY).lazy.to_enum(:each_slice, 2) + assert_kind_of Enumerator::Lazy, lazy_enum + assert_equal [0*1, 2*3, 4*5, 6*7], lazy_enum.map { |a| a.first * a.last }.first(4) +end + +assert("Enumerator::Lazy#zip with cycle") do + e1 = [1, 2, 3].cycle + e2 = [:a, :b].cycle + assert_equal [[1,:a],[2,:b],[3,:a]], e1.lazy.zip(e2).first(3) +end |