类方法中的实例变量

时间:2016-03-15 03:25:40

标签: ruby

我在SO上找到了这个基于'tee'实现的整洁的委托人:

https://stackoverflow.com/a/6410202/2379703

我很好奇@targets(实例变量)的意思是在类方法的上下文中意味着什么:

require 'logger'

class MultiDelegator
  def initialize(*targets)
    @targets = targets
  end

  def self.delegate(*methods)
    methods.each do |m|
      define_method(m) do |*args|
        @targets.map { |t| t.send(m, *args) }
      end
    end
    self
  end

  class <<self
    alias to new
  end
end

log_file = File.open("debug.log", "a")
log = Logger.new MultiDelegator.delegate(:write, :close).to(STDOUT, log_file)

我得到它定义方法write / close但是@targets在这一点上甚至没有被定义,因为.to(别名为new)还没有被调用所以我假设@targets是nil。

任何人都可以解释一下这段代码的工作方式吗? ruby甚至没有尝试访问/解析@targets,直到尝试调用有问题的方法,记录器在实例化后会被调用吗?

1 个答案:

答案 0 :(得分:1)

在类上调用define_method方法来创建实例方法。在该方法中,self(和实例变量)是类的实例。

例如:

class Foo
  @bar = "CLASS"
  def initialize
    @bar = "INSTANCE"
  end
  def self.make_method
    define_method :whee do
      p @bar
    end
  end
end

begin
  Foo.new.whee
rescue NoMethodError=>e
  puts e
end
  #=> undefined method `whee' for #<Foo:0x007fc0719794b8 @bar="INSTANCE">

Foo.make_method
Foo.new.whee
#=> "INSTANCE"

您可以随时询问有关从未创建过的实例变量是正确的:

class Bar
  def who_dat
    puts "@dat is #{@dat.inspect}"
  end
end

Bar.new.who_dat
#=> dat is nil

该语言的其他方面也是如此。只要方法中的代码语法有效,就可以定义它,即使调用它会导致运行时错误:

class Jim
  def say_stuff
    stuff!
  end
end
puts "Good so far!"
#=> Good so far!

j = Jim.new
begin
  j.say_stuff
rescue Exception=>e
  puts e
end
#=> undefined method `stuff!' for #<Jim:0x007f9c498852d8>

# Let's add the method now, by re-opening the class
class Jim # this is not a new class
  def stuff!
    puts "Hello, World!"
  end
end

j.say_stuff
#=> "Hello, World!"

在上面我定义了一个语法上有效的say_stuff方法,但它调用了一个不存在的方法。这是找到的。该方法已创建,但未调用。

然后我尝试调用该方法,它会导致错误(我们会抓住并妥善处理)。

然后我将stuff!方法添加到类中。现在我可以运行say_stuff方法(与之前相同的实例!)并且它运行正常。

最后一个示例显示了定义方法如何不运行它,或者要求它在运行时甚至可以工作。每次调用时都会动态评估它(并且仅在那时)。