Merging¶
One feature of JayAPI::Configuration is that it can be ‘merged’ with another JayAPI::Configuration object. More precisely, merging in a ‘selective’ way, which differs from the standard merge behaviour of Hash objects. Merging in this case can be defined as follows:
If config_a
and config_b
are two JayAPI::Configuration objects, they
are merged like this:
require 'jay_api/mergeables/merge_selector' # Note that this must be required to add the merging functionality to JayAPI::Configuration
config_a = config_a.with_merge_selector
config_a.merge_select(config_b)
Merging Rules¶
The merging will follow the following rules:
All nodes in
config_b
will completely overwrite nodes inconfig_a
(Just like the standard Hash merging behaviour). Example:# config_a one: two: 3 # config_b one: two: 4 # config_a.merge_select(config_b) one: two: 4 # <== note that the 'b' node overwrites the 'a' node.
All nodes in
config_a
that are not found inconfig_b
will be ignored in the result.# config_a one: 1 two: 2 three: 3 # config_b four: 4 # config_a.merge_select(config_b) four: 4 # <= note that only the node from 'config_b' shows up in the result.
If a node value is ‘nil’ in
config_b
and the node matches a node inconfig_a
then the matching node inconfig_a
will be ‘selected’ to be in the result.# config_a one: two: 3 # config_b one: ~ # The tilde is a YAML nil. # config_a.merge_select(config_b) one: two: 3 # <= note that config_b 'one: ~' acts as a 'selector' for everything under 'one:' in config_a.
Note
Note that internally the Hashes are converted to HashWithIndifferentAccess objects. This means that for example { ‘c’ => 1 } will override a Hash like { c: 1 }, because it treats Symbols and Strings as the same entity.
Realistic Example¶
To see how this can realistically be used in some configuration, the following examples can be studied:
config_a
1htmls:
2 index:
3 render_config:
4 config: ~
5 template_data:
6 breadcrumbs: Start
7 all_internal:
8 overall:
9 template_data:
10 filter: { category: ['software', 'architecture', 'module'] }
11 breadcrumbs: ['SWE Specs', 'Overall']
12 off_target:
13 template_data:
14 filter: { test_setups: off_target, category: ['software', 'architecture', 'module'] }
15 breadcrumbs: ['SWE Specs', 'Off Target']
16 on_target:
17 template_data:
18 filter: { test_setups: on_target, category: ['software', 'architecture', 'module'] }
19 breadcrumbs: ['SWE Specs', 'On Target']
20 manual:
21 template_data:
22 filter: { test_setups: manual, category: ['software', 'architecture', 'module'] }
23 breadcrumbs: ['SWE Specs', 'Manual']
config_b
1htmls:
2 index: ~
3 all_internal:
4 overall:
5 template_data: ~
6 some_new: attribute
7 off_target:
8 template_data:
9 breadcrumbs: ['New', 'Breadcrumbs']
10 on_target: ~
config_a.merge_select(config_b)
1htmls:
2index:
3 render_config:
4 config: ~
5 template_data:
6 breadcrumbs: Start
7all_internal:
8 overall:
9 template_data:
10 filter: { category: ['software', 'architecture', 'module'] }
11 breadcrumbs: ['SWE Specs', 'Overall']
12 some_new: attribute
13 off_target:
14 template_data:
15 breadcrumbs: ['New', 'Breadcrumbs']
16 on_target:
17 template_data:
18 filter: { test_setups: on_target, category: ['software', 'architecture', 'module'] }
19 breadcrumbs: ['SWE Specs', 'On Target']
Notice:
Due to rule number 3, notice that
config_a
entries belonging to ‘htmls -> index’ (lines 3-6) are in the result, because theconfig_b
’s ‘htmls -> index’ value is ‘~’, in effect instructing a ‘selection’.Due to rule number 1, notice that
config_a
’s’ ‘htmls -> all_internal -> off_target -> template_data -> breacrumbs’ (line 15) is overwritten by the corresponding new node value inconfig_b
.Due to rule number 2, notice that the ‘htmls -> all_internal -> manual’ node (lines 20-23) in
config_a
does not show up in the result, becauseconfig_b
does not contain it.