lib/backports/2.0.0/enumerator/lazy.rb in backports-2.8.2 vs lib/backports/2.0.0/enumerator/lazy.rb in backports-3.0.0
- old
+ new
@@ -8,17 +8,20 @@
attr_accessor :backports_memo
end
class Lazy < Enumerator
@@done = :__backports_lazy_enumeration_done__ # used internally to bail out of an iteration
+ @@lazy_with_no_block = Struct.new(:object, :method, :args) # used internally to create lazy without block
- alias_method :non_lazy_cycle, :cycle # cycle must be handled in a tricky way
- @@cycler = Struct.new(:object, :n)
-
def initialize(obj)
- return super(obj.object, :non_lazy_cycle, obj.n) if obj.is_a?(@@cycler)
+ if obj.is_a?(@@lazy_with_no_block)
+ @inspect_info = obj
+ return super(@receiver = obj.object, @method = obj.method || :each, * @args = obj.args)
+ end
raise ArgumentError, "must supply a block" unless block_given?
+ @receiver = obj
+ @method = caller[1][/`([^']*)'/, 1]
super() do |yielder, *args|
catch @@done do
obj.each(*args) do |*x|
yield yielder, *x
end
@@ -30,10 +33,45 @@
def lazy
self
end
+ def to_enum(method = :each, *args)
+ Lazy.new(@@lazy_with_no_block.new(self, method, args))
+ end
+ alias_method :enum_for, :to_enum
+
+ def inspect
+ suff = ''
+ suff << ":#{@method}" unless @method == :each
+ suff << "(#{@args.inspect[1...-1]})" if @args && !@args.empty?
+ "#<#{self.class}: #{@receiver.inspect}#{suff}>"
+ end
+
+ {
+ :slice_before => //,
+ :with_index => [],
+ :cycle => [],
+ :each_with_object => 42,
+ :each_slice => 42,
+ :each_entry => [],
+ :each_cons => 42,
+ }.each do |method, args|
+ unless [].lazy.send(method, *args).is_a?(Lazy) # Nothing to do if already backported, since it would use to_enum...
+ module_eval <<-EOT, __FILE__, __LINE__ + 1
+ def #{method}(*args) # def cycle(*args)
+ return to_enum(:#{method}, *args) unless block_given? # return to_enum(:cycle, *args) unless block_given?
+ super # super
+ end # end
+ EOT
+ end
+ end
+
+ def chunk(*)
+ super.lazy
+ end unless [].lazy.chunk{}.is_a?(Lazy)
+
def map
raise ArgumentError, "tried to call lazy map without a block" unless block_given?
Lazy.new(self) do |yielder, *values|
yielder << yield(*values)
end
@@ -67,11 +105,11 @@
else
Lazy.new(self) do |yielder, *values|
values = values.first unless values.size > 1
yielder.yield(values) if pattern === values
end
- end
+ end.__set_inspect([pattern])
end
def drop(n)
n = Backports::coerce_to_int(n)
Lazy.new(self) do |yielder, *values|
@@ -79,11 +117,11 @@
if data[:remain] > 0
data[:remain] -= 1
else
yielder.yield(*values)
end
- end
+ end.__set_inspect([n])
end
def drop_while
raise ArgumentError, "tried to call lazy drop_while without a block" unless block_given?
Lazy.new(self) do |yielder, *values|
@@ -93,16 +131,15 @@
end
def take(n)
n = Backports::coerce_to_int(n)
raise ArgumentError, 'attempt to take negative size' if n < 0
- return Lazy.new([]){} if n == 0
- Lazy.new(self) do |yielder, *values|
+ Lazy.new(n == 0 ? [] : self) do |yielder, *values|
data = yielder.backports_memo ||= {:remain => n}
yielder.yield(*values)
throw @@done if (data[:remain] -= 1) == 0
- end
+ end.__set_inspect([n], self)
end
def take_while
raise ArgumentError, "tried to call lazy take_while without a block" unless block_given?
Lazy.new(self) do |yielder, *values|
@@ -123,15 +160,10 @@
end
end
end
alias_method :collect_concat, :flat_map
- def cycle(n = nil)
- return super if block_given?
- Lazy.new(@@cycler.new(self, n))
- end
-
def zip(*args)
return super if block_given?
arys = args.map{ |arg| Backports.is_array?(arg) }
if arys.all?
# Handle trivial case of multiple array arguments separately
@@ -141,10 +173,13 @@
values = values.first unless values.size > 1
yielder << arys.map{|ary| ary[data[:iter]]}.unshift(values)
data[:iter] += 1
end
else
+ args.each do |a|
+ raise TypeError, "wrong argument type #{a.class} (must respond to :each)" unless a.respond_to? :each
+ end
Lazy.new(self) do |yielder, *values|
enums = yielder.backports_memo ||= args.map(&:to_enum)
values = values.first unless values.size > 1
others = enums.map do |arg|
begin
@@ -153,9 +188,16 @@
nil
end
end
yielder << others.unshift(values)
end
- end
+ end.__set_inspect(args)
+ end
+
+ protected
+ def __set_inspect(args, receiver = nil)
+ @args = args
+ @receiver = receiver if receiver
+ self
end
end
end