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.