< :the previous in number
^ :the list in numerical order
> :the next in number
P :the previous (in thread)
N :the next (in thread)
|<:the top of this thread
>|:the next thread
^ :the parent (reply-to)
_:the child (an article replying to this)
>:the elder article having the same parent
<:the youger article having the same parent
---:split window and show thread lists
| :split window (vertically) and show thread lists
~ :close the thread frame
.:the index
..:the index of indices
Scripsit ille ?Brian Candler? <B.Candler / pobox.com>:
> On Fri, Aug 08, 2003 at 12:00:15AM +0900, KONTRA Gergely wrote:
> > > > How can I alter items in a hash nicely?
> > >
> > > h[key] = value # replace it
> > > h[key] << value # append to existing array
> >
> > Oops. Sorry. The question was dumb. I mean: I want to iterate over a
> > hash and change some elements. (in perl you get the elements, not copys
> > of the elements.
>
> In Ruby you get the elements, not copies of the elements.
>
> If you want to replace elements with completely new objects, you could do
>
> h.each_key do |k|
> h[k] = new_element
> end
>
> But otherwise you call whatever mutator method you like on the object which
> is in the hash:
>
> h.each do |e|
> e.change_my_state
> end
he means, that in Perl you can do:
use Data::Dumper;
@l = qw(one two three);
for my $elem(@l)
{
$elem = 'X' . uc $elem;
}
print Dumper \@l;
which yields
$VAR1 = [
'XONE',
'XTWO',
'XTHREE'
];
while something which looks like its equivalent in Ruby:
l = %w{one two three}
l.each() do |elem|
elem = 'X' + elem.upcase()
end
p l
does not work like a Perl programmer expects:
["one", "two", "three"]
Of course, elem.upcase!() would solve the problem... but in this case,
eventually the equivalent of Perl's map operator, Array#collect and
Array#collect!, are more appropiate:
l = %w{one two three}
l.collect!() do |elem|
'X' + elem.upcase()
end
p l
which works. BTW, one can use "next" instead of return to yield a
return value:
l = %w{one two three}
l.collect!() do |elem|
next elem if elem.match(/wo/)
next 'four' if elem == 'three'
'X' + elem.upcase()
end
p l
But, as stated in the other posting, that's a 1.8 feature. Contrary to
next, break works the usual way.
def tester(&block)
5.times() do |x|
p :before => x
y = yield x
p :after => y
end
p :end
42
end
p (tester do |x|
next 'CAUGHT' if x == 1
break 'BROKEN' if x == 3
x
end)
So the next doesn't exit a loop iteration (the second :after wouldn't
have been printed then) but returns a value from a block. Looks like
an intended feature. The break, however, exits the block-using method
'tester'. Somehow looks suspicious to me. But it's a yield feature
and can be circumvented by calling he block directly; the break can
be "caught":
3.times() do |t|
p t
begin
break 17
ensure next
end
end
prints 0, 1 and 2. The break value however is lost. I think it would be
a good idiom if one puts "ensure next" in the same line... since this
construct is to ensure that there'll be every loop iteration and breaks
will be ignored (transformed into nexts, that is). But, somehow I don't
like it:
3.times() do |t|
p t
begin
raise "StupidError"
ensure next
end
end
Even the exception is silently ignored.
3.times() do |t|
p t
begin
throw :ball
ensure next
end
end
"works" the same way. Somehow "ensure" seems to be too strong for me...
can one check WHY one is in an ensure block, that is, because of a return,
a break, a next, an exception or in the normal program flow?
As this program shows, there seems to be only one way to get out; to make
it less obvious, I used random order of breaking-out attempts:
def unbreakable(&block)
loop do
begin
yield
ensure next
end
end
end
def thefooledone()
cont = callcc() do |c| c end
if cont
catch :ball do
unbreakable do
i = rand(6)
p :this_time => i
case i
when 0 then return 42
when 1 then break
when 2 then cont.call()
when 3 then next
when 4 then raise "ID10T"
when 5 then throw :ball
end
end
end
end
end
thefooledone()