need help with recursion

Discussion in 'Ruby' started by Boris \BXS\ Schulz, Apr 9, 2004.

  1. Hi,

    I was just trying to replace the underscores I get when using files from
    my Linux-friends, but somehow my code seems to be corrupt.
    The code runs fine without the recursion, so it must be something wrong
    in those three lines, but I do not know what :-(
    The "under_score.txt" is my testobject.
    I am using: Ruby 1.8.0, Windows XP
    Any help would be great.

    greetings, BXS


    This is my code:

    class FileHandling
    def noRecursiveUnderscore(basedirectory)
    Dir::foreach(basedirectory){ |filename|
    if File.stat(filename).file?
    newname = filename.gsub("_", " ")
    File.rename(filename, newname)
    end
    if File.stat(filename).directory? and filename != "." and filename != ".."
    noRecursiveUnderscore(filename)
    end
    }
    end

    end #class

    testDir = FileHandling.new()
    testDir.noRecursiveUnderscore(Dir.getwd)


    **** This is my errormessage ****
    recursivenounderscore.rb:4:in `stat': No such file or directory -
    under_score.txt
    (Errno::ENOENT)
    from recursivenounderscore.rb:4:in `noRecursiveUnderscore'
    from recursivenounderscore.rb:3:in `foreach'
    from recursivenounderscore.rb:3:in `noRecursiveUnderscore'
    from recursivenounderscore.rb:9:in `noRecursiveUnderscore'
    from recursivenounderscore.rb:3:in `foreach'
    from recursivenounderscore.rb:3:in `noRecursiveUnderscore'
    from recursivenounderscore.rb:17
    Boris \BXS\ Schulz, Apr 9, 2004
    #1
    1. Advertising

  2. Boris \BXS\ Schulz

    Mark Hubbart Guest

    On Apr 8, 2004, at 5:54 PM, Boris "BXS" Schulz wrote:

    > Hi,
    >
    > I was just trying to replace the underscores I get when using files
    > from my Linux-friends, but somehow my code seems to be corrupt.
    > The code runs fine without the recursion, so it must be something
    > wrong in those three lines, but I do not know what :-(
    > The "under_score.txt" is my testobject.
    > I am using: Ruby 1.8.0, Windows XP
    > Any help would be great.
    >
    > greetings, BXS
    >
    >
    > This is my code:
    >
    > class FileHandling
    > def noRecursiveUnderscore(basedirectory)
    > Dir::foreach(basedirectory){ |filename|
    > if File.stat(filename).file?
    > newname = filename.gsub("_", " ")
    > File.rename(filename, newname)
    > end
    > if File.stat(filename).directory? and filename != "." and filename
    > != ".."
    > noRecursiveUnderscore(filename)
    > end
    > }
    > end
    >
    > end #class
    >
    > testDir = FileHandling.new()
    > testDir.noRecursiveUnderscore(Dir.getwd)
    >
    >
    > **** This is my errormessage ****
    > recursivenounderscore.rb:4:in `stat': No such file or directory -
    > under_score.txt
    > (Errno::ENOENT)
    > [...]


    You are correct, the problem *is* in the recursion part; you are
    stat()ing the same filename "with_underscores", but you had already
    renamed the file, so it gave an error. To fix it, make it an
    if..elsif..end, rather than two if..end's:

    if File.stat(filename).file?
    newname = filename.gsub("_", " ")
    File.rename(filename, newname)
    elsif File.stat(filename).directory? and filename != "." and filename
    != ".."
    noRecursiveUnderscore(filename)
    end

    That should fix that particular problem.

    --Mark
    Mark Hubbart, Apr 9, 2004
    #2
    1. Advertising

  3. Hi --

    On Fri, 9 Apr 2004, Boris "BXS" Schulz wrote:

    > Hi,
    >
    > I was just trying to replace the underscores I get when using files from
    > my Linux-friends, but somehow my code seems to be corrupt.
    > The code runs fine without the recursion, so it must be something wrong
    > in those three lines, but I do not know what :-(
    > The "under_score.txt" is my testobject.
    > I am using: Ruby 1.8.0, Windows XP
    > Any help would be great.


    I think it's because you're looking for a filename without the full
    path. At least, if under_score.txt is one level down, I think that's
    what's happening. You'd need to chdir to the new directory, which you
    can do with Dir.chdir.

    You can actually let the Find module handle this too:

    class FileHandling
    require 'find'
    def noRecursiveUnderscore(dir)
    Find.find(dir) do |f|
    File.rename(f, f.gsub("_", " ")) if File.stat(f).file?
    end
    end
    end


    David

    --
    David A. Black
    David A. Black, Apr 9, 2004
    #3
  4. Hi --

    Mark Hubbart <> writes:

    > On Apr 8, 2004, at 5:54 PM, Boris "BXS" Schulz wrote:
    >
    > > Hi,
    > >
    > > I was just trying to replace the underscores I get when using files
    > > from my Linux-friends, but somehow my code seems to be corrupt.
    > > The code runs fine without the recursion, so it must be something
    > > wrong in those three lines, but I do not know what :-(
    > > The "under_score.txt" is my testobject.
    > > I am using: Ruby 1.8.0, Windows XP
    > > Any help would be great.
    > >
    > > greetings, BXS
    > >
    > >
    > > This is my code:
    > >
    > > class FileHandling
    > > def noRecursiveUnderscore(basedirectory)
    > > Dir::foreach(basedirectory){ |filename|
    > > if File.stat(filename).file?
    > > newname = filename.gsub("_", " ")
    > > File.rename(filename, newname)
    > > end
    > > if File.stat(filename).directory? and filename != "." and filename
    > > != ".."
    > > noRecursiveUnderscore(filename)
    > > end
    > > }
    > > end
    > >
    > > end #class
    > >
    > > testDir = FileHandling.new()
    > > testDir.noRecursiveUnderscore(Dir.getwd)
    > >
    > >
    > > **** This is my errormessage ****
    > > recursivenounderscore.rb:4:in `stat': No such file or directory -
    > > under_score.txt
    > > (Errno::ENOENT)
    > > [...]

    >
    > You are correct, the problem *is* in the recursion part; you are
    > stat()ing the same filename "with_underscores", but you had already
    > renamed the file, so it gave an error. To fix it, make it an
    > if..elsif..end, rather than two if..end's:
    >
    > if File.stat(filename).file?
    > newname = filename.gsub("_", " ")
    > File.rename(filename, newname)
    > elsif File.stat(filename).directory? and filename != "." and filename
    > != ".."
    > noRecursiveUnderscore(filename)
    > end



    You'll still have the subdirectory problem. Let's say you've got:

    a
    a/b
    a/b/under_score.txt

    It will run the method for b, and filename will be set to
    under_score.txt. But when it stats it, it will stat it with respect
    to a, unless you do a chdir to b or expand the path.


    David

    --
    David Alan Black
    home: # New email address
    work:
    Web: http://pirate.shu.edu/~blackdav
    David Alan Black, Apr 9, 2004
    #4
  5. Hi --

    On Fri, 9 Apr 2004, ibotty wrote:

    > > You'll still have the subdirectory problem. Let's say you've got:
    > >
    > > a
    > > a/b
    > > a/b/under_score.txt
    > >
    > > It will run the method for b, and filename will be set to
    > > under_score.txt. But when it stats it, it will stat it with respect
    > > to a, unless you do a chdir to b or expand the path.

    >
    > you can of course simply set filename to the right value. just change this,
    > and it should work.
    >
    > File.rename(filename, newname)
    > + filename = newname
    > end


    That won't change the behavior of the original code. The problem I'm
    describing is that you're trying to stat a file when you're in the
    wrong directory. It's not the same as the problem involving renaming
    the file.

    Here's an example, leaving out the renaming to show the problem:

    def find_files_broken(dir)
    Dir.new(dir).reject {|f| /\A\.\.?\z/.match(f)} .each do |f|
    if File.stat(f).file?
    puts "File: #{f}"
    elsif File.stat(f).directory?
    puts "Directory: #{f}"
    find_files(f)
    end
    end
    end

    find_files_broken(Dir.pwd)

    Here's a modified example that works:

    def find_files(dir)
    Dir.chdir(dir) do
    Dir["*"].each do |f|
    if File.stat(f).file?
    puts "File: #{f}"
    elsif File.stat(f).directory?
    puts "Directory: #{f}"
    find_files(f)
    end
    end
    end
    end

    find_files(Dir.pwd)

    The difference is that I've used Dir.chdir to make sure I'm addressing
    the right space at the right time. (This also allows me to use Dir.[]
    instead of Dir.new, which saves the trouble of checking for "." and
    "..".)


    David

    --
    David A. Black
    David A. Black, Apr 9, 2004
    #5
  6. "David A. Black" <> schrieb im Newsbeitrag
    news:pine.LNX.4.44.0404081823560.22274-100000@wobblini...
    > Hi --
    >
    > On Fri, 9 Apr 2004, Boris "BXS" Schulz wrote:
    >
    > > Hi,
    > >
    > > I was just trying to replace the underscores I get when using files from
    > > my Linux-friends, but somehow my code seems to be corrupt.
    > > The code runs fine without the recursion, so it must be something wrong
    > > in those three lines, but I do not know what :-(
    > > The "under_score.txt" is my testobject.
    > > I am using: Ruby 1.8.0, Windows XP
    > > Any help would be great.

    >
    > I think it's because you're looking for a filename without the full
    > path. At least, if under_score.txt is one level down, I think that's
    > what's happening. You'd need to chdir to the new directory, which you
    > can do with Dir.chdir.
    >
    > You can actually let the Find module handle this too:
    >
    > class FileHandling
    > require 'find'
    > def noRecursiveUnderscore(dir)
    > Find.find(dir) do |f|
    > File.rename(f, f.gsub("_", " ")) if File.stat(f).file?
    > end
    > end
    > end


    There's a subtly problem with your code: Files which are in directories that
    contain an underscore are not treated well... Better do something along
    these lines:

    Dir[ File.join( dir, "**", "*" ) ].each do |name|
    d, base = File.split name
    changed = base.dup.gsub!("_", " ") and
    File.rename( name, File.join( d, changed ) )
    end

    The same is possible with Find.find of course. In fact, File.find might be
    more efficient if the hieararchy contains many files.

    Kind regards

    robert
    Robert Klemme, Apr 9, 2004
    #6
  7. File.rename weirdness (was Re: need help with recursion)

    Hi --

    On Sat, 10 Apr 2004, Robert Klemme wrote:

    > Dir[ File.join( dir, "**", "*" ) ].each do |name|
    > d, base = File.split name
    > changed = base.dup.gsub!("_", " ") and
    > File.rename( name, File.join( d, changed ) )
    > end
    >
    > The same is possible with Find.find of course. In fact, File.find might be
    > more efficient if the hieararchy contains many files.


    Yes, actually I used Find.find in my example :) You're right about
    the overzealous gsub'ing. I'm not sure how directories were supposed
    to be handled, but I thought I was ignoring them, which I accidentally
    wasn't.

    But here's some rename weirdness I've discovered while doing this:

    $ ls u_score/
    u_file
    $ ruby -e 'File.rename("u_score/u_s", "u_score/u s")'
    -e:1:in `rename': No such file or directory -
    u_score/u_s or u_score/u s (Errno::ENOENT)
    from -e:1


    I have to admit I have no idea why that happens or even what the error
    exactly means. (What's with the "or"?)


    David

    --
    David A. Black
    David A. Black, Apr 9, 2004
    #7
  8. Re: File.rename weirdness (was Re: need help with recursion)

    Hi --

    On Sat, 10 Apr 2004, David A. Black wrote:

    > But here's some rename weirdness I've discovered while doing this:
    >
    > $ ls u_score/
    > u_file
    > $ ruby -e 'File.rename("u_score/u_s", "u_score/u s")'
    > -e:1:in `rename': No such file or directory -
    > u_score/u_s or u_score/u s (Errno::ENOENT)
    > from -e:1
    >
    >
    > I have to admit I have no idea why that happens or even what the error
    > exactly means. (What's with the "or"?)


    Never mind. I am an idiot. "u_s" != "u_file". (Private note to the
    person who pointed this out: merci :)


    David

    --
    David A. Black
    David A. Black, Apr 9, 2004
    #8
  9. Re: File.rename weirdness (was Re: need help with recursion)

    "David A. Black" <> schrieb im Newsbeitrag
    news:pine.LNX.4.44.0404090846010.18453-100000@wobblini...
    > Hi --
    >
    > On Sat, 10 Apr 2004, Robert Klemme wrote:
    >
    > > Dir[ File.join( dir, "**", "*" ) ].each do |name|
    > > d, base = File.split name
    > > changed = base.dup.gsub!("_", " ") and
    > > File.rename( name, File.join( d, changed ) )
    > > end
    > >
    > > The same is possible with Find.find of course. In fact, File.find might

    be
    > > more efficient if the hieararchy contains many files.

    >
    > Yes, actually I used Find.find in my example :)


    I know. I included the other variant for the purpose of showing a different
    approach. :)

    > You're right about
    > the overzealous gsub'ing. I'm not sure how directories were supposed
    > to be handled, but I thought I was ignoring them, which I accidentally
    > wasn't.


    Me, too. But that's an easy change:

    Dir[ File.join( dir, "**", "*" ) ].each do |name|
    if File.file? name
    d, base = File.split name
    changed = base.dup.gsub!("_", " ") and
    File.rename( name, File.join( d, changed ) )
    end
    end

    or

    Dir[ File.join( dir, "**", "*" ) ].each do |name|
    next unless File.file? name

    d, base = File.split name
    changed = base.dup.gsub!("_", " ") and
    File.rename( name, File.join( d, changed ) )
    end

    Note: even when directories are ignored for the rename, the gsub on the
    complete name still can do harm and should by replaced by something along
    the lines of my suggestion (File.split and File.join).

    Regards

    robert
    Robert Klemme, Apr 9, 2004
    #9
  10. Re: File.rename weirdness (was Re: need help with recursion)

    Hi --

    On Sat, 10 Apr 2004, Robert Klemme wrote:

    > Note: even when directories are ignored for the rename, the gsub on the
    > complete name still can do harm and should by replaced by something along
    > the lines of my suggestion (File.split and File.join).


    Yes -- that's what I meant when I said I thought I'd ignored them but
    accidentally hadn't (i.e., by using gsub on the complete name).


    David

    --
    David A. Black
    David A. Black, Apr 9, 2004
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Anakin
    Replies:
    14
    Views:
    745
    Thomas G. Marshall
    Apr 13, 2005
  2. Alexander

    need help with recursion

    Alexander, May 13, 2004, in forum: C++
    Replies:
    2
    Views:
    317
    David Harmon
    May 13, 2004
  3. Replies:
    2
    Views:
    297
  4. Replies:
    2
    Views:
    264
    Mike Schilling
    Oct 21, 2008
  5. Replies:
    8
    Views:
    733
    John Reye
    Apr 26, 2012
Loading...

Share This Page