Ruby看不到方法

时间:2019-12-24 08:40:16

标签: ruby dsl

我为DSL创建了deep_merged(实际上我是从configus gem复制的),但是ruby看不到该方法,我也不明白为什么。 :/

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


我需要做的是: 通过该命令合并被采用的_hash(例如,阶段env)和parent_hash(生产环境),并通过该命令输出合并后的值: p config.key_name或p config.group1.key_name

但是我复制的deep_merge方法不起作用。 :/

P.S我试图将方法放在InHash类和Configus类中,但是self.config仍然看不到它。

我需要通过该命令输出值: p config.key_name或p config.group1.key_name

当我不为环境值正确使用父函数时:

p config.key1 #=> ["value1"]
p config.group1.key3 #=> ["value3"]

但是当我使用父函数时:

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 个答案:

答案 0 :(得分:0)

您在deep_merge上将InHash定义为实例方法,因此在Configus的类级别上不可见。

在我看来,deep_merge方法实际上不需要来自InHash实例的任何数据,因此,将IMO设为类方法是合理的。更改

def deep_merge(target, source)
  # ...
end

def self.deep_merge(target, source)
  # ...
end

然后您可以像这样在Configus.config中调用它

merged_hash = InHash.deep_merge(parent_hash, adopted_hash)