Project

General

Profile

Feature #15588 ยป patch.diff

Glass_saga (Masaki Matsushita), 02/06/2019 01:35 AM

View differences:

string.c
8318 8318
    return rb_str_enumerate_chars(str, 0);
8319 8319
}
8320 8320

  
8321
static long
8322
each_chunk_size(VALUE str, VALUE rb_len)
8323
{
8324
    long len, str_len, size;
8325

  
8326
    len = NUM2LONG(rb_len);
8327

  
8328
    if (len <= 0) {
8329
        return 0;
8330
    }
8331

  
8332
    str_len = rb_str_strlen(str);
8333

  
8334
    size = (str_len + (len - 1)) / len; /* ceil */
8335

  
8336
    return size;
8337
}
8338

  
8339
static VALUE
8340
rb_str_each_chunk_size(VALUE str, VALUE args, VALUE eobj)
8341
{
8342
    VALUE rb_len = RARRAY_AREF(args, 0);
8343
    long size = each_chunk_size(str, rb_len);
8344

  
8345
    if (size > 0) {
8346
        return LONG2NUM(size);
8347
    } else {
8348
        return Qnil;
8349
    }
8350
}
8351

  
8352
static VALUE rb_str_strip(VALUE str);
8353

  
8354
static VALUE
8355
rb_str_enumerate_chunk(int argc, VALUE *argv, VALUE str, VALUE ary)
8356
{
8357
    VALUE rb_len, opts, substr, strip = Qfalse, orig = str;
8358
    long i, len, str_len;
8359

  
8360
    rb_scan_args(argc, argv, "1:", &rb_len, &opts);
8361

  
8362
    len = NUM2LONG(rb_len);
8363

  
8364
    if (len <= 0) {
8365
        rb_raise(rb_eArgError, "length of chunk should be a positive number");
8366
    }
8367

  
8368
    if (!NIL_P(opts)) {
8369
	static ID keywords[1];
8370
	if (!keywords[0]) {
8371
	    keywords[0] = rb_intern_const("strip");
8372
	}
8373
	rb_get_kwargs(opts, keywords, 0, 1, &strip);
8374
	strip = (strip!= Qundef && RTEST(strip));
8375
    }
8376

  
8377
    str = rb_str_new_frozen(str);
8378
    str_len = rb_str_strlen(str);
8379

  
8380
    for (i = 0; i*len < str_len; i++) {
8381
        substr = rb_str_substr(str, i*len, len);
8382
        if (strip) {
8383
            substr = rb_str_strip(substr);
8384
        }
8385
        ENUM_ELEM(ary, substr);
8386
    }
8387

  
8388
    RB_GC_GUARD(str);
8389

  
8390
    if (ary)
8391
	return ary;
8392
    else
8393
	return orig;
8394
}
8395

  
8396
/*
8397
 *  call-seq:
8398
 *     str.each_chunk(length, strip: false) {|chunk| block }  -> str
8399
 *     str.each_chunk(length, strip: false)                   -> an_enumerator
8400
 *
8401
 *  Passes each chunk size of length in <i>str</i> to the given block,
8402
 *  or returns an enumerator if no block is given.
8403
 *
8404
 *     "hello hello\nhello".each_chunk(6) {|c| p c }
8405
 *     "hello hello\nhello".each_chunk(6, strip: true) {|c| p c }
8406
 *
8407
 *  <em>produces:</em>
8408
 *
8409
 *     "hello "
8410
 *     "hello\n"
8411
 *     "hello"
8412
 *
8413
 *     "hello"
8414
 *     "hello"
8415
 *     "hello"
8416
 */
8417

  
8418
static VALUE
8419
rb_str_each_chunk(int argc, VALUE *argv, VALUE str)
8420
{
8421
    RETURN_SIZED_ENUMERATOR(str, argc, argv, rb_str_each_chunk_size);
8422
    return rb_str_enumerate_chunk(argc, argv, str, 0);
8423
}
8424

  
8425
/*
8426
 *  call-seq:
8427
 *     str.chunks(length, strip: false)  -> an_array
8428
 *
8429
 *  Returns an array of chunks size of length in <i>str</i>. This is a
8430
 *  shorthand for <code>str.each_chunk(length, strip: bool).to_a</code>.
8431
 *
8432
 *     "hello hello\nhello".chunks(6) #=> ["hello ", "hello\n", "hello"]
8433
 *     "hello hello\nhello".chunks(6, strip: true) #=> ["hello", "hello", "hello"]
8434
 *
8435
 */
8436
static VALUE
8437
rb_str_chunks(int argc, VALUE *argv, VALUE str)
8438
{
8439
    VALUE rb_len, opts, ary;
8440
    rb_scan_args(argc, argv, "1:", &rb_len, &opts);
8441
    ary = WANTARRAY("chunks", each_chunk_size(str, rb_len));
8442
    return rb_str_enumerate_chunk(argc, argv, str, ary);
8443
}
8444

  
8321 8445
/*
8322 8446
 *  call-seq:
8323 8447
 *     str.chars    -> an_array
......
11034 11158
    rb_define_method(rb_cString, "chars", rb_str_chars, 0);
11035 11159
    rb_define_method(rb_cString, "codepoints", rb_str_codepoints, 0);
11036 11160
    rb_define_method(rb_cString, "grapheme_clusters", rb_str_grapheme_clusters, 0);
11161
    rb_define_method(rb_cString, "chunks", rb_str_chunks, -1);
11037 11162
    rb_define_method(rb_cString, "reverse", rb_str_reverse, 0);
11038 11163
    rb_define_method(rb_cString, "reverse!", rb_str_reverse_bang, 0);
11039 11164
    rb_define_method(rb_cString, "concat", rb_str_concat_multi, -1);
......
11090 11215
    rb_define_method(rb_cString, "each_char", rb_str_each_char, 0);
11091 11216
    rb_define_method(rb_cString, "each_codepoint", rb_str_each_codepoint, 0);
11092 11217
    rb_define_method(rb_cString, "each_grapheme_cluster", rb_str_each_grapheme_cluster, 0);
11218
    rb_define_method(rb_cString, "each_chunk", rb_str_each_chunk, -1);
11093 11219

  
11094 11220
    rb_define_method(rb_cString, "sum", rb_str_sum, -1);
11095 11221

  
test/ruby/test_string.rb
1146 1146
    end
1147 1147
  end
1148 1148

  
1149
  def test_each_chunk
1150
    s = S("hello world\nhello")
1151

  
1152
    res = []
1153
    s.each_chunk(6) {|x| res << x }
1154
    assert_equal([S("hello "), S("world\n"), S("hello")], res)
1155

  
1156
    res = []
1157
    s.each_chunk(6, strip: true) {|x| res << x }
1158
    assert_equal([S("hello"), S("world"), S("hello")], res)
1159

  
1160
    assert_equal s.each_chunk(s.size).to_a, [s]
1161
    assert_equal s.each_chunk(65536).to_a, [s]
1162

  
1163
    assert_equal s.each_chunk(6).size, 3
1164
    assert_equal s.each_chunk(0).size, nil
1165
    assert_equal s.each_chunk(-1).size, nil
1166
    assert_equal s.each_chunk(s.size).size, 1
1167
    assert_equal s.each_chunk(65536).size, 1
1168

  
1169
    assert_raise(ArgumentError) { s.each_chunk(0).each {} }
1170
    assert_raise(ArgumentError) { s.each_chunk(-1).each {} }
1171

  
1172
    s = S("\u{3053 3093 306b 3061 306f 0020 3053 3093 306b 3061 306f 000a 3053 3093 306b 3061 306f}")
1173

  
1174
    res = []
1175
    s.each_chunk(6) {|x| res << x }
1176
    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)
1177

  
1178
    res = []
1179
    s.each_chunk(6, strip: true) {|x| res << x }
1180
    assert_equal([S("\u{3053 3093 306b 3061 306f}"), S("\u{3053 3093 306b 3061 306f}"), S("\u{3053 3093 306b 3061 306f}")], res)
1181

  
1182
    assert_equal s.each_chunk(6).size, 3
1183
    assert_equal s.each_chunk(s.size).size, 1
1184
  end
1185

  
1186
  def test_chunks
1187
    s = S("hello world\nhello")
1188
    assert_equal ["hello ", "world\n", "hello"], s.chunks(6)
1189
    assert_equal ["hello", "world", "hello"], s.chunks(6, strip: true)
1190
    assert_equal s.chunks(1), s.chars
1191
    assert_equal s.chunks(65536), [s]
1192

  
1193
    s = S("\u{3053 3093 306b 3061 306f 0020 3053 3093 306b 3061 306f 000a 3053 3093 306b 3061 306f}")
1194
    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)
1195
    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)
1196
    assert_equal s.chunks(1), s.chars
1197

  
1198
    s = S("hello world\nhello")
1199
    assert_raise(ArgumentError) { s.chunks(0) }
1200
    assert_raise(ArgumentError) { s.chunks(-1) }
1201

  
1202
    s = S("")
1203
    assert_equal s.chunks(1), []
1204
  end
1205

  
1149 1206
  def test_empty?
1150 1207
    assert_empty(S(""))
1151 1208
    assert_not_empty(S("not"))