2

在控制台中:

class Logger
end
l = Logger.new

抛出错误:ArgumentError: wrong number of arguments (0 for 1) from /home/zzz/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/logger.rb:268:in 'initialize'

为什么要使用 Logger in /home/zzz/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/logger.rb

4

2 回答 2

4

我会试着回答你的第二个问题。那么,为什么 Ruby 使用其他Logger类而不是您尝试定义的类呢?

Ruby 的基本特性之一是类的重新开放。假设您的应用程序中已经定义并加载了一些类:

class A
  def foo
    puts 'foo'
  end
end

A.new.foo
#=> foo

如果在那之后 Ruby 解释器遇到类似的情况:

class A
  def bar
    puts 'bar'
  end
end

它没有重新定义 class A,而只是将此定义附加到前一个定义中。在结果中已经定义的类A得到了新的实例方法bar

A.new.foo # still works
#=> foo
A.new.bar # new method
#=> bar

由于 Ruby 处理方法调用的方式,在类的第二次定义(实际上是重新打开)之前A初始化的类的所有实例也会获得这个新方法。因此,每次重新打开一个类时,都会向该类本身以及该类的所有先前初始化的实例添加新功能。Abar

重新打开类还允许重写现有类的方法:

class A
  def foo
    puts 'new foo'
  end
end

A.new.foo
#=> new_foo

考虑到这一特性以及 Rails 已经Logger为您加载了标准类这一事实,您的定义只会重新打开该类,但甚至不会更改任何内容。

于 2012-07-10T15:18:03.550 回答
2

那个类已经被加载了,大概是因为 rails 正在使用它:你没有重新定义这个类,你只是重新打开它。

您可以删除现有的课程

Object.send(:remove_const, :Logger)

在这种情况下,以前称为的类Logger仍然存在,只是不再绑定到常量Logger,所以当你这样做时

class Logger
end

您将创建一个新课程,而不是重新打开旧课程。当然,您最终可能会破坏假设存在旧 Logger 类的代码。

如果您在测试中这样做,您可能会对rspec 2.11中的新常量存根感兴趣

于 2012-07-10T15:09:07.560 回答