string_pattern 2.1.4 → 2.2.3

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.
@@ -1,5 +1,8 @@
1
1
  SP_ADD_TO_RUBY = true if !defined?(SP_ADD_TO_RUBY)
2
- require_relative 'string/pattern/add_to_ruby' if SP_ADD_TO_RUBY
2
+ require_relative "string/pattern/add_to_ruby" if SP_ADD_TO_RUBY
3
+ require_relative "string/pattern/analyze"
4
+ require_relative "string/pattern/generate"
5
+ require_relative "string/pattern/validate"
3
6
 
4
7
  # SP_ADD_TO_RUBY: (TrueFalse, default: true) You need to add this constant value before requiring the library if you want to modify the default.
5
8
  # If true it will add 'generate' and 'validate' methods to the classes: Array, String and Symbol. Also it will add 'generate' method to Kernel
@@ -19,24 +22,24 @@ require_relative 'string/pattern/add_to_ruby' if SP_ADD_TO_RUBY
19
22
  # dont_repeat: (TrueFalse, default: false)
20
23
  # If you want to generate for example 1000 strings and be sure all those strings are different you can set it to true
21
24
  # default_infinite: (Integer, default: 10)
22
- # In case using regular expressions the maximum when using * or + for repetitions
25
+ # In case using regular expressions the maximum when using * or + for repetitions
23
26
  # word_separator: (String, default: '_')
24
27
  # When generating words using symbol types 'w' or 'p' the character to separate the english or spanish words.
25
28
  class StringPattern
26
29
  class << self
27
30
  attr_accessor :national_chars, :optimistic, :dont_repeat, :cache, :cache_values, :default_infinite, :word_separator
28
31
  end
29
- @national_chars = (('a'..'z').to_a + ('A'..'Z').to_a).join
32
+ @national_chars = (("a".."z").to_a + ("A".."Z").to_a).join
30
33
  @optimistic = true
31
34
  @cache = Hash.new()
32
35
  @cache_values = Hash.new()
33
36
  @dont_repeat = false
34
37
  @default_infinite = 10
35
- @word_separator = '_'
36
- NUMBER_SET = ('0'..'9').to_a
37
- SPECIAL_SET = [' ', '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '+', '=', '{', '}', '[', ']', "'", ';', ':', '?', '>', '<', '`', '|', '/', '"']
38
- ALPHA_SET_LOWER = ('a'..'z').to_a
39
- ALPHA_SET_CAPITAL = ('A'..'Z').to_a
38
+ @word_separator = "_"
39
+ NUMBER_SET = ("0".."9").to_a
40
+ SPECIAL_SET = [" ", "~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "_", "+", "=", "{", "}", "[", "]", "'", ";", ":", "?", ">", "<", "`", "|", "/", '"']
41
+ ALPHA_SET_LOWER = ("a".."z").to_a
42
+ ALPHA_SET_CAPITAL = ("A".."Z").to_a
40
43
  @palabras = []
41
44
  @palabras_camel = []
42
45
  @words = []
@@ -49,984 +52,8 @@ class StringPattern
49
52
  Pattern = Struct.new(:min_length, :max_length, :symbol_type, :required_data, :excluded_data, :data_provided,
50
53
  :string_set, :all_characters_set, :unique)
51
54
 
52
- ###############################################
53
- # Analyze the pattern supplied and returns an object of Pattern structure including:
54
- # min_length, max_length, symbol_type, required_data, excluded_data, data_provided, string_set, all_characters_set
55
- ###############################################
56
- def StringPattern.analyze(pattern, silent: false)
57
- return @cache[pattern.to_s] unless @cache[pattern.to_s].nil?
58
- min_length, max_length, symbol_type = pattern.to_s.scan(/(\d+)-(\d+):(.+)/)[0]
59
- if min_length.nil?
60
- min_length, symbol_type = pattern.to_s.scan(/^!?(\d+):(.+)/)[0]
61
- max_length = min_length
62
- if min_length.nil?
63
- puts "pattern argument not valid on StringPattern.generate: #{pattern.inspect}" unless silent
64
- return pattern.to_s
65
- end
66
- end
67
- if symbol_type[-1]=="&"
68
- symbol_type.chop!
69
- unique = true
70
- else
71
- unique = false
72
- end
73
-
74
- symbol_type = '!' + symbol_type if pattern.to_s[0] == '!'
75
- min_length = min_length.to_i
76
- max_length = max_length.to_i
77
-
78
- required_data = Array.new
79
- excluded_data = Array.new
80
- required = false
81
- excluded = false
82
- data_provided = Array.new
83
- a = symbol_type
84
- begin_provided = a.index('[')
85
- excluded_end_tag = false
86
- unless begin_provided.nil?
87
- c = begin_provided + 1
88
- until c == a.size or (a[c..c] == ']' and a[c..c + 1] != ']]')
89
- if a[c..c + 1] == ']]'
90
- data_provided.push(']')
91
- c = c + 2
92
- elsif a[c..c + 1] == '%%' and !excluded then
93
- data_provided.push('%')
94
- c = c + 2
95
- else
96
- if a[c..c] == '/' and !excluded
97
- if a[c..c + 1] == '//'
98
- data_provided.push(a[c..c])
99
- if required
100
- required_data.push([a[c..c]])
101
- end
102
- c = c + 1
103
- else
104
- if !required
105
- required = true
106
- else
107
- required = false
108
- end
109
- end
110
- else
111
- if required
112
- required_data.push([a[c..c]])
113
- else
114
- if a[c..c] == '%'
115
- if a[c..c + 1] == '%%' and excluded
116
- excluded_data.push([a[c..c]])
117
- c = c + 1
118
- else
119
- if !excluded
120
- excluded = true
121
- else
122
- excluded = false
123
- excluded_end_tag = true
124
- end
125
- end
126
- else
127
- if excluded
128
- excluded_data.push([a[c..c]])
129
- end
130
- end
131
-
132
- end
133
- if excluded == false and excluded_end_tag == false
134
- data_provided.push(a[c..c])
135
- end
136
- excluded_end_tag = false
137
- end
138
- c = c + 1
139
- end
140
- end
141
- symbol_type = symbol_type[0..begin_provided].to_s + symbol_type[c..symbol_type.size].to_s
142
- end
143
-
144
- required = false
145
- required_symbol = ''
146
- if symbol_type.include?("/")
147
- symbol_type.chars.each {|stc|
148
- if stc == '/'
149
- if !required
150
- required = true
151
- else
152
- required = false
153
- end
154
- else
155
- if required
156
- required_symbol += stc
157
- end
158
- end
159
- }
160
- end
161
-
162
- national_set = @national_chars.chars
163
-
164
- if symbol_type.include?('L') then
165
- alpha_set = ALPHA_SET_LOWER + ALPHA_SET_CAPITAL
166
- elsif symbol_type.include?('x')
167
- alpha_set = ALPHA_SET_LOWER
168
- if symbol_type.include?('X')
169
- alpha_set = alpha_set + ALPHA_SET_CAPITAL
170
- end
171
- elsif symbol_type.include?('X')
172
- alpha_set = ALPHA_SET_CAPITAL
173
- else
174
- alpha_set = []
175
- end
176
- if symbol_type.include?('T')
177
- alpha_set = alpha_set + national_set
178
- end
179
-
180
- unless required_symbol.nil?
181
- if required_symbol.include?('x')
182
- required_data.push ALPHA_SET_LOWER
183
- end
184
- if required_symbol.include?('X')
185
- required_data.push ALPHA_SET_CAPITAL
186
- end
187
- if required_symbol.include?('L')
188
- required_data.push(ALPHA_SET_CAPITAL + ALPHA_SET_LOWER)
189
- end
190
- if required_symbol.include?('T')
191
- required_data.push national_set
192
- end
193
- required_symbol = required_symbol.downcase
194
- end
195
- string_set = Array.new
196
- all_characters_set = ALPHA_SET_CAPITAL + ALPHA_SET_LOWER + NUMBER_SET + SPECIAL_SET + data_provided + national_set
197
-
198
- if symbol_type.include?('_')
199
- unless symbol_type.include?('$')
200
- string_set.push(' ')
201
- end
202
- if required_symbol.include?('_')
203
- required_data.push([' '])
204
- end
205
- end
206
-
207
- #symbol_type = symbol_type.downcase
208
-
209
- if symbol_type.downcase.include?('x') or symbol_type.downcase.include?('l') or symbol_type.downcase.include?('t')
210
- string_set = string_set + alpha_set
211
- end
212
- if symbol_type.downcase.include?('n')
213
- string_set = string_set + NUMBER_SET
214
- end
215
- if symbol_type.include?('$')
216
- string_set = string_set + SPECIAL_SET
217
- end
218
- if symbol_type.include?('*')
219
- string_set = string_set + all_characters_set
220
- end
221
- if data_provided.size != 0
222
- string_set = string_set + data_provided
223
- end
224
- unless required_symbol.empty?
225
- if required_symbol.include?('n')
226
- required_data.push NUMBER_SET
227
- end
228
- if required_symbol.include?('$')
229
- required_data.push SPECIAL_SET
230
- end
231
- end
232
- unless excluded_data.empty?
233
- string_set = string_set - excluded_data.flatten
234
- end
235
- string_set.uniq!
236
- @cache[pattern.to_s] = Pattern.new(min_length, max_length, symbol_type, required_data, excluded_data, data_provided,
237
- string_set, all_characters_set, unique)
238
- return @cache[pattern.to_s]
55
+ def self.national_chars=(par)
56
+ @cache = Hash.new()
57
+ @national_chars = par
239
58
  end
240
-
241
- ###############################################
242
- # Generate a random string based on the pattern supplied
243
- # (if SP_ADD_TO_RUBY==true, by default is true) To simplify its use it is part of the String, Array, Symbol and Kernel Ruby so can be easily used also like this:
244
- # "10-15:Ln/x/".generate #generate method on String class (alias: gen)
245
- # ['(', :'3:N', ')', :'6-8:N'].generate #generate method on Array class (alias: gen)
246
- # generate("10-15:Ln/x/") #generate Ruby Kernel method
247
- # generate(['(', :'3:N', ')', :'6-8:N']) #generate Ruby Kernel method
248
- # "(,3:N,) ,3:N,-,2:N,-,2:N".split(",").generate #>(937) #generate method on Array class (alias: gen)
249
- # %w{( 3:N ) 1:_ 3:N - 2:N - 2:N}.gen #generate method on Array class, using alias gen method
250
- # Input:
251
- # pattern: array or string of different patterns. A pattern is a string with this info:
252
- # "length:symbol_type" or "min_length-max_length:symbol_type"
253
- # In case an array supplied, the positions using a string pattern should be supplied as symbols if StringPattern.optimistic==false
254
- #
255
- # These are the possible string patterns you will be able to supply:
256
- # If at the beginning we supply the character ! the resulting string won't fulfill the pattern. This character need to be the first character of the pattern.
257
- # min_length -- minimum length of the string
258
- # max_length (optional) -- maximum length of the string. If not provided the result will be with the min_length provided
259
- # symbol_type -- the type of the string we want.
260
- # you can use a combination of any ot these:
261
- # x for alpha in lowercase
262
- # X for alpha in capital letters
263
- # L for all kind of alpha in capital and lower letters
264
- # T for the national characters defined on StringPattern.national_chars
265
- # n for number
266
- # $ for special characters (includes space)
267
- # _ for space
268
- # * all characters
269
- # [characters] the characters we want. If we want to add also the ] character you have to write: ]]. If we want to add also the % character you have to write: %%
270
- # %characters% the characters we don't want on the resulting string. %% to exclude the character %
271
- # /symbols or characters/ If we want these characters to be included on the resulting string. If we want to add also the / character you have to write: //
272
- # We can supply 0 to allow empty strings, this character need to be at the beginning
273
- # If you want to include the character " use \"
274
- # If you want to include the character \ use \\
275
- # If you want to include the character [ use \[
276
- # Other uses:
277
- # @ for email
278
- # W for English words, capital and lower
279
- # w for English words only lower and words separated by underscore
280
- # P for Spanish words, capital and lower
281
- # p for Spanish words only lower and words separated by underscore
282
- # Examples:
283
- # [:"6:X", :"3-8:_N"]
284
- # # it will return a string starting with 6 capital letters and then a string containing numbers and space from 3 to 8 characters, for example: "LDJKKD34 555"
285
- # [:"6-15:L_N", "fixed text", :"3:N"]
286
- # # it will return a string of 6-15 characters containing Letters-spaces-numbers, then the text: 'fixed text' and at the end a string of 3 characters containing numbers, for example: ["L_N",6,15],"fixed text",["N",3] "3 Am399 afixed text882"
287
- # "10-20:LN[=#]"
288
- # # it will return a string of 10-20 characters containing Letters and/or numbers and/or the characters = and #, for example: eiyweQFWeL#do4Vl
289
- # "30:TN_[#=]/x/"
290
- # # it will return a string of 30 characters containing national characters defined on StringPattern.national_chars and/or numbers and/or spaces and/or the characters # = and it is necessary the resultant string includes lower alpha chars. For example: HaEdQTzJ3=OtXMh1mAPqv7NCy=upLy
291
- # "10:N[%0%]"
292
- # # 10 characters length containing numbers and excluding the character 0, for example: 3523497757
293
- # "10:N[%0%/AB/]"
294
- # # 10 characters length containing numbers and excluding the character 0 and necessary to contain the characters A B, for example: 3AA4AA57BB
295
- # "!10:N[%0%/AB/]"
296
- # # it will generate a string that doesn't fulfill the pattern supplied, examples:
297
- # # a6oMQ4JK9g
298
- # # /Y<N6Aa[ae
299
- # # 3444439A34B32
300
- # "10:N[%0%/AB/]", errors: [:length]
301
- # # it will generate a string following the pattern and with the errors supplied, in this case, length, example: AB44
302
- # Output:
303
- # the generated string
304
- ###############################################
305
- def StringPattern.generate(pattern, expected_errors: [], **synonyms)
306
- tries = 0
307
- begin
308
- good_result = true
309
- tries += 1
310
- string = ''
311
-
312
- expected_errors = synonyms[:errors] if synonyms.keys.include?(:errors)
313
-
314
- if expected_errors.kind_of?(Symbol)
315
- expected_errors = [expected_errors]
316
- end
317
-
318
- if pattern.kind_of?(Array)
319
- pattern.each {|pat|
320
-
321
- if pat.kind_of?(Array) # for the case it is one of the values
322
- pat = pat.sample
323
- end
324
-
325
- if pat.kind_of?(Symbol)
326
- if pat.to_s.scan(/^!?\d+-?\d*:.+/).size > 0
327
- string << StringPattern.generate(pat.to_s, expected_errors: expected_errors)
328
- else
329
- string << pat.to_s
330
- end
331
- elsif pat.kind_of?(String) then
332
- if @optimistic and pat.to_s.scan(/^!?\d+-?\d*:.+/).size > 0
333
- string << StringPattern.generate(pat.to_s, expected_errors: expected_errors)
334
- else
335
- string << pat
336
- end
337
- else
338
- puts "StringPattern.generate: it seems you supplied wrong array of patterns: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}"
339
- return ''
340
- end
341
- }
342
- return string
343
- elsif pattern.kind_of?(String) or pattern.kind_of?(Symbol)
344
- patt = StringPattern.analyze(pattern)
345
- min_length = patt.min_length
346
- max_length = patt.max_length
347
- symbol_type = patt.symbol_type
348
-
349
- required_data = patt.required_data
350
- excluded_data = patt.excluded_data
351
- string_set = patt.string_set
352
- all_characters_set = patt.all_characters_set
353
-
354
- required_chars = Array.new
355
- unless required_data.size == 0
356
- required_data.each {|rd|
357
- required_chars << rd if rd.size == 1
358
- }
359
- unless excluded_data.size == 0
360
- if (required_chars.flatten & excluded_data.flatten).size > 0
361
- puts "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}"
362
- return ''
363
- end
364
- end
365
- end
366
- string_set_not_allowed = Array.new
367
- elsif pattern.kind_of?(Regexp)
368
- return generate(pattern.to_sp, expected_errors: expected_errors)
369
- else
370
- puts "pattern argument not valid on StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}"
371
- return pattern.to_s
372
- end
373
-
374
-
375
- allow_empty = false
376
- deny_pattern = false
377
- if symbol_type[0..0] == '!'
378
- deny_pattern = true
379
- possible_errors = [:length, :value, :required_data, :excluded_data, :string_set_not_allowed]
380
- (rand(possible_errors.size) + 1).times {
381
- expected_errors << possible_errors.sample
382
- }
383
- expected_errors.uniq!
384
- if symbol_type[1..1] == '0'
385
- allow_empty = true
386
- end
387
- elsif symbol_type[0..0] == '0' then
388
- allow_empty = true
389
- end
390
-
391
- if expected_errors.include?(:min_length) or expected_errors.include?(:length) or
392
- expected_errors.include?(:max_length)
393
- allow_empty = !allow_empty
394
- elsif expected_errors.include?(:value) or
395
- expected_errors.include?(:excluded_data) or
396
- expected_errors.include?(:required_data) or
397
- expected_errors.include?(:string_set_not_allowed) and allow_empty
398
- allow_empty = false
399
- end
400
-
401
- length = min_length
402
- symbol_type_orig = symbol_type
403
-
404
- expected_errors_left = expected_errors.dup
405
-
406
- symbol_type = symbol_type_orig
407
-
408
- unless deny_pattern
409
- if required_data.size == 0 and expected_errors_left.include?(:required_data)
410
- puts "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}"
411
- return ''
412
- end
413
-
414
- if excluded_data.size == 0 and expected_errors_left.include?(:excluded_data)
415
- puts "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}"
416
- return ''
417
- end
418
-
419
- if expected_errors_left.include?(:string_set_not_allowed)
420
- string_set_not_allowed = all_characters_set - string_set
421
- if string_set_not_allowed.size == 0 then
422
- puts "all characters are allowed so it won't be possible to generate a wrong string. StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}"
423
- return ''
424
- end
425
- end
426
- end
427
-
428
- if expected_errors_left.include?(:min_length) or
429
- expected_errors_left.include?(:max_length) or
430
- expected_errors_left.include?(:length)
431
- if expected_errors_left.include?(:min_length) or
432
- (min_length > 0 and expected_errors_left.include?(:length) and rand(2) == 0)
433
- if min_length > 0
434
- if allow_empty
435
- length = rand(min_length).to_i
436
- else
437
- length = rand(min_length - 1).to_i + 1
438
- end
439
- if required_data.size > length and required_data.size < min_length
440
- length = required_data.size
441
- end
442
- expected_errors_left.delete(:length)
443
- expected_errors_left.delete(:min_length)
444
- else
445
- puts "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}"
446
- return ''
447
- end
448
- elsif expected_errors_left.include?(:max_length) or expected_errors_left.include?(:length)
449
- length = max_length + 1 + rand(max_length).to_i
450
- expected_errors_left.delete(:length)
451
- expected_errors_left.delete(:max_length)
452
- end
453
- else
454
- if allow_empty and rand(7) == 1
455
- length = 0
456
- else
457
- if max_length == min_length
458
- length = min_length
459
- else
460
- length = min_length + rand(max_length - min_length + 1)
461
- end
462
- end
463
- end
464
-
465
- if deny_pattern
466
- if required_data.size == 0 and expected_errors_left.include?(:required_data)
467
- expected_errors_left.delete(:required_data)
468
- end
469
-
470
- if excluded_data.size == 0 and expected_errors_left.include?(:excluded_data)
471
- expected_errors_left.delete(:excluded_data)
472
- end
473
-
474
- if expected_errors_left.include?(:string_set_not_allowed)
475
- string_set_not_allowed = all_characters_set - string_set
476
- if string_set_not_allowed.size == 0
477
- expected_errors_left.delete(:string_set_not_allowed)
478
- end
479
- end
480
-
481
- if symbol_type == '!@' and expected_errors_left.size == 0 and !expected_errors.include?(:length) and
482
- (expected_errors.include?(:required_data) or expected_errors.include?(:excluded_data))
483
- expected_errors_left.push(:value)
484
- end
485
-
486
- end
487
-
488
- string = ''
489
- if symbol_type != '@' and symbol_type != '!@' and length != 0 and string_set.size != 0
490
- if string_set.size != 0
491
- 1.upto(length) {|i| string << string_set.sample.to_s
492
- }
493
- end
494
- if required_data.size > 0
495
- positions_to_set = (0..(string.size - 1)).to_a
496
- required_data.each {|rd|
497
- if (string.chars & rd).size > 0
498
- rd_to_set = (string.chars & rd).sample
499
- else
500
- rd_to_set = rd.sample
501
- end
502
- if ((0...string.length).find_all {|i| string[i, 1] == rd_to_set}).size == 0
503
- if positions_to_set.size == 0
504
- puts "pattern not valid on StringPattern.generate, not possible to generate a valid string: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}"
505
- return ''
506
- else
507
- k = positions_to_set.sample
508
- string[k] = rd_to_set
509
- positions_to_set.delete(k)
510
- end
511
- else
512
- k = ((0...string.length).find_all {|i| string[i, 1] == rd_to_set}).sample
513
- positions_to_set.delete(k)
514
- end
515
- }
516
- end
517
- excluded_data.each {|ed|
518
- if (string.chars & ed).size > 0
519
- (string.chars & ed).each {|s|
520
- string.gsub!(s, string_set.sample)
521
- }
522
- end
523
- }
524
-
525
- if expected_errors_left.include?(:value)
526
- string_set_not_allowed = all_characters_set - string_set if string_set_not_allowed.size == 0
527
- if string_set_not_allowed.size == 0
528
- puts "Not possible to generate a non valid string on StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}"
529
- return ''
530
- end
531
- (rand(string.size) + 1).times {
532
- string[rand(string.size)] = (all_characters_set - string_set).sample
533
- }
534
- expected_errors_left.delete(:value)
535
- end
536
-
537
- if expected_errors_left.include?(:required_data) and required_data.size > 0
538
- (rand(required_data.size) + 1).times {
539
- chars_to_remove = required_data.sample
540
- chars_to_remove.each {|char_to_remove|
541
- string.gsub!(char_to_remove, (string_set - chars_to_remove).sample)
542
- }
543
- }
544
- expected_errors_left.delete(:required_data)
545
- end
546
-
547
- if expected_errors_left.include?(:excluded_data) and excluded_data.size > 0
548
- (rand(string.size) + 1).times {
549
- string[rand(string.size)] = excluded_data.sample.sample
550
- }
551
- expected_errors_left.delete(:excluded_data)
552
- end
553
-
554
- if expected_errors_left.include?(:string_set_not_allowed)
555
- string_set_not_allowed = all_characters_set - string_set if string_set_not_allowed.size == 0
556
- if string_set_not_allowed.size > 0
557
- (rand(string.size) + 1).times {
558
- string[rand(string.size)] = string_set_not_allowed.sample
559
- }
560
- expected_errors_left.delete(:string_set_not_allowed)
561
- end
562
- end
563
- elsif (symbol_type == 'W' or symbol_type == 'P' or symbol_type=='w' or symbol_type =='p') and length>0
564
- words = []
565
- words_short = []
566
- if symbol_type == 'W'
567
- if @words_camel.empty?
568
- require "pathname"
569
- require "json"
570
- filename = File.join Pathname(File.dirname(__FILE__)), "../data", "english/nouns.json"
571
- nouns = JSON.parse(File.read(filename))
572
- filename = File.join Pathname(File.dirname(__FILE__)), "../data", "english/adjs.json"
573
- adjs = JSON.parse(File.read(filename))
574
- nouns = nouns.map(&:to_camel_case)
575
- adjs = adjs.map(&:to_camel_case)
576
- @words_camel = adjs + nouns
577
- @words_camel_short = @words_camel.sample(2000)
578
- end
579
- words = @words_camel
580
- words_short = @words_camel_short
581
- elsif symbol_type == 'w'
582
- if @words.empty?
583
- require "pathname"
584
- require "json"
585
- filename = File.join Pathname(File.dirname(__FILE__)), "../data", "english/nouns.json"
586
- nouns = JSON.parse(File.read(filename))
587
- filename = File.join Pathname(File.dirname(__FILE__)), "../data", "english/adjs.json"
588
- adjs = JSON.parse(File.read(filename))
589
- @words = adjs + nouns
590
- @words_short = @words.sample(2000)
591
- end
592
- words = @words
593
- words_short = @words_short
594
- elsif symbol_type == 'P'
595
- if @palabras_camel.empty?
596
- require "pathname"
597
- require "json"
598
- filename = File.join Pathname(File.dirname(__FILE__)), "../data", "spanish/palabras#{rand(12)}.json"
599
- palabras = JSON.parse(File.read(filename))
600
- palabras = palabras.map(&:to_camel_case)
601
- @palabras_camel = palabras
602
- @palabras_camel_short = @palabras_camel.sample(2000)
603
- end
604
- words = @palabras_camel
605
- words_short = @palabras_camel_short
606
- elsif symbol_type == 'p'
607
- if @palabras.empty?
608
- require "pathname"
609
- require "json"
610
- filename = File.join Pathname(File.dirname(__FILE__)), "../data", "spanish/palabras#{rand(12)}.json"
611
- palabras = JSON.parse(File.read(filename))
612
- @palabras = palabras
613
- @palabras_short = @palabras.sample(2000)
614
- end
615
- words = @palabras
616
- words_short = @palabras_short
617
- end
618
-
619
- wordr = ""
620
- wordr_array = []
621
- tries = 0
622
- while wordr.length < min_length
623
- tries += 1
624
- length = max_length - wordr.length
625
- if tries > 1000
626
- wordr += 'A'*length
627
- break
628
- end
629
- if symbol_type == 'w' or symbol_type == "p"
630
- length = length -1 if wordr_array.size>0
631
- res = (words_short.select { |word| word.length <= length && word.length!=length-1 && word.length!=length-2 && word.length!=length-3 }).sample.to_s
632
- unless res.to_s==''
633
- wordr_array<<res
634
- wordr = wordr_array.join(@word_separator)
635
- end
636
- else
637
- wordr += (words_short.select { |word| word.length <= length && word.length!=length-1 && word.length!=length-2 && word.length!=length-3}).sample.to_s
638
- end
639
- if (tries % 100) == 0
640
- words_short = words.sample(2000)
641
- end
642
- end
643
- good_result = true
644
- string = wordr
645
-
646
- elsif (symbol_type == '@' or symbol_type == '!@') and length > 0
647
- if min_length > 6 and length < 6
648
- length = 6
649
- end
650
- if deny_pattern and
651
- (expected_errors.include?(:required_data) or expected_errors.include?(:excluded_data) or
652
- expected_errors.include?(:string_set_not_allowed))
653
- expected_errors_left.push(:value)
654
- expected_errors.push(:value)
655
- expected_errors.uniq!
656
- expected_errors_left.uniq!
657
- end
658
-
659
- expected_errors_left_orig = expected_errors_left.dup
660
- tries = 0
661
- begin
662
- expected_errors_left = expected_errors_left_orig.dup
663
- tries += 1
664
- string = ''
665
- alpha_set = ALPHA_SET_LOWER + ALPHA_SET_CAPITAL
666
- string_set = alpha_set + NUMBER_SET + ['.'] + ['_'] + ['-']
667
- string_set_not_allowed = all_characters_set - string_set
668
-
669
- extension = '.'
670
- at_sign = '@'
671
-
672
- if expected_errors_left.include?(:value)
673
- if rand(2) == 1
674
- extension = (all_characters_set - ['.']).sample
675
- expected_errors_left.delete(:value)
676
- expected_errors_left.delete(:required_data)
677
- end
678
- if rand(2) == 1
679
- 1.upto(rand(7)) {|i| extension << alpha_set.sample.downcase
680
- }
681
- (rand(extension.size) + 1).times {
682
- extension[rand(extension.size)] = (string_set - alpha_set - ['.']).sample
683
- }
684
- expected_errors_left.delete(:value)
685
- else
686
- 1.upto(rand(3) + 2) {|i| extension << alpha_set.sample.downcase
687
- }
688
- end
689
- if rand(2) == 1
690
- at_sign = (string_set - ['@']).sample
691
- expected_errors_left.delete(:value)
692
- expected_errors_left.delete(:required_data)
693
- end
694
- else
695
- if length > 6
696
- 1.upto(rand(3) + 2) {|i| extension << alpha_set.sample.downcase
697
- }
698
- else
699
- 1.upto(2) {|i| extension << alpha_set.sample.downcase
700
- }
701
- end
702
- end
703
- length_e = length - extension.size - 1
704
- length1 = rand(length_e - 1) + 1
705
- length2 = length_e - length1
706
- 1.upto(length1) {|i| string << string_set.sample}
707
-
708
- string << at_sign
709
-
710
- domain = ''
711
- domain_set = alpha_set + NUMBER_SET + ['.'] + ['-']
712
- 1.upto(length2) {|i| domain << domain_set.sample.downcase
713
- }
714
-
715
- if expected_errors.include?(:value) and rand(2) == 1 and domain.size > 0
716
- (rand(domain.size) + 1).times {
717
- domain[rand(domain.size)] = (all_characters_set - domain_set).sample
718
- }
719
- expected_errors_left.delete(:value)
720
- end
721
- string << domain << extension
722
-
723
- if expected_errors_left.include?(:value) or expected_errors_left.include?(:string_set_not_allowed)
724
- (rand(string.size) + 1).times {
725
- string[rand(string.size)] = string_set_not_allowed.sample
726
- }
727
- expected_errors_left.delete(:value)
728
- expected_errors_left.delete(:string_set_not_allowed)
729
- end
730
-
731
- error_regular_expression = false
732
-
733
- if deny_pattern and expected_errors.include?(:length)
734
- good_result = true #it is already with wrong length
735
- else
736
- # I'm doing this because many times the regular expression checking hangs with these characters
737
- wrong = %w(.. __ -- ._ _. .- -. _- -_ @. @_ @- .@ _@ -@ @@)
738
- if !(Regexp.union(*wrong) === string) #don't include any or the wrong strings
739
- if string.index('@').to_i > 0 and
740
- string[0..(string.index('@') - 1)].scan(/([a-z0-9]+([\+\._\-][a-z0-9]|)*)/i).join == string[0..(string.index('@') - 1)] and
741
- string[(string.index('@') + 1)..-1].scan(/([0-9a-z]+([\.-][a-z0-9]|)*)/i).join == string[string[(string.index('@') + 1)..-1]]
742
- error_regular_expression = false
743
- else
744
- error_regular_expression = true
745
- end
746
- else
747
- error_regular_expression = true
748
- end
749
-
750
- if expected_errors.size == 0
751
- if error_regular_expression
752
- good_result = false
753
- else
754
- good_result = true
755
- end
756
- elsif expected_errors_left.size == 0 and
757
- (expected_errors - [:length, :min_length, :max_length]).size == 0
758
- good_result = true
759
- elsif expected_errors != [:length]
760
- if !error_regular_expression
761
- good_result = false
762
- elsif expected_errors.include?(:value)
763
- good_result = true
764
- end
765
- end
766
- end
767
-
768
- end until good_result or tries > 100
769
- unless good_result
770
- puts "Not possible to generate an email on StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}"
771
- return ''
772
- end
773
- end
774
- if @dont_repeat
775
- if @cache_values[pattern.to_s].nil?
776
- @cache_values[pattern.to_s] = Array.new()
777
- @cache_values[pattern.to_s].push(string)
778
- good_result = true
779
- elsif @cache_values[pattern.to_s].include?(string)
780
- good_result = false
781
- else
782
- @cache_values[pattern.to_s].push(string)
783
- good_result = true
784
- end
785
- end
786
- if pattern.kind_of?(Symbol) and patt.unique
787
- if @cache_values[pattern.__id__].nil?
788
- @cache_values[pattern.__id__] = Array.new()
789
- @cache_values[pattern.__id__].push(string)
790
- good_result = true
791
- elsif @cache_values[pattern.__id__].include?(string)
792
- good_result = false
793
- else
794
- @cache_values[pattern.__id__].push(string)
795
- good_result = true
796
- end
797
- end
798
- end until good_result or tries > 10000
799
- unless good_result
800
- puts "Not possible to generate the string on StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}"
801
- puts "Take 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"
802
- return ''
803
- end
804
-
805
- return string
806
- end
807
-
808
-
809
- ##############################################
810
- # This method is defined to validate if the text_to_validate supplied follows the pattern
811
- # It works also with array of patterns but in that case will return only true or false
812
- # input:
813
- # text (String) (synonyms: text_to_validate, validate) -- The text to validate
814
- # pattern -- symbol with this info: "length:symbol_type" or "min_length-max_length:symbol_type"
815
- # min_length -- minimum length of the string
816
- # max_length (optional) -- maximum length of the string. If not provided the result will be with the min_length provided
817
- # symbol_type -- the type of the string we want.
818
- # expected_errors (Array of symbols) (optional) (synonyms: errors) -- :length, :min_length, :max_length, :value, :required_data, :excluded_data, :string_set_not_allowed
819
- # not_expected_errors (Array of symbols) (optional) (synonyms: not_errors, non_expected_errors) -- :length, :min_length, :max_length, :value, :required_data, :excluded_data, :string_set_not_allowed
820
- # example:
821
- # validate(text: "This text will be validated", pattern: :"10-20:Xn", expected_errors: [:value, :max_length])
822
- #
823
- # Output:
824
- # if expected_errors and not_expected_errors are not supplied: an array with all detected errors
825
- # if expected_errors or not_expected_errors supplied: true or false
826
- # if array of patterns supplied, it will return true or false
827
- ###############################################
828
- def StringPattern.validate(text: '', pattern: '', expected_errors: [], not_expected_errors: [], **synonyms)
829
- text_to_validate = text
830
- text_to_validate = synonyms[:text_to_validate] if synonyms.keys.include?(:text_to_validate)
831
- text_to_validate = synonyms[:validate] if synonyms.keys.include?(:validate)
832
- expected_errors = synonyms[:errors] if synonyms.keys.include?(:errors)
833
- not_expected_errors = synonyms[:not_errors] if synonyms.keys.include?(:not_errors)
834
- not_expected_errors = synonyms[:non_expected_errors] if synonyms.keys.include?(:non_expected_errors)
835
- #:length, :min_length, :max_length, :value, :required_data, :excluded_data, :string_set_not_allowed
836
- if (expected_errors.include?(:min_length) or expected_errors.include?(:max_length)) and !expected_errors.include?(:length)
837
- expected_errors.push(:length)
838
- end
839
- if (not_expected_errors.include?(:min_length) or not_expected_errors.include?(:max_length)) and !not_expected_errors.include?(:length)
840
- not_expected_errors.push(:length)
841
- end
842
- if pattern.kind_of?(Array) and pattern.size == 1
843
- pattern = pattern[0]
844
- elsif pattern.kind_of?(Array) and pattern.size > 1 then
845
- total_min_length = 0
846
- total_max_length = 0
847
- all_errors_collected = Array.new
848
- result = true
849
- num_patt = 0
850
- patterns = Array.new
851
- pattern.each {|pat|
852
- if (pat.kind_of?(String) and (!StringPattern.optimistic or
853
- (StringPattern.optimistic and pat.to_s.scan(/(\d+)-(\d+):(.+)/).size == 0 and pat.to_s.scan(/^!?(\d+):(.+)/).size == 0))) #fixed text
854
- symbol_type = ''
855
- min_length = max_length = pat.length
856
- elsif pat.kind_of?(Symbol) or (pat.kind_of?(String) and StringPattern.optimistic and
857
- (pat.to_s.scan(/(\d+)-(\d+):(.+)/).size > 0 or pat.to_s.scan(/^!?(\d+):(.+)/).size > 0))
858
- patt = StringPattern.analyze(pat)
859
- min_length = patt.min_length
860
- max_length = patt.max_length
861
- symbol_type = patt.symbol_type
862
- else
863
- puts "String pattern class not supported (#{pat.class} for #{pat})"
864
- end
865
-
866
- patterns.push({pattern: pat, min_length: min_length, max_length: max_length, symbol_type: symbol_type})
867
-
868
- total_min_length += min_length
869
- total_max_length += max_length
870
-
871
- if num_patt == (pattern.size - 1) # i am in the last one
872
- if text_to_validate.length < total_min_length
873
- all_errors_collected.push(:length)
874
- all_errors_collected.push(:min_length)
875
- end
876
-
877
- if text_to_validate.length > total_max_length
878
- all_errors_collected.push(:length)
879
- all_errors_collected.push(:max_length)
880
- end
881
-
882
- end
883
- num_patt += 1
884
-
885
-
886
- }
887
-
888
- num_patt = 0
889
- patterns.each {|patt|
890
-
891
- tmp_result = false
892
- (patt[:min_length]..patt[:max_length]).each {|n|
893
- res = StringPattern.validate(text: text_to_validate[0..n - 1], pattern: patt[:pattern], not_expected_errors: not_expected_errors)
894
- if res.kind_of?(Array)
895
- all_errors_collected += res
896
- end
897
-
898
- if res.kind_of?(TrueClass) or (res.kind_of?(Array) and res.size == 0) #valid
899
- #we pass in the next one the rest of the pattern array list: pattern: pattern[num_patt+1..pattern.size]
900
- res = StringPattern.validate(text: text_to_validate[n..text_to_validate.length], pattern: pattern[num_patt + 1..pattern.size], expected_errors: expected_errors, not_expected_errors: not_expected_errors)
901
-
902
- if res.kind_of?(Array)
903
- if ((all_errors_collected + res) - expected_errors).size > 0
904
- tmp_result = false
905
- else
906
- all_errors_collected += res
907
- tmp_result = true
908
- end
909
- elsif res.kind_of?(TrueClass) then
910
- tmp_result = true
911
- end
912
- return true if tmp_result
913
- end
914
- }
915
-
916
- unless tmp_result
917
- return false
918
- end
919
- num_patt += 1
920
- }
921
- return result
922
- end
923
-
924
- if (pattern.kind_of?(String) and (!StringPattern.optimistic or
925
- (StringPattern.optimistic and pattern.to_s.scan(/(\d+)-(\d+):(.+)/).size == 0 and pattern.to_s.scan(/^!?(\d+):(.+)/).size == 0))) #fixed text
926
- symbol_type = ''
927
- min_length = max_length = pattern.length
928
- else #symbol
929
- patt = StringPattern.analyze(pattern)
930
- min_length = patt.min_length
931
- max_length = patt.max_length
932
- symbol_type = patt.symbol_type
933
-
934
- required_data = patt.required_data
935
- excluded_data = patt.excluded_data
936
- string_set = patt.string_set
937
- all_characters_set = patt.all_characters_set
938
-
939
- required_chars = Array.new
940
- required_data.each {|rd|
941
- required_chars << rd if rd.size == 1
942
- }
943
- if (required_chars.flatten & excluded_data.flatten).size > 0
944
- puts "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}"
945
- return ''
946
- end
947
-
948
- end
949
-
950
- if text_to_validate.nil?
951
- return false
952
- end
953
- detected_errors = Array.new
954
-
955
- if text_to_validate.length < min_length
956
- detected_errors.push(:min_length)
957
- detected_errors.push(:length)
958
- end
959
- if text_to_validate.length > max_length
960
- detected_errors.push(:max_length)
961
- detected_errors.push(:length)
962
- end
963
-
964
- if symbol_type == '' #fixed text
965
- if pattern.to_s != text.to_s #not equal
966
- detected_errors.push(:value)
967
- detected_errors.push(:required_data)
968
- end
969
- else # pattern supplied
970
- if symbol_type != '@'
971
- if required_data.size > 0
972
- required_data.each {|rd|
973
- if (text_to_validate.chars & rd).size == 0
974
- detected_errors.push(:value)
975
- detected_errors.push(:required_data)
976
- break
977
- end
978
- }
979
- end
980
- if excluded_data.size > 0
981
- if (excluded_data & text_to_validate.chars).size > 0
982
- detected_errors.push(:value)
983
- detected_errors.push(:excluded_data)
984
- end
985
- end
986
- string_set_not_allowed = all_characters_set - string_set
987
- text_to_validate.chars.each {|st|
988
- if string_set_not_allowed.include?(st)
989
- detected_errors.push(:value)
990
- detected_errors.push(:string_set_not_allowed)
991
- break
992
- end
993
- }
994
- else #symbol_type=="@"
995
- string = text_to_validate
996
- wrong = %w(.. __ -- ._ _. .- -. _- -_ @. @_ @- .@ _@ -@ @@)
997
- if !(Regexp.union(*wrong) === string) #don't include any or the wrong strings
998
- if string.index('@').to_i > 0 and
999
- string[0..(string.index('@') - 1)].scan(/([a-z0-9]+([\+\._\-][a-z0-9]|)*)/i).join == string[0..(string.index('@') - 1)] and
1000
- string[(string.index('@') + 1)..-1].scan(/([0-9a-z]+([\.-][a-z0-9]|)*)/i).join == string[string[(string.index('@') + 1)..-1]]
1001
- error_regular_expression = false
1002
- else
1003
- error_regular_expression = true
1004
- end
1005
- else
1006
- error_regular_expression = true
1007
- end
1008
-
1009
- if error_regular_expression
1010
- detected_errors.push(:value)
1011
- end
1012
-
1013
- end
1014
- end
1015
-
1016
- if expected_errors.size == 0 and not_expected_errors.size == 0
1017
- return detected_errors
1018
- else
1019
- if expected_errors & detected_errors == expected_errors
1020
- if (not_expected_errors & detected_errors).size > 0
1021
- return false
1022
- else
1023
- return true
1024
- end
1025
- else
1026
- return false
1027
- end
1028
- end
1029
- end
1030
-
1031
59
  end
1032
-