[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Does an Array#apply make any sense at all?

nikolai.weibull@gmail.com

8/14/2007 9:38:00 AM

Hi!

I wanted to write a simple method for comparing two paths on a Windows
system. My initial algorithm felt very contrived:

def same_path?(a, b)
a, b = [a, b].map{ |p| File.expand_path(p).downcase }
a == b
end

It felt like saving the result from #map and then doing the comparison
shouldn't be necessary. So I came up with the following solution:

class Array
def apply(method)
shift.send(method, *self)
end
end

This allowed me to define #same_path? thusly:

def same_path?(a, b)
[a, b].map{ |p| File.expand_path(p).downcase }.apply(:==)
end

which, to me, looks a lot nicer. Array#apply takes a method (in a
symbolic manner) and applies it to its first element, passing the rest
of the elements as arguments to the given method.

Any thoughts? Is Array#apply a method that could potentially have
other uses than my specific example above?

nikolai

27 Answers

Eric Hodel

8/14/2007 9:50:00 AM

0

On Aug 14, 2007, at 02:40, nikolai.weibull@gmail.com wrote:
> I wanted to write a simple method for comparing two paths on a Windows
> system.

Is there something wrong with Pathname#==?

--
Poor workers blame their tools. Good workers build better tools. The
best workers get their tools to do the work for them. -- Syndicate Wars



nikolai.weibull@gmail.com

8/14/2007 11:36:00 AM

0

On Aug 14, 11:50 am, Eric Hodel <drbr...@segment7.net> wrote:
> On Aug 14, 2007, at 02:40, nikolai.weib...@gmail.com wrote:
>
> > I wanted to write a simple method for comparing two paths on a Windows
> > system.
>
> Is there something wrong with Pathname#==?

Yes, not that it can't be fixed, but the current definition is sort of
broken (on all systems):

#
# Compare this pathname with +other+. The comparison is string-
based.
# Be aware that two different paths (<tt>foo.txt</tt> and <tt>./
foo.txt</tt>)
# can refer to the same file.
#
def ==(other)
return false unless Pathname === other
other.to_s == @path
end
alias === ==
alias eql? ==

nikolai

Robert Klemme

8/14/2007 11:52:00 AM

0

2007/8/14, nikolai.weibull@gmail.com <nikolai.weibull@gmail.com>:
> Hi!
>
> I wanted to write a simple method for comparing two paths on a Windows
> system. My initial algorithm felt very contrived:
>
> def same_path?(a, b)
> a, b = [a, b].map{ |p| File.expand_path(p).downcase }
> a == b
> end
>
> It felt like saving the result from #map and then doing the comparison
> shouldn't be necessary. So I came up with the following solution:
>
> class Array
> def apply(method)
> shift.send(method, *self)
> end
> end
>
> This allowed me to define #same_path? thusly:
>
> def same_path?(a, b)
> [a, b].map{ |p| File.expand_path(p).downcase }.apply(:==)
> end
>
> which, to me, looks a lot nicer. Array#apply takes a method (in a
> symbolic manner) and applies it to its first element, passing the rest
> of the elements as arguments to the given method.
>
> Any thoughts? Is Array#apply a method that could potentially have
> other uses than my specific example above?

Your method should be called "apply!" because it's destructive. I'd
rather not do it that way, i.e. without changing the array at hand.You
can use inject for that.

I'd use #inject for your problem:

match = [a,b].map {|x| File.expand_path(x).downcase}.inject {|x,y| x==y}

Yet another solution is to use one of Pathname's multiple methods (for
example #realpath).

Kind regards

robert

nikolai.weibull@gmail.com

8/14/2007 11:57:00 AM

0

On Aug 14, 1:51 pm, "Robert Klemme" <shortcut...@googlemail.com>
wrote:
> 2007/8/14, nikolai.weib...@gmail.com <nikolai.weib...@gmail.com>:
>
>
>
> > Hi!
>
> > I wanted to write a simple method for comparing two paths on a Windows
> > system. My initial algorithm felt very contrived:
>
> > def same_path?(a, b)
> > a, b = [a, b].map{ |p| File.expand_path(p).downcase }
> > a == b
> > end
>
> > It felt like saving the result from #map and then doing the comparison
> > shouldn't be necessary. So I came up with the following solution:
>
> > class Array
> > def apply(method)
> > shift.send(method, *self)
> > end
> > end
>
> > This allowed me to define #same_path? thusly:
>
> > def same_path?(a, b)
> > [a, b].map{ |p| File.expand_path(p).downcase }.apply(:==)
> > end
>
> > which, to me, looks a lot nicer. Array#apply takes a method (in a
> > symbolic manner) and applies it to its first element, passing the rest
> > of the elements as arguments to the given method.
>
> > Any thoughts? Is Array#apply a method that could potentially have
> > other uses than my specific example above?
>
> Your method should be called "apply!" because it's destructive. I'd
> rather not do it that way, i.e. without changing the array at hand.You
> can use inject for that.
>
> I'd use #inject for your problem:
>
> match = [a,b].map {|x| File.expand_path(x).downcase}.inject {|x,y| x==y}

Ah, I had no idea inject would take the first item of an array if not
given an argument; thanks! That solves my problem.

nikolai

David A. Black

8/14/2007 12:07:00 PM

0

Trans

8/14/2007 12:11:00 PM

0



On Aug 14, 2:40 am, "nikolai.weib...@gmail.com"
<nikolai.weib...@gmail.com> wrote:
> Hi!
>
> I wanted to write a simple method for comparing two paths on a Windows
> system. My initial algorithm felt very contrived:
>
> def same_path?(a, b)
> a, b = [a, b].map{ |p| File.expand_path(p).downcase }
> a == b
> end
>
> It felt like saving the result from #map and then doing the comparison
> shouldn't be necessary. So I came up with the following solution:
>
> class Array
> def apply(method)
> shift.send(method, *self)
> end
> end
>
> This allowed me to define #same_path? thusly:
>
> def same_path?(a, b)
> [a, b].map{ |p| File.expand_path(p).downcase }.apply(:==)
> end

Your first solution is much easier to understand. In fact I would do:

def same_path?(a, b)
a = File.expand_path(a).downcase
b = File.expand_path(b).downcase
a == b
end

It's very clear and actually should be a tad faster. LOC isn't
everything!

But if you just can't abide by more that one line:

def same_path?(a, b)
File.expand_path(a).downcase == File.expand_path(b).downcase
end

HTH,
T.


nikolai.weibull@gmail.com

8/14/2007 12:30:00 PM

0

On Aug 14, 1:51 pm, "Robert Klemme" <shortcut...@googlemail.com>
wrote:

> Yet another solution is to use one of Pathname's multiple methods (for
> example #realpath).

The problem is that Pathname's comparison is case sensitive.

nikolai

nikolai.weibull@gmail.com

8/14/2007 2:23:00 PM

0

On Aug 14, 2:11 pm, Trans <transf...@gmail.com> wrote:
> On Aug 14, 2:40 am, "nikolai.weib...@gmail.com"

> > def same_path?(a, b)
> > [a, b].map{ |p| File.expand_path(p).downcase }.apply(:==)
> > end
>
> Your first solution is much easier to understand. In fact I would do:

> def same_path?(a, b)
> File.expand_path(a).downcase == File.expand_path(b).downcase
> end

It's not about the line count but about executing the same set of
functions/methods on both a and b. With the #inject or #apply
solution it's clear that both a and b undergo the same conversion.

nikolai

nikolai.weibull@gmail.com

8/14/2007 2:28:00 PM

0

On Aug 14, 2:07 pm, dbl...@rubypal.com wrote:
> Hi --
>
>
>
> On Tue, 14 Aug 2007, Robert Klemme wrote:
> > 2007/8/14, nikolai.weib...@gmail.com <nikolai.weib...@gmail.com>:
> >> Hi!
>
> >> I wanted to write a simple method for comparing two paths on a Windows
> >> system. My initial algorithm felt very contrived:
>
> >> def same_path?(a, b)
> >> a, b = [a, b].map{ |p| File.expand_path(p).downcase }
> >> a == b
> >> end
>
> >> It felt like saving the result from #map and then doing the comparison
> >> shouldn't be necessary. So I came up with the following solution:
>
> >> class Array
> >> def apply(method)
> >> shift.send(method, *self)
> >> end
> >> end
>
> >> This allowed me to define #same_path? thusly:
>
> >> def same_path?(a, b)
> >> [a, b].map{ |p| File.expand_path(p).downcase }.apply(:==)
> >> end
>
> >> which, to me, looks a lot nicer. Array#apply takes a method (in a
> >> symbolic manner) and applies it to its first element, passing the rest
> >> of the elements as arguments to the given method.
>
> >> Any thoughts? Is Array#apply a method that could potentially have
> >> other uses than my specific example above?
>
> > Your method should be called "apply!" because it's destructive.
>
> I could be wrong, but I think the convention (at least in core Ruby)
> is that ! methods always come in a pair with the non-! version. I
> don't think there are any cases where there's just a method called m!
> where the ! indicates destructiveness (or other "danger"). All the
> unpaired destructive methods have non-! names.

Ugh. This was so NOT about whether to call the method Array#apply or
Array#apply!. I just wrote the absolute shortest solution I could
think of. I didn't suggest that it was the final version. Yes,
seeing as how my definition mutates its target, Array#apply! is the
appropriate name. I simply didn't want to clutter the definition
thusly:

class Array
def apply(method)
first.send(method, *self[1..-1])
end
end

(which sort of begs the question why we don't have Array#rest ;-)

nikolai

Simon Krahnke

8/14/2007 2:29:00 PM

0

* <dblack@rubypal.com> (14:07) schrieb:

>> Your method should be called "apply!" because it's destructive.
>
> I could be wrong, but I think the convention (at least in core Ruby)
> is that ! methods always come in a pair with the non-! version. I
> don't think there are any cases where there's just a method called m!
> where the ! indicates destructiveness (or other "danger"). All the
> unpaired destructive methods have non-! names.

That is true for Array#delete. delete is always destructive, there is no
need to flag that.

But there is no need for your method to be destructive, so you need to
tell the world about it.

> I think this makes sense. If unpaired dangerous methods have !, it
> sort of suggests that any time there isn't a !, the method is
> non-dangerous, which in turn suggests non-destructive... and that
> isn't true.

It should simply be clear from the name[0] if a method is destructive.
Often you need the ! for that, in some cases it's obvious without the !.

mfg, simon .... [0] is that actually english?