Beispiel #1
0
/*
 * call-seq:
 *   Enumerator.new(size = nil) { |yielder| ... }
 *   Enumerator.new(obj, method = :each, *args)
 *
 * Creates a new Enumerator object, which can be used as an
 * Enumerable.
 *
 * In the first form, iteration is defined by the given block, in
 * which a "yielder" object, given as block parameter, can be used to
 * yield a value by calling the +yield+ method (aliased as +<<+):
 *
 *   fib = Enumerator.new do |y|
 *     a = b = 1
 *     loop do
 *       y << a
 *       a, b = b, a + b
 *     end
 *   end
 *
 *   p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
 *
 * The optional parameter can be used to specify how to calculate the size
 * in a lazy fashion (see Enumerator#size). It can either be a value or
 * a callable object.
 *
 * In the second, deprecated, form, a generated Enumerator iterates over the
 * given object using the given method with the given arguments passed.
 *
 * Use of this form is discouraged.  Use Kernel#enum_for or Kernel#to_enum
 * instead.
 *
 *   e = Enumerator.new(ObjectSpace, :each_object)
 *       #-> ObjectSpace.enum_for(:each_object)
 *
 *   e.select { |obj| obj.is_a?(Class) }  #=> array of all classes
 *
 */
static VALUE
enumerator_initialize(int argc, VALUE *argv, VALUE obj)
{
    VALUE recv, meth = sym_each;
    VALUE size = Qnil;

    if (rb_block_given_p()) {
	rb_check_arity(argc, 0, 1);
	recv = generator_init(generator_allocate(rb_cGenerator), rb_block_proc());
	if (argc) {
            if (NIL_P(argv[0]) || rb_obj_is_proc(argv[0]) ||
                (RB_TYPE_P(argv[0], T_FLOAT) && RFLOAT_VALUE(argv[0]) == INFINITY)) {
                size = argv[0];
            }
            else {
                size = rb_to_int(argv[0]);
            }
            argc = 0;
        }
    }
    else {
	rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
	rb_warn("Enumerator.new without a block is deprecated; use Object#to_enum");
	recv = *argv++;
	if (--argc) {
	    meth = *argv++;
	    --argc;
	}
    }

    return enumerator_init(obj, recv, meth, argc, argv, 0, size);
}
Beispiel #2
0
static VALUE
lazy_initialize(int argc, VALUE *argv, VALUE self)
{
    VALUE obj, meth;
    VALUE generator;
    int offset;

    if (argc < 1) {
	rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..)", argc);
    }
    else {
	obj = argv[0];
	if (argc == 1) {
	    meth = sym_each;
	    offset = 1;
	}
	else {
	    meth = argv[1];
	    offset = 2;
	}
    }
    generator = generator_allocate(rb_cGenerator);
    rb_block_call(generator, id_initialize, 0, 0,
		  (rb_block_given_p() ? lazy_init_block_i : lazy_init_block),
		  obj);
    enumerator_init(self, generator, meth, argc - offset, argv + offset);
    rb_ivar_set(self, id_receiver, obj);

    return self;
}
Beispiel #3
0
/*
 *  call-seq:
 *    Enumerator.new(obj, method = :each, *args)
 *    Enumerator.new { |y| ... }
 *
 *  Creates a new Enumerator object, which is to be used as an
 *  Enumerable object iterating in a given way.
 *
 *  In the first form, a generated Enumerator iterates over the given
 *  object using the given method with the given arguments passed.
 *  Use of this form is discouraged.  Use Kernel#enum_for(), alias
 *  to_enum, instead.
 *
 *    e = Enumerator.new(ObjectSpace, :each_object)
 *        #-> ObjectSpace.enum_for(:each_object)
 *
 *    e.select { |obj| obj.is_a?(Class) }  #=> array of all classes
 *
 *  In the second form, iteration is defined by the given block, in
 *  which a "yielder" object given as block parameter can be used to
 *  yield a value by calling the +yield+ method, alias +<<+.
 *
 *    fib = Enumerator.new { |y|
 *      a = b = 1
 *      loop {
 *        y << a
 *        a, b = b, a + b
 *      }
 *    }
 *
 *    p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
 */
static VALUE
enumerator_initialize(int argc, VALUE *argv, VALUE obj)
{
    VALUE recv, meth = sym_each;

    if (argc == 0) {
        if (!rb_block_given_p())
            rb_raise(rb_eArgError, "wrong number of argument (0 for 1+)");

        recv = generator_init(generator_allocate(rb_cGenerator), rb_block_proc());
    } else {
        recv = *argv++;
        if (--argc) {
            meth = *argv++;
            --argc;
        }
    }

    return enumerator_init(obj, recv, meth, argc, argv);
}
Beispiel #4
0
/*
 * call-seq:
 *   Lazy.new(obj, size=nil) { |yielder, *values| ... }
 *
 * Creates a new Lazy enumerator. When the enumerator is actually enumerated
 * (e.g. by calling #force), +obj+ will be enumerated and each value passed
 * to the given block. The block can yield values back using +yielder+.
 * For example, to create a method +filter_map+ in both lazy and
 * non-lazy fashions:
 *
 *   module Enumerable
 *     def filter_map(&block)
 *       map(&block).compact
 *     end
 *   end
 *
 *   class Enumerator::Lazy
 *     def filter_map
 *       Lazy.new(self) do |yielder, *values|
 *         result = yield *values
 *         yielder << result if result
 *       end
 *     end
 *   end
 *
 *   (1..Float::INFINITY).lazy.filter_map{|i| i*i if i.even?}.first(5)
 *       # => [4, 16, 36, 64, 100]
 */
static VALUE
lazy_initialize(int argc, VALUE *argv, VALUE self)
{
    VALUE obj, size = Qnil;
    VALUE generator;

    rb_check_arity(argc, 1, 2);
    if (!rb_block_given_p()) {
	rb_raise(rb_eArgError, "tried to call lazy new without a block");
    }
    obj = argv[0];
    if (argc > 1) {
	size = argv[1];
    }
    generator = generator_allocate(rb_cGenerator);
    rb_block_call(generator, id_initialize, 0, 0, lazy_init_block_i, obj);
    enumerator_init(self, generator, sym_each, 0, 0, 0, size);
    rb_ivar_set(self, id_receiver, obj);

    return self;
}
Beispiel #5
0
/*
 * call-seq:
 *   Enumerator.new { |yielder| ... }
 *   Enumerator.new(obj, method = :each, *args)
 *
 * Creates a new Enumerator object, which can be used as an
 * Enumerable.
 *
 * In the first form, iteration is defined by the given block, in
 * which a "yielder" object, given as block parameter, can be used to
 * yield a value by calling the +yield+ method (aliased as +<<+):
 *
 *   fib = Enumerator.new do |y|
 *     a = b = 1
 *     loop do
 *       y << a
 *       a, b = b, a + b
 *     end
 *   end
 *
 *   p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
 *
 * The block form can be used to create a lazy enumeration that only processes
 * elements as-needed.  The generic pattern for this is:
 *
 *    Enumerator.new do |yielder|
 *      source.each do |source_item|
 *        # process source_item and append the yielder
 *      end
 *    end
 *
 * This can be used with infinite streams to support multiple chains:
 *
 *   class Fib
 *     def initialize(a = 1, b = 1)
 *       @a, @b = a, b
 *     end
 *
 *     def each
 *       a, b = @a, @b
 *       yield a
 *       while true
 *         yield b
 *         a, b = b, a+b
 *       end
 *     end
 *   end
 *
 *   def lazy_select enum
 *     Enumerator.new do |y|
 *       enum.each do |e|
 *         y << e if yield e
 *       end
 *     end
 *   end
 *
 *   def lazy_map enum
 *     Enumerator.new do |y|
 *       enum.each do |e|
 *         y << yield(e)
 *       end
 *     end
 *   end
 *
 *   even_fibs   = lazy_select(Fibs.new) { |x| x % 2 == 0 }
 *   string_fibs = lazy_map(even_fibs)   { |x| "<#{x}>" }
 *   string_fibs.each_with_index do |fib, i|
 *     puts "#{i}: #{fib}"
 *     break if i >= 3
 *   end
 *
 * This allows output even though the Fib produces an infinite sequence of
 * Fibonacci numbers:
 *
 *   0: <2>
 *   1: <8>
 *   2: <34>
 *   3: <144>
 *
 * In the second, deprecated, form, a generated Enumerator iterates over the
 * given object using the given method with the given arguments passed.
 *
 * Use of this form is discouraged.  Use Kernel#enum_for or Kernel#to_enum
 * instead.
 *
 *   e = Enumerator.new(ObjectSpace, :each_object)
 *       #-> ObjectSpace.enum_for(:each_object)
 *
 *   e.select { |obj| obj.is_a?(Class) }  #=> array of all classes
 *
 */
static VALUE
enumerator_initialize(int argc, VALUE *argv, VALUE obj)
{
    VALUE recv, meth = sym_each;

    if (argc == 0) {
	if (!rb_block_given_p())
	    rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);

	recv = generator_init(generator_allocate(rb_cGenerator), rb_block_proc());
    }
    else {
	recv = *argv++;
	if (--argc) {
	    meth = *argv++;
	    --argc;
	}
    }

    return enumerator_init(obj, recv, meth, argc, argv);
}
Beispiel #6
0
/*
 *  call-seq:
 *    Enumerator.new(obj, method = :each, *args)
 *    Enumerator.new { |y| ... }
 *
 *  Creates a new Enumerator object, which is to be used as an
 *  Enumerable object iterating in a given way.
 *
 *  In the first form, a generated Enumerator iterates over the given
 *  object using the given method with the given arguments passed.
 *  Use of this form is discouraged.  Use Kernel#enum_for(), alias
 *  to_enum, instead.
 *
 *    e = Enumerator.new(ObjectSpace, :each_object)
 *        #-> ObjectSpace.enum_for(:each_object)
 *
 *    e.select { |obj| obj.is_a?(Class) }  #=> array of all classes
 *
 *  In the second form, iteration is defined by the given block, in
 *  which a "yielder" object given as block parameter can be used to
 *  yield a value by calling the +yield+ method, alias +<<+.
 *
 *    fib = Enumerator.new { |y|
 *      a = b = 1
 *      loop {
 *        y << a
 *        a, b = b, a + b
 *      }
 *    }
 *
 *    p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
 */
static VALUE
enumerator_initialize(VALUE obj, SEL sel, int argc, VALUE *argv)
{
    VALUE recv, meth = sym_each;

    if (argc == 0) {
	if (!rb_block_given_p())
	    rb_raise(rb_eArgError, "wrong number of argument (0 for 1+)");

	recv = generator_init(generator_allocate(rb_cGenerator, 0), rb_block_proc());
    }
    else {
	recv = *argv++;
	if (--argc) {
	    meth = *argv++;
	    --argc;
	}
    }

    ID meth_id = rb_to_id(meth);
    SEL meth_sel = rb_vm_id_to_sel(meth_id, argc);
    return enumerator_init(obj, recv, meth_sel, argc, argv);
}