Introduction
In this article, we will learn how to manage class data in the Ruby programming language.
Class variables are also called static variables. They are declared with the static keyword in a class but outside a method, constructor, or block. Instance variables are generally created when an object is made by using the keyword 'new' and destroyed when the object is destroyed.
Problem 🕵️♀️
We wish to save a small amount of data with the class itself rather than storing the bit of data with each instance of the class.
Solution
Class variables have two at signs before them, whereas instance variables only have one. An instance variable, as well as a class variable, is present in this class:
class Bike
@make
@@wheels = 2
def initialize(make)
@make = make
end
def self.wheels
@@wheels
end
attr_accessor :make
end
# outside of the class
panigale = Bike.new("Ducati")
# instance variable is called on the ob
puts panigale.make
# class variable is called on the class
puts Bike.wheels
Output
Explanation🧠
Class variables hold data that is relevant to the class itself or to each instance of the class. They are frequently used to regulate, stop, or respond to the instantiation of the class. In Ruby, a class variable functions similarly to a static variable in Java.
Let’s see an example in which we will try to use a class variable and a class constant so that we can regulate how and when a class instantiation is done:
Code:
class Test
THINGS = ['Rock', 'Paper', 'Scissors'].freeze
@@number_instantiated = 0
def initialize
if @@number_instantiated >= THINGS.size
raise ArgumentError, 'Sorry, we only had three.'
end
@name = THINGS[@@number_instantiated]
@@number_instantiated += 1
puts "Let's go for… #{@name}!"
end
end
Test.new
Test.new
Test.new
Test.new
Output:
Writing setter or getter methods for class variables are not regarded as being appropriate. Apart from useful constants and those you can expose via class constants, like NAMES in the example above, you won't often need to disclose any class-wide information.
The following class-level Module#attr_reader and Module#attr_writer counterparts can be used if you do not wish to write setter or getter methods for class variables.
In order to define new accessor methods, they employ metaprogramming:
class Module
def class_attr_reader(*symbols)
symbols.each do |symbol|
self.class.send(:define_method, symbol) do
class_variable_get("@@#{symbol}")
end
end
end
def class_attr_writer(*symbols)
symbols.each do |symbol|
self.class.send(:define_method, "#{symbol}=") do |value|
class_variable_set("@@#{symbol}", value)
end
end
end
def class_attr_accessor(*symbols)
class_attr_reader(*symbols)
class_attr_writer(*symbols)
end
end
Here, the Test class is given an accessor for its class variable using Module#class_attr_reader in this instance.
Test.number_instantiated
# NoMethodError: undefined method 'number_instantiated' for Test:Class
Output:
class Test
class_attr_reader :number_instantiated
end
Test.number_instantiated # => 3
Both a class variable foo and an instance variable foo are permissible, but doing so will make things more difficult for you. The accessor method foo, for instance, must retrieve either one or the other. attr_accessor: foo followed by class attr_accessor: foo will discreetly replace the instance version with the class version.
Similar to instance variables, class variables can be used directly with class_variable_get and class_variable_set by avoiding encapsulation. Similar to instance variables, this should only be done from within the class, typically inside of a define_method call.
Check out this article - Compile Time Polymorphism