注意:准备这个答案需要几个小时。与此同时,janko-m 的回答很好。
Rails 或 Shrine 的人已经将一个人在 Ruby 中可以做什么的知识推到了一个远远超出阅读 Ruby 书籍所能想象的水平,而我已经阅读了十几本。
99 % 的时间包括形式
include SomeModule
并SomeModule
在一个单独的文件中定义,该some_module.rb
文件以require 'some_module'
.
这个
include ImageUploader::Attachment.new(:image)
由于许多原因很棘手。
=== 内部类 ===
98% 的时间,一个类是一个外部对象,它主要包含 def 方法,一些包含和一些类实例变量。我没有写过大量的 Ruby 代码,但在特殊情况下只写过一次内部类。从外部看,它只能通过提供完整的访问路径来使用,例如Shrine::Attachment
或Shrine::Plugins::Base::AttacherMethods
。
我不知道子类“继承”内部类以便可以编写
ImageUploader::Attachment
=== Module.new ===
如果您阅读了足够多的 Ruby 文档,您会发现 1'000 次类和模块之间的区别在于我们无法实例化模块。模块仅用于围绕一个人的代码或(主要)在类中的混合方法创建命名空间(更准确地说,包括 SomeModule 创建一个匿名超类,以便方法的搜索路径从类到 SomeModule,然后到超类(Object if未明确定义))。
因此,我会在酷刑下发誓,Module 没有新方法,因为没有必要。但是有一个,它返回一个匿名模块。
好吧,话虽如此,这里我们实例化的是类ImageUploader::Attachment
,而不是模块,甚至Module.new
实例化了类Module
。
=== 包含表达式 ===
对于不使用常量而是使用表达式的 1% 的包含,表达式必须返回一个模块。你对为什么 Attachment 继承自 Module 有了答案。如果没有这样的继承,include 就会抱怨。运行以下代码,它可以工作。但是如果你取消注释
# include ImageUploader::Attachment_O.new(:image)
在图片类中,有一个错误:
t.rb:28:in `include': wrong argument type Shrine::Attachment_O (expected Module) (TypeError)
from t.rb:28:in `<class:Picture>'
from t.rb:27:in `<main>'
文件 t.rb :
class Shrine
class Attachment_O
def initialize(parm=nil)
puts "creating an instance of #{self.class.name}"
end
end
class Attachment_M < Module
def initialize(parm=nil)
puts "creating an instance of #{self.class.name}"
end
end
end
print 'Attachment_O ancestors '; p Shrine::Attachment_O.ancestors
print 'Attachment_M ancestors '; p Shrine::Attachment_M.ancestors
class ImageUploader < Shrine
end
imupO = ImageUploader::Attachment_O.new
imupM = ImageUploader::Attachment_M.new
print 'imupO is a Module ? '; p imupO.is_a?(Module)
print 'imupM is a Module ? '; p imupM.is_a?(Module)
class Picture
# include ImageUploader::Attachment_O.new(:image)
include ImageUploader::Attachment_M.new(:image)
end
执行 :
$ ruby -w t.rb
Attachment_O ancestors [Shrine::Attachment_O, Object, Kernel, BasicObject]
Attachment_M ancestors [Shrine::Attachment_M, Module, Object, Kernel, BasicObject]
creating an instance of Shrine::Attachment_O
creating an instance of Shrine::Attachment_M
imupO is a Module ? false
imupM is a Module ? true
creating an instance of Shrine::Attachment_M
这就是全部:
乍一看,Attachment 的定义似乎很奇怪,因为它是空的。我没有详细研究神殿.rb,但我看过这个:
# Load a new plugin into the current class ...
def plugin(plugin, *args, &block)
...
self::Attachment.include(plugin::AttachmentMethods) if defined?(plugin::AttachmentMethods)
显然 Attachment 稍后会通过包含一个模块来填充方法,或者更准确地说,include
为 Attachment 创建一个匿名超类,它指向 AttachmentMethods,以便方法搜索机制在包含的模块中找到方法。另请参阅继承在 Ruby 中如何工作?
.