Class: Karafka::Core::Configurable::Injector

Inherits:
Object
  • Object
show all
Defined in:
lib/karafka/core/configurable/injector.rb

Overview

Note:

The base class holds no state and defines no defaults on its own; it is not useful directly and is expected to be subclassed. Subclasses should return the same defaults object (e.g. a frozen constant) on each call so that a prepended layer doing super.merge(...) never mutates it.

Note:

Default values are injected by reference, not copied. A mutable default (an array or hash) is therefore shared across every target it is injected into, and mutating it in one place is visible everywhere. When a per-target mutable value is needed, the defaults layer should hand out a copy (e.g. dup it in .defaults).

Base class for config defaults injectors.

An injector enriches a config-like hash with a set of default values, applying each default only when the corresponding key is not already present. This lets a component ship sane defaults while still letting users override any of them by pre-populating the key themselves.

Injectors are meant to be layered. A base (e.g. OSS) injector defines its Injector.defaults and an extension (e.g. Pro) prepends a module onto the singleton class and calls super to contribute additional defaults on top:

Base.singleton_class.prepend(Extension)

The only-if-absent rule applies to the target being enriched, not to the defaults themselves: a key the user already set in the target is never touched. How two layers resolve a key they both define is up to the layers -- e.g. an extension using super.merge(extra) lets its own value win, while extra.merge(super) would keep the base value.

Examples:

Define an injector with defaults

class MyInjector < Karafka::Core::Configurable::Injector
  DEFAULTS = { 'a' => 1, 'b' => 2 }.freeze

  class << self
    def defaults
      DEFAULTS
    end
  end
end

MyInjector.call({ 'b' => 20 }) #=> { 'b' => 20, 'a' => 1 }

Layer extra defaults (e.g. Pro) via prepend + super

module ProDefaults
  def defaults
    super.merge('c' => 3)
  end
end

MyInjector.singleton_class.prepend(ProDefaults)
MyInjector.call({}) #=> { 'a' => 1, 'b' => 2, 'c' => 3 }

Class Method Summary collapse

Class Method Details

.call(target) ⇒ Hash

Enriches the target with the defaults, without overwriting any key that is already present in it. The target is mutated in place.

Parameters:

  • target (Hash)

    config hash to enrich in place

Returns:

  • (Hash)

    the same target, enriched with the missing defaults



69
70
71
72
73
74
75
76
77
# File 'lib/karafka/core/configurable/injector.rb', line 69

def call(target)
  defaults.each do |key, value|
    next if target.key?(key)

    target[key] = value
  end

  target
end

.defaultsHash

Returns default values to inject. Override in subclasses; extensions may prepend a module onto the singleton class and call super to contribute additional defaults on top. The base class defines none.

Returns:

  • (Hash)

    default values to inject. Override in subclasses; extensions may prepend a module onto the singleton class and call super to contribute additional defaults on top. The base class defines none.



82
83
84
# File 'lib/karafka/core/configurable/injector.rb', line 82

def defaults
  EMPTY_DEFAULTS
end