views:

32

answers:

2

I have to following code in ruby:

<%
  files = Dir.glob('/**/*')
  files.each do |file|
    puts file
  end
%>

It outputs (for example):

/dirA/file1.txt
/dirA/file2.txt
/dirB/file1.txt
/file1.txt
/file2.txt
/subdirA/file1.txt

I want it to output it like this:

/file1.txt
/file2.txt
/dirA/file1.txt
/dirA/file2.txt
/dirB/file1.txt
/subdirA/file1.txt

Basically, I'd like to have the files displayed before the directories. Is there a sorting command I can use?

+2  A: 

I believe this should work for you:

files = Dir.glob('**/*')
files = files.map { |file| [file.count("/"), file] }
files = files.sort.map { |file| file[1] }
files.each do |file|
  puts file
end

Change "/" to ?/ if you're on Ruby 1.8.

Or, as a one-liner: :)

Dir.glob('**/*').map { |file| [file.count("/"), file] }.sort.map { |file| file[1] }.each { |file| puts file }
Amadan
that works!! THANKS!
James Nine
`Enumerable#sort_by` makes the Schwartzian transform easier to follow, and `String#count` works on both 1.8 and 1.9: `files = Dir.glob('**/*').sort_by {|file| [file.count("/"), file]}`. (The array is still needed to break ties between filenames with the same slash count.)
bk1e
I don't get why `sort_by` would be needed; array sorting criterion should be okay, no? (compare first elements, if same, move to the next one.) I do not want to put counting inside the comparison block since that would be inefficient (I don't think Ruby is smart enough to memoize by itself). I did not know about `String#count`; thanks for that. Using that would definitely be more elegant. I'll edit it in.
Amadan
A: 
d,f = Dir.glob('*').partition{|d|test(?d,d)}
d.sort.each{|x|puts x}
f.sort.each{|y|puts y}
ghostdog74