通过 ruby 中的方法输出散列中键的值

Output value of keys in hash by method in ruby

我在 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的奇怪实现¯\_(ツ)_/¯

问题是您 return 来自 Configus.config 方法的普通散列。相反,您应该 return 您可以自定义行为的特殊 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

上面的问题并没有完全解决,因为现在return是你的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 实例,它定义了您的自定义行为。如果没有给出进一步的参数,method_missing 中的 args.empty? 签入将 return 一个值。意思是:

config.key1

现在应该 return 你的 ["value1"] 值。 @inner_hash[name] = args 将始终将值设置为数组。如果你不想要这个,你可能想把它改成:

@inner_hash[name] = args.size > 1 ? args : args.first