nice_hash 1.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fb7ee5f4b573f8086229554d2faa0b453a3151b0d1079de3506a91576e6e1fdb
4
+ data.tar.gz: 682b00b149237da2b21c039ad405583389cde10b9a8a7051ecf86212d762f8ca
5
+ SHA512:
6
+ metadata.gz: 507dc1d466f6fa6a34708a716f778b33d1c77608ad11ad8f58c853e47de41c9f8023f3ec486412c8c655691bee689bfc495bd3cbabb2aed4a1eb82ea6e57fd08
7
+ data.tar.gz: 3cfb95b45dd3931f02d91d572a568f032be4fcec3d0386541b75a6fe2ab106f9532348148f557b564c5ccc1d81a8254692fec066cf0c667b1d1124f605280113
@@ -0,0 +1,5 @@
1
+ --readme README.md
2
+ --title 'nice_hash - NiceHash creates hashes following certain patterns so your testing will be much easier. You can easily generates all the hashes you want following the criteria you specify.'
3
+ --charset utf-8
4
+ --markup markdown
5
+ 'lib/**/*.rb' - '*.md' - 'LICENSE'
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Mario Ruiz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,515 @@
1
+ # NiceHash
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/nice_hash.svg)](https://rubygems.org/gems/nice_hash)
4
+
5
+ NiceHash creates hashes following certain patterns so your testing will be much easier.
6
+
7
+ You can easily generates all the hashes you want following the criteria you specify.
8
+
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. You will be able to generate thousands of different hashes just declaring one and test easily APIs based on JSON for example.
10
+
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
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'nice_hash'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install nice_hash
28
+
29
+ ## Usage
30
+
31
+ Remember!! To generate the strings following a pattern take a look at the documentation for string_pattern gem: https://github.com/MarioRuiz/string_pattern
32
+
33
+ This is he Hash we will be using on our examples:
34
+
35
+ ```ruby
36
+
37
+ require 'nice_hash'
38
+
39
+ my_hash={
40
+ loginame: :"5-10:/xn/",
41
+ [:pwd1, :pwd2, :pwd3] => :"5-10:L/n/",
42
+ name: :"10-20:T_/x/",
43
+ draws: [
44
+ {
45
+ drawId: :"5:N",
46
+ drawName: :"10:Ln",
47
+ type: :"Weekely|Daily",
48
+ owner: {
49
+ default: 'admin',
50
+ correct: :"20:L"
51
+ }
52
+ },
53
+ {
54
+ drawId: :"5:N",
55
+ drawName: :"10:Ln",
56
+ type: :"Weekely|Daily",
57
+ owner: {
58
+ default: 'admin',
59
+ correct: :"20:L"
60
+ }
61
+ }
62
+ ],
63
+ zip: {default: '00000', correct: :'5:N'},
64
+ address: "21 Doom Av",
65
+ city: {
66
+ default: "Madrid",
67
+ correct: "London|Rome"
68
+ },
69
+ wagers: ['34AAB', 'dfffDD', '33499A'],
70
+ country: {default: 'Spain', correct: ["Spain", "Iceland", "Serbia", "Denmark", "Canada", "Italy", "Austria"].join("|")}, #one of these values
71
+ mobilePhone: {default: '(987)654321', correct: ['(', :'3:N', ')', :'6-8:N']},
72
+ sex: :"male|female", #any of these values
73
+ display: true
74
+ }
75
+ ```
76
+
77
+ Explanations of the different fields:
78
+
79
+ loginname: from 5 to 10 characters, mandatory to have lower letters and numbers
80
+ pwd, pwd2, pwd3: will have the same value. The value from 5 to 10 chars, optional capital and lower letters, necessary to contain numbers
81
+ name: from 10 to 20 chars. Optional national characters and space, necessary lower letters.
82
+ drawId: 5 numbers
83
+ drawName: 10 letters and/or numbers
84
+ type: 'Weekely' or 'Daily'
85
+ owner: correct: 20 letters
86
+ zip: correct: 5 numbers
87
+ city: correct: 'London' or 'Rome'
88
+ country: correct: one of these values "Spain", "Iceland", "Serbia", "Denmark", "Canada", "Italy", "Austria"
89
+ mobilePhone: correct: a sting pattern with one of the next: "(nnn) nnnnnn", "(nnn) nnnnnnn", "(nnn) nnnnnnnn"
90
+ sex: 'male' or 'female'
91
+
92
+ So in case you want to assign to a key a string pattern value like for example in loginame, you need to specify the string pattern as a symbol :"5-10:/xn/"
93
+
94
+ You can also supply an array of strings and string patterns, like on mobilePhone.correct: ['(', :'3:N', ')', :'6-8:N']}
95
+
96
+ Also you can specify to select one of the values you want by separating them with |, like for example on sex field: "male|female"
97
+
98
+ ### How to access the different keys
99
+
100
+ You can access the keys of the hash like always, but now we added to the Hash class the posibility of accessing it using:
101
+
102
+ ```ruby
103
+ puts my_hash[:address] # like usually is done
104
+ puts my_hash.address
105
+ my_hash.address = '99 Danish Street' #assignment
106
+ puts my_hash.loginame
107
+ puts my_hash.mobilePhone.correct
108
+ puts my_hash.draws[1].owner.correct
109
+ ```
110
+ Also another way to access the different keys is by adding first underscore.
111
+ By doing it this way we are avoiding the cases where already exists a method with the same name on Hash class, for example: zip, display, default, select...
112
+
113
+ ```ruby
114
+ puts my_hash._address
115
+ my_hash._address = '99 Danish Street' #assignment
116
+ my_hash._display = false #assignment
117
+ puts my_hash._loginame
118
+ puts my_hash._mobilePhone._correct
119
+ puts my_hash._draws[1]._owner._correct
120
+ puts my_hash._zip.correct #you can mix both also
121
+ ```
122
+
123
+ By using the string_pattern gem you can generate single strings following the specific pattern on the field:
124
+
125
+ ```ruby
126
+ puts my_hash.loginame.generate #>s93owuvkh
127
+ puts my_hash.mobilePhone.correct.generate #>(039)5669558
128
+ puts my_hash._zip._correct.gen # gen is an alias for generate method #>84584
129
+ ```
130
+
131
+ ### Filtering / Selecting an specific key on the hash and subhashes
132
+
133
+ In case you supply different possibilities to be used like for example on fields: owner, zip, city and mobilePhone, and you one to use a concrete one, use the method select_key
134
+
135
+ ```ruby
136
+ #using NiceHash class
137
+ new_hash = NiceHash.select_key(my_hash, :correct)
138
+ #using select_key method on Hash class
139
+ new_hash = my_hash.select_key(:correct)
140
+ default_hash = my_hash.select_key(:default)
141
+ ```
142
+
143
+ On this example new_hash will contain:
144
+
145
+ ```ruby
146
+ {
147
+ loginame: :"5-10:/xn/",
148
+ [:pwd1, :pwd2, :pwd3] => :"5-10:L/n/",
149
+ name: :"10-20:T_/x/",
150
+ draws: [
151
+ {
152
+ drawId: :"5:N",
153
+ drawName: :"10:Ln",
154
+ type: :"Weekely|Daily",
155
+ owner: :"20:L"
156
+ },
157
+ {
158
+ drawId: :"5:N",
159
+ drawName: :"10:Ln",
160
+ type: :"Weekely|Daily",
161
+ owner: :"20:L"
162
+ }
163
+ ],
164
+ zip: :'5:N',
165
+ address: "21 Doom Av",
166
+ city: "London|Rome",
167
+ wagers: ['34AAB', 'dfffDD', '33499A'],
168
+ country: ["Spain", "Iceland", "Serbia", "Denmark", "Canada", "Italy", "Austria"].join("|"), #one of these values
169
+ mobilePhone: ['(', :'3:N', ')', :'6-8:N'],
170
+ sex: :"male|female", #any of these values
171
+ display: true
172
+ }
173
+ ```
174
+
175
+ ### How to generate the hash with the criteria we want
176
+
177
+ You can use the 'generate' method and everytime will be generated a different hash with different values.
178
+
179
+ Remember you can filter/select by a hash key
180
+
181
+ Using the NiceHash class:
182
+ ```ruby
183
+ #without filtering
184
+ new_hash = NiceHash.generate(my_hash)
185
+ #filtering by a key passing the key on parameters
186
+ new_hash = NiceHash.generate(my_hash, :correct)
187
+ ```
188
+
189
+ Using Hash class (you can use the alias 'gen' for 'generate'):
190
+ ```ruby
191
+ #without filtering
192
+ new_hash = my_hash.generate
193
+ #filtering by a key passing the key on parameters
194
+ new_hash = my_hash.generate(:correct)
195
+ #filtering by a key using select_key method
196
+ new_hash = my_hash.select_key(:correct).generate
197
+ ```
198
+
199
+
200
+ In case of filtering by :correct new_hash would have a value like this for example:
201
+
202
+ ```ruby
203
+ {:loginame=>"s45x029o",
204
+ :pwd1=>"E6hz9YS7",
205
+ :pwd2=>"E6hz9YS7",
206
+ :pwd3=>"E6hz9YS7",
207
+ :name=>"OyTQNfEyPOzVYMxPym",
208
+ :draws=>
209
+ [{:drawId=>"54591",
210
+ :drawName=>"cr5Q7pq4G8",
211
+ :type=>"Weekely",
212
+ :owner=>"nKEasYWInPGJxxElBZUB"},
213
+ {:drawId=>"73307",
214
+ :drawName=>"FnHPM4CsRC",
215
+ :type=>"Weekely",
216
+ :owner=>"cNGpHDhDLcxSFbOGqvNy"}],
217
+ :zip=>"47537",
218
+ :address=>"21 Doom Av",
219
+ :city=>"London",
220
+ :wagers=>["34AAB", "dfffDD", "33499A"],
221
+ :country=>"Denmark",
222
+ :mobilePhone=>"(707)8782080",
223
+ :sex=>"male",
224
+ :display=>true}
225
+ ```
226
+
227
+ In case no filtering you will get all the values for all keys
228
+
229
+ ### How to generate the hash with wrong values for the string patterns specified on the hash
230
+
231
+ We can generate wrong values passing the keyword argument: expected_errors (alias: errors)
232
+
233
+ The possible values you can specify is one or more of these ones: :length, :min_length, :max_length, :value, :required_data, :excluded_data, :string_set_not_allowed
234
+
235
+ :length: wrong length, minimum or maximum
236
+ :min_length: wrong minimum length
237
+ :max_length: wrong maximum length
238
+ :value: wrong resultant value
239
+ :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.
240
+ :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.
241
+ :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.
242
+
243
+ Examples:
244
+
245
+ ```ruby
246
+ wrong_values = my_hash.generate(:correct, expected_errors: [:value])
247
+
248
+ wrong_max_length = my_hash.generate(:correct, errors: :max_length)
249
+
250
+ wrong_min_length = my_hash.generate(:correct, expected_errors: :min_length)
251
+
252
+ wrong_min_length = my_hash.select_key(:correct).generate(errors: :min_length)
253
+
254
+ valid_values = my_hash.generate(:correct)
255
+ ```
256
+
257
+ On this example wrong_min_length will contain something like:
258
+
259
+ ```ruby
260
+ {:loginame=>"0u",
261
+ :pwd1=>"4XDx",
262
+ :pwd2=>"4XDx",
263
+ :pwd3=>"4XDx",
264
+ :name=>"bU",
265
+ :draws=>
266
+ [{:drawId=>"", :drawName=>"P03AgdMqV", :type=>"Dail", :owner=>"dYzLRMCnVc"},
267
+ {:drawId=>"", :drawName=>"qw", :type=>"Dail", :owner=>"zkHhTEzM"}],
268
+ :zip=>"7168",
269
+ :address=>"21 Doom Av",
270
+ :city=>"Rom",
271
+ :wagers=>["34AAB", "dfffDD", "33499A"],
272
+ :country=>"Spai",
273
+ :mobilePhone=>"(237)17640431",
274
+ :sex=>"mal",
275
+ :display=>true}
276
+ ```
277
+
278
+ ### Return the select_fields or the pattern_fields
279
+
280
+ If you need a list of select fields or pattern fields that exist on your hash you can use the methods: select_fields and pattern_fields
281
+
282
+ It will return an array with all the fields found. On every entry of the array you will see keys to the field.
283
+
284
+ ```ruby
285
+ all_select_fields = my_hash.select_fields
286
+ select_fields_on_correct = my_hash.select_fields(:correct)
287
+
288
+ all_pattern_fields = my_hash.pattern_fields
289
+ pattern_fields_on_correct = my_hash.pattern_fields(:correct)
290
+ ```
291
+
292
+ all_select_fields contains:
293
+
294
+ ```ruby
295
+ [[:draws, 0, :type],
296
+ [:draws, 1, :type],
297
+ [:city, :correct],
298
+ [:country, :correct],
299
+ [:sex]]
300
+ ```
301
+
302
+ select_fields_on_correct contains:
303
+
304
+ ```ruby
305
+ [[:draws, 0, :type],
306
+ [:draws, 1, :type],
307
+ [:city],
308
+ [:country],
309
+ [:sex]]
310
+ ```
311
+
312
+ all_pattern_fields contains:
313
+
314
+ ```ruby
315
+ [[:loginame],
316
+ [[:pwd1, :pwd2, :pwd3]],
317
+ [:name],
318
+ [:draws, 0, :drawId],
319
+ [:draws, 0, :drawName],
320
+ [:draws, 0, :owner, :correct],
321
+ [:draws, 1, :drawId],
322
+ [:draws, 1, :drawName],
323
+ [:draws, 1, :owner, :correct],
324
+ [:zip, :correct],
325
+ [:mobilePhone, :correct]]
326
+ ```
327
+
328
+ pattern_fields_on_correct contains:
329
+
330
+ ```ruby
331
+ [[:loginame],
332
+ [[:pwd1, :pwd2, :pwd3]],
333
+ [:name],
334
+ [:draws, 0, :drawId],
335
+ [:draws, 0, :drawName],
336
+ [:draws, 0, :owner],
337
+ [:draws, 1, :drawId],
338
+ [:draws, 1, :drawName],
339
+ [:draws, 1, :owner],
340
+ [:zip],
341
+ [:mobilePhone]]
342
+ ```
343
+
344
+
345
+ #### dig and bury Hash methods
346
+ In case you want to access the values on a hash structure by using the key array location, you can use the 'dig' method on the Hash class:
347
+
348
+ ```ruby
349
+ min_length_error = my_hash.generate :correct, errors: :min_length
350
+
351
+ patterns = my_hash.pattern_fields :correct
352
+
353
+ patterns.each{|key|
354
+ if key[0].kind_of?(Array) # same values, like in pwd1, pwd2 and pwd3
355
+ puts "#{key} same values"
356
+ value = min_length_error.dig(key[0][0])
357
+ else
358
+ value = min_length_error.dig(*key)
359
+ end
360
+
361
+ pattern = my_hash.select_key(:correct).dig(*key)
362
+ puts "the value: '#{value}' was generated from the key: #{key} with pattern: #{pattern}"
363
+ }
364
+ ```
365
+
366
+ This returns something like:
367
+
368
+ ```
369
+ the value: '5z' was generated from the key: [:loginame] with pattern: 5-10:/xn/
370
+ [[:pwd1, :pwd2, :pwd3]] same values
371
+ the value: '5' was generated from the key: [[:pwd1, :pwd2, :pwd3]] with pattern: 5-10:L/n/
372
+ the value: 'KshiYAmp' was generated from the key: [:name] with pattern: 10-20:T_/x/
373
+ the value: '722' was generated from the key: [:draws, 0, :drawId] with pattern: 5:N
374
+ the value: '4' was generated from the key: [:draws, 0, :drawName] with pattern: 10:Ln
375
+ the value: 'jhVZkII' was generated from the key: [:draws, 0, :owner] with pattern: 20:L
376
+ the value: '260' was generated from the key: [:draws, 1, :drawId] with pattern: 5:N
377
+ the value: 'ssty8hlnJ' was generated from the key: [:draws, 1, :drawName] with pattern: 10:Ln
378
+ the value: 'zPvcwOyyXvWSgNHsuv' was generated from the key: [:draws, 1, :owner] with pattern: 20:L
379
+ the value: '242' was generated from the key: [:zip] with pattern: 5:N
380
+ the value: '(91)7606' was generated from the key: [:mobilePhone] with pattern: ["(", :"3:N", ")", :"6-8:N"]
381
+ ```
382
+
383
+ Ruby Hash class doesn't have a method to allocate a value using the key array location so we added to Hash class a method for that purpose, the 'bury' method.
384
+
385
+ ```ruby
386
+ default_values = my_hash.generate :default
387
+
388
+ default_values.bury([:draws, 0, :drawName], "FirstDraw")
389
+ ```
390
+
391
+ After using the bury method default_values will contain:
392
+
393
+ ```ruby
394
+ {:loginame=>"i0v2jy",
395
+ :pwd1=>"x33exx",
396
+ :pwd2=>"x33exx",
397
+ :pwd3=>"x33exx",
398
+ :name=>"HdmsjLxlEgYIFY",
399
+ :draws=>
400
+ [{:drawId=>"12318",
401
+ :drawName=>"FirstDraw",
402
+ :type=>"Weekely",
403
+ :owner=>"admin"},
404
+ {:drawId=>"18947",
405
+ :drawName=>"LPgf2ZQvkG",
406
+ :type=>"Weekely",
407
+ :owner=>"admin"}],
408
+ :zip=>"00000",
409
+ :address=>"21 Doom Av",
410
+ :city=>"Madrid",
411
+ :wagers=>["34AAB", "dfffDD", "33499A"],
412
+ :country=>"Spain",
413
+ :mobilePhone=>"(987)654321",
414
+ :sex=>"male",
415
+ :display=>true}
416
+ ```
417
+
418
+ ### Validating hashes
419
+
420
+ If you have a Hash that should follow the patterns you specified (in this example declared on my_hash) and you want to validate, then use the 'validate' method.
421
+
422
+ This is particulary useful to test REST APIs responses in JSON
423
+
424
+ If we have a hash with these values:
425
+
426
+ ```ruby
427
+ {:loginame=>"rdewvqur",
428
+ :pwd1=>"d3ulo",
429
+ :pwd2=>"d3ulo",
430
+ :pwd3=>"d3ulo",
431
+ :name=>"LTqVKxxFCTqpkdjFkxU",
432
+ :draws=>
433
+ [{:drawId=>"54a43",
434
+ :drawName=>"h3F24yjMWp",
435
+ :type=>"Daily",
436
+ :owner=>"abIZMRxTDsWjQcpdspZt"},
437
+ {:drawId=>"13010",
438
+ :drawName=>"NurCEAtE1M",
439
+ :type=>"Daily",
440
+ :owner=>"vSVoqtSzHkbvRNyJoYGz"}],
441
+ :zip=>"30222",
442
+ :address=>"21 Doom Av",
443
+ :city=>"New York",
444
+ :wagers=>["34AAB", "dfffDD", "33499A"],
445
+ :country=>"Iceland",
446
+ :mobilePhone=>"(441)97037845",
447
+ :sex=>"male",
448
+ :display=>true}
449
+ ```
450
+
451
+ To validate those values taking in consideration was is stated on my_hash:
452
+
453
+ ```ruby
454
+ results_all_fields = my_hash.validate :correct, values
455
+
456
+ results_pattern_fields = my_hash.validate_patterns :correct, values
457
+ ```
458
+
459
+ results_all_fields will contain all the validation errors:
460
+
461
+ ```ruby
462
+ {:loginame=>[:value, :required_data],
463
+ :draws=>[{:drawId=>[:value, :string_set_not_allowed]}],
464
+ :city=>false}
465
+ ```
466
+
467
+ and results_pattern_fields will contain only the validation errors for the fields containing patterns:
468
+
469
+ ```ruby
470
+ {:loginame=>[:value, :required_data],
471
+ :draws=>[{:drawId=>[:value, :string_set_not_allowed]}]}
472
+ ```
473
+
474
+ The possible validation values returned:
475
+
476
+ :length: wrong length, minimum or maximum
477
+ :min_length: wrong minimum length
478
+ :max_length: wrong maximum length
479
+ :value: wrong resultant value
480
+ :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.
481
+ :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.
482
+ :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.
483
+
484
+
485
+ ### Change only one value at a time and return an Array of Hashes
486
+
487
+ 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.
488
+
489
+ Then the best thing you can do is to use the method NiceHash.change_one_by_one.
490
+
491
+
492
+ ```ruby
493
+
494
+ wrong_min_length_hash = my_hash.generate(:correct, errors: :min_length)
495
+
496
+ array_of_hashes = NiceHash.change_one_by_one([my_hash, :correct], wrong_min_length_hash)
497
+
498
+ array_of_hashes.each {|hash_with_one_wrong_field|
499
+ #Here your code to send through http the JSON data stored in hash_with_one_wrong_field
500
+
501
+ #if you want to know which field is the one that is wrong:
502
+ res = my_hash.validate(:correct, hash_with_one_wrong_field)
503
+ }
504
+ ```
505
+
506
+ ## Contributing
507
+
508
+ Bug reports and pull requests are welcome on GitHub at https://github.com/marioruiz/nice_hash.
509
+
510
+
511
+ ## License
512
+
513
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
514
+
515
+
@@ -0,0 +1,127 @@
1
+ class Array
2
+
3
+ ###########################################################################
4
+ # Stores a value on the location indicated
5
+ # input:
6
+ # where: (Array)
7
+ # value
8
+ # examples:
9
+ # my_array.bury([3, 0], "doom") # array of array
10
+ # my_array.bury([2, 1, :original],"the value to set") #array of array of hash
11
+ ###########################################################################
12
+ def bury(where, value)
13
+ me=self
14
+ where[0..-2].each {|key|
15
+ me=me[key]
16
+ }
17
+ me[where[-1]]=value
18
+ end
19
+ end
20
+
21
+
22
+ class Hash
23
+ ###########################################################################
24
+ # Returns the value of the key specified in case doesn't exist a Hash method with the same name
25
+ # The keys can be accessed also adding underscore to avoid problems with existent methods
26
+ # Also set values in case = supplied
27
+ # examples:
28
+ # my_hash.address.correct
29
+ # my_hash._address._correct
30
+ # my_hash.city
31
+ # my_hash._city
32
+ # my_hash.city="Paris"
33
+ # my_hash.products[1].price.wrong="AAAAA"
34
+ ###########################################################################
35
+ def method_missing(m, *arguments, &block)
36
+ if m[0]=='_'
37
+ m=m[1..-1].to_sym
38
+ end
39
+ if self.keys.include?(m)
40
+ self[m]
41
+ elsif m.to_s[-1]=="="
42
+ self[m.to_s.chop.to_sym]=arguments[0]
43
+ else
44
+ super
45
+ end
46
+ end
47
+
48
+ ###########################################################################
49
+ # Stores a value on the location indicated
50
+ # input:
51
+ # where: (Array)
52
+ # value
53
+ # examples:
54
+ # my_hash.bury([:bip, :doom], "doom") # hash of hash
55
+ # my_hash.bury([:original, 1, :doom],"the value to set") #hash of array of hash
56
+ ###########################################################################
57
+ def bury(where, value)
58
+ me=self
59
+ where[0..-2].each {|key|
60
+ me=me[key]
61
+ }
62
+ key=where[-1]
63
+ key=[key] unless where[-1].kind_of?(Array) # for the case same value for different keys, for example pwd1, pwd2, pwd3
64
+ key.each {|k|
65
+ me[k]=value
66
+ }
67
+ end
68
+
69
+ ###########################################################################
70
+ # It will filter the hash by the key specified on select_hash_key.
71
+ # In case a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
72
+ # More info: NiceHash.select_key
73
+ ###########################################################################
74
+ def select_key(select_hash_key)
75
+ NiceHash.select_key(self, select_hash_key)
76
+ end
77
+
78
+ ###########################################################################
79
+ # It will generate a new hash with the values generated from the string patterns and select fields specified.
80
+ # 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
81
+ # If expected_errors specified the values will be generated with the specified errors.
82
+ # More info: NiceHash.generate
83
+ # alias: gen
84
+ ###########################################################################
85
+ def generate(select_hash_key=nil, expected_errors: [], **synonyms)
86
+ NiceHash.generate(self, select_hash_key, expected_errors: expected_errors, **synonyms)
87
+ end
88
+
89
+ ###########################################################################
90
+ # Validates a given values_hash_to_validate with string patterns and select fields
91
+ # More info: NiceHash.validate
92
+ # alias: val
93
+ ###########################################################################
94
+ def validate(select_hash_key=nil, values_hash_to_validate)
95
+ NiceHash.validate([self, select_hash_key], values_hash_to_validate, only_patterns: false)
96
+ end
97
+
98
+ ###########################################################################
99
+ # Validates a given values_hash_to_validate with string patterns
100
+ # More info: NiceHash.validate
101
+ ###########################################################################
102
+ def validate_patterns(select_hash_key=nil, values_hash_to_validate)
103
+ NiceHash.validate([self, select_hash_key], values_hash_to_validate, only_patterns: true)
104
+ end
105
+
106
+ ###########################################################################
107
+ # It will return an array of the keys where we are using string patterns.
108
+ # More info: NiceHash.pattern_fields
109
+ ###########################################################################
110
+ def pattern_fields(*select_hash_key)
111
+ NiceHash.pattern_fields(self, *select_hash_key)
112
+ end
113
+
114
+ ###########################################################################
115
+ # It will return an array of the keys where we are using select values of the kind: "value1|value2|value3".
116
+ # More info: NiceHash.select_fields
117
+ ###########################################################################
118
+ def select_fields(*select_hash_key)
119
+ NiceHash.select_fields(self, *select_hash_key)
120
+ end
121
+
122
+
123
+ alias_method :gen, :generate
124
+ alias_method :val, :validate
125
+ alias_method :patterns, :pattern_fields
126
+
127
+ end
@@ -0,0 +1,582 @@
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
+
31
+ ###########################################################################
32
+ # It will filter the hash by the key specified on select_hash_key.
33
+ # In case a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
34
+ #
35
+ # input:
36
+ # pattern_hash: (Hash) Hash we want to select specific keys
37
+ # select_hash_key: (key value) The key we want to select on the subhashes
38
+ # output: (Hash)
39
+ # 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
40
+ # example:
41
+ # new_hash = NiceHash.select_key(my_hash, :wrong)
42
+ # #> {:name=>"Peter", :address=>"\#$$$$$", :city=>"Germany", :products=> [{:name=>:"10:Ln", :price=>"-20"}, {:name=>:"10:Ln", :price=>"-20"}]}
43
+ # Using it directly on Hash class, select_key(select_hash_key):
44
+ # new_hash = my_hash.select_key(:wrong)
45
+ ###########################################################################
46
+ def NiceHash.select_key(pattern_hash, select_hash_key)
47
+ hash=Hash.new()
48
+
49
+ if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
50
+ pattern_hash.each {|key, value|
51
+
52
+ if value.kind_of?(Hash)
53
+ if value.keys.include?(select_hash_key)
54
+ value=value[select_hash_key]
55
+ else
56
+ value=NiceHash.select_key(value, select_hash_key)
57
+ end
58
+ end
59
+ if value.kind_of?(Array)
60
+ array_pattern=false
61
+ value.each {|v|
62
+ if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
63
+ hash[key]=value
64
+ array_pattern=true
65
+ break
66
+ end
67
+ }
68
+ unless array_pattern
69
+ value_ret=Array.new
70
+ value.each {|v|
71
+ ret=NiceHash.select_key(v, select_hash_key)
72
+ value_ret<<ret
73
+ }
74
+ hash[key]=value_ret
75
+ end
76
+ else
77
+ hash[key]=value
78
+ end
79
+ }
80
+ else
81
+ return pattern_hash
82
+ end
83
+ return hash
84
+ end
85
+
86
+ ###########################################################################
87
+ # It will return an array of the keys where we are using string patterns.
88
+ #
89
+ # input:
90
+ # pattern_hash: (Hash) Hash we want to get the pattern_fields
91
+ # select_hash_key: (key value) (optional) The key we want to select on the subhashes
92
+ # output: (Array)
93
+ # Array of the kind: [ [key], [key, subkey, subkey] ]
94
+ # Each value of the array can be used as parameter for the methods: dig, bury
95
+ # examples:
96
+ # NiceHash.pattern_fields(my_hash)
97
+ # #> [
98
+ # [:address, :correct],
99
+ # [:products, 0, :name],
100
+ # [:products, 0, :price, :correct],
101
+ # [:products, 1, :name],
102
+ # [:products, 1, :price, :correct]
103
+ # ]
104
+ # NiceHash.pattern_fields(my_hash, :correct)
105
+ # #> [
106
+ # [:address],
107
+ # [:products, 0, :name],
108
+ # [:products, 0, :price],
109
+ # [:products, 1, :name],
110
+ # [:products, 1, :price]
111
+ # ]
112
+ # Using it directly on Hash class, pattern_fields(*select_hash_key) (alias: patterns):
113
+ # my_hash.pattern_fields
114
+ # my_hash.pattern_fields(:correct)
115
+ # my_hash.patterns(:correct)
116
+ ###########################################################################
117
+ def NiceHash.pattern_fields(pattern_hash, *select_hash_key)
118
+ pattern_fields = Array.new
119
+
120
+ if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
121
+ pattern_hash.each {|key, value|
122
+ key=[key]
123
+ if value.kind_of?(Hash)
124
+ if select_hash_key.size==1 and value.keys.include?(select_hash_key[0])
125
+ value=value[select_hash_key[0]]
126
+ else
127
+ res=NiceHash.pattern_fields(value, *select_hash_key)
128
+ if res.size>0
129
+ res.each {|r|
130
+ pattern_fields<<(r.unshift(key)).flatten
131
+ }
132
+ end
133
+ next
134
+ end
135
+ end
136
+ if value.kind_of?(String)
137
+ if StringPattern.optimistic and value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
138
+ pattern_fields << key
139
+ end
140
+ elsif value.kind_of?(Symbol)
141
+ if value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
142
+ pattern_fields << key
143
+ end
144
+ elsif value.kind_of?(Array)
145
+
146
+ array_pattern=false
147
+ value.each {|v|
148
+ if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
149
+ pattern_fields << key
150
+ array_pattern=true
151
+ break
152
+ end
153
+ }
154
+ unless array_pattern
155
+ i=0
156
+ value.each {|v|
157
+ res=NiceHash.pattern_fields(v, *select_hash_key)
158
+ if res.size>0
159
+ res.each {|r|
160
+ pattern_fields<<(r.unshift(i).unshift(key)).flatten
161
+ }
162
+ end
163
+ i+=1
164
+ }
165
+ end
166
+ end
167
+ }
168
+ end
169
+
170
+ return pattern_fields
171
+ end
172
+
173
+ ###########################################################################
174
+ # It will return an array of the keys where we are using select values of the kind: "value1|value2|value3".
175
+ #
176
+ # input:
177
+ # pattern_hash: (Hash) Hash we want to get the select_fields
178
+ # select_hash_key: (key value) (optional) The key we want to select on the subhashes
179
+ # output: (Array)
180
+ # Array of the kind: [ [key], [key, subkey, subkey] ]
181
+ # Each value of the array can be used as parameter for the methods: dig, bury
182
+ # examples:
183
+ # NiceHash.select_fields(my_hash)
184
+ # #> [[:city, :correct]]
185
+ # NiceHash.select_fields(my_hash, :correct)
186
+ # #> [[:city]]
187
+ # Using it directly on Hash class, select_fields(*select_hash_key):
188
+ # my_hash.select_fields
189
+ # my_hash.select_fields(:correct)
190
+ ###########################################################################
191
+ def NiceHash.select_fields(pattern_hash, *select_hash_key)
192
+ select_fields = Array.new
193
+
194
+ if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
195
+ pattern_hash.each {|key, value|
196
+ key=[key]
197
+ if value.kind_of?(Hash)
198
+ if select_hash_key.size==1 and value.keys.include?(select_hash_key[0])
199
+ value=value[select_hash_key[0]]
200
+ else
201
+ res=NiceHash.select_fields(value, *select_hash_key)
202
+ if res.size>0
203
+ res.each {|r|
204
+ select_fields<<(r.unshift(key)).flatten
205
+ }
206
+ end
207
+ next
208
+ end
209
+ end
210
+ if value.kind_of?(String)
211
+ if StringPattern.optimistic and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
212
+ select_fields << key
213
+ end
214
+ elsif value.kind_of?(Symbol)
215
+ if value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
216
+ select_fields << key
217
+ end
218
+ elsif value.kind_of?(Array)
219
+
220
+ array_pattern=false
221
+ value.each {|v|
222
+ if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
223
+ array_pattern=true
224
+ break
225
+ end
226
+ }
227
+ unless array_pattern
228
+ i=0
229
+ value.each {|v|
230
+ res=NiceHash.select_fields(v, *select_hash_key)
231
+ if res.size>0
232
+ res.each {|r|
233
+ select_fields<<(r.unshift(i).unshift(key)).flatten
234
+ }
235
+ end
236
+ i+=1
237
+ }
238
+ end
239
+ end
240
+ }
241
+ end
242
+
243
+ return select_fields
244
+ end
245
+
246
+
247
+ ###########################################################################
248
+ # It will generate a new hash with the values generated from the string patterns and select fields specified.
249
+ # 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
250
+ # If expected_errors specified the values will be generated with the specified errors.
251
+ # input:
252
+ # pattern_hash: (Hash) Hash we want to use to generate the values
253
+ # select_hash_key: (key value) (optional) The key we want to select on the subhashes
254
+ # expected_errors: (Array) (optional) (alias: errors) To generate the string patterns with the specified errors.
255
+ # The possible values you can specify is one or more of these ones:
256
+ # :length: wrong length, minimum or maximum
257
+ # :min_length: wrong minimum length
258
+ # :max_length: wrong maximum length
259
+ # :value: wrong resultant value
260
+ # :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.
261
+ # :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.
262
+ # :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.
263
+ # output: (Hash)
264
+ # The Hash with the select_hash_key selected and the values generated from the string patterns and select fields specified.
265
+ # examples:
266
+ # new_hash = NiceHash.generate(my_hash)
267
+ # #> {:name=>"Peter",
268
+ # :address=>{:wrong=>"\#$$$$$", :correct=>"KZPCzxsWGMLqonesu wbqH"},
269
+ # :city=>{:wrong=>"Germany", :correct=>"Barcelona"},
270
+ # :products=> [
271
+ # {:name=>"gIqkWygmVm", :price=>{:wrong=>"-20", :correct=>"34338330"}},
272
+ # {:name=>"CK68VLIcYf", :price=>{:wrong=>"-20", :correct=>"616066520"}}
273
+ # ]
274
+ # }
275
+ # new_hash = NiceHash.generate(my_hash, :correct)
276
+ # #> {:name=>"Peter",
277
+ # :address=>"juQeAVZjIuWBPsE",
278
+ # :city=>"Madrid",
279
+ # :products=> [
280
+ # {:name=>"G44Ilr0puV", :price=>"477813"},
281
+ # {:name=>"v6ojs79LOp", :price=>"74820"}
282
+ # ]
283
+ # }
284
+ # new_hash = NiceHash.generate(my_hash, :correct, expected_errors: [:min_length])
285
+ # #> {:name=>"Peter",
286
+ # :address=>"ZytjefJ",
287
+ # :city=>"Madri",
288
+ # :products=>[
289
+ # {:name=>"cIBrzeO", :price=>""},
290
+ # {:name=>"5", :price=>""}
291
+ # ]
292
+ # }
293
+ # Using it directly on Hash class, generate(select_hash_key=nil, expected_errors: []) (alias: gen):
294
+ # new_hash = my_hash.generate
295
+ # new_hash = my_hash.gen(:correct)
296
+ # new_hash = my_hash.generate(:correct, errors: [:min_length])
297
+ ###########################################################################
298
+ def NiceHash.generate(pattern_hash, select_hash_key=nil, expected_errors: [], **synonyms)
299
+ hash=Hash.new()
300
+ same_values=Hash.new()
301
+ expected_errors=synonyms[:errors] if synonyms.keys.include?(:errors)
302
+ if expected_errors.kind_of?(Symbol)
303
+ expected_errors=[expected_errors]
304
+ end
305
+
306
+ if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
307
+ pattern_hash.each {|key, value|
308
+
309
+ if key.kind_of?(Array)
310
+ same_values[key[0]]=key.dup
311
+ same_values[key[0]].shift
312
+ key=key[0]
313
+ end
314
+ if value.kind_of?(Hash)
315
+ if value.keys.include?(select_hash_key)
316
+ value=value[select_hash_key]
317
+ else
318
+ value=NiceHash.generate(value, select_hash_key, expected_errors: expected_errors)
319
+ end
320
+ end
321
+
322
+ if value.kind_of?(String) or value.kind_of?(Symbol)
323
+ if ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
324
+ hash[key]=StringPattern.generate(value, expected_errors: expected_errors)
325
+ elsif ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
326
+ if expected_errors.include?(:min_length) or (expected_errors.include?(:length) and rand.round==0)
327
+ min=value.to_s.split("|").min {|a, b| a.size <=> b.size}
328
+ hash[key]=min[0..-2] unless min==""
329
+ end
330
+ if !hash.keys.include?(key) and (expected_errors.include?(:max_length) or expected_errors.include?(:length))
331
+ max=value.to_s.split("|").max {|a, b| a.size <=> b.size}
332
+ hash[key]=max+max[-1]
333
+ end
334
+ if expected_errors.include?(:value) or
335
+ expected_errors.include?(:string_set_not_allowed) or
336
+ expected_errors.include?(:required_data)
337
+ if hash.keys.include?(key)
338
+ v=hash[key]
339
+ else
340
+ v=value.to_s.split("|").sample
341
+ end
342
+ unless expected_errors.include?(:string_set_not_allowed)
343
+ v=StringPattern.generate(:"#{v.size}:[#{value.to_s.split("|").join.split(//).uniq.join}]")
344
+ hash[key]=v unless value.to_s.split("|").include?(v)
345
+ end
346
+ unless hash.keys.include?(key)
347
+ one_wrong_letter=StringPattern.generate(:"1:LN$[%#{value.to_s.split("|").join.split(//).uniq.join}%]")
348
+ v[rand(v.size)]=one_wrong_letter
349
+ hash[key]=v unless value.to_s.split("|").include?(v)
350
+ end
351
+ end
352
+ unless hash.keys.include?(key)
353
+ hash[key]=value.to_s.split("|").sample
354
+ end
355
+ else
356
+ hash[key]=value
357
+ end
358
+ elsif value.kind_of?(Array)
359
+ array_pattern=false
360
+ value.each {|v|
361
+ if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
362
+ hash[key]=StringPattern.generate(value, expected_errors: expected_errors)
363
+ array_pattern=true
364
+ break
365
+ end
366
+ }
367
+ unless array_pattern
368
+ value_ret=Array.new
369
+ value.each {|v|
370
+ ret=NiceHash.generate(v, select_hash_key, expected_errors: expected_errors)
371
+ ret=v if ret.kind_of?(Hash) and ret.size==0
372
+ value_ret<<ret
373
+ }
374
+ hash[key]=value_ret
375
+ end
376
+ else
377
+ hash[key]=value
378
+ end
379
+
380
+ if same_values.include?(key)
381
+ same_values[key].each {|k|
382
+ hash[k]=hash[key]
383
+ }
384
+ end
385
+
386
+ }
387
+ end
388
+
389
+ return hash
390
+ end
391
+
392
+
393
+ ###########################################################################
394
+ # Validates a given values_hash_to_validate with string patterns and select fields from pattern_hash
395
+ # input:
396
+ # patterns_hash:
397
+ # (Hash) Hash where we have defined the patterns to follow.
398
+ # (Array) In case of array supplied, the pair: [pattern_hash, select_hash_key]. select_hash_key will filter the hash by that key
399
+ # values_hash_to_validate: (Hash) Hash of values to validate
400
+ # only_patterns: (TrueFalse) (by default true) If true it will validate only the patterns and not the other fields
401
+ # output: (Hash)
402
+ # A hash with the validation results. It will return only the validation errors so in case no validation errors found, empty hash.
403
+ # The keys of the hash will be the keys of the values hash with the validation error.
404
+ # The value in case of a pattern, will be an array with one or more of these possibilities:
405
+ # :length: wrong length, minimum or maximum
406
+ # :min_length: wrong minimum length
407
+ # :max_length: wrong maximum length
408
+ # :value: wrong resultant value
409
+ # :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.
410
+ # :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.
411
+ # :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.
412
+ # The value in any other case it will be false if the value is not corresponding to the expected.
413
+ # examples:
414
+ # values_to_validate = {:name=>"Peter",
415
+ # :address=>"fnMuKW",
416
+ # :city=>"Dublin",
417
+ # :products=>[{:name=>"V4", :price=>"344"}, {:name=>"E", :price=>"a"}]
418
+ # }
419
+ # results = NiceHash.validate([my_hash, :correct], values_to_validate)
420
+ # #> {:address=>[:min_length, :length],
421
+ # :products=> [{:name=>[:min_length, :length]},
422
+ # {:name=>[:min_length, :length], :price=>[:value, :string_set_not_allowed]}
423
+ # ]
424
+ # }
425
+ # results = NiceHash.validate([my_hash, :correct], values_to_validate, only_patterns: false)
426
+ # #> {:address=>[:min_length, :length],
427
+ # :city=>false,
428
+ # :products=> [{:name=>[:min_length, :length]},
429
+ # {:name=>[:min_length, :length], :price=>[:value, :string_set_not_allowed]}
430
+ # ]
431
+ # }
432
+ # Using it directly on Hash class:
433
+ # validate(select_hash_key=nil, values_hash_to_validate) (alias: val)
434
+ # validate_patterns(select_hash_key=nil, values_hash_to_validate)
435
+ #
436
+ # results = my_hash.validate_patterns(:correct, values_to_validate)
437
+ # results = my_hash.validate(:correct, values_to_validate)
438
+ ###########################################################################
439
+ def NiceHash.validate(patterns_hash, values_hash_to_validate, only_patterns: true)
440
+ if patterns_hash.kind_of?(Array)
441
+ pattern_hash=patterns_hash[0]
442
+ select_hash_key=patterns_hash[1]
443
+ elsif patterns_hash.kind_of?(Hash)
444
+ pattern_hash=patterns_hash
445
+ select_hash_key=nil
446
+ else
447
+ puts "NiceHash.validate wrong pattern_hash supplied #{patterns_hash.inspect}"
448
+ return {error: :error}
449
+ end
450
+ values = values_hash_to_validate
451
+ results={}
452
+ same_values={}
453
+ if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
454
+ pattern_hash.each {|key, value|
455
+
456
+ if key.kind_of?(Array)
457
+ same_values[key[0]]=key.dup
458
+ same_values[key[0]].shift
459
+ key=key[0]
460
+ end
461
+ if value.kind_of?(Hash)
462
+ if !select_hash_key.nil? and value.keys.include?(select_hash_key)
463
+ value=value[select_hash_key]
464
+ elsif values.keys.include?(key) and values[key].kind_of?(Hash)
465
+ res=NiceHash.validate([value, select_hash_key], values[key], only_patterns: only_patterns)
466
+ results[key]=res if res.size>0
467
+ next
468
+ end
469
+ end
470
+
471
+ if values.keys.include?(key)
472
+ if value.kind_of?(String) or value.kind_of?(Symbol)
473
+ if ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
474
+ res=StringPattern.validate(pattern: value, text: values[key])
475
+ results[key]=res if res.size>0
476
+ 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
477
+ results[key]=false unless value.to_s.split("|").include?(values[key])
478
+ elsif !only_patterns
479
+ results[key]=false unless value.to_s==values[key].to_s
480
+ end
481
+ elsif value.kind_of?(Array)
482
+ array_pattern=false
483
+ complex_data=false
484
+ value.each {|v|
485
+ if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
486
+ res=StringPattern.validate(pattern: value, text: values[key])
487
+ results[key]=res if res==false
488
+ array_pattern=true
489
+ break
490
+ elsif v.kind_of?(Hash) or v.kind_of?(Array) or v.kind_of?(Struct)
491
+ complex_data=true
492
+ break
493
+ end
494
+ }
495
+ unless array_pattern or results.include?(key)
496
+ i=0
497
+ value.each {|v|
498
+ res=NiceHash.validate([v, select_hash_key], values[key][i], only_patterns: only_patterns)
499
+ if res.size>0
500
+ results[key]=Array.new() if !results.keys.include?(key)
501
+ results[key][i]=res
502
+ end
503
+ i+=1
504
+ }
505
+
506
+ end
507
+ unless array_pattern or only_patterns or results.include?(key) or complex_data
508
+ results[key]=false unless value==values[key]
509
+ end
510
+
511
+ else
512
+ unless only_patterns
513
+ results[key]=false unless value==values[key]
514
+ end
515
+ end
516
+
517
+ if same_values.include?(key)
518
+ same_values[key].each {|k|
519
+ if values.keys.include?(k)
520
+ if values[key]!=values[k]
521
+ results[k]="Not equal to #{key}"
522
+ end
523
+ end
524
+ }
525
+ end
526
+
527
+ end
528
+ }
529
+
530
+ end
531
+
532
+ return results
533
+ end
534
+
535
+ ###########################################################################
536
+ # Change only one value at a time and return an Array of Hashes
537
+ # 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.
538
+ # 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
539
+ # input:
540
+ # patterns_hash:
541
+ # (Hash) Hash where we have defined the patterns to follow.
542
+ # (Array) In case of array supplied, the pair: [pattern_hash, select_hash_key]. select_hash_key will filter the hash by that key
543
+ # values_hash: (Hash) Hash of values to use to modify the values generated on patterns_hash
544
+ # output: (Array of Hashes)
545
+ # example:
546
+ # wrong_min_length_hash = my_hash.generate(:correct, errors: :min_length)
547
+ # array_of_hashes = NiceHash.change_one_by_one([my_hash, :correct], wrong_min_length_hash)
548
+ # array_of_hashes.each {|hash_with_one_wrong_field|
549
+ # #Here your code to send through http the JSON data stored in hash_with_one_wrong_field
550
+ # #if you want to know which field is the one that is wrong:
551
+ # res = my_hash.validate(:correct, hash_with_one_wrong_field)
552
+ # }
553
+ ###########################################################################
554
+ def NiceHash.change_one_by_one(patterns_hash, values_hash)
555
+ if patterns_hash.kind_of?(Array)
556
+ select_key=patterns_hash[1]
557
+ pattern_hash=patterns_hash[0]
558
+ else
559
+ pattern_hash=patterns_hash
560
+ select_key=[]
561
+ end
562
+ array=Array.new
563
+ good_values=NiceHash.generate(pattern_hash, select_key)
564
+ select_keys=pattern_hash.pattern_fields(select_key)+pattern_hash.select_fields(select_key)
565
+ select_keys.each {|field|
566
+ new_hash=Marshal.load(Marshal.dump(good_values))
567
+ # to deal with the case same values... like in pwd1, pwd2, pwd3
568
+ if field[-1].kind_of?(Array)
569
+ last_to_set=field[-1]
570
+ else
571
+ last_to_set=[field[-1]]
572
+ end
573
+ last_to_set.each {|f|
574
+ keys=field[0..-2]<<f
575
+ new_hash.bury(keys, values_hash.dig(*keys))
576
+ }
577
+ array<<new_hash
578
+ }
579
+ return array
580
+ end
581
+
582
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nice_hash
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mario Ruiz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-05-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: string_pattern
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.1.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.1.0
33
+ description: 'You can easily generates all the hashes you want following the criteria
34
+ you specify. Many other features coming to Hash class like the methods ''bury''
35
+ or select_key, access the keys like methods: my_hash.my_key.other_key. You will
36
+ be able to generate thousands of different hashes just declaring one and test easily
37
+ APIs based on JSON for example.'
38
+ email: marioruizs@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.md
44
+ files:
45
+ - ".yardopts"
46
+ - LICENSE
47
+ - README.md
48
+ - lib/nice/hash/add_to_ruby.rb
49
+ - lib/nice_hash.rb
50
+ homepage: https://github.com/MarioRuiz/nice_hash
51
+ licenses:
52
+ - MIT
53
+ metadata: {}
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project:
70
+ rubygems_version: 2.7.6
71
+ signing_key:
72
+ specification_version: 4
73
+ summary: NiceHash creates hashes following certain patterns so your testing will be
74
+ much easier.
75
+ test_files: []