0

我有一个变量,可以调用它@foo。我希望它是一个字符串,所以我调用@foo.downcase. 有时它为零,我会得到这个错误:

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>

我想做的是写一些代码告诉我 nil 实际上是@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. 我想要变量的人类可读名称。是否有可能以编程方式获取变量的名称?

4

4 回答 4

1

你想要的有点乱。

这是完成此任务的正确方法:

@foo && @foo.downcase

或者你可以使用 rails 库:

require 'active_support'

@foo.try(:downcase)
于 2012-06-10T18:26:42.313 回答
1

目前没有任何方法可以做到这一点。

变量只是引用,而不是对象本身。如果您使用点表示法来调用方法,例如downcase,则该方法正在对对象进行操作,而不是对变量进行操作。您示例中的对象是单例nil;如果nil在一个地方分配了一个属性来命名它被分配到的变量,那么相同的属性将适用于所有nils。

更一般地说,一个对象可能有许多指向它的变量/引用,因此没有很好的方法来确定应该将哪个变量名保存在对象中。但是,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" 
于 2012-06-10T19:58:56.290 回答
1

您可以使用 instance_variable_get(:@foo) 从符号中获取实例变量,这只会为您提供值。

但你可以这样做:

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
于 2012-06-10T20:05:18.297 回答
0

编辑: 可能最好的方法(见 mu 的评论)就是确保你正在使用一个字符串:

@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

希望有帮助!

于 2012-06-10T18:26:06.613 回答