Module: Scimitar::Support::Utilities

Defined in:
lib/scimitar/support/utilities.rb

Overview

A namespace that contains various stand-alone utility methods which act as helpers for other parts of the code base, without risking namespace pollution by e.g. being part of a module loaded into a client class.

Class Method Summary collapse

Class Method Details

.dot_path(array, value) ⇒ Object

Takes an array of components that usually come from a dotted path such as foo.bar.baz, along with a value that is found at the end of that path, then converts it into a nested Hash with each level of the Hash corresponding to a step along the path.

This was written to help with edge case SCIM uses where (most often, at least) inbound calls use a dotted notation where nested values are more commonly accepted; converting to nesting makes it easier for subsequent processing code, which needs only handle nested Hash data.

As an example, passing:

['foo', 'bar', 'baz'], 'value'

…yields:

{'foo' => {'bar' => {'baz' => 'value'}}}

Parameters:

array

Array containing path components, usually acquired from a string with dot separators and a call to String#split.

value

The value found at the path indicated by array.

If array is empty, value is returned directly, with no nesting Hash wrapping it.



42
43
44
45
46
47
48
# File 'lib/scimitar/support/utilities.rb', line 42

def self.dot_path(array, value)
  return value if array.empty?

  {}.tap do | hash |
    hash[array.shift()] = self.dot_path(array, value)
  end
end

.path_str_to_array(schemas, path_str) ⇒ Object

Schema ID-aware splitter handling “:” or “.” separators. Adapted from contribution by @bettysteger and @MorrisFreeman in:

https://github.com/RIPAGlobal/scimitar/issues/48
https://github.com/RIPAGlobal/scimitar/pull/49
+schemas

Array of extension schemas, e.g. a SCIM resource class’ scim_resource_type.extended_schemas value. The Array should be empty if there are no extensions.

path_str

Path String, e.g. "password", "name.givenName", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" (special case), "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:organization" (if given a Symbol, it’ll be converted to a String).

Returns an array of components, e.g. ["password"], ["name", "givenName"], ["urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"] (special case), ["urn:ietf:params:scim:schemas:extension:enterprise:2.0:User", "organization"].

The called-out special case is for a schema ID without any appended path components, which is returned as a single element ID to aid in traversal particularly of things like PATCH requests. There, a “value” attribute might have a key string that’s simply a schema ID, with an object beneath that’s got attribute-name pairs, possibly nested, in a path-free payload.



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
# File 'lib/scimitar/support/utilities.rb', line 77

def self.path_str_to_array(schemas, path_str)
  path_str   = path_str.to_s
  components = []

  # Note the ":" separating the schema ID (URN) from the attribute.
  # The nature of JSON rendering / other payloads might lead you to
  # expect a "." as with any complex types, but that's not the case;
  # see https://tools.ietf.org/html/rfc7644#section-3.10, or
  # https://tools.ietf.org/html/rfc7644#section-3.5.2 of which in
  # particular, https://tools.ietf.org/html/rfc7644#page-35.
  #
  if path_str.include?(':')
    lower_case_path_str = path_str.downcase()

    schemas.each do |schema|
      lower_case_schema_id       = schema.id.downcase()
      attributes_after_schema_id = lower_case_path_str.split(lower_case_schema_id + ':').drop(1)

      if attributes_after_schema_id.empty?
        components += [schema.id] if lower_case_path_str == lower_case_schema_id
      else
        attributes_after_schema_id.each do |component|
          components += [schema.id] + component.split('.')
        end
      end
    end
  end

  components = path_str.split('.') if components.empty?
  return components
end