Module: NestedObjects

Defined in:
lib/nested_objects.rb,
lib/nested_objects/mixin.rb,
lib/nested_objects/version.rb

Overview

Utilities for working with POROs arbitrarily nested with Hashes and Arrays

Defined Under Namespace

Modules: Mixin Classes: BadPathError

Constant Summary collapse

VERSION =

The last released gem version

'0.1.17'

Class Method Summary collapse

Class Method Details

.bury(data, path, value) ⇒ Object

Sets a value within a nested data structure

Creates intermediate Hashes along the path if they do not exist. Does NOT create intermediate Arrays (creates a Hash instead).

Examples:

data = { 'a' => { 'b' => [1, 2, 3] } }
NestedObjects.bury(data, ['a', 'b', '0'], 42) #=> { 'a' => { 'b' => [42, 2, 3] } }

will overwrite existing values

data = { 'a' => { 'b' => [1, 2, 3] } }
NestedObjects.bury(data, ['a'], 42) #=> { 'a' => 42 }

will create intermediate Hashes

data = {}
NestedObjects.bury(data, ['a', 'b'], 42) #=> { 'a' => { 'b' => 42 } })

will NOT create intermediate Arrays (creates a Hash instead)

data = {}
NestedObjects.bury(data, ['a', '0'], 42) #=> { 'a' => { '0' => [42, 2, 3] } }

Parameters:

  • data (Hash, Array, Object)

    The structure to modify

  • path (Array<String>)

    An array of keys/indices representing the path to the item to set

  • value (Object)

    The value to set at the specified path

Returns:

  • (Object)

    The modified data structure

Raises:

  • (BadPathError)

    if the path is invalid or the item does not exist



75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/nested_objects.rb', line 75

def bury(data, path, value)
  raise BadPathError if path.empty? || !(data.is_a?(Hash) || data.is_a?(Array))

  key, found = next_key(data, path)

  if path.length == 1
    data[key] = value
  else
    data[key] = {} unless found
    bury(data[key], path[1..], value)
  end

  data
end

.deep_copy(data) ⇒ Object

Creates a deep copy of data using Marshal

Examples:

data = { 'a' => { 'b' => [1, 2, 3] } }
NestedObjects.deep_copy(data) #=> { 'a' => { 'b' => [1, 2, 3] } }

Parameters:

  • data (Object)

    The object to be deeply copied

Returns:

  • (Object)

    A new object that is a deep copy of the input obj

Raises:

  • (TypeError)

    if the object cannot be marshaled (see Marshal documentation)



22
23
24
# File 'lib/nested_objects.rb', line 22

def deep_copy(data)
  Marshal.load(Marshal.dump(data))
end

.delete(data, path) ⇒ Object

Delete a key or element from nested data identified by path

Examples:

data = { 'a' => { 'b' => [1, 2, 3] } }
NestedObjects.delete(data, ['a', 'b', '0']) #=> 1
data #=> { 'a' => { 'b' => [2, 3] } }

Parameters:

  • data (Hash, Array, Object)

    The structure to modify

  • path (Array<String>)

    An array of keys/indices representing the path to the item to delete

Returns:

  • (Object)

    The value of the element that was deleted

Raises:

  • (BadPathError)

    if the path is invalid or the item does not exist



102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/nested_objects.rb', line 102

def delete(data, path)
  raise BadPathError if path.empty? || !(data.is_a?(Hash) || data.is_a?(Array))

  key, found = next_key(data, path)

  raise BadPathError unless found

  if path.length == 1
    delete_key(data, key)
  else
    delete(data[key], path[1..])
  end
end

.dig(data, path) ⇒ Object

Retrieves the value at the specified path in the given data

Examples:

data = { 'a' => { 'b' => [1, 2, 3] } }
NestedObjects.dig(data, ['a', 'b', '0']) #=> 1

Parameters:

  • data (Hash, Array, Object)

    The data containing the value to retrieve

  • path (Array<String>)

    An array of keys/indices representing the path to the desired value

Returns:

  • (Object)

    the value at the specified path

Raises:

  • (BadPathError)

    if the path is invalid or does not exist



36
37
38
39
40
41
42
43
44
45
46
# File 'lib/nested_objects.rb', line 36

def dig(data, path)
  return data if path.empty?

  raise BadPathError unless data.is_a?(Hash) || data.is_a?(Array)

  if data.is_a?(Hash)
    dig_into_hash(data, path)
  else
    dig_into_array(data, path)
  end
end

.path?(data, path) ⇒ Boolean

Check if the path is valid for the given data structure

Examples:

data = { 'a' => { 'b' => [1, 2, 3] } }
NestedObjects.path?(data, ['a', 'b', '0']) #=> true
NestedObjects.path?(data, ['d']) #=> false

Parameters:

  • data (Hash, Array, Object)

    The structure to check

  • path (Array<String>)

    An array of keys/indices representing the path to check

Returns:

  • (Boolean)

    true if the path is valid, false otherwise

Raises:

  • (BadPathError)

    if path tries to traverse an Array with a non-integer key



128
129
130
131
132
133
134
135
136
137
138
# File 'lib/nested_objects.rb', line 128

def path?(data, path)
  return true if path.empty?

  return false unless data.is_a?(Hash) || data.is_a?(Array)

  key, found = next_key(data, path)

  return false unless found

  path?(data[key], path[1..])
end