From: Intransition on
Here, I worked on it I came up with:

module Enumerable

def visit(type=Enumerable, &block)
if block_given?
each do |e|
case e
when type
e.visit(type, &block)
else
block.call(e)
end
end
else
to_enum(:visit, type)
end
end

end

I am going to add this to Facets, but I have to decide for sure on the
name. Which is better?

#visit
#traverse
#recurse

other ?

From: Colin Bartlett on
On Sat, Apr 3, 2010 at 2:30 PM, Intransition <transfire(a)gmail.com> wrote:
> Here, I worked on it I came up with:
Is this the Array#recursively "TODO: Can this be generalized in Enumerable?" :)
http://facets.rubyforge.org/apidoc/api/core/classes/Array.html#M000055

Oddly enough, I'd also started wondering about a fully recursive version!
Borrowing ideas from Facets (Array#recursively, Enumerable#traverse)
I came up with the code at the end of this post. It's not as general
as either your code or Robert Klemme's (sort of "orthogonal" to yours)
but it was intended to cope with an element of the array
having an each method but not mixing in Enumerable

> I am going to add this to Facets, but I have to decide for sure on the
> name. Which is better? #visit #traverse #recurse other ?
I know they are long names, but because it's a recursive each, why not
#each_recursively (Facets already uses recursively) or #each_recursive
(I prefer the latter - shorter!) and maybe have visit as a short alias?
Or maybe use Robert Klemme's #each_flat, although since this will
apply a recursive each to Ranges (or Files, or anything else using each
which mixes in Enumerable) I'm not sure that flatten (or a derivative)
is fully appropriate?

I also like Robert Klemme's idea of having a level parameter,
so if Robert is agreeable - and from his Ruby-talk posts he seems to be
a very agreeable person! - maybe include levels, maybe renamed depth?
(I've thought of using level in a more general Find module, and
eventually decided depth was a better word for the concept. I can't
remember why, but I'm sure there must have been very good reasons!)
And maybe cater for "unlimited" depth using depth/levels = nil ? So:
if levels > 1 && Enumerable === x
x.each_flat(levels - 1, &b)
would become
if (! levels || levels > 1) && Enumerable === x
x.each_flat( levels && levels - 1, &b)

A question: should the depth/levels test be levels > 1 or > 0?
Using [ 2..2 ] and "levels > 1":
levels param: 0 #=> 2..2; 1 #=> 2..2; 2 #=> 2;
Using [ 2..2 ] and "levels > 0":
levels param: 0 #=> 2..2; 1 #=> 2; 2 #=> 2;
It seems (maybe?) more logical to have depth/levels arguments:
0 means don't do any recursive expansion of each;
1 means do some recursive expansion of each;


### Intended to cope with an element of an array (or whatever)
### having an each method but not mixing in Enumerable.
module Enumerable
def visits(&block)
each { |item| Enumerable.visits?(item, &block) }
end
def Enumerable.visits?(obj, &block)
if obj.respond_to?( :each ) then
obj.each { |item| Enumerable.visits?(item, &block) }
else
yield obj
end
end
end

From: Intransition on


On Apr 3, 11:47 am, Colin Bartlett <colin...(a)googlemail.com> wrote:
> On Sat, Apr 3, 2010 at 2:30 PM, Intransition <transf...(a)gmail.com> wrote:
> > Here, I worked on it I came up with:
>
> Is this the Array#recursively "TODO: Can this be generalized in Enumerable?" :)http://facets.rubyforge.org/apidoc/api/core/classes/Array.html#M000055

Thanks you for pointing this one out. I am working to make these
methods more uniform/consistent across all of Facets. There is also
similar methods for Pathname and Dir (e.g. Dir#recurse).

> Oddly enough, I'd also started wondering about a fully recursive version!
> Borrowing ideas from Facets (Array#recursively, Enumerable#traverse)
> I came up with the code at the end of this post. It's not as general
> as either your code or Robert Klemme's (sort of "orthogonal" to yours)
> but it was intended to cope with an element of the array
> having an each method but not mixing in Enumerable
>
> > I am going to add this to Facets, but I have to decide for sure on the
> > name. Which is better?   #visit   #traverse   #recurse   other ?
>
> I know they are long names, but because it's a recursive each, why not
>   #each_recursively (Facets already uses recursively) or #each_recursive
> (I prefer the latter - shorter!) and maybe have visit as a short alias?
> Or maybe use Robert Klemme's #each_flat, although since this will
> apply a recursive each to Ranges (or Files, or anything else using each
> which mixes in Enumerable) I'm not sure that flatten (or a derivative)
> is fully appropriate?

Yes, I was thinking of #recursive_each as well, since that name is
also along the lines of #reverse_each. On the other hand #recurse is
nice and short and to the point.

> I also like Robert Klemme's idea of having a level parameter,
> so if Robert is agreeable - and from his Ruby-talk posts he seems to be
> a very agreeable person! - maybe include levels, maybe renamed depth?
> (I've thought of using level in a more general Find module, and
> eventually decided depth was a better word for the concept. I can't
> remember why, but I'm sure there must have been very good reasons!)
> And maybe cater for "unlimited" depth using depth/levels = nil ? So:
>      if levels > 1 && Enumerable === x
>        x.each_flat(levels - 1, &b)
> would become
>      if (! levels || levels > 1) && Enumerable === x
>        x.each_flat( levels && levels - 1, &b)
>
> A question: should the depth/levels test be levels > 1 or > 0?
> Using [ 2..2 ] and "levels > 1":
>   levels param: 0 #=> 2..2;   1 #=> 2..2;   2 #=> 2;
> Using [ 2..2 ] and "levels > 0":
>   levels param: 0 #=> 2..2;   1 #=> 2;      2 #=> 2;
> It seems (maybe?) more logical to have depth/levels arguments:
>   0 means don't do any recursive expansion of each;
>   1 means do some recursive expansion of each;

Yes, I agree, a depth parameter could be useful as well.

> ### Intended to cope with an element of an array (or whatever)
> ### having an each method but not mixing in Enumerable.
> module Enumerable
>   def visits(&block)
>     each { |item| Enumerable.visits?(item, &block) }
>   end
>   def Enumerable.visits?(obj, &block)
>     if obj.respond_to?( :each ) then
>       obj.each { |item| Enumerable.visits?(item, &block) }
>     else
>       yield obj
>     end
>   end
> end

Interesting, you could take this a step further.

class Object
def visits(&block)
if respond_to?(:each)
each{ |item| item.visits(&block) }
else
yield(self)
end
end
end

Then every object would be "visitable".

However, using respond_to? can be dangerous. Consider if I (foolishly)
did:

class Object
def each
yield(self)
end
end

The more OOP approach would be:

class Object
def visits
yield(self)
end
end

module Enumerable
def visits(&block)
each{ |item| item.visits(&block) }
end
end

Then you can override #visits in any object as desired.

From: Caleb Clausen on
On 4/3/10, Intransition <transfire(a)gmail.com> wrote:
> The more OOP approach would be:
>
> class Object
> def visits
> yield(self)
> end
> end
>
> module Enumerable
> def visits(&block)
> each{ |item| item.visits(&block) }
> end
> end

This won't behave well if passed a true graph (not just tree or dag)
of ruby objects. For instance:

a=[]
a<<a
a.visits{|x| p x }

At one time, I got interested enough in this problem to write a fairly
complete solution to this problem (at least I think so). If
interested, please have a look at:
http://github.com/coatl/ron/blob/master/lib/ron/graphedge.rb

From: Colin Bartlett on
On Sun, Apr 4, 2010 at 12:47 AM, Intransition <transfire(a)gmail.com> wrote:
> On Apr 3, 11:47 am, Colin Bartlett <colin...(a)googlemail.com> wrote:
>
>> On Sat, Apr 3, 2010 at 2:30 PM, Intransition <transf...(a)gmail.com> wrote:
>>> I am going to add this to Facets, but I have to decide for sure on the
>>> name. Which is better?   #visit   #traverse   #recurse   other ?
>
>> I know they are long names, but because it's a recursive each, why not
>>   #each_recursively (Facets already uses recursively) or #each_recursive
>> (I prefer the latter - shorter!) and maybe have visit as a short alias?
>
> Yes, I was thinking of #recursive_each as well, since that name is
> also along the lines of #reverse_each. On the other hand #recurse is
> nice and short and to the point.

Some time after suggesting #each_recursive it occurred to me that
a possibility is #each_each which (apart from the issue of objects
which have an each method but which don't mix in Enumerable)
sort of says what it does. Then we could also have
#each_each_with_index, Array#reverse_each_each, etc.

First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5 6
Prev: A little help needed
Next: ANN: Sequel 3.10.0 Released