nice_hash 1.15.2 → 1.15.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b3dfa4920ee6ffc492f91f20f01fdad4e22953a681bd5071d7f7f72ecbed4eb
4
- data.tar.gz: 357269895379ab1744886a6107493f339820e4a5cf4bd81ddd9ed4f7ecb94de9
3
+ metadata.gz: 5e1518b1eb83a00333a4051d91aa0b40fb9fe58e4b0b3ad229fcc78b0f86eb56
4
+ data.tar.gz: 69c215835f068a459dfc0e01605c45c42a5447e4e818eeabfac3f90a746c6012
5
5
  SHA512:
6
- metadata.gz: acbd759da3e565e4493cd6c6b082e31248124cd93dec40d9572a695d2055ec4c34850c82c19f2e548e8c71c31a0504d6ae4cf0e4b4457d789eb90b299a1d6eee
7
- data.tar.gz: 80f5adf41b3c01f6c32aff59ff8410c507e53f937aa794523485699afc8ca796934f72b9cc3ec22ec8797265b62d7c96413b4d9d058b58f136943e47367904ef
6
+ metadata.gz: f61c5845665e7dcddf367e2850afb0d83b95bef3d39c8931be7bce5f27ffc24d6352b5c13d9a600f0d128fc25b1ff8332a2796943abf7f6fe647c4ac9739830e
7
+ data.tar.gz: 6f5ae2c245b192ee7ee331bf6d1a990551dd5e57e93997d168e83a3acfa2d471649ca83e06efdc0a3e18f4f948b1a7e594a6bdd5a2de916745bc9339e2228994
data/.yardopts CHANGED
@@ -5,6 +5,6 @@
5
5
  -
6
6
  lib/**/*.rb
7
7
  lib/nice_hash.rb
8
- lib/nice/hash/add_to_ruby.rb
8
+ lib/nice/hash/*.rb
9
9
  *.md
10
10
  LICENSE
@@ -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