Feature #8246 ยป 275.patch
| hash.c | ||
|---|---|---|
|
/*
|
||
|
* call-seq:
|
||
|
* hsh.traverse(*keys) => obj
|
||
|
* hsh.traverse(*keys) {| key | block } => obj
|
||
|
*
|
||
|
* Traverses the hash and returns a value for the given key. If the key can't be
|
||
|
* found, there are two options: With no other arguments, it will
|
||
|
* return nil;if the optional code block is
|
||
|
* specified, then that will be run and its result returned.
|
||
|
*
|
||
|
* h = { "a" => { "b" => { "c" => 100 } } }
|
||
|
* h.traverse("a", "b", "c") #=> 100
|
||
|
* h.traverse("a", "z") #=> nil
|
||
|
* h.traverse("a", "z") { |key| "#{key} not found"} #=> "z not found"
|
||
|
*/
|
||
|
static VALUE
|
||
|
rb_hash_traverse(int argc, VALUE *argv, VALUE hash)
|
||
|
{
|
||
|
VALUE required;
|
||
|
VALUE rval = hash;
|
||
|
int i;
|
||
|
rb_scan_args(argc, argv, "1*", &required, &argv);
|
||
|
rb_ary_unshift(argv, required);
|
||
|
for (i = 0; i < RARRAY_LEN(argv) ; i++) {
|
||
|
rval = rb_hash_aref(rval, RARRAY_PTR(argv)[i]);
|
||
|
if (!rb_obj_is_kind_of(rval, rb_cHash)){
|
||
|
if (i < RARRAY_LEN(argv) - 1){
|
||
|
rval = Qnil;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (rval == Qnil && rb_block_given_p()){
|
||
|
rval = rb_yield(RARRAY_PTR(argv)[i]);
|
||
|
}
|
||
|
return rval;
|
||
|
}
|
||
|
/*
|
||
|
* call-seq:
|
||
|
* hsh.default(key=nil) -> obj
|
||
|
*
|
||
|
* Returns the default value, the value that would be returned by
|
||
| ... | ... | |
|
rb_define_method(rb_cHash,"hash", rb_hash_hash, 0);
|
||
|
rb_define_method(rb_cHash,"eql?", rb_hash_eql, 1);
|
||
|
rb_define_method(rb_cHash,"fetch", rb_hash_fetch_m, -1);
|
||
|
rb_define_method(rb_cHash,"traverse", rb_hash_traverse, -1);
|
||
|
rb_define_method(rb_cHash,"[]=", rb_hash_aset, 2);
|
||
|
rb_define_method(rb_cHash,"store", rb_hash_aset, 2);
|
||
|
rb_define_method(rb_cHash,"default", rb_hash_default, -1);
|
||
| test/ruby/test_hash.rb | ||
|---|---|---|
|
end
|
||
|
end
|
||
|
def test_traverse
|
||
|
hash = { :l1 => { :l2 => { :l3 => 100 } } }
|
||
|
assert_raise(ArgumentError) { hash.traverse }
|
||
|
assert_nothing_raised { hash.traverse 'gumby' }
|
||
|
assert_equal(nil, hash.traverse('nonexistent'))
|
||
|
assert_equal({ :l2 => { :l3 => 100 } }, hash.traverse(:l1))
|
||
|
assert_equal('gumbygumby', hash.traverse('gumby') {|k| k * 2 })
|
||
|
assert_equal(100, hash.traverse(:l1, :l2, :l3))
|
||
|
assert_equal(nil, hash.traverse(:l1, :l2, :l3, :l4))
|
||
|
end
|
||
|
class TestSubHash < TestHash
|
||
|
class SubHash < Hash
|
||
|
end
|
||