Featured image

When developing your own Ruby gem, at some point you might need to make some of the parameters configurable. The most idiomatic and elegant way to achieve this in Ruby is global configuration using a block. In my opinion, this approach is so simple that you likely won’t need any third-party gems for it. However, there are a few important caveats to keep in mind:

  • Avoid referencing your config directly inside methods. Instead, use the configuration to set a default value for your method’s parameter (see the example image). Alternatively, add an optional config parameter to the method - this allows caller code to override the global configuration for a specific invocation.
  • This pattern is not thread-safe. You should apply your configuration at boot time, before spawning any threads (this is especially crucial if your configuration class performs any side effects).

How do you implement configuration in your own gems? What aspects should be considered?

module MyLib
  class Config
    attr_accessor :some_setting

    def initialize
      @some_setting = 'default value'
    end
  end

  def config
    @config ||= Config.new
  end

  def configure(&block)
    block&.call(config)
  end

  def process(value = config.some_setting)
    puts "Processing with #{value.inspect}"
  end

  module_function :config, :configure, :process
end

MyLib.configure do |c|
  c.some_setting = 'other value'
end

MyLib.process # Processing with "other value"