2012-06-10 36 views
0

我有一个变量叫它@foo。我期望它是一个字符串,所以我打电话@foo.downcase。有时是零,我会得到这个错误:Ruby中的Self的变量名称

NoMethodError: undefined method `downcase' for nil:NilClass 
    from (irb):4 
    from /Users/schneems/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main> 

我想要做的就是编写一些代码来告诉我,零实际上是@foo

NoMethodError: undefined method `downcase' on variable @foo, variable is a nil:NilClass 
    from (irb):4 
    from /Users/schneems/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main> 

要做到这样的事情,我会需要以编程方式获取变量的名称。

问题:是否有可能以编程方式获得变量的名称ruby?

我在寻找的东西,其输出是这样的:

@foo.magical_variable_method #=> '@foo' 
bar.magical_variable_method  #=> 'bar' 
AweSome.magical_variable_method #=> 'AweSome' 
$wat.magical_variable_method #=> '$wat' 

我不想变量的值,也不关心它是否nil。我想要这个变量的人类可读的名字。是否有可能通过编程方式获得变量的名称?

+0

你能澄清你想要的东西多一点?你在寻找一种方法来查看'@ foo'是否为'nil',或者寻找一种方法来返回所有当前为'nil'的变量?或者也许完全是另一回事? – redhotvengeance

+0

我更新了这个问题,希望能更清楚一点,谢谢你的提问。 – Schneems

+1

看看这个http://stackoverflow.com/questions/58482/ruby-get-a-variables-name – shime

回答

0

编辑:也许是最好的方式(见亩的评论)是只要确保你有一个字符串的工作:

@foo.to_s.downcase 

你并不需要获得“名”做这个。你可以只使用条件:

# Downcased if @foo's a string, empty string otherwise: 
(String === @foo)? @foo.downcase : '' 

或者,如果你打算在很多地方做这个,不希望有包裹每一个在有条件的,猴子补丁NilClass和添加虚拟downcase方法:

class NilClass 
    def downcase 
     return '' 
    end 
end 

希望帮助!

+2

猴子补丁'NilClass'是疯狂的,并要求麻烦。如果你想将'nil'转换为空字符串,那么你应该'@ foo.to_s.downcase',这样读取代码的人至少会得到一个提示,说明'@ foo'有点特别。 –

+0

@ muistooshort - 我会说在这种情况下比平常更安全,因为很明显'downcase'应该返回。虽然认为这是一条危险的道路,但......无论如何,'to_s'绝对是最好的,我忘记了它的一切(dur)。现在修复。干杯! –

+0

我希望从名为'@ foo'的变量以某种方式输出“'@ foo'”,如果它被命名为'@ bar',我想要名为“'bar”的变量。我很熟悉如何防止方法错误,我想要的是以编程方式从ruby实际得到的变量名称,正如问题所述。 – Schneems

1

你想要的是有点混乱。

下面是正确的方法完成这个任务:

@foo && @foo.downcase 

或者你可以使用轨道库:

require 'active_support' 

@foo.try(:downcase) 
+0

那根本不能回答我的问题,那就是如何防止调用一个不存在的变量的方法。我想从名为'@ foo'的变量以某种方式输出“'@ foo'”的字符串,如果它被命名为@bar,我想要名为“'@ bar'的变量”。 – Schneems

1

目前还不能以任何方式做到这一点。

变量只是引用,而不是对象本身。如果使用点符号来调用方法,如downcase,则该方法在对象上操作,而不是变量。在你的例子中的对象是单身人士nil;如果nil在一个地方有一个属性分配给它分配给它的变量,则该属性将适用于所有nil s。

更一般地说,一个对象可能有很多变量/引用指向它,所以没有什么好的方法可以确定哪个变量名应该保存在对象中。但是,在Ruby中有一种特殊的处理方式来为一个常量赋一个类;在这种情况下,类对象记得第一常数它分配到的名称,例如:

$ irb 
1.9.3p194 :001 > Foo = Class.new do 
1.9.3p194 :002 > attr_accessor :foo 
1.9.3p194 :003?> end 
=> Foo 
1.9.3p194 :004 > Bar = Foo 
=> Foo 
1.9.3p194 :005 > Foo.name 
=> "Foo" 
1.9.3p194 :006 > Bar.name 
=> "Foo" 
+0

想想吧,尽管如此,您会认为实现将能够在内存中保留发送消息的变量的名称 - 只是该对象本身不会保存该信息。我打赌,在这种情况下,变量名称被解析器所了解,但是Ruby的实际发送消息的部分是未知的;但人们不得不挖掘来源以找出答案。 – echristopherson

+1

局部变量通常不会被保留。它们只是通过索引到一个局部变量数组中。一些实现也有一个优化,即它们将一个数组中的少量实例变量直接保存在对象头中,这些实例变量也只是按数字进行索引。当然,优化编译器通常会完全消除变量。 –

1

您可以从符号获取实例变量,instance_variable_get(:@富) 其中只会给你价值。

但你可以这样做:

puts "I'm gonna call @foo now, people" 
some_obj.instance_variable_get(:@foo) 

你也可以做你想要观看的attrs了method_missing钩子。不要为@foo存取方法,赶上呼叫的method_missing并转发给一些通用的实现,如instance_variable_get

未经测试的尝试:

def method_missing(method_name, *args) 
    super(method_name, *args) unless watched_attributes.include?(method_name) 
    attr = ":@#{method_name.to_str}" 
    log.debug "Calling watched attribute #{attr}" 
    val = instance_variable_get(method_name) 
    log.debug "#{attr} was nil omg!" unless val 
    val 
end