让我们打开课程Module并为其添加一个方法:
class Module
def foo
puts "phew"
end
end
Run Code Online (Sandbox Code Playgroud)
我可以通过这样做来调用这个方法,
Class.foo
Run Code Online (Sandbox Code Playgroud)
这是可以理解的,因为Class是Class超类的类Module.所以它可以调用中定义的实例方法Module.

现在,bar下面的方法是在Module'eigenclass 上定义的:
class Module
def self.bar
puts "bar"
end
end
Run Code Online (Sandbox Code Playgroud)
但现在
Class.bar
Run Code Online (Sandbox Code Playgroud)
也有效.
有人可以解释一下如何在特征类Class中访问方法Module吗?
我想我现在明白了.方法查找不像我之前解释的那样工作.当我这样做的时候Class.foo,这个方法是在特征Class类中进行搜索,然后是超类,它是本Module征类的特征类,直到它的特征类BasicObject,此时它会转向自身(就像蛇吃它自己的尾巴)来寻找方法Class(就像'eigenclass Class的超类BasicObject一样)然后到它的超类Module,它找到了方法.
类似地,当我这样做时Class.bar,方法在Class's eigenclass中搜索,然后在Module它找到它的本征类中搜索.
当我做
class Class
def check
puts "class instance method"
end
end …Run Code Online (Sandbox Code Playgroud) 我创建了一个包含常量NAME和方法的模块hello.如果类包含模块,则两个定义应在不同范围内可见.
module A
NAME = 'Otto'
def self.included(base)
base.extend(ClassMethods)
end
def hello(name = 'world')
self.class.hello(name)
end
module ClassMethods
def hello(name = 'world')
"Hello #{name}!"
end
end
end
class B
include A
def instance_scope
p [__method__, hello(NAME)]
end
def self.class_scope
p [__method__, hello(NAME)]
end
class << self
def eigen_scope
p [__method__, hello(NAME)]
end
end
end
B.new.instance_scope
B.class_scope
B.eigen_scope
#=> script.rb:34:in `eigen_scope': uninitialized constant Class::NAME (NameError)
from script.rb:41
Run Code Online (Sandbox Code Playgroud)
但是常量在本征类的实例方法范围中是不可见的class << self.
有没有办法使模块更健壮,并在上面的错误范围内提供常量?
这主要是一个"学术"的,但在这里:
根据这个Ruby eigenclass图(略加编辑):
BasicObject.singleton_class.singleton_class.superclass是Class.
但是,在Ruby解释器(Ruby v2.5.1)上运行它,事实证明它BasicObject.singleton_class.singleton_class.superclass是#<Class:Class>和不是Class.因此,图表是说谎还是我遗漏了什么?
该图来自我在Freenode的Ruby IRC聊天的用户.但是,它被多次引用给许多其他用户,它被视为Ruby对象模型圣经.
在对象或类上定义单例方法之前是否存在Eigenclasses.即当定义单例方法或类方法时,它们是否总是存在或存在?
首先,让我们添加一个方法来检索"从此博客帖子中复制"的特征类
class Object
def eigenclass
class << self
self
end
end
end
Run Code Online (Sandbox Code Playgroud)
然后创建一个简单的类
class A
end
puts A.new.eigenclass.superclass # => A
puts Class.new.eigenclass.superclass # => #<Class:Object>
Run Code Online (Sandbox Code Playgroud)
我期待第二次投入输出Class
任何线索为什么会这样?
这是交易:我需要用一些方法扩展class Box的特定实例.我需要包含实时内部模块的方法,我希望Box实例能够动态地包含模块.现在我使用带有eval的钩子:
class Box
def after_initialize
if self.injected_module.present?
eval("class << self; include #{self.injected_module}; end")
end
end
end
Run Code Online (Sandbox Code Playgroud)
它工作得很好但是当我使用eval时我真的感觉很脏.我正在寻找类似的东西:
module_to_inject = self.injected_module
self.eigenclass.class_eval do
include module_to_inject
end
Run Code Online (Sandbox Code Playgroud)
但是我无法让eigenclass在没有monkeypatching类的情况下运行class_eval:
class Box; def eigenclass; class << self; self; end end end
Run Code Online (Sandbox Code Playgroud)
有一种美丽(可靠)的方式让我这样做吗?
我无法理解红宝石中特征类或单例类的概念。我读了很多,认为 eigenclass是一个类的类。这对我来说没有意义,因为对我来说,类的类实际上是Class因为所有类实际上都是类的实例Class。
另一件我不太明白的事情是下面的说法:类方法实际上是类 eigenclass 的实例方法。特征类可以通过以下方式访问:
YourClass = Class.new
class << YourClass
def class_method
end
end
Run Code Online (Sandbox Code Playgroud)
但是,如果特征类确实是 YourClass 类(即Class),那么前面的代码不应该打开该类Class并向其添加实例方法class_method,使其可供所有未来的实例访问(即在未来)?
我实际上感觉单例类与Class. 当你这样做时:
class MyClass
end
MyClass.singleton_class
Run Code Online (Sandbox Code Playgroud)
你得到的#<Class:MyClass>结果与输出不同MyClass.class => Class
#<Class:MyClass>那个输出是什么?这与命名空间无关,否则会有两个:Class::MyClass...
我正在寻找对本征类概念的简单且明确的解释,以澄清我的想法。
好的,所以我想在Ruby中做一些元编程,我有点困惑.根据我读过的几篇文章(像这一篇),为了动态地将类方法添加到Ruby类中,你必须使用类的单例类:
class Klass
end
class << Klass
self.define_method(:foo) { return "foo" }
end
Run Code Online (Sandbox Code Playgroud)
这是为什么,与此有何不同?
class Klass
self.define_method(:foo) { return "foo" }
end
Run Code Online (Sandbox Code Playgroud)
(对不起,如果这个问题包含任何错误的假设.就像我说的,我有点困惑.)
这部分有效:
class Example1
@@var1= "var1 in the Example1"
def get_var1
@@var1
end
end
example1 = Example1.new
example1.get_var1
# => "var1 in the Example1"
Run Code Online (Sandbox Code Playgroud)
但如果我尝试eigenclass:
def example1.get_var1
@@var1
end
example1.get_var1
# NameError: uninitialized class variable @@var1 in Object
# from (pry):128:in `get_var1'
Run Code Online (Sandbox Code Playgroud)
红宝石看起来@@var1在Object代替Example.
我已经在Ruby 1.9.3和2.0中测试了这个代码并得到了相同的结果.
为什么会这样?
第二件事,我们可以将其关闭(因此example.get_var1不会在Object中查找类变量)吗?
我正在寻找一种方法来获取本征类的实例,因为每个本征类只有一个实例.
我可以通过ObjectSpace来测试每个本征类,但我猜它很昂贵.
奇怪的是,我必须得到每个对象的本征类来测试匹配,因为is_a?这还不够:
class A; end
class B < A; end
AA = class << A; self; end
p A.is_a? AA #=> true
p B.is_a? AA #=> true!!!!
Run Code Online (Sandbox Code Playgroud)
我希望有一个Class#instance或Class#instances方法来获取类(或本征类)的实例.
最直接的方法是从特征类中提取实例inspect,但我想知道我是否可以依赖它:
p AA #=> #<Class:A>
instance = Object.const_get(AA.inspect.match(/^#<Class:(\w+)>$/)[1])
p instance #=> A
# (this works for class' eigenclass)
Run Code Online (Sandbox Code Playgroud)
我的用例是我必须得到类方法的类,但是Method#owner给了我本征类,并Method#receiver给了我当前的接收器:
# Continuing previous example
def A.f; end
mtd = B.method(:f)
p mtd.owner #=> #<Class:A>
p mtd.receiver #=> B
# I …Run Code Online (Sandbox Code Playgroud)