Class: Aspera::DotContainer

Inherits:
Object
  • Object
show all
Defined in:
lib/aspera/dot_container.rb

Overview

Convert dotted-path to/from nested Hash/Array container

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(container) ⇒ DotContainer

Returns a new instance of DotContainer.

Parameters:

  • Container (Hash, Array)

    object



52
53
54
55
56
57
# File 'lib/aspera/dot_container.rb', line 52

def initialize(container)
  Aspera.assert_type(container, Hash)
  # tail (pop,push) contains the next element to display
  # elements are [path, value]
  @stack = container.empty? ? [] : [[[], container]]
end

Class Method Details

.dotted_to_container(path, value, result = nil) ⇒ Hash, Array

Insert extended value ‘value` into struct `result` at `path`

Parameters:

  • path (Array<String>)

    Path in container

  • value (Object)

    Value to insert in deep container

  • result (nil, Hash, Array) (defaults to: nil)

    Current container to use (or nil to create a new one)

Returns:

  • (Hash, Array)

    Container



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/aspera/dot_container.rb', line 14

def dotted_to_container(path, value, result = nil)
  Aspera.assert_array_all(path, String)
  # Typed keys
  keys = path.map{ |k| int_or_string(k)}
  # Create, or re-use first level container
  current = (result ||= new_hash_or_array_from_key(keys.first))
  # walk the path, and create sub-containers if necessary
  keys.each_cons(2) do |k, next_k|
    array_requires_integer_index!(current, k)
    current = (current[k] ||= new_hash_or_array_from_key(next_k))
  end
  # Assign value at last index
  array_requires_integer_index!(current, keys.last)
  current[keys.last] = value
  result
end

Instance Method Details

#to_dottedHash

Convert nested Hash/Array container to dotted-path Hash

Returns:

  • (Hash)

    Dotted-path Hash



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
# File 'lib/aspera/dot_container.rb', line 61

def to_dotted
  result = {}
  until @stack.empty?
    # path: Array, current: Array or Hash or other
    path, current = @stack.pop
    to_insert = nil
    # empty things are left intact
    if current.respond_to?(:empty?) && current.empty?
      to_insert = current
    else
      case current
      when Hash
        add_elements(path, current)
      when Array
        # Array has no nested structures -> list of Strings
        if current.none?{ |i| i.is_a?(Array) || i.is_a?(Hash)}
          to_insert = current.map(&:to_s)
        # Array of Hashes with only 'name' keys -> list of Strings
        elsif current.all?{ |i| i.is_a?(Hash) && i.keys == ['name']}
          to_insert = current.map{ |i| i['name']}
        # Array of Hashes with only 'name' and 'value' keys -> Hash of key/values
        elsif current.all?{ |i| i.is_a?(Hash) && i.key?('name') && i.key?('value') && i.length <= 3}
          # if there is an extra key, other than 'name' and 'value', insert that key as is
          add_elements(path, current.flat_map{ |h| h.except('name', 'value').to_a})
          # Insert name/value pairs as Hash
          add_elements(path, current.to_h{ |h| h.values_at('name', 'value')})
        else
          add_elements(path, current.each_with_index.map{ |v, i| [i, v]})
        end
      else
        to_insert = current
      end
    end
    result[path.join(SEPARATOR)] = to_insert unless to_insert.nil?
  end
  result
end