I am trying to code a method that accepts a block… easy. The problem
is that this method is recursive, so I don’t know how to pass the
block through the recursive calls.
The specific code is about recurising through a directory tree while
calling the provided code block once per each directory, passing the
list of files in that directory. This is the code:
class DirInfo
constructor, etc. removed for clarity
def scan @path.each_entry do |p|
next if p.to_s == “.” || p.to_s == “…”
p = @path + p
if p.file?
finf = FileInfo.new§ @files << finf
elsif p.directory?
dinf = DirInfo.new§
dinf.scan # ==> Recursive search of subdirs
end
end
yield @path, @files
end
end
So if I do:
di = DirInfo.new("/devtools/ruby")
di.scan do |path, files|
puts “Directory #{path} has #{files.length} files”
end
I expect to get my block called once per each subdirectory, passing
the subdir path and list of files in that subdir. The problem is that
the fisrt time the call scan is made from within scan, no block is
given, so I get a “no block given” exception and the program stops.
I know there are other ways to scan directories, but please take it
just as an example. Still the question is, how to combine
recursiveness with blocks?
Another poster mentioned the &block thing, which is probably preferable.
Note that you could also simply do:
dinf.scan { |p,f| yield p,f }
The advantage to this is that (for shallow recursion), there is less
overhead than creating a Proc object for the block. The big
disadvantage
is that you add an extra layer of yield-ing for each level recursion.
I know there are other ways to scan directories, but please take it
just as an example. Still the question is, how to combine
recursiveness with blocks?
The typical (and IIRC most efficient) idiom is to pass on the block
parameter:
def foo(&b)
foo(&b)
end
Another remark: it seems you are reinventing Find.find(). Why do you do
that?
The typical (and IIRC most efficient) idiom is to pass on the block
parameter:
def foo(&b)
foo(&b)
end
That looks nice and simple.
Thanks!
Another remark: it seems you are reinventing Find.find(). Why do you do
that?
As I said, the dir scanning was just an example of recursiveness.
Still, I do need to scan a directory in a way that I get an array of
files per each block call, and not one file at a time, because I want
to compare the contents of a directory with other directory, in order
to identify changed files, new files, deleted files, etc.
I know there are other ways to scan directories, but please take it
just as an example. Still the question is, how to combine
recursiveness with blocks?
Thanks in advance,
Luis.
You can make the block argument explicit:
def scan(&block)
do stuff
scan &block # <== recursive call with block
yield
end
to identify changed files, new files, deleted files, etc.
robert
Cool! The code is much more advanced compared with mine… yes, I am a
Ruby beginner.
Still, if I understood your code well, it creates a whole directory
tree in memory, which, if applied to “/” (or "c:") it can really take
a huge amount of RAM.
I want to process the list of files in each directory, one directory
at a time, and then forget about these files once they are processed.
However I guess I can modify your code above a bit, remove the hash,
check that “d” is the same as the previous pass, and if not yield the
list, etc.