Skip to content

Commit

Permalink
add patch to make correct merging of booleans possible in deep_merge
Browse files Browse the repository at this point in the history
The deep_merge gem lacks on a issue, reported here:
danielsdeleo/deep_merge#23
danielsdeleo/deep_merge#28

As yaml_extend uses this gem to merge, here is a workaround to solve
this issue. It will be full forward compatible, if the original deep_merge
solves its issue, due we don't patch deep_merge directly in any way.
  • Loading branch information
entwanderer committed May 27, 2018
1 parent 9c68e6d commit 494cd1f
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 6 deletions.
10 changes: 6 additions & 4 deletions lib/yaml_extend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
require 'yaml'
require 'deep_merge/rails_compat'

require_relative 'yaml_extend/yaml_extend_helper'

require_relative 'custom_errors/invalid_key_type_error'

#
Expand Down Expand Up @@ -49,20 +51,20 @@ def self.ext_load_file(yaml_path, inheritance_key=nil, extend_existing_arrays=tr
end
total_config ||= {}
yaml_path = YAML.make_absolute_path yaml_path
super_config = YAML.load_file(File.open(yaml_path))
super_config = YamlExtendHelper.encode_booleans YAML.load_file(File.open(yaml_path))
super_inheritance_files = yaml_value_by_key inheritance_key, super_config
delete_yaml_key inheritance_key, super_config # we don't merge the super inheritance keys into the base yaml
merged_config = config.clone.deeper_merge(super_config, extend_existing_arrays: extend_existing_arrays)
if super_inheritance_files && super_inheritance_files != ''
super_inheritance_files = [super_inheritance_files] unless super_inheritance_files.is_a? Array # we support strings as well as arrays of type string to extend from
super_inheritance_files.each_with_index do |super_inheritance_file, index|
super_config_path = File.dirname(yaml_path) + '/' + super_inheritance_file
total_config = YAML.ext_load_file super_config_path, inheritance_key, extend_existing_arrays, total_config.deeper_merge(merged_config, extend_existing_arrays: extend_existing_arrays)
total_config = YamlExtendHelper.encode_booleans YAML.ext_load_file(super_config_path, inheritance_key, extend_existing_arrays, total_config.deeper_merge(merged_config, extend_existing_arrays: extend_existing_arrays))
end
total_config
YamlExtendHelper.decode_booleans total_config
else
delete_yaml_key inheritance_key, merged_config
merged_config
YamlExtendHelper.decode_booleans merged_config
end
end

Expand Down
68 changes: 68 additions & 0 deletions lib/yaml_extend/yaml_extend_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@

#
# This class includes a workaround patch, providing a solution of the unaccepted pull request
# 'false is not overriden by true if preserve_unmergeables'
# https://github.com/danielsdeleo/deep_merge/pull/28
#
# It ensures, that booleans can be merged correctly, by en- and decoding them to strings, before and after merging
# see #encode_boolens and #decode_booleans
#

class YamlExtendHelper

TRUE_CLASS_ENCODED = '#={TrueClass}=#'
FALSE_CLASS_ENCODED = '#={FalseClass}=#'

def self.encode_booleans(hash)
hash.each_with_object({}) do |(k,v),g|
g[k] = if v.is_a? Hash
YamlExtendHelper.encode_booleans(v)
elsif v.is_a? Array
v.each_with_index do |av, ai|
v[ai] = if av.is_a? Hash
YamlExtendHelper.encode_booleans(av)
elsif av.is_a? TrueClass
TRUE_CLASS_ENCODED
elsif av.is_a? FalseClass
FALSE_CLASS_ENCODED
else
av
end
end
elsif v.is_a? TrueClass
TRUE_CLASS_ENCODED
elsif v.is_a? FalseClass
FALSE_CLASS_ENCODED
else
v
end
end
end

def self.decode_booleans(hash)
hash.each_with_object({}) do |(k,v),g|
g[k] = if v.is_a? Hash
YamlExtendHelper.decode_booleans(v)
elsif v.is_a? Array
v.each_with_index do |av, ai|
v[ai] = if av.is_a? Hash
YamlExtendHelper.decode_booleans(av)
elsif av === TRUE_CLASS_ENCODED
true
elsif av === FALSE_CLASS_ENCODED
false
else
av
end
end
elsif v === TRUE_CLASS_ENCODED
true
elsif v === FALSE_CLASS_ENCODED
false
else
v
end
end
end

end
7 changes: 7 additions & 0 deletions spec/test_data/booleans/base.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
alpha: true
beta: false
gamma: true
data:
delta: false
kappa: true
theta: false
6 changes: 6 additions & 0 deletions spec/test_data/booleans/extended.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extends: 'base.yml'
alpha: false
beta: true
data:
delta: true
kappa: false
60 changes: 58 additions & 2 deletions spec/yaml_extend_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,14 @@
end
it 'has no custom extension key in the final merged yaml included (Array)' do
yaml_obj = YAML.ext_load_file 'test_data/yaml_value_by_key/config.yml', ['options','inherits_from']
puts "EMPTY?"
p yaml_obj
expect(yaml_obj['options']['inherits_from']).to eql(nil)
end
it 'can extend and overwrite booleans' do
yaml_obj = YAML.ext_load_file 'test_data/booleans/extended.yml'
expect(yaml_obj['data']['kappa']).to eql(false)
expect(yaml_obj['data']['theta']).to eql(false)
expect(yaml_obj['data']['delta']).to eql(true)
end
end
end

Expand Down Expand Up @@ -159,3 +163,55 @@
YAML.reset_load_key
end
end

RSpec.describe YAML,'#decode_booleans / #encode_booleans' do
context 'Encode and decode booleans' do

yaml_obj = {
tbool: true,
fbool: false,
nested: {
fbool: false,
tbool: true
},
array: [
true,
false,
{
fbool: false,
array: [
true,
{
fbool: false
}
]
}
]
}

it "can encode booleans" do
yaml_obj = YamlExtendHelper.encode_booleans(yaml_obj)
expect(yaml_obj[:tbool]).to eql(YamlExtendHelper::TRUE_CLASS_ENCODED)
expect(yaml_obj[:fbool]).to eql(YamlExtendHelper::FALSE_CLASS_ENCODED)
expect(yaml_obj[:nested][:tbool]).to eql(YamlExtendHelper::TRUE_CLASS_ENCODED)
expect(yaml_obj[:nested][:fbool]).to eql(YamlExtendHelper::FALSE_CLASS_ENCODED)
expect(yaml_obj[:array][0]).to eql(YamlExtendHelper::TRUE_CLASS_ENCODED)
expect(yaml_obj[:array][1]).to eql(YamlExtendHelper::FALSE_CLASS_ENCODED)
expect(yaml_obj[:array][2][:fbool]).to eql(YamlExtendHelper::FALSE_CLASS_ENCODED)
expect(yaml_obj[:array][2][:array][0]).to eql(YamlExtendHelper::TRUE_CLASS_ENCODED)
expect(yaml_obj[:array][2][:array][1][:fbool]).to eql(YamlExtendHelper::FALSE_CLASS_ENCODED)
end
it "can decode booleans" do
yaml_obj = YamlExtendHelper.decode_booleans(yaml_obj)
expect(yaml_obj[:tbool]).to eql(true)
expect(yaml_obj[:fbool]).to eql(false)
expect(yaml_obj[:nested][:tbool]).to eql(true)
expect(yaml_obj[:nested][:fbool]).to eql(false)
expect(yaml_obj[:array][0]).to eql(true)
expect(yaml_obj[:array][1]).to eql(false)
expect(yaml_obj[:array][2][:fbool]).to eql(false)
expect(yaml_obj[:array][2][:array][0]).to eql(true)
expect(yaml_obj[:array][2][:array][1][:fbool]).to eql(false)
end
end
end

0 comments on commit 494cd1f

Please sign in to comment.