简体   繁体   中英

Access class variables in a modules class and instance methods

I have a module that contains both instance methods and class methods when included in a class. Both instance methods and class methods shall access class variables.

module MyModule
  @@a_class_variable = "lorem ipsum"

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

  module ClassMethods
    def a_class_method
      @@a_class_variable << "abc"
    end
  end

  # Use it in constructor
  def initialize
    @@a_class_variable << "abc"
  end

  def an_instance_method
    @@a_class_variable << "abc"
  end
end

When I include MyModule in some class, the interpreter says: NameError: uninitialized class variable @@a_class_method in MyModule::ClassMethods

What am I doing wrong?

When inside MyModule::ClassMethods , you're not inside MyModule and don't have access to @@a_class_variable . Here's a related question.

With an accessor, your code works fine :

module MyModule
  @@a_class_variable = "lorem ipsum"

  def self.a_class_variable
    @@a_class_variable
  end

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

  module ClassMethods
    def a_class_method
      MyModule.a_class_variable << " abc1"
    end
  end

  # Use it in constructor
  def initialize
    @@a_class_variable << " abc2"
  end

  def an_instance_method
    @@a_class_variable << " abc3"
  end
end

class MyObject
  include MyModule
end

my_object = MyObject.new
MyObject.a_class_method
p my_object.an_instance_method
#=> "lorem ipsum abc2 abc1 abc3"

As you noted in the comments, it exposes @@a_class_variable to the public. Setting the method as private or protected wouldn't work in the above example, since ClassMethods and MyModule aren't related.

It might not be the cleanest solution, but you could use send to access the private method :

module MyModule
  @@a_class_variable = 'lorem ipsum'

  module ClassMethods
    def a_class_method
      MyModule.send(:__a_class_variable) << ' abc1'
    end
  end

  # Use it in constructor
  def initialize
    @@a_class_variable << ' abc2'
  end

  def an_instance_method
    @@a_class_variable << ' abc3'
  end

  class << self
    def included(base)
      base.extend ClassMethods
    end

    private

    def __a_class_variable
      @@a_class_variable
    end
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM