Ruby Can't See Method

夙愿已清 提交于 2020-01-07 17:32:41

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!