nice_hash 1.18.7 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +100 -26
- data/lib/nice/hash/add_to_ruby.rb +45 -0
- data/lib/nice/hash/deep_clone.rb +1 -2
- data/lib/nice/hash/delete_nested.rb +9 -4
- data/lib/nice/hash/diff.rb +55 -0
- data/lib/nice/hash/flatten_keys.rb +56 -0
- data/lib/nice/hash/generate.rb +31 -12
- data/lib/nice/hash/set_nested.rb +11 -19
- data/lib/nice/hash/validate.rb +7 -5
- data/lib/nice_hash.rb +2 -0
- metadata +10 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7eae7fae66c4ee14c40481157a8cd6e90ec43781b092779a3344c36a7d0d6308
|
|
4
|
+
data.tar.gz: f3071e0977d3e7e0f0e7ced9699f4823535c1daaa880cbfd7d5693d8329e9513
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 72ced814e688ca65212c8812969947ce77f0496c2e7dbc12e2ab9ef9c396db77da473e5c079788206c6fcc24e05d92b1186c85bfe986c634e75e3b7894208b5a
|
|
7
|
+
data.tar.gz: bce43cdcaa33a6e50a06a364737e3a723156e052b34ba3423574dc4f296743f47c7b089723f72ba2ad617ece70f3ec129617dcf500fc6c5d5cddd8cf8f7bba27
|
data/README.md
CHANGED
|
@@ -22,31 +22,37 @@ To generate the strings following a pattern take a look at the documentation for
|
|
|
22
22
|
To use nice_hash on Http connections take a look at nice_http gem: https://github.com/MarioRuiz/nice_http
|
|
23
23
|
|
|
24
24
|
## Table of contents
|
|
25
|
-
- [
|
|
26
|
-
- [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
- [
|
|
49
|
-
- [
|
|
25
|
+
- [NiceHash](#nicehash)
|
|
26
|
+
- [Table of contents](#table-of-contents)
|
|
27
|
+
- [Installation](#installation)
|
|
28
|
+
- [Configuration](#configuration)
|
|
29
|
+
- [Usage](#usage)
|
|
30
|
+
- [How to access the different keys](#how-to-access-the-different-keys)
|
|
31
|
+
- [Change all values on the keys we specified](#change-all-values-on-the-keys-we-specified)
|
|
32
|
+
- [Filtering / Selecting an specific key on the hash and subhashes](#filtering--selecting-an-specific-key-on-the-hash-and-subhashes)
|
|
33
|
+
- [How to generate the hash with the criteria we want](#how-to-generate-the-hash-with-the-criteria-we-want)
|
|
34
|
+
- [How to generate the hash with wrong values for the string patterns specified on the hash](#how-to-generate-the-hash-with-wrong-values-for-the-string-patterns-specified-on-the-hash)
|
|
35
|
+
- [Return the select\_fields or the pattern\_fields](#return-the-select_fields-or-the-pattern_fields)
|
|
36
|
+
- [dig and bury Hash methods](#dig-and-bury-hash-methods)
|
|
37
|
+
- [Validating hashes](#validating-hashes)
|
|
38
|
+
- [Change only one value at a time and return an Array of Hashes](#change-only-one-value-at-a-time-and-return-an-array-of-hashes)
|
|
39
|
+
- [Adding other values on run time when calling `generate` method](#adding-other-values-on-run-time-when-calling-generate-method)
|
|
40
|
+
- [Accessing other values of the hash on run time](#accessing-other-values-of-the-hash-on-run-time)
|
|
41
|
+
- [Compare the structure of a replica with the supplied structure](#compare-the-structure-of-a-replica-with-the-supplied-structure)
|
|
42
|
+
- [Other useful methods](#other-useful-methods)
|
|
43
|
+
- [Hash diff](#hash-diff)
|
|
44
|
+
- [Flatten / unflatten keys](#flatten--unflatten-keys)
|
|
45
|
+
- [Time stamp](#time-stamp)
|
|
46
|
+
- [Random dates](#random-dates)
|
|
47
|
+
- [Deep copy of a hash](#deep-copy-of-a-hash)
|
|
48
|
+
- [Nested deletion](#nested-deletion)
|
|
49
|
+
- [Deep merge of two hashes](#deep-merge-of-two-hashes)
|
|
50
|
+
- [Boolean class](#boolean-class)
|
|
51
|
+
- [in?(array)](#inarray)
|
|
52
|
+
- [Other tools integration](#other-tools-integration)
|
|
53
|
+
- [Tabulo](#tabulo)
|
|
54
|
+
- [Contributing](#contributing)
|
|
55
|
+
- [License](#license)
|
|
50
56
|
|
|
51
57
|
## Installation
|
|
52
58
|
|
|
@@ -64,9 +70,34 @@ Or install it yourself as:
|
|
|
64
70
|
|
|
65
71
|
$ gem install nice_hash
|
|
66
72
|
|
|
73
|
+
## Configuration
|
|
74
|
+
|
|
75
|
+
Set these constants **before** `require 'nice_hash'` if you need to change default behavior:
|
|
76
|
+
|
|
77
|
+
- **`SP_ADD_TO_RUBY`** (default: `true`): When `true`, the gem adds methods to core classes (`Hash`, `Array`, `String`, `Object`, `Date`, `Time`, etc.). Set to `false` to avoid patching core classes and use only `NiceHash` class methods.
|
|
78
|
+
- **`SP_COMPARE_NUMBERS_AS_STRINGS`** (default: `true`): When `true`, `String#==` is overridden so that strings are compared with numbers as strings (e.g. `'300' == 300` and `'' == nil`). Set to `false` if this causes issues with other gems (e.g. some versions of `net/ldap`).
|
|
79
|
+
|
|
80
|
+
When using **string_pattern** 2.4+, you can also set **`StringPattern.logger`** (e.g. `Logger.new($stderr)`) to redirect generation/validation messages, and **`StringPattern.raise_on_error = true`** to raise on invalid patterns or impossible generation instead of returning empty strings.
|
|
81
|
+
|
|
82
|
+
Example:
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
SP_COMPARE_NUMBERS_AS_STRINGS = false
|
|
86
|
+
require 'nice_hash'
|
|
87
|
+
```
|
|
88
|
+
|
|
67
89
|
## Usage
|
|
68
90
|
|
|
69
|
-
Remember!! To generate the strings following a pattern take a look at the documentation for string_pattern gem: https://github.com/MarioRuiz/string_pattern. You can also generate Spanish or English words. We added support for generating strings from regular expressions but it is only working for the ´generate´ method, use it with caution since it is still on an early stage of development.
|
|
91
|
+
Remember!! To generate the strings following a pattern take a look at the documentation for string_pattern gem: https://github.com/MarioRuiz/string_pattern. You can also generate Spanish or English words. We added support for generating strings from regular expressions but it is only working for the ´generate´ method, use it with caution since it is still on an early stage of development.
|
|
92
|
+
|
|
93
|
+
For **UUID v4** you can use the shorthand `:uuid` (requires string_pattern 2.4+):
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
my_hash = { id: :uuid, key: "Wsdf88888", doomId: :"10:N" }
|
|
97
|
+
# id will be like "550e8400-e29b-41d4-a716-446655440000"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Or use a Regular expression for custom formats:
|
|
70
101
|
|
|
71
102
|
```ruby
|
|
72
103
|
my_hash = {
|
|
@@ -371,6 +402,23 @@ new_hash = my_hash.generate(:correct)
|
|
|
371
402
|
new_hash = my_hash.select_key(:correct).generate
|
|
372
403
|
```
|
|
373
404
|
|
|
405
|
+
**Reproducible generation (seed)**
|
|
406
|
+
With **string_pattern** 2.4+, pass `seed:` to get the same hash every time (useful for tests):
|
|
407
|
+
|
|
408
|
+
```ruby
|
|
409
|
+
new_hash = my_hash.generate(:correct, seed: 42)
|
|
410
|
+
# Same result every time for the same seed
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
**Generate n hashes at once**
|
|
414
|
+
Use `generate_n` (alias `gen_n`) to build several different hashes in one call (e.g. for bulk or boundary tests):
|
|
415
|
+
|
|
416
|
+
```ruby
|
|
417
|
+
hashes = NiceHash.generate_n(my_hash, 5, :correct)
|
|
418
|
+
hashes = my_hash.generate_n(5, :correct) # or my_hash.gen_n(5, :correct)
|
|
419
|
+
# With seed: hashes = my_hash.generate_n(5, :correct, seed: 123)
|
|
420
|
+
# => array of 5 hashes
|
|
421
|
+
```
|
|
374
422
|
|
|
375
423
|
In case of filtering by :correct new_hash would have a value like this for example:
|
|
376
424
|
|
|
@@ -838,9 +886,35 @@ Valid patterns:
|
|
|
838
886
|
- 10.. (from 10 to infinite) Only from Ruby 2.6
|
|
839
887
|
- DateTime: it will verify if the value is following Time stamp string '2019-06-20T12:01:09.971Z' or if the object is a Time, Date or DateTime class
|
|
840
888
|
- selectors, one of the values. Example: "uno|dos|tres"
|
|
889
|
+
- **:uuid** (string_pattern 2.4+): UUID v4 format
|
|
841
890
|
|
|
842
891
|
### Other useful methods
|
|
843
892
|
|
|
893
|
+
#### Hash diff
|
|
894
|
+
Compare two hashes and get differences with dot-notation paths (useful for API or test assertions):
|
|
895
|
+
|
|
896
|
+
```ruby
|
|
897
|
+
expected = { user: { address: { city: "Madrid" } } }
|
|
898
|
+
actual = { user: { address: { city: "London" } } }
|
|
899
|
+
NiceHash.diff(expected, actual)
|
|
900
|
+
#=> { "user.address.city" => { expected: "Madrid", got: "London" } }
|
|
901
|
+
|
|
902
|
+
# Or on a hash instance:
|
|
903
|
+
expected.diff(actual)
|
|
904
|
+
```
|
|
905
|
+
|
|
906
|
+
#### Flatten / unflatten keys
|
|
907
|
+
Convert between nested hashes and flat hashes with dot-notation keys:
|
|
908
|
+
|
|
909
|
+
```ruby
|
|
910
|
+
h = { user: { address: { city: "Madrid" } } }
|
|
911
|
+
h.flatten_keys
|
|
912
|
+
#=> { "user.address.city" => "Madrid" }
|
|
913
|
+
|
|
914
|
+
{ "user.address.city" => "Madrid" }.unflatten_keys
|
|
915
|
+
#=> { user: { address: { city: "Madrid" } } }
|
|
916
|
+
```
|
|
917
|
+
|
|
844
918
|
#### Time stamp
|
|
845
919
|
In case you need the time stamp, we added the method `stamp` to the `Time` class
|
|
846
920
|
|
|
@@ -166,6 +166,16 @@ class Hash
|
|
|
166
166
|
# my_hash.city="Paris"
|
|
167
167
|
# my_hash.products[1].price.wrong="AAAAA"
|
|
168
168
|
###########################################################################
|
|
169
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
170
|
+
sym = (method_name.to_s[0] == "_" ? method_name.to_s[1..-1].to_sym : method_name)
|
|
171
|
+
return true if key?(sym) || key?(sym.to_s)
|
|
172
|
+
if method_name.to_s[-1] == "="
|
|
173
|
+
setter_key = method_name.to_s.chop
|
|
174
|
+
return true if key?(setter_key) || key?(setter_key.to_sym)
|
|
175
|
+
end
|
|
176
|
+
false
|
|
177
|
+
end
|
|
178
|
+
|
|
169
179
|
def method_missing(m, *arguments, &block)
|
|
170
180
|
m = m[1..-1].to_sym if m[0] == "_"
|
|
171
181
|
if key?(m)
|
|
@@ -231,6 +241,13 @@ class Hash
|
|
|
231
241
|
NiceHash.generate(self, select_hash_key, expected_errors: expected_errors, **synonyms)
|
|
232
242
|
end
|
|
233
243
|
|
|
244
|
+
###########################################################################
|
|
245
|
+
# Generates n different hashes from the same pattern. More info: NiceHash.generate_n
|
|
246
|
+
###########################################################################
|
|
247
|
+
def generate_n(n, select_hash_key = nil, expected_errors: [], **synonyms)
|
|
248
|
+
NiceHash.generate_n(self, n, select_hash_key, expected_errors: expected_errors, **synonyms)
|
|
249
|
+
end
|
|
250
|
+
|
|
234
251
|
###########################################################################
|
|
235
252
|
# Validates a given values_hash_to_validate with string patterns and select fields
|
|
236
253
|
# More info: NiceHash.validate
|
|
@@ -298,6 +315,28 @@ class Hash
|
|
|
298
315
|
NiceHash.nice_filter(self, keys)
|
|
299
316
|
end
|
|
300
317
|
|
|
318
|
+
###########################################################################
|
|
319
|
+
# Compares with another hash and returns differences with dot-notation paths.
|
|
320
|
+
# More info: NiceHash.diff
|
|
321
|
+
###########################################################################
|
|
322
|
+
def diff(other)
|
|
323
|
+
NiceHash.diff(self, other)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
###########################################################################
|
|
327
|
+
# Flattens the hash to dot-notation keys. More info: NiceHash.flatten_keys
|
|
328
|
+
###########################################################################
|
|
329
|
+
def flatten_keys
|
|
330
|
+
NiceHash.flatten_keys(self)
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
###########################################################################
|
|
334
|
+
# Unflattens a hash with dot-notation keys into nested hash. More info: NiceHash.unflatten_keys
|
|
335
|
+
###########################################################################
|
|
336
|
+
def unflatten_keys
|
|
337
|
+
NiceHash.unflatten_keys(self)
|
|
338
|
+
end
|
|
339
|
+
|
|
301
340
|
###########################################################################
|
|
302
341
|
# Merging multi-dimensional hashes
|
|
303
342
|
###########################################################################
|
|
@@ -322,6 +361,7 @@ class Hash
|
|
|
322
361
|
end
|
|
323
362
|
|
|
324
363
|
alias gen generate
|
|
364
|
+
alias gen_n generate_n
|
|
325
365
|
alias val validate
|
|
326
366
|
alias patterns pattern_fields
|
|
327
367
|
alias nice_copy deep_copy
|
|
@@ -365,6 +405,11 @@ class Array
|
|
|
365
405
|
# my_array.city
|
|
366
406
|
# my_array._name
|
|
367
407
|
###########################################################################
|
|
408
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
409
|
+
sym = (method_name.to_s[0] == "_" ? method_name.to_s[1..-1].to_sym : method_name)
|
|
410
|
+
any? { |elem| elem.is_a?(Hash) && (elem.key?(sym) || elem.key?(sym.to_s)) }
|
|
411
|
+
end
|
|
412
|
+
|
|
368
413
|
def method_missing(m, *arguments, &block)
|
|
369
414
|
m = m[1..-1].to_sym if m[0] == "_"
|
|
370
415
|
array = []
|
data/lib/nice/hash/deep_clone.rb
CHANGED
|
@@ -21,6 +21,7 @@ class NiceHash
|
|
|
21
21
|
# #>{:user=>{:address=>{:city=>"Madrid", :country=>"Spain"}, :name=>"Peter", :age=>33}, :customer=>true}
|
|
22
22
|
##################################################
|
|
23
23
|
def self.deep_clone(obj)
|
|
24
|
+
return obj.clone unless obj.is_a?(Array) || obj.is_a?(Hash)
|
|
24
25
|
obj.clone.tap do |new_obj|
|
|
25
26
|
if new_obj.is_a?(Array)
|
|
26
27
|
new_obj.each_with_index do |val, i|
|
|
@@ -30,8 +31,6 @@ class NiceHash
|
|
|
30
31
|
new_obj.each do |key, val|
|
|
31
32
|
new_obj[key] = deep_clone(val)
|
|
32
33
|
end
|
|
33
|
-
else
|
|
34
|
-
new_obj = obj.clone
|
|
35
34
|
end
|
|
36
35
|
end
|
|
37
36
|
end
|
|
@@ -27,11 +27,16 @@ class NiceHash
|
|
|
27
27
|
if keys.size == 1
|
|
28
28
|
hash.delete(nested_key.to_sym)
|
|
29
29
|
else
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
parent = hash
|
|
31
|
+
keys[0..-2].each do |k|
|
|
32
|
+
sym = k.to_sym
|
|
33
|
+
return hash unless parent.is_a?(Hash) && parent.key?(sym)
|
|
34
|
+
parent = parent[sym]
|
|
35
|
+
end
|
|
36
|
+
parent.delete(keys[-1].to_sym) if parent.is_a?(Hash)
|
|
32
37
|
end
|
|
33
38
|
return hash
|
|
34
39
|
end
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
end
|
|
41
|
+
|
|
42
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class NiceHash
|
|
4
|
+
##################################################
|
|
5
|
+
# Compares two hashes and returns differences with dot-notation paths.
|
|
6
|
+
#
|
|
7
|
+
# @param expected [Hash, Array] Expected structure (hash or array of hashes)
|
|
8
|
+
# @param actual [Hash, Array] Actual structure to compare
|
|
9
|
+
# @param prefix [String] Internal: current path prefix for recursion
|
|
10
|
+
#
|
|
11
|
+
# @return [Hash] Path => { expected: value, got: value } for each difference
|
|
12
|
+
#
|
|
13
|
+
# @example
|
|
14
|
+
# expected = { user: { address: { city: "Madrid" } } }
|
|
15
|
+
# actual = { user: { address: { city: "London" } } }
|
|
16
|
+
# NiceHash.diff(expected, actual)
|
|
17
|
+
# #=> { "user.address.city" => { expected: "Madrid", got: "London" } }
|
|
18
|
+
##################################################
|
|
19
|
+
def self.diff(expected, actual, prefix = "")
|
|
20
|
+
result = {}
|
|
21
|
+
exp_keys = expected.is_a?(Hash) ? expected.keys : (expected.is_a?(Array) ? (0...expected.size) : nil)
|
|
22
|
+
act_keys = actual.is_a?(Hash) ? actual.keys : (actual.is_a?(Array) ? (0...actual.size) : nil)
|
|
23
|
+
|
|
24
|
+
if expected.is_a?(Hash) && actual.is_a?(Hash)
|
|
25
|
+
all_keys = (expected.keys + actual.keys).uniq
|
|
26
|
+
all_keys.each do |k|
|
|
27
|
+
path = prefix.empty? ? k.to_s : "#{prefix}.#{k}"
|
|
28
|
+
exp_v = expected[k]
|
|
29
|
+
act_v = actual[k]
|
|
30
|
+
if !expected.key?(k)
|
|
31
|
+
result[path] = { expected: nil, got: act_v }
|
|
32
|
+
elsif !actual.key?(k)
|
|
33
|
+
result[path] = { expected: exp_v, got: nil }
|
|
34
|
+
elsif exp_v.is_a?(Hash) && act_v.is_a?(Hash)
|
|
35
|
+
result.merge!(diff(exp_v, act_v, path))
|
|
36
|
+
elsif exp_v.is_a?(Array) && act_v.is_a?(Array)
|
|
37
|
+
max_len = [exp_v.size, act_v.size].max
|
|
38
|
+
max_len.times do |i|
|
|
39
|
+
result.merge!(diff(exp_v[i], act_v[i], "#{path}[#{i}]"))
|
|
40
|
+
end
|
|
41
|
+
elsif exp_v != act_v
|
|
42
|
+
result[path] = { expected: exp_v, got: act_v }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
elsif expected.is_a?(Array) && actual.is_a?(Array)
|
|
46
|
+
max_len = [expected.size, actual.size].max
|
|
47
|
+
max_len.times do |i|
|
|
48
|
+
result.merge!(diff(expected[i], actual[i], prefix.empty? ? "[#{i}]" : "#{prefix}[#{i}]"))
|
|
49
|
+
end
|
|
50
|
+
elsif expected != actual
|
|
51
|
+
result[prefix] = { expected: expected, got: actual } unless prefix.empty?
|
|
52
|
+
end
|
|
53
|
+
result
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class NiceHash
|
|
4
|
+
##################################################
|
|
5
|
+
# Flattens a nested hash so keys become dot-notation strings.
|
|
6
|
+
#
|
|
7
|
+
# @param hash [Hash] The hash to flatten
|
|
8
|
+
# @param prefix [String] Internal: current path prefix for recursion
|
|
9
|
+
#
|
|
10
|
+
# @return [Hash] Flat hash with string keys like "user.address.city"
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# NiceHash.flatten_keys({ user: { address: { city: "Madrid" } } })
|
|
14
|
+
# #=> { "user.address.city" => "Madrid" }
|
|
15
|
+
##################################################
|
|
16
|
+
def self.flatten_keys(hash, prefix = "")
|
|
17
|
+
return {} unless hash.is_a?(Hash)
|
|
18
|
+
result = {}
|
|
19
|
+
hash.each do |k, v|
|
|
20
|
+
path = prefix.empty? ? k.to_s : "#{prefix}.#{k}"
|
|
21
|
+
if v.is_a?(Hash)
|
|
22
|
+
result.merge!(flatten_keys(v, path))
|
|
23
|
+
else
|
|
24
|
+
result[path] = v
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
result
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
##################################################
|
|
31
|
+
# Unflattens a hash with dot-notation keys into a nested hash.
|
|
32
|
+
#
|
|
33
|
+
# @param hash [Hash] Flat hash with string keys like "user.address.city"
|
|
34
|
+
#
|
|
35
|
+
# @return [Hash] Nested hash
|
|
36
|
+
#
|
|
37
|
+
# @example
|
|
38
|
+
# NiceHash.unflatten_keys({ "user.address.city" => "Madrid" })
|
|
39
|
+
# #=> { user: { address: { city: "Madrid" } } }
|
|
40
|
+
##################################################
|
|
41
|
+
def self.unflatten_keys(hash)
|
|
42
|
+
return {} unless hash.is_a?(Hash)
|
|
43
|
+
result = {}
|
|
44
|
+
hash.each do |key_str, value|
|
|
45
|
+
keys = key_str.to_s.split(".")
|
|
46
|
+
keys = keys.map { |k| k.match?(/\A\d+\z/) ? k.to_i : k.to_sym }
|
|
47
|
+
current = result
|
|
48
|
+
keys[0..-2].each do |k|
|
|
49
|
+
current[k] = {} unless current[k].is_a?(Hash)
|
|
50
|
+
current = current[k]
|
|
51
|
+
end
|
|
52
|
+
current[keys[-1]] = value
|
|
53
|
+
end
|
|
54
|
+
result
|
|
55
|
+
end
|
|
56
|
+
end
|
data/lib/nice/hash/generate.rb
CHANGED
|
@@ -58,6 +58,7 @@ class NiceHash
|
|
|
58
58
|
if expected_errors.kind_of?(Symbol)
|
|
59
59
|
expected_errors = [expected_errors]
|
|
60
60
|
end
|
|
61
|
+
sp_opts = { expected_errors: expected_errors }.merge(synonyms)
|
|
61
62
|
|
|
62
63
|
if pattern_hash.kind_of?(Hash) and pattern_hash.size > 0
|
|
63
64
|
pattern_hash.each { |key, value|
|
|
@@ -70,12 +71,14 @@ class NiceHash
|
|
|
70
71
|
if value.keys.include?(select_hash_key)
|
|
71
72
|
value = value[select_hash_key]
|
|
72
73
|
else
|
|
73
|
-
value = NiceHash.generate(value, select_hash_key, expected_errors: expected_errors)
|
|
74
|
+
value = NiceHash.generate(value, select_hash_key, expected_errors: expected_errors, **synonyms)
|
|
74
75
|
end
|
|
75
76
|
end
|
|
76
|
-
if value
|
|
77
|
+
if value == :uuid
|
|
78
|
+
hashv[key] = expected_errors.empty? ? StringPattern.uuid : (StringPattern.uuid[0..-2] + "X")
|
|
79
|
+
elsif value.kind_of?(String) or value.kind_of?(Symbol)
|
|
77
80
|
if ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^!?\d+-?\d*:.+/).size > 0
|
|
78
|
-
hashv[key] = StringPattern.generate(value,
|
|
81
|
+
hashv[key] = StringPattern.generate(value, **sp_opts)
|
|
79
82
|
elsif ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size > 0
|
|
80
83
|
if expected_errors.include?(:min_length) or (expected_errors.include?(:length) and rand.round == 0)
|
|
81
84
|
min = value.to_s.split("|").min { |a, b| a.size <=> b.size }
|
|
@@ -94,10 +97,11 @@ class NiceHash
|
|
|
94
97
|
v = value.to_s.split("|").sample
|
|
95
98
|
end
|
|
96
99
|
unless expected_errors.include?(:string_set_not_allowed)
|
|
97
|
-
v = StringPattern.generate(:"#{v.size}:[#{value.to_s.split("|").join.split(//).uniq.join}]")
|
|
100
|
+
v = StringPattern.generate(:"#{v.size}:[#{value.to_s.split("|").join.split(//).uniq.join}]", **sp_opts)
|
|
98
101
|
hashv[key] = v unless value.to_s.split("|").include?(v)
|
|
99
102
|
end
|
|
100
103
|
unless hashv.keys.include?(key)
|
|
104
|
+
# Need a valid 1-char not in the allowed set (do not pass expected_errors)
|
|
101
105
|
one_wrong_letter = StringPattern.generate(:"1:LN$[%#{value.to_s.split("|").join.split(//).uniq.join}%]")
|
|
102
106
|
v[rand(v.size)] = one_wrong_letter
|
|
103
107
|
hashv[key] = v unless value.to_s.split("|").include?(v)
|
|
@@ -115,15 +119,15 @@ class NiceHash
|
|
|
115
119
|
v = value[0]
|
|
116
120
|
if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
|
|
117
121
|
hashv[key] = []
|
|
118
|
-
(rand(5)+1).times do
|
|
119
|
-
hashv[key]<<StringPattern.generate(v,
|
|
122
|
+
(rand(5)+1).times do
|
|
123
|
+
hashv[key]<<StringPattern.generate(v, **sp_opts)
|
|
120
124
|
end
|
|
121
125
|
array_pattern = true
|
|
122
126
|
end
|
|
123
127
|
else
|
|
124
128
|
value.each { |v|
|
|
125
129
|
if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
|
|
126
|
-
hashv[key] = StringPattern.generate(value,
|
|
130
|
+
hashv[key] = StringPattern.generate(value, **sp_opts)
|
|
127
131
|
array_pattern = true
|
|
128
132
|
break
|
|
129
133
|
end
|
|
@@ -133,9 +137,9 @@ class NiceHash
|
|
|
133
137
|
value_ret = Array.new
|
|
134
138
|
value.each { |v|
|
|
135
139
|
if v.is_a?(Hash)
|
|
136
|
-
ret = NiceHash.generate(v, select_hash_key, expected_errors: expected_errors)
|
|
140
|
+
ret = NiceHash.generate(v, select_hash_key, expected_errors: expected_errors, **synonyms)
|
|
137
141
|
else
|
|
138
|
-
ret = NiceHash.generate({ doit: v }, select_hash_key, expected_errors: expected_errors)
|
|
142
|
+
ret = NiceHash.generate({ doit: v }, select_hash_key, expected_errors: expected_errors, **synonyms)
|
|
139
143
|
ret = ret[:doit] if ret.is_a?(Hash) and ret.key?(:doit)
|
|
140
144
|
end
|
|
141
145
|
ret = v if ret.kind_of?(Hash) and ret.size == 0
|
|
@@ -208,7 +212,7 @@ class NiceHash
|
|
|
208
212
|
elsif value.kind_of?(Proc)
|
|
209
213
|
hashv[key] = value.call
|
|
210
214
|
elsif value.kind_of?(Regexp)
|
|
211
|
-
hashv[key] = value.generate(
|
|
215
|
+
hashv[key] = value.generate(**sp_opts)
|
|
212
216
|
else
|
|
213
217
|
hashv[key] = value
|
|
214
218
|
end
|
|
@@ -225,5 +229,20 @@ class NiceHash
|
|
|
225
229
|
|
|
226
230
|
return hashv
|
|
227
231
|
end
|
|
228
|
-
|
|
229
|
-
|
|
232
|
+
|
|
233
|
+
###########################################################################
|
|
234
|
+
# Generates n different hashes from the same pattern (useful for bulk or boundary tests).
|
|
235
|
+
# input:
|
|
236
|
+
# pattern_hash: (Hash) Hash we want to use to generate the values
|
|
237
|
+
# n: (Integer) Number of hashes to generate
|
|
238
|
+
# select_hash_key: (key value) (optional) The key we want to select on the subhashes
|
|
239
|
+
# expected_errors: (Array) (optional) (alias: errors) Same as in generate
|
|
240
|
+
# output: (Array of Hash)
|
|
241
|
+
# examples:
|
|
242
|
+
# hashes = NiceHash.generate_n(my_hash, 5, :correct)
|
|
243
|
+
# hashes = my_hash.generate_n(5, :correct)
|
|
244
|
+
###########################################################################
|
|
245
|
+
def NiceHash.generate_n(pattern_hash, n, select_hash_key = nil, expected_errors: [], **synonyms)
|
|
246
|
+
n.times.map { NiceHash.generate(pattern_hash, select_hash_key, expected_errors: expected_errors, **synonyms) }
|
|
247
|
+
end
|
|
248
|
+
end
|
data/lib/nice/hash/set_nested.rb
CHANGED
|
@@ -28,27 +28,19 @@ class NiceHash
|
|
|
28
28
|
if keys.size == 1
|
|
29
29
|
hash[nested_key.to_sym] = value unless only_if_exist and !hash.key?(nested_key.to_sym)
|
|
30
30
|
else
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
exist = false
|
|
37
|
-
break
|
|
38
|
-
end
|
|
39
|
-
ht = ht[k.to_sym]
|
|
40
|
-
end
|
|
31
|
+
parent = hash
|
|
32
|
+
keys[0..-2].each do |k|
|
|
33
|
+
sym = k.to_sym
|
|
34
|
+
return hash unless parent.is_a?(Hash) && parent.key?(sym)
|
|
35
|
+
parent = parent[sym]
|
|
41
36
|
end
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
else
|
|
46
|
-
#todo: consider other kind of objects apart of strings
|
|
47
|
-
eval("hash.#{nested_key}=#{value}")
|
|
48
|
-
end
|
|
37
|
+
return hash unless parent.is_a?(Hash)
|
|
38
|
+
if only_if_exist
|
|
39
|
+
return hash unless parent.key?(keys[-1].to_sym)
|
|
49
40
|
end
|
|
41
|
+
parent[keys[-1].to_sym] = value
|
|
50
42
|
end
|
|
51
43
|
return hash
|
|
52
44
|
end
|
|
53
|
-
|
|
54
|
-
end
|
|
45
|
+
|
|
46
|
+
end
|
data/lib/nice/hash/validate.rb
CHANGED
|
@@ -59,7 +59,7 @@ class NiceHash
|
|
|
59
59
|
end
|
|
60
60
|
values = values_hash_to_validate
|
|
61
61
|
if pattern_hash.keys.size == get_all_keys(pattern_hash).size and values.keys.size != get_all_keys(values) and
|
|
62
|
-
pattern_hash.keys.size == pattern_hash.keys.flatten.size # dont't set_values for the case of same_value
|
|
62
|
+
pattern_hash.keys.size == pattern_hash.keys.flatten.size # dont't set_values for the case of same_value
|
|
63
63
|
# all patterns on patterns_hash are described on first level, so no same structure than values
|
|
64
64
|
pattern_hash = values.set_values(pattern_hash)
|
|
65
65
|
end
|
|
@@ -83,7 +83,9 @@ class NiceHash
|
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
if values.keys.include?(key)
|
|
86
|
-
if value
|
|
86
|
+
if value == :uuid
|
|
87
|
+
results[key] = false unless StringPattern.valid_uuid?(values[key].to_s)
|
|
88
|
+
elsif value.kind_of?(String) or value.kind_of?(Symbol)
|
|
87
89
|
if ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^!?\d+-?\d*:.+/).size > 0
|
|
88
90
|
res = StringPattern.validate(pattern: value, text: values[key])
|
|
89
91
|
results[key] = res if res.size > 0
|
|
@@ -133,7 +135,7 @@ class NiceHash
|
|
|
133
135
|
results[key] << res
|
|
134
136
|
end
|
|
135
137
|
if results[key].flatten.size == 0
|
|
136
|
-
results.delete(key)
|
|
138
|
+
results.delete(key)
|
|
137
139
|
end
|
|
138
140
|
else
|
|
139
141
|
res = StringPattern.validate(pattern: value, text: values[key])
|
|
@@ -213,5 +215,5 @@ class NiceHash
|
|
|
213
215
|
return results
|
|
214
216
|
end
|
|
215
217
|
|
|
216
|
-
|
|
217
|
-
end
|
|
218
|
+
|
|
219
|
+
end
|
data/lib/nice_hash.rb
CHANGED
|
@@ -5,6 +5,8 @@ require_relative "nice/hash/add_to_ruby" if SP_ADD_TO_RUBY
|
|
|
5
5
|
require_relative "nice/hash/change_one_by_one"
|
|
6
6
|
require_relative "nice/hash/compare_structure"
|
|
7
7
|
require_relative "nice/hash/delete_nested"
|
|
8
|
+
require_relative "nice/hash/diff"
|
|
9
|
+
require_relative "nice/hash/flatten_keys"
|
|
8
10
|
require_relative "nice/hash/generate"
|
|
9
11
|
require_relative "nice/hash/get_all_keys"
|
|
10
12
|
require_relative "nice/hash/get_values"
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: nice_hash
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.19.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mario Ruiz
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: string_pattern
|
|
@@ -16,20 +15,20 @@ dependencies:
|
|
|
16
15
|
requirements:
|
|
17
16
|
- - "~>"
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '2.
|
|
18
|
+
version: '2.4'
|
|
20
19
|
- - ">="
|
|
21
20
|
- !ruby/object:Gem::Version
|
|
22
|
-
version: 2.
|
|
21
|
+
version: 2.4.0
|
|
23
22
|
type: :runtime
|
|
24
23
|
prerelease: false
|
|
25
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
26
25
|
requirements:
|
|
27
26
|
- - "~>"
|
|
28
27
|
- !ruby/object:Gem::Version
|
|
29
|
-
version: '2.
|
|
28
|
+
version: '2.4'
|
|
30
29
|
- - ">="
|
|
31
30
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 2.
|
|
31
|
+
version: 2.4.0
|
|
33
32
|
- !ruby/object:Gem::Dependency
|
|
34
33
|
name: rspec
|
|
35
34
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -71,6 +70,8 @@ files:
|
|
|
71
70
|
- lib/nice/hash/compare_structure.rb
|
|
72
71
|
- lib/nice/hash/deep_clone.rb
|
|
73
72
|
- lib/nice/hash/delete_nested.rb
|
|
73
|
+
- lib/nice/hash/diff.rb
|
|
74
|
+
- lib/nice/hash/flatten_keys.rb
|
|
74
75
|
- lib/nice/hash/generate.rb
|
|
75
76
|
- lib/nice/hash/get_all_keys.rb
|
|
76
77
|
- lib/nice/hash/get_values.rb
|
|
@@ -95,15 +96,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
95
96
|
requirements:
|
|
96
97
|
- - ">="
|
|
97
98
|
- !ruby/object:Gem::Version
|
|
98
|
-
version: '0'
|
|
99
|
+
version: '3.0'
|
|
99
100
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
101
|
requirements:
|
|
101
102
|
- - ">="
|
|
102
103
|
- !ruby/object:Gem::Version
|
|
103
104
|
version: '0'
|
|
104
105
|
requirements: []
|
|
105
|
-
rubygems_version:
|
|
106
|
-
signing_key:
|
|
106
|
+
rubygems_version: 4.0.6
|
|
107
107
|
specification_version: 4
|
|
108
108
|
summary: NiceHash creates hashes following certain patterns so your testing will be
|
|
109
109
|
much easier. Parse and filter JSON. Perfect to be used in test data factories
|