Project

General

Profile

Feature #5970 ยป enumerable_join.patch

zzak (zzak _), 11/19/2012 08:26 AM

View differences:

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 })
    (1-1/1)