Search code examples
rubymoduleworker

Why do I get a NoMethodError with this Ruby module?


I am programming a distributed system where a worker performs some job and in order to start the worker a init.rb is started which loads the lib folder and performs some configuration.

Structure

init.rb
lib
|-- modulename
|   |-- foo.rb
|   |-- configuration.rb
|   `-- worker.rb
`-- modulename.rb

init.rb

$LOAD_PATH.unshift(File.expand_path("../lib", __FILE__))

require "bundler/setup"
require "modulename"

ModuleName.configure do |c|
    c.log       = "module.log"
    c.pool_size = 10
end

modulename.rb

require "sidekiq"

require "modulename/foo"
require "modulename/configuration"
require "modulename/worker"

module ModuleName
    def self.config
        @config ||= Configuration.new
    end

    def self.configure
        yield(config)
    end
end

worker.rb

module ModuleName
    class Worker
        include Sidekiq::Worker

        REDIS_POOL = ConnectionPool.new(:size => ModuleName.config.pool_size, :timeout => 3) { Redis.new }

        def dosomething
            # ...
        end
    end
end

If I now run ruby init.rb I get a NoMethodError: <class:Worker>: undefined method config for ModuleName:Module (NoMethodError)

I don't really understand why, please give me a hint on how to solve this problem!


Solution

  • In modulename.rb you're requiring worker.rb, so ruby goes off and runs the code in that file, including the bit where you set REDIS_POOL, which tries to call Modulename.config

    Modulename.config hasn't been defined yet (you only do so at the bottom of modulename.rb, hence the error.

    You probably only want to create the redis pool lazily, or at the very least after the configuration has been updated.