问题
I created deep_merged for my DSL (actually I copied it from configus gem), but ruby can't see that method, and I don't understand why. :/
Init.rb:
require "./configus"
require "pry"
#Binding.pry
config = Configus.config :staging, :production do
production do
key1 "value1"
key2 "value2"
group1 do
key3 "value3"
key4 "value4"
end
end
staging do
key2 "new value2"
group1 do
key4 "new value4"
end
end
end
p config.key1
Configus.rb:
class Configus
class InHash
attr_reader :inner_hash
def initialize
@inner_hash = {}
end
def method_missing(name, *args, &block)
if block_given?
context = InHash.new
context.instance_eval &block
@inner_hash[name] = context
elsif args.empty?
@inner_hash[name]
else
@inner_hash[name] = args
end
end
def deep_merge(target, source)
source.each_pair do |k, v|
tv = target[k]
target[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? deep_merge(tv, v) : v
end
target
end
end
def self.config(environment, parent = nil, &block)
in_hash = InHash.new
in_hash.instance_eval &block
keys = in_hash.inner_hash.keys
index = keys.find_index(environment)
if parent && environment
parent_hash = in_hash.inner_hash[parent]
adopted_hash = in_hash.inner_hash[environment]
merged_hash = deep_merge(parent_hash, adopted_hash)
in_hash
elsif environment == keys[index]
in_hash.inner_hash[environment]
end
end
end
All I need is: Merge adopted_hash (for the example staging env) with parent_hash (production env) and output of the merged values by that command: p config.key_name or p config.group1.key_name
But the deep_merge method that I copied didn't work. :/
P.S I tried to put the method in the InHash class, and in the Configus class, but self.config still can't see it.
I need to output values via that command: p config.key_name or p config.group1.key_name
When I DO NOT use parent function for environments' values outputs correctly:
p config.key1 #=> ["value1"]
p config.group1.key3 #=> ["value3"]
But when i USE parent function:
p config.key1 => nil
p config.group1.key3 => Traceback (most recent call last):
init.rb:24:in `<main>': undefined method `key3' for nil:NilClass (NoMethodError)
p config => #<Configus::InHash:0x000055cfe51410d0
@inner_hash={:production=>#<Configus::InHash:0x000055cfe5140f40
@inner_hash={:key1=>["value1"], :key2=>["value2"], :group1=>#
<Configus::InHash:0x000055cfe5140bf8 @inner_hash={:key3=>["value3"],
:key4=>["value4"]}>, :[]=>[#<Configus::InHash:0x000055cfe514bee0
@inner_hash={}>], :[]==>[#<Configus::InHash:0x000055cfe514bee0
@inner_hash={}>, nil]}>, :staging=>#<Configus::InHash:0x000055cfe5140748
@inner_hash={:key2=>["new value2"], :group1=>#
<Configus::InHash:0x000055cfe51404c8 @inner_hash={:key4=>["new value4"]}>,
:each_pair=>#<Configus::InHash:0x000055cfe514bee0 @inner_hash={}>}>}>
回答1:
You defined deep_merge
as an instance method on InHash
, therefore it is not visible at a class level in Configus
.
It feels to me like the deep_merge
method actually does not need any data from an InHash
instance, therefore IMO it is reasonable to just make it a class method. Change
def deep_merge(target, source)
# ...
end
to
def self.deep_merge(target, source)
# ...
end
Then you can call it in Configus.config
like this
merged_hash = InHash.deep_merge(parent_hash, adopted_hash)
来源:https://stackoverflow.com/questions/59466085/ruby-cant-see-method