I'm writing a gem which I would like to work with and without the Rails environment.
I have a Configuration
class to allow configuration of the gem:
module NameChecker
class Configuration
attr_accessor :api_key, :log_level
def initialize
self.api_key = nil
self.log_level = 'info'
end
end
class << self
attr_accessor :configuration
end
def self.configure
self.configuration ||= Configuration.new
yield(configuration) if block_given?
end
end
This can now be used like so:
NameChecker.configure do |config|
config.api_key = 'dfskljkf'
end
However, I don't seem to be able to access my configuration variables from withing the other classes in my gem. For example, when I configure the gem in my spec_helper.rb
like so:
# spec/spec_helper.rb
require "name_checker"
NameChecker.configure do |config|
config.api_key = 'dfskljkf'
end
and reference the configuration from my code:
# lib/name_checker/net_checker.rb
module NameChecker
class NetChecker
p NameChecker.configuration.api_key
end
end
I get an undefined method error:
`<class:NetChecker>': undefined method `api_key' for nil:NilClass (NoMethodError)
What is wrong with my code?
Try refactoring to:
The main issue is that you've applied too much indirection. Why don't you just do
and be done with it? You could also override the two generated readers right afterwards so that they ensure the presence of the environment that you need...
Now, the actual (technical) problem is that you are defining a class called
NetChecker
and while defining it you are trying to print the return value of theapi_key
call on an assumedConfiguration
object (so you are violating the law of Demeter here). This fails, because you are definingNetChecker
before anyone really has had time to define any configuration. So you are in fact requestingapi_key
before theconfigure
method has been called onNameChecker
, so it hasnil
in it'sconfiguration
ivar.My advice would be to remove the overengineering and try again ;-)