Joel VanderWerf
2/10/2007 8:24:00 PM
Garance A Drosehn wrote:
> ARGV.each { |arg|
> case arg
> when "-f"
> ...do something with the *next* value of |arg|...
> end
> }
The following works with any Enumerable, doesn't use threads,
continuations, or generators, doesn't construct temp arrays (except to
hold the next value(s)) or do any shifting on the original argument, and
has fairly nice syntax (but you have to remember not to fall off the end
of your block with an integer value). It handles corner cases AFAICT.
Any suggestions for a better name than #each2?
module Enumerable
class InsufficientDataError < StandardError; end
def each2
req = first = rest = nil
each do |x|
if req
req -= 1
rest << x
next if req > 0
req = yield first, rest
first = nil
rest = nil
else
req = yield x, nil
end
if req
if req.kind_of?(Integer) and req > 0
first = x
rest = []
else
raise ArgumentError, "Bad request: next #{req.inspect}"
end
end
end
if req and req > 0
raise InsufficientDataError,
"Ran out of data fulfilling request: next #{req}"
end
end
end
(1..10).each2 do |x, rest|
next 2 if (x == 3 or x == 7) and not rest
puts "x = #{x}, rest = #{rest.inspect}"
nil ## make sure not to request more entries by returning an integer
end
%w{ -f foo -b bar --copy src dst }.each2 do |arg, values|
case arg
when "-f", "-b"
next 1 unless values
puts "#{arg} #{values[0]}"
when "--copy"
next 2 unless values
puts "#{arg} #{values.join(" ")}"
end
nil ## make sure not to request more entries by returning an integer
end
__END__
Output:
x = 1, rest = nil
x = 2, rest = nil
x = 3, rest = [4, 5]
x = 6, rest = nil
x = 7, rest = [8, 9]
x = 10, rest = nil
-f foo
-b bar
--copy src dst
--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407