I’m sorry that this message will be long and somewhat rambling,
but I wanted to try to write up my thoughts on this, even though
my thoughts are not very clear…
There’s a situation that I occassionally run into, which I can work
around easy enough, but it seems that there might be an cleaner
solution than the ones I fall back on. Let’s say I want to have
something like:
ARGV.each { |arg|
case arg
when “-f”
…do something with the next value of |arg|…
end
}
What I do is set some variable to remember that I’m in the middle
of “-f” processing, and then catch that when the code-block is
executed for the next value. For example:
in_option = nil
ARGV.each { |arg|
if in_option
case in_option
when “-f”
…do the -f processing of this ‘arg’ value…
end
in_option = nil
next
end
case arg
when “-f”
in_option = arg
end
}
if in_opt
…some error message about the missing value for an option…
end
This can be made to work well, but it’s a mess in many ways. Please
note that I’m not asking for everyone’s favorite package for processing
ARGV, since this same situation comes up (for me at least) in many
other contexts. I am only using ARGV as an convenient example
because everyone will understand what I’m talking about. Also note
that the same situation can come up with ‘each_value’, ‘each_key’,
‘each_pair’, or other kinds of ‘each’-ish methods.
What I’d like is some way for the ‘-f’ case to say “give me the next
values for ‘each’” (perhaps multiple times in a row). If there is no
next-value, then it would get a ‘nil’ value.
And to complicate things a bit more, sometimes the option might want
to check the next option, but not necessarily use it up. For
instance,
if the “-f” option can take one-or-more names, then it would keep taking
the next value for ‘arg’ until it sees arg =~ /^-/
It seems to me that this situation can come up in enough contexts that
the ruby language could provide a way to do it. I have no good idea of
what wording would make sense for this. But the idea would be
something like:
ARGV.each { |arg|
case arg
when “-f”
opt_value = next_yield(0)
if opt_value and opt_value =~ /^-/
skip_next_yield
…do something with that opt_value…
else
$stderr.printf “Error: Missing value for ‘-f’\n”
opterr = true
end
end
}
So, what I’m suggesting is two new keywords for ruby. The first would
know what the value(s) would be for the next call to this code-block,
but
it would not change anything. The ‘skip_next_yeild’ would delete that
next value (or set-of-values for methods like each_pair). I added the
parameter to next_yield so that it could also handle the values of
methods like each_pair, eg:
somehash.each_pair { |key, strval|
…whatever…
next_key = next_yield(0)
next_strval = next_yield(1)
}
I guess next_yield is really an array more than a keyword which takes
a parameter, but I thought it (next_yield) would be more flexible if it
could support other options with additional parameters.
It might be that ‘skip_next_yield’ would also take a parameter, which
would be the value the caller should use for the current execution of
the code-block, for those cases where the caller cares about the
return-value from the code-block. ‘each’ does not care, but a method
like ‘sort’ would care about the value.
I’m sure I’m overlooking some details on how this would have to work,
and I’m sure that ‘next_yield’ and ‘skip_next_yield’ are dumb names for
those two new keywords. But I think that some feature like the above
could be useful.
Or is there already some good way to handle this in ruby?