Forum: Ruby using Enumerable when each has arguments?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
6e296d1bf1f3d230bb12a15ce8b5fe9b?d=identicon&s=25 Erwin Abbott (Guest)
on 2007-05-21 12:42
(Received via mailing list)
Hi

I've written a number of classes which would benefit from the
Enumerable mixin, but my #each method requires arguments.  These are
usually to specify the range of values, like Fibonacci#each(first,
last) or whatever.  Since Enumerable's #map, #collect, etc don't take
arguments, how should I proceed?  I would be okay with wrapping the
Enumerable methods I need, but that doesn't seem possible.  Do I just
have to implement my own #map, #to_a, etc?

Thanks,
  Erwin
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2007-05-21 13:01
(Received via mailing list)
On 21.05.2007 12:41, Erwin Abbott wrote:
> I've written a number of classes which would benefit from the
> Enumerable mixin, but my #each method requires arguments.  These are
> usually to specify the range of values, like Fibonacci#each(first,
> last) or whatever.  Since Enumerable's #map, #collect, etc don't take
> arguments, how should I proceed?  I would be okay with wrapping the
> Enumerable methods I need, but that doesn't seem possible.  Do I just
> have to implement my own #map, #to_a, etc?

Just use Enumerator:

12:54:27 [client_1]: irb -r enumerator
irb(main):001:0> class Foo
irb(main):002:1> include Enumerable
irb(main):003:1> def each(a,b,&bl) (a..b).each(&bl); self end
irb(main):004:1> end
=> nil
irb(main):005:0> Foo.new.each(1,5) {|x| p x}
1
2
3
4
5
=> #<Foo:0x7ef7e9b8>
irb(main):006:0> Foo.new.to_enum(:each,1,5).map {|x| x+x}
=> [2, 4, 6, 8, 10]

Btw, is your Foibonacci#each really an instance method or rather a class
method?  If it is an instance method you might as well store arguments
in the instance, so you do

Fibonacci.new(1,10).each {|fib| puts fib}

Kind regards

  robert
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2007-05-21 15:28
(Received via mailing list)
On May 21, 6:41 am, "Erwin Abbott" <erwin.abb...@gmail.com> wrote:
> Hi
>
> I've written a number of classes which would benefit from the
> Enumerable mixin, but my #each method requires arguments.  These are
> usually to specify the range of values, like Fibonacci#each(first,
> last) or whatever.  Since Enumerable's #map, #collect, etc don't take
> arguments, how should I proceed?  I would be okay with wrapping the
> Enumerable methods I need, but that doesn't seem possible.  Do I just
> have to implement my own #map, #to_a, etc?

The standard response is "use enumerator and to_enum". but if you feel
like me, that's equivalent to tying knots in your spaghetti noodles to
save money on rotini.

I heard rumor that a future Ruby will ultimately pass thru each
parameters, but in the mean time you can have a go with Facets
enumerablepass.rb (http://facets.rubyforge.org).

An alternative is to use a functor (a function delegator) for your
parameters, eg.

  f = Foo.new
  f.range(1,5).each{|x| p x}

T.
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2007-05-21 16:36
(Received via mailing list)
On 21.05.2007 15:27, Trans wrote:
>> have to implement my own #map, #to_a, etc?
>
> The standard response is "use enumerator and to_enum". but if you feel
> like me, that's equivalent to tying knots in your spaghetti noodles to
> save money on rotini.

I on the other hand am a big fan of Enumerator. :-)

> I heard rumor that a future Ruby will ultimately pass thru each
> parameters, but in the mean time you can have a go with Facets
> enumerablepass.rb (http://facets.rubyforge.org).

That's a good solution.

> An alternative is to use a functor (a function delegator) for your
> parameters, eg.
>
>   f = Foo.new
>   f.range(1,5).each{|x| p x}

... which is basically the same as using to_enum - only less portable;
to_enum works with *all* methods. :-)

Kind regards

  robert
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2007-05-21 17:52
(Received via mailing list)
On May 21, 10:35 am, Robert Klemme <shortcut...@googlemail.com> wrote:

> > An alternative is to use a functor (a function delegator) for your
> > parameters, eg.
>
> >   f = Foo.new
> >   f.range(1,5).each{|x| p x}
>
> ... which is basically the same as using to_enum - only less portable;
> to_enum works with *all* methods. :-)

That true. But at least it reads much better.

T.
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2007-05-21 17:55
(Received via mailing list)
On 21.05.2007 17:51, Trans wrote:
> That true. But at least it reads much better.
Even that is subjective: I personally prefer to read f.to_enum(:range,
1, 5) because then I know this is going to be capable of all the
Enumerable methods.  YMMD though.  :-)

Kind regards

  robert
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-05-21 18:00
(Received via mailing list)
On May 21, 2007, at 10:55 AM, Robert Klemme wrote:

>> That true. But at least it reads much better.
>
> Even that is subjective: I personally prefer to read f.to_enum
> (:range, 1, 5) because then I know this is going to be capable of
> all the Enumerable methods.  YMMD though.  :-)

I agree.  It's also worth noting that to_enum() is aliased to enum_for
() which I think often reads a little better.

James Edward Gray II
6e296d1bf1f3d230bb12a15ce8b5fe9b?d=identicon&s=25 Erwin Abbott (Guest)
on 2007-05-21 19:42
(Received via mailing list)
Thanks for the replies.  I hadn't looked at Enumerator before, I think
that will do the trick. I kind of agree it's not the prettiest looking
code, but I'll write my own #map, #to_a, etc and won't have to look at
it again.

> I heard rumor that a future Ruby will ultimately pass thru each
> parameters, but in the mean time you can have a go with Facets
> enumerablepass.rb (http://facets.rubyforge.org).

I'll look into that too... I see quite a lot of people using facets in
the code and have been meaning to check it out.  It seems like passing
parameters along would've been easy and very useful, I'm sort of
surprised it's not already that way.

Cheers,
  Erwin
8f6f95c4bd64d5f10dfddfdcd03c19d6?d=identicon&s=25 Rick Denatale (rdenatale)
on 2007-05-21 19:48
(Received via mailing list)
On 5/21/07, Trans <transfire@gmail.com> wrote:


> I heard rumor that a future Ruby will ultimately pass thru each
> parameters,

I'm not sure that that means in general, but what the current 1.9 does
is to first make Enumerator part of the standard library, and to make
each and other similar methods return an enumerator for the method and
it's parameters in cases where no block is given.

i.e.  (in ruby 1.9)

   e = "abc".each_byte
is equivalent to
   e = "abc".enum_for(:each_byte)

and
   e = array.each_slice(2)
is equivalent to
   e = array.enum_for(:each_slice, 2)

and you can do things like:

   "abc".each_byte.inject {|sum, chr| sum + chr}


--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-05-21 19:53
(Received via mailing list)
On May 21, 2007, at 12:46 PM, Rick DeNatale wrote:

> On 5/21/07, Trans <transfire@gmail.com> wrote:
>
>
>> I heard rumor that a future Ruby will ultimately pass thru each
>> parameters,
>
> I'm not sure that that means in general, but what the current 1.9 does
> is to first make Enumerator part of the standard library...

Enumerator is part of the standard library (libraries shipped with
Ruby) in Ruby 1.8.  1.9 mores the library to the core (no require
needed).

James Edward Gray II
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2007-05-21 19:54
(Received via mailing list)
On May 21, 11:55 am, Robert Klemme <shortcut...@googlemail.com> wrote:
> >> ... which is basically the same as using to_enum - only less portable;
> >> to_enum works with *all* methods. :-)
>
> > That true. But at least it reads much better.
>
> Even that is subjective: I personally prefer to read f.to_enum(:range,
> 1, 5) because then I know this is going to be capable of all the
> Enumerable methods.  YMMD though.  :-)

Not sure I understand what you mean by "because then I know this is
going to be capable of all the Enumerable methods", b/c what #range
returns can be too. In fact I think it can be defined like this:

  def range(x,y)
    Functor.new(self) do |op, obj|
      obj.to_enum(op,x,y)
    end
  end

(don't quote me on that though, I haven't tested it.)

So I take it you actually mean that using to_enum is better in that
you don't need to know anything about #range to understand the code? I
can understand, but I think its preferable to break things down into
smaller, more readable, sub-functions.

T.
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2007-05-21 20:45
(Received via mailing list)
On 21.05.2007 19:42, Erwin Abbott wrote:
> Thanks for the replies.  I hadn't looked at Enumerator before, I think
> that will do the trick. I kind of agree it's not the prettiest looking
> code, but I'll write my own #map, #to_a, etc and won't have to look at
> it again.

No, the point is that with Enumerator you do *not* have to write your
own #map etc.  Just create a method that will iterate - whatever name -
and then *any* client can do

obj.to_enum(:your_iterator_method, arg1, arg2).map {|item| item.to_s}

(see my first posting to the thread)

>> I heard rumor that a future Ruby will ultimately pass thru each
>> parameters, but in the mean time you can have a go with Facets
>> enumerablepass.rb (http://facets.rubyforge.org).
>
> I'll look into that too... I see quite a lot of people using facets in
> the code and have been meaning to check it out.  It seems like passing
> parameters along would've been easy and very useful, I'm sort of
> surprised it's not already that way.

But then again, #each probably needs arguments less often than you might
think right now.

Kind regards

  robert


PS: Please do not top post.  Thank you!
8f6f95c4bd64d5f10dfddfdcd03c19d6?d=identicon&s=25 Rick Denatale (rdenatale)
on 2007-05-21 22:24
(Received via mailing list)
On 5/21/07, James Edward Gray II <james@grayproductions.net> wrote:
>
> Enumerator is part of the standard library (libraries shipped with
> Ruby) in Ruby 1.8.  1.9 mores the library to the core (no require
> needed).

Thanks James, that's what I meant, of course.  I plead one or more of:

1) Alzheimers
2) Arthritis
3) Brain f*rt.


--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2007-05-22 00:11
(Received via mailing list)
On 21.05.2007 19:52, Trans wrote:
>>>>>   f.range(1,5).each{|x| p x}
>>>> ... which is basically the same as using to_enum - only less portable;
>>>> to_enum works with *all* methods. :-)
>>> That true. But at least it reads much better.
>> Even that is subjective: I personally prefer to read f.to_enum(:range,
>> 1, 5) because then I know this is going to be capable of all the
>> Enumerable methods.  YMMD though.  :-)
>
> Not sure I understand what you mean by "because then I know this is
> going to be capable of all the Enumerable methods", b/c what #range
> returns can be too.

Yes, it *can* - that's not the point.  But if I see foo.to_enum(:bar,
24, 5) in code I know already that the return value of #to_enum includes
Enumerable while in the case of #range I have to look into
documentation.

> In fact I think it can be defined like this:
>
>   def range(x,y)
>     Functor.new(self) do |op, obj|
>       obj.to_enum(op,x,y)
>     end
>   end
>
> (don't quote me on that though, I haven't tested it.)

:-)

> So I take it you actually mean that using to_enum is better in that
> you don't need to know anything about #range to understand the code?

Exactly.

> I can understand, but I think its preferable to break things down into
> smaller, more readable, sub-functions.

Um, I am not sure I understand what you mean by this in the current
context.  Can you please elaborate?

Kind regards

  robert
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2007-05-22 01:00
(Received via mailing list)
On May 21, 6:10 pm, Robert Klemme <shortcut...@googlemail.com> wrote:
> >>>>> An alternative is to use a functor (a function delegator) for your
> > Not sure I understand what you mean by "because then I know this is
> >     Functor.new(self) do |op, obj|
>
> Exactly.
>
> > I can understand, but I think its preferable to break things down into
> > smaller, more readable, sub-functions.
>
> Um, I am not sure I understand what you mean by this in the current
> context.  Can you please elaborate?

Hmmm... The best answer I can probably give is actually this:

  http://thinking-forth.sourceforge.net/

Sorry it's not a concise answer, but this conversation could very well
EXPLODE from here. And I'd prefer to keep DRY ;-)

T.
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2007-05-22 15:01
(Received via mailing list)
On 22.05.2007 00:58, Trans wrote:
>> Um, I am not sure I understand what you mean by this in the current
>> context.  Can you please elaborate?
>
> Hmmm... The best answer I can probably give is actually this:
>
>   http://thinking-forth.sourceforge.net/
>
> Sorry it's not a concise answer, but this conversation could very well
> EXPLODE from here. And I'd prefer to keep DRY ;-)

Frankly, I won't be reading a 300+ page document in order to try to get
an idea of what you /might/ have intended.

Kind regards

  robert
This topic is locked and can not be replied to.