hashlib 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/hashlib.rb +132 -0
- metadata +63 -0
data/lib/hashlib.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
class Hash
|
2
|
+
def diff(other)
|
3
|
+
self.keys.inject({}) do |memo, key|
|
4
|
+
unless self[key] == other[key]
|
5
|
+
if other[key].is_a?(Hash)
|
6
|
+
memo[key] = self[key].diff(other[key])
|
7
|
+
else
|
8
|
+
memo[key] = [self[key], other[key]]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
memo
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def get(path, default=nil)
|
16
|
+
root = self
|
17
|
+
|
18
|
+
begin
|
19
|
+
if not path.is_a?(Array)
|
20
|
+
path = path.strip.scan(/[a-z0-9\@\_\-\+]+(?:\[[^\]]+\])?/).to_a
|
21
|
+
end
|
22
|
+
|
23
|
+
path.each do |p|
|
24
|
+
x, key, subfield, subvalue = p.split(/([a-z0-9\@\_\-\+]+)(?:\[([^=]+)(?:=(.+))?\])?/i)
|
25
|
+
root = (root[key] rescue nil)
|
26
|
+
#puts key, root.inspect
|
27
|
+
|
28
|
+
if subfield and root.is_a?(Array)
|
29
|
+
root.each do |r|
|
30
|
+
if r.is_a?(Hash) and r[subfield] and ( (subvalue && r[subfield].to_s == subvalue) || true)
|
31
|
+
root = r
|
32
|
+
break
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
return root || default
|
39
|
+
rescue NoMethodError
|
40
|
+
return default
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def set(path, value)
|
45
|
+
if not path.is_a?(Array)
|
46
|
+
path = path.strip.split(/[\/\.]/)
|
47
|
+
end
|
48
|
+
root = self
|
49
|
+
|
50
|
+
path[0..-2].each do |p|
|
51
|
+
root[p] = {} unless root[p].is_a?(Hash)
|
52
|
+
root = root[p]
|
53
|
+
end
|
54
|
+
|
55
|
+
if value
|
56
|
+
root[path.last] = value
|
57
|
+
else
|
58
|
+
root.reject!{|k,v| k.to_sym == path.last.to_sym }
|
59
|
+
end
|
60
|
+
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
def unset(path)
|
65
|
+
set(path, nil)
|
66
|
+
end
|
67
|
+
|
68
|
+
def rekey(from, to)
|
69
|
+
value = get(from)
|
70
|
+
unset(from)
|
71
|
+
set(to, value)
|
72
|
+
end
|
73
|
+
|
74
|
+
def join(inner_delimiter, outer_delimiter=nil)
|
75
|
+
outer_delimiter = inner_delimiter unless outer_delimiter
|
76
|
+
self.to_a.collect{|i| i.join(inner_delimiter) }.join(outer_delimiter)
|
77
|
+
end
|
78
|
+
|
79
|
+
def coalesce(prefix=nil, base=nil, delimiter='_')
|
80
|
+
base = self unless base
|
81
|
+
rv = {}
|
82
|
+
|
83
|
+
if base.is_a?(Hash)
|
84
|
+
base.each do |k,v|
|
85
|
+
if v
|
86
|
+
base.coalesce(k,v,delimiter).each do |kk,vv|
|
87
|
+
kk = (prefix.to_s+delimiter+kk.to_s) if prefix
|
88
|
+
rv[kk.to_s] = vv
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
else
|
93
|
+
rv[prefix.to_s] = base
|
94
|
+
end
|
95
|
+
|
96
|
+
rv
|
97
|
+
end
|
98
|
+
|
99
|
+
def each_recurse(root=self, path=[], &block)
|
100
|
+
root.each do |k,v|
|
101
|
+
path << k
|
102
|
+
|
103
|
+
if v.is_a?(Hash)
|
104
|
+
each_recurse(v, path, &block)
|
105
|
+
else
|
106
|
+
yield(k, v, path)
|
107
|
+
end
|
108
|
+
|
109
|
+
path.pop
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def compact
|
114
|
+
def _is_empty?(i)
|
115
|
+
i === nil or (i.is_a?(String) and i.strip.chomp.empty?) or (i.respond_to?(:empty?) and i.empty?)
|
116
|
+
end
|
117
|
+
|
118
|
+
each_recurse do |k,v,path|
|
119
|
+
path = path.join('.')
|
120
|
+
|
121
|
+
if v.is_a?(Array)
|
122
|
+
v.reject!{|i| _is_empty?(i) }
|
123
|
+
unset(path) if v.empty?
|
124
|
+
|
125
|
+
else
|
126
|
+
unset(path) if _is_empty?(v)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
self
|
131
|
+
end
|
132
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hashlib
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Gary Hetzel
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-14 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! "Hashlib: Utility methods for Ruby Hashes\n========================================\n\nHashlib
|
15
|
+
extends the base Ruby Hash class with new methods that offer useful functionality
|
16
|
+
for working with hashes, specifically addressing handling of deeply-nested Hashes
|
17
|
+
for representing rich object structures.\n\nget\n---\n\nThe get method is used to
|
18
|
+
allow for retrieval of a deeply-nested value in a hash structure.\n\nGiven:\n\n```ruby\nconfig
|
19
|
+
= {\n :global => {\n :security => {\n :sslroot => '/etc/ssl'\n },\n
|
20
|
+
\ :pidfile => '/var/run/example.pid'\n },\n :plugins => ['logger', 'cruncher']\n}\n```\n\nThe
|
21
|
+
following statements are equivalent:\n\n```ruby\nconfig.get('global.security.sslroot')\n\n#
|
22
|
+
returns the same thing as\n\nconfig[:global][:security][:sslroot]\n```\n\nHowever,
|
23
|
+
let's say you attempted to get <code>config[:global][:adapters][:path]</code>. You
|
24
|
+
would get a nasty NilError because <code>:adapters</code> doesn't exist. However,
|
25
|
+
if you used <code>config.get('global.adapters.path')</code>, the result would just
|
26
|
+
be <code>nil</code>. _get_ also takes a second argument that let's you specify
|
27
|
+
the default value if the given path is not found. This lets you very easily work
|
28
|
+
with rich nested hashes while also specifying sane defaults for missing values.\n\n\nset\n---\n\nThe
|
29
|
+
set method is the opposite of get. It creates one or more intermediary hashes along
|
30
|
+
a specified path and setting the value for the last component.\n\n```ruby\ny = {}\ny.set('this.is.a.number',
|
31
|
+
4)\n\n# results in\n# {\"this\"=>{\n# \"is\"=>{\n# \"a\"=>{\n# \"number\"=>4\n#
|
32
|
+
}}}}\n\n```\n"
|
33
|
+
email: garyhetzel@gmail.com
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- lib/hashlib.rb
|
39
|
+
homepage: https://github.com/ghetzel/hashlib
|
40
|
+
licenses: []
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
47
|
+
requirements:
|
48
|
+
- - ! '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements: []
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 1.8.11
|
60
|
+
signing_key:
|
61
|
+
specification_version: 3
|
62
|
+
summary: Useful utility methods for working with Ruby hashes
|
63
|
+
test_files: []
|