How can I recursively define Hash in Ruby from the provided arguments?

This piece of code fills the hash @options. valuesis Arraythat contains zero or more dissimilar elements. If you call populatewith arguments Hash, they use the value specified for each entry to accept the default value.

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

What I would like to do is change populateso that it recursively populates @options. There is a special case: if the values ​​that it is going to fill in with a key are an array consisting entirely of (1) characters or (2) hashes whose keys are characters (or some combination of two), then they should be considered as subkeys, and not the values ​​associated with this key, and the same logic used to evaluate the original arguments populatemust be recursively repeated.

It was a little hard to put into words, so I wrote some test cases. Below are some test cases and the expected value @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 , - . , .

, ?

+3
2

, , .

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 - :c. populate :a, {:b => "apples"}, :c
  • populate :a => [:one], :b => [:two, :three => "four"] {:a=>{:one=>{}}, :b=>{:two=>{}, :three=>"four"}}. populate :a => [:b].
+1

Ruby Perl, => . , , .

, populate , Ruby, ?

+1

Source: https://habr.com/ru/post/1746928/


All Articles