Module: IndiferentHash

Defined in:
lib/scout/indiferent_hash.rb,
lib/scout/indiferent_hash/options.rb,
lib/scout/indiferent_hash/serialize.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.add_defaults(options, defaults = {}) ⇒ Object



2
3
4
5
6
7
8
9
10
11
12
13
14
15
# File 'lib/scout/indiferent_hash/options.rb', line 2

def self.add_defaults(options, defaults = {})
  options = string2hash options if String === options
  IndiferentHash.setup(options)

  defaults = string2hash defaults if String === defaults

  defaults.each do |key, value|
    next if options.include?(key)

    options[key] = value 
  end

  options
end

.array2hash(array, default = nil) ⇒ Object



74
75
76
77
78
79
80
81
# File 'lib/scout/indiferent_hash/options.rb', line 74

def self.array2hash(array, default = nil)
  hash = {}
  array.each do |key, value|
    value = default.dup if value.nil? and not default.nil?
    hash[key] = value
  end
  IndiferentHash.setup(hash)
end

.dig(obj, *keys) ⇒ Object



173
174
175
176
# File 'lib/scout/indiferent_hash.rb', line 173

def self.dig(obj, *keys)
  IndiferentHash.setup obj
  obj.dig(*keys)
end

.hash2string(hash) ⇒ Object



88
89
90
91
92
93
94
# File 'lib/scout/indiferent_hash/options.rb', line 88

def self.hash2string(hash)
  hash.sort_by{|k,v| k.to_s}.collect{|k,v| 
    next unless %w(Symbol String Float Fixnum Integer Numeric TrueClass FalseClass Module Class Object).include? v.class.to_s
    [ Symbol === k ? ":" + k.to_s : k.to_s.chomp,
      Symbol === v ? ":" + v.to_s : v.to_s.chomp] * "="
  }.compact * "#"
end

.parse_options(str) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/scout/indiferent_hash/options.rb', line 118

def self.parse_options(str)
  options = {}
  # Match key=value pairs, supporting quoted values with spaces
  str.scan(/(\w+)=("[^"]*"|[^\s"]+)/) do |key, raw_value|
    value = raw_value.strip

    # Remove surrounding quotes if present
    if value.start_with?('"') && value.end_with?('"')
      value = value[1..-2]
    end

    # Split by commas, but preserve quoted substrings as single elements
    if value.include?(',')
      # This regex splits on commas not inside quotes
      parts = value.scan(/"[^"]*"|[^,]+/).map do |v|
        v = v.strip
        v = v[1..-2] if v.start_with?('"') && v.end_with?('"')
        v
      end
      value = parts
      options[key] = value
      next
    end

    options[key] = true and next if value.empty?
    options[key] = value[1..-1].to_sym and next if value[0] == ":"
    options[key] = Regexp.new(/#{value[1..-2]}/) and next if value[0] == "/" and value[-1] == "/"
    options[key] = value[1..-2] and next if value =~ /^['"].*['"]$/
    options[key] = value.to_i and next if value =~ /^\d+$/
    options[key] = value.to_f and next if value =~ /^\d*\.\d+$/
    options[key] = true and next if value == "true"
    options[key] = false and next if value == "false"
    options[key] = value
  end

  IndiferentHash.setup(options)
end

.positional2hash(keys, *values) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/scout/indiferent_hash/options.rb', line 61

def self.positional2hash(keys, *values)
  if Hash === values.last
    extra = values.pop
    inputs = IndiferentHash.zip2hash(keys, values)
    inputs.delete_if{|k,v| v.nil? or (String === v and v.empty?)}
    inputs = IndiferentHash.add_defaults inputs, extra
    inputs.delete_if{|k,v| not keys.include?(k) and not (Symbol === k ? keys.include?(k.to_s) : keys.include?(k.to_sym))}
    inputs
  else
    IndiferentHash.zip2hash(keys, values)
  end
end


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/scout/indiferent_hash/options.rb', line 156

def self.print_options(options)
  options.map do |key, value|
    if value.is_a?(Array)
      vals = value.map do |v|
        if v.to_s.empty? || v.to_s.include?(' ')
          "\"#{v}\""
        else
          v.to_s
        end
      end
      "#{key}=#{vals.join(',')}"
    else
      val = value.to_s
      val = "\"#{val}\"" if val.empty? || val.include?(' ')
      "#{key}=#{val}"
    end
  end.join(' ')
end

.process_options(hash, *keys) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/scout/indiferent_hash/options.rb', line 17

def self.process_options(hash, *keys)
  IndiferentHash.setup(hash)

  defaults = keys.pop if Hash === keys.last
  hash = IndiferentHash.add_defaults hash, defaults if defaults

  if keys.length == 1
    hash.include?(keys.first.to_sym) ? hash.delete(keys.first.to_sym) : hash.delete(keys.first.to_s) 
  else
    keys.collect do |key| hash.include?(key.to_sym) ? hash.delete(key.to_sym) : hash.delete(key.to_s) end
  end
end

.process_to_hash(list) ⇒ Object



83
84
85
86
# File 'lib/scout/indiferent_hash/options.rb', line 83

def self.process_to_hash(list)
  result = yield list
  zip2hash(list, result)
end

.pull_keys(hash, prefix) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/scout/indiferent_hash/options.rb', line 30

def self.pull_keys(hash, prefix)
  IndiferentHash.setup(hash)
  new = hash.delete("#{prefix}_options") if hash.include?("#{prefix}_options")
  new = {} if new.nil?
  IndiferentHash.setup(new)
  prefix = prefix.to_s
  hash.keys.each do |key|
    if key.to_s =~ /#{ prefix }_(.*)/
      case
      when String === key
        new[$1] = hash.delete key
      when Symbol === key
        new[$1.to_sym] = hash.delete key
      end
    else
      if key.to_s == prefix.to_s
        new[key] = hash.delete key
      end
    end
  end
  new
end

.serializable(obj) ⇒ Object



2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/scout/indiferent_hash/serialize.rb', line 2

def self.serializable(obj)
	case obj
	when Hash
 obj.each_with_object({}) do |(k, v), h|
h[k] = serializable(v)
 end

	when Array
 if obj.length <= 100
obj.map { |v| serializable(v) }
 else
first = obj.first(70).map { |v| serializable(v) }
last  = obj.last(30).map { |v| serializable(v) }
truncated_msg = "TRUNCATED only 100 out of #{obj.length} shown"

first + ['...'] + last + [truncated_msg]
 end

	else
 obj
	end
end

.setup(hash) ⇒ Object



7
8
9
10
# File 'lib/scout/indiferent_hash.rb', line 7

def self.setup(hash)
  hash.extend IndiferentHash 
  hash
end

.string2hash(string, sep = "#") ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/scout/indiferent_hash/options.rb', line 96

def self.string2hash(string, sep="#")
  options = {}

  string.split(sep).each do |str|
    key, _, value = str.partition "="

    key = key[1..-1].to_sym if key[0] == ":"

    options[key] = true and next if value.empty?
    options[key] = value[1..-1].to_sym and next if value[0] == ":"
    options[key] = Regexp.new(/#{value[1..-2]}/) and next if value[0] == "/" and value[-1] == "/"
    options[key] = value[1..-2] and next if value =~ /^['"].*['"]$/
    options[key] = value.to_i and next if value =~ /^\d+$/
    options[key] = value.to_f and next if value =~ /^\d*\.\d+$/
    options[key] = true and next if value == "true"
    options[key] = false and next if value == "false"
    options[key] = value
  end

  IndiferentHash.setup(options)
end

.zip2hash(list1, list2) ⇒ Object



53
54
55
56
57
58
59
# File 'lib/scout/indiferent_hash/options.rb', line 53

def self.zip2hash(list1, list2)
  hash = {}
  list1.each_with_index do |e,i|
    hash[e] = list2[i]
  end
  IndiferentHash.setup(hash)
end

Instance Method Details

#[](key) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/scout/indiferent_hash.rb', line 43

def [](key)
  res = super(key) 

  if ! (res.nil? || (_default? and not keys.include?(key)))
    IndiferentHash.setup(res) if Hash === res
    return res
  end

  res = case key
        when Symbol, Module
          super(key.to_s)
        when String
          super(key.to_sym)
        else
          res
        end
  IndiferentHash.setup(res) if Hash === res
  res
end

#[]=(key, value) ⇒ Object



34
35
36
37
# File 'lib/scout/indiferent_hash.rb', line 34

def []=(key,value)
  delete(key)
  super(key,value)
end

#_default?Boolean

Returns:

  • (Boolean)


39
40
41
# File 'lib/scout/indiferent_hash.rb', line 39

def _default?
  @_default ||= self.default or self.default_proc
end

#clean_versionObject



91
92
93
94
95
96
97
# File 'lib/scout/indiferent_hash.rb', line 91

def clean_version
  clean = {}
  each do |k,v|
    clean[k.to_s] = v unless clean.include? k.to_s
  end
  clean
end

#deep_merge(other) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/scout/indiferent_hash.rb', line 21

def deep_merge(other)
  new = self.dup
  IndiferentHash.setup(new)
  other.each do |k,value|
    if new.include?(k) && IndiferentHash === new[k] && Hash === value
      new[k] = new[k].deep_merge(value)
    else
      new[k] = value
    end
  end
  new
end

#delete(key) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/scout/indiferent_hash.rb', line 78

def delete(key)
  case key
  when Symbol, Module
    v = super(key) 
    v.nil? ? super(key.to_s) : v
  when String
    v = super(key)
    v.nil? ? super(key.to_sym) : v
  else
    super(key)
  end
end

#dig(*keys) ⇒ Object



162
163
164
165
166
167
168
169
170
171
# File 'lib/scout/indiferent_hash.rb', line 162

def dig(*keys)
  current = self
  while keys.any?
    first = keys.shift
    current = current[first]
    break if current.nil?
    IndiferentHash.setup(current) if Hash === current
  end
  current
end

#except(*list) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/scout/indiferent_hash.rb', line 144

def except(*list)
  full_list = list.dup

  list.each do |e|
    begin
      if String === e
        full_list << e.to_sym
      else
        full_list << e.to_s
      end
    rescue
      next
    end
  end

  super(*full_list)
end

#include?(key) ⇒ Boolean

Returns:

  • (Boolean)


67
68
69
70
71
72
73
74
75
76
# File 'lib/scout/indiferent_hash.rb', line 67

def include?(key)
  case key
  when Symbol, Module
    super(key) || super(key.to_s)
  when String
    super(key) || super(key.to_sym)
  else
    super(key)
  end
end

#keys_to_symObject



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

def keys_to_sym
  new = IndiferentHash.setup({})
  self.keys.each do |key|
    begin
      skey = key.is_a?(String) ? key.to_sym : key
    rescue
      skey = key
    end
    new[skey] = self[key]
  end
  new
end

#keys_to_sym!Object



116
117
118
119
120
121
122
123
124
125
# File 'lib/scout/indiferent_hash.rb', line 116

def keys_to_sym!
  string_keys = keys.select{|k| String === k}
  string_keys.each do |key|
    begin
      self[key.to_sym] = self.delete(key)
    rescue
      next
    end
  end
end

#merge(other) ⇒ Object



12
13
14
15
16
17
18
19
# File 'lib/scout/indiferent_hash.rb', line 12

def merge(other)
  new = self.dup
  IndiferentHash.setup(new)
  other.each do |k,value|
    new[k] = value
  end
  new
end

#pretty_printObject



140
141
142
# File 'lib/scout/indiferent_hash.rb', line 140

def pretty_print
  Misc.format_definition_list(self, sep: "\n")
end

#slice(*list) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/scout/indiferent_hash.rb', line 99

def slice(*list)
  ext_list = []
  list.each do |e|
    case e
    when Symbol
      ext_list << e
      ext_list << e.to_s
    when String
      ext_list << e
      ext_list << e.to_sym
    else
      ext_list << e
    end
  end
  IndiferentHash.setup(super(*ext_list))
end

#values_at(*key_list) ⇒ Object



63
64
65
# File 'lib/scout/indiferent_hash.rb', line 63

def values_at(*key_list)
  key_list.inject([]){|acc,key| acc << self[key]}
end