From 126d55480d9668a6a313a8e8c428cccfb88d459e Mon Sep 17 00:00:00 2001 From: ksss Date: Fri, 11 Nov 2016 15:49:17 +0900 Subject: Reimplement Enumerable#cycle Fix pattern of infinite loop And support all specs in https://github.com/ruby/spec/blob/27960d06e0ce92c37f074450f0eab4b0519b118c/core/enumerable/cycle_spec.rb without Enumerable#size --- mrbgems/mruby-enum-ext/mrblib/enum.rb | 49 +++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 23 deletions(-) (limited to 'mrbgems/mruby-enum-ext') diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index a5f661ce6..6724dff37 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -573,35 +573,38 @@ module Enumerable # a.cycle(2) { |x| puts x } # print, a, b, c, a, b, c. # - def cycle(n=nil, &block) - return to_enum(:cycle, n) if !block && n.nil? + def cycle(nv = nil, &block) + return to_enum(:cycle, nv) unless block - ary = [] - if n.nil? - self.each do|*val| - ary.push val - block.call(*val) + n = nil + + if nv.nil? + n = -1 + else + unless nv.respond_to?(:to_int) + raise TypeError, "no implicit conversion of #{nv.class} into Integer" end - loop do - ary.each do|e| - block.call(*e) - end + n = nv.to_int + unless n.kind_of?(Integer) + raise TypeError, "no implicit conversion of #{nv.class} into Integer" end - else - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + return nil if n <= 0 + end - n = n.to_int - self.each do|*val| - ary.push val - end - count = 0 - while count < n - ary.each do|e| - block.call(*e) - end - count += 1 + ary = [] + each do |*i| + ary.push(i) + yield(*i) + end + return nil if ary.empty? + + while n < 0 || 0 < (n -= 1) + ary.each do |i| + yield(*i) end end + + nil end ## -- cgit v1.2.3 From 7685783af4872b99265e2ea9c41ac00baf191c30 Mon Sep 17 00:00:00 2001 From: ksss Date: Fri, 11 Nov 2016 15:54:42 +0900 Subject: Add regression test for Enumerable#cycle --- mrbgems/mruby-enum-ext/test/enum.rb | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'mrbgems/mruby-enum-ext') diff --git a/mrbgems/mruby-enum-ext/test/enum.rb b/mrbgems/mruby-enum-ext/test/enum.rb index 08b553fe5..076562f45 100644 --- a/mrbgems/mruby-enum-ext/test/enum.rb +++ b/mrbgems/mruby-enum-ext/test/enum.rb @@ -128,6 +128,13 @@ assert("Enumerable#cycle") do ["a", "b", "c"].cycle(2) { |v| a << v } assert_equal ["a", "b", "c", "a", "b", "c"], a assert_raise(TypeError) { ["a", "b", "c"].cycle("a") { |v| a << v } } + + empty = Class.new do + include Enumerable + def each + end + end + assert_nil empty.new.cycle { break :nope } end assert("Enumerable#find_index") do -- cgit v1.2.3 From 9e2faec8e4f5cb24ffc8a7f10284c05598b91acd Mon Sep 17 00:00:00 2001 From: ksss Date: Thu, 24 Nov 2016 10:34:14 +0900 Subject: Support object does'n have `<` method --- mrbgems/mruby-enum-ext/mrblib/enum.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'mrbgems/mruby-enum-ext') diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index 6724dff37..bd64cc6bd 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -58,9 +58,8 @@ module Enumerable def take(n) raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) - raise ArgumentError, "attempt to take negative size" if n < 0 - - n = n.to_int + i = n.to_int + raise ArgumentError, "attempt to take negative size" if i < 0 ary = [] self.each do |*val| break if ary.size >= n -- cgit v1.2.3 From 5134734541dd993f74a40b1621009add2cf110bf Mon Sep 17 00:00:00 2001 From: ksss Date: Thu, 24 Nov 2016 10:35:15 +0900 Subject: Shouldn't call `each` method if size is 0 --- mrbgems/mruby-enum-ext/mrblib/enum.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'mrbgems/mruby-enum-ext') diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index bd64cc6bd..5b50aba00 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -61,9 +61,11 @@ module Enumerable i = n.to_int raise ArgumentError, "attempt to take negative size" if i < 0 ary = [] + return ary if i == 0 self.each do |*val| - break if ary.size >= n ary << val.__svalue + i -= 1 + break if i == 0 end ary end -- cgit v1.2.3 From c28a963bf426afb00f2ebb32c0dff65dd3ff4b3f Mon Sep 17 00:00:00 2001 From: ksss Date: Fri, 25 Nov 2016 22:20:33 +0900 Subject: Like a Enumerable#take --- mrbgems/mruby-enum-ext/mrblib/enum.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'mrbgems/mruby-enum-ext') diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index 5b50aba00..54db189f4 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -222,14 +222,17 @@ module Enumerable end return nil else - a = [] - i = 0 + raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + i = n.to_int + raise ArgumentError, "attempt to take negative size" if i < 0 + ary = [] + return ary if i == 0 self.each do |*val| - break if n<=i - a.push val.__svalue - i += 1 + ary << val.__svalue + i -= 1 + break if i == 0 end - a + ary end end -- cgit v1.2.3 From 1bf565ea0447f69d8ffcca756b82fa789f6afca0 Mon Sep 17 00:00:00 2001 From: ksss Date: Fri, 25 Nov 2016 22:25:48 +0900 Subject: Argument more strictly --- mrbgems/mruby-enum-ext/mrblib/enum.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'mrbgems/mruby-enum-ext') diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index 54db189f4..113b470a9 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -215,13 +215,15 @@ module Enumerable # Returns the first element, or the first +n+ elements, of the enumerable. # If the enumerable is empty, the first form returns nil, and the # second form returns an empty array. - def first(n=NONE) - if n == NONE + def first(*args) + case args.length + when 0 self.each do |*val| return val.__svalue end return nil - else + when 1 + n = args[0] raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) i = n.to_int raise ArgumentError, "attempt to take negative size" if i < 0 @@ -233,6 +235,8 @@ module Enumerable break if i == 0 end ary + else + raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 0..1)" end end -- cgit v1.2.3