string_pattern 2.3.0 → 2.4.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 +70 -5
- data/lib/string/pattern/add_to_ruby.rb +5 -6
- data/lib/string/pattern/analyze.rb +5 -5
- data/lib/string/pattern/email.rb +21 -0
- data/lib/string/pattern/generate.rb +24 -27
- data/lib/string/pattern/validate.rb +3 -16
- data/lib/string_pattern.rb +73 -0
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 47172de723c22b8175a1119aa51c065056ec4eab029cfb989b4fa4c9bc20d845
|
|
4
|
+
data.tar.gz: c9e9996c3f5ec59813b157a9f818c10723fb1b9f95a1ed871ba80219d04bbe6e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 840a84447c523a01e21657fa772c190388a1401e41d254e5340fe9bd081eb0740ba200161c0a29e06dcfa841632c26d51346da53bf2c5a8f93ad3459aa455930
|
|
7
|
+
data.tar.gz: f53b2b1ef110f8e20b95e7e5bafac00067bbc782e2817fa3292cbd4b60492454b171133b80b8808e737606c83dd8f2df59d5d57447bcc5cc225d6239c0edb7e3
|
data/README.md
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
[](https://rubygems.org/gems/string_pattern)
|
|
4
4
|
[](https://github.com/MarioRuiz/string_pattern)
|
|
5
5
|
[](https://coveralls.io/github/MarioRuiz/string_pattern?branch=master)
|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+
|
|
6
11
|
|
|
7
12
|
With this gem, you can easily generate strings supplying a very simple pattern. Even generate random words in English or Spanish.
|
|
8
13
|
Also, you can validate if a text fulfills a specific pattern or even generate a string following a pattern and returning the wrong length, value... for testing your applications. Perfect to be used in test data factories.
|
|
@@ -313,12 +318,9 @@ Examples:
|
|
|
313
318
|
|
|
314
319
|
If you need to validate if a specific text is fulfilling the pattern you can use the validate method.
|
|
315
320
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
Possible output values, empty array (validation without errors detected) or one or more of: :min_length, :max_length, :length, :value, :string_set_not_allowed, :required_data, :excluded_data
|
|
321
|
+
When you supply a single pattern and do **not** supply `expected_errors` or `not_expected_errors`, the method returns an **array of error symbols**: an empty array `[]` when the text is valid, or one or more of `:min_length`, `:max_length`, `:length`, `:value`, `:string_set_not_allowed`, `:required_data`, `:excluded_data` when invalid.
|
|
320
322
|
|
|
321
|
-
|
|
323
|
+
When an array of patterns is supplied, the method returns only `true` or `false`.
|
|
322
324
|
|
|
323
325
|
Examples:
|
|
324
326
|
|
|
@@ -438,6 +440,69 @@ StringPattern.block_list_enabled = true
|
|
|
438
440
|
"2-20:Tn".gen #>AAñ34Ef99éNOP
|
|
439
441
|
```
|
|
440
442
|
|
|
443
|
+
#### StringPattern.analyze
|
|
444
|
+
|
|
445
|
+
To inspect how a pattern is parsed without generating or validating:
|
|
446
|
+
|
|
447
|
+
```ruby
|
|
448
|
+
p = StringPattern.analyze("10-20:LN/x/")
|
|
449
|
+
# => #<Struct min_length=10, max_length=20, symbol_type="LN/x/", required_data=..., string_set=..., unique=false>
|
|
450
|
+
p.min_length # => 10
|
|
451
|
+
p.max_length # => 20
|
|
452
|
+
p.symbol_type # => "LN/x/"
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Useful for debugging or building tools on top of the pattern DSL. Invalid patterns return the pattern string; use `silent: true` to avoid logging.
|
|
456
|
+
|
|
457
|
+
#### Error handling and logging
|
|
458
|
+
|
|
459
|
+
By default, when generation is impossible (e.g. invalid pattern or `dont_repeat` exhausted), `generate` returns an empty string `""` and a message is printed. You can:
|
|
460
|
+
|
|
461
|
+
- Set `StringPattern.logger = Logger.new($stderr)` to send messages to a logger instead of `puts`.
|
|
462
|
+
- Set `StringPattern.raise_on_error = true` to raise `StringPattern::GenerationImpossibleError` or `StringPattern::InvalidPatternError` instead of returning `""`.
|
|
463
|
+
|
|
464
|
+
#### Reproducible generation (seed)
|
|
465
|
+
|
|
466
|
+
Pass `seed:` to get the same string for the same pattern in tests:
|
|
467
|
+
|
|
468
|
+
```ruby
|
|
469
|
+
"10:N".gen(seed: 42) # => same result every time
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
#### Batch generation (sample)
|
|
473
|
+
|
|
474
|
+
Generate up to `n` distinct strings without mutating the global dont_repeat cache:
|
|
475
|
+
|
|
476
|
+
```ruby
|
|
477
|
+
StringPattern.sample("4:N", 10) # => array of 10 distinct 4-digit strings
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
#### Boolean validation (valid?)
|
|
481
|
+
|
|
482
|
+
Check if text matches a pattern without building the full error list:
|
|
483
|
+
|
|
484
|
+
```ruby
|
|
485
|
+
StringPattern.valid?(text: "user@domain.com", pattern: "14-40:@") # => true
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
#### UUID
|
|
489
|
+
|
|
490
|
+
Generate a random UUID v4 or validate one:
|
|
491
|
+
|
|
492
|
+
```ruby
|
|
493
|
+
StringPattern.uuid # => "550e8400-e29b-41d4-a716-446655440000"
|
|
494
|
+
StringPattern.valid_uuid?(some_str) # => true or false
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
#### block_list as Proc
|
|
498
|
+
|
|
499
|
+
You can set `block_list` to a Proc for custom blocking:
|
|
500
|
+
|
|
501
|
+
```ruby
|
|
502
|
+
StringPattern.block_list = ->(s) { s.include?("forbidden") }
|
|
503
|
+
StringPattern.block_list_enabled = true
|
|
504
|
+
```
|
|
505
|
+
|
|
441
506
|
|
|
442
507
|
## Contributing
|
|
443
508
|
|
|
@@ -106,7 +106,7 @@ class Regexp
|
|
|
106
106
|
elsif token == :literal and text.size == 2
|
|
107
107
|
text = text[1]
|
|
108
108
|
else
|
|
109
|
-
|
|
109
|
+
StringPattern.log_message("Report token not controlled: type: #{type}, token: #{token}, text: '#{text}' [#{ts}..#{te}]")
|
|
110
110
|
end
|
|
111
111
|
end
|
|
112
112
|
|
|
@@ -165,7 +165,7 @@ class Regexp
|
|
|
165
165
|
set_negate = false
|
|
166
166
|
else
|
|
167
167
|
pats += "]"
|
|
168
|
-
end
|
|
168
|
+
end
|
|
169
169
|
|
|
170
170
|
end
|
|
171
171
|
elsif type == :group
|
|
@@ -190,7 +190,6 @@ class Regexp
|
|
|
190
190
|
patg << pats
|
|
191
191
|
pats = ""
|
|
192
192
|
elsif patg.empty?
|
|
193
|
-
# for the case the first element was not added to patg and was on pata fex: (a+|b|c)
|
|
194
193
|
patg << pata.pop
|
|
195
194
|
end
|
|
196
195
|
end
|
|
@@ -299,11 +298,11 @@ class Regexp
|
|
|
299
298
|
end
|
|
300
299
|
if pats != ""
|
|
301
300
|
if pata.empty?
|
|
302
|
-
if pats[0] == "[" and pats[-1] == "]"
|
|
301
|
+
if pats[0] == "[" and pats[-1] == "]"
|
|
303
302
|
pata = ["1:#{pats}"]
|
|
304
303
|
end
|
|
305
304
|
else
|
|
306
|
-
pata[-1] += pats[1]
|
|
305
|
+
pata[-1] += pats[1]
|
|
307
306
|
end
|
|
308
307
|
end
|
|
309
308
|
if pata.size == 1 and pata[0].kind_of?(String)
|
|
@@ -325,7 +324,7 @@ module Kernel
|
|
|
325
324
|
if pattern.is_a?(String) || pattern.is_a?(Array) || pattern.is_a?(Symbol) || pattern.is_a?(Regexp)
|
|
326
325
|
StringPattern.generate(pattern, expected_errors: expected_errors, **synonyms)
|
|
327
326
|
else
|
|
328
|
-
|
|
327
|
+
StringPattern.log_message(" Kernel generate method: class not recognized:#{pattern.class}")
|
|
329
328
|
end
|
|
330
329
|
end
|
|
331
330
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
class StringPattern
|
|
2
|
-
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
|
|
2
|
+
# Analyzes a pattern string and returns a Pattern struct.
|
|
3
|
+
# @param pattern [String, Symbol] Pattern in format "length:type" or "min-max:type" (e.g. "10:N", "5-15:L")
|
|
4
|
+
# @param silent [Boolean] If true, invalid patterns do not log a message.
|
|
5
|
+
# @return [Struct, String] Pattern struct with min_length, max_length, symbol_type, required_data, excluded_data, data_provided, string_set, all_characters_set, unique; or the pattern string if invalid.
|
|
6
6
|
def StringPattern.analyze(pattern, silent: false)
|
|
7
7
|
#unless @cache[pattern.to_s].nil?
|
|
8
8
|
# return Pattern.new(@cache[pattern.to_s].min_length.clone, @cache[pattern.to_s].max_length.clone,
|
|
@@ -16,7 +16,7 @@ class StringPattern
|
|
|
16
16
|
min_length, symbol_type = pattern.to_s.scan(/^!?(\d+):(.+)/)[0]
|
|
17
17
|
max_length = min_length
|
|
18
18
|
if min_length.nil?
|
|
19
|
-
|
|
19
|
+
StringPattern.log_message("pattern argument not valid on StringPattern.generate: #{pattern.inspect}") unless silent
|
|
20
20
|
return pattern.to_s
|
|
21
21
|
end
|
|
22
22
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class StringPattern
|
|
4
|
+
# Validates email format using the same rules as pattern type @:
|
|
5
|
+
# - Forbids consecutive/adjacent invalid sequences (.. __ -- etc.)
|
|
6
|
+
# - Local part: [a-z0-9]+([\+\._\-][a-z0-9])*
|
|
7
|
+
# - Domain part: [0-9a-z]+([\.-][a-z0-9])*
|
|
8
|
+
def self.valid_email?(string)
|
|
9
|
+
return false if string.nil? || !string.is_a?(String)
|
|
10
|
+
return false if string.index("@").to_i <= 0
|
|
11
|
+
|
|
12
|
+
wrong = %w(.. __ -- ._ _. .- -. _- -_ @. @_ @- .@ _@ -@ @@)
|
|
13
|
+
return false if Regexp.union(*wrong) === string
|
|
14
|
+
|
|
15
|
+
local = string[0..(string.index("@") - 1)]
|
|
16
|
+
domain = string[(string.index("@") + 1)..-1]
|
|
17
|
+
local_ok = local.scan(/([a-z0-9]+([\+\._\-][a-z0-9]|)*)/i).join == local
|
|
18
|
+
domain_ok = domain.scan(/([0-9a-z]+([\.-][a-z0-9]|)*)/i).join == domain
|
|
19
|
+
local_ok && domain_ok
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -64,6 +64,8 @@ class StringPattern
|
|
|
64
64
|
# the generated string
|
|
65
65
|
###############################################
|
|
66
66
|
def StringPattern.generate(pattern, expected_errors: [], **synonyms)
|
|
67
|
+
seed_given = synonyms.key?(:seed)
|
|
68
|
+
saved_rng = seed_given ? srand(synonyms[:seed]) : nil
|
|
67
69
|
tries = 0
|
|
68
70
|
begin
|
|
69
71
|
good_result = true
|
|
@@ -95,7 +97,7 @@ class StringPattern
|
|
|
95
97
|
string << pat
|
|
96
98
|
end
|
|
97
99
|
else
|
|
98
|
-
|
|
100
|
+
StringPattern.log_message("StringPattern.generate: it seems you supplied wrong array of patterns: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}")
|
|
99
101
|
return ""
|
|
100
102
|
end
|
|
101
103
|
}
|
|
@@ -120,7 +122,7 @@ class StringPattern
|
|
|
120
122
|
}
|
|
121
123
|
unless excluded_data.size == 0
|
|
122
124
|
if (required_chars.flatten & excluded_data.flatten).size > 0
|
|
123
|
-
|
|
125
|
+
StringPattern.log_message("pattern argument not valid on StringPattern.generate, a character cannot be required and excluded at the same time: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}")
|
|
124
126
|
return ""
|
|
125
127
|
end
|
|
126
128
|
end
|
|
@@ -130,7 +132,7 @@ class StringPattern
|
|
|
130
132
|
elsif pattern.kind_of?(Regexp)
|
|
131
133
|
return generate(pattern.to_sp, expected_errors: expected_errors)
|
|
132
134
|
else
|
|
133
|
-
|
|
135
|
+
StringPattern.log_message("pattern argument not valid on StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}")
|
|
134
136
|
return pattern.to_s
|
|
135
137
|
end
|
|
136
138
|
|
|
@@ -169,12 +171,12 @@ class StringPattern
|
|
|
169
171
|
|
|
170
172
|
unless deny_pattern
|
|
171
173
|
if required_data.size == 0 and expected_errors_left.include?(:required_data)
|
|
172
|
-
|
|
174
|
+
StringPattern.log_message("required data not supplied on pattern so it won't be possible to generate a wrong string. StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}")
|
|
173
175
|
return ""
|
|
174
176
|
end
|
|
175
177
|
|
|
176
178
|
if excluded_data.size == 0 and expected_errors_left.include?(:excluded_data)
|
|
177
|
-
|
|
179
|
+
StringPattern.log_message("excluded data not supplied on pattern so it won't be possible to generate a wrong string. StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}")
|
|
178
180
|
return ""
|
|
179
181
|
end
|
|
180
182
|
|
|
@@ -182,7 +184,7 @@ class StringPattern
|
|
|
182
184
|
string_set_not_allowed = all_characters_set - string_set
|
|
183
185
|
|
|
184
186
|
if string_set_not_allowed.size == 0
|
|
185
|
-
|
|
187
|
+
StringPattern.log_message("all characters are allowed so it won't be possible to generate a wrong string. StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}")
|
|
186
188
|
return ""
|
|
187
189
|
end
|
|
188
190
|
end
|
|
@@ -205,7 +207,7 @@ class StringPattern
|
|
|
205
207
|
expected_errors_left.delete(:length)
|
|
206
208
|
expected_errors_left.delete(:min_length)
|
|
207
209
|
else
|
|
208
|
-
|
|
210
|
+
StringPattern.log_message("min_length is 0 so it won't be possible to generate a wrong string smaller than 0 characters. StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}")
|
|
209
211
|
return ""
|
|
210
212
|
end
|
|
211
213
|
elsif expected_errors_left.include?(:max_length) or expected_errors_left.include?(:length)
|
|
@@ -264,7 +266,7 @@ class StringPattern
|
|
|
264
266
|
end
|
|
265
267
|
if ((0...string.length).find_all { |i| string[i, 1] == rd_to_set }).size == 0
|
|
266
268
|
if positions_to_set.size == 0
|
|
267
|
-
|
|
269
|
+
StringPattern.log_message("pattern not valid on StringPattern.generate, not possible to generate a valid string: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}")
|
|
268
270
|
return ""
|
|
269
271
|
else
|
|
270
272
|
k = positions_to_set.sample
|
|
@@ -289,7 +291,7 @@ class StringPattern
|
|
|
289
291
|
string_set_not_allowed = all_characters_set - string_set if string_set_not_allowed.size == 0
|
|
290
292
|
|
|
291
293
|
if string_set_not_allowed.size == 0
|
|
292
|
-
|
|
294
|
+
StringPattern.log_message("Not possible to generate a non valid string on StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}")
|
|
293
295
|
return ""
|
|
294
296
|
end
|
|
295
297
|
(rand(string.size) + 1).times {
|
|
@@ -502,24 +504,11 @@ class StringPattern
|
|
|
502
504
|
expected_errors_left.delete(:string_set_not_allowed)
|
|
503
505
|
end
|
|
504
506
|
|
|
505
|
-
error_regular_expression =
|
|
507
|
+
error_regular_expression = !StringPattern.valid_email?(string)
|
|
506
508
|
|
|
507
509
|
if deny_pattern and expected_errors.include?(:length)
|
|
508
510
|
good_result = true #it is already with wrong length
|
|
509
511
|
else
|
|
510
|
-
# I'm doing this because many times the regular expression checking hangs with these characters
|
|
511
|
-
wrong = %w(.. __ -- ._ _. .- -. _- -_ @. @_ @- .@ _@ -@ @@)
|
|
512
|
-
if !(Regexp.union(*wrong) === string) #don't include any or the wrong strings
|
|
513
|
-
if string.index("@").to_i > 0 and
|
|
514
|
-
string[0..(string.index("@") - 1)].scan(/([a-z0-9]+([\+\._\-][a-z0-9]|)*)/i).join == string[0..(string.index("@") - 1)] and
|
|
515
|
-
string[(string.index("@") + 1)..-1].scan(/([0-9a-z]+([\.-][a-z0-9]|)*)/i).join == string[string[(string.index("@") + 1)..-1]]
|
|
516
|
-
error_regular_expression = false
|
|
517
|
-
else
|
|
518
|
-
error_regular_expression = true
|
|
519
|
-
end
|
|
520
|
-
else
|
|
521
|
-
error_regular_expression = true
|
|
522
|
-
end
|
|
523
512
|
|
|
524
513
|
if expected_errors.size == 0
|
|
525
514
|
if error_regular_expression
|
|
@@ -540,7 +529,9 @@ class StringPattern
|
|
|
540
529
|
end
|
|
541
530
|
end until good_result or tries > 100
|
|
542
531
|
unless good_result
|
|
543
|
-
|
|
532
|
+
msg = "Not possible to generate an email on StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}"
|
|
533
|
+
raise StringPattern::GenerationImpossibleError, msg if @raise_on_error
|
|
534
|
+
StringPattern.log_message(msg)
|
|
544
535
|
return ""
|
|
545
536
|
end
|
|
546
537
|
end
|
|
@@ -569,7 +560,9 @@ class StringPattern
|
|
|
569
560
|
end
|
|
570
561
|
end
|
|
571
562
|
if @block_list_enabled
|
|
572
|
-
if @block_list.
|
|
563
|
+
if @block_list.respond_to?(:call)
|
|
564
|
+
good_result = false if @block_list.call(string)
|
|
565
|
+
elsif @block_list.is_a?(Array)
|
|
573
566
|
@block_list.each do |bl|
|
|
574
567
|
if string.match?(/#{bl}/i)
|
|
575
568
|
good_result = false
|
|
@@ -580,10 +573,14 @@ class StringPattern
|
|
|
580
573
|
end
|
|
581
574
|
end until good_result or tries > 10000
|
|
582
575
|
unless good_result
|
|
583
|
-
|
|
584
|
-
|
|
576
|
+
msg = "Not possible to generate the string on StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}"
|
|
577
|
+
msg += "\nTake in consideration if you are using StringPattern.dont_repeat=true that you don't try to generate more strings that are possible to be generated"
|
|
578
|
+
raise StringPattern::GenerationImpossibleError, msg if @raise_on_error
|
|
579
|
+
StringPattern.log_message(msg)
|
|
585
580
|
return ""
|
|
586
581
|
end
|
|
587
582
|
return string
|
|
583
|
+
ensure
|
|
584
|
+
srand(saved_rng) if saved_rng
|
|
588
585
|
end
|
|
589
586
|
end
|
|
@@ -54,7 +54,7 @@ class StringPattern
|
|
|
54
54
|
max_length = patt.max_length.clone
|
|
55
55
|
symbol_type = patt.symbol_type.clone
|
|
56
56
|
else
|
|
57
|
-
|
|
57
|
+
StringPattern.log_message("String pattern class not supported (#{pat.class} for #{pat})")
|
|
58
58
|
return false
|
|
59
59
|
end
|
|
60
60
|
|
|
@@ -133,7 +133,7 @@ class StringPattern
|
|
|
133
133
|
required_chars << rd if rd.size == 1
|
|
134
134
|
}
|
|
135
135
|
if (required_chars.flatten & excluded_data.flatten).size > 0
|
|
136
|
-
|
|
136
|
+
StringPattern.log_message("pattern argument not valid on StringPattern.validate, a character cannot be required and excluded at the same time: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}")
|
|
137
137
|
return ""
|
|
138
138
|
end
|
|
139
139
|
end
|
|
@@ -183,20 +183,7 @@ class StringPattern
|
|
|
183
183
|
end
|
|
184
184
|
}
|
|
185
185
|
else #symbol_type=="@"
|
|
186
|
-
|
|
187
|
-
wrong = %w(.. __ -- ._ _. .- -. _- -_ @. @_ @- .@ _@ -@ @@)
|
|
188
|
-
if !(Regexp.union(*wrong) === string) #don't include any or the wrong strings
|
|
189
|
-
if string.index("@").to_i > 0 and
|
|
190
|
-
string[0..(string.index("@") - 1)].scan(/([a-z0-9]+([\+\._\-][a-z0-9]|)*)/i).join == string[0..(string.index("@") - 1)] and
|
|
191
|
-
string[(string.index("@") + 1)..-1].scan(/([0-9a-z]+([\.-][a-z0-9]|)*)/i).join == string[string[(string.index("@") + 1)..-1]]
|
|
192
|
-
error_regular_expression = false
|
|
193
|
-
else
|
|
194
|
-
error_regular_expression = true
|
|
195
|
-
end
|
|
196
|
-
else
|
|
197
|
-
error_regular_expression = true
|
|
198
|
-
end
|
|
199
|
-
|
|
186
|
+
error_regular_expression = !StringPattern.valid_email?(text_to_validate)
|
|
200
187
|
if error_regular_expression
|
|
201
188
|
detected_errors.push(:value)
|
|
202
189
|
end
|
data/lib/string_pattern.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
SP_ADD_TO_RUBY = true if !defined?(SP_ADD_TO_RUBY)
|
|
2
2
|
require_relative "string/pattern/add_to_ruby" if SP_ADD_TO_RUBY
|
|
3
3
|
require_relative "string/pattern/analyze"
|
|
4
|
+
require_relative "string/pattern/email"
|
|
4
5
|
require_relative "string/pattern/generate"
|
|
5
6
|
require_relative "string/pattern/validate"
|
|
6
7
|
|
|
@@ -29,8 +30,22 @@ require_relative "string/pattern/validate"
|
|
|
29
30
|
# Array of words to be avoided from resultant strings.
|
|
30
31
|
# block_list_enabled: (TrueFalse, default: false)
|
|
31
32
|
# If true block_list will be take in consideration
|
|
33
|
+
#
|
|
34
|
+
# @example Generate a string
|
|
35
|
+
# StringPattern.generate("10:N") # => "3448910834"
|
|
36
|
+
# @example Validate and get errors
|
|
37
|
+
# StringPattern.validate(text: "ab", pattern: "6:N") # => [:min_length, :length]
|
|
32
38
|
class StringPattern
|
|
39
|
+
# Raised when an invalid pattern is used and {raise_on_error} is true.
|
|
40
|
+
InvalidPatternError = Class.new(StandardError)
|
|
41
|
+
# Raised when generation is impossible (e.g. exhausted by dont_repeat) and {raise_on_error} is true.
|
|
42
|
+
GenerationImpossibleError = Class.new(StandardError)
|
|
43
|
+
|
|
33
44
|
class << self
|
|
45
|
+
# @return [String, nil] When set, warning messages are sent here instead of +puts+.
|
|
46
|
+
attr_accessor :logger
|
|
47
|
+
# @return [Boolean] When true, invalid patterns or impossible generation raise instead of returning "".
|
|
48
|
+
attr_accessor :raise_on_error
|
|
34
49
|
attr_accessor :national_chars, :optimistic, :dont_repeat, :cache, :cache_values, :default_infinite, :word_separator, :block_list, :block_list_enabled
|
|
35
50
|
end
|
|
36
51
|
@national_chars = (("a".."z").to_a + ("A".."Z").to_a).join
|
|
@@ -42,6 +57,8 @@ class StringPattern
|
|
|
42
57
|
@word_separator = "_"
|
|
43
58
|
@block_list_enabled = false
|
|
44
59
|
@block_list = []
|
|
60
|
+
@logger = nil
|
|
61
|
+
@raise_on_error = false
|
|
45
62
|
NUMBER_SET = ("0".."9").to_a
|
|
46
63
|
SPECIAL_SET = [" ", "~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "_", "+", "=", "{", "}", "[", "]", "'", ";", ":", "?", ">", "<", "`", "|", "/", '"']
|
|
47
64
|
ALPHA_SET_LOWER = ("a".."z").to_a
|
|
@@ -63,4 +80,60 @@ class StringPattern
|
|
|
63
80
|
@national_chars = par
|
|
64
81
|
end
|
|
65
82
|
|
|
83
|
+
def self.log_message(message)
|
|
84
|
+
if @logger
|
|
85
|
+
@logger.warn(message)
|
|
86
|
+
else
|
|
87
|
+
puts message
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Returns true if +text+ matches +pattern+; false otherwise. Uses validate under the hood.
|
|
92
|
+
# @param text [String] (synonyms: text_to_validate, validate)
|
|
93
|
+
# @param pattern [String, Symbol, Array]
|
|
94
|
+
# @return [Boolean]
|
|
95
|
+
def self.valid?(text: nil, pattern: nil, **synonyms)
|
|
96
|
+
text = synonyms[:text_to_validate] if text.nil? && synonyms.key?(:text_to_validate)
|
|
97
|
+
text = synonyms[:validate] if text.nil? && synonyms.key?(:validate)
|
|
98
|
+
return false if text.nil? || pattern.nil?
|
|
99
|
+
result = validate(text: text, pattern: pattern, **synonyms)
|
|
100
|
+
pattern.is_a?(Array) ? result == true : result.is_a?(Array) && result.empty?
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Generates up to +n+ distinct strings for +pattern+. Uses a temporary dont_repeat state.
|
|
104
|
+
# @param pattern [String, Symbol, Array, Regexp]
|
|
105
|
+
# @param n [Integer]
|
|
106
|
+
# @return [Array<String>]
|
|
107
|
+
def self.sample(pattern, n)
|
|
108
|
+
return [] if n <= 0
|
|
109
|
+
old_dont = @dont_repeat
|
|
110
|
+
old_cache = @cache_values.dup
|
|
111
|
+
@dont_repeat = true
|
|
112
|
+
@cache_values = {}
|
|
113
|
+
results = []
|
|
114
|
+
n.times do
|
|
115
|
+
s = generate(pattern)
|
|
116
|
+
break if s.nil? || s.empty?
|
|
117
|
+
results << s
|
|
118
|
+
end
|
|
119
|
+
results
|
|
120
|
+
ensure
|
|
121
|
+
@dont_repeat = old_dont
|
|
122
|
+
@cache_values = old_cache
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Generates a random UUID v4 (e.g. "550e8400-e29b-41d4-a716-446655440000").
|
|
126
|
+
# @return [String]
|
|
127
|
+
def self.uuid
|
|
128
|
+
require "securerandom"
|
|
129
|
+
SecureRandom.uuid
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Returns true if +str+ is a valid UUID v4 format (8-4-4-4-12 hex with version and variant bits).
|
|
133
|
+
# @param str [String]
|
|
134
|
+
# @return [Boolean]
|
|
135
|
+
def self.valid_uuid?(str)
|
|
136
|
+
return false unless str.is_a?(String)
|
|
137
|
+
str.match?(/\A[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/i)
|
|
138
|
+
end
|
|
66
139
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: string_pattern
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mario Ruiz
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-02-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: regexp_parser
|
|
@@ -61,6 +61,7 @@ files:
|
|
|
61
61
|
- data/spanish/palabras9.json
|
|
62
62
|
- lib/string/pattern/add_to_ruby.rb
|
|
63
63
|
- lib/string/pattern/analyze.rb
|
|
64
|
+
- lib/string/pattern/email.rb
|
|
64
65
|
- lib/string/pattern/generate.rb
|
|
65
66
|
- lib/string/pattern/validate.rb
|
|
66
67
|
- lib/string_pattern.rb
|
|
@@ -83,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
83
84
|
- !ruby/object:Gem::Version
|
|
84
85
|
version: '0'
|
|
85
86
|
requirements: []
|
|
86
|
-
rubygems_version: 3.
|
|
87
|
+
rubygems_version: 3.4.19
|
|
87
88
|
signing_key:
|
|
88
89
|
specification_version: 4
|
|
89
90
|
summary: 'Generate easily random strings following a simple pattern or regular expression.
|