mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
enumerator.c: Introduce Enumerator::ArithmeticSequence
This commit introduces new core class Enumerator::ArithmeticSequence. Enumerator::ArithmeticSequence is a subclass of Enumerator, and represents a number generator of an arithmetic sequence. After this commit, Numeric#step and Range#step without blocks returned an ArithmeticSequence object instead of an Enumerator. This class introduces the following incompatibilities: - You can create a zero-step ArithmeticSequence, and its size is not ArgumentError, but Infinity. - You can create a negative-step ArithmeticSequence from a range. [ruby-core:82816] [Feature #13904] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64205 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
1777e39c2a
commit
f15069338d
11 changed files with 883 additions and 47 deletions
412
enumerator.c
412
enumerator.c
|
@ -15,6 +15,10 @@
|
|||
#include "internal.h"
|
||||
#include "id.h"
|
||||
|
||||
#ifdef HAVE_FLOAT_H
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Document-class: Enumerator
|
||||
*
|
||||
|
@ -105,6 +109,7 @@ VALUE rb_cEnumerator;
|
|||
static VALUE rb_cLazy;
|
||||
static ID id_rewind, id_new, id_yield, id_to_enum;
|
||||
static ID id_next, id_result, id_lazy, id_receiver, id_arguments, id_memo, id_method, id_force;
|
||||
static ID id_begin, id_end, id_step, id_exclude_end;
|
||||
static VALUE sym_each, sym_cycle;
|
||||
|
||||
#define id_call idCall
|
||||
|
@ -156,6 +161,8 @@ struct proc_entry {
|
|||
static VALUE generator_allocate(VALUE klass);
|
||||
static VALUE generator_init(VALUE obj, VALUE proc);
|
||||
|
||||
static VALUE rb_cArithSeq;
|
||||
|
||||
/*
|
||||
* Enumerator
|
||||
*/
|
||||
|
@ -2375,6 +2382,391 @@ stop_result(VALUE self)
|
|||
return rb_attr_get(self, id_result);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_arith_seq_new(VALUE obj, VALUE meth, int argc, VALUE const *argv,
|
||||
rb_enumerator_size_func *size_fn,
|
||||
VALUE beg, VALUE end, VALUE step, int excl)
|
||||
{
|
||||
VALUE aseq = enumerator_init(enumerator_allocate(rb_cArithSeq),
|
||||
obj, meth, argc, argv, size_fn, Qnil);
|
||||
rb_ivar_set(aseq, id_begin, beg);
|
||||
rb_ivar_set(aseq, id_end, end);
|
||||
rb_ivar_set(aseq, id_step, step);
|
||||
rb_ivar_set(aseq, id_exclude_end, excl ? Qtrue : Qfalse);
|
||||
return aseq;
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
arith_seq_begin(VALUE self)
|
||||
{
|
||||
return rb_ivar_get(self, id_begin);
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
arith_seq_end(VALUE self)
|
||||
{
|
||||
return rb_ivar_get(self, id_end);
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
arith_seq_step(VALUE self)
|
||||
{
|
||||
return rb_ivar_get(self, id_step);
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
arith_seq_exclude_end(VALUE self)
|
||||
{
|
||||
return rb_ivar_get(self, id_exclude_end);
|
||||
}
|
||||
|
||||
static inline int
|
||||
arith_seq_exclude_end_p(VALUE self)
|
||||
{
|
||||
return RTEST(arith_seq_exclude_end(self));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
arith_seq_first(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE b, e, s, len_1;
|
||||
|
||||
b = arith_seq_begin(self);
|
||||
e = arith_seq_end(self);
|
||||
s = arith_seq_step(self);
|
||||
|
||||
if (!NIL_P(e)) {
|
||||
len_1 = rb_int_idiv(rb_int_minus(e, b), s);
|
||||
if (rb_num_negative_int_p(len_1)) {
|
||||
if (argc == 0) {
|
||||
return Qnil;
|
||||
}
|
||||
return rb_ary_new_capa(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
return b;
|
||||
}
|
||||
|
||||
/* TODO: optimization */
|
||||
|
||||
return rb_call_super(argc, argv);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
arith_seq_last(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE b, e, s, len_1, len, last, nv, ary;
|
||||
int last_is_adjusted;
|
||||
long n;
|
||||
|
||||
e = arith_seq_end(self);
|
||||
if (NIL_P(e)) {
|
||||
rb_raise(rb_eRangeError,
|
||||
"cannot get the last element of endless arithmetic sequence");
|
||||
}
|
||||
|
||||
b = arith_seq_begin(self);
|
||||
s = arith_seq_step(self);
|
||||
|
||||
len_1 = rb_int_idiv(rb_int_minus(e, b), s);
|
||||
if (rb_num_negative_int_p(len_1)) {
|
||||
if (argc == 0) {
|
||||
return Qnil;
|
||||
}
|
||||
return rb_ary_new_capa(0);
|
||||
}
|
||||
|
||||
last = rb_int_plus(b, rb_int_mul(s, len_1));
|
||||
if ((last_is_adjusted = arith_seq_exclude_end_p(self) && rb_equal(last, e))) {
|
||||
last = rb_int_minus(last, s);
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
return last;
|
||||
}
|
||||
|
||||
if (last_is_adjusted) {
|
||||
len = len_1;
|
||||
}
|
||||
else {
|
||||
len = rb_int_plus(len_1, INT2FIX(1));
|
||||
}
|
||||
|
||||
rb_scan_args(argc, argv, "1", &nv);
|
||||
if (RTEST(rb_int_gt(nv, len))) {
|
||||
nv = len;
|
||||
}
|
||||
n = NUM2LONG(nv);
|
||||
if (n < 0) {
|
||||
rb_raise(rb_eArgError, "negative array size");
|
||||
}
|
||||
|
||||
ary = rb_ary_new_capa(n);
|
||||
b = rb_int_minus(last, rb_int_mul(s, nv));
|
||||
while (n) {
|
||||
b = rb_int_plus(b, s);
|
||||
rb_ary_push(ary, b);
|
||||
--n;
|
||||
}
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
arith_seq_inspect(VALUE self)
|
||||
{
|
||||
struct enumerator *e;
|
||||
VALUE eobj, str, eargs;
|
||||
int range_p;
|
||||
|
||||
TypedData_Get_Struct(self, struct enumerator, &enumerator_data_type, e);
|
||||
|
||||
eobj = rb_attr_get(self, id_receiver);
|
||||
if (NIL_P(eobj)) {
|
||||
eobj = e->obj;
|
||||
}
|
||||
|
||||
range_p = RTEST(rb_obj_is_kind_of(eobj, rb_cRange));
|
||||
str = rb_sprintf("(%s%"PRIsVALUE"%s.", range_p ? "(" : "", eobj, range_p ? ")" : "");
|
||||
|
||||
rb_str_buf_append(str, rb_id2str(e->meth));
|
||||
|
||||
eargs = rb_attr_get(eobj, id_arguments);
|
||||
if (NIL_P(eargs)) {
|
||||
eargs = e->args;
|
||||
}
|
||||
if (eargs != Qfalse) {
|
||||
long argc = RARRAY_LEN(eargs);
|
||||
const VALUE *argv = RARRAY_CONST_PTR(eargs); /* WB: no new reference */
|
||||
|
||||
if (argc > 0) {
|
||||
VALUE kwds = Qnil;
|
||||
|
||||
rb_str_buf_cat2(str, "(");
|
||||
|
||||
if (RB_TYPE_P(argv[argc-1], T_HASH)) {
|
||||
int all_key = TRUE;
|
||||
rb_hash_foreach(argv[argc-1], key_symbol_p, (VALUE)&all_key);
|
||||
if (all_key) kwds = argv[--argc];
|
||||
}
|
||||
|
||||
while (argc--) {
|
||||
VALUE arg = *argv++;
|
||||
|
||||
rb_str_append(str, rb_inspect(arg));
|
||||
rb_str_buf_cat2(str, ", ");
|
||||
OBJ_INFECT(str, arg);
|
||||
}
|
||||
if (!NIL_P(kwds)) {
|
||||
rb_hash_foreach(kwds, kwd_append, str);
|
||||
}
|
||||
rb_str_set_len(str, RSTRING_LEN(str)-2); /* drop the last ", " */
|
||||
rb_str_buf_cat2(str, ")");
|
||||
}
|
||||
}
|
||||
|
||||
rb_str_buf_cat2(str, ")");
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
arith_seq_eq(VALUE self, VALUE other)
|
||||
{
|
||||
if (!RTEST(rb_obj_is_kind_of(other, rb_cArithSeq))) {
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
if (!rb_equal(arith_seq_begin(self), arith_seq_begin(other))) {
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
if (!rb_equal(arith_seq_end(self), arith_seq_end(other))) {
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
if (!rb_equal(arith_seq_step(self), arith_seq_step(other))) {
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
if (arith_seq_exclude_end_p(self) != arith_seq_exclude_end_p(other)) {
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
arith_seq_hash(VALUE self)
|
||||
{
|
||||
st_index_t hash;
|
||||
VALUE v;
|
||||
|
||||
hash = rb_hash_start(arith_seq_exclude_end_p(self));
|
||||
v = rb_hash(arith_seq_begin(self));
|
||||
hash = rb_hash_uint(hash, NUM2LONG(v));
|
||||
v = rb_hash(arith_seq_end(self));
|
||||
hash = rb_hash_uint(hash, NUM2LONG(v));
|
||||
v = rb_hash(arith_seq_step(self));
|
||||
hash = rb_hash_uint(hash, NUM2LONG(v));
|
||||
hash = rb_hash_end(hash);
|
||||
|
||||
return LONG2FIX(hash);
|
||||
}
|
||||
|
||||
struct arith_seq_gen {
|
||||
VALUE current;
|
||||
VALUE end;
|
||||
VALUE step;
|
||||
int excl;
|
||||
};
|
||||
|
||||
static VALUE
|
||||
arith_seq_each(VALUE self)
|
||||
{
|
||||
VALUE c, e, s, len_1, last;
|
||||
int x;
|
||||
|
||||
if (!rb_block_given_p()) return self;
|
||||
|
||||
c = arith_seq_begin(self);
|
||||
e = arith_seq_end(self);
|
||||
s = arith_seq_step(self);
|
||||
x = arith_seq_exclude_end_p(self);
|
||||
|
||||
if (ruby_float_step(c, e, s, x, TRUE)) {
|
||||
return self;
|
||||
}
|
||||
|
||||
if (NIL_P(e)) {
|
||||
while (1) {
|
||||
rb_yield(c);
|
||||
c = rb_int_plus(c, s);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
if (rb_equal(s, INT2FIX(0))) {
|
||||
while (1) {
|
||||
rb_yield(c);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
len_1 = rb_int_idiv(rb_int_minus(e, c), s);
|
||||
last = rb_int_plus(c, rb_int_mul(s, len_1));
|
||||
if (x && rb_equal(last, e)) {
|
||||
last = rb_int_minus(last, s);
|
||||
}
|
||||
|
||||
if (rb_num_negative_int_p(s)) {
|
||||
while (RTEST(rb_int_ge(c, last))) {
|
||||
rb_yield(c);
|
||||
c = rb_int_plus(c, s);
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (RTEST(rb_int_ge(last, c))) {
|
||||
rb_yield(c);
|
||||
c = rb_int_plus(c, s);
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static double
|
||||
arith_seq_float_step_size(double beg, double end, double step, int excl)
|
||||
{
|
||||
double const epsilon = DBL_EPSILON;
|
||||
double n = (end - beg) / step;
|
||||
double err = (fabs(beg) + fabs(end) + fabs(end - beg)) / fabs(step) * epsilon;
|
||||
|
||||
if (isinf(step)) {
|
||||
return step > 0 ? beg <= end : beg >= end;
|
||||
}
|
||||
if (step == 0) {
|
||||
return HUGE_VAL;
|
||||
}
|
||||
if (err > 0.5) err = 0.5;
|
||||
if (excl) {
|
||||
if (n <= 0) return 0;
|
||||
if (n < 1)
|
||||
n = 0;
|
||||
else
|
||||
n = floor(n - err);
|
||||
}
|
||||
else {
|
||||
if (n < 0) return 0;
|
||||
n = floor(n + err);
|
||||
}
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
arith_seq_size(VALUE self)
|
||||
{
|
||||
VALUE b, e, s, len_1, len, last;
|
||||
int x;
|
||||
|
||||
b = arith_seq_begin(self);
|
||||
e = arith_seq_end(self);
|
||||
s = arith_seq_step(self);
|
||||
x = arith_seq_exclude_end_p(self);
|
||||
|
||||
if (RB_FLOAT_TYPE_P(b) || RB_FLOAT_TYPE_P(e) || RB_FLOAT_TYPE_P(s)) {
|
||||
double ee, n;
|
||||
|
||||
if (NIL_P(e)) {
|
||||
if (rb_num_negative_int_p(s)) {
|
||||
ee = -HUGE_VAL;
|
||||
}
|
||||
else {
|
||||
ee = HUGE_VAL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ee = NUM2DBL(e);
|
||||
}
|
||||
|
||||
n = arith_seq_float_step_size(NUM2DBL(b), ee, NUM2DBL(s), x);
|
||||
if (isinf(n)) return DBL2NUM(n);
|
||||
if (POSFIXABLE(n)) return LONG2FIX(n);
|
||||
return rb_dbl2big(n);
|
||||
}
|
||||
|
||||
if (NIL_P(e)) {
|
||||
return DBL2NUM(HUGE_VAL);
|
||||
}
|
||||
|
||||
if (!rb_obj_is_kind_of(s, rb_cNumeric)) {
|
||||
s = rb_to_int(s);
|
||||
}
|
||||
|
||||
if (rb_equal(s, INT2FIX(0))) {
|
||||
return DBL2NUM(HUGE_VAL);
|
||||
}
|
||||
|
||||
len_1 = rb_int_idiv(rb_int_minus(e, b), s);
|
||||
if (rb_num_negative_int_p(len_1)) {
|
||||
return INT2FIX(0);
|
||||
}
|
||||
|
||||
last = rb_int_plus(b, rb_int_mul(s, len_1));
|
||||
if (x && rb_equal(last, e)) {
|
||||
len = len_1;
|
||||
}
|
||||
else {
|
||||
len = rb_int_plus(len_1, INT2FIX(1));
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void
|
||||
InitVM_Enumerator(void)
|
||||
{
|
||||
|
@ -2450,6 +2842,22 @@ InitVM_Enumerator(void)
|
|||
rb_define_method(rb_cYielder, "yield", yielder_yield, -2);
|
||||
rb_define_method(rb_cYielder, "<<", yielder_yield_push, -2);
|
||||
|
||||
/* ArithmeticSequence */
|
||||
rb_cArithSeq = rb_define_class_under(rb_cEnumerator, "ArithmeticSequence", rb_cEnumerator);
|
||||
rb_define_method(rb_cArithSeq, "begin", arith_seq_begin, 0);
|
||||
rb_define_method(rb_cArithSeq, "end", arith_seq_end, 0);
|
||||
rb_define_method(rb_cArithSeq, "exclude_end?", arith_seq_exclude_end, 0);
|
||||
rb_define_method(rb_cArithSeq, "step", arith_seq_step, 0);
|
||||
rb_define_method(rb_cArithSeq, "first", arith_seq_first, -1);
|
||||
rb_define_method(rb_cArithSeq, "last", arith_seq_last, -1);
|
||||
rb_define_method(rb_cArithSeq, "inspect", arith_seq_inspect, 0);
|
||||
rb_define_method(rb_cArithSeq, "==", arith_seq_eq, 1);
|
||||
rb_define_method(rb_cArithSeq, "===", arith_seq_eq, 1);
|
||||
rb_define_method(rb_cArithSeq, "eql?", arith_seq_eq, 1);
|
||||
rb_define_method(rb_cArithSeq, "hash", arith_seq_hash, 0);
|
||||
rb_define_method(rb_cArithSeq, "each", arith_seq_each, 0);
|
||||
rb_define_method(rb_cArithSeq, "size", arith_seq_size, 0);
|
||||
|
||||
rb_provide("enumerator.so"); /* for backward compatibility */
|
||||
}
|
||||
|
||||
|
@ -2469,6 +2877,10 @@ Init_Enumerator(void)
|
|||
id_method = rb_intern("method");
|
||||
id_force = rb_intern("force");
|
||||
id_to_enum = rb_intern("to_enum");
|
||||
id_begin = rb_intern("begin");
|
||||
id_end = rb_intern("end");
|
||||
id_step = rb_intern("step");
|
||||
id_exclude_end = rb_intern("exclude_end");
|
||||
sym_each = ID2SYM(id_each);
|
||||
sym_cycle = ID2SYM(rb_intern("cycle"));
|
||||
|
||||
|
|
|
@ -1995,6 +1995,11 @@ enum rb_int_parse_flags {
|
|||
};
|
||||
VALUE rb_int_parse_cstr(const char *str, ssize_t len, char **endp, size_t *ndigits, int base, int flags);
|
||||
|
||||
/* enumerator.c (export) */
|
||||
VALUE rb_arith_seq_new(VALUE obj, VALUE meth, int argc, VALUE const *argv,
|
||||
rb_enumerator_size_func *size_fn,
|
||||
VALUE beg, VALUE end, VALUE step, int excl);
|
||||
|
||||
/* error.c (export) */
|
||||
int rb_bug_reporter_add(void (*func)(FILE *, void *), void *data);
|
||||
NORETURN(void rb_unexpected_type(VALUE,int));
|
||||
|
|
67
numeric.c
67
numeric.c
|
@ -2581,10 +2581,9 @@ num_step_negative_p(VALUE num)
|
|||
}
|
||||
|
||||
static int
|
||||
num_step_scan_args(int argc, const VALUE *argv, VALUE *to, VALUE *step)
|
||||
num_step_extract_args(int argc, const VALUE *argv, VALUE *to, VALUE *step, VALUE *by)
|
||||
{
|
||||
VALUE hash;
|
||||
int desc;
|
||||
|
||||
argc = rb_scan_args(argc, argv, "02:", to, step, &hash);
|
||||
if (!NIL_P(hash)) {
|
||||
|
@ -2599,28 +2598,47 @@ num_step_scan_args(int argc, const VALUE *argv, VALUE *to, VALUE *step)
|
|||
}
|
||||
if (values[1] != Qundef) {
|
||||
if (argc > 1) rb_raise(rb_eArgError, "step is given twice");
|
||||
*step = values[1];
|
||||
*by = values[1];
|
||||
}
|
||||
}
|
||||
|
||||
return argc;
|
||||
}
|
||||
|
||||
static int
|
||||
num_step_check_fix_args(int argc, VALUE *to, VALUE *step, VALUE by, int fix_nil, int allow_zero_step)
|
||||
{
|
||||
int desc;
|
||||
if (by != Qundef) {
|
||||
*step = by;
|
||||
}
|
||||
else {
|
||||
/* compatibility */
|
||||
if (argc > 1 && NIL_P(*step)) {
|
||||
rb_raise(rb_eTypeError, "step must be numeric");
|
||||
}
|
||||
if (rb_equal(*step, INT2FIX(0))) {
|
||||
rb_raise(rb_eArgError, "step can't be 0");
|
||||
}
|
||||
/* compatibility */
|
||||
if (argc > 1 && NIL_P(*step)) {
|
||||
rb_raise(rb_eTypeError, "step must be numeric");
|
||||
}
|
||||
if (!allow_zero_step && rb_equal(*step, INT2FIX(0))) {
|
||||
rb_raise(rb_eArgError, "step can't be 0");
|
||||
}
|
||||
}
|
||||
if (NIL_P(*step)) {
|
||||
*step = INT2FIX(1);
|
||||
}
|
||||
desc = num_step_negative_p(*step);
|
||||
if (NIL_P(*to)) {
|
||||
*to = desc ? DBL2NUM(-HUGE_VAL) : DBL2NUM(HUGE_VAL);
|
||||
if (fix_nil && NIL_P(*to)) {
|
||||
*to = desc ? DBL2NUM(-HUGE_VAL) : DBL2NUM(HUGE_VAL);
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
static int
|
||||
num_step_scan_args(int argc, const VALUE *argv, VALUE *to, VALUE *step, int fix_nil, int allow_zero_step)
|
||||
{
|
||||
VALUE by = Qundef;
|
||||
argc = num_step_extract_args(argc, argv, to, step, &by);
|
||||
return num_step_check_fix_args(argc, to, step, by, fix_nil, allow_zero_step);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
num_step_size(VALUE from, VALUE args, VALUE eobj)
|
||||
{
|
||||
|
@ -2628,7 +2646,7 @@ num_step_size(VALUE from, VALUE args, VALUE eobj)
|
|||
int argc = args ? RARRAY_LENINT(args) : 0;
|
||||
const VALUE *argv = args ? RARRAY_CONST_PTR(args) : 0;
|
||||
|
||||
num_step_scan_args(argc, argv, &to, &step);
|
||||
num_step_scan_args(argc, argv, &to, &step, TRUE, FALSE);
|
||||
|
||||
return ruby_num_interval_step_size(from, to, step, FALSE);
|
||||
}
|
||||
|
@ -2691,9 +2709,28 @@ num_step(int argc, VALUE *argv, VALUE from)
|
|||
VALUE to, step;
|
||||
int desc, inf;
|
||||
|
||||
RETURN_SIZED_ENUMERATOR(from, argc, argv, num_step_size);
|
||||
/* RETURN_SIZED_ENUMERATOR(from, argc, argv, num_step_size); */
|
||||
|
||||
desc = num_step_scan_args(argc, argv, &to, &step);
|
||||
if (!rb_block_given_p()) {
|
||||
VALUE by = Qundef;
|
||||
|
||||
num_step_extract_args(argc, argv, &to, &step, &by);
|
||||
if (by != Qundef) {
|
||||
step = by;
|
||||
}
|
||||
if (NIL_P(step)) {
|
||||
step = INT2FIX(1);
|
||||
}
|
||||
if ((NIL_P(to) || rb_obj_is_kind_of(to, rb_cNumeric)) &&
|
||||
rb_obj_is_kind_of(step, rb_cNumeric)) {
|
||||
return rb_arith_seq_new(from, ID2SYM(rb_frame_this_func()), argc, argv,
|
||||
num_step_size, from, to, step, FALSE);
|
||||
}
|
||||
|
||||
RETURN_SIZED_ENUMERATOR(from, argc, argv, num_step_size);
|
||||
}
|
||||
|
||||
desc = num_step_scan_args(argc, argv, &to, &step, TRUE, FALSE);
|
||||
if (rb_equal(step, INT2FIX(0))) {
|
||||
inf = 1;
|
||||
}
|
||||
|
|
18
range.c
18
range.c
|
@ -388,18 +388,26 @@ range_step(int argc, VALUE *argv, VALUE range)
|
|||
{
|
||||
VALUE b, e, step, tmp;
|
||||
|
||||
RETURN_SIZED_ENUMERATOR(range, argc, argv, range_step_size);
|
||||
|
||||
b = RANGE_BEG(range);
|
||||
e = RANGE_END(range);
|
||||
if (argc == 0) {
|
||||
step = INT2FIX(1);
|
||||
step = INT2FIX(1);
|
||||
}
|
||||
else {
|
||||
rb_scan_args(argc, argv, "01", &step);
|
||||
step = check_step_domain(step);
|
||||
rb_scan_args(argc, argv, "01", &step);
|
||||
}
|
||||
|
||||
if (!rb_block_given_p()) {
|
||||
if (rb_obj_is_kind_of(b, rb_cNumeric) && (NIL_P(e) || rb_obj_is_kind_of(e, rb_cNumeric))) {
|
||||
return rb_arith_seq_new(range, ID2SYM(rb_frame_this_func()), argc, argv,
|
||||
range_step_size, b, e, step, EXCL(range));
|
||||
}
|
||||
|
||||
RETURN_SIZED_ENUMERATOR(range, argc, argv, range_step_size);
|
||||
}
|
||||
|
||||
step = check_step_domain(step);
|
||||
|
||||
if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(step)) {
|
||||
long i = FIX2LONG(b), unit = FIX2LONG(step);
|
||||
do {
|
||||
|
|
|
@ -259,15 +259,15 @@ describe :numeric_step, :shared => true do
|
|||
|
||||
describe "when no block is given" do
|
||||
it "returns an Enumerator when step is 0" do
|
||||
1.send(@method, *@step_args.call(2, 0)).should be_an_instance_of(Enumerator)
|
||||
1.send(@method, *@step_args.call(2, 0)).should be_an_instance_of(Enumerator::ArithmeticSequence)
|
||||
end
|
||||
|
||||
it "returns an Enumerator when not passed a block and self > stop" do
|
||||
1.send(@method, *@step_args.call(0, 2)).should be_an_instance_of(Enumerator)
|
||||
1.send(@method, *@step_args.call(0, 2)).should be_an_instance_of(Enumerator::ArithmeticSequence)
|
||||
end
|
||||
|
||||
it "returns an Enumerator when not passed a block and self < stop" do
|
||||
1.send(@method, *@step_args.call(2, 3)).should be_an_instance_of(Enumerator)
|
||||
1.send(@method, *@step_args.call(2, 3)).should be_an_instance_of(Enumerator::ArithmeticSequence)
|
||||
end
|
||||
|
||||
it "returns an Enumerator that uses the given step" do
|
||||
|
|
|
@ -23,23 +23,23 @@ describe "Numeric#step" do
|
|||
|
||||
describe "when no block is given" do
|
||||
it "returns an Enumerator when step is 0" do
|
||||
1.step(5, 0).should be_an_instance_of(Enumerator)
|
||||
1.step(5, 0).should be_an_instance_of(Enumerator::ArithmeticSequence)
|
||||
end
|
||||
|
||||
it "returns an Enumerator when step is 0.0" do
|
||||
1.step(2, 0.0).should be_an_instance_of(Enumerator)
|
||||
1.step(2, 0.0).should be_an_instance_of(Enumerator::ArithmeticSequence)
|
||||
end
|
||||
|
||||
describe "returned Enumerator" do
|
||||
describe "size" do
|
||||
it "raises an ArgumentError when step is 0" do
|
||||
enum = 1.step(5, 0)
|
||||
lambda { enum.size }.should raise_error(ArgumentError)
|
||||
enum.size.should == Float::INFINITY
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when step is 0.0" do
|
||||
enum = 1.step(2, 0.0)
|
||||
lambda { enum.size }.should raise_error(ArgumentError)
|
||||
enum.size.should == Float::INFINITY
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,9 +5,9 @@ describe "Range#step" do
|
|||
ScratchPad.record []
|
||||
end
|
||||
|
||||
it "returns an enumerator when no block is given" do
|
||||
it "returns an arithmetic sequence when no block is given" do
|
||||
enum = (1..10).step(4)
|
||||
enum.should be_an_instance_of(Enumerator)
|
||||
enum.should be_an_instance_of(Enumerator::ArithmeticSequence)
|
||||
enum.to_a.should eql([1, 5, 9])
|
||||
end
|
||||
|
||||
|
@ -263,7 +263,7 @@ describe "Range#step" do
|
|||
end
|
||||
|
||||
describe "when no block is given" do
|
||||
describe "returned Enumerator" do
|
||||
describe "returned Enumerator::ArithmeticSequence" do
|
||||
describe "size" do
|
||||
it "raises a TypeError if step does not respond to #to_int" do
|
||||
obj = mock("Range#step non-integer")
|
||||
|
@ -279,19 +279,9 @@ describe "Range#step" do
|
|||
lambda { enum.size }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError if step is 0" do
|
||||
enum = (-1..1).step(0)
|
||||
lambda { enum.size }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError if step is 0.0" do
|
||||
enum = (-1..1).step(0.0)
|
||||
lambda { enum.size }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError if step is negative" do
|
||||
enum = (-1..1).step(-2)
|
||||
lambda { enum.size }.should raise_error(ArgumentError)
|
||||
it "returns Float::INFINITY for zero step" do
|
||||
(-1..1).step(0).size.should == Float::INFINITY
|
||||
(-1..1).step(0.0).size.should == Float::INFINITY
|
||||
end
|
||||
|
||||
it "returns the ceil of range size divided by the number of steps" do
|
||||
|
@ -307,6 +297,11 @@ describe "Range#step" do
|
|||
(-5...5).step(2).size.should == 5
|
||||
end
|
||||
|
||||
it "returns the ceil of range size divided by the number of steps even if step is negative" do
|
||||
(-1..1).step(-1).size.should == 0
|
||||
(1..-1).step(-1).size.should == 3
|
||||
end
|
||||
|
||||
it "returns the correct number of steps when one of the arguments is a float" do
|
||||
(-1..1.0).step(0.5).size.should == 5
|
||||
(-1.0...1.0).step(0.5).size.should == 4
|
||||
|
|
367
test/ruby/test_arithmetic_sequence.rb
Normal file
367
test/ruby/test_arithmetic_sequence.rb
Normal file
|
@ -0,0 +1,367 @@
|
|||
# frozen_string_literal: false
|
||||
require 'test/unit'
|
||||
|
||||
class TestArithmeticSequence < Test::Unit::TestCase
|
||||
def test_begin
|
||||
assert_equal(1, 1.step.begin)
|
||||
assert_equal(1, 1.step(10).begin)
|
||||
assert_equal(1, 1.step(to: 10).begin)
|
||||
assert_equal(1, 1.step(nil).begin)
|
||||
assert_equal(1, 1.step(to: nil).begin)
|
||||
assert_equal(1, 1.step(by: 2).begin)
|
||||
assert_equal(1, 1.step(by: -1).begin)
|
||||
assert_equal(1, 1.step(by: nil).begin)
|
||||
assert_equal(1, 1.step(10, 2).begin)
|
||||
assert_equal(1, 1.step(10, by: 2).begin)
|
||||
assert_equal(1, 1.step(to: 10, by: 2).begin)
|
||||
assert_equal(10, 10.step(to: 1, by: -1).begin)
|
||||
assert_equal(10, 10.step(to: 1, by: -2).begin)
|
||||
assert_equal(10, 10.step(to: -1, by: -2).begin)
|
||||
assert_equal(10.0, 10.0.step(to: -1.0, by: -2.0).begin)
|
||||
end
|
||||
|
||||
def test_end
|
||||
assert_equal(nil, 1.step.end)
|
||||
assert_equal(10, 1.step(10).end)
|
||||
assert_equal(10, 1.step(to: 10).end)
|
||||
assert_equal(nil, 1.step(nil).end)
|
||||
assert_equal(nil, 1.step(to: nil).end)
|
||||
assert_equal(nil, 1.step(by: 2).end)
|
||||
assert_equal(nil, 1.step(by: -1).end)
|
||||
assert_equal(nil, 1.step(by: nil).end)
|
||||
assert_equal(10, 1.step(10, 2).end)
|
||||
assert_equal(10, 1.step(10, by: 2).end)
|
||||
assert_equal(10, 1.step(to: 10, by: 2).end)
|
||||
assert_equal(1, 10.step(to: 1, by: -1).end)
|
||||
assert_equal(1, 10.step(to: 1, by: -2).end)
|
||||
assert_equal(-1, 10.step(to: -1, by: -2).end)
|
||||
assert_equal(-1.0, 10.0.step(to: -1.0, by: -2.0).end)
|
||||
end
|
||||
|
||||
def test_exclude_end_p
|
||||
assert_equal(false, 1.step.exclude_end?)
|
||||
assert_equal(false, 1.step(10).exclude_end?)
|
||||
assert_equal(false, 1.step(to: 10).exclude_end?)
|
||||
assert_equal(false, 1.step(nil).exclude_end?)
|
||||
assert_equal(false, 1.step(to: nil).exclude_end?)
|
||||
assert_equal(false, 1.step(by: 2).exclude_end?)
|
||||
assert_equal(false, 1.step(by: -1).exclude_end?)
|
||||
assert_equal(false, 1.step(by: nil).exclude_end?)
|
||||
assert_equal(false, 1.step(10, 2).exclude_end?)
|
||||
assert_equal(false, 1.step(10, by: 2).exclude_end?)
|
||||
assert_equal(false, 1.step(to: 10, by: 2).exclude_end?)
|
||||
assert_equal(false, 10.step(to: 1, by: -1).exclude_end?)
|
||||
assert_equal(false, 10.step(to: 1, by: -2).exclude_end?)
|
||||
assert_equal(false, 10.step(to: -1, by: -2).exclude_end?)
|
||||
end
|
||||
|
||||
def test_step
|
||||
assert_equal(1, 1.step.step)
|
||||
assert_equal(1, 1.step(10).step)
|
||||
assert_equal(1, 1.step(to: 10).step)
|
||||
assert_equal(1, 1.step(nil).step)
|
||||
assert_equal(1, 1.step(to: nil).step)
|
||||
assert_equal(2, 1.step(by: 2).step)
|
||||
assert_equal(-1, 1.step(by: -1).step)
|
||||
assert_equal(1, 1.step(by: nil).step)
|
||||
assert_equal(2, 1.step(10, 2).step)
|
||||
assert_equal(2, 1.step(10, by: 2).step)
|
||||
assert_equal(2, 1.step(to: 10, by: 2).step)
|
||||
assert_equal(-1, 10.step(to: 1, by: -1).step)
|
||||
assert_equal(-2, 10.step(to: 1, by: -2).step)
|
||||
assert_equal(-2, 10.step(to: -1, by: -2).step)
|
||||
assert_equal(-2.0, 10.0.step(to: -1.0, by: -2.0).step)
|
||||
end
|
||||
|
||||
def test_eq
|
||||
seq = 1.step
|
||||
assert_equal(seq, seq)
|
||||
assert_equal(seq, 1.step)
|
||||
assert_equal(seq, 1.step(nil))
|
||||
end
|
||||
|
||||
def test_eqq
|
||||
seq = 1.step
|
||||
assert_operator(seq, :===, seq)
|
||||
assert_operator(seq, :===, 1.step)
|
||||
assert_operator(seq, :===, 1.step(nil))
|
||||
end
|
||||
|
||||
def test_eql_p
|
||||
seq = 1.step
|
||||
assert_operator(seq, :eql?, seq)
|
||||
assert_operator(seq, :eql?, 1.step)
|
||||
assert_operator(seq, :eql?, 1.step(nil))
|
||||
end
|
||||
|
||||
def test_hash
|
||||
seq = 1.step
|
||||
assert_equal(seq.hash, seq.hash)
|
||||
assert_equal(seq.hash, 1.step.hash)
|
||||
assert_equal(seq.hash, 1.step(nil).hash)
|
||||
end
|
||||
|
||||
def test_first
|
||||
seq = 1.step
|
||||
assert_equal(1, seq.first)
|
||||
assert_equal([1], seq.first(1))
|
||||
assert_equal([1, 2, 3], seq.first(3))
|
||||
|
||||
seq = 1.step(by: 2)
|
||||
assert_equal(1, seq.first)
|
||||
assert_equal([1], seq.first(1))
|
||||
assert_equal([1, 3, 5], seq.first(3))
|
||||
|
||||
seq = 10.step(by: -2)
|
||||
assert_equal(10, seq.first)
|
||||
assert_equal([10], seq.first(1))
|
||||
assert_equal([10, 8, 6], seq.first(3))
|
||||
|
||||
seq = 1.step(by: 4)
|
||||
assert_equal([1, 5, 9], seq.first(3))
|
||||
|
||||
seq = 1.step(10, by: 4)
|
||||
assert_equal([1, 5, 9], seq.first(5))
|
||||
|
||||
seq = 1.step(0)
|
||||
assert_equal(nil, seq.first)
|
||||
assert_equal([], seq.first(1))
|
||||
assert_equal([], seq.first(3))
|
||||
|
||||
seq = 1.step(10, by: -1)
|
||||
assert_equal(nil, seq.first)
|
||||
assert_equal([], seq.first(1))
|
||||
assert_equal([], seq.first(3))
|
||||
|
||||
seq = 10.0.step(-1.0, by: -2.0)
|
||||
assert_equal(10.0, seq.first)
|
||||
assert_equal([10.0], seq.first(1))
|
||||
assert_equal([10.0, 8.0, 6.0], seq.first(3))
|
||||
end
|
||||
|
||||
def test_last
|
||||
seq = 1.step(10)
|
||||
assert_equal(10, seq.last)
|
||||
assert_equal([10], seq.last(1))
|
||||
assert_equal([8, 9, 10], seq.last(3))
|
||||
|
||||
seq = 1.step(10, 2)
|
||||
assert_equal(9, seq.last)
|
||||
assert_equal([9], seq.last(1))
|
||||
assert_equal([5, 7, 9], seq.last(3))
|
||||
|
||||
seq = 10.step(1, -2)
|
||||
assert_equal(2, seq.last)
|
||||
assert_equal([2], seq.last(1))
|
||||
assert_equal([6, 4, 2], seq.last(3))
|
||||
|
||||
seq = 10.step(-1, -2)
|
||||
assert_equal(0, seq.last)
|
||||
|
||||
seq = 1.step(10, 4)
|
||||
assert_equal([1, 5, 9], seq.last(5))
|
||||
|
||||
seq = 10.step(1)
|
||||
assert_equal(nil, seq.last)
|
||||
assert_equal([], seq.last(1))
|
||||
assert_equal([], seq.last(5))
|
||||
|
||||
seq = 1.step(10, -1)
|
||||
assert_equal(nil, seq.last)
|
||||
assert_equal([], seq.last(1))
|
||||
assert_equal([], seq.last(5))
|
||||
|
||||
seq = (1..10).step
|
||||
assert_equal(10, seq.last)
|
||||
assert_equal([10], seq.last(1))
|
||||
assert_equal([8, 9, 10], seq.last(3))
|
||||
|
||||
seq = (1...10).step
|
||||
assert_equal(9, seq.last)
|
||||
assert_equal([9], seq.last(1))
|
||||
assert_equal([7, 8, 9], seq.last(3))
|
||||
|
||||
seq = 10.0.step(-3.0, by: -2.0)
|
||||
assert_equal(-2.0, seq.last)
|
||||
assert_equal([-2.0], seq.last(1))
|
||||
assert_equal([2.0, 0.0, -2.0], seq.last(3))
|
||||
end
|
||||
|
||||
def test_to_a
|
||||
assert_equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 1.step(10).to_a)
|
||||
assert_equal([1, 3, 5, 7, 9], 1.step(10, 2).to_a)
|
||||
assert_equal([1, 3, 5, 7, 9], (1..10).step(2).to_a)
|
||||
assert_equal([10, 8, 6, 4, 2], 10.step(1, by: -2).to_a)
|
||||
assert_equal([10, 8, 6, 4, 2], (10..1).step(-2).to_a)
|
||||
assert_equal([10.0, 8.0, 6.0, 4.0, 2.0], (10.0..1.0).step(-2.0).to_a)
|
||||
end
|
||||
|
||||
def test_slice
|
||||
seq = 1.step(10, 2)
|
||||
assert_equal([[1, 3, 5], [7, 9]], seq.each_slice(3).to_a)
|
||||
|
||||
seq = 10.step(1, -2)
|
||||
assert_equal([[10, 8, 6], [4, 2]], seq.each_slice(3).to_a)
|
||||
end
|
||||
|
||||
def test_cons
|
||||
seq = 1.step(10, 2)
|
||||
assert_equal([[1, 3, 5], [3, 5, 7], [5, 7, 9]], seq.each_cons(3).to_a)
|
||||
|
||||
seq = 10.step(1, -2)
|
||||
assert_equal([[10, 8, 6], [8, 6, 4], [6, 4, 2]], seq.each_cons(3).to_a)
|
||||
end
|
||||
|
||||
def test_with_index
|
||||
seq = 1.step(6, 2)
|
||||
assert_equal([[1, 0], [3, 1], [5, 2]], seq.with_index.to_a)
|
||||
assert_equal([[1, 10], [3, 11], [5, 12]], seq.with_index(10).to_a)
|
||||
|
||||
seq = 10.step(5, -2)
|
||||
assert_equal([[10, 0], [8, 1], [6, 2]], seq.with_index.to_a)
|
||||
assert_equal([[10, 10], [8, 11], [6, 12]], seq.with_index(10).to_a)
|
||||
end
|
||||
|
||||
def test_with_object
|
||||
obj = [0, 1]
|
||||
seq = 1.step(10, 2)
|
||||
ret = seq.each_with_object(obj) do |i, memo|
|
||||
memo[0] += i
|
||||
memo[1] *= i
|
||||
end
|
||||
assert_same(obj, ret)
|
||||
assert_equal([25, 945], ret)
|
||||
|
||||
obj = [0, 1]
|
||||
seq = 10.step(1, -2)
|
||||
ret = seq.each_with_object(obj) do |i, memo|
|
||||
memo[0] += i
|
||||
memo[1] *= i
|
||||
end
|
||||
assert_same(obj, ret)
|
||||
assert_equal([30, 3840], ret)
|
||||
end
|
||||
|
||||
def test_next
|
||||
seq = 1.step(10, 2)
|
||||
[1, 3, 5, 7, 9].each do |i|
|
||||
assert_equal(i, seq.next)
|
||||
end
|
||||
|
||||
seq = 10.step(1, -2)
|
||||
[10, 8, 6, 4, 2].each do |i|
|
||||
assert_equal(i, seq.next)
|
||||
end
|
||||
end
|
||||
|
||||
def test_next_rewind
|
||||
seq = 1.step(6, 2)
|
||||
assert_equal(1, seq.next)
|
||||
assert_equal(3, seq.next)
|
||||
seq.rewind
|
||||
assert_equal(1, seq.next)
|
||||
assert_equal(3, seq.next)
|
||||
assert_equal(5, seq.next)
|
||||
assert_raise(StopIteration) { seq.next }
|
||||
|
||||
seq = 10.step(5, -2)
|
||||
assert_equal(10, seq.next)
|
||||
assert_equal(8, seq.next)
|
||||
seq.rewind
|
||||
assert_equal(10, seq.next)
|
||||
assert_equal(8, seq.next)
|
||||
assert_equal(6, seq.next)
|
||||
assert_raise(StopIteration) { seq.next }
|
||||
end
|
||||
|
||||
def test_next_after_stopiteration
|
||||
seq = 1.step(2, 2)
|
||||
assert_equal(1, seq.next)
|
||||
assert_raise(StopIteration) { seq.next }
|
||||
assert_raise(StopIteration) { seq.next }
|
||||
seq.rewind
|
||||
assert_equal(1, seq.next)
|
||||
assert_raise(StopIteration) { seq.next }
|
||||
assert_raise(StopIteration) { seq.next }
|
||||
end
|
||||
|
||||
def test_stop_result
|
||||
seq = 1.step(2, 2)
|
||||
res = seq.each {}
|
||||
assert_equal(1, seq.next)
|
||||
exc = assert_raise(StopIteration) { seq.next }
|
||||
assert_equal(res, exc.result)
|
||||
end
|
||||
|
||||
def test_peek
|
||||
seq = 1.step(2, 2)
|
||||
assert_equal(1, seq.peek)
|
||||
assert_equal(1, seq.peek)
|
||||
assert_equal(1, seq.next)
|
||||
assert_raise(StopIteration) { seq.peek }
|
||||
assert_raise(StopIteration) { seq.peek }
|
||||
|
||||
seq = 10.step(9, -2)
|
||||
assert_equal(10, seq.peek)
|
||||
assert_equal(10, seq.peek)
|
||||
assert_equal(10, seq.next)
|
||||
assert_raise(StopIteration) { seq.peek }
|
||||
assert_raise(StopIteration) { seq.peek }
|
||||
end
|
||||
|
||||
def test_next_values
|
||||
seq = 1.step(2, 2)
|
||||
assert_equal([1], seq.next_values)
|
||||
end
|
||||
|
||||
def test_peek_values
|
||||
seq = 1.step(2, 2)
|
||||
assert_equal([1], seq.peek_values)
|
||||
end
|
||||
|
||||
def test_num_step_inspect
|
||||
assert_equal('(1.step)', 1.step.inspect)
|
||||
assert_equal('(1.step(10))', 1.step(10).inspect)
|
||||
assert_equal('(1.step(10, 2))', 1.step(10, 2).inspect)
|
||||
assert_equal('(1.step(10, by: 2))', 1.step(10, by: 2).inspect)
|
||||
assert_equal('(1.step(by: 2))', 1.step(by: 2).inspect)
|
||||
end
|
||||
|
||||
def test_range_step_inspect
|
||||
assert_equal('((1..).step)', (1..).step.inspect)
|
||||
assert_equal('((1..10).step)', (1..10).step.inspect)
|
||||
assert_equal('((1..10).step(2))', (1..10).step(2).inspect)
|
||||
end
|
||||
|
||||
def test_num_step_size
|
||||
assert_equal(10, 1.step(10).size)
|
||||
assert_equal(5, 1.step(10, 2).size)
|
||||
assert_equal(4, 1.step(10, 3).size)
|
||||
assert_equal(1, 1.step(10, 10).size)
|
||||
assert_equal(0, 1.step(0).size)
|
||||
assert_equal(Float::INFINITY, 1.step.size)
|
||||
|
||||
assert_equal(10, 10.step(1, -1).size)
|
||||
assert_equal(5, 10.step(1, -2).size)
|
||||
assert_equal(4, 10.step(1, -3).size)
|
||||
assert_equal(1, 10.step(1, -10).size)
|
||||
assert_equal(0, 1.step(2, -1).size)
|
||||
assert_equal(Float::INFINITY, 1.step(by: -1).size)
|
||||
end
|
||||
|
||||
def test_range_step_size
|
||||
assert_equal(10, (1..10).step.size)
|
||||
assert_equal(9, (1...10).step.size)
|
||||
assert_equal(5, (1..10).step(2).size)
|
||||
assert_equal(5, (1...10).step(2).size)
|
||||
assert_equal(4, (1...9).step(2).size)
|
||||
assert_equal(Float::INFINITY, (1..).step.size)
|
||||
|
||||
assert_equal(10, (10..1).step(-1).size)
|
||||
assert_equal(9, (10...1).step(-1).size)
|
||||
assert_equal(5, (10..1).step(-2).size)
|
||||
assert_equal(5, (10...1).step(-2).size)
|
||||
assert_equal(4, (10...2).step(-2).size)
|
||||
assert_equal(Float::INFINITY, (1..).step(-1).size)
|
||||
end
|
||||
end
|
|
@ -632,7 +632,7 @@ class TestEnumerator < Test::Unit::TestCase
|
|||
assert_equal 4, (1..10).step(3).size
|
||||
assert_equal 3, (1...10).step(3).size
|
||||
assert_equal Float::INFINITY, (42..Float::INFINITY).step(2).size
|
||||
assert_raise(ArgumentError){ (1..10).step(-2).size }
|
||||
assert_equal 0, (1..10).step(-2).size
|
||||
end
|
||||
|
||||
def test_size_for_downup_to
|
||||
|
|
|
@ -260,11 +260,11 @@ class TestNumeric < Test::Unit::TestCase
|
|||
assert_raise(ArgumentError) { 1.step(10, 1, 0) { } }
|
||||
assert_raise(ArgumentError) { 1.step(10, 1, 0).size }
|
||||
assert_raise(ArgumentError) { 1.step(10, 0) { } }
|
||||
assert_raise(ArgumentError) { 1.step(10, 0).size }
|
||||
assert_raise(ArgumentError) { 1.step(10, "1") { } }
|
||||
assert_raise(ArgumentError) { 1.step(10, "1").size }
|
||||
assert_raise(TypeError) { 1.step(10, nil) { } }
|
||||
assert_raise(TypeError) { 1.step(10, nil).size }
|
||||
assert_nothing_raised { 1.step(10, 0).size }
|
||||
assert_nothing_raised { 1.step(10, nil).size }
|
||||
assert_nothing_raised { 1.step(by: 0, to: nil) }
|
||||
assert_nothing_raised { 1.step(by: 0, to: nil).size }
|
||||
assert_nothing_raised { 1.step(by: 0) }
|
||||
|
@ -272,6 +272,14 @@ class TestNumeric < Test::Unit::TestCase
|
|||
assert_nothing_raised { 1.step(by: nil) }
|
||||
assert_nothing_raised { 1.step(by: nil).size }
|
||||
|
||||
assert_kind_of(Enumerator::ArithmeticSequence, 1.step(10))
|
||||
assert_kind_of(Enumerator::ArithmeticSequence, 1.step(10, 2))
|
||||
assert_kind_of(Enumerator::ArithmeticSequence, 1.step(10, by: 2))
|
||||
assert_kind_of(Enumerator::ArithmeticSequence, 1.step(by: 2))
|
||||
assert_kind_of(Enumerator::ArithmeticSequence, 1.step(by: 2, to: nil))
|
||||
assert_kind_of(Enumerator::ArithmeticSequence, 1.step(by: 2, to: 10))
|
||||
assert_kind_of(Enumerator::ArithmeticSequence, 1.step(by: -1))
|
||||
|
||||
bug9811 = '[ruby-dev:48177] [Bug #9811]'
|
||||
assert_raise(ArgumentError, bug9811) { 1.step(10, foo: nil) {} }
|
||||
assert_raise(ArgumentError, bug9811) { 1.step(10, foo: nil).size }
|
||||
|
|
|
@ -222,7 +222,11 @@ class TestRange < Test::Unit::TestCase
|
|||
(0..).step(2) {|x| a << x; break if a.size == 10 }
|
||||
assert_equal([0, 2, 4, 6, 8, 10, 12, 14, 16, 18], a)
|
||||
|
||||
assert_raise(ArgumentError) { (0..10).step(-1) { } }
|
||||
assert_kind_of(Enumerator::ArithmeticSequence, (0..10).step)
|
||||
assert_kind_of(Enumerator::ArithmeticSequence, (0..10).step(2))
|
||||
assert_kind_of(Enumerator::ArithmeticSequence, (0..10).step(0.5))
|
||||
assert_kind_of(Enumerator::ArithmeticSequence, (10..0).step(-1))
|
||||
|
||||
assert_raise(ArgumentError) { (0..10).step(0) { } }
|
||||
assert_raise(ArgumentError) { (0..).step(-1) { } }
|
||||
assert_raise(ArgumentError) { (0..).step(0) { } }
|
||||
|
|
Loading…
Reference in a new issue