Ruby:使用模块扩展实例时执行某些操作

当使用Object #extend扩展实例时,我想执行一些代码。 有点像实例化类而不是模块时初始化。

这是扩展文档示例 :

 module Mod def hello "Hello from Mod.\n" end end class GoodKlass def hello "Hello from GoodKlass.\n" end end class BadKlass # something totally different end good = GoodKlass.new good.hello #=> "Hello from GoodKlass.\n" good.extend(Mod) #=> # good.hello #=> "Hello from Mod.\n" 

例如,如果使用ModextendGoodKlass实例以外的其他东西,我想显示警告或加注:

 bad = BadKlass.new bad.extend(Mod) #=> raise "Mod cannot extend BadKlass" 

您可以在模块中定义self.extended :

 module Mod def self.extended(base) raise "Cannot extend #{base}" unless base.is_a?(GoodKlass) end def hello "Hello from Mod.\n" end end 

你对这个问题的评论,回复我的评论,证实了我的怀疑。 你所做的不是扩展类,而是扩展类的特定实例。 让我们看看你的代码做了什么。

 good = GoodKlass.new good.hello #=> "Hello from GoodKlass.\n" GoodKlass.hello #=> NoMethodError: undefined method `hello' for GoodKlass:Class good.extend(Mod) GoodKlass.hello #=> NoMethodError: undefined method `hello' for GoodKlass:Class good.hello #=> "Hello from Mod.\n" very_good = GoodKlass.new very_good.hello #=> "Hello from GoodKlass.\n" 

如您所见, hello仅在实例上定义。

注意

 GoodKlass.methods.include?(:hello) #=> false good.methods.include?(:hello) #=> true 

如果这不是你想要的,有两种可能性。 我参考

 class VeryGoodKlass end 

在讨论两者。

1. Extend课程

在你的应用程序中(对问题的ref评论),这种方法可以让你创建一个类方法File::jpg? 哪个会被调用File.jpeg?("cat.jpg")

要将Mod的实例方法hello转换为GoodKlass的类方法,您需要使用Object#extend扩展类(不是类的实例)。 要防止其他类扩展模块,请使用模块中的回调方法Module#extended 。

 module Mod def self.extended(base) raise ArgumentError, "Cannot extend #{base}" unless base == GoodKlass end def hello "Hello from Mod" end end class GoodKlass def self.hello "Hello from GoodKlass" end end GoodKlass.hello #=> "Hello from GoodKlass" GoodKlass.extend(Mod) GoodKlass.hello #=> "Hello from Mod" VeryGoodKlass.extend(Mod) #=> ArgumentError: Cannot extend VeryGoodKlass 

2.在课堂中包含模块

要将Mod的实例方法添加到GoodKlass (保留它们的实例方法),您需要使用Module GoodKlass包含该模块。 要防止其他类包含模块,请使用模块中的回调方法#included 。

在您的应用程序中,这将允许您编写实例方法File#jpg? 1使用如下:

 f = File.new('cat.jpg') f.jpg? 

你可以这样做。

 module Mod def self.included(base) raise ArgumentError, "Cannot include #{base}" unless base == GoodKlass end def hello "Hello" end end class GoodKlass end good = GoodKlass.new GoodKlass.include(Mod) GoodKlass.hello #=> NoMethodError: undefined method `hello' for GoodKlass:Class good.hello #=> "Hello" VeryGoodKlass.include(Mod) #=> ArgumentError: Cannot include VeryGoodKlass 

1.也许File.basename(f.path).end_with?(".jpg")