Class: Enumerator::Lazy

Inherits:
Enumerator show all
Defined in:
enumerator.c

Instance Method Summary collapse

Methods inherited from Enumerator

#each, #each_with_index, #each_with_object, #feed, #initialize_copy, #inspect, #next, #next_values, #peek, #peek_values, #rewind, #size, #with_index, #with_object

Methods included from Enumerable

#all?, #any?, #count, #cycle, #detect, #each_cons, #each_entry, #each_slice, #each_with_index, #each_with_object, #entries, #find, #find_index, #first, #group_by, #include?, #inject, #max, #max_by, #member?, #min, #min_by, #minmax, #minmax_by, #none?, #one?, #partition, #reduce, #reverse_each, #sort, #sort_by, #to_a, #to_h

Constructor Details

#new(obj, size = nil) {|yielder, *values| ... } ⇒ Object

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]

Yields:

  • (yielder, *values)


1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
# File 'enumerator.c', line 1383

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;
}

Instance Method Details

#chunk(*args) ⇒ Object



1928
1929
1930
1931
1932
# File 'enumerator.c', line 1928

static VALUE
lazy_super(int argc, VALUE *argv, VALUE lazy)
{
    return enumerable_lazy(rb_call_super(argc, argv));
}

#collectObject



1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
# File 'enumerator.c', line 1517

static VALUE
lazy_map(VALUE obj)
{
    if (!rb_block_given_p()) {
	rb_raise(rb_eArgError, "tried to call lazy map without a block");
    }

    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
					 lazy_map_func, 0),
			   Qnil, lazy_receiver_size);
}

#collect_concat {|obj| ... } ⇒ Object #flat_map {|obj| ... } ⇒ Object

Returns a new lazy enumerator with the concatenated results of running block once for every element in lazy.

["foo", "bar"].lazy.flat_map {|i| i.each_char.lazy}.force
#=> ["f", "o", "o", "b", "a", "r"]

A value x returned by block is decomposed if either of the following conditions is true:

a) <i>x</i> responds to both each and force, which means that
   <i>x</i> is a lazy enumerator.
b) <i>x</i> is an array or responds to to_ary.

Otherwise, x is contained as-is in the return value.

[{a:1}, {b:2}].lazy.flat_map {|i| i}.force
#=> [{:a=>1}, {:b=>2}]

Overloads:

  • #collect_concat {|obj| ... } ⇒ Object

    Yields:

    • (obj)
  • #flat_map {|obj| ... } ⇒ Object

    Yields:

    • (obj)


1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
# File 'enumerator.c', line 1602

static VALUE
lazy_flat_map(VALUE obj)
{
    if (!rb_block_given_p()) {
	rb_raise(rb_eArgError, "tried to call lazy flat_map without a block");
    }

    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
					 lazy_flat_map_func, 0),
			   Qnil, 0);
}

#drop(n) ⇒ Object



1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
# File 'enumerator.c', line 1891

static VALUE
lazy_drop(VALUE obj, VALUE n)
{
    long len = NUM2LONG(n);

    if (len < 0) {
	rb_raise(rb_eArgError, "attempt to drop negative size");
    }
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
					 lazy_drop_func, n),
			   rb_ary_new3(1, n), lazy_drop_size);
}

#drop_whileObject



1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
# File 'enumerator.c', line 1917

static VALUE
lazy_drop_while(VALUE obj)
{
    if (!rb_block_given_p()) {
	rb_raise(rb_eArgError, "tried to call lazy drop_while without a block");
    }
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
					 lazy_drop_while_func, 0),
			   Qnil, 0);
}

#to_enum(method = :each, *args) ⇒ Object #enum_for(method = :each, *args) ⇒ Object #to_enum(method = :each, *args) {|*args| ... } ⇒ Object #enum_for(method = :each, *args) {|*args| ... } ⇒ Object

Similar to Kernel#to_enum, except it returns a lazy enumerator. This makes it easy to define Enumerable methods that will naturally remain lazy if called from a lazy enumerator.

For example, continuing from the example in Kernel#to_enum:

# See Kernel#to_enum for the definition of repeat
r = 1..Float::INFINITY
r.repeat(2).first(5) # => [1, 1, 2, 2, 3]
r.repeat(2).class # => Enumerator
r.repeat(2).map{|n| n ** 2}.first(5) # => endless loop!
# works naturally on lazy enumerator:
r.lazy.repeat(2).class # => Enumerator::Lazy
r.lazy.repeat(2).map{|n| n ** 2}.first(5) # => [1, 1, 4, 4, 9]

Overloads:

  • #to_enum(method = :each, *args) {|*args| ... } ⇒ Object

    Yields:

    • (*args)
  • #enum_for(method = :each, *args) {|*args| ... } ⇒ Object

    Yields:

    • (*args)


1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
# File 'enumerator.c', line 1492

static VALUE
lazy_to_enum(int argc, VALUE *argv, VALUE self)
{
    VALUE lazy, meth = sym_each;

    if (argc > 0) {
	--argc;
	meth = *argv++;
    }
    lazy = lazy_to_enum_i(self, meth, argc, argv, 0);
    if (rb_block_given_p()) {
	enumerator_ptr(lazy)->size = rb_block_proc();
    }
    return lazy;
}

#find_allObject



1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
# File 'enumerator.c', line 1625

static VALUE
lazy_select(VALUE obj)
{
    if (!rb_block_given_p()) {
	rb_raise(rb_eArgError, "tried to call lazy select without a block");
    }

    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
					 lazy_select_func, 0),
			   Qnil, 0);
}

#collect_concat {|obj| ... } ⇒ Object #flat_map {|obj| ... } ⇒ Object

Returns a new lazy enumerator with the concatenated results of running block once for every element in lazy.

["foo", "bar"].lazy.flat_map {|i| i.each_char.lazy}.force
#=> ["f", "o", "o", "b", "a", "r"]

A value x returned by block is decomposed if either of the following conditions is true:

a) <i>x</i> responds to both each and force, which means that
   <i>x</i> is a lazy enumerator.
b) <i>x</i> is an array or responds to to_ary.

Otherwise, x is contained as-is in the return value.

[{a:1}, {b:2}].lazy.flat_map {|i| i}.force
#=> [{:a=>1}, {:b=>2}]

Overloads:

  • #collect_concat {|obj| ... } ⇒ Object

    Yields:

    • (obj)
  • #flat_map {|obj| ... } ⇒ Object

    Yields:

    • (obj)


1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
# File 'enumerator.c', line 1602

static VALUE
lazy_flat_map(VALUE obj)
{
    if (!rb_block_given_p()) {
	rb_raise(rb_eArgError, "tried to call lazy flat_map without a block");
    }

    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
					 lazy_flat_map_func, 0),
			   Qnil, 0);
}

#grep(pattern) ⇒ Object



1684
1685
1686
1687
1688
1689
1690
1691
1692
# File 'enumerator.c', line 1684

static VALUE
lazy_grep(VALUE obj, VALUE pattern)
{
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
					 rb_block_given_p() ?
					 lazy_grep_iter : lazy_grep_func,
					 pattern),
			   rb_ary_new3(1, pattern), 0);
}

#lazyObject



1934
1935
1936
1937
1938
# File 'enumerator.c', line 1934

static VALUE
lazy_lazy(VALUE obj)
{
    return obj;
}

#mapObject



1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
# File 'enumerator.c', line 1517

static VALUE
lazy_map(VALUE obj)
{
    if (!rb_block_given_p()) {
	rb_raise(rb_eArgError, "tried to call lazy map without a block");
    }

    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
					 lazy_map_func, 0),
			   Qnil, lazy_receiver_size);
}

#rejectObject



1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
# File 'enumerator.c', line 1648

static VALUE
lazy_reject(VALUE obj)
{
    if (!rb_block_given_p()) {
	rb_raise(rb_eArgError, "tried to call lazy reject without a block");
    }

    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
					 lazy_reject_func, 0),
			   Qnil, 0);
}

#selectObject



1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
# File 'enumerator.c', line 1625

static VALUE
lazy_select(VALUE obj)
{
    if (!rb_block_given_p()) {
	rb_raise(rb_eArgError, "tried to call lazy select without a block");
    }

    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
					 lazy_select_func, 0),
			   Qnil, 0);
}

#slice_after(*args) ⇒ Object



1928
1929
1930
1931
1932
# File 'enumerator.c', line 1928

static VALUE
lazy_super(int argc, VALUE *argv, VALUE lazy)
{
    return enumerable_lazy(rb_call_super(argc, argv));
}

#slice_before(*args) ⇒ Object



1928
1929
1930
1931
1932
# File 'enumerator.c', line 1928

static VALUE
lazy_super(int argc, VALUE *argv, VALUE lazy)
{
    return enumerable_lazy(rb_call_super(argc, argv));
}

#slice_when(*args) ⇒ Object



1928
1929
1930
1931
1932
# File 'enumerator.c', line 1928

static VALUE
lazy_super(int argc, VALUE *argv, VALUE lazy)
{
    return enumerable_lazy(rb_call_super(argc, argv));
}

#take(n) ⇒ Object



1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
# File 'enumerator.c', line 1820

static VALUE
lazy_take(VALUE obj, VALUE n)
{
    long len = NUM2LONG(n);
    VALUE lazy;

    if (len < 0) {
	rb_raise(rb_eArgError, "attempt to take negative size");
    }
    if (len == 0) {
	VALUE len = INT2FIX(0);
	lazy = lazy_to_enum_i(obj, sym_cycle, 1, &len, 0);
    }
    else {
	lazy = rb_block_call(rb_cLazy, id_new, 1, &obj,
					 lazy_take_func, n);
    }
    return lazy_set_method(lazy, rb_ary_new3(1, n), lazy_take_size);
}

#take_whileObject



1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
# File 'enumerator.c', line 1849

static VALUE
lazy_take_while(VALUE obj)
{
    if (!rb_block_given_p()) {
	rb_raise(rb_eArgError, "tried to call lazy take_while without a block");
    }
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
					 lazy_take_while_func, 0),
			   Qnil, 0);
}

#to_enum(method = :each, *args) ⇒ Object #enum_for(method = :each, *args) ⇒ Object #to_enum(method = :each, *args) {|*args| ... } ⇒ Object #enum_for(method = :each, *args) {|*args| ... } ⇒ Object

Similar to Kernel#to_enum, except it returns a lazy enumerator. This makes it easy to define Enumerable methods that will naturally remain lazy if called from a lazy enumerator.

For example, continuing from the example in Kernel#to_enum:

# See Kernel#to_enum for the definition of repeat
r = 1..Float::INFINITY
r.repeat(2).first(5) # => [1, 1, 2, 2, 3]
r.repeat(2).class # => Enumerator
r.repeat(2).map{|n| n ** 2}.first(5) # => endless loop!
# works naturally on lazy enumerator:
r.lazy.repeat(2).class # => Enumerator::Lazy
r.lazy.repeat(2).map{|n| n ** 2}.first(5) # => [1, 1, 4, 4, 9]

Overloads:

  • #to_enum(method = :each, *args) {|*args| ... } ⇒ Object

    Yields:

    • (*args)
  • #enum_for(method = :each, *args) {|*args| ... } ⇒ Object

    Yields:

    • (*args)


1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
# File 'enumerator.c', line 1492

static VALUE
lazy_to_enum(int argc, VALUE *argv, VALUE self)
{
    VALUE lazy, meth = sym_each;

    if (argc > 0) {
	--argc;
	meth = *argv++;
    }
    lazy = lazy_to_enum_i(self, meth, argc, argv, 0);
    if (rb_block_given_p()) {
	enumerator_ptr(lazy)->size = rb_block_proc();
    }
    return lazy;
}

#zip(*args) ⇒ Object



1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
# File 'enumerator.c', line 1758

static VALUE
lazy_zip(int argc, VALUE *argv, VALUE obj)
{
    VALUE ary, v;
    long i;
    rb_block_call_func *func = lazy_zip_arrays_func;

    if (rb_block_given_p()) {
	return rb_call_super(argc, argv);
    }

    ary = rb_ary_new2(argc);
    for (i = 0; i < argc; i++) {
	v = rb_check_array_type(argv[i]);
	if (NIL_P(v)) {
	    for (; i < argc; i++) {
		if (!rb_respond_to(argv[i], id_each)) {
		    rb_raise(rb_eTypeError, "wrong argument type %s (must respond to :each)",
			rb_obj_classname(argv[i]));
		}
	    }
	    ary = rb_ary_new4(argc, argv);
	    func = lazy_zip_func;
	    break;
	}
	rb_ary_push(ary, v);
    }

    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
					 func, ary),
			   ary, lazy_receiver_size);
}