我正在读这本书“The Well-Grounded Rubyist”,这个随机的问题来找我。我知道在Ruby中可以重新打开一个类并覆盖该方法。
示例:
class A
def x
"First definition of x"
end
def x
"Second definition of x"
end
end
test = A.new
test.x #returns "Second definition of x"
基于上面的结果,我很好奇是否可以使用我自己的(随机)定义覆盖类方法attr_accessor
。这就是我的想法:
class Dummy
attr_accessor :test
def self.attr_accessor(method_name)
puts "Overwrite the default functionality of attr_accessor by printing this text instead."
end
end
d = Dummy.new
d.test #not sure why this returns nil instead of putting my message
Dummy.attr_accessor(test) #fails because of ArgumentError: wrong number of arguments (0 for 2..3)
对于上面的两个例子,我希望通过修补并提出问题来更好地理解Ruby。
答案 0 :(得分:6)
您位于正确的路径上,但是在运行时按顺序执行类定义。您需要在调用之前定义新方法,否则原始方法将用于该方法。
如果你这样做
class Dummy
def self.attr_accessor(method)
puts 'your message here'
end
attr_accessor :test # message printed
end
d = Dummy.new
d.test # raises an error, since we aren't creating a test method anymore
Dummy.attr_accessor(test) #will still fail, read on
test
是Ruby中的一个方法,对应于shell中内置的test
。这种方法就是你最后收到错误的原因。你真正想要的是
Dummy.attr_accessor(:test1)
请注意,您无法调用普通attr_accessor
,因为它是类定义中self
类实例的私有方法。 (IOW,attr_accessor
是Module
上的私有实例方法,在执行类定义时,self
是Module
的实例)
答案 1 :(得分:3)
是的,这是可能的,你刚才做到了!
d.test #not sure why this returns nil instead of putting my message
返回nil
因为您在下面重新定义它之前使用了attr_accessor :test
,因此,Ruby执行了attr_accessor
的默认行为并在Dummy
类中创建了一个成员和访问者。它返回nil
,因为该成员的值未设置... nil
。
Dummy.attr_accessor(test) #fails because of ArgumentError: wrong number of arguments (0 for 2..3)
没有因为你的想法而失败。此通话有效:
Dummy.attr_accessor("method_name")
问题是您正在调用名为test
的方法,而不是提供所有预期值。请参阅Kernel.test()
http://www.ruby-doc.org/core-1.9.3/Kernel.html#method-i-test的文档。
您看到的错误消息是因为您错误地调用了测试方法,而不是因为重新定义attr_accessor
时出错。
答案 2 :(得分:2)
在Dummy
班级中调用了Class
attr_accessor
版本的Dummy
,因为attr_accessor
版本尚未在调用class Dummy
def self.attr_accessor(method_name)
puts "Overwrite the default functionality of attr_accessor by printing this text instead."
end
attr_accessor :test
end
时定义。如果在调用之前移动定义,行为将会有所不同。
test
这将在读取类定义时打印您的消息。当您尝试在Dummy
对象上调用方法{{1}}时,您将收到错误,因为没有定义此类方法。
答案 3 :(得分:1)
如果您改变attr_accessor
来电和def self.attr_accessor
的订单会怎样?我不知道是否会解决这个问题,但你肯定不能按照你的顺序做到这一点。请记住,当您使用类似class Dummy
的行打开类时,您将实时执行实际代码。所以首先你正在调用attr_accessor
和然后你正试图重新定义它。好吧,我不知道你是否可以像这样重新定义它,但你确实需要在之前重新定义它,或者你将调用旧版本!