Class: HashTree

Inherits:
Object
  • Object
show all
Defined in:
lib/hash-tree.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hash = {}) ⇒ HashTree

************************************************************************************* CONSTRUCTOR *************************************************************************************



8
9
10
11
12
# File 'lib/hash-tree.rb', line 8

def initialize(hash={})
  hash = {} unless hash.is_a? Hash

  @hash = hash
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args, &block) ⇒ Object (private)



442
443
444
445
446
447
448
449
# File 'lib/hash-tree.rb', line 442

def method_missing(m, *args, &block)
  if exists?(m.to_s)
    return get(m.to_s)
  else
    return nil
    #raise "DIG : The method #{m} doesn't exist in HashTree"
  end
end

Class Method Details

.from_json(json_data) ⇒ Object

************************************************************************************* PUBLIC CLASS METHODS *************************************************************************************



18
19
20
21
22
23
24
25
26
27
# File 'lib/hash-tree.rb', line 18

def self.from_json(json_data)
  return nil if json_data.to_s.empty?

  parsed_data = JSON.parse(json_data)

  tree = self.new(parsed_data)
  tree.replace_values!(nil, '')

  return tree
end

.from_json_path(json_path) ⇒ Object



29
30
31
# File 'lib/hash-tree.rb', line 29

def self.from_json_path(json_path)
  from_json File.read(json_path)
end

.from_xml(xml_data) ⇒ Object



33
34
35
36
37
38
39
40
# File 'lib/hash-tree.rb', line 33

def self.from_xml(xml_data)
  return nil if xml_data.to_s.empty?

  tree = self.new(Nori.parse(xml_data))
  tree.replace_values!(nil, '')

  return tree
end

.from_xml_path(xml_path) ⇒ Object



42
43
44
# File 'lib/hash-tree.rb', line 42

def self.from_xml_path(xml_path)
  from_xml File.read(xml_path)
end

.from_yml_path(yml_path) ⇒ Object



46
47
48
49
50
51
52
# File 'lib/hash-tree.rb', line 46

def self.from_yml_path(yml_path)
  yml_data = YAML.load_file(yml_path)

  tree = self.new(yml_data)

  return tree
end

Instance Method Details

#checksumObject

************************************************************************************* PUBLIC METHODS *************************************************************************************



58
59
60
# File 'lib/hash-tree.rb', line 58

def checksum
  Digest::MD5.hexdigest(@hash.to_json.scan(/\S/).sort.join)
end

#children(name) ⇒ Object



62
63
64
65
66
67
68
# File 'lib/hash-tree.rb', line 62

def children(name)
  if @hash[name] and @hash[name][name.chop]
    return [@hash[name][name.chop]].flatten
  else
    return []
  end
end

#clone_treeObject



70
71
72
# File 'lib/hash-tree.rb', line 70

def clone_tree
  HashTree.new(Marshal.load(Marshal.dump(@hash)))
end

#compact!Object

Remove all key with a nil value



75
76
77
# File 'lib/hash-tree.rb', line 75

def compact!
  @hash = compact
end

#each(options = {}, &block) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/hash-tree.rb', line 79

def each(options={}, &block)
  options = { :hash => @hash, :key_path => [], :scope => nil }.merge(options)

  options[:hash].each do |key, value|
    key_path = [options[:key_path], key].flatten
    key_path_string = key_path.join('.')

    if in_scope?(key_path_string, options[:scope])
      if (options[:scope] and options[:scope] == key_path_string)
        yield options[:hash], key, value, key_path_string
      else
        cast(value, Array).each do |item|
          if item.is_a? Hash
            each(:hash => item, :key_path => key_path, :scope => options[:scope], &block)
          else
            yield options[:hash], key, item, key_path_string
          end
        end
      end
    end
  end
end

#empty?Boolean



102
103
104
# File 'lib/hash-tree.rb', line 102

def empty?
  @hash.empty?
end

#exists?(path = '', hash = nil) ⇒ Boolean



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/hash-tree.rb', line 106

def exists?(path='', hash=nil)
  hash = @hash unless hash

  path_parts = path.split('.')

  hash.each do |key, value|
    value_for_loop = (value.is_a? Array) ? value : [value]

    if path_parts[0] == key
      return true if path_parts.length == 1

      value_for_loop.each do |item|
        if item.is_a?(Hash)
          return true if exists?(path_parts[1..-1].join('.'), item)
        end
      end

    end
  end

  return false
end

#get(path = '', options = {}) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/hash-tree.rb', line 129

def get(path='', options={})
  options = { :default => '', :force => nil }.merge(options)

  if not path.empty?
    data = []
    self.each(:scope => path) { |parent, k, v| data << cast(v, options[:force]) }
    data = (data.length <= 1 ? data.first : data)
  else
    data = @hash
  end

  return (data == nil ? options[:default] : data)
end

#idObject



156
157
158
159
# File 'lib/hash-tree.rb', line 156

def id
  #override the id method of all object
  get('id')
end

#insert(path, content) ⇒ Object



161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/hash-tree.rb', line 161

def insert(path, content)
  current_value = get(path)

  if current_value.is_a? Array
    if content.is_a? Array
      current_value = current_value.concat(content)
    else
      current_value << content
    end
  end

  set(path, current_value)
end

#inspect(options = {}) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/hash-tree.rb', line 175

def inspect(options={})
  options = { :hash => nil, :position => 0, :raw => true }.merge(options)

  options[:hash] = @hash unless options[:hash]

  return options[:hash].inspect if options[:raw]

  content = ""

  options[:hash].each do |key, value|
    convert_to_array(value).each do |item|
      content << "\n" + ('   ' * options[:position]) + "#{key} : "
      content << (item.is_a?(Hash) ? inspect(:hash => item, :position => options[:position]+1) : value.inspect)
    end
  end

  return content
end

#keys_to_s!(options = {}) ⇒ Object



143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/hash-tree.rb', line 143

def keys_to_s!(options={})
  options = { :hash => nil }.merge(options)

  options[:hash] = @hash unless options[:hash]

  options[:hash].keys_to_s!

  options[:hash].each do |key, value|
    value_for_loop = (value.is_a? Array) ? value : [value]
    value_for_loop.each { |item| keys_to_s!(:hash => item) if item.is_a? Hash }
  end
end

#merge(other_hash) ⇒ Object



194
195
196
# File 'lib/hash-tree.rb', line 194

def merge(other_hash)
  @hash = merge_children(@hash, other_hash)
end

#remove(path, options = {}) ⇒ Object



198
199
200
201
202
# File 'lib/hash-tree.rb', line 198

def remove(path, options={})
  options = { :if => nil, :remove_leaf => true, :unless => nil }.merge(options)

  set(path, nil, options) if exists?(path)
end

#rename_key!(path, new_name, hash = nil) ⇒ Object



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/hash-tree.rb', line 204

def rename_key!(path, new_name, hash=nil)
  hash = @hash unless hash

  path_parts = path.split('.')

  renamed_keys = {}

  hash.each do |key, value|
    if path_parts[0] == key
      if path_parts.length == 1
        renamed_keys[new_name] = hash.delete path_parts[0]
      else
        convert_to_array(value).each { |i| rename_key!(path_parts[1..-1].join('.'), new_name, i) if i.is_a? Hash }
      end
    end
  end

  hash.merge! renamed_keys if not renamed_keys.empty?
end

#replace_values!(old_value, new_value, hash = nil) ⇒ Object



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/hash-tree.rb', line 224

def replace_values!(old_value, new_value, hash=nil)
  hash = @hash unless hash

  hash.each do |key, value|
    if value.is_a? Array
      value.each do |item|
        if item.is_a?(Hash)
          item = replace_values!(old_value, new_value, item)
        else
          item = new_value if item == old_value
        end
      end
    elsif value.is_a? Hash
      value = replace_values!(old_value, new_value, value)
    elsif value == old_value
      value = new_value
    end

    hash[key] = value
  end

  return hash
end

#set(path, value, options = {}) ⇒ Object



248
249
250
251
252
# File 'lib/hash-tree.rb', line 248

def set(path, value, options={})
  options = { :accept_nil => true, :if => nil, :remove_leaf => false, :unless => nil }.merge(options)

  set_children(@hash, path, value, options) if options[:accept_nil] or value
end

#slash(path) ⇒ Object



254
255
256
257
258
259
260
261
262
263
# File 'lib/hash-tree.rb', line 254

def slash(path)
  if exists?(path)
    slashed_tree = get(path)
    slashed_tree = slashed_tree.first if slashed_tree.is_a? Array and slashed_tree.length == 1 and slashed_tree.first.is_a? Hash
  else
    slashed_tree = @hash
  end

  return HashTree.new(slashed_tree)
end

#slash!(path) ⇒ Object



265
266
267
# File 'lib/hash-tree.rb', line 265

def slash!(path)
  @hash = slash(path).get
end

#to_jsonObject



269
270
271
# File 'lib/hash-tree.rb', line 269

def to_json
  @hash.to_json
end

#to_yamlObject



273
274
275
276
277
# File 'lib/hash-tree.rb', line 273

def to_yaml
  self.keys_to_s!

  return @hash.ya2yaml
end