通过ruby中的方法在哈希中输出键的值

问题描述 投票:0回答:1

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

ruby hash dsl
1个回答
1
投票

问题是您从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
© www.soinside.com 2019 - 2024. All rights reserved.