nice_hash 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.yardopts +5 -0
- data/LICENSE +21 -0
- data/README.md +515 -0
- data/lib/nice/hash/add_to_ruby.rb +127 -0
- data/lib/nice_hash.rb +582 -0
- metadata +75 -0
checksums.yaml
ADDED
@@ -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
|
data/.yardopts
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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
|
data/lib/nice_hash.rb
ADDED
@@ -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: []
|