3

这段代码填充了一个@options哈希。values是一个Array包含零个或多个异质项的。如果您使用作为条目populate的参数进行调用Hash,它会使用您为每个条目指定的值来假定默认值。

def populate(*args)
  args.each do |a|
    values = nil
    if (a.kind_of? Hash)
      # Converts {:k => "v"} to `a = :k, values = "v"`
      a, values = a.to_a.first
    end

    @options[:"#{a}"] ||= values ||= {}
  end
end

我想做的是改变populate它以递归方式填充@options. 有一种特殊情况:如果要填充键的值是一个完全由(1)符号或(2)键为符号(或两者的某种组合)的哈希组成的数组,那么它们应该被视为子键而不是与该键关联的值,并且populate应该递归地重新应用用于评估原始参数的相同逻辑。

这有点难以用语言表达,所以我写了一些测试用例。以下是一些测试用例和@options之后的期望值:

populate :a
=> @options is {:a => {}}

populate :a => 42
=> @options is {:a => 42}

populate :a, :b, :c
=> @options is {:a => {}, :b => {}, :c => {}}

populate :a, :b => "apples", :c
=> @options is {:a => {}, :b => "apples", :c => {}}

populate :a => :b
=> @options is {:a => :b}

# Because [:b] is an Array consisting entirely of Symbols or
# Hashes whose keys are Symbols, we assume that :b is a subkey
# of @options[:a], rather than the value for @options[:a].
populate :a => [:b]
=> @options is {:a => {:b => {}}}

populate :a => [:b, :c => :d]
=> @options is {:a => {:b => {}, :c => :d}}

populate :a => [:a, :b, :c]
=> @options is {:a => {:a => {}, :b => {}, :c => {}}}

populate :a => [:a, :b, "c"]
=> @options is {:a => [:a, :b, "c"]}

populate :a => [:one], :b => [:two, :three => "four"]
=> @options is {:a => :one, :b => {:two => {}, :three => "four"}}

populate :a => [:one], :b => [:two => {:four => :five}, :three => "four"]
=> @options is {:a => :one,
                :b => {
                   :two => {
                      :four => :five
                      }
                   },
                   :three => "four"
                }
               }

如果需要更改签名populate以适应某种递归版本,这是可以接受的。理论上可能发生的嵌套数量没有限制。

关于我如何解决这个问题的任何想法?

4

2 回答 2

1

Ruby 不是 Perl,=>只能在真正的 Hash 定义中工作或作为方法调用中的最终参数。大多数你想要的东西都会导致语法错误。

您确定populate仅限于 Ruby 语法支持的情况值得吗?

于 2010-07-29T00:05:32.893 回答
1

所以这里有一些简单的代码。

def to_value args
  ret = {}
  # make sure we were given an array
  raise unless args.class == Array
  args.each do |arg|
    case arg
    when Symbol
      ret[arg] = {} 
    when Hash
      arg.each do |k,v|
        # make sure that all the hash keys are symbols
        raise unless k.class == Symbol
        ret[k] = to_value v 
      end           
    else    
      # make sure all the array elements are symbols or symbol-keyed hashes
      raise         
    end     
  end
  ret
rescue
  args
end
def populate *args
  @options ||= {}
  value = to_value(args)
  if value.class == Hash
    @options.merge! value
  end
end

它确实偏离了您的测试用例:

  • 测试用例populate :a, :b => "apples", :c是一个 ruby​​ 语法错误。Ruby 将假设方法的最后一个参数是一个散列(当没有给出大括号时),但不是一个非最终参数,正如您在此处假设的那样。给定的代码是一个语法错误(无论 的定义如何populate),因为它假定是一个哈希键,并在查找' 值 :c时找到了行尾。按预期工作:cpopulate :a, {:b => "apples"}, :c
  • 测试用例populate :a => [:one], :b => [:two, :three => "four"]返回{:a=>{:one=>{}}, :b=>{:two=>{}, :three=>"four"}}。这与测试用例是一致的populate :a => [:b]
于 2010-05-25T20:15:06.023 回答