在 Ruby 中,如何编写一个方法来显示任何对象的实例变量名称及其值
给定 Ruby(on Rails)中的任何对象,我如何编写一个方法,以便它显示该对象的实例变量名称及其值,如下所示:(
@x: 1
@y: 2
@link_to_point: #<Point:0x10031b298 @y=20, @x=38>
更新: inspect
除了大对象之外,很难从 200 行输出中分解变量,就像在 Rails 中,当您在 request.inspect
或 self.inspect
中ActionView 对象)
我还希望能够将
打印到每个实例变量值的末尾,以便在网页上很好地打印它们。
现在的困难似乎是不是每个实例变量都有访问器,因此不能用 obj.send(var_name) 调用它
(var_name 删除了“@”,因此“@x”变成了“x”)
<更新:我想使用递归,它可以打印出更高级的版本:
#<Point:0x10031b462>
@x: 1
@y: 2
@link_to_point: #<Point:0x10031b298>
@x=38
@y=20
Given any object in Ruby (on Rails), how can I write a method so that it will display that object's instance variable names and its values, like this:
@x: 1
@y: 2
@link_to_point: #<Point:0x10031b298 @y=20, @x=38>
(Update: inspect
will do except for large object it is difficult to break down the variables from the 200 lines of output, like in Rails, when you request.inspect
or self.inspect
in the ActionView object)
I also want to be able to print <br>
to the end of each instance variable's value so as to print them out nicely on a webpage.
the difficulty now seems to be that not every instance variable has an accessor, so it can't be called with obj.send(var_name)
(the var_name has the "@" removed, so "@x" becomes "x")
Update: I suppose using recursion, it can print out a more advanced version:
#<Point:0x10031b462>
@x: 1
@y: 2
@link_to_point: #<Point:0x10031b298>
@x=38
@y=20
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我可能会这样写:
Object#all_variables
方法生成一个数组,其中包含 (0) 给定对象和 (1) 将实例变量名称映射到包含 (0) 实例变量的数组的哈希值,以及(1) 哈希映射......因此,它为您提供了一个很好的递归结构。 string_variables 函数可以很好地打印出该哈希值;inspect_variables
只是一个方便的包装器。因此,printspect_variables(foo)
为您提供了一个换行符分隔的选项,而printinspect_variables(foo, "
为您提供了版本带有 HTML 换行符。如果您想指定缩进,也可以这样做:gt;\n")
printspectr_variables(foo, "\n", "|---")
生成(无用的)人造树格式而不是制表符基于-的缩进。应该有一种明智的方法来编写一个编辑1:我想到了一些事情。each_variable
函数,您可以向该函数提供回调(不必分配中间存储);如果我想到什么,我会编辑这个答案以包含它。这是另一种编写方式,我认为这种方式稍微好一些:
Object#each_variable
方法采用许多可选参数,这些参数不是设计为由用户指定的;相反,递归使用它们来维护状态。给定的块被传递 (a) 实例变量的名称,如果变量是递归的根,则传递 nil ; (b) 变量; (c) 递归下降的深度; (d) 当前变量的父级,如果所述变量是递归的根,则为 nil。递归是深度优先的。inspect_variables
函数使用它来构建一个字符串。obj
参数是要迭代的对象;nl
是行分隔符;indent
是要在每个级别应用的缩进;和sep
分隔名称和值。编辑2:这并没有真正为您的问题的答案添加任何内容,但是:只是为了证明我们在重新实现中没有丢失任何内容,这里是
all_variables 就
each_variables
而言。我觉得它应该更短,但那可能不可能;因为我们现在没有递归,所以我们必须显式维护堆栈(在
parents
中)。但这是可能的,因此each_variable
方法也同样有效(而且我认为它更好一点)。I would probably write it like this:
The
Object#all_variables
method produces an array containing (0) the given object and (1) a hash mapping instance variable names to arrays containing (0) the instance variable and (1) a hash mapping…. Thus, it gives you a nice recursive structure. Thestring_variables
function prints out that hash nicely;inspect_variables
is just a convenience wrapper. Thus,print inspect_variables(foo)
gives you a newline-separated option, andprint inspect_variables(foo, "<br />\n")
gives you the version with HTML line breaks. If you want to specify the indent, you can do that too:print inspect_variables(foo, "\n", "|---")
produces a (useless) faux-tree format instead of tab-based indenting.There ought to be a sensible way to write anEdit 1: I thought of something.each_variable
function to which you provide a callback (which wouldn't have to allocate the intermediate storage); I'll edit this answer to include it if I think of something.Here's another way to write it, which I think is slightly nicer:
The
Object#each_variable
method takes a number of optional arguments, which are not designed to be specified by the user; instead, they are used by the recursion to maintain state. The given block is passed (a) the name of the instance variable, ornil
if the variable is the root of the recursion; (b) the variable; (c) the depth to which the recursion has descended; and (d), the parent of the current variable, ornil
if said variable is the root of the recursion. The recursion is depth-first. Theinspect_variables
function uses this to build up a string. Theobj
argument is the object to iterate through;nl
is the line separator;indent
is the indentation to be applied at each level; andsep
separates the name and the value.Edit 2: This doesn't really add anything to the answer to your question, but: just to prove that we haven't lost anything in the reimplementation, here's a reimplementation of
all_variables
in terms ofeach_variables
.I feel like it ought to be shorter, but that may not be possible; because we don't have the recursion now, we have to maintain the stack explicitly (in
parents
). But it is possible, so theeach_variable
method works just as well (and I think it's a little nicer).我明白了... Antal 必须在这里给出高级版本...
简短版本可能是:
或将其作为字符串返回:
或更短:
I see... Antal must be giving the advanced version here...
the short version then probably is:
or to return it as a string:
or shorter:
这是一个简单的 我为另一个问题编写的 JSON 发射器:
这就是所有的魔力,真的。现在,我们只需要对某些类型进行一些简单的默认设置,在这些类型中,全面检查实际上没有意义(
nil
、false
、true
、数字等):This is a quick adaptation of a simple JSON emitter I wrote for another question:
That's all the magic, really. Now we only need some simple defaults for some types where a full-on inspect doesn't really make sense (
nil
,false
,true
, numbers, etc.):像这样?
有关instance_variables的Ruby文档。
这个概念通常被称为“内省”(审视自己)。
Like this?
Ruby Documentation on instance_variables.
The concept is commonly called "introspection", (to look into oneself).