Sharing class variables between an instance and the class itself when expanding in a module

I am trying to understand why this code:

class BaseClass
end

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

  module ClassMethods
    def message(message)
      @@message = message
    end
  end
end

BaseClass.send(:include, Extensions)

class ExtendedClass < BaseClass
  message "hello world!"

  def say_message
    puts @@message
  end
end

ExtendedClass.new.say_message

outputs:

test.rb:22:in `say_message': uninitialized class variable @@message in ExtendedClass (NameError)
    from test.rb:26:in `<main>'

instead

hello world!

Could you explain to me why?

+3
source share
1 answer

Because when this method is executed:

def message(message)
  @@message = message
end

@@ message refers to a class variable in the ClassMethods module (and not in the ExtendedClass class)

Here's a one-line change that makes it work the way you expect:

def message(message)
  self.send(:class_variable_set, "@@message", message)
end

This is a bit antipattern (using send to get around the fact that class_variable_set is private), but I believe it answers the question.

NTN

+2

Source: https://habr.com/ru/post/1765425/


All Articles