Feature #15588 ยป patch.diff
| string.c | ||
|---|---|---|
|     return rb_str_enumerate_chars(str, 0); | ||
| } | ||
| static long | ||
| each_chunk_size(VALUE str, VALUE rb_len) | ||
| { | ||
|     long len, str_len, size; | ||
|     len = NUM2LONG(rb_len); | ||
|     if (len <= 0) { | ||
|         return 0; | ||
|     } | ||
|     str_len = rb_str_strlen(str); | ||
|     size = (str_len + (len - 1)) / len; /* ceil */ | ||
|     return size; | ||
| } | ||
| static VALUE | ||
| rb_str_each_chunk_size(VALUE str, VALUE args, VALUE eobj) | ||
| { | ||
|     VALUE rb_len = RARRAY_AREF(args, 0); | ||
|     long size = each_chunk_size(str, rb_len); | ||
|     if (size > 0) { | ||
|         return LONG2NUM(size); | ||
|     } else { | ||
|         return Qnil; | ||
|     } | ||
| } | ||
| static VALUE rb_str_strip(VALUE str); | ||
| static VALUE | ||
| rb_str_enumerate_chunk(int argc, VALUE *argv, VALUE str, VALUE ary) | ||
| { | ||
|     VALUE rb_len, opts, substr, strip = Qfalse, orig = str; | ||
|     long i, len, str_len; | ||
|     rb_scan_args(argc, argv, "1:", &rb_len, &opts); | ||
|     len = NUM2LONG(rb_len); | ||
|     if (len <= 0) { | ||
|         rb_raise(rb_eArgError, "length of chunk should be a positive number"); | ||
|     } | ||
|     if (!NIL_P(opts)) { | ||
| 	static ID keywords[1]; | ||
| 	if (!keywords[0]) { | ||
| 	    keywords[0] = rb_intern_const("strip"); | ||
| 	} | ||
| 	rb_get_kwargs(opts, keywords, 0, 1, &strip); | ||
| 	strip = (strip!= Qundef && RTEST(strip)); | ||
|     } | ||
|     str = rb_str_new_frozen(str); | ||
|     str_len = rb_str_strlen(str); | ||
|     for (i = 0; i*len < str_len; i++) { | ||
|         substr = rb_str_substr(str, i*len, len); | ||
|         if (strip) { | ||
|             substr = rb_str_strip(substr); | ||
|         } | ||
|         ENUM_ELEM(ary, substr); | ||
|     } | ||
|     RB_GC_GUARD(str); | ||
|     if (ary) | ||
| 	return ary; | ||
|     else | ||
| 	return orig; | ||
| } | ||
| /* | ||
|  *  call-seq: | ||
|  *     str.each_chunk(length, strip: false) {|chunk| block }  -> str | ||
|  *     str.each_chunk(length, strip: false)                   -> an_enumerator | ||
|  * | ||
|  *  Passes each chunk size of length in <i>str</i> to the given block, | ||
|  *  or returns an enumerator if no block is given. | ||
|  * | ||
|  *     "hello hello\nhello".each_chunk(6) {|c| p c } | ||
|  *     "hello hello\nhello".each_chunk(6, strip: true) {|c| p c } | ||
|  * | ||
|  *  <em>produces:</em> | ||
|  * | ||
|  *     "hello " | ||
|  *     "hello\n" | ||
|  *     "hello" | ||
|  * | ||
|  *     "hello" | ||
|  *     "hello" | ||
|  *     "hello" | ||
|  */ | ||
| static VALUE | ||
| rb_str_each_chunk(int argc, VALUE *argv, VALUE str) | ||
| { | ||
|     RETURN_SIZED_ENUMERATOR(str, argc, argv, rb_str_each_chunk_size); | ||
|     return rb_str_enumerate_chunk(argc, argv, str, 0); | ||
| } | ||
| /* | ||
|  *  call-seq: | ||
|  *     str.chunks(length, strip: false)  -> an_array | ||
|  * | ||
|  *  Returns an array of chunks size of length in <i>str</i>. This is a | ||
|  *  shorthand for <code>str.each_chunk(length, strip: bool).to_a</code>. | ||
|  * | ||
|  *     "hello hello\nhello".chunks(6) #=> ["hello ", "hello\n", "hello"] | ||
|  *     "hello hello\nhello".chunks(6, strip: true) #=> ["hello", "hello", "hello"] | ||
|  * | ||
|  */ | ||
| static VALUE | ||
| rb_str_chunks(int argc, VALUE *argv, VALUE str) | ||
| { | ||
|     VALUE rb_len, opts, ary; | ||
|     rb_scan_args(argc, argv, "1:", &rb_len, &opts); | ||
|     ary = WANTARRAY("chunks", each_chunk_size(str, rb_len)); | ||
|     return rb_str_enumerate_chunk(argc, argv, str, ary); | ||
| } | ||
| /* | ||
|  *  call-seq: | ||
|  *     str.chars    -> an_array | ||
| ... | ... | |
|     rb_define_method(rb_cString, "chars", rb_str_chars, 0); | ||
|     rb_define_method(rb_cString, "codepoints", rb_str_codepoints, 0); | ||
|     rb_define_method(rb_cString, "grapheme_clusters", rb_str_grapheme_clusters, 0); | ||
|     rb_define_method(rb_cString, "chunks", rb_str_chunks, -1); | ||
|     rb_define_method(rb_cString, "reverse", rb_str_reverse, 0); | ||
|     rb_define_method(rb_cString, "reverse!", rb_str_reverse_bang, 0); | ||
|     rb_define_method(rb_cString, "concat", rb_str_concat_multi, -1); | ||
| ... | ... | |
|     rb_define_method(rb_cString, "each_char", rb_str_each_char, 0); | ||
|     rb_define_method(rb_cString, "each_codepoint", rb_str_each_codepoint, 0); | ||
|     rb_define_method(rb_cString, "each_grapheme_cluster", rb_str_each_grapheme_cluster, 0); | ||
|     rb_define_method(rb_cString, "each_chunk", rb_str_each_chunk, -1); | ||
|     rb_define_method(rb_cString, "sum", rb_str_sum, -1); | ||
| test/ruby/test_string.rb | ||
|---|---|---|
|     end | ||
|   end | ||
|   def test_each_chunk | ||
|     s = S("hello world\nhello") | ||
|     res = [] | ||
|     s.each_chunk(6) {|x| res << x } | ||
|     assert_equal([S("hello "), S("world\n"), S("hello")], res) | ||
|     res = [] | ||
|     s.each_chunk(6, strip: true) {|x| res << x } | ||
|     assert_equal([S("hello"), S("world"), S("hello")], res) | ||
|     assert_equal s.each_chunk(s.size).to_a, [s] | ||
|     assert_equal s.each_chunk(65536).to_a, [s] | ||
|     assert_equal s.each_chunk(6).size, 3 | ||
|     assert_equal s.each_chunk(0).size, nil | ||
|     assert_equal s.each_chunk(-1).size, nil | ||
|     assert_equal s.each_chunk(s.size).size, 1 | ||
|     assert_equal s.each_chunk(65536).size, 1 | ||
|     assert_raise(ArgumentError) { s.each_chunk(0).each {} } | ||
|     assert_raise(ArgumentError) { s.each_chunk(-1).each {} } | ||
|     s = S("\u{3053 3093 306b 3061 306f 0020 3053 3093 306b 3061 306f 000a 3053 3093 306b 3061 306f}") | ||
|     res = [] | ||
|     s.each_chunk(6) {|x| res << x } | ||
|     assert_equal([S("\u{3053 3093 306b 3061 306f 0020}"), S("\u{3053 3093 306b 3061 306f 000a}"), S("\u{3053 3093 306b 3061 306f}")], res) | ||
|     res = [] | ||
|     s.each_chunk(6, strip: true) {|x| res << x } | ||
|     assert_equal([S("\u{3053 3093 306b 3061 306f}"), S("\u{3053 3093 306b 3061 306f}"), S("\u{3053 3093 306b 3061 306f}")], res) | ||
|     assert_equal s.each_chunk(6).size, 3 | ||
|     assert_equal s.each_chunk(s.size).size, 1 | ||
|   end | ||
|   def test_chunks | ||
|     s = S("hello world\nhello") | ||
|     assert_equal ["hello ", "world\n", "hello"], s.chunks(6) | ||
|     assert_equal ["hello", "world", "hello"], s.chunks(6, strip: true) | ||
|     assert_equal s.chunks(1), s.chars | ||
|     assert_equal s.chunks(65536), [s] | ||
|     s = S("\u{3053 3093 306b 3061 306f 0020 3053 3093 306b 3061 306f 000a 3053 3093 306b 3061 306f}") | ||
|     assert_equal [S("\u{3053 3093 306b 3061 306f 0020}"), S("\u{3053 3093 306b 3061 306f 000a}"), S("\u{3053 3093 306b 3061 306f}")], s.chunks(6) | ||
|     assert_equal [S("\u{3053 3093 306b 3061 306f}"), S("\u{3053 3093 306b 3061 306f}"), S("\u{3053 3093 306b 3061 306f}")], s.chunks(6, strip: true) | ||
|     assert_equal s.chunks(1), s.chars | ||
|     s = S("hello world\nhello") | ||
|     assert_raise(ArgumentError) { s.chunks(0) } | ||
|     assert_raise(ArgumentError) { s.chunks(-1) } | ||
|     s = S("") | ||
|     assert_equal s.chunks(1), [] | ||
|   end | ||
|   def test_empty? | ||
|     assert_empty(S("")) | ||
|     assert_not_empty(S("not")) | ||