nice_hash 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
[](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: []
|