不理解类,模块和类<<自我方法

时间:2012-03-27 23:59:44

标签: ruby-on-rails ruby

我有以下代码:

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 个答案:

答案 0 :(得分: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

答案 1 :(得分: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

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

<强>更新 我会尝试更具体。当你在模块上定义instance / singleton方法时,你真正在做的是你定义了包含该模块的类的实例方法,另一方面,在模块上定义的类方法将成为该模块的类方法。第二个想知道是attr_accessor为给定参数的getter和setter创建实例方法。

现在回答你问题的一部分,在第一个例子中,你将在模块的类上创建3个类方法。在第二个方法中,您正在创建一个类方法,您尝试访问另一个类方法(setter),但是您的getter和setter被定义为实例方法=它们将成为包含您的模块的类方法的实例,您无法以这种方式找到他们=你无法访问你的getter和setter。 至于自我的解释,我不是那么熟练,但据我所知,当你使用“class&lt;&lt; self”时,你正在打开对象的本征类(每个对象都有它自己的任何一个)(注意)您定义实例方法的类,模块或类实例当然也是对象。 Ruby中对象的类方法=对象本征类的实例方法。所以你可以这样做:

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

text.say_hi

当您创建类的实例(该示例中为String)时,该实例将获得它自己的唯一匿名类,该类是该类的子类。在该示例中,您已在String类的匿名子类的本征类上定义了实例方法。因此,您可以在文本对象上使用方法“say_hi”,但不能在String类上使用。所以“class&lt;&lt; self”正在打开那些本征类。

另一方面,单独的“self”只代表当前上下文中的一个对象,在某些情况下(例如你的)也是如此。对于self.included方法,它只是一个回调方法,当模块包含在具有表示对象的参数(此处为类SomeObject)的类中时,将调用该方法。

我希望我至少回答了你的部分问题。 更多信息: Difference between 'self.method_name' and 'class << self' in Ruby