Ruby创建递归目录树

我需要以递归方式遍历目录并创建一个与jsTree控件一起使用的树。 该控件接受像这样的JSON格式。 我需要一些ruby魔法才能让它干净而迅速地发生。

任何帮助表示赞赏。

你可能想要这样的东西(未经测试):

def directory_hash(path, name=nil) data = {:data => (name || path)} data[:children] = children = [] Dir.foreach(path) do |entry| next if (entry == '..' || entry == '.') full_path = File.join(path, entry) if File.directory?(full_path) children << directory_hash(full_path, entry) else children << entry end end return data end 

递归地走下树,建立一个哈希。 用你最喜欢的序列化库把它变成json。

首先取出树,将其转换为叶子路径列表,类似于:

 def leaves_paths tree if tree[:children] tree[:children].inject([]){|acc, c| leaves_paths(c).each{|p| acc += [[tree[:name]] + p] } acc } else [[tree[:name]]] end end 

(不确定以上是否完全符合您的jsTree结构,但原理是相同的。)

这是输入和输出的示例:

 tree = {name: 'foo', children: [ {name: 'bar'}, {name: 'baz', children: [ {name: 'boo'}, {name: 'zoo', children: [ {name: 'goo'} ]} ]} ]} p leaves_paths tree #=> [["foo", "bar"], ["foo", "baz", "boo"], ["foo", "baz", "zoo", "goo"]] 

然后,对于每个路径,调用FileUtils#mkdir_p

 paths = leaves_paths tree paths.each do |path| FileUtils.mkdir_p(File.join(*path)) end 

你应该没问题。

编辑:更简单的版本:

您不需要创建叶子列表,只需遍历整个树并为每个节点创建一个目录:

 # executes block on each tree node, recursively, passing the path to the block as argument def traverse_with_path tree, path = [], &block path += [tree[:name]] yield path tree[:children].each{|c| traverse_with_path c, path, &block} if tree[:children] end traverse_with_path tree do |path| FileUtils.mkdir(File.join(*path)) end 

EDIT2:

哦,对不起,我误会了。 所以,这是一种基于磁盘上的目录树制作哈希的方法:

 Dir.glob('**/*'). # get all files below current dir select{|f| File.directory?(f) # only directories we need }.map{|path| path.split '/' # split to parts }.inject({}){|acc, path| # start with empty hash path.inject(acc) do |acc2,dir| # for each path part, create a child of current node acc2[dir] ||= {} # and pass it as new current node end acc } 

因此,对于以下结构:

 #$ mkdir -p foo/bar #$ mkdir -p baz/boo/bee #$ mkdir -p baz/goo 

上面的代码返回此哈希:

 { "baz"=>{ "boo"=>{ "bee"=>{}}, "goo"=>{}}, "foo"=>{ "bar"=>{}}} 

希望您能够满足您的需求。

Ruby的Find模块( require 'find' )是极简主义但很好地处理目录递归: http : //www.ruby-doc.org/stdlib/libdoc/find/rdoc/classes/Find.html

截至2015年6月,已接受的答案无效。我将密钥:data更改为'text' 。 我还将代码概括为排除目录和文件。

 def directory_hash(path, name=nil, exclude = []) exclude.concat(['..', '.', '.git', '__MACOSX', '.DS_Store']) data = {'text' => (name || path)} data[:children] = children = [] Dir.foreach(path) do |entry| next if exclude.include?(entry) full_path = File.join(path, entry) if File.directory?(full_path) children << directory_hash(full_path, entry) else children << {'icon' => 'jstree-file', 'text' => entry} end end return data end