need help with recursion

  • Thread starter Boris \BXS\ Schulz
  • Start date
B

Boris \BXS\ Schulz

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
 
M

Mark Hubbart

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
 
D

David A. Black

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 :-(
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
 
D

David Alan Black

Hi --

Mark Hubbart said:
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
 
D

David A. Black

Hi --

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
 
R

Robert Klemme

David A. Black said:
Hi --



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
 
D

David A. Black

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 :) 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
 
D

David A. Black

Hi --

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
 
R

Robert Klemme

David A. Black said:
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 :)

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
 
D

David A. Black

Hi --

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top