Настройка параметров конфигурации при записи драгоценного камня

Я пишу драгоценный камень, с которым я бы хотел работать и без среды Rails.

У меня есть класс Configuration, позволяющий настроить драгоценный камень:

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

Теперь это можно использовать так:

NameChecker.configure do |config|
  config.api_key = 'dfskljkf'
end

Однако, похоже, я не могу получить доступ к своим переменным конфигурации из других классов в моем драгоценном камне. Например, когда я настраиваю жемчужину в моем spec_helper.rb так:

# spec/spec_helper.rb
require "name_checker"

NameChecker.configure do |config|
  config.api_key = 'dfskljkf'
end

и укажите конфигурацию из моего кода:

# lib/name_checker/net_checker.rb
module NameChecker
  class NetChecker
    p NameChecker.configuration.api_key
  end
end

Я получаю ошибку метода undefined:

`<class:NetChecker>': undefined method `api_key' for nil:NilClass (NoMethodError)

Что не так с моим кодом?

Ответы

Ответ 1

Попробуйте выполнить рефакторинг:

def self.configuration
  @configuration ||=  Configuration.new
end

def self.configure
  yield(configuration) if block_given?
end

Ответ 2

Основная проблема заключается в том, что вы применили слишком много косвенных ссылок. Почему бы вам просто не сделать

module NameChecker
  class << self
    attr_accessor :api_key, :log_level
  end
end

и сделать с ним? После этого вы также можете переопределить два сгенерированных читателя, чтобы они обеспечивали наличие необходимой вам среды...

module NameChecker
  class << self
    attr_accessor :api_key, :log_level

    def api_key
      raise "NameChecker really needs is't api_key set to work" unless @api_key
      @api_key
    end

    DEFAULT_LOG_LEVEL = 'info'

    def log_level
      @log_level || DEFAULT_LOG_LEVEL
    end

  end
end

Теперь фактическая (техническая) проблема заключается в том, что вы определяете класс с именем NetChecker, и при определении этого параметра вы пытаетесь напечатать возвращаемое значение вызова api_key на предполагаемом объекте Configuration (так что вы нарушают закон Деметры здесь). Это не удается, потому что вы определяете NetChecker, прежде чем кто-либо действительно успел определить какую-либо конфигурацию. Таким образом, вы действительно запрашиваете api_key до того, как метод configure был вызван на NameChecker, поэтому он имеет nil в нем Configuration ivar.

Мой совет должен был бы устранить переналадку и повторить попытку; -)