The beginning steps to writing a new class usually involve writing a quick def initialize method. The purpose of these type of methods is to setup any dependencies or configurations necessary for the object to fulfill its responsibility. With instance variables, a common paradigm is to use an attr_reader or attr_writer to read/write values. However, these methods specifically work off of instance variables.

attr_reader :element

The difference between instance variables and class variables

An attr_ is basically a shortcut for getter and setter methods. For example, if you have the following initializer method, and wanted to access the instance variable @element in a private method, you might do something like this:

class SiteBuilder
  attr_accessor :element

  def initialize(element)
    @element = element
    add_timestamp_to_element
    @element
  end

  private

  # Notice we no longer need to reference the instance variable but can instead
  # call element which is now part of the attr_accessor reader portion
  def add_timestamp_to_element
    element.update(timestamp: DateTime.now)
  end
end

This approach works because you reference the set instance variable @element. However, for class methods you don’t have access to instance level variables so something like the following won’t work:

class SiteBuilder
  attr_accessor :element

  def self.format(element)
    @element = element
    append_timestamp
  end

  def self.add_timestamp_to_element
    element.update(timestamp: DateTime.now)
  end
end

The reason the instance variable isn’t available is that the context that the above is ran in is the class context. In other words it runs directly off the class like a method while instances of that class represent an object.

SiteBuilder.new(element) #=> Returns an element with the updated timestamp
SiteBuilder.format(element) #=> Explodes horribly in a deadly fire tornado

For SiteBuilder.new(element), we are creating a new object instance of the SiteBuilder class. The element becomes part of its properties or what describes its data and features.

For SiteBuilder.format(element), we are calling a method that works off of whatever the input is. It isn’t a new object but rather a way to perform an operation on something that doesn’t need an object.

Using an attr_accessor method with class level methods

Still want to have the benefits of attr_reader, attr_writer, and attr_accessor? We can implement another approach that allows the usage of these instance variables in a class level context. Basically what it does is create an instance variable in the class context to be used elsewhere.

class SiteBuilder

  # Creates an instance variable in the class context
  class << self
    attr_accessor :element
  end

  def self.format(element)
    self.element = element # We need to set the variable directly on the class
    append_timestamp
  end

  # We can now use the following shorthand without the @ symbol
  def self.add_timestamp_to_element
    element.update(timestamp: DateTime.now)
  end
end
« Previous Post
Enable ESLint for SublimeLinter while using asdf for version management
Next Post »
How to call Pry from within a SimpleDelegator Decorator

Join the conversation

comments powered by Disqus