Feature #4787 ยป each_modulo.patch
numeric.c  

3296  3296  
3297  3297 
/* 
3298  3298 
* callseq: 
3299 
* int.each_modulo(n) > 

3300 
* 

3301 
* If a block given, enumerates with iterated modulo and returns self. 

3302 
* Otherwise, returns an Enumerator. 

3303 
*/ 

3304  
3305 
static VALUE 

3306 
int_each_modulo(VALUE num, VALUE modulus) 

3307 
{ 

3308 
VALUE big_q, qr; 

3309 
long q, r, m; 

3310  
3311 
switch (TYPE(modulus)) { 

3312 
case T_BIGNUM: 

3313 
if (rb_big_cmp(modulus, rb_int2big(1)) <= 0) { 

3314 
goto arg_must_be_lt_1; 

3315 
} 

3316 
break; 

3317  
3318 
case T_FIXNUM: 

3319 
if (FIX2INT(modulus) <= 1) { 

3320 
arg_must_be_lt_1: 

3321 
rb_raise(rb_eArgError, "argument must be larger than 1"); 

3322 
} 

3323 
break; 

3324  
3325 
default: 

3326 
rb_raise(rb_eArgError, "argument must be an Integer (%s)", 

3327 
rb_obj_classname(modulus)); 

3328 
} 

3329  
3330 
RETURN_ENUMERATOR(num, 1, &modulus); 

3331  
3332 
big_q = num; 

3333 
if (TYPE(big_q) == T_BIGNUM) { 

3334 
while (TYPE(big_q) == T_BIGNUM) { 

3335 
qr = rb_big_divmod(big_q, modulus); 

3336 
rb_yield(RARRAY_PTR(qr)[1]); 

3337 
big_q = RARRAY_PTR(qr)[0]; 

3338 
} 

3339 
} 

3340  
3341 
q = NUM2INT(big_q); 

3342 
switch (TYPE(modulus)) { 

3343 
case T_BIGNUM: 

3344 
while (q > 0) { 

3345 
qr = rb_big_divmod(rb_int2big(q), modulus); 

3346 
rb_yield(RARRAY_PTR(qr)[1]); 

3347 
q = NUM2INT(RARRAY_PTR(qr)[0]); 

3348 
} 

3349 
break; 

3350  
3351 
case T_FIXNUM: 

3352 
m = FIX2INT(modulus); 

3353 
while (q > 0) { 

3354 
fixdivmod(q, m, &q, &r); 

3355 
rb_yield(INT2FIX(r)); 

3356 
} 

3357 
break; 

3358 
} 

3359  
3360 
return num; 

3361 
} 

3362  
3363 
/* 

3364 
* callseq: 

3299  3365 
* fix.zero? > true or false 
3300  3366 
* 
3301  3367 
* Returns <code>true</code> if <i>fix</i> is zero. 
...  ...  
3454  3520 
rb_define_method(rb_cInteger, "truncate", int_to_i, 0); 
3455  3521 
rb_define_method(rb_cInteger, "round", int_round, 1); 
3456  3522  
3523 
rb_define_method(rb_cInteger, "each_modulo", int_each_modulo, 1); 

3524  
3457  3525 
rb_cFixnum = rb_define_class("Fixnum", rb_cInteger); 
3458  3526  
3459  3527 
rb_define_method(rb_cFixnum, "to_s", fix_to_s, 1); 
test/ruby/test_integer.rb  

198  198 
assert_equal(1111_1111_1111_1111_1111_1111_1111_1110, (1111_1111_1111_1111_1111_1111_1111_1111).round(1)) 
199  199 
assert_equal(Bignum, (1111_1111_1111_1111_1111_1111_1111_1111).round(1).class) 
200  200 
end 
201  
202 
def test_each_modulo_returns_Enumerator_unless_block_given 

203 
assert_instance_of(Enumerator, 1111.each_modulo(10)) 

204 
assert_instance_of(Enumerator, 1111.each_modulo(2**100)) 

205 
assert_instance_of(Enumerator, (2**100).each_modulo(10)) 

206 
assert_instance_of(Enumerator, (2**100).each_modulo(2**100)) 

207 
end 

208  
209 
def test_each_modulo_calls_block_with_values_of_iterated_modulo 

210 
assert_equal([1, 2, 2, 1, 1], 133.each_modulo(3).to_a) 

211 
assert_equal([133], 133.each_modulo(2**100).to_a) 

212 
assert_equal([1, 2, 1], (2**200).each_modulo(2**1001).to_a) 

213 
end 

214  
215 
def test_each_modulo_raise_ArgumentError_when_arg_le_1 

216 
assert_raise(ArgumentError) { 111.each_modulo(1) } 

217 
assert_raise(ArgumentError) { 111.each_modulo(0) } 

218 
assert_raise(ArgumentError) { 111.each_modulo(42) } 

219 
assert_raise(ArgumentError) { (2**100).each_modulo(1) } 

220 
assert_raise(ArgumentError) { (2**100).each_modulo(0) } 

221 
assert_raise(ArgumentError) { (2**100).each_modulo(42) } 

222 
end 

223  
224 
def test_each_modulo_raise_ArgumentError_when_arg_not_int 

225 
assert_raise(ArgumentError) { 111.each_modulo(Object.new) } 

226 
assert_raise(ArgumentError) { 111.each_modulo(1.0) } 

227 
assert_raise(ArgumentError) { 111.each_modulo(1.quo(3)) } 

228 
assert_raise(ArgumentError) { 111.each_modulo(Complex(1, 1)) } 

229 
assert_raise(ArgumentError) { (2**100).each_modulo(Object.new) } 

230 
assert_raise(ArgumentError) { (2**100).each_modulo(1.0) } 

231 
assert_raise(ArgumentError) { (2**100).each_modulo(1.quo(3)) } 

232 
assert_raise(ArgumentError) { (2**100).each_modulo(Complex(1, 1)) } 

233 
end 

201  234 
end 