如何在Rails控制台中替换现有的类?

时间:2012-07-10 14:58:10

标签: ruby-on-rails ruby class

在控制台中:

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'

为什么在/home/zzz/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/logger.rb中使用记录器?

2 个答案:

答案 0 :(得分:3)

我会尽力回答你的第二个问题。那么,为什么Ruby使用其他Logger类而不是你自己定义的那个?

Ruby的一个基本功能是重新打开类。假设您已经在应用中定义并加载了一些类:

class A
  def foo
    puts 'foo'
  end
end

A.new.foo
#=> foo

如果之后Ruby解释器遇到类似的事情:

class A
  def bar
    puts 'bar'
  end
end

它不会重新定义类A,而只是将此定义附加到前一个定义。在已定义的结果中,类A获取新的实例方法bar

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

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

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

class A
  def foo
    puts 'new foo'
  end
end

A.new.foo
#=> new_foo

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

答案 1 :(得分:2)

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

您可以删除现有的课程

Object.send(:remove_const, :Logger)

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

class Logger
end

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

如果你在测试中这样做,你可能会对rspec 2.11中的新constant stubbing感兴趣