我可能会写这样的:
class Object
def all_variables(root=true)
vars = {}
self.instance_variables.each do |var|
ivar = self.instance_variable_get(var)
vars[var] = [ivar, ivar.all_variables(false)]
end
root ? [self, vars] : vars
end
end
def string_variables(vars, lb="\n", indent="\t", current_indent="")
out = "#{vars[0].inspect}#{lb}"
current_indent += indent
out += vars[1].map do |var, ivar|
ivstr = string_variables(ivar, lb, indent, current_indent)
"#{current_indent}#{var}: #{ivstr}"
end.join
return out
end
def inspect_variables(obj, lb="\n", indent="\t", current_indent="")
string_variables(obj.all_variables, lb, indent, current_indent)
end
的Object#all_variables
方法产生含有(0)的给定对象和(1)的散列映射实例变量名阵列含有(0)的实例的阵列变量和(1)哈希映射...。因此,它给你一个很好的递归结构。 string_variables
函数很好地打印出该散列; inspect_variables
只是一个便利的包装。因此,print inspect_variables(foo)
为您提供换行符分隔选项,print inspect_variables(foo, "<br />\n")
为您提供HTML换行符的版本。如果你想指定缩进,你也可以这样做:print inspect_variables(foo, "\n", "|---")
产生一个(无用的)人造树格式,而不是基于制表符的缩进。
应该有一个明智的方法来编写一个each_variable
函数,您可以提供一个回调函数(不需要分配中间存储);如果我想到某件事情,我会编辑这个答案以包含它。编辑1:我想到了一些东西。
这里是另一种方式来写它,我认为这是稍微更好:
class Object
def each_variable(name=nil, depth=0, parent=nil, &block)
yield name, self, depth, parent
self.instance_variables.each do |var|
self.instance_variable_get(var).each_variable(var, depth+1, self, &block)
end
end
end
def inspect_variables(obj, nl="\n", indent="\t", sep=': ')
out = ''
obj.each_variable do |name, var, depth, _parent|
out += [indent*depth, name, name ? sep : '', var.inspect, nl].join
end
return out
end
的Object#each_variable
方法需要一些可选的参数,它没有被设计成由用户指定;相反,它们被递归用来维护状态。给定的块传递(a)实例变量的名称,或者如果变量是递归的根,则传递nil
; (b)变量; (c)递归下降的深度;和(d)是当前变量的父亲,或者如果所述变量是递归的根,则为nil
。递归是深度优先的。 inspect_variables
函数使用它来建立一个字符串。 obj
参数是要迭代的对象; nl
是行分隔符; indent
是在每个级别应用的缩进;和sep
分隔名称和值。
编辑2:这并没有真正的答案添加任何你的问题,而是:只是为了证明我们并没有失去在重新实现什么,这里有一个all_variables
在each_variables
方面重新实现。
def all_variables(obj)
cur_depth = 0
root = [obj, {}]
tree = root
parents = []
prev = root
obj.each_variable do |name, var, depth, _parent|
next unless name
case depth <=> cur_depth
when -1 # We've gone back up
tree = parents.pop(cur_depth - depth)[0]
when +1 # We've gone down
parents << tree
tree = prev
else # We're at the same level
# Do nothing
end
cur_depth = depth
prev = tree[1][name] = [var, {}]
end
return root
end
我觉得它应该更短,但这可能是不可能的;因为我们现在没有递归,所以我们必须明确地维护栈(在parents
中)。但这是可能的,所以each_variable
方法也可以工作(我认为它有点更好)。
你可以使用'inspect'方法如果这是你的问题,请这样做。也许这就足够了。 – hurikhan77 2010-06-17 00:38:17