Project

General

Profile

Feature #5970 ยป enumerable_join.patch

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

View differences:

enum.c
11 11

  
12 12
#include "ruby/ruby.h"
13 13
#include "ruby/util.h"
14
#include "ruby/encoding.h"
14 15
#include "node.h"
15 16
#include "id.h"
16 17
#include "internal.h"
......
2215 2216
}
2216 2217

  
2217 2218
static VALUE
2219
enum_join_i(VALUE obj, VALUE *params, int argc, VALUE *argv)
2220
{
2221
    VALUE *param = (VALUE *)params;
2222
    VALUE sep = param[0];
2223
    VALUE result = param[1];
2224
    int *first = (int *)param[2];
2225
    ID join = rb_intern("join");
2226
    VALUE tmp;
2227

  
2228
    switch (TYPE(obj)) {
2229
	case T_STRING:
2230
	str_join:
2231
	  if (!NIL_P(sep) && !*first)
2232
		rb_str_buf_append(result, sep);
2233
	  if (*first)
2234
		rb_enc_copy(result, obj);
2235
	  rb_str_buf_append(result, obj);
2236
	  *first = FALSE;
2237
	  break;
2238
	default:
2239
	  if (rb_respond_to(obj, join)) {
2240
		obj = rb_funcall(obj, join, 1, sep);
2241
	  }
2242
	  else {
2243
		obj = rb_obj_as_string(obj);
2244
	  }
2245
	  rb_enc_copy(obj, result);
2246
	  goto str_join;
2247
    }
2248
    return result;
2249
}
2250

  
2251
/*
2252
 *  call-seq:
2253
 *     enum.join(sep=$,)    -> str
2254
 *
2255
 *  Returns a string created by converting each element of the 
2256
 *  <i>enum</i> to a string, separated by <i>sep</i>.
2257
 *
2258
 *     (1..3).join        #=> "123"
2259
 *     (1..3).join("-")   #=> "1-2-3"
2260
 */
2261

  
2262
static VALUE
2263
enum_join(int argc, VALUE *argv, VALUE obj)
2264
{
2265
    VALUE sep;
2266
    VALUE result;
2267
    VALUE args[3];
2268
    int first = TRUE;
2269
    int taint = FALSE;
2270
    int untrust = FALSE;
2271

  
2272
    if (!enum_any(obj))
2273
	return rb_usascii_str_new(0, 0);
2274

  
2275
    rb_scan_args(argc, argv, "01", &sep);
2276
    if (NIL_P(sep)) sep = rb_output_fs;
2277
    if (!NIL_P(sep)) StringValue(sep);
2278

  
2279
    if (OBJ_TAINTED(obj) || OBJ_TAINTED(sep)) taint = TRUE;
2280
    if (OBJ_UNTRUSTED(obj) || OBJ_UNTRUSTED(sep)) untrust = TRUE;
2281

  
2282
    result = rb_usascii_str_new(0, 0);
2283

  
2284
    if (taint) OBJ_TAINT(result);
2285
    if (untrust) OBJ_UNTRUST(result);
2286

  
2287
    args[0] = sep;
2288
    args[1] = result;
2289
    args[2] = (VALUE)&first;
2290

  
2291
    rb_block_call(obj, id_each, 0, 0, enum_join_i, (VALUE)args);
2292

  
2293
    return result;
2294
}
2295

  
2296
static VALUE
2218 2297
cycle_i(VALUE i, VALUE ary, int argc, VALUE *argv)
2219 2298
{
2220 2299
    ENUM_WANT_SVALUE();
......
2762 2841
    rb_define_method(rb_mEnumerable, "cycle", enum_cycle, -1);
2763 2842
    rb_define_method(rb_mEnumerable, "chunk", enum_chunk, -1);
2764 2843
    rb_define_method(rb_mEnumerable, "slice_before", enum_slice_before, -1);
2844
    rb_define_method(rb_mEnumerable, "join", enum_join, -1);
2765 2845

  
2766 2846
    id_next = rb_intern("next");
2767 2847
}
test/ruby/test_enum.rb
103 103
    assert_equal([1, 2, 3, 1, 2], @obj.to_a)
104 104
  end
105 105

  
106
  def test_join
107
    assert_equal('123', (1..3).join )
108

  
109
    @speach = Object.new
110
    class << @speach
111
      attr_writer :statements
112
      include Enumerable
113
      def each
114
        @statements.each{|s| yield s }
115
      end
116
    end
117
    @speach.statements = [1,2,3,1,2]
118

  
119
    assert_equal('12312', @speach.join )
120
    assert_equal('1;2;3;1;2', @speach.join(';') )
121

  
122
    @speach.statements = [ [9,8,7], 'ohai', @obj ]
123
    assert_equal('9;8;7;ohai;1;2;3;1;2', @speach.join(';') )
124

  
125
    @speach.statements = []
126
    assert_equal('', @speach.join )
127

  
128
    ["", ":", nil].each do |output_fs|
129
      $, = output_fs
130
      assert_equal("", @speach.join)
131
      assert_equal("", @speach.join(','))
132
      assert_equal(Encoding::US_ASCII, @speach.join.encoding)
133
    end
134

  
135
    @speach.statements = [1,2,3,1,2]
136
    ["", ":", nil].each do |output_fs|
137
      assert_equal("1,2,3,1,2", @speach.join(','))
138
    end
139

  
140
    $, = ":"
141
    assert_equal("1:2:3:1:2", @speach.join)
142

  
143
    $, = nil
144
    assert_equal("12312", @speach.join)
145

  
146
    @speach.taint
147
    @speach.untrust
148
    s = @speach.join
149
    assert_equal(true, s.tainted?)
150
    assert_equal(true, s.untrusted?)
151

  
152
    e = ''.force_encoding('EUC-JP')
153
    u = ''.force_encoding('UTF-8')
154
    assert_equal(Encoding::US_ASCII, @speach.join.encoding)
155
    @speach.statements = [1, [u]]
156
    assert_equal(Encoding::US_ASCII, @speach.join.encoding)
157
    @speach.statements = [u, [e]]
158
    assert_equal(Encoding::UTF_8, @speach.join.encoding)
159
    @speach.statements = [u, [1]]
160
    assert_equal(Encoding::UTF_8, @speach.join.encoding)
161
    bug5379 = '[ruby-core:39776]'
162
    @speach.statements = [[], u, nil]
163
    assert_equal(Encoding::US_ASCII, @speach.join.encoding, bug5379)
164
    @speach.statements = [[], "\u3042", nil]
165
    assert_equal(Encoding::UTF_8, @speach.join.encoding, bug5379)
166

  
167
    @nested = Object.new
168
    class << @nested
169
      include Enumerable
170
      class Nested
171
        include Enumerable
172
        def each
173
          yield Nested.new
174
        end
175
      end
176
      def each
177
        yield Nested.new
178
      end
179
    end
180
    assert_raise(SystemStackError){ @nested.join }
181
  ensure
182
    $, = nil
183
  end
184

  
106 185
  def test_inject
107 186
    assert_equal(12, @obj.inject {|z, x| z * x })
108 187
    assert_equal(48, @obj.inject {|z, x| z * 2 + x })
109
-