我在ruby上写了怪异的,小而简单的DSL,我坚持使用键的输出值。我需要通过该命令输出哈希的具体关键字的值:
p config.key1
#> Output down below:
#> "value1"
# here's key1 is key of hash, i want to output value of key that i wrote in method call.
# p config.key_name for example
有我的配置实现:
require "deep_merge/rails_compat"
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
result = context.inner_hash
else
result = args
end
@inner_hash[name] = result
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 = parent_hash.deeper_merge!(adopted_hash, { :overwrite_arrays => "TRUE" })
elsif environment == keys[index]
"#{environment.capitalize} hash: " + in_hash.inner_hash[environment]
end
end
end
这是我的init.rb:
require "./configus"
require "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
development do
key1 "new value1"
key2 "value2"
group1 do
key3 "new value3"
key4 "value4"
end
end
productionisgsgsd do
key10 "value10"
end
end
puts config.key1
#> I wrote output down below:
Traceback (most recent call last):
init.rb:35:in `<main>': undefined method `key1' for #<Hash:0x000056261379cdb0> (NoMethodError)
Did you mean? key
key?
keys
我只想用具体命令输出哈希的具体键值:p config.key_name但是我不知道该怎么做,由于我的愚蠢问题,我想问你们。
P.S对不起,我的英语能力以及dsl的奇怪实现_ \ _(ツ)_ /¯
问题是您从Configus.config
方法返回了普通哈希。相反,您应该返回可以自定义行为的特殊InHash
实例。
当前问题在这里:
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 = parent_hash.deeper_merge!(adopted_hash, { :overwrite_arrays => "TRUE" })
# ^ the above line returns a normal hash from the method
in_hash # <= add this to return your in_hash object
elsif environment == keys[index]
"#{environment.capitalize} hash: " + in_hash.inner_hash[environment]
end
end
上述问题并未完全解决,因为此操作现在返回您的InHash
实例,但是InHash
无法获取密钥,您只能对其进行设置。因此,您想添加一种获取值的方法:
def method_missing(name, *args, &block)
if block_given?
context = InHash.new
context.instance_eval &block
@inner_hash[name] = context # set to the nested InHash instance
elsif args.empty?
@inner_hash[name] # without arguments given read the value
else
@inner_hash[name] = args # set to the arguments provided
end
end
以下代码:
config = Configus.config :staging, :production do
# ...
end
现在应该将config
设置为InHash
实例,该实例已定义了您的自定义行为。如果未提供其他参数,则args.empty?
中的method_missing
检查将返回一个值。意思是:
config.key1
现在应该返回您的["value1"]
值。 @inner_hash[name] = args
将始终将值设置为数组。如果您不希望这样做,则可以将其更改为:
@inner_hash[name] = args.size > 1 ? args : args.first