Class: Karafka::Core::Configurable::Node
- Inherits:
-
Object
- Object
- Karafka::Core::Configurable::Node
- Defined in:
- lib/karafka/core/configurable/node.rb
Overview
Single non-leaf node This is a core component for the configurable settings
The idea here is simple: we collect settings (leafs) and children (nodes) information and we only compile/initialize the values prior to user running the ‘#configure` API. This API needs to run prior to using the result stuff even if there is nothing to configure
Instance Attribute Summary collapse
-
#children ⇒ Object
We need to be able to redefine children for deep copy.
-
#nestings ⇒ Object
readonly
Returns the value of attribute nestings.
-
#node_name ⇒ Object
readonly
Returns the value of attribute node_name.
Class Method Summary collapse
-
.new ⇒ Object
Builds each node through its own anonymous subclass.
Instance Method Summary collapse
-
#compile ⇒ Object
Converts the settings definitions into end children.
-
#configure {|_self| ... } ⇒ Node
Allows for the configuration and setup of the settings.
-
#deep_dup ⇒ Node
Deep copies all the children nodes to allow us for templates building on a class level and non-side-effect usage on an instance/inherited.
-
#initialize(node_name, nestings = ->(_) {}, evaluate: true) ⇒ Node
constructor
A new instance of Node.
-
#register(name, value) ⇒ Object
Registers a key-value pair as a setting on an already-compiled node without going through the static ‘setting` DSL.
-
#setting(node_name, default: nil, constructor: nil, lazy: false, &block) ⇒ Object
Allows for a single leaf or nested node definition.
-
#to_h ⇒ Hash
Frozen config hash representation.
Constructor Details
#initialize(node_name, nestings = ->(_) {}, evaluate: true) ⇒ Node
Returns a new instance of Node.
65 66 67 68 69 70 71 72 73 |
# File 'lib/karafka/core/configurable/node.rb', line 65 def initialize(node_name, nestings = ->(_) {}, evaluate: true) @node_name = node_name @children = [] @nestings = nestings @compiled = false @configs_refs = {} @local_defs = {} instance_eval(&nestings) if evaluate end |
Instance Attribute Details
#children ⇒ Object
We need to be able to redefine children for deep copy
16 17 18 |
# File 'lib/karafka/core/configurable/node.rb', line 16 def children @children end |
#nestings ⇒ Object (readonly)
Returns the value of attribute nestings.
13 14 15 |
# File 'lib/karafka/core/configurable/node.rb', line 13 def nestings @nestings end |
#node_name ⇒ Object (readonly)
Returns the value of attribute node_name.
13 14 15 |
# File 'lib/karafka/core/configurable/node.rb', line 13 def node_name @node_name end |
Class Method Details
.new ⇒ Object
Builds each node through its own anonymous subclass. Since setting values are mirrored into instance variables for fast access and each node layout carries a different set of them, instantiating nodes directly from this class would grow its object shape variations past the Ruby limit, degrading ivar access for all nodes. A subclass per layout keeps shape variations per class minimal (late ‘setting` calls after inheritance or runtime `register` calls may add a few more, staying well under the limit). `#deep_dup` reuses the subclass of its template, so duplicated configs share shapes as well.
56 57 58 |
# File 'lib/karafka/core/configurable/node.rb', line 56 def new(...) equal?(Node) ? Class.new(self).new(...) : super end |
Instance Method Details
#compile ⇒ Object
It runs once, after things are compiled, they will not be recompiled again
Converts the settings definitions into end children
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/karafka/core/configurable/node.rb', line 188 def compile @children.each do |value| # Do not redefine something that was already set during compilation # This will allow us to reconfigure things and skip override with defaults skippable = @configs_refs.key?(value.node_name) || (value.is_a?(Leaf) && value.compiled?) lazy_leaf = value.is_a?(Leaf) && value.lazy? # Do not create accessor for leafs that are lazy as they will get a custom method # created instead build_accessors(value) unless lazy_leaf next if skippable initialized = if value.is_a?(Leaf) value.compiled = true if value.constructor && value.lazy? false elsif value.constructor call_constructor(value) else value.default end else value.compile value end if lazy_leaf && !initialized build_dynamic_accessor(value) else config_write(value.node_name, initialized) end end @compiled = true end |
#configure {|_self| ... } ⇒ Node
Allows for the configuration and setup of the settings
Compile settings, allow for overrides via yielding
104 105 106 107 108 |
# File 'lib/karafka/core/configurable/node.rb', line 104 def configure compile if !@compiled || node_name == :root yield(self) if block_given? self end |
#deep_dup ⇒ Node
Deep copies all the children nodes to allow us for templates building on a class level and non-side-effect usage on an instance/inherited.
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/karafka/core/configurable/node.rb', line 138 def deep_dup # Same-layout nodes reuse the class of their template so they share object shapes dupped = self.class.new(node_name, nestings, evaluate: false) children.each do |value| dupped.children << if value.is_a?(Leaf) # After inheritance we need to reload the state so the leafs are recompiled again value = value.dup value.compiled = false value else value.deep_dup end end dupped end |
#register(name, value) ⇒ Object
Registers a key-value pair as a setting on an already-compiled node without going through the static ‘setting` DSL. Useful for dynamic registries (e.g. named clusters) where the keys are not known at class-load time.
Unlike ‘setting`, which is designed to be called at class-definition time, `register` is safe to call at runtime because it:
- appends a pre-compiled Leaf so `deep_dup` and `to_h` include it
- sets `@configs_refs` directly so the reader accessor returns the value immediately
- builds reader/writer accessors via the same `build_accessors` path
Raises ‘ArgumentError` if the name is already registered to prevent silent overwrites.
173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/karafka/core/configurable/node.rb', line 173 def register(name, value) name = name.to_sym prevent_reserved_names!(name) raise ArgumentError, "#{name} is already registered" if @configs_refs.key?(name) leaf = Leaf.new(name, value, nil, true, false) @children << leaf build_accessors(leaf) config_write(name, value) end |
#setting(node_name, default: nil, constructor: nil, lazy: false, &block) ⇒ Object
Allows for a single leaf or nested node definition
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/karafka/core/configurable/node.rb', line 83 def setting(node_name, default: nil, constructor: nil, lazy: false, &block) # Symbolize at definition time (same as `#register`) so the config store, accessors, # `#to_h` and the compile state checks all agree on the key type also when a String # name is provided node_name = node_name.to_sym prevent_reserved_names!(node_name) @children << if block Node.new(node_name, block) else Leaf.new(node_name, default, constructor, false, lazy) end compile end |
#to_h ⇒ Hash
Returns frozen config hash representation.
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/karafka/core/configurable/node.rb', line 111 def to_h config = {} @children.each do |value| config[value.node_name] = if value.is_a?(Leaf) result = if @configs_refs.key?(value.node_name) @configs_refs[value.node_name] elsif value.constructor value.constructor.call elsif value.default value.default end # We need to check if value is not a result node for cases # where we merge additional config result.is_a?(Node) ? result.to_h : result else value.to_h end end config.freeze end |