2012-03-27 50 views
8

我有以下代码:不理解类,模块和类<<自我方法

class MyClass 
    module MyModule 
    class << self 

     attr_accessor :first_name 

     def myfunction 
     MyModule.first_name = "Nathan" 
     end 

    end 
    end 
end 

当我调用该方法myfunction像这样,它工作正常:

> me = MyClass::MyModule.myfunction 
=> "Nathan" 
> me 
=> "Nathan" 

但如果我删除class << self并将self.前缀添加到myfunction,则不起作用。

例如:

class MyClass 
    module MyModule 

    attr_accessor :first_name 

    def self.myfunction 
     MyModule.first_name = "Nathan" 
    end 

    end 
end 


> me = MyClass::MyModule.myfunction 
NoMethodError: undefined method `first_name=' for MyClass::MyModule:Module 

我想了解class << self方法。我认为这是一种将self.前缀添加到其内部的所有方法的方法,但如果这是真的,那么为什么它不起作用,如果我将其删除并手动为每个方法添加前缀self.

在此先感谢您的帮助。

+2

如果你真的想学习Ruby的元编程的细节,我建议[Ruby的元编程书由保罗·佩罗塔(http://pragprog.com/book/ppmetr/metaprogramming-ruby) 。 – sarnold 2012-03-28 00:04:41

回答

7

这是因为您的attr_accessor :first_name也包含class << self

要做到这一点,你建议的方式,你可以使用mattr_accessor像这样:

require 'active_support' 

class MyClass 
    module MyModule 

    mattr_accessor :first_name 

    def self.myfunction 
     MyModule.first_name = "Nathan" 
    end 

    end 
end 
+0

所以这是一个依赖于active_support的特定于rails的东西?我假设mattr_accessor是一个模块特定的setter/getter方法? – Nathan 2012-03-28 03:22:39

+0

这是正确的。无论好坏,“mattr_accessor”只能通过Rails访问。 – jnevelson 2012-03-28 06:44:09

+0

有一些有时我希望在常规Ruby中可用的东西,不仅仅是Rails或ActiveRecord。 – 2012-04-05 22:41:56

4

为了更好地理解如何可以达到你想要什么,看看下面的例子:

module PrintingModule 

    def self.included(object) 
    object.extend(ClassMethods) 
    end 

    module ClassMethods 

    def class_method_of_class 
     puts "I am class #{self.name}" 
    end 

    end 

    def instance_method_of_class 
    puts "My name is: #{@name}" 
    end 

    class << self 
    def static_module_method 
     puts "Printer version 1.0" 
    end 
    end 
end 

class SomeObject 
    include PrintingModule 
    def initialize(name) 
    @name = name 
    end 
end 

object = SomeObject.new("Something") 
object.instance_method_of_class 
SomeObject.class_method_of_class 
PrintingModule.static_module_method 

我希望这是更清楚了,请注意,这只是一种可能的方式(也有其他人)

UPDATE: 我会尽量更具体。当你在模块上定义实例/单例方法时,你真正在做的是你定义了包含该模块的类的实例方法,另一方面,在模块上定义的类方法将成为该模块的类方法。第二个想到的是,attr_accessor为给定参数的getter和setter创建实例方法。

现在要回答您的问题的一部分,在第一个示例中,您将在模块的类上创建3个类方法。在第二个例子中,你正在创建1个类方法,你试图访问另一个类方法(setter),但你的getter和setter被定义为实例方法=它们将成为包含你的模块的类方法的实例,你不能以这种方式得到他们=你无法获得你的获得者和制定者。 至于说明自我,以及我不熟练,但据我所知,当你使用“类< <自我”你打开对象的特征类(每个对象有它自己的任何一个)(注意类,模块或类的实例当然也是对象),您正在定义实例方法。对象的类方法Ruby =对象的本征类的实例方法。所以,你可以举例来说做到这一点:

text = "something" 
class << text 
    def say_hi 
    puts "Hi!" 
    end 
end 

text.say_hi 

当你(在这个例子字符串)创建类的实例,该实例得到它自己独特的匿名类,它是类的子类。在该示例中,您已经在String类的匿名子类的特征类上定义了实例方法。所以你可以在文本对象上使用方法“say_hi”,但不能在String类上使用。所以“类< <自我”正在打开这些特征类。

另一方面,“自我”仅代表当前情境中的一个对象,这意味着在某些情况下(例如您的情况)相同。至于self.included方法,它只是一个回调方法,当模块被包含在一个带有代表对象的参数的类中时(这里是类SomeObject),它会被调用。

我希望我已经回答了至少部分你的问题。 点击此处了解详情: Difference between 'self.method_name' and 'class << self' in Ruby

+0

我明白你是如何使用mixins的,除了'def self.included(object)...'之外,大多数情况下它都是有意义的。事情是,虽然我没有那么期望达到任何事情,但我试图理解这种行为。我不确定你的例子解释了为什么'class << self'与混合模块一起工作,但当尝试访问类方法时,'.self'前缀没有。实际上,在我的示例中,我很困惑实例方法:first_name对于类调用是否可用。 – Nathan 2012-03-28 03:19:54

+0

我已经更新了我的答案,我希望它能回答您的问题中的至少一部分。祝你今天愉快。 – Giron 2012-03-28 21:44:55