Jikku Jose
Jikku Jose

Reputation: 18804

Getter/Setter for class variables in Ruby

Can getter/setter be auto-generated/enabled for class variables like that are being generated for instance variables using attr_accessor:

class School
  @@syllabus = :cbse

  def self.syllabus
    @@syllabus
  end

  def self.syllabus=(_)
    @@syllabus = _
  end
end

School.syllabus = :icse
School.syllabus # => :icse

Upvotes: 5

Views: 3701

Answers (2)

Uri Agassi
Uri Agassi

Reputation: 37409

All you need to do is to declare the attr_accessor in the scope of the class:

class School
 class << self
   attr_accessor :syllabus
  end
end

School.syllabus = :icse
School.syllabus # => :icse

Be aware though that the underlying member will not be @@syllabus (there is no built in solution for these kind of variables) but @syllabus in the class scope, which is the recommended way to do it anyway, see this blog post on the difference between the two:

The issue with class variables is inheritance. Let’s say I want to subclass Polygon with Triangle like so:

class Triangle < Polygon
  @@sides = 3
end

puts Triangle.sides # => 3
puts Polygon.sides # => 3

Wha? But Polygon’s sides was set to 10? When you set a class variable, you set it for the superclass and all of the subclasses.

Upvotes: 7

Cameron Martin
Cameron Martin

Reputation: 6012

Uri Agassi's answer is for setting instance variables on the class itself, something similar to, but not the same as class variables. See Difference between class variables and class instance variables? for an explantation of the differences.

What you're looking for is something like rails' cattr_accessor. You can achieve that with a bit of meta-programming

module CattrAccessors
  def cattr_accessor(*attrs)
    cattr_reader(*attrs)
    cattr_writer(*attrs)
  end

  def cattr_reader(*attrs)
    attrs.each do |attr|
      define_singleton_method(attr) { class_variable_get("@@#{attr}") }
    end
  end

  def cattr_writer(*attrs)
    attrs.each do |attr|
      define_singleton_method("#{attr}=") { |value| class_variable_set("@@#{attr}", value) }
    end
  end
end

Then use it like so:

class School
  extend CattrAccessors

  attr_accessor :syllabus
end

I haven't tested the above module, so it may not work. Let me know if it does not.

Upvotes: 3

Related Questions