我可能會寫這樣的:
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