hash_pick 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.rdoc +3 -1
- data/lib/hash_pick/version.rb +1 -1
- data/lib/hash_pick.rb +94 -8
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 930eee6958a5e12f3706b0c47b2d8b36e8209a94
|
4
|
+
data.tar.gz: f3bbcca070e3d83dfba08d4286da1747bde8b6ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9473e4453f82608a60450281e1c4fce27b3e78bed49bef720a30102a9d691a267c69802c3af1cce88eabc0413e3e9ef74721710dae133bb3634e3fe882ae642
|
7
|
+
data.tar.gz: 5d1e2ad8ef12b33f3ca3aba8d6e33e7fe4802f94e30731899880ba93047ee7da28498ba10f86502251ed303abfcb837941525b7b9e5e44b2d6cac3815f96008a
|
data/README.rdoc
CHANGED
@@ -7,7 +7,9 @@ Hash paths can be expressed as lists of keys of these types:
|
|
7
7
|
* Object.
|
8
8
|
* String.
|
9
9
|
* Symbol.
|
10
|
-
*
|
10
|
+
* Either String or Symbol.
|
11
|
+
|
12
|
+
In addition, the general form of hash path query iteration is available in support of arbitrary path query semantics.
|
11
13
|
|
12
14
|
The methods are provided by the module {HashPick}.
|
13
15
|
|
data/lib/hash_pick/version.rb
CHANGED
data/lib/hash_pick.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# Fetch a value from a nested dictionary
|
5
5
|
#
|
6
6
|
# Provides methods for fetching a value from a nested dictionary (an object that implements +include?+ and +fetch+),
|
7
|
-
# using a key path expressed as a list (+
|
7
|
+
# using a key path expressed as a list (an object that implements +inject+).
|
8
8
|
#
|
9
9
|
# The key path is iterated. In each iteration, the key is looked up in the dictionary, and the value found is used
|
10
10
|
# as the dictionary for the next iteration. Lookup failure immediately returns nil.
|
@@ -45,22 +45,101 @@ module HashPick
|
|
45
45
|
# an ordered list of keys that implement +to_s+ and +to_sym+.
|
46
46
|
# @return [Object] the value found at the path in the dictionary.
|
47
47
|
# @return [nil] if any key lookup failed.
|
48
|
+
# @raise [ArgumentError] if +hash+ isn't a dictionary.
|
49
|
+
# @raise [ArgumentError] if +path+ isn't a list.
|
50
|
+
# @raise [ArgumentError] if any key in +path+ is +nil+.
|
48
51
|
#
|
49
52
|
def self.indifferent(hash, path)
|
50
|
-
path
|
51
|
-
|
53
|
+
assert_non_nil_path_keys(path)
|
54
|
+
|
55
|
+
pick(hash, path) do |acc, p|
|
52
56
|
if acc.include?(p.to_sym)
|
53
57
|
acc.fetch(p.to_sym)
|
54
58
|
elsif acc.include?(p.to_s)
|
55
59
|
acc[p.to_s]
|
56
60
|
else
|
57
|
-
break
|
61
|
+
throw :break
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# General form of hash path iteration
|
68
|
+
#
|
69
|
+
# Passes to +block+, the dictionary and hash key for each iteration of the hash path, using
|
70
|
+
# the return value of the block as the dictionary for the next iteration, or as the return
|
71
|
+
# value of the last iteration. If the block throws +:break+, iteration is aborted.
|
72
|
+
#
|
73
|
+
# @example Complex hash path semantics
|
74
|
+
#
|
75
|
+
# require "hash_pick"
|
76
|
+
#
|
77
|
+
# dict = {
|
78
|
+
# live: true,
|
79
|
+
# sheldon: {
|
80
|
+
# live: true,
|
81
|
+
# first_name: "Sheldon",
|
82
|
+
# last_name: "Hearn",
|
83
|
+
# },
|
84
|
+
# charles: {
|
85
|
+
# first_name: "Charles",
|
86
|
+
# last_name: "Mulder",
|
87
|
+
# }
|
88
|
+
# }
|
89
|
+
#
|
90
|
+
# HashPick.pick(dict, [:sheldon, :first_name]) do |p, k|
|
91
|
+
# throw :break unless p[:live] and p.include?(k)
|
92
|
+
# p[k]
|
93
|
+
# end
|
94
|
+
# # => "Sheldon"
|
95
|
+
#
|
96
|
+
# HashPick.pick(dict, [:charles, :first_name]) do |p, k|
|
97
|
+
# throw :break unless p[:live] and p.include?(k)
|
98
|
+
# p[k]
|
99
|
+
# end
|
100
|
+
# # => "Hearn"
|
101
|
+
#
|
102
|
+
# @param [Hash] hash
|
103
|
+
# the dictionary to apply the +path+ to.
|
104
|
+
# @param [Array] path
|
105
|
+
# an ordered list of path keys.
|
106
|
+
# @return [Object] the value of the last iteration.
|
107
|
+
# @return [nil] if +block+ throws +:break+ in any iteration.
|
108
|
+
# @raise [ArgumentError] if +hash+ isn't a dictionary.
|
109
|
+
# @raise [ArgumentError] if +path+ isn't a list.
|
110
|
+
#
|
111
|
+
def self.pick(hash, path, &block)
|
112
|
+
assert_dictionary(hash)
|
113
|
+
assert_enumerable_path(path)
|
114
|
+
catch(:break) do
|
115
|
+
path.inject(hash) do |acc, p|
|
116
|
+
break unless dictionary?(acc)
|
117
|
+
block.call(acc, p)
|
58
118
|
end
|
59
119
|
end
|
60
120
|
end
|
61
121
|
|
62
122
|
class << self
|
63
123
|
alias_method :[], :indifferent
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def assert_dictionary(hash)
|
128
|
+
raise ArgumentError.new("hash is not a dictionary") unless dictionary?(hash)
|
129
|
+
end
|
130
|
+
|
131
|
+
def dictionary?(hash)
|
132
|
+
hash.respond_to?(:include?) && hash.respond_to?(:fetch)
|
133
|
+
end
|
134
|
+
|
135
|
+
def assert_non_nil_path_keys(path)
|
136
|
+
raise ArgumentError.new("nil key in path") if path.any? { |p| p.nil? }
|
137
|
+
end
|
138
|
+
|
139
|
+
def assert_enumerable_path(path)
|
140
|
+
raise ArgumentError.new("path is not enumerable") unless path.respond_to?(:inject)
|
141
|
+
end
|
142
|
+
|
64
143
|
end
|
65
144
|
|
66
145
|
##
|
@@ -74,12 +153,11 @@ module HashPick
|
|
74
153
|
# an ordered list of object keys.
|
75
154
|
# @return [Object] the value found at the path in the dictionary.
|
76
155
|
# @return [nil] if any key lookup failed.
|
156
|
+
# @raise [ArgumentError] if +hash+ isn't a dictionary.
|
157
|
+
# @raise [ArgumentError] if +path+ isn't a list.
|
77
158
|
#
|
78
159
|
def self.object(hash, path)
|
79
|
-
|
80
|
-
break unless acc.respond_to?(:include?) && acc.respond_to?(:fetch) && acc.include?(p)
|
81
|
-
acc[p]
|
82
|
-
end
|
160
|
+
pick(hash, path) { |acc, p| acc[p] }
|
83
161
|
end
|
84
162
|
|
85
163
|
##
|
@@ -93,8 +171,12 @@ module HashPick
|
|
93
171
|
# an ordered list of keys that implement +to_sym+.
|
94
172
|
# @return [Object] the value found at the path in the dictionary.
|
95
173
|
# @return [nil] if any key lookup failed.
|
174
|
+
# @raise [ArgumentError] if +hash+ isn't a dictionary.
|
175
|
+
# @raise [ArgumentError] if +path+ isn't a list.
|
176
|
+
# @raise [ArgumentError] if any key in +path+ is +nil+.
|
96
177
|
#
|
97
178
|
def self.symbol(hash, path)
|
179
|
+
assert_non_nil_path_keys(path)
|
98
180
|
object(hash, path.map(&:to_sym))
|
99
181
|
end
|
100
182
|
|
@@ -109,8 +191,12 @@ module HashPick
|
|
109
191
|
# an ordered list of keys that implement +to_s+.
|
110
192
|
# @return [Object] the value found at the path in the dictionary.
|
111
193
|
# @return [nil] if any key lookup failed.
|
194
|
+
# @raise [ArgumentError] if +hash+ isn't a dictionary.
|
195
|
+
# @raise [ArgumentError] if +path+ isn't a list.
|
196
|
+
# @raise [ArgumentError] if any key in +path+ is +nil+.
|
112
197
|
#
|
113
198
|
def self.string(hash, path)
|
199
|
+
assert_non_nil_path_keys(path)
|
114
200
|
object(hash, path.map(&:to_s))
|
115
201
|
end
|
116
202
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hash_pick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sheldon Hearn
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|