Class: Ibex::Configuration::Resolver
- Inherits:
-
Object
- Object
- Ibex::Configuration::Resolver
- Defined in:
- lib/ibex/configuration.rb,
sig/ibex/configuration.rbs
Overview
Applies fixed/minimum override algebra and exposes deterministic evidence.
Instance Attribute Summary collapse
- #values ⇒ Array[Value] readonly
Instance Method Summary collapse
-
#dump ⇒ String
Deterministic JSON independent of caller hash insertion order.
- #fetch(name) ⇒ Value
-
#initialize(keys: Registry.keys, grammar: {}, project: {}, cli: {}, analysis_overrides: {}, locations: {}) ⇒ Resolver
constructor
A new instance of Resolver.
- #origin(kind, name, locations) ⇒ Origin
- #reject_fixed_conflicts!(key, grammar, declared, requested) ⇒ void
- #resolve_fixed(key, builtin, sources, locations) ⇒ Value
- #resolve_key(key, sources, locations) ⇒ Value
- #resolve_minimum(key, builtin, sources, locations) ⇒ Value
- #resolve_override(key, builtin, sources, locations) ⇒ Value
- #source_value(key, kind, sources, locations) ⇒ Value?
- #to_h ⇒ Hash[String, Array[Hash[String, json_value]]]
- #validate_locations!(locations, sources) ⇒ void
- #validate_source!(kind, entries) ⇒ void
- #value(name) ⇒ config_value
- #value_from(key, raw, kind, locations, explicit:) ⇒ Value
Constructor Details
#initialize(keys: Registry.keys, grammar: {}, project: {}, cli: {}, analysis_overrides: {}, locations: {}) ⇒ Resolver
Returns a new instance of Resolver.
331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/ibex/configuration.rb', line 331 def initialize(keys: Registry.keys, grammar: {}, project: {}, cli: {}, analysis_overrides: {}, locations: {}) @keys = keys.sort_by(&:name).freeze @key_index = @keys.to_h { |key| [key.name, key] }.freeze raise ArgumentError, "duplicate configuration key definition" unless @key_index.length == @keys.length sources = { grammar: grammar, project: project, cli: cli, analysis_override: analysis_overrides } sources.each { |kind, entries| validate_source!(kind, entries) } validate_locations!(locations, sources) @values = @keys.map do |key| resolve_key(key, sources, locations) end.freeze @value_index = @values.to_h { |entry| [entry.key.name, entry] }.freeze freeze end |
Instance Attribute Details
#values ⇒ Array[Value] (readonly)
326 327 328 |
# File 'lib/ibex/configuration.rb', line 326 def values @values end |
Instance Method Details
#dump ⇒ String
Deterministic JSON independent of caller hash insertion order.
363 364 365 |
# File 'lib/ibex/configuration.rb', line 363 def dump "#{JSON.generate(to_h)}\n" end |
#fetch(name) ⇒ Value
347 348 349 |
# File 'lib/ibex/configuration.rb', line 347 def fetch(name) @value_index.fetch(name) { raise ArgumentError, "unknown configuration key: #{name.inspect}" } end |
#origin(kind, name, locations) ⇒ Origin
491 492 493 |
# File 'lib/ibex/configuration.rb', line 491 def origin(kind, name, locations) Origin.new(kind, location: locations.dig(kind, name)) end |
#reject_fixed_conflicts!(key, grammar, declared, requested) ⇒ void
This method returns an undefined value.
430 431 432 433 434 435 436 437 |
# File 'lib/ibex/configuration.rb', line 430 def reject_fixed_conflicts!(key, grammar, declared, requested) if grammar conflict = requested.find { |selection| selection.value != declared.value } raise Conflict.new(key, declared, conflict) if conflict elsif requested.map(&:value).uniq.length > 1 raise Conflict.new(key, requested.fetch(0), requested.fetch(1)) end end |
#resolve_fixed(key, builtin, sources, locations) ⇒ Value
420 421 422 423 424 425 426 427 |
# File 'lib/ibex/configuration.rb', line 420 def resolve_fixed(key, builtin, sources, locations) grammar = source_value(key, :grammar, sources, locations) declared = grammar || builtin requested = %i[project cli].filter_map { |kind| source_value(key, kind, sources, locations) } reject_fixed_conflicts!(key, grammar, declared, requested) grammar || requested.last || builtin end |
#resolve_key(key, sources, locations) ⇒ Value
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
# File 'lib/ibex/configuration.rb', line 396 def resolve_key(key, sources, locations) builtin = value_from(key, key.default, :builtin, locations, explicit: false) selected = case key.policy when :fixed then resolve_fixed(key, builtin, sources, locations) when :minimum then resolve_minimum(key, builtin, sources, locations) when :build, :invocation then resolve_override(key, builtin, sources, locations) else raise ArgumentError, "unsupported configuration policy: #{key.policy.inspect}" end override = sources.fetch(:analysis_override) return selected unless override.key?(key.name) raise ArgumentError, "analysis overrides are only valid for fixed configuration" unless key.policy == :fixed if key.validate(override.fetch(key.name)) == selected.value raise ArgumentError, "analysis override for #{key.name} must differ from the canonical value" end selected_origin = origin(:analysis_override, key.name, locations) Value.new( key, override.fetch(key.name), origin: selected_origin, explicit: true, canonical: false, declared_value: selected.value ) end |
#resolve_minimum(key, builtin, sources, locations) ⇒ Value
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 |
# File 'lib/ibex/configuration.rb', line 441 def resolve_minimum(key, builtin, sources, locations) grammar = source_value(key, :grammar, sources, locations) floor = grammar || builtin selected = floor %i[project cli].each do |kind| request = source_value(key, kind, sources, locations) next unless request request_value = request.value #: Integer floor_value = floor.value #: Integer raise Conflict.new(key, floor, request) if request_value < floor_value selected_value = selected.value #: Integer selected = request if request_value > selected_value end selected end |
#resolve_override(key, builtin, sources, locations) ⇒ Value
461 462 463 464 465 466 467 468 469 470 471 |
# File 'lib/ibex/configuration.rb', line 461 def resolve_override(key, builtin, sources, locations) if sources.fetch(:grammar).key?(key.name) raise ArgumentError, "#{key.name} is #{key.policy} configuration and cannot be grammar-owned" end if key.policy == :invocation && sources.fetch(:project).key?(key.name) raise ArgumentError, "#{key.name} is invocation configuration and cannot be project-owned" end source_value(key, :cli, sources, locations) || source_value(key, :project, sources, locations) || builtin end |
#source_value(key, kind, sources, locations) ⇒ Value?
475 476 477 478 479 480 |
# File 'lib/ibex/configuration.rb', line 475 def source_value(key, kind, sources, locations) entries = sources.fetch(kind) return unless entries.key?(key.name) value_from(key, entries.fetch(key.name), kind, locations, explicit: true) end |
#to_h ⇒ Hash[String, Array[Hash[String, json_value]]]
357 358 359 |
# File 'lib/ibex/configuration.rb', line 357 def to_h { "configuration" => @values.map(&:to_h) } end |
#validate_locations!(locations, sources) ⇒ void
This method returns an undefined value.
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 |
# File 'lib/ibex/configuration.rb', line 378 def validate_locations!(locations, sources) locations.each do |kind, entries| unless %i[grammar project].include?(kind) raise ArgumentError, "#{kind} configuration cannot have source locations" end entries.each do |name, location| raise ArgumentError, "unknown #{kind} configuration location: #{name.inspect}" unless @key_index.key?(name) raise ArgumentError, "configuration location must be an Ibex::Location" unless location.is_a?(Location) next if sources.fetch(kind).key?(name) raise ArgumentError, "configuration location for #{name} has no #{kind} value" end end end |
#validate_source!(kind, entries) ⇒ void
This method returns an undefined value.
370 371 372 373 374 |
# File 'lib/ibex/configuration.rb', line 370 def validate_source!(kind, entries) entries.each_key do |name| raise ArgumentError, "unknown #{kind} configuration key: #{name.inspect}" unless @key_index.key?(name) end end |
#value(name) ⇒ config_value
352 353 354 |
# File 'lib/ibex/configuration.rb', line 352 def value(name) fetch(name).value end |