nice_hash 1.15.2 → 1.15.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -1
- data/lib/nice/hash/change_one_by_one.rb +49 -0
- data/lib/nice/hash/compare_structure.rb +69 -0
- data/lib/nice/hash/delete_nested.rb +37 -0
- data/lib/nice/hash/generate.rb +209 -0
- data/lib/nice/hash/get_all_keys.rb +26 -0
- data/lib/nice/hash/get_values.rb +152 -0
- data/lib/nice/hash/nice_filter.rb +53 -0
- data/lib/nice/hash/pattern_fields.rb +89 -0
- data/lib/nice/hash/select_fields.rb +75 -0
- data/lib/nice/hash/select_key.rb +56 -0
- data/lib/nice/hash/set_nested.rb +54 -0
- data/lib/nice/hash/set_values.rb +99 -0
- data/lib/nice/hash/transtring.rb +32 -0
- data/lib/nice/hash/validate.rb +196 -0
- data/lib/nice_hash.rb +16 -1133
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e1518b1eb83a00333a4051d91aa0b40fb9fe58e4b0b3ad229fcc78b0f86eb56
|
4
|
+
data.tar.gz: 69c215835f068a459dfc0e01605c45c42a5447e4e818eeabfac3f90a746c6012
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f61c5845665e7dcddf367e2850afb0d83b95bef3d39c8931be7bce5f27ffc24d6352b5c13d9a600f0d128fc25b1ff8332a2796943abf7f6fe647c4ac9739830e
|
7
|
+
data.tar.gz: 6f5ae2c245b192ee7ee331bf6d1a990551dd5e57e93997d168e83a3acfa2d471649ca83e06efdc0a3e18f4f948b1a7e594a6bdd5a2de916745bc9339e2228994
|
data/.yardopts
CHANGED
@@ -0,0 +1,49 @@
|
|
1
|
+
class NiceHash
|
2
|
+
###########################################################################
|
3
|
+
# Change only one value at a time and return an Array of Hashes
|
4
|
+
# Let's guess we need to test a typical registration REST service and the service has many fields with many validations but we want to test it one field at a time.
|
5
|
+
# This method generates values following the patterns on patterns_hash and generates a new hash for every pattern/select field found on patterns_hash using the value supplied on values_hash
|
6
|
+
# input:
|
7
|
+
# patterns_hash:
|
8
|
+
# (Hash) Hash where we have defined the patterns to follow.
|
9
|
+
# (Array) In case of array supplied, the pair: [pattern_hash, select_hash_key]. select_hash_key will filter the hash by that key
|
10
|
+
# values_hash: (Hash) Hash of values to use to modify the values generated on patterns_hash
|
11
|
+
# output: (Array of Hashes)
|
12
|
+
# example:
|
13
|
+
# wrong_min_length_hash = my_hash.generate(:correct, errors: :min_length)
|
14
|
+
# array_of_hashes = NiceHash.change_one_by_one([my_hash, :correct], wrong_min_length_hash)
|
15
|
+
# array_of_hashes.each {|hash_with_one_wrong_field|
|
16
|
+
# #Here your code to send through http the JSON data stored in hash_with_one_wrong_field
|
17
|
+
# #if you want to know which field is the one that is wrong:
|
18
|
+
# res = my_hash.validate(:correct, hash_with_one_wrong_field)
|
19
|
+
# }
|
20
|
+
###########################################################################
|
21
|
+
def NiceHash.change_one_by_one(patterns_hash, values_hash)
|
22
|
+
if patterns_hash.kind_of?(Array)
|
23
|
+
select_key = patterns_hash[1]
|
24
|
+
pattern_hash = patterns_hash[0]
|
25
|
+
else
|
26
|
+
pattern_hash = patterns_hash
|
27
|
+
select_key = []
|
28
|
+
end
|
29
|
+
array = Array.new
|
30
|
+
good_values = NiceHash.generate(pattern_hash, select_key)
|
31
|
+
select_keys = pattern_hash.pattern_fields(select_key) + pattern_hash.select_fields(select_key)
|
32
|
+
select_keys.each { |field|
|
33
|
+
new_hash = Marshal.load(Marshal.dump(good_values))
|
34
|
+
# to deal with the case same values... like in pwd1, pwd2, pwd3
|
35
|
+
if field[-1].kind_of?(Array)
|
36
|
+
last_to_set = field[-1]
|
37
|
+
else
|
38
|
+
last_to_set = [field[-1]]
|
39
|
+
end
|
40
|
+
last_to_set.each { |f|
|
41
|
+
keys = field[0..-2] << f
|
42
|
+
new_hash.bury(keys, values_hash.dig(*keys))
|
43
|
+
}
|
44
|
+
array << new_hash
|
45
|
+
}
|
46
|
+
return array
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class NiceHash
|
2
|
+
##################################################
|
3
|
+
# Analyzes the supplied replica and verifies that the structure follows the one supplied on structure
|
4
|
+
#
|
5
|
+
# @param structure [Array] [Hash] Contains the structure that should follow the replica. It can be a nested combination of arrays and hashes.
|
6
|
+
# @param replica [Array] [Hash] Contains the element to be verified on following the supplied structure. It can be a nested combination of arrays and hashes.
|
7
|
+
# @param compare_only_if_exist_key [Boolean] (Default false) If true, in case an element exist on structure but doesn't exist on replica won't be verified.
|
8
|
+
# @param patterns [Hash] add verification of data values following the patterns supplied on a one level hash
|
9
|
+
#
|
10
|
+
# @return [Boolean] true in case replica follows the structure supplied
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# my_structure = [
|
14
|
+
# { name: 'xxx',
|
15
|
+
# zip: 'yyyy',
|
16
|
+
# customer: true,
|
17
|
+
# product_ids: [1]
|
18
|
+
# }
|
19
|
+
# ]
|
20
|
+
# my_replica = [ {name: 'Peter Ben', zip: '1121A', customer: false, product_ids: []},
|
21
|
+
# {name: 'John Woop', zip: '74014', customer: true, product_ids: [10,120,301]}]
|
22
|
+
# NiceHash.compare_structure(my_structure, my_replica)
|
23
|
+
# #>true
|
24
|
+
##################################################
|
25
|
+
def NiceHash.compare_structure(structure, replica, compare_only_if_exist_key = false, patterns = {})
|
26
|
+
unless structure.class == replica.class or
|
27
|
+
((structure.is_a?(TrueClass) or structure.is_a?(FalseClass)) and (replica.is_a?(TrueClass) or replica.is_a?(FalseClass)))
|
28
|
+
puts "NiceHash.compare_structure: different object type #{structure.class} is not #{replica.class}. expected: #{structure.inspect}. found: #{replica.inspect}."
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
success = true
|
32
|
+
if structure.is_a?(Hash)
|
33
|
+
structure.each do |key, value|
|
34
|
+
if patterns.key?(key) and replica.key?(key)
|
35
|
+
unless (patterns[key].is_a?(Array) and replica[key].is_a?(Array) and replica[key].empty?) or
|
36
|
+
{key => patterns[key]}.validate({key => replica[key]}).empty?
|
37
|
+
puts "NiceHash.compare_structure: key :#{key} not following pattern #{patterns[key]}. value: #{replica[key]}"
|
38
|
+
success = false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
if compare_only_if_exist_key and replica.key?(key)
|
43
|
+
unless compare_structure(value, replica[key], compare_only_if_exist_key, patterns)
|
44
|
+
puts "NiceHash.compare_structure: key :#{key} different."
|
45
|
+
success = false
|
46
|
+
end
|
47
|
+
elsif compare_only_if_exist_key == false
|
48
|
+
unless replica.key?(key)
|
49
|
+
puts "NiceHash.compare_structure: key :#{key} missing."
|
50
|
+
success = false
|
51
|
+
else
|
52
|
+
unless compare_structure(value, replica[key], compare_only_if_exist_key, patterns)
|
53
|
+
puts "NiceHash.compare_structure: key :#{key} different."
|
54
|
+
success = false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
elsif structure.is_a?(Array)
|
60
|
+
# compare all elements of replica with the structure of the first element on structure
|
61
|
+
replica.each do |elem|
|
62
|
+
unless compare_structure(structure[0], elem, compare_only_if_exist_key, patterns)
|
63
|
+
success = false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
return success
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class NiceHash
|
2
|
+
##################################################
|
3
|
+
# Deletes the supplied nested key
|
4
|
+
#
|
5
|
+
# @param hash [Hash] The hash we want
|
6
|
+
# @param nested_key [Hash] [String] String with the nested key: 'uno.dos.tres' or a hash { uno: {dos: :tres} }
|
7
|
+
#
|
8
|
+
# @return [Hash]
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# my_hash = { user: {
|
12
|
+
# address: {
|
13
|
+
# city: 'Madrid',
|
14
|
+
# country: 'Spain'
|
15
|
+
# },
|
16
|
+
# name: 'Peter',
|
17
|
+
# age: 33
|
18
|
+
# },
|
19
|
+
# customer: true
|
20
|
+
# }
|
21
|
+
# NiceHash.delete_nested(my_hash, 'user.address.city')
|
22
|
+
# #>{:user=>{:address=>{:country=>"Spain"}, :name=>"Peter", :age=>33}, :customer=>true}
|
23
|
+
##################################################
|
24
|
+
def self.delete_nested(hash, nested_key)
|
25
|
+
nested_key = transtring(nested_key)
|
26
|
+
keys = nested_key.split(".")
|
27
|
+
if keys.size == 1
|
28
|
+
hash.delete(nested_key.to_sym)
|
29
|
+
else
|
30
|
+
last_key = keys[-1]
|
31
|
+
eval("hash.#{keys[0..(keys.size - 2)].join(".")}.delete(:#{last_key})")
|
32
|
+
end
|
33
|
+
return hash
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
class NiceHash
|
2
|
+
|
3
|
+
###########################################################################
|
4
|
+
# It will generate a new hash with the values generated from the string patterns and select fields specified.
|
5
|
+
# In case supplied select_hash_key and a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
|
6
|
+
# If expected_errors specified the values will be generated with the specified errors.
|
7
|
+
# input:
|
8
|
+
# pattern_hash: (Hash) Hash we want to use to generate the values
|
9
|
+
# select_hash_key: (key value) (optional) The key we want to select on the subhashes
|
10
|
+
# expected_errors: (Array) (optional) (alias: errors) To generate the string patterns with the specified errors.
|
11
|
+
# The possible values you can specify is one or more of these ones:
|
12
|
+
# :length: wrong length, minimum or maximum
|
13
|
+
# :min_length: wrong minimum length
|
14
|
+
# :max_length: wrong maximum length
|
15
|
+
# :value: wrong resultant value
|
16
|
+
# :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.
|
17
|
+
# :excluded_data: the resultant string will include one or more characters that should be excluded. It works only if excluded data supplied on the pattern.
|
18
|
+
# :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.
|
19
|
+
# output: (Hash)
|
20
|
+
# The Hash with the select_hash_key selected and the values generated from the string patterns and select fields specified.
|
21
|
+
# examples:
|
22
|
+
# new_hash = NiceHash.generate(my_hash)
|
23
|
+
# #> {:name=>"Peter",
|
24
|
+
# :address=>{:wrong=>"\#$$$$$", :correct=>"KZPCzxsWGMLqonesu wbqH"},
|
25
|
+
# :city=>{:wrong=>"Germany", :correct=>"Barcelona"},
|
26
|
+
# :products=> [
|
27
|
+
# {:name=>"gIqkWygmVm", :price=>{:wrong=>"-20", :correct=>"34338330"}},
|
28
|
+
# {:name=>"CK68VLIcYf", :price=>{:wrong=>"-20", :correct=>"616066520"}}
|
29
|
+
# ]
|
30
|
+
# }
|
31
|
+
# new_hash = NiceHash.generate(my_hash, :correct)
|
32
|
+
# #> {:name=>"Peter",
|
33
|
+
# :address=>"juQeAVZjIuWBPsE",
|
34
|
+
# :city=>"Madrid",
|
35
|
+
# :products=> [
|
36
|
+
# {:name=>"G44Ilr0puV", :price=>"477813"},
|
37
|
+
# {:name=>"v6ojs79LOp", :price=>"74820"}
|
38
|
+
# ]
|
39
|
+
# }
|
40
|
+
# new_hash = NiceHash.generate(my_hash, :correct, expected_errors: [:min_length])
|
41
|
+
# #> {:name=>"Peter",
|
42
|
+
# :address=>"ZytjefJ",
|
43
|
+
# :city=>"Madri",
|
44
|
+
# :products=>[
|
45
|
+
# {:name=>"cIBrzeO", :price=>""},
|
46
|
+
# {:name=>"5", :price=>""}
|
47
|
+
# ]
|
48
|
+
# }
|
49
|
+
# Using it directly on Hash class, generate(select_hash_key=nil, expected_errors: []) (alias: gen):
|
50
|
+
# new_hash = my_hash.generate
|
51
|
+
# new_hash = my_hash.gen(:correct)
|
52
|
+
# new_hash = my_hash.generate(:correct, errors: [:min_length])
|
53
|
+
###########################################################################
|
54
|
+
def NiceHash.generate(pattern_hash, select_hash_key = nil, expected_errors: [], **synonyms)
|
55
|
+
hashv = Hash.new()
|
56
|
+
same_values = Hash.new()
|
57
|
+
expected_errors = synonyms[:errors] if synonyms.keys.include?(:errors)
|
58
|
+
if expected_errors.kind_of?(Symbol)
|
59
|
+
expected_errors = [expected_errors]
|
60
|
+
end
|
61
|
+
|
62
|
+
if pattern_hash.kind_of?(Hash) and pattern_hash.size > 0
|
63
|
+
pattern_hash.each { |key, value|
|
64
|
+
if key.kind_of?(Array)
|
65
|
+
same_values[key[0]] = key.dup
|
66
|
+
same_values[key[0]].shift
|
67
|
+
key = key[0]
|
68
|
+
end
|
69
|
+
if value.kind_of?(Hash)
|
70
|
+
if value.keys.include?(select_hash_key)
|
71
|
+
value = value[select_hash_key]
|
72
|
+
else
|
73
|
+
value = NiceHash.generate(value, select_hash_key, expected_errors: expected_errors)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
if value.kind_of?(String) or value.kind_of?(Symbol)
|
77
|
+
if ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^!?\d+-?\d*:.+/).size > 0
|
78
|
+
hashv[key] = StringPattern.generate(value, expected_errors: expected_errors)
|
79
|
+
elsif ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size > 0
|
80
|
+
if expected_errors.include?(:min_length) or (expected_errors.include?(:length) and rand.round == 0)
|
81
|
+
min = value.to_s.split("|").min { |a, b| a.size <=> b.size }
|
82
|
+
hashv[key] = min[0..-2] unless min == ""
|
83
|
+
end
|
84
|
+
if !hashv.keys.include?(key) and (expected_errors.include?(:max_length) or expected_errors.include?(:length))
|
85
|
+
max = value.to_s.split("|").max { |a, b| a.size <=> b.size }
|
86
|
+
hashv[key] = max + max[-1]
|
87
|
+
end
|
88
|
+
if expected_errors.include?(:value) or
|
89
|
+
expected_errors.include?(:string_set_not_allowed) or
|
90
|
+
expected_errors.include?(:required_data)
|
91
|
+
if hashv.keys.include?(key)
|
92
|
+
v = hashv[key]
|
93
|
+
else
|
94
|
+
v = value.to_s.split("|").sample
|
95
|
+
end
|
96
|
+
unless expected_errors.include?(:string_set_not_allowed)
|
97
|
+
v = StringPattern.generate(:"#{v.size}:[#{value.to_s.split("|").join.split(//).uniq.join}]")
|
98
|
+
hashv[key] = v unless value.to_s.split("|").include?(v)
|
99
|
+
end
|
100
|
+
unless hashv.keys.include?(key)
|
101
|
+
one_wrong_letter = StringPattern.generate(:"1:LN$[%#{value.to_s.split("|").join.split(//).uniq.join}%]")
|
102
|
+
v[rand(v.size)] = one_wrong_letter
|
103
|
+
hashv[key] = v unless value.to_s.split("|").include?(v)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
unless hashv.keys.include?(key)
|
107
|
+
hashv[key] = value.to_s.split("|").sample
|
108
|
+
end
|
109
|
+
else
|
110
|
+
hashv[key] = value
|
111
|
+
end
|
112
|
+
elsif value.kind_of?(Array)
|
113
|
+
array_pattern = false
|
114
|
+
value.each { |v|
|
115
|
+
if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
|
116
|
+
hashv[key] = StringPattern.generate(value, expected_errors: expected_errors)
|
117
|
+
array_pattern = true
|
118
|
+
break
|
119
|
+
end
|
120
|
+
}
|
121
|
+
unless array_pattern
|
122
|
+
value_ret = Array.new
|
123
|
+
value.each { |v|
|
124
|
+
if v.is_a?(Hash)
|
125
|
+
ret = NiceHash.generate(v, select_hash_key, expected_errors: expected_errors)
|
126
|
+
else
|
127
|
+
ret = NiceHash.generate({ doit: v }, select_hash_key, expected_errors: expected_errors)
|
128
|
+
ret = ret[:doit] if ret.is_a?(Hash) and ret.key?(:doit)
|
129
|
+
end
|
130
|
+
ret = v if ret.kind_of?(Hash) and ret.size == 0
|
131
|
+
value_ret << ret
|
132
|
+
}
|
133
|
+
hashv[key] = value_ret
|
134
|
+
end
|
135
|
+
elsif value.kind_of?(Range)
|
136
|
+
if expected_errors.empty?
|
137
|
+
hashv[key] = rand(value)
|
138
|
+
else
|
139
|
+
hashv[key] = rand(value)
|
140
|
+
expected_errors.each do |er|
|
141
|
+
if er == :min_length
|
142
|
+
hashv[key] = rand((value.first - value.last)..value.first - 1)
|
143
|
+
elsif er == :max_length
|
144
|
+
hashv[key] = rand((value.last + 1)..(value.last * 2))
|
145
|
+
elsif er == :length
|
146
|
+
if rand.round == 1
|
147
|
+
hashv[key] = rand((value.first - value.last)..value.first - 1)
|
148
|
+
else
|
149
|
+
hashv[key] = rand((value.last + 1)..(value.last * 2))
|
150
|
+
end
|
151
|
+
elsif er == :value
|
152
|
+
hashv[key] = :"1-10:N/L/".gen
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
elsif value.kind_of?(Class) and value == DateTime
|
157
|
+
if expected_errors.empty?
|
158
|
+
hashv[key] = Time.now.stamp
|
159
|
+
else
|
160
|
+
hashv[key] = Time.now.stamp
|
161
|
+
expected_errors.each do |er|
|
162
|
+
if er == :min_length
|
163
|
+
hashv[key] = hashv[key].chop
|
164
|
+
elsif er == :max_length
|
165
|
+
hashv[key] = hashv[key] + "Z"
|
166
|
+
elsif er == :length
|
167
|
+
if rand.round == 1
|
168
|
+
hashv[key] = hashv[key].chop
|
169
|
+
else
|
170
|
+
hashv[key] = hashv[key] + "Z"
|
171
|
+
end
|
172
|
+
elsif er == :value
|
173
|
+
hashv[key][rand(hashv[key].size - 1)] = "1:L".gen
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
elsif value.kind_of?(Module) and value == Boolean
|
178
|
+
if expected_errors.empty?
|
179
|
+
hashv[key] = (rand.round == 0)
|
180
|
+
else
|
181
|
+
hashv[key] = (rand.round == 0)
|
182
|
+
expected_errors.each do |er|
|
183
|
+
if er == :value
|
184
|
+
hashv[key] = "1-10:L".gen
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
elsif value.kind_of?(Proc)
|
189
|
+
hashv[key] = value.call
|
190
|
+
elsif value.kind_of?(Regexp)
|
191
|
+
hashv[key] = value.generate(expected_errors: expected_errors)
|
192
|
+
else
|
193
|
+
hashv[key] = value
|
194
|
+
end
|
195
|
+
|
196
|
+
if same_values.include?(key)
|
197
|
+
same_values[key].each { |k|
|
198
|
+
hashv[k] = hashv[key]
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
@values = hashv
|
203
|
+
}
|
204
|
+
end
|
205
|
+
|
206
|
+
return hashv
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class NiceHash
|
2
|
+
##################################################
|
3
|
+
# Get all the keys of a hash
|
4
|
+
#
|
5
|
+
# @param hash [Hash] The hash
|
6
|
+
#
|
7
|
+
# @return [Array]
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# my_hash = { uno: {dos: {tres: 3}} }
|
11
|
+
# NiceHash.get_all_keys(my_hash)
|
12
|
+
# #>[:uno, :dos, :tres]
|
13
|
+
##################################################
|
14
|
+
def self.get_all_keys(h)
|
15
|
+
h.each_with_object([]) do |(k, v), keys|
|
16
|
+
keys << k
|
17
|
+
keys.concat(get_all_keys(v)) if v.is_a? Hash
|
18
|
+
if v.is_a?(Array)
|
19
|
+
v.each do |vv|
|
20
|
+
keys.concat(get_all_keys(vv)) if vv.is_a? Hash or vv.is_a? Array
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
class NiceHash
|
2
|
+
|
3
|
+
##################################################
|
4
|
+
# Get values from the Hash structure (array of Hashes allowed)
|
5
|
+
# In case the key supplied doesn't exist in the hash then it will be returned nil for that one
|
6
|
+
# input:
|
7
|
+
# hashv: a simple hash or a hash containing arrays. Example:
|
8
|
+
# example={"id"=>344,
|
9
|
+
# "customer"=>{
|
10
|
+
# "name"=>"Peter Smith",
|
11
|
+
# "phone"=>334334333
|
12
|
+
# },
|
13
|
+
# "tickets"=>[
|
14
|
+
# {"idt"=>345,"name"=>"myFavor1"},
|
15
|
+
# {"idt"=>3123},
|
16
|
+
# {"idt"=>3145,"name"=>"Special ticket"}
|
17
|
+
# ]
|
18
|
+
# }
|
19
|
+
# keys: one key (string) or an array of keys. key can be a nested key
|
20
|
+
# output:
|
21
|
+
# a Hash of Arrays with all values found.
|
22
|
+
# Example of output with example.get_values("id","name")
|
23
|
+
# {"id"=>344, "name"=>["Peter Smith", ["myFavor1", "Special ticket"]]}
|
24
|
+
# Example of output with example.get_values("idt")
|
25
|
+
# {"idt"=>[345,3123,3145]}
|
26
|
+
# Example of output with example.get_values(:'tickets.idt')
|
27
|
+
# {:"tickets.idt"=>[345,3123,3145]}
|
28
|
+
#
|
29
|
+
####################################################
|
30
|
+
def NiceHash.get_values(hashv, keys)
|
31
|
+
#todo: check if we should return {"id"=>344, "name"=>["Peter Smith", "myFavor1", "Special ticket"]} instead of
|
32
|
+
# {"id"=>344, "name"=>["Peter Smith", ["myFavor1", "Special ticket"]]}
|
33
|
+
if keys.kind_of?(String) or keys.kind_of?(Symbol)
|
34
|
+
keys = [keys]
|
35
|
+
end
|
36
|
+
if (keys.grep(/\./)).empty?
|
37
|
+
nested = false
|
38
|
+
else
|
39
|
+
nested = true
|
40
|
+
end
|
41
|
+
result = Hash.new()
|
42
|
+
number_of_results = Hash.new()
|
43
|
+
keys.each { |key|
|
44
|
+
number_of_results[key] = 0
|
45
|
+
}
|
46
|
+
if hashv.kind_of?(Array)
|
47
|
+
hashv.each { |tmp|
|
48
|
+
if tmp.kind_of?(Array) or tmp.kind_of?(Hash)
|
49
|
+
n_result = get_values(tmp, keys)
|
50
|
+
if n_result != :error
|
51
|
+
n_result.each { |n_key, n_value|
|
52
|
+
if result.has_key?(n_key)
|
53
|
+
if !result[n_key].kind_of?(Array) or
|
54
|
+
(result[n_key].kind_of?(Array) and number_of_results[n_key] < result[n_key].size)
|
55
|
+
if result[n_key].kind_of?(Hash) or result[n_key].kind_of?(Array)
|
56
|
+
res_tx = result[n_key].dup()
|
57
|
+
else
|
58
|
+
res_tx = result[n_key]
|
59
|
+
end
|
60
|
+
result[n_key] = Array.new()
|
61
|
+
result[n_key].push(res_tx)
|
62
|
+
result[n_key].push(n_value)
|
63
|
+
else
|
64
|
+
result[n_key].push(n_value)
|
65
|
+
end
|
66
|
+
else
|
67
|
+
result[n_key] = n_value
|
68
|
+
end
|
69
|
+
number_of_results[n_key] += 1
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
}
|
74
|
+
elsif hashv.kind_of?(Hash)
|
75
|
+
hashv.each { |key, value|
|
76
|
+
#if keys.include?(key) then
|
77
|
+
#added to be able to access the keys with symbols to strings and opposite
|
78
|
+
if keys.include?(key) or keys.include?(key.to_s) or keys.include?(key.to_sym)
|
79
|
+
#todo: check on next ruby versions since it will be not necessary to do it
|
80
|
+
#added to be able to access the keys with symbols to strings and opposite
|
81
|
+
key = key.to_s() if keys.include?(key.to_s)
|
82
|
+
key = key.to_sym() if keys.include?(key.to_sym)
|
83
|
+
|
84
|
+
if result.has_key?(key)
|
85
|
+
if !result[key].kind_of?(Array) or
|
86
|
+
(result[key].kind_of?(Array) and number_of_results[key] < result[key].size)
|
87
|
+
if result[key].kind_of?(Hash) or result[key].kind_of?(Array)
|
88
|
+
res_tx = result[key].dup()
|
89
|
+
else
|
90
|
+
res_tx = result[key]
|
91
|
+
end
|
92
|
+
result[key] = Array.new()
|
93
|
+
result[key].push(res_tx)
|
94
|
+
result[key].push(value)
|
95
|
+
else
|
96
|
+
result[key].push(value)
|
97
|
+
end
|
98
|
+
else
|
99
|
+
result[key] = value
|
100
|
+
end
|
101
|
+
number_of_results[key] += 1
|
102
|
+
end
|
103
|
+
if value.kind_of?(Array) or value.kind_of?(Hash)
|
104
|
+
if nested
|
105
|
+
keys_nested = []
|
106
|
+
keys.grep(/^#{key}\./).each do |k|
|
107
|
+
keys_nested << k.to_s.gsub(/^#{key}\./,'').to_sym
|
108
|
+
end
|
109
|
+
n_result_tmp = get_values(value, keys_nested)
|
110
|
+
n_result = {}
|
111
|
+
n_result_tmp.each do |k,v|
|
112
|
+
n_result["#{key}.#{k}".to_sym] = v
|
113
|
+
end
|
114
|
+
else
|
115
|
+
n_result = get_values(value, keys)
|
116
|
+
end
|
117
|
+
if n_result != :error
|
118
|
+
n_result.each { |n_key, n_value|
|
119
|
+
if result.has_key?(n_key)
|
120
|
+
if !result[n_key].kind_of?(Array) or
|
121
|
+
(result[n_key].kind_of?(Array) and number_of_results[n_key] < result[n_key].size)
|
122
|
+
if result[n_key].kind_of?(Hash) or result[n_key].kind_of?(Array)
|
123
|
+
res_tx = result[n_key].dup()
|
124
|
+
else
|
125
|
+
res_tx = result[n_key]
|
126
|
+
end
|
127
|
+
result[n_key] = Array.new()
|
128
|
+
result[n_key].push(res_tx)
|
129
|
+
result[n_key].push(n_value)
|
130
|
+
else
|
131
|
+
result[n_key].push(n_value)
|
132
|
+
end
|
133
|
+
else
|
134
|
+
result[n_key] = n_value
|
135
|
+
end
|
136
|
+
number_of_results[n_key] += 1
|
137
|
+
}
|
138
|
+
end
|
139
|
+
end
|
140
|
+
}
|
141
|
+
else
|
142
|
+
return :error
|
143
|
+
end
|
144
|
+
if result.kind_of?(Hash) and caller[0]["get_values"].nil? #no error or anything weird
|
145
|
+
(keys - result.keys).each { |k| #in case some keys don't exist in the hash
|
146
|
+
result[k] = nil
|
147
|
+
}
|
148
|
+
end
|
149
|
+
return result
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|