The Spaghetti Refactory Established 2015

Staying Class-y with Instance Variables in Ruby

I was recently writing a time logging gem and was trying to figure out how to have data read/write accessible in a class without having to explicitly pass it through method arguments or save anything to a database.

I knew about class variables (@@some_variable), but for some reason, I always felt a little dirty writing those. Probably because their evils are written about a lot. Although, the main evil of class variables seems to be that they can troll you when using inheritance, and since I wasn’t using that at all, I should not need to feel dirty.

Anyway, during my Googling for a different solution, I came across John Nunemaker’s excellent write-up of Class Level Instance Variables, and that approach has worked like a charm so far.

We all know how to define instance variables in a class:

class Widget
  attr_accessor :thingy

  def initialize(thingy)
    @thingy = thingy
  end
end

@widget = Widget.new('cool')
@widget.thingy # => 'cool'

Turns out, class level instance variables are just as simple. We just have to define them as accessible attrs within the singleton class:

class Widget
  class << self
    attr_accessor :thingy

    def set_thingy(thingy)
      @thingy = thingy
    end
  end
end

Widget.set_thingy('sweeter!')
Widget.thingy # => 'sweeter!'
Widget.thingy = 'Sweetest!!!'
Widget.thingy # => 'Sweetest!!!'

And now I can mutate, add to, or do whatever I please with thingy in any other methods in the class.

This is particularly useful for my gem. It attempts to connect to the JIRA API to log work time, but each attempt I want to add to either a successes or an errors array, then pass both of those arrays into a separate Reporter class to print them to the console.

Here is my class in action with a few class level instance vars.