class LoadableConfig

Constants

ATTRIBUTE_BLACKLIST
Attribute
VERSION

Attributes

_attributes[R]
_config_file[R]

Public Class Methods

_configuration() click to toggle source
# File lib/loadable_config.rb, line 47
def _configuration
  @@_configuration
end
attribute(attr, type: :string, schema: {}, optional: false, serializer: nil, default: nil) click to toggle source
# File lib/loadable_config.rb, line 24
def attribute(attr, type: :string, schema: {}, optional: false, serializer: nil, default: nil)
  @_attributes ||= []
  attr = attr.to_sym
  if ATTRIBUTE_BLACKLIST.include?(attr)
    raise ArgumentError.new("Illegal attribute name '#{attr}': "\
                            'attributes must not collide with class methods of LoadableConfig')
  end

  type = [type] unless type.is_a?(Array)
  type.map! { |t| t.to_s }

  _attributes << Attribute.new(attr.to_s, type, schema, optional, serializer, default)
  attr_accessor attr

  define_singleton_method(attr) { instance.send(attr) }
end
attributes(*attrs, type: :string, optional: false, serializer: nil) click to toggle source
# File lib/loadable_config.rb, line 41
def attributes(*attrs, type: :string, optional: false, serializer: nil)
  attrs.each do |attr|
    attribute(attr, type: type, optional: optional, serializer: serializer)
  end
end
config_file(path) click to toggle source
# File lib/loadable_config.rb, line 20
def config_file(path)
  @_config_file = path
end
configure!() { |_configuration| ... } click to toggle source
# File lib/loadable_config.rb, line 51
def configure!
  if @@_configuration.frozen?
    raise ArgumentError.new('Cannot configure LoadableConfig: already configured')
  end

  yield(@@_configuration)
  @@_configuration.freeze
end
inherited(subclass) click to toggle source
Calls superclass method
# File lib/loadable_config.rb, line 15
def inherited(subclass)
  super
  subclass.send(:include, Singleton)
end
new() click to toggle source
# File lib/loadable_config.rb, line 71
def initialize
  if self.class._config_file.nil? || self.class._config_file.empty?
    raise RuntimeError.new("Incomplete LoadableConfig '#{self.class.name}': config_file not set")
  end

  config_file_path = self.class._config_file

  if (prefix = LoadableConfig._configuration.config_path_prefix)
    config_file_path = File.join(prefix, config_file_path)
  end

  unless File.exist?(config_file_path)
    raise RuntimeError.new("Cannot configure #{self.class.name}: "\
                           "configuration file '#{config_file_path}' missing")
  end

  config_data = File.read(config_file_path)

  if (preprocessor = LoadableConfig._configuration.preprocessor)
    config_data = preprocessor.call(config_data)
  end

  config = YAML.safe_load(config_data, [], [], true)
  unless config
    raise RuntimeError.new("Cannot configure #{self.class.name}: "\
                           "Configuration file empty for #{self.class.name}.")
  end

  if (env = LoadableConfig._configuration.environment_key)
    config = config.fetch(env) do
      raise RuntimeError.new("Cannot configure #{self.class.name}: "\
                             "Configuration missing for environment '#{env}'")
    end
  end

  unless config
    raise RuntimeError.new("Configuration file missing config for #{self.class.name}.")
  end

  valid, errors = _schema.validate(config)
  unless valid
    raise ArgumentError.new("Errors parsing #{self.class.name}:\n" +
                            errors.map { |e| "#{e.pointer}: #{e.message}" }.join("\n"))
  end

  self.class._attributes.each do |attr|
    if config.has_key?(attr.name)
      value = config[attr.name]
      if attr.serializer
        value = attr.serializer.load(value)
      end
    else
      value = attr.default
    end

    self.public_send(:"#{attr.name}=", value)
  end

  self.freeze
end

Private Class Methods

_reinitialize_configuration!() click to toggle source
# File lib/loadable_config.rb, line 62
def _reinitialize_configuration!
  @@_configuration = LoadableConfig::Options.new
end

Private Instance Methods

_schema() click to toggle source
# File lib/loadable_config.rb, line 134
def _schema
  JsonSchema.parse!(
    'type'                 => 'object',
    'description'          => "#{self.class.name} Configuration",
    'properties'           => self.class._attributes.each_with_object({}) do |attr, h|
                                h[attr.name] = { 'type' => attr.type }.merge!(attr.schema)
                              end,
    'required'             => self.class._attributes.reject(&:optional).map(&:name),
    'additionalProperties' => false,
  )
end