Class: Hash

Inherits:
Object show all
Includes:
JamfRubyExtensions::Hash::BackPorts, RubyDig
Defined in:
lib/jamf/ruby_extensions/dig.rb,
lib/jss/compatibility.rb,
lib/jamf/compatibility.rb,
lib/jss/ruby_extensions/hash.rb,
lib/jamf/ruby_extensions/hash.rb

Overview

include the modules loaded above

Instance Method Summary collapse

Instance Method Details

#dig(key, *rest) ⇒ Object Originally defined in module RubyDig

#jss_nillify!(to_nils = '', recurse = false) {|value| ... } ⇒ Hash

Convert Hash values to nil.

With no block, values equalling the String, or any member of the Array, given will be converted to nil. Equality is evaluated with == and Array#include?

With a block, if the result of the block evaluates to true, the value is converted to nil.

Subhashes are ignored unless recurse is true.

Examples:

hash = {:foo => '', :bar => {:baz => '' }}
hash.jss_nillify!  # {:foo => nil, :bar => {:baz => '' }}

hash = {:foo => '', :bar => {:baz => '' }}
hash.jss_nillify! '', :recurse  # {:foo => nil, :bar => {:baz => nil }}

hash = {:foo => 123, :bar => {:baz => '', :bim => "123" }}
hash.jss_nillify! ['', 123], :recurse # {:foo => nil, :bar => {:baz => nil, :bim => "123" }}

hash = {:foo => 123, :bar => {:baz => '', :bim => "123" }}
hash.jss_nillify!(:anything, :recurse){|v| v.to_i == 123 }  # {:foo => nil, :bar => {:baz => '', :bim => nil }}

Parameters:

  • to_nils (String, Array) (defaults to: '')

    Hash values equal to (==) these become nil. Defaults to empty string

  • recurse (Boolean) (defaults to: false)

    should sub-Hashes be nillified?

Yields:

  • (value)

    Hash values for which the block returns true will become nil.

Returns:

  • (Hash)

    the hash with the desired values converted to nil



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/jss/ruby_extensions/hash.rb', line 60

def jss_nillify!(to_nils = '', recurse = false, &block)
  nillify_these = [] << to_nils
  nillify_these.flatten!

  each_pair do |k, v|
    if v.class == Hash
      v.jss_nillify!(to_nils, recurse, &block)
      next
    end
    do_it =
      if block_given?
        yield v
      else
        nillify_these.include? v
      end
    self[k] = nil if do_it
  end # each pair
end

#jss_recursive_ostructObject Also known as: jss_ros

Since a lot of JSON data from the API comes as deeply-nested structures of Hashes and Arrays, it can be a pain to reference some of the deeper data inside, and it isn't worth coding them out into instance attributes.

For example see the 'hardware' subset of a JSS::Computer's API data, which is stored as a Hash in the JSS::Computer#hardware attribute.

To refer to the percent-full value of one of the machine's drives, you need to use e.g. this:

computer_instance.hardware[:storage].first[:partition][:percentage_full]

It would be nice to use method-like chains to access that data, similar to what OpenStruct provides.

But, there are two problems with just storing #hardware as an OpenStruct: 1) we'd lose some important Hash methods, like #keys and #values, breaking backward compatibility. 2) OpenStructs only work on the Hash itself, not its contents.

So to get the best of both worlds, we use the RecursiveOpenStruct gem

https://github.com/aetherknight/recursive-open-struct

which subclasses OpenStruct to be recursive.

And, instead of replacing the Hash, we'll add a RecursiveOpenStruct version of itself to itself as an attribute.

Now, we can access the same data using this:

computer_instance.hardware.jss_ros.storage.first.partition.percentage_full

CAVEAT: Treat these as read-only.

While the Hashes themselves may be mutable, their use in ruby-jss Classes should usually be considered read-only - neither the Hash, nor the RecursiveOpenStruct object created by this method should be changed. Changes to the Hash or the RecursiveOpenStruct are NOT synced between them, and ruby-jss won't know to send such changes back to the API when #update is called.

This should be fine for the intended uses. Data like Computer#hardware isn't sent back to the JSS via Computer#update, since it must come from a 'recon' anyway.

Data that is sent back to the JSS will have setter methods defined in the class or a mixin module (e.g. the Locatable module).

Since the data is functionally read-only, why not use the ImmutableStruct gem, used elsewhere in ruby-jss?

Because ImmutableStruct is really for creating fully-fleshed-out read-only classes, with a known set of attributes rather than just giving us a nicer way to access Hash data with arbitrary keys.



135
136
137
# File 'lib/jss/ruby_extensions/hash.rb', line 135

def jss_recursive_ostruct
  @jss_ros ||= RecursiveOpenStruct.new(self, recurse_over_arrays: true)
end

#transform_keys(&block) ⇒ Object Originally defined in module JamfRubyExtensions::Hash::BackPorts

#transform_keys!(&block) ⇒ Object Originally defined in module JamfRubyExtensions::Hash::BackPorts

#transform_values(&block) ⇒ Object Originally defined in module JamfRubyExtensions::Hash::BackPorts

#transform_values!(&block) ⇒ Object Originally defined in module JamfRubyExtensions::Hash::BackPorts