Search code examples
rubyclassinstance-variablespopulate

Ruby Class Variable for init() Setters


How can I populate instance variables from a config hash that I want to park inside my class definition? I have a development and production set of values that I want to shove into instance variables at initialize(). How can I accomplish this?

Here is what I have:

class Alpha

    CONFIG = {  development: {mid: '123', uid: 'trial', pin: 'abcde' },
        production: {mid: '65432', uid: 'go_go_go', pin: 'kwir7' }
        }

    def initialize(environment = 'development')
        @env = environment
        @mid = nil
        @uid = nil
        @pin = nil
    end

end

a = Alpha.new('development)
puts a.inspect      
# ==> #<Alpha:0x00007fb1228d6b68 @env="development", @mid=nil, @uid=nil, @pin=nil>

I would like to use the Config constant to populate the three empty instance variables. Ideally I would like to set them inside initalize(), however a call to a private method to set those values can be done. The challenge remains the same, using either a class variable or constant to grab it from, and I can't seem to achieve this. I am assuming that parking such account key-value pairs inside the class definition, is best practice for such an application. i.e.: eCommerce account metrics.

I've tried the following, which can't seem to get the Config hash values referenced properly.

@mid = Alpha::Config[environment.to_s][:mid]

Just so that nobody balks on this post, the question is not answered in these posts:

Ruby: defining class level hash with default values

Confusion about ruby class variable


Solution

  • Remember that in Ruby symbols and strings are not equivalent, so you must explicitly convert when looking up in a Hash with symbol keys:

    class Alpha
      CONFIG = {
        development: { mid: '123', uid: 'trial', pin: 'abcde' },
        production: { mid: '65432', uid: 'go_go_go', pin: 'kwir7' }
      }
    
      attr_reader :mid, :uid, :pid
    
      def initialize(environment = 'development')
        @env = environment.to_sym
    
        @mid = CONFIG.dig(@env, :mid)
        @uid = CONFIG.dig(@env, :uid)
        @pid = CONFIG.dig(@env, :pid)
      end
    end
    

    Now it works:

    Alpha.new('development').mid
    # => "123"
    

    The .to_sym call when assigning @env takes care of the conversion, then it can be used past that point. dig is used to avoid crashing if a particular environment isn't defined, the values just come up nil instead.