Feature #5970 ยป enumerable_join.patch
| enum.c | ||
|---|---|---|
|
#include "ruby/ruby.h"
|
||
|
#include "ruby/util.h"
|
||
|
#include "ruby/encoding.h"
|
||
|
#include "node.h"
|
||
|
#include "id.h"
|
||
|
#include "internal.h"
|
||
| ... | ... | |
|
}
|
||
|
static VALUE
|
||
|
enum_join_i(VALUE obj, VALUE *params, int argc, VALUE *argv)
|
||
|
{
|
||
|
VALUE *param = (VALUE *)params;
|
||
|
VALUE sep = param[0];
|
||
|
VALUE result = param[1];
|
||
|
int *first = (int *)param[2];
|
||
|
ID join = rb_intern("join");
|
||
|
VALUE tmp;
|
||
|
switch (TYPE(obj)) {
|
||
|
case T_STRING:
|
||
|
str_join:
|
||
|
if (!NIL_P(sep) && !*first)
|
||
|
rb_str_buf_append(result, sep);
|
||
|
if (*first)
|
||
|
rb_enc_copy(result, obj);
|
||
|
rb_str_buf_append(result, obj);
|
||
|
*first = FALSE;
|
||
|
break;
|
||
|
default:
|
||
|
if (rb_respond_to(obj, join)) {
|
||
|
obj = rb_funcall(obj, join, 1, sep);
|
||
|
}
|
||
|
else {
|
||
|
obj = rb_obj_as_string(obj);
|
||
|
}
|
||
|
rb_enc_copy(obj, result);
|
||
|
goto str_join;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
/*
|
||
|
* call-seq:
|
||
|
* enum.join(sep=$,) -> str
|
||
|
*
|
||
|
* Returns a string created by converting each element of the
|
||
|
* <i>enum</i> to a string, separated by <i>sep</i>.
|
||
|
*
|
||
|
* (1..3).join #=> "123"
|
||
|
* (1..3).join("-") #=> "1-2-3"
|
||
|
*/
|
||
|
static VALUE
|
||
|
enum_join(int argc, VALUE *argv, VALUE obj)
|
||
|
{
|
||
|
VALUE sep;
|
||
|
VALUE result;
|
||
|
VALUE args[3];
|
||
|
int first = TRUE;
|
||
|
int taint = FALSE;
|
||
|
int untrust = FALSE;
|
||
|
if (!enum_any(obj))
|
||
|
return rb_usascii_str_new(0, 0);
|
||
|
rb_scan_args(argc, argv, "01", &sep);
|
||
|
if (NIL_P(sep)) sep = rb_output_fs;
|
||
|
if (!NIL_P(sep)) StringValue(sep);
|
||
|
if (OBJ_TAINTED(obj) || OBJ_TAINTED(sep)) taint = TRUE;
|
||
|
if (OBJ_UNTRUSTED(obj) || OBJ_UNTRUSTED(sep)) untrust = TRUE;
|
||
|
result = rb_usascii_str_new(0, 0);
|
||
|
if (taint) OBJ_TAINT(result);
|
||
|
if (untrust) OBJ_UNTRUST(result);
|
||
|
args[0] = sep;
|
||
|
args[1] = result;
|
||
|
args[2] = (VALUE)&first;
|
||
|
rb_block_call(obj, id_each, 0, 0, enum_join_i, (VALUE)args);
|
||
|
return result;
|
||
|
}
|
||
|
static VALUE
|
||
|
cycle_i(VALUE i, VALUE ary, int argc, VALUE *argv)
|
||
|
{
|
||
|
ENUM_WANT_SVALUE();
|
||
| ... | ... | |
|
rb_define_method(rb_mEnumerable, "cycle", enum_cycle, -1);
|
||
|
rb_define_method(rb_mEnumerable, "chunk", enum_chunk, -1);
|
||
|
rb_define_method(rb_mEnumerable, "slice_before", enum_slice_before, -1);
|
||
|
rb_define_method(rb_mEnumerable, "join", enum_join, -1);
|
||
|
id_next = rb_intern("next");
|
||
|
}
|
||
| test/ruby/test_enum.rb | ||
|---|---|---|
|
assert_equal([1, 2, 3, 1, 2], @obj.to_a)
|
||
|
end
|
||
|
def test_join
|
||
|
assert_equal('123', (1..3).join )
|
||
|
@speach = Object.new
|
||
|
class << @speach
|
||
|
attr_writer :statements
|
||
|
include Enumerable
|
||
|
def each
|
||
|
@statements.each{|s| yield s }
|
||
|
end
|
||
|
end
|
||
|
@speach.statements = [1,2,3,1,2]
|
||
|
assert_equal('12312', @speach.join )
|
||
|
assert_equal('1;2;3;1;2', @speach.join(';') )
|
||
|
@speach.statements = [ [9,8,7], 'ohai', @obj ]
|
||
|
assert_equal('9;8;7;ohai;1;2;3;1;2', @speach.join(';') )
|
||
|
@speach.statements = []
|
||
|
assert_equal('', @speach.join )
|
||
|
["", ":", nil].each do |output_fs|
|
||
|
$, = output_fs
|
||
|
assert_equal("", @speach.join)
|
||
|
assert_equal("", @speach.join(','))
|
||
|
assert_equal(Encoding::US_ASCII, @speach.join.encoding)
|
||
|
end
|
||
|
@speach.statements = [1,2,3,1,2]
|
||
|
["", ":", nil].each do |output_fs|
|
||
|
assert_equal("1,2,3,1,2", @speach.join(','))
|
||
|
end
|
||
|
$, = ":"
|
||
|
assert_equal("1:2:3:1:2", @speach.join)
|
||
|
$, = nil
|
||
|
assert_equal("12312", @speach.join)
|
||
|
@speach.taint
|
||
|
@speach.untrust
|
||
|
s = @speach.join
|
||
|
assert_equal(true, s.tainted?)
|
||
|
assert_equal(true, s.untrusted?)
|
||
|
e = ''.force_encoding('EUC-JP')
|
||
|
u = ''.force_encoding('UTF-8')
|
||
|
assert_equal(Encoding::US_ASCII, @speach.join.encoding)
|
||
|
@speach.statements = [1, [u]]
|
||
|
assert_equal(Encoding::US_ASCII, @speach.join.encoding)
|
||
|
@speach.statements = [u, [e]]
|
||
|
assert_equal(Encoding::UTF_8, @speach.join.encoding)
|
||
|
@speach.statements = [u, [1]]
|
||
|
assert_equal(Encoding::UTF_8, @speach.join.encoding)
|
||
|
bug5379 = '[ruby-core:39776]'
|
||
|
@speach.statements = [[], u, nil]
|
||
|
assert_equal(Encoding::US_ASCII, @speach.join.encoding, bug5379)
|
||
|
@speach.statements = [[], "\u3042", nil]
|
||
|
assert_equal(Encoding::UTF_8, @speach.join.encoding, bug5379)
|
||
|
@nested = Object.new
|
||
|
class << @nested
|
||
|
include Enumerable
|
||
|
class Nested
|
||
|
include Enumerable
|
||
|
def each
|
||
|
yield Nested.new
|
||
|
end
|
||
|
end
|
||
|
def each
|
||
|
yield Nested.new
|
||
|
end
|
||
|
end
|
||
|
assert_raise(SystemStackError){ @nested.join }
|
||
|
ensure
|
||
|
$, = nil
|
||
|
end
|
||
|
def test_inject
|
||
|
assert_equal(12, @obj.inject {|z, x| z * x })
|
||
|
assert_equal(48, @obj.inject {|z, x| z * 2 + x })
|
||