Special Array method about Unix pathes

here is the goal:

i've an Array of Unix pathes :
forbidden = ["/Volumes/U3 System",
             "/Volumes/EMTEC KEY/emtec_dl",
             "/Volumes/EMTEC KEY/emtec_dl/Win98SE new driver.exe",
             "/Volumes/EMTEC KEY/emtec_dl/v233r001"
            ]

i want to forbid access to those pathes BUT since, for example,
"/Volumes/EMTEC KEY/emtec_dl/Win98SE new driver.exe" « belongs »
to the path (it's below this path) "/Volumes/EMTEC KEY/emtec_dl"
it is unusefull to have it in the Array.

in the case above i'd like to return :

forbidden = ["/Volumes/U3 System",
             "/Volumes/EMTEC KEY/emtec_dl"
            ]

what i've done :

class Array
   def includePath?(path)
     self.each { | x |
       return true if path.startsWith?(x)
     }
     return false
   end
   def getContainers!
     self.delete_if { | x | ( self - [ x ] ).includePath?( x ) }
   end
end

class String
  def startsWith?(dir)
    self.index(dir) === 0
  end
end

then forbidden.getContainers! gives me the expected result.

what do you think about this solution ?
could you propose a better one ?

also, because english isn't my mother tongue, are my methods naming
correct ?

···

--
Une Bévue

Une Bévue wrote:

here is the goal:

i've an Array of Unix pathes :
forbidden = ["/Volumes/U3 System",
             "/Volumes/EMTEC KEY/emtec_dl",
             "/Volumes/EMTEC KEY/emtec_dl/Win98SE new driver.exe",
             "/Volumes/EMTEC KEY/emtec_dl/v233r001"
            ]

i want to forbid access to those pathes BUT since, for example,
"/Volumes/EMTEC KEY/emtec_dl/Win98SE new driver.exe" « belongs »
to the path (it's below this path) "/Volumes/EMTEC KEY/emtec_dl"
it is unusefull to have it in the Array.

in the case above i'd like to return :

forbidden = ["/Volumes/U3 System",
             "/Volumes/EMTEC KEY/emtec_dl"
            ]

what i've done :

class Array
   def includePath?(path)
     self.each { | x |
       return true if path.startsWith?(x)
     }
     return false
   end
   def getContainers!
     self.delete_if { | x | ( self - [ x ] ).includePath?( x ) }
   end
end

class String
  def startsWith?(dir)
    self.index(dir) === 0
  end
end

then forbidden.getContainers! gives me the expected result.

what do you think about this solution ?
could you propose a better one ?

also, because english isn't my mother tongue, are my methods naming
correct ?

Array doesn't seem the proper class to have a includePath? method, otherwise the names look reasonable. If the method is in Array, then a reasonable name might be includesStart?

Alle mercoledì 19 settembre 2007, Une Bévue ha scritto:

here is the goal:

i've an Array of Unix pathes :
forbidden = ["/Volumes/U3 System",
             "/Volumes/EMTEC KEY/emtec_dl",
             "/Volumes/EMTEC KEY/emtec_dl/Win98SE new driver.exe",
             "/Volumes/EMTEC KEY/emtec_dl/v233r001"
            ]

i want to forbid access to those pathes BUT since, for example,
"/Volumes/EMTEC KEY/emtec_dl/Win98SE new driver.exe" « belongs »
to the path (it's below this path) "/Volumes/EMTEC KEY/emtec_dl"
it is unusefull to have it in the Array.

in the case above i'd like to return :

forbidden = ["/Volumes/U3 System",
             "/Volumes/EMTEC KEY/emtec_dl"
            ]

what i've done :

class Array
   def includePath?(path)
     self.each { | x |
       return true if path.startsWith?(x)
     }
     return false
   end
   def getContainers!
     self.delete_if { | x | ( self - [ x ] ).includePath?( x ) }
   end
end

class String
  def startsWith?(dir)
    self.index(dir) === 0
  end
end

then forbidden.getContainers! gives me the expected result.

what do you think about this solution ?
could you propose a better one ?

also, because english isn't my mother tongue, are my methods naming
correct ?

This is my alternative solution:

def select_toplevel_paths arg
  a = arg.dup.sort_by{|i| i.size}
  a.inject() do |res, i|
    res.any?{|j| i.index(j) == 0 } ? res : (res << i)
  end
end

It doesn't change the contents of the array and it's not a method of class
Array, because, in my opinion, it's a too specialized method to be put in a
core class.

Regarding your code, I'd say names are correct, as far as English is
concerned. I'd like to give you a copule of suggestions:
* use underscores instead of camel-case (include_path? instead of includePath,
for example), because it's the more common style in the ruby community
* use start_with? instead of starts_with?. In the ruby standard library, there
are several cases in which both methods exist, with the ones ending in s being
obsolete (for example, File.exists? and File.exist?) For consistency, I think
it's better to follow the same convention.

Stefano

Une Bévue <unbewusst.sein <at> wortanschahung.com.invalid> writes:

what i've done :

class Array
   def includePath?(path)
     self.each { | x |
       return true if path.startsWith?(x)
     }
     return false
   end
   def getContainers!
     self.delete_if { | x | ( self - [ x ] ).includePath?( x ) }
   end
end

In contrast to everyone else's points about your naming, I'm not happy with your
implementation.

/home/gareth/files/my_file
is not a child of
/home/gareth/fil

Gareth

Charles D Hixson wrote:

> self.each { | x |
> return true if path.startsWith?(x)
> }
> return false

self.any? {|x| path.starts_with?(x) }

HTH,
Sebastian

···

--
NP: Iron Maiden - Infinite Dreams
Jabber: sepp2k@jabber.org
ICQ: 205544826

Array doesn't seem the proper class to have a includePath? method,
otherwise the names look reasonable.

i'll lokk if there is something more related to Unix pathes...

If the method is in Array, then a
reasonable name might be includesStart?

OK, thanks!

···

Charles D Hixson <charleshixsn@earthlink.net> wrote:

--
Une Bévue

Hi,

At Thu, 20 Sep 2007 03:24:58 +0900,
Stefano Crocco wrote in [ruby-talk:269890]:

def select_toplevel_paths arg
  a = arg.dup.sort_by{|i| i.size}
  a.inject() do |res, i|
    res.any?{|j| i.index(j) == 0 } ? res : (res << i)

i.rindex(j, 0) is faster than i.index(j) == 0 when j matches in
the middle.

* use start_with? instead of starts_with?. In the ruby standard library, there
are several cases in which both methods exist, with the ones ending in s being
obsolete (for example, File.exists? and File.exist?) For consistency, I think
it's better to follow the same convention.

And ruby 1.9 has String#start_with? already in fact.

···

--
Nobu Nakada

This is my alternative solution:

def select_toplevel_paths arg
  a = arg.dup.sort_by{|i| i.size}
  a.inject() do |res, i|
    res.any?{|j| i.index(j) == 0 } ? res : (res << i)
  end
end

clever solution, thanks a lot !

however with the following (part of a yaml file) :

  forbiddenList:
  - /Volumes/EMTEC KEY/emtec_dl
  - /Volumes/EMTEC KEY/emtec_dl/v233r001/Setup.exe
  - /Volumes/U3 System
  - /Volumes/U3 System/Launchpad.zip

your select_toplevel_paths don't remove /Volumes/EMTEC
KEY/emtec_dl/v233r001/Setup.exe and /Volumes/U3 System/Launchpad.zip

It doesn't change the contents of the array and it's not a method of class
Array, because, in my opinion, it's a too specialized method to be put in a
core class.

U're right, i was embarassed with that point.

Regarding your code, I'd say names are correct, as far as English is
concerned. I'd like to give you a copule of suggestions:
* use underscores instead of camel-case (include_path? instead of includePath,
for example), because it's the more common style in the ruby community
* use start_with? instead of starts_with?. In the ruby standard library, there
are several cases in which both methods exist, with the ones ending in s being
obsolete (for example, File.exists? and File.exist?) For consistency, I think
it's better to follow the same convention.

OK, done !

···

Stefano Crocco <stefano.crocco@alice.it> wrote:

--
Une Bévue

fine thanks, i didn't know the #any?

···

Sebastian Hungerecker <sepp2k@googlemail.com> wrote:

self.any? {|x| path.starts_with?(x) }

--
Une Bévue

You can even leave the "self." out. :slight_smile:

I can think of several approaches to solve this:

1. order the array and do a second iteration where each item is
checked against the last seen prefix; the idea is that every string
comes before the strings that contain it as prefix.

2. insert names into a tree and output only prefixes during a tree walk.

Bévue, the only issue I see with your method naming is that in Ruby
methods typically use under_scores and not CamelCase as in Java.

Kind regards

robert

···

2007/9/19, Sebastian Hungerecker <sepp2k@googlemail.com>:

Charles D Hixson wrote:
> > self.each { | x |
> > return true if path.startsWith?(x)
> > }
> > return false

self.any? {|x| path.starts_with?(x) }

Alle mercoledì 19 settembre 2007, Une Bévue ha scritto:

forbiddenList:
- /Volumes/EMTEC KEY/emtec_dl
- /Volumes/EMTEC KEY/emtec_dl/v233r001/Setup.exe
- /Volumes/U3 System
- /Volumes/U3 System/Launchpad.zip

your select_toplevel_paths don't remove /Volumes/EMTEC
KEY/emtec_dl/v233r001/Setup.exe and /Volumes/U3 System/Launchpad.zip

It works for me:

irb: 001> def select_toplevel_path arg
irb: 002+> a = arg.dup.sort_by{|i| i.size}
irb: 003+> a.inject() do |res, i|
irb: 004*> res.any?{|j| i[0, j.size] == j} ? res : (res << i)
irb: 005+> end
irb: 006+> end
nil
irb: 007> forbidden = ["/Volumes/EMTEC KEY/emtec_dl",
irb: 008*> "/Volumes/EMTEC KEY/emtec_dl/v233r001/Setup.exe",
irb: 009*> "/Volumes/U3 System",
irb: 010*> "/Volumes/U3 System/Launchpad.zip"
irb: 011+> ]
["/Volumes/EMTEC KEY/emtec_dl", "/Volumes/EMTEC
KEY/emtec_dl/v233r001/Setup.exe", "/Volumes/U3 System", "/Volumes/U3
System/Launchpad.zip"]
irb: 012> select_toplevel_path forbidden
["/Volumes/U3 System", "/Volumes/EMTEC KEY/emtec_dl"]

Notice that this doesn't change the forbidden array, but creates a new one.

Stefano

sorry, in fact that works wheb used as :

forbidden = [
  "/Volumes/U3 System",
  "/Volumes/EMTEC KEY/emtec_dl",
  "/Volumes/EMTEC KEY/emtec_dl/Win98SE new driver.exe",
  "/Volumes/EMTEC KEY/emtec_dl/v233r001/Setup.exe",
  "/Volumes/EMTEC KEY/emtec_dl/v233r001",
  "/Volumes/U3 System/LaunchU3.exe",
  "/Volumes/U3 System/Launchpad.zip"
  ]

p forbidden
forbidden = select_toplevel_paths( forbidden )
p forbidden

but not when used in a class :

class SyncDataSource < OSX::NSObject
            
    def initialize

[...]

        @forbiddenList =

[...]

    end

[...]

    def addForbidden( notification )

[...]

        p @forbiddenList
        @forbiddenList = select_toplevel_paths( @forbiddenList )
        p @forbiddenList

[...]

    end

end

i don't understand why for the time being...

···

Une Bévue <unbewusst.sein@wortanschahung.com.invalid> wrote:

however with the following (part of a yaml file) :

  forbiddenList:
  - /Volumes/EMTEC KEY/emtec_dl
  - /Volumes/EMTEC KEY/emtec_dl/v233r001/Setup.exe
  - /Volumes/U3 System
  - /Volumes/U3 System/Launchpad.zip

your select_toplevel_paths don't remove /Volumes/EMTEC
KEY/emtec_dl/v233r001/Setup.exe and /Volumes/U3 System/Launchpad.zip

--
Une Bévue

You can even leave the "self." out. :slight_smile:

OK !

I can think of several approaches to solve this:

1. order the array and do a second iteration where each item is
checked against the last seen prefix; the idea is that every string
comes before the strings that contain it as prefix.

fine, the Array is allready ordered elsewhere, i thought putting sort!
in this method ))

2. insert names into a tree and output only prefixes during a tree walk.

ok, i see what you mean, may be better not to do that when output rather
than when building the three having a means to compare three deepness.

Bévue, the only issue I see with your method naming is that in Ruby
methods typically use under_scores and not CamelCase as in Java.

Yes i've corrected that, it's an habit coming from java, as the getter
"getContainers!"...

···

Robert Klemme <shortcutter@googlemail.com> wrote:
--
Une Bévue

I can think of several approaches to solve this:

1. order the array and do a second iteration where each item is
checked against the last seen prefix; the idea is that every string
comes before the strings that contain it as prefix.

fine, the Array is allready ordered elsewhere, i thought putting sort!
in this method ))

If it's sorted anyway that's probably the approach I'd take.

2. insert names into a tree and output only prefixes during a tree walk.

ok, i see what you mean, may be better not to do that when output rather
than when building the three having a means to compare three deepness.

I am not sure what you mean here. You have to build the tree first before you can decide which branches you can omit. With "output" I did not necessarily mean output to screen, but rather output from the method. Maybe I should have chosen a different wording. I am sorry if that caused confusion.

Bévue, the only issue I see with your method naming is that in Ruby
methods typically use under_scores and not CamelCase as in Java.

Yes i've corrected that, it's an habit coming from java, as the getter
"getContainers!"...

Different languages, different conventions. :slight_smile:

Kind regards

  robert

···

On 19.09.2007 21:26, Une Bévue wrote:

Robert Klemme <shortcutter@googlemail.com> wrote:

> ok, i see what you mean, may be better not to do that when output rather
> than when building the three having a means to compare three deepness.

I am not sure what you mean here. You have to build the tree first
before you can decide which branches you can omit. With "output" I did
not necessarily mean output to screen, but rather output from the
method. Maybe I should have chosen a different wording. I am sorry if
that caused confusion.

i've found a simpler approach, in fact, this list of pathes is entered
by the user using a File/folder chooser window, then instead of walking
a three or something else, xhen the user enter a new path right now i
check only if this path is allready taken into account by :

files.each { |f|
  f_to_s = f.to_s
  @forbiddenList << f_to_s unless @forbiddenList.include_path?( f_to_s )
}

with :
files the File(s)/Folder(s) entered by the user ;
f.to_s converting NSString to Ruby String (NS stands for NextStep) ;
Array#include_path?( a_path ) being :
class Array
   def include_path?(path)
     self.any? { | x | a_path.rindex( x, 0 ) }
   end
end

the only thing i dislike is in that pathes have nothing to do with
Array,i must rexrite this part.

>> Bévue, the only issue I see with your method naming is that in Ruby
>> methods typically use under_scores and not CamelCase as in Java.
>
> Yes i've corrected that, it's an habit coming from java, as the getter
> "getContainers!"...

Different languages, different conventions. :slight_smile:

yes right, here i'm embarassed because my code isn't "pure" Ruby, it's
RubyCocoa (a bridge between Cocoa/ObjC on Mac OS X) and in RubyCocoa the
Cocoa methods like :

NSOpenPanel#beginSheetForDirectory:file:types:modalForWindow:modalDelega
te:didEndSelector:contextInfo:

are translated, on the Ruby side, in :

beginSheetForDirectory_file_types_modalForWindow_modalDelegate_didEndSel
ector:contextInfo( ... )

then "_" replaces ":" and still camelized...

···

Robert Klemme <shortcutter@googlemail.com> wrote:

--
Une Bévue