Access Ruby Hash Using Dotted Path Key String

后端 未结 7 2174
情深已故
情深已故 2021-01-01 21:35

The Rails I18n library transforms a YAML file into a data structure that is accessible via a dotted path call using the t() function.

t(\'one.two.three.four\         


        
相关标签:
7条回答
  • 2021-01-01 22:07

    This code not only allows dot notation to traverse a Hash but also square brackets to traverse Arrays with indices. It also avoids recursion for efficiency.

    class Hash
    
      def key_path(dotted_path)
        result = self
        dotted_path.split('.').each do |dot_part|
          dot_part.split('[').each do |part|
            if part.include?(']')
              index = part.to_i
              result = result[index] rescue nil
            else
              result = result[part] rescue nil
            end
          end
        end
    
        result
      end
    
    end
    

    Example:

    a = {"b" => {"c" => [0, [1, 42]]}}
    a.key_path("b.c[-1][1]") # => 42
    
    0 讨论(0)
  • 2021-01-01 22:18

    Yeah, I don't think that's built-in, anywhere else. But I use something like this in one of my projects:

    class Hash
      def dig(dotted_path)
        parts = dotted_path.split '.', 2
        match = self[parts[0]]
        if !parts[1] or match.nil?
          return match
        else
          return match.dig(parts[1])
        end
      end
    end
    

    And then call it like

    my_hash = {'a' => {'b' => 'a-b', 'c' => 'a-c', 'd' => {'e' => 'a-d-e'}}, 'f' => 'f'}
    my_hash.dig('a.d.e') # outputs 'a-d-e' (by calling my_hash['a']['d']['e'])
    
    0 讨论(0)
  • 2021-01-01 22:18

    I would suggest taking a look at this gist:
    https://gist.github.com/potatosalad/760726

    It adds implode and explode methods to Hash object that transforms nested keys to single-level dotted path keys, and vice versa.

    0 讨论(0)
  • 2021-01-01 22:19

    There is a Gem too keypath-ruby

    gem 'key_path', :git => 'https://github.com/nickcharlton/keypath-ruby.git'
    

    Looking at the code (and guessing a little about what t is), it looks like you can do this:

    t.value_at_keypath('one.two.three.four')
    
    0 讨论(0)
  • 2021-01-01 22:20

    Ruby 2.3 introduces the dig method that looks into nested arrays/hashes, it returns nil when no data is found.

    For example:

    test_data = {a: {b: {c: {d: 1}, e: 2}}}
    path = 'a.b.c.d'.split('.').map(&:to_sym)
    # path => [:a, :b, :c, :d]
    test_data.dig(*path)
    

    Of course if your nested use string keys, the to_sym step is not needed.

    0 讨论(0)
  • 2021-01-01 22:21

    There is also HashDot.

    HashDot allows dot notation syntax use on hashes. It is faster, and more traversable than an object created with OpenStruct.

    a = {b: {c: {d: 1}}}
    a.b.c.d => 1
    
    0 讨论(0)
提交回复
热议问题