0

could you please explain me why the class variable cannot be accessed by attribute_accessors?

As i am trying here to have the list of all methods of all subclasses in one array it works a little different. It created array @method_names in every subclass with specific methods for every class ... so i do need to do a loop through subclasses.

What kind of variable/attribute is @method_names?

Thanks!

module First
      class First_class
        class << self
          def info
            puts "First_class method info."
            puts @subclasses
            puts @method_names
          end
      
          def inherited(subclass)
            puts "#{subclass} located ..."
            subclasses << subclass
          end
    
          def subclasses
            @subclasses ||= []
          end
    
          def method_added(method_name)
            puts "Method located #{method_name} ..."
            method_names << method_name
          end
    
          def method_names
            @method_names ||= []
          end
        end
     
        def initialize
          puts "Instance of First_class is created."
        end
    
        def first_method
        end
      end
    
      class Second_class < First_class
        def self.info
          puts "Second_class method info."
          puts @subclasses
          puts @method_names
        end
        
        def second_method
        end
    
        def initialize
          puts "Instance of Second_class is created."
        end
      end
    
      class Third_class < First_class
        def third_method
        end
    
        def initialize
          puts "Instance of Third_class is created."
        end
      end
    end

    
    First::First_class.subclasses.each {
        |subclass| puts subclass
      subclass.method_names.each {
        |methodn| puts methodn
      }
    }

#################UPDATE######### Ok, maybe I put the question incorrectly.

Basically what is the difference for @@method_names(class variable) and @method_names (instance variable) if i do not create the instance of object? After inserting more inputs into @method_names it still inserts into the same object_id. So what is benefit of @@method_names?

  • 2
    Because they are instance variables and they are used on different instances of class `Class` – BroiSatse Feb 02 '21 at 14:14
  • 1
    Without knowing more context... Just a *word of warning*: If a base class needs to know about its sub classes, then this is probably a violation of SOLID design principles. – Tom Lord Feb 02 '21 at 14:35
  • If you want to register all your instance variables in a class variable (I can't imagine why, but okay) then you need to define class variables like `@@foo` where instances can *register* their variables. Or just iterate over the members of your class and introspect instance variables. Without more information about *why* you want to do this, it seems like an X/Y problem. – Todd A. Jacobs Feb 02 '21 at 14:54
  • "could you please explain me why the class variable cannot be accessed by attribute_accessors?" – Can you clarify your question, please? There is not a single class variable in your code, and also no attribute accessors. – Jörg W Mittag Feb 02 '21 at 15:15
  • Your question makes more sense now. Please see my updated answer. – lacostenycoder Feb 02 '21 at 21:20

1 Answers1

0

updated to answer updated question.

Classes in ruby can have class variables. However if you modify the class level variable, ALL instances will be modified. This is not recommended but will illustrate the point. But also see this answer

class Foo
  @@bar = 'bar'

  attr_accessor :bar

  def initialize
    @bar = 'bar'
  end

  def class_bar
    @@bar
  end

  def change_class_bar string
    raise ArgumentError unless string.is_a?(String)
    @@bar = string
  end
end

a = Foo.new
b = Foo.new

# change the class variable @@bar
b.change_class_bar 'wtf?'

# see both instances are changed because objects are passed by referrence
print 'a.class_bar is: '
puts a.class_bar
print 'b.class_bar is: '
puts b.class_bar

# change one instance only
a.bar = 'only a has changed'
print 'a.bar is: '
puts a.bar
print 'b.bar is still: '
puts b.bar

run this and you should get output:

a.class_bar is: wtf?
b.class_bar is: wtf?
a.bar is: only a has changed
b.bar is still: bar

original answer left here

@method_names is an instance variable of an instance of the class from which it was instantiated. However it cannot be accessed for read/write unless those attributes are defined with getter or setter methods defined.

ff = First::First_class.new
Instance of First_class is created.
=> #<First::First_class:0x00007fde5a6867b8>
ff.method_names
NoMethodError: undefined method `method_names' for #<First::First_class:0x00007fde5a6867b8>
Did you mean?  methods

Now if you call ff.methods you will see all methods defined through standard Ruby inheritance.

As a side note, class names in Ruby conventionally use PascalCase see PascalCase. Mixed_case is discouraged.

lacostenycoder
  • 10,623
  • 4
  • 31
  • 48