Class: Nucleon::Util::Data

Inherits:
Object
  • Object
show all
Defined in:
lib/core/util/data.rb

Overview

  1. Other utilities

Class Method Summary collapse

Class Method Details

.array(data, default = [], split_string = false) ⇒ Object

Ensure a data object is an array.

It converts:

  1. Symbols to arrays

  2. Strings to arrays

  3. Splits strings on commas (if split_string requested)

  4. If no array found, returns default

TODO: Parameter for string separator split

  • Parameters

    • ANY

      data Ruby data to ensure array

    • Array

      default Default value if no array is found

    • Boolean

      split_string Whether to split strings on comma

  • Returns

    • Array

      Returns an array

  • Errors

See also:

  • ::filter (switch)

  • ::hash

  • ::string

  • ::symbol

  • ::test



428
429
430
431
432
433
434
435
436
437
438
439
440
441
# File 'lib/core/util/data.rb', line 428

def self.array(data, default = [], split_string = false)
  result = default
  if data
    case data
    when Array
      result = data
    when String
      result = [ ( split_string ? data.split(/\s*,\s*/) : data ) ]
    else
      result = [ data ]
    end
  end
  return result
end

.clean(data, remove_empty = true) ⇒ Object

Clean nil or empty values out of a hash object.

  • Parameters

    • Hash

      data Ruby data to clean properties

    • Boolean

      remove_empty Whether or not to remove empty values or just nil

  • Returns

    • Hash

      Returns hash with all nil or empty values scrubbed (depending on remove_empty)

  • Errors

See also:

  • ::deep_clean (recursive clean)



591
592
593
594
595
596
597
# File 'lib/core/util/data.rb', line 591

def self.clean(data, remove_empty = true)
  data.keys.each do |key|
    obj = data[key]
    data.delete(key) if obj.nil? || ( remove_empty && obj.is_a?(Hash) && obj.empty? )
  end
  data
end

.clone(data) ⇒ Object

Recursively clone an array or tree based hash object.

  • Parameters

    • Hash, Array

      data Ruby data to recursively clone

  • Returns

    • Hash

      Returns completely new nested hash if hash data given

    • Array

      Returns completely new array if array data given

  • Errors



639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
# File 'lib/core/util/data.rb', line 639

def self.clone(data)
  if data.is_a?(Array)
    new_data = []
    data.each do |item|
      new_data << clone(item)
    end
  elsif data.is_a?(Hash)
    new_data = {}
    data.each do |key, value|
      new_data[key] = clone(value)
    end
  else
    new_data = data
  end
  new_data
end

.deep_clean(data, remove_empty = true) ⇒ Object

Recursively clean nil or empty values out of a hash object.

  • Parameters

    • Hash

      data Ruby data to clean properties

    • Boolean

      remove_empty Whether or not to remove empty values or just nil

  • Returns

    • Hash

      Returns hash with all nil or empty values scrubbed (depending on remove_empty)

  • Errors

See also:

  • ::clean (shallow clean)



613
614
615
616
617
618
619
620
621
622
623
624
625
# File 'lib/core/util/data.rb', line 613

def self.deep_clean(data, remove_empty = true)
  data.keys.each do |key|
    obj = data[key]

    if obj.nil? || ( remove_empty && obj.is_a?(Hash) && obj.empty? )
      data.delete(key)

    elsif data[key].is_a?(Hash)
      deep_clean(data[key], remove_empty)
    end
  end
  data
end

.empty?(value) ⇒ Boolean

Check if given value is empty.

It currently checks for: (our definition of empty)

  • ::undef?

  • ::false?

  • value.empty?

This method was created to provide an easy way for us to load and work with configurations from text formats, such as JSON.

  • Parameters

    • ANY

      value Value to check if empty

  • Returns

    • Boolean

      Returns true if value is empty, false otherwise

  • Errors

Returns:

  • (Boolean)


120
121
122
123
124
125
# File 'lib/core/util/data.rb', line 120

def self.empty?(value)
  if undef?(value) || false?(value) || (value.respond_to?('empty?') && value.empty?)
    return true
  end
  return false
end

.ensure(test, success_value = nil, failure_value = nil) ⇒ Object

Ensure a value is set one way or another depending on a test condition.

  • Parameters

    • Boolean

      test Test for success / failure

    • ANY

      success_value Value returned if test is not empty

    • ANY

      failure_value Value returned if test is empty

  • Returns

    • ANY

      Success or failure values depending on the outcome of test

  • Errors

See also:

  • ::empty?



915
916
917
918
919
920
921
922
923
924
925
# File 'lib/core/util/data.rb', line 915

def self.ensure(test, success_value = nil, failure_value = nil)
  success_value = (success_value ? success_value : test)
  failure_value = (failure_value ? failure_value : nil)

  if empty?(test)
    value = failure_value
  else
    value = success_value
  end
  return value
end

.ensure_value(value, failure_value = nil) ⇒ Object

Return value if not empty or else return failure value.

  • Parameters

    • ANY

      value Test for success / failure

    • ANY

      failure_value Value returned if value is empty

  • Returns

    • ANY

      Value or failure value depending on the emptiness of value

  • Errors

See:

  • ::ensure



941
942
943
# File 'lib/core/util/data.rb', line 941

def self.ensure_value(value, failure_value = nil)
  return self.ensure(value, nil, failure_value)
end

.exists?(data, keys, check_empty = false) ⇒ Boolean

Check if given keys exist in data hash.

This method allows for the easy checking of nested keys. It takes care of traversing the data structure and checking for empty recursively.

  • Parameters

    • Hash<String, Symbol|…|ANY>

      data Data object to check

    • Array<String, Symbol>

      keys Hash key path (nested keys)

    • Boolean

      check_empty Whether to check element for emptiness

  • Returns

    • Boolean

      Returns true if keys exist and not empty, false otherwise if check_empty

    • Boolean

      Returns true if keys exist, false otherwise

  • Errors

See:

  • ::empty?

Returns:

  • (Boolean)


146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/core/util/data.rb', line 146

def self.exists?(data, keys, check_empty = false)
  if keys.is_a?(String) || keys.is_a?(Symbol)
    keys = [ keys ]
  end
  key = keys.shift.to_sym

  if data.has_key?(key)
    value = data[key]

    if keys.empty?
      return false if check_empty && empty?(value)
      return true
    else
      return exists?(data[key], keys)
    end
  end
  return false
end

.false?(value) ⇒ Boolean

Check if given value is false.

It currently checks for: (our definition of false)

  • false

  • Symbols: :false

  • Strings: “false”, “FALSE”, “False

This method was created to provide an easy way for us to load and work with configurations from text formats, such as JSON.

  • Parameters

    • ANY

      value Value to check if false

  • Returns

    • Boolean

      Returns true if value is false, false otherwise

  • Errors

Returns:

  • (Boolean)


93
94
95
96
97
98
99
100
# File 'lib/core/util/data.rb', line 93

def self.false?(value)
  if value == false ||
    (value.is_a?(Symbol) && value == :false) ||
    (value.is_a?(String) && value.match(/^\s*(false|FALSE|False)\s*$/))
    return true
  end
  return false
end

.filter(data, method = false) ⇒ Object

Run a defined filter on a data object.

This method ensures that a given data object meets some criteria or else an empty value for that type is returned that matches the criteria.

Currently implemented filters:

  1. ::array Ensure result is an array (non arrays are converted)

  2. ::hash Ensure result is a hash (non hashes are converted)

  3. ::string Ensure result is a string (non strings are converted)

  4. ::symbol Ensure result is a symbol (non symbols are converted)

  5. ::test Ensure result is not empty (runs a boolean ::empty? check)

More filters can be added by adding methods to the Nucleon::Util::Data class.

For example:

module Nucleon::Util::Data
  def my_filter(data, default = '')
    # Return data modified or default
  end
end

my_data = Nucleon::Util::Data.filter(my_data, :my_filter)
  • Parameters

    • ANY

      data Ruby data object to run through filter

    • false, String

      method Filter method to execute or false for none

  • Returns

    • ANY

      Returns filtered data object

  • Errors



394
395
396
397
398
399
# File 'lib/core/util/data.rb', line 394

def self.filter(data, method = false)
  if method && respond_to?(method.to_sym)
    return send(method.to_sym, data)
  end
  return data
end

.hash(data, default = {}) ⇒ Object

Ensure a data object is a hash.

If data is given and it is not a hash, an empty hash is returned in it’s place.

  • Parameters

    • ANY

      data Ruby data to ensure hash

    • Hash

      default Default value if no data is given (nil)

  • Returns

    • Hash

      Returns a hash

  • Errors

See also:

  • ::filter (switch)

  • ::array

  • ::string

  • ::symbol

  • ::test



464
465
466
467
468
469
470
471
472
473
474
475
# File 'lib/core/util/data.rb', line 464

def self.hash(data, default = {})
  result = default
  if data
    case data
    when Hash
      result = data
    else
      result = {}
    end
  end
  return result
end

.interpolate(value, scope, options = {}) ⇒ Object

Interpolate values into data objects based on patterns.

This method interpolates values into either a single string or a hash of strings that are recursively processed.

This method requires our Hash#search method defined in the mod folder.

  • Parameters

    • String, Hash

      value Value to interpolate properties into

    • Hash

      scope Property values for text replacements

    • Hash

      options Method options

      • String

        :pattern Regexp pattern to match intepolated properties against

      • Integer

        :var_group Regexp group match for property name

      • String

        :flags Optional Regexp flags

  • Returns

    • String, Hash

      Returns interpolated string or hash of strings

  • Errors

See also:

  • Hash#search



752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
# File 'lib/core/util/data.rb', line 752

def self.interpolate(value, scope, options = {})

  pattern = ( options.has_key?(:pattern) ? options[:pattern] : '\$(\{)?([a-zA-Z0-9\_\-]+)(\})?' )
  group   = ( options.has_key?(:var_group) ? options[:var_group] : 2 )
  flags   = ( options.has_key?(:flags) ? options[:flags] : '' )

  if scope.is_a?(Hash)
    regexp = Regexp.new(pattern, flags.split(''))

    replace = lambda do |item|
      matches = item.match(regexp)
      result  = nil

      unless matches.nil?
        replacement = scope.search(matches[group], options)
        result      = item.gsub(matches[0], replacement) unless replacement.nil?
      end
      return result
    end

    case value
    when String
      while (temp = replace.call(value))
        value = temp
      end

    when Hash
      value.each do |key, data|
        value[key] = interpolate(data, scope, options)
      end
    end
  end
  return value
end

.merge(data, force = true, basic = true) ⇒ Object

Merge data objects together.

This method relies on the merging capabilities of the deep_merge gem. It switches between core Ruby shallow merge and deep_merge merges based on the basic boolean.

Elements at the end of the array override values for data at the beginning.

  • Parameters

    • Array<nil, String, Symbol, Array, Hash>

      data Ruby data objects to merge

    • Boolean

      force Whether or not to force override of values where types don’t match

    • Boolean

      basic Whether or not to perform a basic merge or deep (recursive) merge

  • Returns

    • nil, String, Symbol, Array, Hash

      Returns merged data object

  • Errors

See also:

  • ::undef?



677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
# File 'lib/core/util/data.rb', line 677

def self.merge(data, force = true, basic = true)
  value = data

  # Special case because this method is called from within Config.new so we
  # can not use Config.ensure, as that would cause an infinite loop.
  if force.is_a?(Nucleon::Config)
    basic = force.get(:basic, true)
    force = force.get(:force, true)
  end

  if data.is_a?(Array)
    value = undef?(data[0]) ? nil : data.shift.clone

    data.each do |item|
      item = undef?(item) ? nil : item.clone

      case value
      when Hash
        if basic
          if item.is_a?(Hash)
            value = value.merge(item)
          elsif force
            value = item
          end
        else
          begin
            require 'deep_merge'
            value = force ? value.deep_merge!(item) : value.deep_merge(item)

          rescue LoadError
            if item.is_a?(Hash) # Non recursive top level by default.
              value = value.merge(item)
            elsif force
              value = item
            end
          end
        end
      when Array
        if item.is_a?(Array)
          value = value.concat(item).uniq
        elsif force
          value = item
        end

      else
        value = item if force || item.is_a?(String) || item.is_a?(Symbol)
      end
    end
  end
  return value
end

.parse_json(json_text) ⇒ Object

Parse a JSON string into a Ruby data object.

This method uses the MultiJson gem to carry out the heavy lifting. We just sit back and enjoy the ride.

  • Parameters

    • String

      json_text JSON text string to parse into Ruby data

  • Returns

    • nil, true, false, String, Array, Hash<String|…|ANY>

      Returns parsed data object

  • Errors

See also:

  • ::to_json



252
253
254
# File 'lib/core/util/data.rb', line 252

def self.parse_json(json_text)
  return MultiJson.load(json_text)
end

.parse_yaml(yaml_text) ⇒ Object

Parse a YAML string into a Ruby data object.

This method uses the Ruby YAML module to carry out the heavy lifting. We just sit back and enjoy the ride.

  • Parameters

    • String

      yaml_text YAML text string to parse into Ruby data

  • Returns

    • nil, true, false, String, Array, Hash<String|…|ANY>

      Returns parsed data object

  • Errors

See also:

  • ::to_yaml



292
293
294
# File 'lib/core/util/data.rb', line 292

def self.parse_yaml(yaml_text)
  return YAML.load(yaml_text)
end

.prefix(prefix, data, pad = '_') ⇒ Object

Prefix every element in data with prefix separated by pad.

This method basically just does bulk prefixing. This has come in useful in quite a few applications, particularly with dealing with configurations.

This method can recursively set prefixes for hash keys as well.

  • Parameters

    • String

      prefix Prefix string to prepend to data elements

    • String, Symbol, Array, Hash

      data Data elements to prefix

    • String

      pad Whether or not to symbolize data keys before selection

  • Returns

    • String, Symbol, Array, Hash

      Returns prefixed data object

  • Errors

See also:

  • ::empty?



873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
# File 'lib/core/util/data.rb', line 873

def self.prefix(prefix, data, pad = '_')
  result = nil

  unless prefix.is_a?(Symbol) || ( prefix.is_a?(String) && ! empty?(prefix) )
    prefix = ''
  end
  prefix = prefix.to_s

  case data
  when String, Symbol
    result = ( prefix.empty? ? data.to_s : prefix + pad + data.to_s )

  when Array
    result = []
    data.each do |value|
      result << prefix(prefix, value, pad)
    end

  when Hash
    result = {}
    data.each do |key, value|
      result[prefix(prefix, key, pad)] = value
    end
  end
  return result
end

.rm_keys(data, keys, symbolize = false) ⇒ Object

Remove keys from a given hash.

This method first symbolizes all keys of the hash and then deletes any matching elements if the symbolize option is given.

  • Parameters

    • Hash

      data Ruby hash to remove keys from

    • String, Symbol, Array

      keys Keys to remove from

    • Boolean

      symbolize Whether or not to symbolize data keys before removal

  • Returns

    • Hash

      Returns cleaned data object

  • Errors

See also:

  • ::hash

  • ::symbol_map



806
807
808
809
810
811
812
813
814
815
816
# File 'lib/core/util/data.rb', line 806

def self.rm_keys(data, keys, symbolize = false)
  keys = [ keys ] unless keys.is_a?(Array)
  data = hash(data)
  data = symbol_map(data) if symbolize

  keys.each do |key|
    key = key.to_sym if symbolize
    data.delete(key)
  end
  data
end

.string(data, default = '') ⇒ Object

Ensure a data object is a string.

If data is given and it is not a string, the data.to_s method is called to get the rendered string.

  • Parameters

    • ANY

      data Ruby data to ensure string

    • String

      default Default value if no data is given (nil)

  • Returns

    • String

      Returns a string

  • Errors

See also:

  • ::filter (switch)

  • ::array

  • ::hash

  • ::symbol

  • ::test



498
499
500
501
502
503
504
505
506
507
508
509
# File 'lib/core/util/data.rb', line 498

def self.string(data, default = '')
  result = default
  if data
    case data
    when String
      result = data
    else
      result = data.to_s
    end
  end
  return result
end

.string_map(data) ⇒ Object

Return hash as a string map.

This method converts all hash keys to strings. Nested hashes are recursively translated as well.

This comes in really handy when performing operations across hashes in Ruby because of the distinction between symbols and strings.

  • Parameters

    • Hash<String, Symbol|…|ANY>

      data Hash data to stringify keys

  • Returns

    • Hash<String|…|ANY>

      Returns data structure grouped by string keys

  • Errors

See also:

  • ::symbol_map



221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/core/util/data.rb', line 221

def self.string_map(data)
  results = {}
  return data unless data

  case data
  when Hash
    data.each do |key, value|
      results[key.to_s] = string_map(value)
    end
  else
    results = data
  end
  return results
end

.subset(data, keys, symbolize = false) ⇒ Object

Select specific keys from a given hash.

This method first symbolizes all keys of the hash and then deletes any matching elements if the symbolize option is given.

  • Parameters

    • Hash

      data Ruby hash to select keys from

    • String, Symbol, Array

      keys Keys to select

    • Boolean

      symbolize Whether or not to symbolize data keys before selection

  • Returns

    • Hash

      Returns data object with selected keys

  • Errors

See also:

  • ::hash

  • ::symbol_map



837
838
839
840
841
842
843
844
845
846
847
848
# File 'lib/core/util/data.rb', line 837

def self.subset(data, keys, symbolize = false)
  keys     = [ keys ] unless keys.is_a?(Array)
  data     = hash(data)
  data     = symbol_map(data) if symbolize
  new_data = {}

  keys.each do |key|
    key           = key.to_sym if symbolize
    new_data[key] = data[key] if data.has_key?(key)
  end
  new_data
end

.symbol(data, default = :undefined) ⇒ Object

Ensure a data object is a symbol.

If data is given and it is not a symbol, the data.to_sym method is called to get the generated symbol. If data is not a string or symbol, it’s class name is symbolized.

  • Parameters

    • ANY

      data Ruby data to ensure symbol

    • Symbol

      default Default value if no data is given (:undefined)

  • Returns

    • Symbol

      Returns a symbol

  • Errors

See also:

  • ::filter (switch)

  • ::array

  • ::hash

  • ::string

  • ::test



533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
# File 'lib/core/util/data.rb', line 533

def self.symbol(data, default = :undefined)
  result = default
  if data
    case data
    when TrueClass, FalseClass
      result = data ? :true : :false
    when Symbol
      result = data
    when String
      result = data.to_sym
    else
      result = data.class.to_sym
    end
  end
  return result
end

.symbol_map(data) ⇒ Object

Return hash as a symbol map.

This method converts all hash keys to symbols. Nested hashes are recursively translated as well.

This comes in really handy when performing operations across hashes in Ruby because of the distinction between symbols and strings.

  • Parameters

    • Hash<String, Symbol|…|ANY>

      data Hash data to symbolize keys

  • Returns

    • Hash<Symbol|…|ANY>

      Returns data structure symbolized

  • Errors

See also:

  • ::string_map



187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/core/util/data.rb', line 187

def self.symbol_map(data)
  results = {}
  return data unless data

  case data
  when Hash
    data.each do |key, value|
      results[key.to_sym] = symbol_map(value)
    end
  else
    results = data
  end
  return results
end

.test(data) ⇒ Object

Test a data object for emptiness and return boolean result.

Uses the ::empty? method to check for emptiness.

  • Parameters

    • ANY

      data Ruby data to test for emptiness

  • Returns

    • Boolean

      Returns true if data not empty, false otherwise

  • Errors

See also:

  • ::filter (switch)

  • ::array

  • ::hash

  • ::string

  • ::symbol



569
570
571
572
# File 'lib/core/util/data.rb', line 569

def self.test(data)
  return false if Util::Data.empty?(data)
  return true
end

.to_json(data, pretty = true) ⇒ Object

Dump a Ruby object to a JSON string.

This method uses the MultiJson gem to carry out the heavy lifting. We just sit back and enjoy the ride.

  • Parameters

    • ANY

      data Ruby data to render JSON string

  • Returns

    • String

      Returns JSON rendered data object

  • Errors

See also:

  • ::parse_json



272
273
274
# File 'lib/core/util/data.rb', line 272

def self.to_json(data, pretty = true)
  return MultiJson.dump(data, :pretty => pretty)
end

.to_yaml(data) ⇒ Object

Dump a Ruby object to a YAML string.

This method uses the Ruby YAML module to carry out the heavy lifting. We just sit back and enjoy the ride.

  • Parameters

    • ANY

      data Ruby data to render YAML string

  • Returns

    • String

      Returns YAML rendered data object

  • Errors

See also:

  • ::parse_yaml



312
313
314
# File 'lib/core/util/data.rb', line 312

def self.to_yaml(data)
  return YAML.dump(data)
end

.true?(value) ⇒ Boolean

Check if given value is true.

It currently checks for: (our definition of true)

  • true

  • Symbols: :true

  • Strings: “true”, “TRUE”, “True

This method was created to provide an easy way for us to load and work with configurations from text formats, such as JSON.

  • Parameters

    • ANY

      value Value to check if true

  • Returns

    • Boolean

      Returns true if value is true, false otherwise

  • Errors

Returns:

  • (Boolean)


66
67
68
69
70
71
72
73
# File 'lib/core/util/data.rb', line 66

def self.true?(value)
  if value == true ||
    (value.is_a?(Symbol) && value == :true) ||
    (value.is_a?(String) && value.match(/^\s*(true|TRUE|True)\s*$/))
    return true
  end
  return false
end

.undef?(value) ⇒ Boolean

Check if given value is undefined.

It currently checks for: (our definition of undefined)

  • nil

  • Symbols: :undef, :undefined

  • Strings: “undef”, “UNDEF”, “Undef”, “nil”, “NIL”, “Nil

This method was created to provide an easy way for us to load and work with configurations from text formats, such as JSON.

  • Parameters

    • ANY

      value Value to check if undefined

  • Returns

    • Boolean

      Returns true if value is undefined, false otherwise

  • Errors

Returns:

  • (Boolean)


39
40
41
42
43
44
45
46
# File 'lib/core/util/data.rb', line 39

def self.undef?(value)
  if value.nil? ||
    (value.is_a?(Symbol) && value == :undef || value == :undefined) ||
    (value.is_a?(String) && value.match(/^\s*(undef|UNDEF|Undef|nil|NIL|Nil)\s*$/))
    return true
  end
  return false
end

.value(value, undefined_value = nil) ⇒ Object

Translate a value to internally standardized form.

It currently translates:

  • ::undef? to undefined_value

  • ::true? to true

  • ::false? to false

  • Array (recursively)

  • Hash (recursively)

This method was created to provide an easy way for us to load and work with configurations from text formats, such as JSON.

  • Parameters

    • ANY

      value Value to internalize

    • ANY

      undefined_value Value that represents undefined (nil)

  • Returns

    • ANY

      Returns internalized value object

  • Errors



337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'lib/core/util/data.rb', line 337

def self.value(value, undefined_value = nil)
  case value
  when String
    if undef?(value)
      value = undefined_value
    elsif true?(value)
      value = true
    elsif false?(value)
      value = false
    end

  when Array
    value.each_with_index do |item, index|
      value[index] = value(item, undefined_value)
    end

  when Hash
    value.each do |key, data|
      value[key] = value(data, undefined_value)
    end
  end
  return value
end