views:

231

answers:

3
+1  A: 

Think tree.

  # setup phase
  for each pathname p in list
  do
     add_path_to_tree(p)
  od
  walk tree depth first, emitting HTML

add_path_to_tree is recursive

 given pathname p
 parse p into first_element, rest
 # that is, "foo/bar/baz" becomes "foo", "bar/baz"
 add first_element to tree
 add_path_to_tree(rest)

I'll leave the optimal data struct (list of lists) for the tree (list of lists) as an exercise.

Charlie Martin
+3  A: 

Here's a quick implementation you can use for inspiration. This implementation disregards the order of files in the input Array.

I've updated the solution to save the entire path as you required.

dirs = ['file1', 'dir1/file2', 'dir1/subdir1/file3',  'dir1/subdir1/file5']
tree = {}

dirs.each do |path|
  current  = tree
  path.split("/").inject("") do |sub_path,dir|
    sub_path = File.join(sub_path, dir)
    current[sub_path] ||= {}
    current  = current[sub_path]
    sub_path
  end
end

def print_tree(prefix, node)
  puts "#{prefix}<ul>"
  node.each_pair do |path, subtree| 
    puts "#{prefix}  <li>[#{path[1..-1]}] #{File.basename(path)}</li>"    
    print_tree(prefix + "  ", subtree) unless subtree.empty?
  end
  puts "#{prefix}</ul>"
end

print_tree "", tree

This code will produce properly indented HTML like your example. But since Hashes in Ruby (1.8.6) aren't ordered the order of the files can't be guaranteed.

The output produced will look like this:

<ul>
  <li>[dir1] dir1</li>
  <ul>
    <li>[dir1/subdir1] subdir1</li>
    <ul>
      <li>[dir1/subdir1/file3] file3</li>
      <li>[dir1/subdir1/file5] file5</li>
    </ul>
    <li>[dir1/file2] file2</li>
  </ul>
  <li>[file1] file1</li>
</ul>

I hope this serves as an example of how you can get both the path and the filename.

sris
This is almost exactly what I was going to post.
Pesto
okay, implemented this solution, but there's still one problem: i need full file paths as values of the checkboxes (each li prefix is a checkbox). here i only get the files.
pduersteler
Does the update answer your new question?
sris
I've updated the example to remove the duplicate use of the path variable name. Hope this answers your question
sris
that did the dtrick, works like a charm, thanks a lot!!
pduersteler
+1  A: 

Expanding on sris's answer, if you really want everything sorted and the files listed before the directories, you can use something like this:

def files_first_traverse(prefix, node = {})
  puts "#{prefix}<ul>" 
  node_list = node.sort
  node_list.each do |base, subtree|
    puts "#{prefix}  <li>#{base}</li>" if subtree.empty?
  end
  node_list.each do |base, subtree|
    next if subtree.empty?
    puts "#{prefix}  <li>#{base}</li>"
    files_first_traverse(prefix + '  ', subtree)
  end
  puts '#{prefix}</ul>'
end
Pesto
I didn't want to clutter the original code too much, but this is a nice addition!
sris
It's not really necessary to have it in order but thanks for the addition :-)
pduersteler