Skip to content

Commit 8a2803f

Browse files
committed
Add Enumerable#join
1 parent 830ab2c commit 8a2803f

5 files changed

Lines changed: 118 additions & 29 deletions

File tree

array.c

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2791,7 +2791,7 @@ rb_ary_resurrect(VALUE ary)
27912791
return ary_make_partial(ary, rb_cArray, 0, RARRAY_LEN(ary));
27922792
}
27932793

2794-
extern VALUE rb_output_fs;
2794+
extern VALUE rb_get_output_fs(void);
27952795

27962796
static void ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first);
27972797

@@ -2858,31 +2858,37 @@ ary_join_1_ary(VALUE obj, VALUE ary, VALUE sep, VALUE result, VALUE val, int *fi
28582858
}
28592859
}
28602860

2861+
void
2862+
rb_ary_join_1(VALUE obj, VALUE ary, VALUE val, VALUE sep, VALUE result, int *first)
2863+
{
2864+
VALUE tmp;
2865+
2866+
if (!*first && !NIL_P(sep))
2867+
rb_str_buf_append(result, sep);
2868+
2869+
if (RB_TYPE_P(val, T_STRING)) {
2870+
ary_join_1_str(result, val, first);
2871+
}
2872+
else if (RB_TYPE_P(val, T_ARRAY)) {
2873+
ary_join_1_ary(val, ary, sep, result, val, first);
2874+
}
2875+
else if (!NIL_P(tmp = rb_check_string_type(val))) {
2876+
ary_join_1_str(result, tmp, first);
2877+
}
2878+
else if (!NIL_P(tmp = rb_check_array_type(val))) {
2879+
ary_join_1_ary(val, ary, sep, result, tmp, first);
2880+
}
2881+
else {
2882+
ary_join_1_str(result, rb_obj_as_string(val), first);
2883+
}
2884+
}
2885+
28612886
static void
28622887
ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first)
28632888
{
2864-
VALUE val, tmp;
2865-
28662889
for (; i<RARRAY_LEN(ary); i++) {
2867-
if (i > 0 && !NIL_P(sep))
2868-
rb_str_buf_append(result, sep);
2869-
2870-
val = RARRAY_AREF(ary, i);
2871-
if (RB_TYPE_P(val, T_STRING)) {
2872-
ary_join_1_str(result, val, first);
2873-
}
2874-
else if (RB_TYPE_P(val, T_ARRAY)) {
2875-
ary_join_1_ary(val, ary, sep, result, val, first);
2876-
}
2877-
else if (!NIL_P(tmp = rb_check_string_type(val))) {
2878-
ary_join_1_str(result, tmp, first);
2879-
}
2880-
else if (!NIL_P(tmp = rb_check_array_type(val))) {
2881-
ary_join_1_ary(val, ary, sep, result, tmp, first);
2882-
}
2883-
else {
2884-
ary_join_1_str(result, rb_obj_as_string(val), first);
2885-
}
2890+
VALUE val = RARRAY_AREF(ary, i);
2891+
rb_ary_join_1(obj, ary, val, sep, result, first);
28862892
}
28872893
}
28882894

@@ -2960,10 +2966,7 @@ rb_ary_join_m(int argc, VALUE *argv, VALUE ary)
29602966
VALUE sep;
29612967

29622968
if (rb_check_arity(argc, 0, 1) == 0 || NIL_P(sep = argv[0])) {
2963-
sep = rb_output_fs;
2964-
if (!NIL_P(sep)) {
2965-
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
2966-
}
2969+
sep = rb_get_output_fs();
29672970
}
29682971

29692972
return rb_ary_join(ary, sep);

enum.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4948,6 +4948,75 @@ enum_compact(VALUE obj)
49484948
return ary;
49494949
}
49504950

4951+
extern VALUE rb_get_output_fs(void);
4952+
void rb_ary_join_1(VALUE obj, VALUE ary, VALUE val, VALUE sep, VALUE result, int *first);
4953+
4954+
struct join_args {
4955+
VALUE obj;
4956+
VALUE sep;
4957+
VALUE result;
4958+
int first;
4959+
};
4960+
4961+
static VALUE
4962+
join_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
4963+
{
4964+
struct join_args *p = (void *)args;
4965+
ENUM_WANT_SVALUE();
4966+
4967+
rb_ary_join_1(p->obj, p->obj, i, p->sep, p->result, &p->first);
4968+
return p->result;
4969+
}
4970+
4971+
/*
4972+
* call-seq:
4973+
* join(separator = $,) -> new_string
4974+
*
4975+
* Returns the new string formed by joining the converted elements of +self+;
4976+
* Returns an array of all non-+nil+ elements:
4977+
*
4978+
* - Converts recursively using <tt>element.join(separator)</tt>
4979+
* if +element+ is a <tt>kind_of?(Array)</tt>.
4980+
* - Otherwise, converts using <tt>element.to_s</tt>.
4981+
*
4982+
* With no argument given, joins using the output field separator, <tt>$,</tt>:
4983+
*
4984+
* a = [:foo, 'bar', 2].lazy
4985+
* $, # => nil
4986+
* a.join # => "foobar2"
4987+
*
4988+
* With string argument +separator+ given, joins using that separator:
4989+
*
4990+
* a = [:foo, 'bar', 2].lazy
4991+
* a.join("\n") # => "foo\nbar\n2"
4992+
*
4993+
* Joins recursively for nested arrays:
4994+
*
4995+
* a = [:foo, [:bar, [:baz, :bat]]]
4996+
* a.join # => "foobarbazbat"
4997+
*
4998+
* See also Array#join.
4999+
*/
5000+
5001+
static VALUE
5002+
enum_join(int argc, VALUE *argv, VALUE obj)
5003+
{
5004+
struct join_args args = {
5005+
.result = Qnil,
5006+
.sep = Qnil,
5007+
.first = 1,
5008+
};
5009+
5010+
if (rb_check_arity(argc, 0, 1) == 0 || NIL_P(args.sep = argv[0])) {
5011+
args.sep = rb_get_output_fs();
5012+
}
5013+
5014+
args.result = rb_usascii_str_new(0, 0);
5015+
rb_block_call(obj, id_each, 0, 0, join_i, (VALUE)&args);
5016+
5017+
return args.result;
5018+
}
5019+
49515020

49525021
/*
49535022
* == What's Here
@@ -5262,6 +5331,7 @@ Init_Enumerable(void)
52625331
rb_define_method(rb_mEnumerable, "sum", enum_sum, -1);
52635332
rb_define_method(rb_mEnumerable, "uniq", enum_uniq, 0);
52645333
rb_define_method(rb_mEnumerable, "compact", enum_compact, 0);
5334+
rb_define_method(rb_mEnumerable, "join", enum_join, -1);
52655335

52665336
id__alone = rb_intern_const("_alone");
52675337
id__separator = rb_intern_const("_separator");

io.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8699,6 +8699,16 @@ deprecated_rs_setter(VALUE val, ID id, VALUE *var)
86998699
*var = val;
87008700
}
87018701

8702+
VALUE
8703+
rb_get_output_fs(void)
8704+
{
8705+
VALUE ofs = rb_output_fs;
8706+
if (!NIL_P(ofs)) {
8707+
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8708+
}
8709+
return ofs;
8710+
}
8711+
87028712
/*
87038713
* call-seq:
87048714
* print(*objects) -> nil
@@ -8767,9 +8777,7 @@ rb_io_print(int argc, const VALUE *argv, VALUE out)
87678777
line = rb_lastline_get();
87688778
argv = &line;
87698779
}
8770-
if (argc > 1 && !NIL_P(rb_output_fs)) {
8771-
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8772-
}
8780+
if (argc > 1) rb_get_output_fs();
87738781
for (i=0; i<argc; i++) {
87748782
if (!NIL_P(rb_output_fs) && i>0) {
87758783
rb_io_write(out, rb_output_fs);

test/ruby/test_enum.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,4 +1356,8 @@ def test_all_fast
13561356
assert_equal(kk, "key")
13571357
assert_equal(vv, { "key2" => 1 })
13581358
end
1359+
1360+
def test_join
1361+
assert_equal "foobar2", [:foo, "bar", 2].each.join("")
1362+
end
13591363
end

test/ruby/test_lazy_enumerator.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,4 +715,8 @@ def test_with_index
715715
def test_with_index_size
716716
assert_equal(3, Enumerator::Lazy.new([1, 2, 3], 3){|y, v| y << v}.with_index.size)
717717
end
718+
719+
def test_join
720+
assert_equal "ABC", (65..).lazy.map {|i| i.chr}.take(3).join("")
721+
end
718722
end

0 commit comments

Comments
 (0)