File: dotted_paths.rb

package info (click to toggle)
ruby-buff-extensions 2.0.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 212 kB
  • sloc: ruby: 506; makefile: 3
file content (126 lines) | stat: -rw-r--r-- 3,529 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
module Buff
  module Extensions::Hash
    module DottedPaths
      class << self
        def included(base)
          base.send(:extend, ClassMethods)
        end
      end

      module ClassMethods
        # Create a new Hash containing other nested Hashes from a string containing
        # a dotted path. A Hash will be created and assigned to a key of another Hash
        # for each entry in the dotted path.
        #
        # If a value is provided for the optional seed argument then the value of the
        # deepest nested key will be set to the given value. If no value is provided
        # the value of the key will be nil.
        #
        # @example creating a nested hash from a dotted path
        #
        #   Hash.from_dotted_path("deep.nested.hash") =>
        #   {
        #     "deep" => {
        #       "nested" => {
        #         "hash" => nil
        #       }
        #     }
        #   }
        #
        #
        # @example specifying a seed value
        #
        #   Hash.from_dotted_path("deep.nested.hash", :seed_value) =>
        #   {
        #     "deep" => {
        #       "nested" => {
        #         "hash" => :seed_value
        #       }
        #     }
        #   }
        #
        # @param [String, Symbol, Array] dotpath
        # @param [Object] seed (nil)
        # @param [Hash] target (self.new)
        #
        # @return [Hash]
        def from_dotted_path(dotpath, seed = nil, target = self.new)
          case dotpath
          when String, Symbol
            from_dotted_path(dotpath.to_s.split("."), seed)
          when Array
            if dotpath.empty?
              return target
            end

            key = dotpath.pop

            if target.empty?
              target[key] = seed
              from_dotted_path(dotpath, seed, target)
            else
              new_target      = self.new
              new_target[key] = target
              from_dotted_path(dotpath, seed, new_target)
            end
          end
        end
      end

      # Return the value of the nested hash key from the given dotted path
      #
      # @example
      #
      #   nested_hash = {
      #     "deep" => {
      #       "nested" => {
      #         "hash" => :seed_value
      #       }
      #     }
      #   }
      #
      #   nested_hash.berks_dig('deep.nested.hash') => :seed_value
      #
      # @param [String] path
      #
      # @return [Object, nil]
      def berks_dig(path)
        return nil unless path.present?

        parts = path.split('.', 2)
        match = self[parts[0].to_s].nil? ? self[parts[0].to_sym] : self[parts[0].to_s]
        if !parts[1] or match.nil?
          match
        else
          match.berks_dig(parts[1])
        end
      end

      # Returns an array of dotted paths from the keys, values of this Hash. Values which are
      # nested Hashes will also recurred into and their paths will be added properly.
      #
      # @param [Hash] source
      # @param [Array] acc
      # @param [Array] namespace
      #
      # @return [Array<String>]
      def dotted_paths(source = self, acc = Array.new, namespace = Array.new)
        if source.is_a?(Hash) && !source.empty?
          source.each do |key, value|
            branch = namespace.dup
            branch << key
            dotted_paths(value, acc, branch)
          end
        else
          acc << namespace.join('.')
        end

        acc
      end
    end
  end
end

class Hash
  include Buff::Extensions::Hash::DottedPaths
end