Class: Quonfig::Resolver

Inherits:
Object
  • Object
show all
Defined in:
lib/quonfig/resolver.rb

Overview

Public-API resolver: looks up a config by key in a ConfigStore and runs it through an Evaluator against a Context.

store     = Quonfig::ConfigStore.new(configs_hash)
evaluator = Quonfig::Evaluator.new(store)
resolver  = Quonfig::Resolver.new(store, evaluator)
result    = resolver.get('my.flag', context)

Mirrors the sdk-node pattern so integration tests (qfg-dk6.22-24) can drive evaluation without constructing a full Client. For the full production read path (with config_loader, SSE updates, telemetry), see Quonfig::ConfigResolver — the two coexist during the JSON migration.

Constant Summary collapse

TRUE_VALUES =
%w[true 1 t yes].freeze
CONFIDENTIAL_PREFIX =

Prefix the eval-summary aggregator stamps onto redacted confidential values before the 5-char MD5 hash. Matches CONFIDENTIAL_PREFIX in ReforgeHQ/sdk-ruby/lib/reforge/config_value_unwrapper.rb so dashboards built against the predecessor wire format keep working.

'*****'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(store, evaluator) ⇒ Resolver

Returns a new instance of Resolver.



29
30
31
32
# File 'lib/quonfig/resolver.rb', line 29

def initialize(store, evaluator)
  @store = store
  @evaluator = evaluator
end

Instance Attribute Details

#evaluatorObject (readonly)

Returns the value of attribute evaluator.



26
27
28
# File 'lib/quonfig/resolver.rb', line 26

def evaluator
  @evaluator
end

#project_env_idObject

Returns the value of attribute project_env_id.



27
28
29
# File 'lib/quonfig/resolver.rb', line 27

def project_env_id
  @project_env_id
end

#storeObject (readonly)

Returns the value of attribute store.



26
27
28
# File 'lib/quonfig/resolver.rb', line 26

def store
  @store
end

Instance Method Details

#get(key, context = nil) ⇒ Object

Look up key and evaluate against context. Mirrors Quonfig.get_or_raise semantics: if the key is unknown to the store, raise Quonfig::Errors::MissingDefaultError so callers can distinguish “no such config” from “config matched a nil/false value”. Tests that want the legacy “return nil if absent” shape can rescue and recover (see IntegrationTestHelpers.assert_resolved, which folds a missing-key raise into the test’s expected default).



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/quonfig/resolver.rb', line 45

def get(key, context = nil)
  config = raw(key)
  raise Quonfig::Errors::MissingDefaultError.new(key) if config.nil?

  eval_result = @evaluator.evaluate_config(config, context, resolver: self)
  return nil if eval_result.nil?

  weighted_index = nil
  resolved_value = resolve_value(eval_result.value, config, context) do |idx|
    weighted_index = idx
  end
  EvalResult.new(
    value: resolved_value,
    rule_index: eval_result.rule_index,
    config: config,
    weighted_value_index: weighted_index,
    reportable_value: redacted_reportable_value(eval_result.value)
  )
end

#raw(key) ⇒ Object



34
35
36
# File 'lib/quonfig/resolver.rb', line 34

def raw(key)
  @store.get(key)
end

#resolve_value(value, config, context = nil, &on_weighted_index) ⇒ Object

Post-evaluation value resolution. Mirrors sdk-node Resolver#resolveValue and sdk-go resolver.Resolve:

  • “provided” + ENV_VAR → read ENV, coerce to config’s valueType

  • confidential + decryptWith → look up the key config, decrypt

  • everything else passes through unchanged



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/quonfig/resolver.rb', line 70

def resolve_value(value, config, context = nil, &on_weighted_index)
  return nil if value.nil?

  type = vget(value, :type, 'type')

  if type == 'provided'
    return resolve_provided(value, config)
  end

  if type == 'weighted_values'
    return resolve_weighted(value, config, context, &on_weighted_index)
  end

  confidential = vget(value, :confidential, 'confidential')
  decrypt_with = vget(value, :decryptWith, 'decryptWith', :decrypt_with, 'decrypt_with')
  return resolve_decryption(value, config, context, decrypt_with) if confidential && decrypt_with && !decrypt_with.to_s.empty?

  value
end

#symbolize_json_names?Boolean

Integration shims for code that expects a ConfigResolver. Keep these narrow; the real ConfigResolver still owns the production hot path.

Returns:

  • (Boolean)


92
93
94
# File 'lib/quonfig/resolver.rb', line 92

def symbolize_json_names?
  false
end