diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2016-02-17 17:42:09 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <k@rhe.jp> | 2016-04-12 22:17:33 +0900 |
commit | 80b537f14c4af699b26e52931ae7e64a547e68c5 (patch) | |
tree | 17dd1e7babde4c90f27a14988a36bd96b6557c28 /range.c | |
parent | 456523e2ede3073767fd8cb73cc4b159c3608890 (diff) | |
download | ruby-feature/enumerable-first-with-block.tar.gz |
{Enumerable,Array,Range}#first, {Array,Range}#last with blockfeature/enumerable-first-with-block
* array.c (rb_ary_first, ary_last): extend Array#{first,last} to accept
a block. If a block is passed, these methods collects only elements
for which the block returns a truthy value.
* enum.c: extend Enumerable#first to accept a block.
* range.c: extend Range#{first,last} to accept a block.
* gc.c: avoid using rb_ary_last(), because it may call a block.
* test/ruby/test_array.rb: add test
* test/ruby/test_enum.rb: ditto
* test/ruby/test_range.rb: ditto
Diffstat (limited to 'range.c')
-rw-r--r-- | range.c | 49 |
1 files changed, 33 insertions, 16 deletions
@@ -851,14 +851,20 @@ first_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, cbarg)) /* * call-seq: - * rng.first -> obj - * rng.first(n) -> an_array + * rng.first -> obj + * rng.first { |obj| block } -> obj + * rng.first(n) -> an_array + * rng.first(n) { |obj| block } -> an_array * * Returns the first object in the range, or an array of the first +n+ * elements. + * If a block is given, only elements for which the given block returns a true + * value are counted. * - * (10..20).first #=> 10 - * (10..20).first(3) #=> [10, 11, 12] + * (10..20).first #=> 10 + * (10..20).first { |i| i.odd? } #=> 11 + * (10..20).first(3) #=> [10, 11, 12] + * (10..20).first(3) { |i| i.odd? } #=> [11, 13, 15] */ static VALUE @@ -866,6 +872,7 @@ range_first(int argc, VALUE *argv, VALUE range) { VALUE n, ary[2]; + if (rb_block_given_p()) return rb_call_super(argc, argv); if (argc == 0) return RANGE_BEG(range); rb_scan_args(argc, argv, "1", &n); @@ -879,26 +886,36 @@ range_first(int argc, VALUE *argv, VALUE range) /* * call-seq: - * rng.last -> obj - * rng.last(n) -> an_array + * rng.last -> obj + * rng.last { |obj| block } -> obj + * rng.last(n) -> an_array + * rng.last(n) { |obj| block } -> an_array * * Returns the last object in the range, * or an array of the last +n+ elements. - * - * Note that with no arguments +last+ will return the object that defines - * the end of the range even if #exclude_end? is +true+. - * - * (10..20).last #=> 20 - * (10...20).last #=> 20 - * (10..20).last(3) #=> [18, 19, 20] - * (10...20).last(3) #=> [17, 18, 19] + * If a block is given, only elements for which the given block returns a true + * value are counted. + * + * Note that with no arguments nor a block +last+ will return the object that + * defines the end of the range even if #exclude_end? is +true+. + * + * (10..20).last #=> 20 + * (10...20).last #=> 20 + * (10...20).last { true } #=> 19 + * (10..20).last(3) #=> [18, 19, 20] + * (10...20).last(3) #=> [17, 18, 19] + * (10...20).last(3) { |i| i.odd? } #=> [15, 17, 19] */ static VALUE range_last(int argc, VALUE *argv, VALUE range) { - if (argc == 0) return RANGE_END(range); - return rb_ary_last(argc, argv, rb_Array(range)); + if (argc > 0 || rb_block_given_p()) { + return rb_ary_last(argc, argv, rb_Array(range)); + } + else { + return RANGE_END(range); + } } |