Непонимание классов, модулей и метода класса << self - PullRequest
8 голосов
/ 28 марта 2012

У меня есть следующий код:

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 ]

7 голосов
/ 28 марта 2012

Это потому, что ваш 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
4 голосов
/ 28 марта 2012

Чтобы лучше понять, как вы можете достичь того, чего хотите, взгляните на следующий пример:

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 метод класса, в котором вы пытаетесь получить доступ к другому методу класса (сеттеру), но ваши методы получения и установки определяются как методы экземпляра = они станут экземпляром метода класса, который будет включать ваш модуль. не может получить к ним этот путь = у вас нет доступа к вашим получателям и установщикам. Что касается объяснения себя, ну, я не настолько квалифицирован, но насколько я знаю, когда вы используете «класс << я», вы открываете собственный класс (каждый объект имеет свой собственный анонимный) объекта (обратите внимание, что класс модули или экземпляры классов, конечно, тоже объекты), где вы определяете методы экземпляров. Метод класса объекта в Ruby = метод экземпляра собственного класса объекта. Так что вы можете сделать это, например: </p>

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

text.say_hi

Когда вы создаете экземпляр класса (в этом примере String), этот экземпляр получает свой собственный уникальный анонимный класс, который является подклассом этого класса. В этом примере вы определили метод экземпляра для собственного класса анонимного подкласса класса String. Таким образом, вы можете использовать метод "say_hi" для текстового объекта, но не для класса String. Таким образом, «class << self» открывает эти собственные классы. </p>

С другой стороны, само "я" просто представляет объект в текущем контексте, что означает то же самое в некоторых сценариях (например, в вашем). Что касается метода self.included, это просто метод обратного вызова, который вызывается, когда модуль включается в класс с параметром, представляющим объект (здесь класс SomeObject).

Я надеюсь, что ответил хотя бы на ваш вопрос. Больше информации здесь: Разница между "self.method_name" и "class << self" в Ruby </a>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...