Class: StandardId::ConfigSchema

Inherits:
Object
  • Object
show all
Defined in:
lib/standard_id/config_schema.rb

Overview

Lightweight configuration schema backed by ActiveSupport::OrderedOptions. Replaces the vendored ‘StandardConfig` DSL/manager. Fields are declared per scope; the resulting top-level config exposes each scope as a nested OrderedOptions and routes any field whose name is unique across scopes to the owning scope (so host apps can read base-scope fields like `config.account_class_name` without the `base.` prefix).

Defined Under Namespace

Classes: Config, DSL, Field, Scope

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeConfigSchema

Returns a new instance of ConfigSchema.



27
# File 'lib/standard_id/config_schema.rb', line 27

def initialize = @scopes = Concurrent::Map.new

Class Method Details

.add_field(**kwargs) ⇒ Object



23
# File 'lib/standard_id/config_schema.rb', line 23

def add_field(**kwargs) = instance.add_field(**kwargs)

.buildObject



24
# File 'lib/standard_id/config_schema.rb', line 24

def build = instance.apply(Config.new)

.define(&block) ⇒ Object



22
# File 'lib/standard_id/config_schema.rb', line 22

def define(&block) = instance.define(&block)

.instanceObject



21
# File 'lib/standard_id/config_schema.rb', line 21

def instance = (@instance ||= new)

Instance Method Details

#add_field(scope:, name:, type: :string, default: nil) ⇒ Object



38
39
40
41
# File 'lib/standard_id/config_schema.rb', line 38

def add_field(scope:, name:, type: :string, default: nil)
  fields = ensure_scope(scope)
  fields.compute_if_absent(name.to_sym) { Field.new(name.to_sym, type, default) }
end

#apply(config) ⇒ Object

Populate the given Config with scope sub-options + defaults. Re-apply is safe; values already set in a Scope are preserved (so provider gems can register fields after host apps have set base values).



58
59
60
61
62
63
64
65
66
# File 'lib/standard_id/config_schema.rb', line 58

def apply(config)
  config.__schema__ = self
  @scopes.each_pair do |scope_name, fields|
    opts = (config.key?(scope_name) && config[scope_name].is_a?(Scope)) ? config[scope_name] : Scope.new(self, scope_name)
    fields.each_value { |f| opts.write_default(f.name, f.default_value) }
    config.write_raw(scope_name, opts)
  end
  config
end

#cast(value, type) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/standard_id/config_schema.rb', line 68

def cast(value, type)
  return value if value.nil?
  case type
  when :any     then value
  when :symbol  then value.is_a?(Symbol) ? value : value.to_sym
  when :string  then value.to_s
  when :integer then value.to_i
  when :float   then value.to_f
  when :array   then Array(value)
  when :hash    then value.is_a?(Hash) ? value : {}
  when :boolean
    case value
    when true, false then value
    when "true", "1", 1 then true
    when "false", "0", 0 then false
    else !!value
    end
  else value
  end
end

#define(&block) ⇒ Object



33
34
35
36
# File 'lib/standard_id/config_schema.rb', line 33

def define(&block)
  DSL.new(self).instance_eval(&block) if block
  self
end

#ensure_scope(name) ⇒ Object

Register a scope without adding a field. Allows ‘define { scope :foo }` so provider gems can later `add_field(scope: :foo, …)` against an existing scope.



45
46
47
# File 'lib/standard_id/config_schema.rb', line 45

def ensure_scope(name)
  @scopes.compute_if_absent(name.to_sym) { Concurrent::Map.new }
end

#field?(scope_name, field_name) ⇒ Boolean

Returns:

  • (Boolean)


30
# File 'lib/standard_id/config_schema.rb', line 30

def field?(scope_name, field_name) = !!@scopes[scope_name.to_sym]&.key?(field_name.to_sym)

#field_for(scope_name, field_name) ⇒ Object



31
# File 'lib/standard_id/config_schema.rb', line 31

def field_for(scope_name, field_name) = @scopes[scope_name.to_sym]&.[](field_name.to_sym)

#scope?(name) ⇒ Boolean

Returns:

  • (Boolean)


29
# File 'lib/standard_id/config_schema.rb', line 29

def scope?(name) = @scopes.key?(name.to_sym)

#scopesObject



28
# File 'lib/standard_id/config_schema.rb', line 28

def scopes = @scopes

#scopes_with_field(field_name) ⇒ Object

Scopes that declare a field with the given name (used for top-level routing).



50
51
52
53
# File 'lib/standard_id/config_schema.rb', line 50

def scopes_with_field(field_name)
  sym = field_name.to_sym
  @scopes.each_pair.with_object([]) { |(s, fs), acc| acc << s if fs.key?(sym) }
end