nice_hash 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []