Here's a filtered file/dir copy, FWIW

I had a need to do a filtered directory-tree copy, but didn’t see
anything in the std lib docs (or from googling) other than
FileUtils.cp_r which doesn’t do filtering, so I made alternate versions
of that and FileUtils.copy_entry that do filtering.

Ordinarily, I’d try to form it into something appropriate for potential
inclusion in the official lib and submit a patch, but I’m still enough
of Ruby novice that I don’t really have enough of a feel for what
exactly would be a “proper” way to integrate the feature, so I’m posting
(attaching) it here as-is in the hopes that someone may at least find it
useful. (FWIW, this is modified from the implementations in fileutils.rb
from Ruby 1.9.1p378).

On Feb 9, 6:07 pm, Nick S. [email protected]
wrote:

useful. (FWIW, this is modified from the implementations in fileutils.rb
from Ruby 1.9.1p378).

Seems like a useful idea. Join ruby-core mailing list and ask. And let
us know the outcome.

Thomas S. wrote:

On Feb 9, 6:07�pm, Nick S. [email protected]
wrote:

useful. (FWIW, this is modified from the implementations in fileutils.rb
from Ruby 1.9.1p378).

Seems like a useful idea. Join ruby-core mailing list and ask. And let
us know the outcome.

I too think it’s useful.

Nick, I hope your code doesn’t create empty folders when none of the
files match the condition.

Albert S. wrote:

Thomas S. wrote:

On Feb 9, 6:07�pm, Nick S. [email protected]
wrote:

useful. (FWIW, this is modified from the implementations in fileutils.rb
from Ruby 1.9.1p378).

Seems like a useful idea. Join ruby-core mailing list and ask. And let
us know the outcome.

I too think it’s useful.

Nick, I hope your code doesn’t create empty folders when none of the
files match the condition.

I haven’t tested that, but I don’t think it will: Unless I’m missing
something, the only path into the code that does any actual copying at
all (file or directory) is through a conditional that calls the filter
and checks if it returns true.

Also, I’m a little confused about the comment about joining the
ruby-core list and asking: The ruby-forum.com interface I’m using (I
hate dealing with mailing lists directly, forums and newsgroups are
fine though) lists ruby-core as read only and there doesn’t seem to be
anything anywhere about joining it. Plus it looks like it’s primarily
just an automatic-tracker that submitted bug tickets get automatically
sent to…?

On Feb 11, 5:03 pm, Nick S. [email protected]
wrote:

Also, I’m a little confused about the comment about joining the
ruby-core list and asking: The ruby-forum.com interface I’m using (I
hate dealing with mailing lists directly, forums and newsgroups are
fine though) lists ruby-core as read only and there doesn’t seem to be
anything anywhere about joining it. Plus it looks like it’s primarily
just an automatic-tracker that submitted bug tickets get automatically
sent to…?

I don’t like using my inbox for mailing lists either. You can use
google groups:

http://groups.google.com/group/ruby-core-google

(I am using ruby-talk-google right now in fact.)

On Mar 1, 2010, at 00:32 , Nick S. wrote:

 File.unlink destent.path if remove_destination && 

Why does it do that, and how can I fix it?
I have no idea because there is no test to look at that reproduces this
problem. So, write a failing test and make it work. This would be
especially easy if you refactored that File.unlink to be a method of
Entry_ (don’t name it that. ugh!).

Turns out there’s a bug in that, but I can’t figure out why…

Consider this part:


def copy_entryx(src, dest, filter, preserve = false, dereference_root =
false, remove_destination = false)
Entry_.new(src, nil, dereference_root).traverse do |ent|
if filter.call(ent.path) then
destent = Entry_.new(dest, ent.rel, false)
File.unlink destent.path if remove_destination &&
File.file?(destent.path)
ent.copy destent.path
ent.copy_metadata destent.path if preserve
end
end
end

(The formatting might have gotten messed up. Check the ‘copy_entryx’
function in the OP’s attachment for the correct formatting.)

What that should be doing is: For each ‘ent’ in the traversal, check
if the filter returns true, and if so, do the copy. Then, regardless of
whether or not it passed the filter and was copied, move on to the next
‘ent’.

What is actually does but shouldn’t do: As soon as filter returns
false, instead of moving on the the next ‘ent’, the entire ‘copy_entryx’
function exits (I’ve checked this with debugging ‘puts’ statements, if I
put one right on a new line right between the last two ‘end’ statements,
it never shows unless the filter always returns true).

Why does it do that, and how can I fix it?

On Mar 1, 2010, at 16:32 , Nick S. wrote:

That “do |value|…end” is not a full function literal like I was
expecting it to be, but some kind of…like a closure of a portion of
the function it’s contained in. More like using cross-function goto’s
than calling a passed-in function.

That is exactly what a block is… a closure.

So the cp_rx function I posted does work right, it was just that the
filter I was passing in to it was malformed and returning from the top
few entires in the call stack instead of just the top one.

exactly.

The proper way to write your reproduction is not:

callWith123 do |value|
if value == 2 then
return false
end
true
end

but:

callWith123 do |value|
value != 2
end

And again, you need to ACTUALLY write tests. /soapbox

Ryan D. wrote:

On Mar 1, 2010, at 16:32 , Nick S. wrote:

That “do |value|…end” is not a full function literal like I was
expecting it to be, but some kind of…like a closure of a portion of
the function it’s contained in. More like using cross-function goto’s
than calling a passed-in function.

That is exactly what a block is… a closure.

Soapbox on terminology: Though these terms frequently get mixed up,
“closure” merely refers to the ability of code to access locals from the
function it’s defined within regardless of whether or not that enclosing
function has returned (And yes, Ruby’s closures fit this definition, or
at least as far as I can tell).

But, “closure” does not imply that it isn’t a function - in fact, in
most languages, closures are full-fledged functions that are,
depending on the language, created with either nested functions and/or
anonymous function literals. I’ve dealt with closures in plenty of
different languages and this is still the first one I’ve come across
where returning from a closure also returned from the function that
invoked the closure and all the way down the stack through the function
it was created within. So no, that’s not how closures necessarily work.

Ryan D. wrote:

On Mar 1, 2010, at 00:32 , Nick S. wrote:

 File.unlink destent.path if remove_destination && 

Why does it do that, and how can I fix it?
I have no idea because there is no test to look at that reproduces this
problem. So, write a failing test and make it work. This would be
especially easy if you refactored that File.unlink to be a method of
Entry_ (don’t name it that. ugh!).

Ok, I’ve done a simplified test:


def callWith123 &dg
puts “dg.call(1) returns #{dg.call(1)}”
puts “dg.call(2) returns #{dg.call(2)}”
puts “dg.call(3) returns #{dg.call(3)}”
end

def testIt
puts “Entering testIt”
callWith123 do |value|
if value == 2 then
return false
end
true
end
puts “Leaving testIt”
end

puts “Start”
testIt
puts “End”

What I expected:


Start
Entering testIt
dg.call(1) returns true
dg.call(2) returns false
dg.call(3) returns true
Leaving testIt
End

What I got:


Start
Entering testIt
dg.call(1) returns true
End

Apparently, the “return false” returns from testIt instead of merely
returning from the delegate. So it turns out that when you do something
like this:


def foo &dg
#stuff here
end

foo do |value|
#stuff here
end

That “do |value|…end” is not a full function literal like I was
expecting it to be, but some kind of…like a closure of a portion of
the function it’s contained in. More like using cross-function goto’s
than calling a passed-in function.

So the cp_rx function I posted does work right, it was just that the
filter I was passing in to it was malformed and returning from the top
few entires in the call stack instead of just the top one.

On Mar 2, 2010, at 11:12 , Nick S. wrote:

Soapbox on terminology: Though these terms frequently get mixed up,
“closure” merely refers to the ability of code to access locals from the
function it’s defined within regardless of whether or not that enclosing
function has returned (And yes, Ruby’s closures fit this definition, or
at least as far as I can tell).

Wow. Thanks for the attitude after helping you with your problem. Maybe
I should have focused on “like I was expecting it to be” and pointed out
that studying one’s language is tantamount to success.

Soapbox on history:

Maybe you should look at (real) programming languages like smalltalk,
commonlisp, or scheme. Ruby bases a lot of its semantics on languages
like lisp and smalltalk. The following wikipedia entry has code samples
of each (and ruby and many others) describing exactly this problem.

Closure (computer programming) - Wikipedia

But, “closure” does not imply that it isn’t a function - in fact, in
most languages, closures are full-fledged functions that are,
depending on the language, created with either nested functions and/or
anonymous function literals. I’ve dealt with closures in plenty of
different languages and this is still the first one I’ve come across
where returning from a closure also returned from the function that
invoked the closure and all the way down the stack through the function
it was created within. So no, that’s not how closures necessarily work.

Not only did I not imply that a closure isn’t a function, I didn’t
imply that ruby blocks were not functions (or methods). They are. That
has little to do with this UNLESS you also carry definitional baggage
from other languages.

Also, I’d watch the use of “most” there. Maybe if you said “most
languages I’ve used”…

In most languages I’ve used, closures behave like ruby’s.

Ryan D. wrote:

On Mar 2, 2010, at 11:12 , Nick S. wrote:

Soapbox on terminology: Though these terms frequently get mixed up,
“closure” merely refers to the ability of code to access locals from the
function it’s defined within regardless of whether or not that enclosing
function has returned (And yes, Ruby’s closures fit this definition, or
at least as far as I can tell).

Wow. Thanks for the attitude after helping you with your problem. Maybe
I should have focused on “like I was expecting it to be” and pointed out
that studying one’s language is tantamount to success.

There was no attitude intended. In fact, I deliberately overlooked what
I saw as attitude in “And again, you need to ACTUALLY write tests.
/soapbox”.

Soapbox on history:

Maybe you should look at (real) programming languages like smalltalk,
commonlisp, or scheme. Ruby bases a lot of its semantics on languages
like lisp and smalltalk. The following wikipedia entry has code samples
of each (and ruby and many others) describing exactly this problem.

Closure (computer programming) - Wikipedia

This snippet is very helpful:


def bar
f = lambda { return “return from lambda” }
f.call # control does not leave bar here
return “return from bar”
end

puts bar # prints “return from bar”

I was not aware of that alternate form of ruby closure.

But, “closure” does not imply that it isn’t a function - in fact, in
most languages, closures are full-fledged functions that are,
depending on the language, created with either nested functions and/or
anonymous function literals. I’ve dealt with closures in plenty of
different languages and this is still the first one I’ve come across
where returning from a closure also returned from the function that
invoked the closure and all the way down the stack through the function
it was created within. So no, that’s not how closures necessarily work.

Not only did I not imply that a closure isn’t a function, I didn’t
imply that ruby blocks were not functions (or methods).

Then there’s no need to take it personally. :slight_smile: