Need help with recursion

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 :frowning:
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:innoRecursiveUnderscore’
from recursivenounderscore.rb:3:in foreach' from recursivenounderscore.rb:3:innoRecursiveUnderscore’
from recursivenounderscore.rb:9:in noRecursiveUnderscore' from recursivenounderscore.rb:3:inforeach’
from recursivenounderscore.rb:3:in `noRecursiveUnderscore’
from recursivenounderscore.rb:17

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

···

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 :frowning:
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)
[…]

Hi --

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 :frowning:
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

···

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

--
David A. Black
dblack@wobblini.net

Hi –

Mark Hubbart discord@mac.com writes:

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 :frowning:
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

···

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


David Alan Black
home: dblack@wobblini.net # New email address
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

“David A. Black” dblack@wobblini.net schrieb im Newsbeitrag
news:Pine.LNX.4.44.0404081823560.22274-100000@wobblini…

Hi –

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 :frowning:
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
···

On Fri, 9 Apr 2004, Boris “BXS” Schulz 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

hope, i understood you.

~ibotty

Hi --

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 :slight_smile: 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

···

On Sat, 10 Apr 2004, Robert Klemme wrote:

--
David A. Black
dblack@wobblini.net

Hi --

> 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

···

On Fri, 9 Apr 2004, ibotty wrote:

--
David A. Black
dblack@wobblini.net

“David A. Black” dblack@wobblini.net writes:

Hi –

$ 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

That’s because the filename is “u_file”, not “u_s”.

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

The error means simply that some file or directory, which the system
needed to access in order to perform the rename, doesn’t exist.

The “or” inside the error message is there because the error can refer to
either a file or directory. The “or” between the pathnames is there
because the error might occur while processing either argument to rename:
the source or the destination.

Obviously, if the destination file doesn’t exist, that’s not an error, because
it’s not supposed to exist until after the rename. But if the destination
is a pathname instead of just a bare filename, then one or more of the
subdirectories on the way to the destination might not exist, and that
would trigger the same error. For instance, if you’d done this:

    $ ruby -e 'File.rename("u_score/u_file", "u score/u_file")'

that would fail with a very similar error because the directory “u score”
doesn’t exist.

(You could, of course, rename the directory itself:

    $ ruby -e 'File.rename("u_score", "u score");

That would work fine.)

-Mark

···

On Sat, 10 Apr 2004, Robert Klemme wrote:

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 :slight_smile:

David


David A. Black
dblack@wobblini.net

“David A. Black” dblack@wobblini.net schrieb im Newsbeitrag
news:Pine.LNX.4.44.0404090846010.18453-100000@wobblini…

Hi –

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 :slight_smile:

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

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
···

On Sat, 10 Apr 2004, Robert Klemme wrote:

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
dblack@wobblini.net