4

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
Jikku Jose
  • 18,306
  • 11
  • 41
  • 61

2 Answers2

6

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.

Community
  • 1
  • 1
Uri Agassi
  • 36,848
  • 14
  • 76
  • 93
  • That's still _instnace var_... Not _class var_ :) AFAIK. – Arup Rakshit Jan 02 '15 at 10:57
  • @ArupRakshit - what do you mean _instance_ var? it is a _class_ var, but not a _global_ var. Try it and see – Uri Agassi Jan 02 '15 at 10:59
  • I did not down vote.. Firstly :(... `@@x` is class var, where as `@x` is instance var. – Arup Rakshit Jan 02 '15 at 11:00
  • http://stackoverflow.com/questions/15773552/ruby-class-instance-variable-vs-class-variable --- One related answer. – Arup Rakshit Jan 02 '15 at 11:01
  • http://stackoverflow.com/a/5890199/1120015 - another, see especially " it's a common idiom in Ruby to track class-level data with an instance variable on the class itself" @ArupRakshit – Uri Agassi Jan 02 '15 at 11:11
  • 1
    I think @Arup is just pointing out that `@syllabus` is a class instance variable: `School.instance_variables => [:@syllabus]`. You know that, of course. – Cary Swoveland Jan 02 '15 at 11:26
  • @CarySwoveland - yes, I've understood that, and pointed to the difference in the answer itself – Uri Agassi Jan 02 '15 at 11:27
  • @UriAgassi Thanks! But I think clarifying that class variables doesn't have a getter/setter method would make your answer complete. – Jikku Jose Jan 02 '15 at 12:18
  • @UriAgassi The question does specifically ask for class variables, as in `@@variable`, rather than class-level instance variables. Regarding "What do you mean instance var? It is a class var." - Well, it is an instance variable that belongs to the class (in this case `School`), just how instance variables normally belong to instances of a class (in this case instances of `School`). Class variables are a distinct concept, hence why we have a different syntax for them. – Cameron Martin Jan 02 '15 at 12:19
  • @JikkuJose - added the clarification – Uri Agassi Jan 02 '15 at 12:29
  • 1
    @UriAgassi thanks! You are a great contributor, have learnt a lot from your answers.. – Jikku Jose Jan 02 '15 at 13:33
3

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.

Community
  • 1
  • 1
Cameron Martin
  • 5,952
  • 2
  • 40
  • 53