Reputation: 15791
I got some yml config files with a deep, different structures and I want to extract passwords(that are located on different levels) and store them in a yml file outside a git repo. Let me show an example
config1.yml
a:
b:
c: 1
password: secret
...
d: 2
...
I wish to replace secret
with ''
and extract a pass to a different yml file that will look like:
config1_passwords.yml
a:
b:
password: secret
Is there any way to merge config1.yml
without passwords with config1_passwords.yml
to get a correct config structure?
So basically in terms of hashes(parsed ymls) I want to do following:
{ :a => { :b => { :c => 1, :password => '' }, :d => 2 } }
{ :a => { :b => { :password => 'secret' } } }
# =>
{ :a => { :b => { :c => 1, :password => 'secret' }, :d => 2 } }
Thanks for suggestions
EDITED another example
{ :a => { :b => { :c => 1, :d => { :password1 => '' }, :password2 => '' } } }
{ :a => { :b => { :d => { :password => 'secret' }, :password2 => 'secret2' } } }
# =>
{ :a => { :b => { :c => 1, :d => { :password => 'secret' }, :password2 => 'secret2' } } }
Upvotes: 3
Views: 461
Reputation: 13574
Rails 3 has a deep_merge
, which does exactly what you want.
a = { :a => { :b => { :c => 1, :d => { :password1 => '' }, :password2 => '' } } }
b = { :a => { :b => { :d => { :password1 => 'secret' }, :password2 => 'secret2' } } }
a.deep_merge(b)
# -> {:a=> {:b=> {:c=>1, :d=>{:password1=>"secret"}, :password2=>"secret2"}}}
Note: I changed a[:a][:b][:d]
to contain :password1
instead of :password
.
Upvotes: 4
Reputation: 74985
It appears you want some sort of Hash deep merge. It's available in ActiveSupport (part of Rails):
# You can omit this require statement if you're running Rails.
require "active_support/core_ext/hash/deep_merge"
a = { a: { b: { c: 1, d: { password1: "" }, password2: "" } } }
b = { a: { b: { d: { password1: "secret" }, password2: "secret2" } } }
a.deep_merge(b)
#=> { a: { b: { c: 1, d: { password1: "secret"}, password2: "secret2" } } }
If you don't want to depend on ActiveSupport, take a look at the implementation.
Upvotes: 2
Reputation: 27207
Don't think this can be done using Ruby one-liners. But a simple recursive function might do
def recurse_merge_password! conf_hash, pw_hash
pw_hash.keys.each do |k|
next unless conf_hash.has_key?(k)
case
when k == :password
conf_hash[:password] = pw_hash[:password]
when conf_hash[k].is_a?(Hash) && pw_hash[k].is_a?(Hash)
recurse_merge_password! conf_hash[k], pw_hash[k]
end
end
end
h1 = { :a => { :b => { :c => 1, :password => '' }, :d => 2 } }
h2 = { :a => { :b => { :password => "secret" } } }
recurse_merge_password! h1, h2
puts h1.inspect
=> {:a=>{:b=>{:c=>1, :password=>"secret"}, :d=>2}}
If you have arrays and other structures that you may need to traverse, it is up to you to improve on this. Note I made it modify the config in place.
Upvotes: 2