Rails: cattr_accessor and class variables

Running this code:

module A
  def self.included(klass)
    klass.send(:cattr_accessor, :my_name)
  end

  def set_my_name_var
    @@my_name = 'A' # does NOT work as expected
  end

  def set_my_name_attr
    self.class.my_name = 'A' # works as expected
  end
end

class B
  include A

  cattr_accessor :my_other_name

  def set_my_other_name_var
    @@my_other_name = 'B' # works
  end

  def set_my_other_name_attr
    self.class.my_other_name = 'B' # works
  end
end

b = B.new

b.set_my_other_name_var
puts "My other name is " + B.my_other_name
b.set_my_name_var
puts "My name is " + B.my_name

b.set_my_other_name_attr
puts "My other name is " + B.my_other_name
b.set_my_name_attr
puts "My name is " + B.my_name

Torn as follows:

My other name is B
TypeError: (eval):34:in `+': can't convert nil into String

If we replace the last two blocks of code (so that b.set_my_name_attris called before b.set_my_name_var), everything works fine.

It looks like it is treating it @@my_nameas a module class variable A, not a class B(as I would expect this). Doesn't that bother you? Where can I learn more about module class variables?

+3
source share
1 answer

set_my_name_var A, @@my_name = 'A', A. , . , - A , @@my_name, . :

module Example
  def name=(name)
    @@name = name
  end

  def name
    @@name
  end
end

class First
  include Example
end

class Second
  include Example
end

irb(main):066:0> f = First.new
=> #<First:0x2d4b80c>
irb(main):067:0> s = Second.new
=> #<Second:0x2d491d8>
irb(main):068:0> f.name = 'Set via f'
=> "Set via f"
irb(main):069:0> s.name
=> "Set via f"

, , , , , . cattr_reader ( cattr_accessor) :

class_eval(<<-EOS, __FILE__, __LINE__)
  unless defined? @@#{sym}  # unless defined? @@hair_colors
    @@#{sym} = nil          #   @@hair_colors = nil
  end

  # code to define reader method follows...

:

  • B
  • A
  • included klass.send(:cattr_accessor, :my_name).
  • a @@my_name B, nil.

cattr_accessor set_my_name_var, @@my_name B, . cattr_accessor , , @@my_name B, B, A 's. , , . ( B A)

, . , b = B.new, :

>> A.class_variables
=> [] # No methods called on A yet so no module variables initialised
>> B.class_variables
=> ["@@my_other_name", "@@my_name"] # these exist and both set to nil by cattr_accessor
>> B.send(:class_variable_get, '@@my_name')
=> nil # B @@my_name is set to nil
>> b.set_my_name_var # we call set_my_name_var as you did in the question
=> "A"
>> A.send(:class_variable_get, '@@my_name')
=> "A" # the variable in the module is to to 'A' as you expect
>> B.send(:class_variable_get, '@@my_name')
=> nil # but the variable in the class is set to nil
>> B.my_name
=> nil # B.my_name accessor has returned the variable from the class i.e. nil

, cattr_reader , uninitialized class variable, . ( nil , ).

+3

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


All Articles