nice_hash 1.7.3 → 1.8.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/.yardopts +4 -4
- data/LICENSE +21 -21
- data/README.md +654 -646
- data/lib/nice/hash/add_to_ruby.rb +240 -240
- data/lib/nice_hash.rb +720 -718
- metadata +3 -3
data/lib/nice_hash.rb
CHANGED
|
@@ -1,718 +1,720 @@
|
|
|
1
|
-
SP_ADD_TO_RUBY = true if !defined?(SP_ADD_TO_RUBY)
|
|
2
|
-
require_relative 'nice/hash/add_to_ruby' if SP_ADD_TO_RUBY
|
|
3
|
-
|
|
4
|
-
require 'string_pattern'
|
|
5
|
-
|
|
6
|
-
###########################################################################
|
|
7
|
-
# NiceHash creates hashes following certain patterns so your testing will be much easier.
|
|
8
|
-
# You can easily generates all the hashes you want following the criteria you specify.
|
|
9
|
-
# Many other features coming to Hash class like the methods 'bury' or select_key, access the keys like methods: my_hash.my_key.other_key.
|
|
10
|
-
# You will be able to generate thousands of different hashes just declaring one and test easily APIs based on JSON for example.
|
|
11
|
-
# To generate the strings following a pattern take a look at the documentation for string_pattern gem: https://github.com/MarioRuiz/string_pattern
|
|
12
|
-
# This is the Hash we will be using on the examples declared on the methods source code documentation:
|
|
13
|
-
# my_hash={
|
|
14
|
-
# name: 'Peter',
|
|
15
|
-
# address: {wrong: '#$$$$$', correct: :'10-30:L_'},
|
|
16
|
-
# city: {wrong: 'Germany', correct: :'Madrid|Barcelona|London|Akureyri'},
|
|
17
|
-
# products: [
|
|
18
|
-
# {
|
|
19
|
-
# name: :'10:Ln',
|
|
20
|
-
# price: {wrong: '-20', correct: :'1-10:N'}
|
|
21
|
-
# },
|
|
22
|
-
# {
|
|
23
|
-
# name: :'10:Ln',
|
|
24
|
-
# price: {wrong: '-20', correct: :'1-10:N'}
|
|
25
|
-
# },
|
|
26
|
-
# ]
|
|
27
|
-
# }
|
|
28
|
-
###########################################################################
|
|
29
|
-
class NiceHash
|
|
30
|
-
class << self
|
|
31
|
-
attr_reader :values
|
|
32
|
-
end
|
|
33
|
-
@values = {}
|
|
34
|
-
|
|
35
|
-
###########################################################################
|
|
36
|
-
# It will filter the hash by the key specified on select_hash_key.
|
|
37
|
-
# In case a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
|
|
38
|
-
#
|
|
39
|
-
# input:
|
|
40
|
-
# pattern_hash: (Hash) Hash we want to select specific keys
|
|
41
|
-
# select_hash_key: (key value) The key we want to select on the subhashes
|
|
42
|
-
# output: (Hash)
|
|
43
|
-
# The same hash but in case a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
|
|
44
|
-
# example:
|
|
45
|
-
# new_hash = NiceHash.select_key(my_hash, :wrong)
|
|
46
|
-
# #> {:name=>"Peter", :address=>"\#$$$$$", :city=>"Germany", :products=> [{:name=>:"10:Ln", :price=>"-20"}, {:name=>:"10:Ln", :price=>"-20"}]}
|
|
47
|
-
# Using it directly on Hash class, select_key(select_hash_key):
|
|
48
|
-
# new_hash = my_hash.select_key(:wrong)
|
|
49
|
-
###########################################################################
|
|
50
|
-
def NiceHash.select_key(pattern_hash, select_hash_key)
|
|
51
|
-
hashv=Hash.new()
|
|
52
|
-
|
|
53
|
-
if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
|
|
54
|
-
pattern_hash.each {|key, value|
|
|
55
|
-
|
|
56
|
-
if value.kind_of?(Hash)
|
|
57
|
-
if value.keys.include?(select_hash_key)
|
|
58
|
-
value=value[select_hash_key]
|
|
59
|
-
else
|
|
60
|
-
value=NiceHash.select_key(value, select_hash_key)
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
if value.kind_of?(Array)
|
|
64
|
-
array_pattern=false
|
|
65
|
-
value.each {|v|
|
|
66
|
-
if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
|
|
67
|
-
hashv[key]=value
|
|
68
|
-
array_pattern=true
|
|
69
|
-
break
|
|
70
|
-
end
|
|
71
|
-
}
|
|
72
|
-
unless array_pattern
|
|
73
|
-
value_ret=Array.new
|
|
74
|
-
value.each {|v|
|
|
75
|
-
ret=NiceHash.select_key(v, select_hash_key)
|
|
76
|
-
value_ret<<ret
|
|
77
|
-
}
|
|
78
|
-
hashv[key]=value_ret
|
|
79
|
-
end
|
|
80
|
-
else
|
|
81
|
-
hashv[key]=value
|
|
82
|
-
end
|
|
83
|
-
}
|
|
84
|
-
else
|
|
85
|
-
return pattern_hash
|
|
86
|
-
end
|
|
87
|
-
return hashv
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
###########################################################################
|
|
91
|
-
# It will return an array of the keys where we are using string patterns.
|
|
92
|
-
#
|
|
93
|
-
# input:
|
|
94
|
-
# pattern_hash: (Hash) Hash we want to get the pattern_fields
|
|
95
|
-
# select_hash_key: (key value) (optional) The key we want to select on the subhashes
|
|
96
|
-
# output: (Array)
|
|
97
|
-
# Array of the kind: [ [key], [key, subkey, subkey] ]
|
|
98
|
-
# Each value of the array can be used as parameter for the methods: dig, bury
|
|
99
|
-
# examples:
|
|
100
|
-
# NiceHash.pattern_fields(my_hash)
|
|
101
|
-
# #> [
|
|
102
|
-
# [:address, :correct],
|
|
103
|
-
# [:products, 0, :name],
|
|
104
|
-
# [:products, 0, :price, :correct],
|
|
105
|
-
# [:products, 1, :name],
|
|
106
|
-
# [:products, 1, :price, :correct]
|
|
107
|
-
# ]
|
|
108
|
-
# NiceHash.pattern_fields(my_hash, :correct)
|
|
109
|
-
# #> [
|
|
110
|
-
# [:address],
|
|
111
|
-
# [:products, 0, :name],
|
|
112
|
-
# [:products, 0, :price],
|
|
113
|
-
# [:products, 1, :name],
|
|
114
|
-
# [:products, 1, :price]
|
|
115
|
-
# ]
|
|
116
|
-
# Using it directly on Hash class, pattern_fields(*select_hash_key) (alias: patterns):
|
|
117
|
-
# my_hash.pattern_fields
|
|
118
|
-
# my_hash.pattern_fields(:correct)
|
|
119
|
-
# my_hash.patterns(:correct)
|
|
120
|
-
###########################################################################
|
|
121
|
-
def NiceHash.pattern_fields(pattern_hash, *select_hash_key)
|
|
122
|
-
pattern_fields = Array.new
|
|
123
|
-
|
|
124
|
-
if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
|
|
125
|
-
pattern_hash.each {|key, value|
|
|
126
|
-
key=[key]
|
|
127
|
-
if value.kind_of?(Hash)
|
|
128
|
-
if select_hash_key.size==1 and value.keys.include?(select_hash_key[0])
|
|
129
|
-
value=value[select_hash_key[0]]
|
|
130
|
-
else
|
|
131
|
-
res=NiceHash.pattern_fields(value, *select_hash_key)
|
|
132
|
-
if res.size>0
|
|
133
|
-
res.each {|r|
|
|
134
|
-
pattern_fields<<(r.unshift(key)).flatten
|
|
135
|
-
}
|
|
136
|
-
end
|
|
137
|
-
next
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
if value.kind_of?(String)
|
|
141
|
-
if StringPattern.optimistic and value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
|
|
142
|
-
pattern_fields << key
|
|
143
|
-
end
|
|
144
|
-
elsif value.kind_of?(Symbol)
|
|
145
|
-
if value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
|
|
146
|
-
pattern_fields << key
|
|
147
|
-
end
|
|
148
|
-
elsif value.kind_of?(Array)
|
|
149
|
-
|
|
150
|
-
array_pattern=false
|
|
151
|
-
value.each {|v|
|
|
152
|
-
if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
|
|
153
|
-
pattern_fields << key
|
|
154
|
-
array_pattern=true
|
|
155
|
-
break
|
|
156
|
-
end
|
|
157
|
-
}
|
|
158
|
-
unless array_pattern
|
|
159
|
-
i=0
|
|
160
|
-
value.each {|v|
|
|
161
|
-
res=NiceHash.pattern_fields(v, *select_hash_key)
|
|
162
|
-
if res.size>0
|
|
163
|
-
res.each {|r|
|
|
164
|
-
pattern_fields<<(r.unshift(i).unshift(key)).flatten
|
|
165
|
-
}
|
|
166
|
-
end
|
|
167
|
-
i+=1
|
|
168
|
-
}
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
}
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
return pattern_fields
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
###########################################################################
|
|
178
|
-
# It will return an array of the keys where we are using select values of the kind: "value1|value2|value3".
|
|
179
|
-
#
|
|
180
|
-
# input:
|
|
181
|
-
# pattern_hash: (Hash) Hash we want to get the select_fields
|
|
182
|
-
# select_hash_key: (key value) (optional) The key we want to select on the subhashes
|
|
183
|
-
# output: (Array)
|
|
184
|
-
# Array of the kind: [ [key], [key, subkey, subkey] ]
|
|
185
|
-
# Each value of the array can be used as parameter for the methods: dig, bury
|
|
186
|
-
# examples:
|
|
187
|
-
# NiceHash.select_fields(my_hash)
|
|
188
|
-
# #> [[:city, :correct]]
|
|
189
|
-
# NiceHash.select_fields(my_hash, :correct)
|
|
190
|
-
# #> [[:city]]
|
|
191
|
-
# Using it directly on Hash class, select_fields(*select_hash_key):
|
|
192
|
-
# my_hash.select_fields
|
|
193
|
-
# my_hash.select_fields(:correct)
|
|
194
|
-
###########################################################################
|
|
195
|
-
def NiceHash.select_fields(pattern_hash, *select_hash_key)
|
|
196
|
-
select_fields = Array.new
|
|
197
|
-
|
|
198
|
-
if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
|
|
199
|
-
pattern_hash.each {|key, value|
|
|
200
|
-
key=[key]
|
|
201
|
-
if value.kind_of?(Hash)
|
|
202
|
-
if select_hash_key.size==1 and value.keys.include?(select_hash_key[0])
|
|
203
|
-
value=value[select_hash_key[0]]
|
|
204
|
-
else
|
|
205
|
-
res=NiceHash.select_fields(value, *select_hash_key)
|
|
206
|
-
if res.size>0
|
|
207
|
-
res.each {|r|
|
|
208
|
-
select_fields<<(r.unshift(key)).flatten
|
|
209
|
-
}
|
|
210
|
-
end
|
|
211
|
-
next
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
if value.kind_of?(String)
|
|
215
|
-
if StringPattern.optimistic and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
|
|
216
|
-
select_fields << key
|
|
217
|
-
end
|
|
218
|
-
elsif value.kind_of?(Symbol)
|
|
219
|
-
if value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
|
|
220
|
-
select_fields << key
|
|
221
|
-
end
|
|
222
|
-
elsif value.kind_of?(Array)
|
|
223
|
-
|
|
224
|
-
array_pattern=false
|
|
225
|
-
value.each {|v|
|
|
226
|
-
if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
|
|
227
|
-
array_pattern=true
|
|
228
|
-
break
|
|
229
|
-
end
|
|
230
|
-
}
|
|
231
|
-
unless array_pattern
|
|
232
|
-
i=0
|
|
233
|
-
value.each {|v|
|
|
234
|
-
res=NiceHash.select_fields(v, *select_hash_key)
|
|
235
|
-
if res.size>0
|
|
236
|
-
res.each {|r|
|
|
237
|
-
select_fields<<(r.unshift(i).unshift(key)).flatten
|
|
238
|
-
}
|
|
239
|
-
end
|
|
240
|
-
i+=1
|
|
241
|
-
}
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
}
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
return select_fields
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
###########################################################################
|
|
252
|
-
# It will generate a new hash with the values generated from the string patterns and select fields specified.
|
|
253
|
-
# 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
|
|
254
|
-
# If expected_errors specified the values will be generated with the specified errors.
|
|
255
|
-
# input:
|
|
256
|
-
# pattern_hash: (Hash) Hash we want to use to generate the values
|
|
257
|
-
# select_hash_key: (key value) (optional) The key we want to select on the subhashes
|
|
258
|
-
# expected_errors: (Array) (optional) (alias: errors) To generate the string patterns with the specified errors.
|
|
259
|
-
# The possible values you can specify is one or more of these ones:
|
|
260
|
-
# :length: wrong length, minimum or maximum
|
|
261
|
-
# :min_length: wrong minimum length
|
|
262
|
-
# :max_length: wrong maximum length
|
|
263
|
-
# :value: wrong resultant value
|
|
264
|
-
# :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.
|
|
265
|
-
# :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.
|
|
266
|
-
# :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.
|
|
267
|
-
# output: (Hash)
|
|
268
|
-
# The Hash with the select_hash_key selected and the values generated from the string patterns and select fields specified.
|
|
269
|
-
# examples:
|
|
270
|
-
# new_hash = NiceHash.generate(my_hash)
|
|
271
|
-
# #> {:name=>"Peter",
|
|
272
|
-
# :address=>{:wrong=>"\#$$$$$", :correct=>"KZPCzxsWGMLqonesu wbqH"},
|
|
273
|
-
# :city=>{:wrong=>"Germany", :correct=>"Barcelona"},
|
|
274
|
-
# :products=> [
|
|
275
|
-
# {:name=>"gIqkWygmVm", :price=>{:wrong=>"-20", :correct=>"34338330"}},
|
|
276
|
-
# {:name=>"CK68VLIcYf", :price=>{:wrong=>"-20", :correct=>"616066520"}}
|
|
277
|
-
# ]
|
|
278
|
-
# }
|
|
279
|
-
# new_hash = NiceHash.generate(my_hash, :correct)
|
|
280
|
-
# #> {:name=>"Peter",
|
|
281
|
-
# :address=>"juQeAVZjIuWBPsE",
|
|
282
|
-
# :city=>"Madrid",
|
|
283
|
-
# :products=> [
|
|
284
|
-
# {:name=>"G44Ilr0puV", :price=>"477813"},
|
|
285
|
-
# {:name=>"v6ojs79LOp", :price=>"74820"}
|
|
286
|
-
# ]
|
|
287
|
-
# }
|
|
288
|
-
# new_hash = NiceHash.generate(my_hash, :correct, expected_errors: [:min_length])
|
|
289
|
-
# #> {:name=>"Peter",
|
|
290
|
-
# :address=>"ZytjefJ",
|
|
291
|
-
# :city=>"Madri",
|
|
292
|
-
# :products=>[
|
|
293
|
-
# {:name=>"cIBrzeO", :price=>""},
|
|
294
|
-
# {:name=>"5", :price=>""}
|
|
295
|
-
# ]
|
|
296
|
-
# }
|
|
297
|
-
# Using it directly on Hash class, generate(select_hash_key=nil, expected_errors: []) (alias: gen):
|
|
298
|
-
# new_hash = my_hash.generate
|
|
299
|
-
# new_hash = my_hash.gen(:correct)
|
|
300
|
-
# new_hash = my_hash.generate(:correct, errors: [:min_length])
|
|
301
|
-
###########################################################################
|
|
302
|
-
def NiceHash.generate(pattern_hash, select_hash_key=nil, expected_errors: [], **synonyms)
|
|
303
|
-
hashv=Hash.new()
|
|
304
|
-
same_values=Hash.new()
|
|
305
|
-
expected_errors=synonyms[:errors] if synonyms.keys.include?(:errors)
|
|
306
|
-
if expected_errors.kind_of?(Symbol)
|
|
307
|
-
expected_errors=[expected_errors]
|
|
308
|
-
end
|
|
309
|
-
|
|
310
|
-
if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
|
|
311
|
-
pattern_hash.each {|key, value|
|
|
312
|
-
|
|
313
|
-
if key.kind_of?(Array)
|
|
314
|
-
same_values[key[0]]=key.dup
|
|
315
|
-
same_values[key[0]].shift
|
|
316
|
-
key=key[0]
|
|
317
|
-
end
|
|
318
|
-
if value.kind_of?(Hash)
|
|
319
|
-
if value.keys.include?(select_hash_key)
|
|
320
|
-
value=value[select_hash_key]
|
|
321
|
-
else
|
|
322
|
-
value=NiceHash.generate(value, select_hash_key, expected_errors: expected_errors)
|
|
323
|
-
end
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
if value.kind_of?(String) or value.kind_of?(Symbol)
|
|
327
|
-
if ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
|
|
328
|
-
hashv[key]=StringPattern.generate(value, expected_errors: expected_errors)
|
|
329
|
-
elsif ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
|
|
330
|
-
if expected_errors.include?(:min_length) or (expected_errors.include?(:length) and rand.round==0)
|
|
331
|
-
min=value.to_s.split("|").min {|a, b| a.size <=> b.size}
|
|
332
|
-
hashv[key]=min[0..-2] unless min==""
|
|
333
|
-
end
|
|
334
|
-
if !hashv.keys.include?(key) and (expected_errors.include?(:max_length) or expected_errors.include?(:length))
|
|
335
|
-
max=value.to_s.split("|").max {|a, b| a.size <=> b.size}
|
|
336
|
-
hashv[key]=max+max[-1]
|
|
337
|
-
end
|
|
338
|
-
if expected_errors.include?(:value) or
|
|
339
|
-
expected_errors.include?(:string_set_not_allowed) or
|
|
340
|
-
expected_errors.include?(:required_data)
|
|
341
|
-
if hashv.keys.include?(key)
|
|
342
|
-
v=hashv[key]
|
|
343
|
-
else
|
|
344
|
-
v=value.to_s.split("|").sample
|
|
345
|
-
end
|
|
346
|
-
unless expected_errors.include?(:string_set_not_allowed)
|
|
347
|
-
v=StringPattern.generate(:"#{v.size}:[#{value.to_s.split("|").join.split(//).uniq.join}]")
|
|
348
|
-
hashv[key]=v unless value.to_s.split("|").include?(v)
|
|
349
|
-
end
|
|
350
|
-
unless hashv.keys.include?(key)
|
|
351
|
-
one_wrong_letter=StringPattern.generate(:"1:LN$[%#{value.to_s.split("|").join.split(//).uniq.join}%]")
|
|
352
|
-
v[rand(v.size)]=one_wrong_letter
|
|
353
|
-
hashv[key]=v unless value.to_s.split("|").include?(v)
|
|
354
|
-
end
|
|
355
|
-
end
|
|
356
|
-
unless hashv.keys.include?(key)
|
|
357
|
-
hashv[key]=value.to_s.split("|").sample
|
|
358
|
-
end
|
|
359
|
-
else
|
|
360
|
-
hashv[key]=value
|
|
361
|
-
end
|
|
362
|
-
elsif value.kind_of?(Array)
|
|
363
|
-
array_pattern=false
|
|
364
|
-
value.each {|v|
|
|
365
|
-
if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
|
|
366
|
-
hashv[key]=StringPattern.generate(value, expected_errors: expected_errors)
|
|
367
|
-
array_pattern=true
|
|
368
|
-
break
|
|
369
|
-
end
|
|
370
|
-
}
|
|
371
|
-
unless array_pattern
|
|
372
|
-
value_ret=Array.new
|
|
373
|
-
value.each {|v|
|
|
374
|
-
ret=NiceHash.generate(v, select_hash_key, expected_errors: expected_errors)
|
|
375
|
-
ret=v if ret.kind_of?(Hash) and ret.size==0
|
|
376
|
-
value_ret<<ret
|
|
377
|
-
}
|
|
378
|
-
hashv[key]=value_ret
|
|
379
|
-
end
|
|
380
|
-
elsif value.kind_of?(Proc)
|
|
381
|
-
hashv[key]=value.call
|
|
382
|
-
|
|
383
|
-
hashv[key]=value
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
#
|
|
405
|
-
#
|
|
406
|
-
#
|
|
407
|
-
#
|
|
408
|
-
#
|
|
409
|
-
#
|
|
410
|
-
#
|
|
411
|
-
#
|
|
412
|
-
#
|
|
413
|
-
#
|
|
414
|
-
#
|
|
415
|
-
# :
|
|
416
|
-
# :
|
|
417
|
-
# :
|
|
418
|
-
# :
|
|
419
|
-
# :
|
|
420
|
-
#
|
|
421
|
-
#
|
|
422
|
-
#
|
|
423
|
-
#
|
|
424
|
-
#
|
|
425
|
-
# :
|
|
426
|
-
#
|
|
427
|
-
#
|
|
428
|
-
#
|
|
429
|
-
#
|
|
430
|
-
#
|
|
431
|
-
#
|
|
432
|
-
#
|
|
433
|
-
#
|
|
434
|
-
#
|
|
435
|
-
#
|
|
436
|
-
#
|
|
437
|
-
#
|
|
438
|
-
#
|
|
439
|
-
#
|
|
440
|
-
#
|
|
441
|
-
#
|
|
442
|
-
#
|
|
443
|
-
#
|
|
444
|
-
#
|
|
445
|
-
#
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
key
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
results[key]=
|
|
486
|
-
elsif !only_patterns
|
|
487
|
-
results[key]=false unless value.to_s
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
#
|
|
547
|
-
#
|
|
548
|
-
#
|
|
549
|
-
#
|
|
550
|
-
#
|
|
551
|
-
#
|
|
552
|
-
#
|
|
553
|
-
#
|
|
554
|
-
#
|
|
555
|
-
#
|
|
556
|
-
#
|
|
557
|
-
#
|
|
558
|
-
#
|
|
559
|
-
#
|
|
560
|
-
#
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
pattern_hash=patterns_hash
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
last_to_set=
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
#
|
|
595
|
-
#
|
|
596
|
-
#
|
|
597
|
-
#
|
|
598
|
-
#
|
|
599
|
-
#
|
|
600
|
-
#
|
|
601
|
-
#
|
|
602
|
-
#
|
|
603
|
-
#
|
|
604
|
-
# {"idt"=>
|
|
605
|
-
#
|
|
606
|
-
#
|
|
607
|
-
#
|
|
608
|
-
#
|
|
609
|
-
#
|
|
610
|
-
#
|
|
611
|
-
#
|
|
612
|
-
# Example of output with example.get_values("
|
|
613
|
-
# {"
|
|
614
|
-
#
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
res_tx=result[n_key]
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
result[n_key].
|
|
642
|
-
|
|
643
|
-
result[n_key].push(n_value)
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
if keys.include?(key)
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
if
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
res_tx=result[key]
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
result[key].
|
|
673
|
-
|
|
674
|
-
result[key].push(value)
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
res_tx=result[n_key]
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
result[n_key].
|
|
696
|
-
|
|
697
|
-
result[n_key].push(n_value)
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
end
|
|
1
|
+
SP_ADD_TO_RUBY = true if !defined?(SP_ADD_TO_RUBY)
|
|
2
|
+
require_relative 'nice/hash/add_to_ruby' if SP_ADD_TO_RUBY
|
|
3
|
+
|
|
4
|
+
require 'string_pattern'
|
|
5
|
+
|
|
6
|
+
###########################################################################
|
|
7
|
+
# NiceHash creates hashes following certain patterns so your testing will be much easier.
|
|
8
|
+
# You can easily generates all the hashes you want following the criteria you specify.
|
|
9
|
+
# Many other features coming to Hash class like the methods 'bury' or select_key, access the keys like methods: my_hash.my_key.other_key.
|
|
10
|
+
# You will be able to generate thousands of different hashes just declaring one and test easily APIs based on JSON for example.
|
|
11
|
+
# To generate the strings following a pattern take a look at the documentation for string_pattern gem: https://github.com/MarioRuiz/string_pattern
|
|
12
|
+
# This is the Hash we will be using on the examples declared on the methods source code documentation:
|
|
13
|
+
# my_hash={
|
|
14
|
+
# name: 'Peter',
|
|
15
|
+
# address: {wrong: '#$$$$$', correct: :'10-30:L_'},
|
|
16
|
+
# city: {wrong: 'Germany', correct: :'Madrid|Barcelona|London|Akureyri'},
|
|
17
|
+
# products: [
|
|
18
|
+
# {
|
|
19
|
+
# name: :'10:Ln',
|
|
20
|
+
# price: {wrong: '-20', correct: :'1-10:N'}
|
|
21
|
+
# },
|
|
22
|
+
# {
|
|
23
|
+
# name: :'10:Ln',
|
|
24
|
+
# price: {wrong: '-20', correct: :'1-10:N'}
|
|
25
|
+
# },
|
|
26
|
+
# ]
|
|
27
|
+
# }
|
|
28
|
+
###########################################################################
|
|
29
|
+
class NiceHash
|
|
30
|
+
class << self
|
|
31
|
+
attr_reader :values
|
|
32
|
+
end
|
|
33
|
+
@values = {}
|
|
34
|
+
|
|
35
|
+
###########################################################################
|
|
36
|
+
# It will filter the hash by the key specified on select_hash_key.
|
|
37
|
+
# In case a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
|
|
38
|
+
#
|
|
39
|
+
# input:
|
|
40
|
+
# pattern_hash: (Hash) Hash we want to select specific keys
|
|
41
|
+
# select_hash_key: (key value) The key we want to select on the subhashes
|
|
42
|
+
# output: (Hash)
|
|
43
|
+
# The same hash but in case a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
|
|
44
|
+
# example:
|
|
45
|
+
# new_hash = NiceHash.select_key(my_hash, :wrong)
|
|
46
|
+
# #> {:name=>"Peter", :address=>"\#$$$$$", :city=>"Germany", :products=> [{:name=>:"10:Ln", :price=>"-20"}, {:name=>:"10:Ln", :price=>"-20"}]}
|
|
47
|
+
# Using it directly on Hash class, select_key(select_hash_key):
|
|
48
|
+
# new_hash = my_hash.select_key(:wrong)
|
|
49
|
+
###########################################################################
|
|
50
|
+
def NiceHash.select_key(pattern_hash, select_hash_key)
|
|
51
|
+
hashv=Hash.new()
|
|
52
|
+
|
|
53
|
+
if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
|
|
54
|
+
pattern_hash.each {|key, value|
|
|
55
|
+
|
|
56
|
+
if value.kind_of?(Hash)
|
|
57
|
+
if value.keys.include?(select_hash_key)
|
|
58
|
+
value=value[select_hash_key]
|
|
59
|
+
else
|
|
60
|
+
value=NiceHash.select_key(value, select_hash_key)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
if value.kind_of?(Array)
|
|
64
|
+
array_pattern=false
|
|
65
|
+
value.each {|v|
|
|
66
|
+
if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
|
|
67
|
+
hashv[key]=value
|
|
68
|
+
array_pattern=true
|
|
69
|
+
break
|
|
70
|
+
end
|
|
71
|
+
}
|
|
72
|
+
unless array_pattern
|
|
73
|
+
value_ret=Array.new
|
|
74
|
+
value.each {|v|
|
|
75
|
+
ret=NiceHash.select_key(v, select_hash_key)
|
|
76
|
+
value_ret<<ret
|
|
77
|
+
}
|
|
78
|
+
hashv[key]=value_ret
|
|
79
|
+
end
|
|
80
|
+
else
|
|
81
|
+
hashv[key]=value
|
|
82
|
+
end
|
|
83
|
+
}
|
|
84
|
+
else
|
|
85
|
+
return pattern_hash
|
|
86
|
+
end
|
|
87
|
+
return hashv
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
###########################################################################
|
|
91
|
+
# It will return an array of the keys where we are using string patterns.
|
|
92
|
+
#
|
|
93
|
+
# input:
|
|
94
|
+
# pattern_hash: (Hash) Hash we want to get the pattern_fields
|
|
95
|
+
# select_hash_key: (key value) (optional) The key we want to select on the subhashes
|
|
96
|
+
# output: (Array)
|
|
97
|
+
# Array of the kind: [ [key], [key, subkey, subkey] ]
|
|
98
|
+
# Each value of the array can be used as parameter for the methods: dig, bury
|
|
99
|
+
# examples:
|
|
100
|
+
# NiceHash.pattern_fields(my_hash)
|
|
101
|
+
# #> [
|
|
102
|
+
# [:address, :correct],
|
|
103
|
+
# [:products, 0, :name],
|
|
104
|
+
# [:products, 0, :price, :correct],
|
|
105
|
+
# [:products, 1, :name],
|
|
106
|
+
# [:products, 1, :price, :correct]
|
|
107
|
+
# ]
|
|
108
|
+
# NiceHash.pattern_fields(my_hash, :correct)
|
|
109
|
+
# #> [
|
|
110
|
+
# [:address],
|
|
111
|
+
# [:products, 0, :name],
|
|
112
|
+
# [:products, 0, :price],
|
|
113
|
+
# [:products, 1, :name],
|
|
114
|
+
# [:products, 1, :price]
|
|
115
|
+
# ]
|
|
116
|
+
# Using it directly on Hash class, pattern_fields(*select_hash_key) (alias: patterns):
|
|
117
|
+
# my_hash.pattern_fields
|
|
118
|
+
# my_hash.pattern_fields(:correct)
|
|
119
|
+
# my_hash.patterns(:correct)
|
|
120
|
+
###########################################################################
|
|
121
|
+
def NiceHash.pattern_fields(pattern_hash, *select_hash_key)
|
|
122
|
+
pattern_fields = Array.new
|
|
123
|
+
|
|
124
|
+
if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
|
|
125
|
+
pattern_hash.each {|key, value|
|
|
126
|
+
key=[key]
|
|
127
|
+
if value.kind_of?(Hash)
|
|
128
|
+
if select_hash_key.size==1 and value.keys.include?(select_hash_key[0])
|
|
129
|
+
value=value[select_hash_key[0]]
|
|
130
|
+
else
|
|
131
|
+
res=NiceHash.pattern_fields(value, *select_hash_key)
|
|
132
|
+
if res.size>0
|
|
133
|
+
res.each {|r|
|
|
134
|
+
pattern_fields<<(r.unshift(key)).flatten
|
|
135
|
+
}
|
|
136
|
+
end
|
|
137
|
+
next
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
if value.kind_of?(String)
|
|
141
|
+
if StringPattern.optimistic and value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
|
|
142
|
+
pattern_fields << key
|
|
143
|
+
end
|
|
144
|
+
elsif value.kind_of?(Symbol)
|
|
145
|
+
if value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
|
|
146
|
+
pattern_fields << key
|
|
147
|
+
end
|
|
148
|
+
elsif value.kind_of?(Array)
|
|
149
|
+
|
|
150
|
+
array_pattern=false
|
|
151
|
+
value.each {|v|
|
|
152
|
+
if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
|
|
153
|
+
pattern_fields << key
|
|
154
|
+
array_pattern=true
|
|
155
|
+
break
|
|
156
|
+
end
|
|
157
|
+
}
|
|
158
|
+
unless array_pattern
|
|
159
|
+
i=0
|
|
160
|
+
value.each {|v|
|
|
161
|
+
res=NiceHash.pattern_fields(v, *select_hash_key)
|
|
162
|
+
if res.size>0
|
|
163
|
+
res.each {|r|
|
|
164
|
+
pattern_fields<<(r.unshift(i).unshift(key)).flatten
|
|
165
|
+
}
|
|
166
|
+
end
|
|
167
|
+
i+=1
|
|
168
|
+
}
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
}
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
return pattern_fields
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
###########################################################################
|
|
178
|
+
# It will return an array of the keys where we are using select values of the kind: "value1|value2|value3".
|
|
179
|
+
#
|
|
180
|
+
# input:
|
|
181
|
+
# pattern_hash: (Hash) Hash we want to get the select_fields
|
|
182
|
+
# select_hash_key: (key value) (optional) The key we want to select on the subhashes
|
|
183
|
+
# output: (Array)
|
|
184
|
+
# Array of the kind: [ [key], [key, subkey, subkey] ]
|
|
185
|
+
# Each value of the array can be used as parameter for the methods: dig, bury
|
|
186
|
+
# examples:
|
|
187
|
+
# NiceHash.select_fields(my_hash)
|
|
188
|
+
# #> [[:city, :correct]]
|
|
189
|
+
# NiceHash.select_fields(my_hash, :correct)
|
|
190
|
+
# #> [[:city]]
|
|
191
|
+
# Using it directly on Hash class, select_fields(*select_hash_key):
|
|
192
|
+
# my_hash.select_fields
|
|
193
|
+
# my_hash.select_fields(:correct)
|
|
194
|
+
###########################################################################
|
|
195
|
+
def NiceHash.select_fields(pattern_hash, *select_hash_key)
|
|
196
|
+
select_fields = Array.new
|
|
197
|
+
|
|
198
|
+
if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
|
|
199
|
+
pattern_hash.each {|key, value|
|
|
200
|
+
key=[key]
|
|
201
|
+
if value.kind_of?(Hash)
|
|
202
|
+
if select_hash_key.size==1 and value.keys.include?(select_hash_key[0])
|
|
203
|
+
value=value[select_hash_key[0]]
|
|
204
|
+
else
|
|
205
|
+
res=NiceHash.select_fields(value, *select_hash_key)
|
|
206
|
+
if res.size>0
|
|
207
|
+
res.each {|r|
|
|
208
|
+
select_fields<<(r.unshift(key)).flatten
|
|
209
|
+
}
|
|
210
|
+
end
|
|
211
|
+
next
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
if value.kind_of?(String)
|
|
215
|
+
if StringPattern.optimistic and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
|
|
216
|
+
select_fields << key
|
|
217
|
+
end
|
|
218
|
+
elsif value.kind_of?(Symbol)
|
|
219
|
+
if value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
|
|
220
|
+
select_fields << key
|
|
221
|
+
end
|
|
222
|
+
elsif value.kind_of?(Array)
|
|
223
|
+
|
|
224
|
+
array_pattern=false
|
|
225
|
+
value.each {|v|
|
|
226
|
+
if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
|
|
227
|
+
array_pattern=true
|
|
228
|
+
break
|
|
229
|
+
end
|
|
230
|
+
}
|
|
231
|
+
unless array_pattern
|
|
232
|
+
i=0
|
|
233
|
+
value.each {|v|
|
|
234
|
+
res=NiceHash.select_fields(v, *select_hash_key)
|
|
235
|
+
if res.size>0
|
|
236
|
+
res.each {|r|
|
|
237
|
+
select_fields<<(r.unshift(i).unshift(key)).flatten
|
|
238
|
+
}
|
|
239
|
+
end
|
|
240
|
+
i+=1
|
|
241
|
+
}
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
}
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
return select_fields
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
###########################################################################
|
|
252
|
+
# It will generate a new hash with the values generated from the string patterns and select fields specified.
|
|
253
|
+
# 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
|
|
254
|
+
# If expected_errors specified the values will be generated with the specified errors.
|
|
255
|
+
# input:
|
|
256
|
+
# pattern_hash: (Hash) Hash we want to use to generate the values
|
|
257
|
+
# select_hash_key: (key value) (optional) The key we want to select on the subhashes
|
|
258
|
+
# expected_errors: (Array) (optional) (alias: errors) To generate the string patterns with the specified errors.
|
|
259
|
+
# The possible values you can specify is one or more of these ones:
|
|
260
|
+
# :length: wrong length, minimum or maximum
|
|
261
|
+
# :min_length: wrong minimum length
|
|
262
|
+
# :max_length: wrong maximum length
|
|
263
|
+
# :value: wrong resultant value
|
|
264
|
+
# :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.
|
|
265
|
+
# :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.
|
|
266
|
+
# :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.
|
|
267
|
+
# output: (Hash)
|
|
268
|
+
# The Hash with the select_hash_key selected and the values generated from the string patterns and select fields specified.
|
|
269
|
+
# examples:
|
|
270
|
+
# new_hash = NiceHash.generate(my_hash)
|
|
271
|
+
# #> {:name=>"Peter",
|
|
272
|
+
# :address=>{:wrong=>"\#$$$$$", :correct=>"KZPCzxsWGMLqonesu wbqH"},
|
|
273
|
+
# :city=>{:wrong=>"Germany", :correct=>"Barcelona"},
|
|
274
|
+
# :products=> [
|
|
275
|
+
# {:name=>"gIqkWygmVm", :price=>{:wrong=>"-20", :correct=>"34338330"}},
|
|
276
|
+
# {:name=>"CK68VLIcYf", :price=>{:wrong=>"-20", :correct=>"616066520"}}
|
|
277
|
+
# ]
|
|
278
|
+
# }
|
|
279
|
+
# new_hash = NiceHash.generate(my_hash, :correct)
|
|
280
|
+
# #> {:name=>"Peter",
|
|
281
|
+
# :address=>"juQeAVZjIuWBPsE",
|
|
282
|
+
# :city=>"Madrid",
|
|
283
|
+
# :products=> [
|
|
284
|
+
# {:name=>"G44Ilr0puV", :price=>"477813"},
|
|
285
|
+
# {:name=>"v6ojs79LOp", :price=>"74820"}
|
|
286
|
+
# ]
|
|
287
|
+
# }
|
|
288
|
+
# new_hash = NiceHash.generate(my_hash, :correct, expected_errors: [:min_length])
|
|
289
|
+
# #> {:name=>"Peter",
|
|
290
|
+
# :address=>"ZytjefJ",
|
|
291
|
+
# :city=>"Madri",
|
|
292
|
+
# :products=>[
|
|
293
|
+
# {:name=>"cIBrzeO", :price=>""},
|
|
294
|
+
# {:name=>"5", :price=>""}
|
|
295
|
+
# ]
|
|
296
|
+
# }
|
|
297
|
+
# Using it directly on Hash class, generate(select_hash_key=nil, expected_errors: []) (alias: gen):
|
|
298
|
+
# new_hash = my_hash.generate
|
|
299
|
+
# new_hash = my_hash.gen(:correct)
|
|
300
|
+
# new_hash = my_hash.generate(:correct, errors: [:min_length])
|
|
301
|
+
###########################################################################
|
|
302
|
+
def NiceHash.generate(pattern_hash, select_hash_key=nil, expected_errors: [], **synonyms)
|
|
303
|
+
hashv=Hash.new()
|
|
304
|
+
same_values=Hash.new()
|
|
305
|
+
expected_errors=synonyms[:errors] if synonyms.keys.include?(:errors)
|
|
306
|
+
if expected_errors.kind_of?(Symbol)
|
|
307
|
+
expected_errors=[expected_errors]
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
|
|
311
|
+
pattern_hash.each {|key, value|
|
|
312
|
+
|
|
313
|
+
if key.kind_of?(Array)
|
|
314
|
+
same_values[key[0]]=key.dup
|
|
315
|
+
same_values[key[0]].shift
|
|
316
|
+
key=key[0]
|
|
317
|
+
end
|
|
318
|
+
if value.kind_of?(Hash)
|
|
319
|
+
if value.keys.include?(select_hash_key)
|
|
320
|
+
value=value[select_hash_key]
|
|
321
|
+
else
|
|
322
|
+
value=NiceHash.generate(value, select_hash_key, expected_errors: expected_errors)
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
if value.kind_of?(String) or value.kind_of?(Symbol)
|
|
327
|
+
if ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
|
|
328
|
+
hashv[key]=StringPattern.generate(value, expected_errors: expected_errors)
|
|
329
|
+
elsif ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
|
|
330
|
+
if expected_errors.include?(:min_length) or (expected_errors.include?(:length) and rand.round==0)
|
|
331
|
+
min=value.to_s.split("|").min {|a, b| a.size <=> b.size}
|
|
332
|
+
hashv[key]=min[0..-2] unless min==""
|
|
333
|
+
end
|
|
334
|
+
if !hashv.keys.include?(key) and (expected_errors.include?(:max_length) or expected_errors.include?(:length))
|
|
335
|
+
max=value.to_s.split("|").max {|a, b| a.size <=> b.size}
|
|
336
|
+
hashv[key]=max+max[-1]
|
|
337
|
+
end
|
|
338
|
+
if expected_errors.include?(:value) or
|
|
339
|
+
expected_errors.include?(:string_set_not_allowed) or
|
|
340
|
+
expected_errors.include?(:required_data)
|
|
341
|
+
if hashv.keys.include?(key)
|
|
342
|
+
v=hashv[key]
|
|
343
|
+
else
|
|
344
|
+
v=value.to_s.split("|").sample
|
|
345
|
+
end
|
|
346
|
+
unless expected_errors.include?(:string_set_not_allowed)
|
|
347
|
+
v=StringPattern.generate(:"#{v.size}:[#{value.to_s.split("|").join.split(//).uniq.join}]")
|
|
348
|
+
hashv[key]=v unless value.to_s.split("|").include?(v)
|
|
349
|
+
end
|
|
350
|
+
unless hashv.keys.include?(key)
|
|
351
|
+
one_wrong_letter=StringPattern.generate(:"1:LN$[%#{value.to_s.split("|").join.split(//).uniq.join}%]")
|
|
352
|
+
v[rand(v.size)]=one_wrong_letter
|
|
353
|
+
hashv[key]=v unless value.to_s.split("|").include?(v)
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
unless hashv.keys.include?(key)
|
|
357
|
+
hashv[key]=value.to_s.split("|").sample
|
|
358
|
+
end
|
|
359
|
+
else
|
|
360
|
+
hashv[key]=value
|
|
361
|
+
end
|
|
362
|
+
elsif value.kind_of?(Array)
|
|
363
|
+
array_pattern=false
|
|
364
|
+
value.each {|v|
|
|
365
|
+
if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
|
|
366
|
+
hashv[key]=StringPattern.generate(value, expected_errors: expected_errors)
|
|
367
|
+
array_pattern=true
|
|
368
|
+
break
|
|
369
|
+
end
|
|
370
|
+
}
|
|
371
|
+
unless array_pattern
|
|
372
|
+
value_ret=Array.new
|
|
373
|
+
value.each {|v|
|
|
374
|
+
ret=NiceHash.generate(v, select_hash_key, expected_errors: expected_errors)
|
|
375
|
+
ret=v if ret.kind_of?(Hash) and ret.size==0
|
|
376
|
+
value_ret<<ret
|
|
377
|
+
}
|
|
378
|
+
hashv[key]=value_ret
|
|
379
|
+
end
|
|
380
|
+
elsif value.kind_of?(Proc)
|
|
381
|
+
hashv[key]=value.call
|
|
382
|
+
elsif value.kind_of?(Regexp)
|
|
383
|
+
hashv[key]=value.generate
|
|
384
|
+
else
|
|
385
|
+
hashv[key]=value
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
if same_values.include?(key)
|
|
389
|
+
same_values[key].each {|k|
|
|
390
|
+
hashv[k]=hashv[key]
|
|
391
|
+
}
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
@values = hashv
|
|
395
|
+
|
|
396
|
+
}
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
return hashv
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
###########################################################################
|
|
404
|
+
# Validates a given values_hash_to_validate with string patterns and select fields from pattern_hash
|
|
405
|
+
# input:
|
|
406
|
+
# patterns_hash:
|
|
407
|
+
# (Hash) Hash where we have defined the patterns to follow.
|
|
408
|
+
# (Array) In case of array supplied, the pair: [pattern_hash, select_hash_key]. select_hash_key will filter the hash by that key
|
|
409
|
+
# values_hash_to_validate: (Hash) Hash of values to validate
|
|
410
|
+
# only_patterns: (TrueFalse) (by default true) If true it will validate only the patterns and not the other fields
|
|
411
|
+
# output: (Hash)
|
|
412
|
+
# A hash with the validation results. It will return only the validation errors so in case no validation errors found, empty hash.
|
|
413
|
+
# The keys of the hash will be the keys of the values hash with the validation error.
|
|
414
|
+
# The value in case of a pattern, will be an array with one or more of these possibilities:
|
|
415
|
+
# :length: wrong length, minimum or maximum
|
|
416
|
+
# :min_length: wrong minimum length
|
|
417
|
+
# :max_length: wrong maximum length
|
|
418
|
+
# :value: wrong resultant value
|
|
419
|
+
# :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.
|
|
420
|
+
# :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.
|
|
421
|
+
# :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.
|
|
422
|
+
# The value in any other case it will be false if the value is not corresponding to the expected.
|
|
423
|
+
# examples:
|
|
424
|
+
# values_to_validate = {:name=>"Peter",
|
|
425
|
+
# :address=>"fnMuKW",
|
|
426
|
+
# :city=>"Dublin",
|
|
427
|
+
# :products=>[{:name=>"V4", :price=>"344"}, {:name=>"E", :price=>"a"}]
|
|
428
|
+
# }
|
|
429
|
+
# results = NiceHash.validate([my_hash, :correct], values_to_validate)
|
|
430
|
+
# #> {:address=>[:min_length, :length],
|
|
431
|
+
# :products=> [{:name=>[:min_length, :length]},
|
|
432
|
+
# {:name=>[:min_length, :length], :price=>[:value, :string_set_not_allowed]}
|
|
433
|
+
# ]
|
|
434
|
+
# }
|
|
435
|
+
# results = NiceHash.validate([my_hash, :correct], values_to_validate, only_patterns: false)
|
|
436
|
+
# #> {:address=>[:min_length, :length],
|
|
437
|
+
# :city=>false,
|
|
438
|
+
# :products=> [{:name=>[:min_length, :length]},
|
|
439
|
+
# {:name=>[:min_length, :length], :price=>[:value, :string_set_not_allowed]}
|
|
440
|
+
# ]
|
|
441
|
+
# }
|
|
442
|
+
# Using it directly on Hash class:
|
|
443
|
+
# validate(select_hash_key=nil, values_hash_to_validate) (alias: val)
|
|
444
|
+
# validate_patterns(select_hash_key=nil, values_hash_to_validate)
|
|
445
|
+
#
|
|
446
|
+
# results = my_hash.validate_patterns(:correct, values_to_validate)
|
|
447
|
+
# results = my_hash.validate(:correct, values_to_validate)
|
|
448
|
+
###########################################################################
|
|
449
|
+
def NiceHash.validate(patterns_hash, values_hash_to_validate, only_patterns: true)
|
|
450
|
+
if patterns_hash.kind_of?(Array)
|
|
451
|
+
pattern_hash=patterns_hash[0]
|
|
452
|
+
select_hash_key=patterns_hash[1]
|
|
453
|
+
elsif patterns_hash.kind_of?(Hash)
|
|
454
|
+
pattern_hash=patterns_hash
|
|
455
|
+
select_hash_key=nil
|
|
456
|
+
else
|
|
457
|
+
puts "NiceHash.validate wrong pattern_hash supplied #{patterns_hash.inspect}"
|
|
458
|
+
return {error: :error}
|
|
459
|
+
end
|
|
460
|
+
values = values_hash_to_validate
|
|
461
|
+
results={}
|
|
462
|
+
same_values={}
|
|
463
|
+
if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
|
|
464
|
+
pattern_hash.each {|key, value|
|
|
465
|
+
|
|
466
|
+
if key.kind_of?(Array)
|
|
467
|
+
same_values[key[0]]=key.dup
|
|
468
|
+
same_values[key[0]].shift
|
|
469
|
+
key=key[0]
|
|
470
|
+
end
|
|
471
|
+
if value.kind_of?(Hash)
|
|
472
|
+
if !select_hash_key.nil? and value.keys.include?(select_hash_key)
|
|
473
|
+
value=value[select_hash_key]
|
|
474
|
+
elsif values.keys.include?(key) and values[key].kind_of?(Hash)
|
|
475
|
+
res=NiceHash.validate([value, select_hash_key], values[key], only_patterns: only_patterns)
|
|
476
|
+
results[key]=res if res.size>0
|
|
477
|
+
next
|
|
478
|
+
end
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
if values.keys.include?(key)
|
|
482
|
+
if value.kind_of?(String) or value.kind_of?(Symbol)
|
|
483
|
+
if ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
|
|
484
|
+
res=StringPattern.validate(pattern: value, text: values[key])
|
|
485
|
+
results[key]=res if res.size>0
|
|
486
|
+
elsif !only_patterns and ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
|
|
487
|
+
results[key]=false unless value.to_s.split("|").include?(values[key])
|
|
488
|
+
elsif !only_patterns
|
|
489
|
+
results[key]=false unless value.to_s==values[key].to_s
|
|
490
|
+
end
|
|
491
|
+
elsif value.kind_of?(Array)
|
|
492
|
+
array_pattern=false
|
|
493
|
+
complex_data=false
|
|
494
|
+
value.each {|v|
|
|
495
|
+
if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
|
|
496
|
+
res=StringPattern.validate(pattern: value, text: values[key])
|
|
497
|
+
results[key]=res if res==false
|
|
498
|
+
array_pattern=true
|
|
499
|
+
break
|
|
500
|
+
elsif v.kind_of?(Hash) or v.kind_of?(Array) or v.kind_of?(Struct)
|
|
501
|
+
complex_data=true
|
|
502
|
+
break
|
|
503
|
+
end
|
|
504
|
+
}
|
|
505
|
+
unless array_pattern or results.include?(key)
|
|
506
|
+
i=0
|
|
507
|
+
value.each {|v|
|
|
508
|
+
res=NiceHash.validate([v, select_hash_key], values[key][i], only_patterns: only_patterns)
|
|
509
|
+
if res.size>0
|
|
510
|
+
results[key]=Array.new() if !results.keys.include?(key)
|
|
511
|
+
results[key][i]=res
|
|
512
|
+
end
|
|
513
|
+
i+=1
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
end
|
|
517
|
+
unless array_pattern or only_patterns or results.include?(key) or complex_data
|
|
518
|
+
results[key]=false unless value==values[key]
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
else
|
|
522
|
+
unless only_patterns or value.kind_of?(Proc)
|
|
523
|
+
results[key]=false unless value==values[key]
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
if same_values.include?(key)
|
|
528
|
+
same_values[key].each {|k|
|
|
529
|
+
if values.keys.include?(k)
|
|
530
|
+
if values[key]!=values[k]
|
|
531
|
+
results[k]="Not equal to #{key}"
|
|
532
|
+
end
|
|
533
|
+
end
|
|
534
|
+
}
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
end
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
return results
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
###########################################################################
|
|
546
|
+
# Change only one value at a time and return an Array of Hashes
|
|
547
|
+
# 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.
|
|
548
|
+
# 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
|
|
549
|
+
# input:
|
|
550
|
+
# patterns_hash:
|
|
551
|
+
# (Hash) Hash where we have defined the patterns to follow.
|
|
552
|
+
# (Array) In case of array supplied, the pair: [pattern_hash, select_hash_key]. select_hash_key will filter the hash by that key
|
|
553
|
+
# values_hash: (Hash) Hash of values to use to modify the values generated on patterns_hash
|
|
554
|
+
# output: (Array of Hashes)
|
|
555
|
+
# example:
|
|
556
|
+
# wrong_min_length_hash = my_hash.generate(:correct, errors: :min_length)
|
|
557
|
+
# array_of_hashes = NiceHash.change_one_by_one([my_hash, :correct], wrong_min_length_hash)
|
|
558
|
+
# array_of_hashes.each {|hash_with_one_wrong_field|
|
|
559
|
+
# #Here your code to send through http the JSON data stored in hash_with_one_wrong_field
|
|
560
|
+
# #if you want to know which field is the one that is wrong:
|
|
561
|
+
# res = my_hash.validate(:correct, hash_with_one_wrong_field)
|
|
562
|
+
# }
|
|
563
|
+
###########################################################################
|
|
564
|
+
def NiceHash.change_one_by_one(patterns_hash, values_hash)
|
|
565
|
+
if patterns_hash.kind_of?(Array)
|
|
566
|
+
select_key=patterns_hash[1]
|
|
567
|
+
pattern_hash=patterns_hash[0]
|
|
568
|
+
else
|
|
569
|
+
pattern_hash=patterns_hash
|
|
570
|
+
select_key=[]
|
|
571
|
+
end
|
|
572
|
+
array=Array.new
|
|
573
|
+
good_values=NiceHash.generate(pattern_hash, select_key)
|
|
574
|
+
select_keys=pattern_hash.pattern_fields(select_key)+pattern_hash.select_fields(select_key)
|
|
575
|
+
select_keys.each {|field|
|
|
576
|
+
new_hash=Marshal.load(Marshal.dump(good_values))
|
|
577
|
+
# to deal with the case same values... like in pwd1, pwd2, pwd3
|
|
578
|
+
if field[-1].kind_of?(Array)
|
|
579
|
+
last_to_set=field[-1]
|
|
580
|
+
else
|
|
581
|
+
last_to_set=[field[-1]]
|
|
582
|
+
end
|
|
583
|
+
last_to_set.each {|f|
|
|
584
|
+
keys=field[0..-2]<<f
|
|
585
|
+
new_hash.bury(keys, values_hash.dig(*keys))
|
|
586
|
+
}
|
|
587
|
+
array<<new_hash
|
|
588
|
+
}
|
|
589
|
+
return array
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
##################################################
|
|
594
|
+
# Get values from the Hash structure (array of Hashes allowed)
|
|
595
|
+
# In case the key supplied doesn't exist in the hash then it will be return nil for that one
|
|
596
|
+
# input:
|
|
597
|
+
# hashv: a simple hash or a hash containing arrays. Example:
|
|
598
|
+
# example={"id"=>344,
|
|
599
|
+
# "customer"=>{
|
|
600
|
+
# "name"=>"Peter Smith",
|
|
601
|
+
# "phone"=>334334333
|
|
602
|
+
# },
|
|
603
|
+
# "tickets"=>[
|
|
604
|
+
# {"idt"=>345,"name"=>"myFavor1"},
|
|
605
|
+
# {"idt"=>3123},
|
|
606
|
+
# {"idt"=>3145,"name"=>"Special ticket"}
|
|
607
|
+
# ]
|
|
608
|
+
# }
|
|
609
|
+
# keys: one key (string) or an array of keys
|
|
610
|
+
# output:
|
|
611
|
+
# a Hash of Arrays with all values found.
|
|
612
|
+
# Example of output with example.get_values("id","name")
|
|
613
|
+
# {"id"=>[334],"name"=>["Peter North"]}
|
|
614
|
+
# Example of output with example.get_values("idt")
|
|
615
|
+
# {"idt"=>[345,3123,3145]}
|
|
616
|
+
#
|
|
617
|
+
####################################################
|
|
618
|
+
def NiceHash.get_values(hashv,keys)
|
|
619
|
+
if keys.kind_of?(String) or keys.kind_of?(Symbol) then
|
|
620
|
+
keys=[keys]
|
|
621
|
+
end
|
|
622
|
+
result=Hash.new()
|
|
623
|
+
number_of_results=Hash.new()
|
|
624
|
+
keys.each {|key|
|
|
625
|
+
number_of_results[key]=0
|
|
626
|
+
}
|
|
627
|
+
if hashv.kind_of?(Array) then
|
|
628
|
+
hashv.each {|tmp|
|
|
629
|
+
if tmp.kind_of?(Array) or tmp.kind_of?(Hash) then
|
|
630
|
+
n_result=get_values(tmp, keys)
|
|
631
|
+
if n_result!=:error then
|
|
632
|
+
n_result.each {|n_key, n_value|
|
|
633
|
+
if result.has_key?(n_key) then
|
|
634
|
+
if !result[n_key].kind_of?(Array) or
|
|
635
|
+
(result[n_key].kind_of?(Array) and number_of_results[n_key] < result[n_key].size) then
|
|
636
|
+
if result[n_key].kind_of?(Hash) or result[n_key].kind_of?(Array) then
|
|
637
|
+
res_tx=result[n_key].dup()
|
|
638
|
+
else
|
|
639
|
+
res_tx=result[n_key]
|
|
640
|
+
end
|
|
641
|
+
result[n_key]=Array.new()
|
|
642
|
+
result[n_key].push(res_tx)
|
|
643
|
+
result[n_key].push(n_value)
|
|
644
|
+
else
|
|
645
|
+
result[n_key].push(n_value)
|
|
646
|
+
end
|
|
647
|
+
else
|
|
648
|
+
result[n_key]=n_value
|
|
649
|
+
end
|
|
650
|
+
number_of_results[n_key]+=1
|
|
651
|
+
}
|
|
652
|
+
end
|
|
653
|
+
end
|
|
654
|
+
}
|
|
655
|
+
elsif hashv.kind_of?(Hash) then
|
|
656
|
+
hashv.each {|key, value|
|
|
657
|
+
#if keys.include?(key) then
|
|
658
|
+
#added to be able to access the keys with symbols to strings and opposite
|
|
659
|
+
if keys.include?(key) or keys.include?(key.to_s) or keys.include?(key.to_sym) then
|
|
660
|
+
#added to be able to access the keys with symbols to strings and opposite
|
|
661
|
+
key=key.to_s() if keys.include?(key.to_s)
|
|
662
|
+
key=key.to_sym() if keys.include?(key.to_sym)
|
|
663
|
+
|
|
664
|
+
if result.has_key?(key) then
|
|
665
|
+
if !result[key].kind_of?(Array) or
|
|
666
|
+
(result[key].kind_of?(Array) and number_of_results[key] < result[key].size) then
|
|
667
|
+
if result[key].kind_of?(Hash) or result[key].kind_of?(Array) then
|
|
668
|
+
res_tx=result[key].dup()
|
|
669
|
+
else
|
|
670
|
+
res_tx=result[key]
|
|
671
|
+
end
|
|
672
|
+
result[key]=Array.new()
|
|
673
|
+
result[key].push(res_tx)
|
|
674
|
+
result[key].push(value)
|
|
675
|
+
else
|
|
676
|
+
result[key].push(value)
|
|
677
|
+
end
|
|
678
|
+
else
|
|
679
|
+
result[key]=value
|
|
680
|
+
end
|
|
681
|
+
number_of_results[key]+=1
|
|
682
|
+
end
|
|
683
|
+
if value.kind_of?(Array) or value.kind_of?(Hash) then
|
|
684
|
+
n_result=get_values(value, keys)
|
|
685
|
+
if n_result!=:error then
|
|
686
|
+
n_result.each {|n_key, n_value|
|
|
687
|
+
if result.has_key?(n_key) then
|
|
688
|
+
if !result[n_key].kind_of?(Array) or
|
|
689
|
+
(result[n_key].kind_of?(Array) and number_of_results[n_key] < result[n_key].size) then
|
|
690
|
+
if result[n_key].kind_of?(Hash) or result[n_key].kind_of?(Array) then
|
|
691
|
+
res_tx=result[n_key].dup()
|
|
692
|
+
else
|
|
693
|
+
res_tx=result[n_key]
|
|
694
|
+
end
|
|
695
|
+
result[n_key]=Array.new()
|
|
696
|
+
result[n_key].push(res_tx)
|
|
697
|
+
result[n_key].push(n_value)
|
|
698
|
+
else
|
|
699
|
+
result[n_key].push(n_value)
|
|
700
|
+
end
|
|
701
|
+
else
|
|
702
|
+
result[n_key]=n_value
|
|
703
|
+
end
|
|
704
|
+
number_of_results[n_key]+=1
|
|
705
|
+
}
|
|
706
|
+
end
|
|
707
|
+
end
|
|
708
|
+
}
|
|
709
|
+
else
|
|
710
|
+
return :error
|
|
711
|
+
end
|
|
712
|
+
if result.kind_of?(Hash) and caller[0]["get_values"].nil? then #no error or anything weird
|
|
713
|
+
(keys-result.keys).each {|k| #in case some keys don't exist in the hash
|
|
714
|
+
result[k]=nil
|
|
715
|
+
}
|
|
716
|
+
end
|
|
717
|
+
return result
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
end
|