string_pattern 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: da42289c954a52372acd4df016416a501476ae07a272c8f5b06ef7966165183c
4
+ data.tar.gz: b491b377808a1f0211e3bdfb9812b54f1d0b223f85fa5af1a61f2dd0c510fe71
5
+ SHA512:
6
+ metadata.gz: 1609036dca1456ff1f3addfe8126c438de9aa70bcd333251531d97f8c05efd71cc2a5d64ed556ae890d62fa53c1037c8c8b196f2864006669e40f7c121472bf2
7
+ data.tar.gz: dd9463dafbed43c843b0a4397ea1e0feff7c10d5820640f8247b02e3cccf31de6ecdabcf979f3c83c9190a0879d63549f3eceeeff7d08c43389b3ce166b42b05
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Mario Ruiz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,298 @@
1
+ # StringPattern
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/string_pattern.svg)](https://rubygems.org/gems/string_pattern)
4
+
5
+ With this gem you can easily generate strings supplying a very simple pattern.
6
+ Also you can validate if a text fulfill an specific pattern or even generate a string following a pattern and returning wrong length, value... for testing your applications.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'string_pattern'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install string_pattern
23
+
24
+ ## Usage
25
+
26
+ ### What is a string pattern?
27
+
28
+ A pattern is a string where we supply these elements "a-b:c" where a is min_length, b is max_length (optional) and c is a set of symbol_type
29
+
30
+ min_length: minimum length of the string
31
+
32
+ max_length (optional): maximum length of the string. If not provided, the result will be with the min_length provided
33
+
34
+ symbol_type: The type of the string we want.
35
+ x: from a to z (lowercase)
36
+ X: A to Z (capital letters)
37
+ L: A to Z and a to z
38
+ T: National characters defined on StringPattern.national_chars
39
+ n or N: for numbers. 0 to 9
40
+ $: special characters, $%&#... (includes blank space)
41
+ _: blank space
42
+ *: all characters
43
+ 0: empty string will be accepted. It needs to be at the beginning of the symbol_type string
44
+ @: It will generate a valid email following the official algorithm. It cannot be used with other symbol_type
45
+
46
+ ### How to generate a string following a pattern
47
+
48
+ To generate a string following a pattern you can do it using directly the StringPattern class or the generate method in the class, be aware you can always use also the alias method: gen
49
+
50
+ ```ruby
51
+ require 'string_pattern'
52
+
53
+ #StringPattern class
54
+ p StringPattern.generate "10:N"
55
+ #>3448910834
56
+ p StringPattern.gen "5:X"
57
+ #>JDDDK
58
+
59
+ #String class
60
+ p "4:Nx".gen
61
+ #>xaa3
62
+
63
+ #Symbol class
64
+ p :"10:T".generate
65
+ #>AccBdjklñD
66
+
67
+ #Array class
68
+ p [:"3:N", "fixed", :"3:N"].gen
69
+ #>334fixed920
70
+ p "(,3:N,) ,3:N,-,2:N,-,2:N".split(',').generate
71
+ #>(937) 980-65-05
72
+
73
+ #Kernel
74
+ p gen "3:N"
75
+ #>443
76
+ ```
77
+
78
+ #### Custom characters
79
+
80
+ Also it's possible to provided the characters we want. To do that we'll use the symbol_type [characters]
81
+
82
+ If we want to add the character ] we have to write ]]
83
+
84
+ Examples
85
+
86
+ ```ruby
87
+ # four chars from the ones provided: asDF9
88
+ p "4:[asDF9]".gen #> aaaa, asFF, 9sFD
89
+
90
+ # from 2 to 20 chars, capital and lower chars (Xx) and also valid the characters $#6
91
+ p "2-20:[$#6]Xx".gen #> aaaa, asFF, 66, B$DkKL#9aDD
92
+
93
+ # four chars from these: asDF]9
94
+ p "4:[asDF]]9]".gen #> aa]a, asFF, 9s]D
95
+ ```
96
+
97
+ #### Required characters or symbol types
98
+
99
+ We'll use the symbol / to specify which characters or symbols we want to be included on the resulting string as required values /symbols or characters/
100
+
101
+ If we need to add the character / we'll use //
102
+
103
+ Examples:
104
+
105
+ ```ruby
106
+ # four characters. optional: capitals and numbers, required: lower
107
+ "4:XN/x/".gen # aaaa, FF9b, j4em, asdf, ADFt
108
+
109
+ # from 6 to 15 chars. optional: numbers, capitals and the chars $ and Æ. required the chars: 23abCD
110
+ "6-15:[/23abCD/$Æ]NX".gen # bCa$D32, 32DJIOKLaCb, b23aD568C
111
+
112
+ # from 4 to 9 chars. optional: numbers and capitals. required: lowers and the characters $ and 5
113
+ "4-9:[/$5/]XN/x/".generate # aa5$, F5$F9b, j$4em5, a5sdf$, $ADFt5
114
+ ```
115
+
116
+ #### Excluded characters
117
+
118
+ If we want to exclude a few characters in the result, we'll use the symbol %characters%
119
+
120
+ If you need to exclude the character %, you should use %%
121
+
122
+ Examples:
123
+
124
+ ```ruby
125
+ # from 2 to 20 characters. optional: Numbers and characters A, B and C. excluded: the characters 8 and 3
126
+ "2-20:[%83%ABC]N".gen # B49, 22900, 9CAB, 22, 11CB6270C26C4572A50C
127
+
128
+ # 10 chars. optional: Letters (capital and lower). required: numbers. excluded: the characters 0 and WXYzZ
129
+ "10:L/n/[%0WXYzZ%]".gen # GoO2ukCt4l, Q1Je2remFL, qPg1T92T2H, 4445556781
130
+ ```
131
+
132
+ #### Not fulfilling a pattern
133
+
134
+ If we want our resulting string doesn't fulfill the pattern we supply, then we'll use the symbol ! at the beginning
135
+
136
+ Examples:
137
+
138
+ ```ruby
139
+ "!4:XN/x/".gen # a$aaa, FF9B, j4DDDem, as, 2345
140
+
141
+ "!10:N".gen # 123, 34899Add34, 3434234234234008, AAFj#kd2x
142
+ ```
143
+
144
+ ### Generate a string with specific expected errors
145
+
146
+ Usually for testing purposes you need to generate strings that don't fulfill an specific pattern, then you can supply as a parameter expected_errors (alias: errors)
147
+
148
+ The possible values you can specify is one or more of these ones: :length, :min_length, :max_length, :value, :required_data, :excluded_data, :string_set_not_allowed
149
+
150
+ :length: wrong length, minimum or maximum
151
+ :min_length: wrong minimum length
152
+ :max_length: wrong maximum length
153
+ :value: wrong resultant value
154
+ :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.
155
+ :excluded_data: the resultant string will include one or more characters that should be excluded. It works only if excluded data supplied on the pattern.
156
+ :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.
157
+
158
+ Examples:
159
+
160
+ ```ruby
161
+ "10-20:N".gen errors: [:min_length]
162
+ #> 627, 098262, 3408
163
+
164
+ "20:N".gen errors: [:length, :value]
165
+ #> |13, tS1b)r-1)<RT65202eTo6bV0g~, 021400323<2ahL0NP86a698063*56076
166
+
167
+ "10:L/n/".gen errors: [:value]
168
+ #> 1hwIw;v{KQ, mpk*l]!7:!, wocipgZt8@
169
+ ```
170
+
171
+ ### Validate if a string is following a pattern
172
+
173
+ If you need to validate if a specific text is fulfilling the pattern you can use the validate method.
174
+
175
+ If a string pattern supplied and no other parameters supplied the output will be an array with the errors detected.
176
+
177
+
178
+ 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
179
+
180
+ In case an array of patterns supplied it will return only true or false
181
+
182
+ Examples:
183
+
184
+ ```ruby
185
+ #StringPattern class
186
+ StringPattern.validate((text: "This text will be validated", pattern: :"10-20:Xn")
187
+ #> [:max_length, :length, :value, :string_set_not_allowed]
188
+
189
+ #String class
190
+ "10:N".validate "333444"
191
+ #> [:min_length, :length]
192
+
193
+ #Symbol class
194
+ :"10:N".validate("333444")
195
+ #> [:min_length, :length]
196
+
197
+ #Array class
198
+ ["5:L","3:xn","4-10:n"].validate "DjkljFFc343444390"
199
+ #> false
200
+ ```
201
+
202
+ If we want to validate a string with a pattern and we are expecting to get specific errors, you can supply the parameter expected_errors (alias: errors) or not_expected_errors (aliases: non_expected_errors, not_errors).
203
+
204
+ In this case the validate method will return true or false.
205
+
206
+ Examples:
207
+
208
+ ```ruby
209
+ "10:N".val "3445", errors: [:min_length]
210
+ #> true
211
+
212
+ "10:N/[09]/".validate "4434039440", errors: [:value]
213
+ #> false
214
+
215
+ "10-12:XN/x/".validate "FDDDDDAA343434", errors: [:max_length, :required_data]
216
+ #> true
217
+ ```
218
+
219
+ ### Configure
220
+
221
+ #### SP_ADD_TO_RUBY
222
+
223
+ This gem adds the methods generate (alias: gen) and validate (alias: val) to the Ruby classes: String, Array and Symbol.
224
+
225
+ Also adds the method generate (alias: gen) to Kernel. By default (true) it is always added.
226
+
227
+ In case you don't want to be added, just before requiring the library set:
228
+
229
+ ```ruby
230
+ SP_ADD_TO_RUBY = false
231
+ require 'string_pattern'
232
+ ```
233
+
234
+ In case it is set to true (default) then you will be able to use:
235
+
236
+ ```ruby
237
+ require 'string_pattern'
238
+
239
+ #String object
240
+ "20-30:@".gen
241
+ #>dkj34MljjJD-df@jfdluul.dfu
242
+
243
+ "10:L/N/[/-./%d%]".validate("12ds6f--.s")
244
+ #>[:value, :string_set_not_allowed]
245
+
246
+ "20-40:@".validate(my_email)
247
+
248
+ #Kernel
249
+ gen "10:N"
250
+ #>3433409877
251
+
252
+ #Array object
253
+ "(,3:N,) ,3:N,-,2:N,-,2:N".split(",").generate
254
+ #>(937) 980-65-05
255
+
256
+ %w{( 3:N ) 1:_ 3:N - 2:N - 2:N}.gen
257
+ #>(045) 448-63-09
258
+
259
+ ["1:L", "5-10:LN", "-", "3:N"].gen
260
+ #>zqWihV-746
261
+ ```
262
+
263
+ #### national_chars
264
+
265
+ To specify which national characters will be used when using the symbol type: T, you use StringPattern.national_chars, by default is the English alphabet
266
+
267
+ ```ruby
268
+ StringPattern.national_chars = (('a'..'z').to_a + ('A'..'Z').to_a).join + "áéíóúÁÉÍÓÚüÜñÑ"
269
+ "10-20:Tn".gen #>AAñ34Ef99éNOP
270
+ ```
271
+
272
+ #### optimistic
273
+
274
+ If true it will check on the strings of the array positions supplied if they have the pattern format and assume in that case that is a pattern. If not it will assume the patterns on the array will be supplied as symbols. By default is set to true.
275
+
276
+ ```ruby
277
+ StringPattern.optimistic = false
278
+ ["5:X","fixedtext", "3:N"].generate
279
+ #>5:Xfixedtext3:N
280
+ [:"5:X","fixedtext", :"3:N"].generate
281
+ #>AUJKJfixedtext454
282
+
283
+ StringPattern.optimistic = true
284
+ ["5:X","fixedtext", "3:N"].generate
285
+ #>KKDMEfixedtext344
286
+ [:"5:X","fixedtext", :"3:N"].generate
287
+ #>SAAERfixedtext988
288
+ ```
289
+
290
+ ## Contributing
291
+
292
+ Bug reports and pull requests are welcome on GitHub at https://github.com/marioruiz/string_pattern.
293
+
294
+
295
+ ## License
296
+
297
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
298
+
@@ -0,0 +1,67 @@
1
+ class Array
2
+ # It will generate an string following the pattern specified
3
+ # The positions with string patterns need to be supplied like symbols:
4
+ # [:"10:N", "fixed", :"10-20:XN/x/"].generate #> "1024320001fixed4OZjNMTnuBibwwj"
5
+ def generate(expected_errors: [], **synonyms)
6
+ StringPattern.generate(self, expected_errors: expected_errors, **synonyms)
7
+ end
8
+
9
+ alias_method :gen, :generate
10
+
11
+ # it will validate an string following the pattern specified
12
+ def validate(string_to_validate, expected_errors: [], not_expected_errors: [], **synonyms)
13
+ StringPattern.validate(text: string_to_validate, pattern: self, expected_errors: expected_errors, not_expected_errors: not_expected_errors, **synonyms)
14
+ end
15
+
16
+ alias_method :val, :validate
17
+ end
18
+
19
+ class String
20
+ # it will generate an string following the pattern specified
21
+ def generate(expected_errors: [], **synonyms)
22
+ StringPattern.generate(self, expected_errors: expected_errors, **synonyms)
23
+ end
24
+
25
+ alias_method :gen, :generate
26
+
27
+ # it will validate an string following the pattern specified
28
+ def validate(string_to_validate, expected_errors: [], not_expected_errors: [], **synonyms)
29
+ StringPattern.validate(text: string_to_validate, pattern: self, expected_errors: expected_errors, not_expected_errors: not_expected_errors, **synonyms)
30
+ end
31
+
32
+ alias_method :val, :validate
33
+ end
34
+
35
+
36
+ class Symbol
37
+ # it will generate an string following the pattern specified
38
+ def generate(expected_errors: [], **synonyms)
39
+ StringPattern.generate(self, expected_errors: expected_errors, **synonyms)
40
+ end
41
+
42
+ alias_method :gen, :generate
43
+
44
+ # it will validate an string following the pattern specified
45
+ def validate(string_to_validate, expected_errors: [], not_expected_errors: [], **synonyms)
46
+ StringPattern.validate(text: string_to_validate, pattern: self.to_s, expected_errors: expected_errors, not_expected_errors: not_expected_errors, **synonyms)
47
+ end
48
+
49
+ alias_method :val, :validate
50
+ end
51
+
52
+
53
+ module Kernel
54
+ public
55
+ # if string or symbol supplied it will generate a string with the supplied pattern specified on the string
56
+ # if array supplied then it will generate a string with the supplied patterns. If a position contains a pattern supply it as symbol, for example: [:"10:N", "fixed", :"10-20:XN/x/"]
57
+ def generate(pattern, expected_errors: [], **synonyms)
58
+ if pattern.kind_of?(String) or pattern.kind_of?(Array) or pattern.kind_of?(Symbol)
59
+ StringPattern.generate(pattern, expected_errors: expected_errors, **synonyms)
60
+ else
61
+ puts " Kernel generate method: class not recognized:#{pattern.class}"
62
+ end
63
+ end
64
+
65
+ alias_method :gen, :generate
66
+ end
67
+
@@ -0,0 +1,859 @@
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
3
+
4
+ # 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
+ # If true it will add 'generate' and 'validate' methods to the classes: Array, String and Symbol. Also it will add 'generate' method to Kernel
6
+ # aliases: 'gen' for 'generate' and 'val' for 'validate'
7
+ # Examples of use:
8
+ # "(,3:N,) ,3:N,-,2:N,-,2:N".split(",").generate #>(937) 980-65-05
9
+ # %w{( 3:N ) 1:_ 3:N - 2:N - 2:N}.gen #>(045) 448-63-09
10
+ # ["1:L", "5-10:LN", "-", "3:N"].gen #>zqWihV-746
11
+ # gen("10:N") #>3433409877
12
+ # "20-30:@".gen #>dkj34MljjJD-df@jfdluul.dfu
13
+ # "10:L/N/[/-./%d%]".validate("12ds6f--.s") #>[:value, :string_set_not_allowed]
14
+ # "20-40:@".validate(my_email)
15
+ # national_chars: (Array, default: english alphabet)
16
+ # Set of characters that will be used when using T pattern
17
+ # optimistic: (TrueFalse, default: true)
18
+ # If true it will check on the strings of the array positions if they have the pattern format and assume in that case that is a pattern.
19
+ class StringPattern
20
+ class << self
21
+ attr_accessor :national_chars, :optimistic
22
+ end
23
+ @national_chars = (('a'..'z').to_a + ('A'..'Z').to_a).join
24
+ @optimistic = true
25
+ NUMBER_SET = ('0'..'9').to_a
26
+ SPECIAL_SET = [' ', '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '+', '=', '{', '}', '[', ']', "'", ';', ':', '?', '>', '<', '`', '|', '/', '"']
27
+ ALPHA_SET_LOWER = ('a'..'z').to_a
28
+ ALPHA_SET_CAPITAL = ('A'..'Z').to_a
29
+
30
+
31
+ Pattern = Struct.new(:min_length, :max_length, :symbol_type, :required_data, :excluded_data, :data_provided,
32
+ :string_set, :all_characters_set)
33
+
34
+ ###############################################
35
+ # Analyze the pattern supplied and returns an object of Pattern structure including:
36
+ # min_length, max_length, symbol_type, required_data, excluded_data, data_provided, string_set, all_characters_set
37
+ ###############################################
38
+ def StringPattern.analyze(pattern, silent:false)
39
+ min_length, max_length, symbol_type=pattern.to_s.scan(/(\d+)-(\d+):(.+)/)[0]
40
+ if min_length.nil?
41
+ min_length, symbol_type=pattern.to_s.scan(/^!?(\d+):(.+)/)[0]
42
+ max_length=min_length
43
+ if min_length.nil?
44
+ puts "pattern argument not valid on StringPattern.generate: #{pattern.inspect}" unless silent
45
+ return pattern.to_s
46
+ end
47
+ end
48
+ symbol_type='!'+symbol_type if pattern.to_s[0]=='!'
49
+ min_length=min_length.to_i
50
+ max_length=max_length.to_i
51
+
52
+ required_data=Array.new
53
+ excluded_data=Array.new
54
+ required=false
55
+ excluded=false
56
+ data_provided=Array.new
57
+ a=symbol_type
58
+ begin_provided=a.index('[')
59
+ excluded_end_tag=false
60
+ if begin_provided!=nil
61
+ c=begin_provided+1
62
+ until c==a.size or (a[c..c]==']' and a[c..c+1]!=']]')
63
+ if a[c..c+1]==']]'
64
+ data_provided.push(']')
65
+ c=c+2
66
+ elsif a[c..c+1]=='%%' and !excluded then
67
+ data_provided.push('%')
68
+ c=c+2
69
+ else
70
+ if a[c..c]=='/' and !excluded
71
+ if a[c..c+1]=='//'
72
+ data_provided.push(a[c..c])
73
+ if required
74
+ required_data.push([a[c..c]])
75
+ end
76
+ c=c+1
77
+ else
78
+ if !required
79
+ required=true
80
+ else
81
+ required=false
82
+ end
83
+ end
84
+ else
85
+ if required
86
+ required_data.push([a[c..c]])
87
+ else
88
+ if a[c..c]=='%'
89
+ if a[c..c+1]=='%%' and excluded
90
+ excluded_data.push([a[c..c]])
91
+ c=c+1
92
+ else
93
+ if !excluded
94
+ excluded=true
95
+ else
96
+ excluded=false
97
+ excluded_end_tag=true
98
+ end
99
+ end
100
+ else
101
+ if excluded
102
+ excluded_data.push([a[c..c]])
103
+ end
104
+ end
105
+
106
+ end
107
+ if excluded==false and excluded_end_tag==false
108
+ data_provided.push(a[c..c])
109
+ end
110
+ excluded_end_tag=false
111
+ end
112
+ c=c+1
113
+ end
114
+ end
115
+ symbol_type=symbol_type[0..begin_provided].to_s + symbol_type[c..symbol_type.size].to_s
116
+ end
117
+
118
+ required=false
119
+ required_symbol=''
120
+ symbol_type.split(//).each {|stc|
121
+ if stc=='/'
122
+ if !required
123
+ required=true
124
+ else
125
+ required=false
126
+ end
127
+ else
128
+ if required
129
+ required_symbol+=stc
130
+ end
131
+ end
132
+ }
133
+ national_set=@national_chars.split(//)
134
+
135
+ if !symbol_type['x'].nil?
136
+ alpha_set=ALPHA_SET_LOWER
137
+ unless symbol_type['X'].nil?
138
+ alpha_set = alpha_set + ALPHA_SET_CAPITAL
139
+ end
140
+ else
141
+ if !symbol_type['X'].nil?
142
+ alpha_set=ALPHA_SET_CAPITAL
143
+ elsif !symbol_type['L'].nil? then
144
+ alpha_set = ALPHA_SET_LOWER + ALPHA_SET_CAPITAL
145
+ else
146
+ alpha_set = ALPHA_SET_LOWER + ALPHA_SET_CAPITAL
147
+ end
148
+ end
149
+ unless symbol_type['T'].nil?
150
+ alpha_set=alpha_set+national_set
151
+ end
152
+
153
+ unless required_symbol['x'].nil?
154
+ required_data.push ALPHA_SET_LOWER
155
+ end
156
+ unless required_symbol['X'].nil?
157
+ required_data.push ALPHA_SET_CAPITAL
158
+ end
159
+ unless required_symbol['L'].nil?
160
+ required_data.push(ALPHA_SET_CAPITAL+ALPHA_SET_LOWER)
161
+ end
162
+ unless required_symbol['T'].nil?
163
+ required_data.push national_set
164
+ end
165
+ required_symbol=required_symbol.downcase
166
+ string_set=Array.new
167
+ all_characters_set=ALPHA_SET_CAPITAL+ALPHA_SET_LOWER+NUMBER_SET+SPECIAL_SET+data_provided+national_set
168
+
169
+ unless symbol_type['_'].nil?
170
+ if symbol_type['$'].nil?
171
+ string_set.push(' ')
172
+ end
173
+ unless required_symbol['_'].nil?
174
+ required_data.push([' '])
175
+ end
176
+ end
177
+
178
+ symbol_type = symbol_type.downcase
179
+
180
+ if !symbol_type['x'].nil? or !symbol_type['l'].nil? or !symbol_type['t'].nil?
181
+ string_set = string_set + alpha_set
182
+ end
183
+ unless symbol_type['n'].nil?
184
+ string_set = string_set + NUMBER_SET
185
+ end
186
+ unless symbol_type['$'].nil?
187
+ string_set = string_set + SPECIAL_SET
188
+ end
189
+ unless symbol_type['*'].nil?
190
+ string_set = string_set+all_characters_set
191
+ end
192
+ if data_provided.size!=0
193
+ string_set = string_set + data_provided
194
+ end
195
+ unless required_symbol['n'].nil?
196
+ required_data.push NUMBER_SET
197
+ end
198
+ unless required_symbol['$'].nil?
199
+ required_data.push SPECIAL_SET
200
+ end
201
+ if excluded_data.size>0
202
+ string_set=string_set-excluded_data.flatten
203
+ end
204
+ string_set.uniq!
205
+ return Pattern.new(min_length, max_length, symbol_type, required_data, excluded_data, data_provided,
206
+ string_set, all_characters_set)
207
+ end
208
+
209
+ ###############################################
210
+ # Generate a random string based on the pattern supplied
211
+ # (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:
212
+ # "10-15:Ln/x/".generate #generate method on String class (alias: gen)
213
+ # ['(', :'3:N', ')', :'6-8:N'].generate #generate method on Array class (alias: gen)
214
+ # generate("10-15:Ln/x/") #generate Ruby Kernel method
215
+ # generate(['(', :'3:N', ')', :'6-8:N']) #generate Ruby Kernel method
216
+ # "(,3:N,) ,3:N,-,2:N,-,2:N".split(",").generate #>(937) #generate method on Array class (alias: gen)
217
+ # %w{( 3:N ) 1:_ 3:N - 2:N - 2:N}.gen #generate method on Array class, using alias gen method
218
+ # Input:
219
+ # pattern: array or string of different patterns. A pattern is a string with this info:
220
+ # "length:symbol_type" or "min_length-max_length:symbol_type"
221
+ # In case an array supplied, the positions using a string pattern should be supplied as symbols if StringPattern.optimistic==false
222
+ #
223
+ # These are the possible string patterns you will be able to supply:
224
+ # 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.
225
+ # min_length -- minimum length of the string
226
+ # max_length (optional) -- maximum length of the string. If not provided the result will be with the min_length provided
227
+ # symbol_type -- the type of the string we want.
228
+ # you can use a combination of any ot these:
229
+ # x for alpha in lowercase
230
+ # X for alpha in capital letters
231
+ # L for all kind of alpha in capital and lower letters
232
+ # T For the national characters defined on StringPattern.national_chars
233
+ # n for number
234
+ # $ for special characters (includes space)
235
+ # _ for space
236
+ # * all characters
237
+ # [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: %%
238
+ # %characters% the characters we don't want on the resulting string. %% to exclude the character %
239
+ # /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: //
240
+ # We can supply 0 to allow empty strings, this character need to be at the beginning
241
+ # If you want to include the character " use \"
242
+ # If you want to include the character \ use \\
243
+ # If you want to include the character [ use \[
244
+ # Another uses: @ for email
245
+ # Examples:
246
+ # [:"6:X", :"3-8:_N"]
247
+ # # 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"
248
+ # [:"6-15:L_N", "fixed text", :"3:N"]
249
+ # # 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"
250
+ # "10-20:LN[=#]"
251
+ # # it will return a string of 10-20 characters containing Letters and/or numbers and/or the characters = and #, for example: eiyweQFWeL#do4Vl
252
+ # "30:TN_[#=]/x/"
253
+ # # 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
254
+ # "10:N[%0%]"
255
+ # # 10 characters length containing numbers and excluding the character 0, for example: 3523497757
256
+ # "10:N[%0%/AB/]"
257
+ # # 10 characters length containing numbers and excluding the character 0 and necessary to contain the characters A B, for example: 3AA4AA57BB
258
+ # "!10:N[%0%/AB/]"
259
+ # # it will generate a string that doesn't fulfill the pattern supplied, examples:
260
+ # # a6oMQ4JK9g
261
+ # # /Y<N6Aa[ae
262
+ # # 3444439A34B32
263
+ # "10:N[%0%/AB/]", errors: [:length]
264
+ # # it will generate a string following the pattern and with the errors supplied, in this case, length, example: AB44
265
+ # Output:
266
+ # the generated string
267
+ ###############################################
268
+ def StringPattern.generate(pattern, expected_errors: [], **synonyms)
269
+ string=''
270
+
271
+ expected_errors=synonyms[:errors] if synonyms.keys.include?(:errors)
272
+
273
+ if expected_errors.kind_of?(Symbol)
274
+ expected_errors=[expected_errors]
275
+ end
276
+
277
+ if pattern.kind_of?(Array)
278
+ pattern.each {|pat|
279
+ if pat.kind_of?(Symbol)
280
+ if pat.to_s.scan(/^!?\d+-?\d*:.+/).size>0
281
+ string<<StringPattern.generate(pat.to_s, expected_errors: expected_errors)
282
+ else
283
+ string<<pat.to_s
284
+ end
285
+ elsif pat.kind_of?(String) then
286
+ if @optimistic and pat.to_s.scan(/^!?\d+-?\d*:.+/).size>0
287
+ string<<StringPattern.generate(pat.to_s, expected_errors: expected_errors)
288
+ else
289
+ string<<pat
290
+ end
291
+ else
292
+ puts "StringPattern.generate: it seems you supplied wrong array of patterns: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}"
293
+ return ''
294
+ end
295
+ }
296
+ return string
297
+ elsif pattern.kind_of?(String) or pattern.kind_of?(Symbol)
298
+ patt=StringPattern.analyze(pattern)
299
+ min_length=patt.min_length
300
+ max_length=patt.max_length
301
+ symbol_type=patt.symbol_type
302
+
303
+ required_data=patt.required_data
304
+ excluded_data=patt.excluded_data
305
+ string_set=patt.string_set
306
+ all_characters_set=patt.all_characters_set
307
+
308
+ required_chars=Array.new
309
+ required_data.each {|rd|
310
+ required_chars<<rd if rd.size==1
311
+ }
312
+ if (required_chars.flatten & excluded_data.flatten).size>0
313
+ 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}"
314
+ return ''
315
+ end
316
+
317
+ string_set_not_allowed=all_characters_set-string_set
318
+
319
+ else
320
+ puts "pattern argument not valid on StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}"
321
+ return pattern.to_s
322
+ end
323
+
324
+ allow_empty=false
325
+ deny_pattern=false
326
+ if symbol_type[0..0]=='!'
327
+ deny_pattern=true
328
+ possible_errors=[:length, :value, :required_data, :excluded_data, :string_set_not_allowed]
329
+ (rand(possible_errors.size)+1).times {
330
+ expected_errors<<possible_errors.sample
331
+ }
332
+ expected_errors.uniq!
333
+ if symbol_type[1..1]=='0'
334
+ allow_empty=true
335
+ end
336
+ elsif symbol_type[0..0]=='0' then
337
+ allow_empty=true
338
+ end
339
+ if expected_errors.include?(:min_length) or expected_errors.include?(:length) or
340
+ expected_errors.include?(:max_length)
341
+ allow_empty=!allow_empty
342
+ elsif expected_errors.include?(:value) or
343
+ expected_errors.include?(:excluded_data) or
344
+ expected_errors.include?(:required_data) or
345
+ expected_errors.include?(:string_set_not_allowed) and allow_empty
346
+ allow_empty=false
347
+ end
348
+
349
+ length=min_length
350
+ symbol_type_orig=symbol_type
351
+
352
+ expected_errors_left=expected_errors.dup
353
+
354
+ symbol_type=symbol_type_orig
355
+
356
+ unless deny_pattern
357
+ if required_data.size==0 and expected_errors_left.include?(:required_data)
358
+ 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}"
359
+ return ''
360
+ end
361
+
362
+ if excluded_data.size==0 and expected_errors_left.include?(:excluded_data)
363
+ 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}"
364
+ return ''
365
+ end
366
+
367
+ if string_set_not_allowed.size==0 and expected_errors_left.include?(:string_set_not_allowed)
368
+ 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}"
369
+ return ''
370
+ end
371
+ end
372
+
373
+ if expected_errors_left.include?(:min_length) or
374
+ expected_errors_left.include?(:max_length) or
375
+ expected_errors_left.include?(:length)
376
+ if expected_errors_left.include?(:min_length) or
377
+ (min_length>0 and expected_errors_left.include?(:length) and rand(2)==0)
378
+ if min_length>0
379
+ if allow_empty
380
+ length=rand(min_length).to_i
381
+ else
382
+ length=rand(min_length-1).to_i+1
383
+ end
384
+ if required_data.size>length and required_data.size<min_length
385
+ length=required_data.size
386
+ end
387
+ expected_errors_left.delete(:length)
388
+ expected_errors_left.delete(:min_length)
389
+ else
390
+ 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}"
391
+ return ''
392
+ end
393
+ elsif expected_errors_left.include?(:max_length) or expected_errors_left.include?(:length)
394
+ length=max_length+1+rand(max_length).to_i
395
+ expected_errors_left.delete(:length)
396
+ expected_errors_left.delete(:max_length)
397
+ end
398
+ else
399
+ if allow_empty and rand(7)==1
400
+ length=0
401
+ else
402
+ if max_length==min_length
403
+ length=min_length
404
+ else
405
+ length=min_length + rand(max_length - min_length + 1)
406
+ end
407
+ end
408
+ end
409
+
410
+ if deny_pattern
411
+ if required_data.size==0 and expected_errors_left.include?(:required_data)
412
+ expected_errors_left.delete(:required_data)
413
+ end
414
+
415
+ if excluded_data.size==0 and expected_errors_left.include?(:excluded_data)
416
+ expected_errors_left.delete(:excluded_data)
417
+ end
418
+
419
+ if string_set_not_allowed.size==0 and expected_errors_left.include?(:string_set_not_allowed)
420
+ expected_errors_left.delete(:string_set_not_allowed)
421
+ end
422
+
423
+ if symbol_type=='!@' and expected_errors_left.size==0 and !expected_errors.include?(:length) and
424
+ (expected_errors.include?(:required_data) or expected_errors.include?(:excluded_data))
425
+ expected_errors_left.push(:value)
426
+ end
427
+
428
+ end
429
+
430
+
431
+ string = ''
432
+ if symbol_type!='@' and symbol_type!='!@' and length!=0 and string_set.size!=0
433
+ if string_set.size!=0
434
+ 1.upto(length) {|i| string << string_set.sample.to_s
435
+ }
436
+ end
437
+ if required_data.size>0
438
+ positions_to_set=(0..(string.size-1)).to_a
439
+ required_data.each {|rd|
440
+ if (string.split(//) & rd).size>0
441
+ rd_to_set=(string.split(//) & rd).sample
442
+ else
443
+ rd_to_set=rd.sample
444
+ end
445
+ if ((0 ... string.length).find_all {|i| string[i, 1] == rd_to_set}).size==0
446
+ if positions_to_set.size==0
447
+ puts "pattern not valid on StringPattern.generate, not possible to generate a valid string: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}"
448
+ return ''
449
+ else
450
+ k=positions_to_set.sample
451
+ string[k]=rd_to_set
452
+ positions_to_set.delete(k)
453
+ end
454
+ else
455
+ k=((0 ... string.length).find_all {|i| string[i, 1] == rd_to_set}).sample
456
+ positions_to_set.delete(k)
457
+ end
458
+ }
459
+ end
460
+ excluded_data.each {|ed|
461
+ if (string.split(//) & ed).size>0
462
+ (string.split(//) & ed).each {|s|
463
+ string.gsub!(s, string_set.sample)
464
+ }
465
+ end
466
+ }
467
+
468
+ if expected_errors_left.include?(:value)
469
+ if string_set_not_allowed.size==0
470
+ puts "Not possible to generate a non valid string on StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}"
471
+ return ''
472
+ end
473
+ (rand(string.size)+1).times {
474
+ string[rand(string.size)]=(all_characters_set-string_set).sample
475
+ }
476
+ expected_errors_left.delete(:value)
477
+ end
478
+
479
+ if expected_errors_left.include?(:required_data) and required_data.size>0
480
+ (rand(required_data.size)+1).times {
481
+ chars_to_remove=required_data.sample
482
+ chars_to_remove.each {|char_to_remove|
483
+ string.gsub!(char_to_remove, (string_set-chars_to_remove).sample)
484
+ }
485
+ }
486
+ expected_errors_left.delete(:required_data)
487
+ end
488
+
489
+ if expected_errors_left.include?(:excluded_data) and excluded_data.size>0
490
+ (rand(string.size)+1).times {
491
+ string[rand(string.size)]=excluded_data.sample.sample
492
+ }
493
+ expected_errors_left.delete(:excluded_data)
494
+ end
495
+
496
+ if expected_errors_left.include?(:string_set_not_allowed) and string_set_not_allowed.size>0
497
+ (rand(string.size)+1).times {
498
+ string[rand(string.size)]=string_set_not_allowed.sample
499
+ }
500
+ expected_errors_left.delete(:string_set_not_allowed)
501
+ end
502
+
503
+ elsif (symbol_type=='@' or symbol_type=='!@') and length>0
504
+ if min_length>6 and length<6
505
+ length=6
506
+ end
507
+ if deny_pattern and
508
+ (expected_errors.include?(:required_data) or expected_errors.include?(:excluded_data) or
509
+ expected_errors.include?(:string_set_not_allowed))
510
+ expected_errors_left.push(:value)
511
+ expected_errors.push(:value)
512
+ expected_errors.uniq!
513
+ expected_errors_left.uniq!
514
+ end
515
+
516
+ expected_errors_left_orig=expected_errors_left.dup
517
+ tries=0
518
+ begin
519
+ expected_errors_left=expected_errors_left_orig.dup
520
+ tries+=1
521
+ string=''
522
+ alpha_set=ALPHA_SET_LOWER + ALPHA_SET_CAPITAL
523
+ string_set=alpha_set + NUMBER_SET + ['.'] + ['_'] + ['-']
524
+ string_set_not_allowed=all_characters_set-string_set
525
+
526
+ extension='.'
527
+ at_sign='@'
528
+
529
+ if expected_errors_left.include?(:value)
530
+ if rand(2)==1
531
+ extension=(all_characters_set-['.']).sample
532
+ expected_errors_left.delete(:value)
533
+ expected_errors_left.delete(:required_data)
534
+ end
535
+ if rand(2)==1
536
+ 1.upto(rand(7)) {|i| extension << alpha_set.sample.downcase
537
+ }
538
+ (rand(extension.size)+1).times {
539
+ extension[rand(extension.size)]=(string_set-alpha_set-['.']).sample
540
+ }
541
+ expected_errors_left.delete(:value)
542
+ else
543
+ 1.upto(rand(3)+2) {|i| extension << alpha_set.sample.downcase
544
+ }
545
+ end
546
+ if rand(2)==1
547
+ at_sign=(string_set-['@']).sample
548
+ expected_errors_left.delete(:value)
549
+ expected_errors_left.delete(:required_data)
550
+ end
551
+ else
552
+ if length>6
553
+ 1.upto(rand(3)+2) {|i| extension << alpha_set.sample.downcase
554
+ }
555
+ else
556
+ 1.upto(2) {|i| extension << alpha_set.sample.downcase
557
+ }
558
+ end
559
+ end
560
+ length_e=length-extension.size - 1
561
+ length1=rand(length_e-1) + 1
562
+ length2=length_e-length1
563
+ 1.upto(length1) {|i| string << string_set.sample}
564
+
565
+ string << at_sign
566
+
567
+ domain=''
568
+ domain_set=alpha_set + NUMBER_SET + ['.'] + ['-']
569
+ 1.upto(length2) {|i| domain << domain_set.sample.downcase
570
+ }
571
+
572
+ if expected_errors.include?(:value) and rand(2)==1 and domain.size>0
573
+ (rand(domain.size)+1).times {
574
+ domain[rand(domain.size)]=(all_characters_set-domain_set).sample
575
+ }
576
+ expected_errors_left.delete(:value)
577
+ end
578
+ string << domain << extension
579
+
580
+ if expected_errors_left.include?(:value) or expected_errors_left.include?(:string_set_not_allowed)
581
+ (rand(string.size)+1).times {
582
+ string[rand(string.size)]=string_set_not_allowed.sample
583
+ }
584
+ expected_errors_left.delete(:value)
585
+ expected_errors_left.delete(:string_set_not_allowed)
586
+ end
587
+
588
+ error_regular_expression=false
589
+
590
+ if deny_pattern and expected_errors.include?(:length)
591
+ good_result=true #it is already with wrong length
592
+ else
593
+ # I'm doing this because many times the regular expression checking hangs with these characters
594
+ wrong=%w(.. __ -- ._ _. .- -. _- -_ @. @_ @- .@ _@ -@ @@)
595
+ if !(Regexp.union(*wrong) === string) #don't include any or the wrong strings
596
+ if string.index('@').to_i>0 and
597
+ string[0..(string.index('@')-1)].scan(/([a-z0-9]+([\+\._\-][a-z0-9]|)*)/i).join==string[0..(string.index('@')-1)] and
598
+ string[(string.index('@')+1)..-1].scan(/([0-9a-z]+([\.-][a-z0-9]|)*)/i).join==string[string[(string.index('@')+1)..-1]]
599
+ error_regular_expression=false
600
+ else
601
+ error_regular_expression=true
602
+ end
603
+ else
604
+ error_regular_expression=true
605
+ end
606
+
607
+ if expected_errors.size==0
608
+ if error_regular_expression
609
+ good_result=false
610
+ else
611
+ good_result=true
612
+ end
613
+ elsif expected_errors_left.size==0 and
614
+ (expected_errors-[:length, :min_length, :max_length]).size==0
615
+ good_result=true
616
+ elsif expected_errors!=[:length]
617
+ if !error_regular_expression
618
+ good_result=false
619
+ elsif expected_errors.include?(:value)
620
+ good_result=true
621
+ end
622
+ end
623
+ end
624
+
625
+ end until good_result or tries>100
626
+ unless good_result
627
+ puts "Not possible to generate an email on StringPattern.generate: #{pattern.inspect}, expected_errors: #{expected_errors.inspect}"
628
+ return ''
629
+ end
630
+ end
631
+
632
+ return string
633
+ end
634
+
635
+
636
+ ##############################################
637
+ # This method is defined to validate if the text_to_validate supplied follows the pattern
638
+ # It works also with array of patterns but in that case will return only true or false
639
+ # input:
640
+ # text (String) (synonyms: text_to_validate, validate) -- The text to validate
641
+ # pattern -- symbol with this info: "length:symbol_type" or "min_length-max_length:symbol_type"
642
+ # min_length -- minimum length of the string
643
+ # max_length (optional) -- maximum length of the string. If not provided the result will be with the min_length provided
644
+ # symbol_type -- the type of the string we want.
645
+ # expected_errors (Array of symbols) (optional) (synonyms: errors) -- :length, :min_length, :max_length, :value, :required_data, :excluded_data, :string_set_not_allowed
646
+ # 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
647
+ # example:
648
+ # validate(text: "This text will be validated", pattern: :"10-20:Xn", expected_errors: [:value, :max_length])
649
+ #
650
+ # Output:
651
+ # if expected_errors and not_expected_errors are not supplied: an array with all detected errors
652
+ # if expected_errors or not_expected_errors supplied: true or false
653
+ # if array of patterns supplied, it will return true or false
654
+ ###############################################
655
+ def StringPattern.validate(text: '', pattern: '', expected_errors: [], not_expected_errors: [], **synonyms)
656
+ text_to_validate=text
657
+ text_to_validate=synonyms[:text_to_validate] if synonyms.keys.include?(:text_to_validate)
658
+ text_to_validate=synonyms[:validate] if synonyms.keys.include?(:validate)
659
+ expected_errors=synonyms[:errors] if synonyms.keys.include?(:errors)
660
+ not_expected_errors=synonyms[:not_errors] if synonyms.keys.include?(:not_errors)
661
+ not_expected_errors=synonyms[:non_expected_errors] if synonyms.keys.include?(:non_expected_errors)
662
+ #:length, :min_length, :max_length, :value, :required_data, :excluded_data, :string_set_not_allowed
663
+ if (expected_errors.include?(:min_length) or expected_errors.include?(:max_length)) and !expected_errors.include?(:length)
664
+ expected_errors.push(:length)
665
+ end
666
+ if (not_expected_errors.include?(:min_length) or not_expected_errors.include?(:max_length)) and !not_expected_errors.include?(:length)
667
+ not_expected_errors.push(:length)
668
+ end
669
+ if pattern.kind_of?(Array) and pattern.size==1
670
+ pattern=pattern[0]
671
+ elsif pattern.kind_of?(Array) and pattern.size>1 then
672
+ total_min_length=0
673
+ total_max_length=0
674
+ all_errors_collected=Array.new
675
+ result=true
676
+ num_patt=0
677
+ patterns=Array.new
678
+ pattern.each {|pat|
679
+ if (pat.kind_of?(String) and (!StringPattern.optimistic or
680
+ (StringPattern.optimistic and pat.to_s.scan(/(\d+)-(\d+):(.+)/).size==0 and pat.to_s.scan(/^!?(\d+):(.+)/).size==0))) #fixed text
681
+ symbol_type=''
682
+ min_length=max_length=pat.length
683
+ elsif pat.kind_of?(Symbol) or (pat.kind_of?(String) and StringPattern.optimistic and
684
+ (pat.to_s.scan(/(\d+)-(\d+):(.+)/).size>0 or pat.to_s.scan(/^!?(\d+):(.+)/).size>0))
685
+ patt=StringPattern.analyze(pat)
686
+ min_length=patt.min_length
687
+ max_length=patt.max_length
688
+ symbol_type=patt.symbol_type
689
+ else
690
+ puts "String pattern class not supported (#{pat.class} for #{pat})"
691
+ end
692
+
693
+ patterns.push({pattern: pat, min_length: min_length, max_length: max_length, symbol_type: symbol_type})
694
+
695
+ total_min_length+=min_length
696
+ total_max_length+=max_length
697
+
698
+ if num_patt==(pattern.size-1) # i am in the last one
699
+ if text_to_validate.length<total_min_length
700
+ all_errors_collected.push(:length)
701
+ all_errors_collected.push(:min_length)
702
+ end
703
+
704
+ if text_to_validate.length>total_max_length
705
+ all_errors_collected.push(:length)
706
+ all_errors_collected.push(:max_length)
707
+ end
708
+
709
+ end
710
+ num_patt+=1
711
+
712
+
713
+ }
714
+
715
+ num_patt=0
716
+ patterns.each {|patt|
717
+
718
+ tmp_result=false
719
+ (patt[:min_length]..patt[:max_length]).each {|n|
720
+ res=StringPattern.validate(text: text_to_validate[0..n-1], pattern: patt[:pattern], not_expected_errors: not_expected_errors)
721
+ if res.kind_of?(Array)
722
+ all_errors_collected+=res
723
+ end
724
+
725
+ if res.kind_of?(TrueClass) or (res.kind_of?(Array) and res.size==0) #valid
726
+ #we pass in the next one the rest of the pattern array list: pattern: pattern[num_patt+1..pattern.size]
727
+ 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)
728
+
729
+ if res.kind_of?(Array)
730
+ if ((all_errors_collected + res)-expected_errors).size>0
731
+ tmp_result=false
732
+ else
733
+ all_errors_collected+=res
734
+ tmp_result=true
735
+ end
736
+ elsif res.kind_of?(TrueClass) then
737
+ tmp_result=true
738
+ end
739
+ return true if tmp_result
740
+ end
741
+ }
742
+
743
+ unless tmp_result
744
+ return false
745
+ end
746
+ num_patt+=1
747
+ }
748
+ return result
749
+ end
750
+
751
+ if (pattern.kind_of?(String) and (!StringPattern.optimistic or
752
+ (StringPattern.optimistic and pattern.to_s.scan(/(\d+)-(\d+):(.+)/).size==0 and pattern.to_s.scan(/^!?(\d+):(.+)/).size==0))) #fixed text
753
+ symbol_type=''
754
+ min_length=max_length=pattern.length
755
+ else #symbol
756
+ patt=StringPattern.analyze(pattern)
757
+ min_length=patt.min_length
758
+ max_length=patt.max_length
759
+ symbol_type=patt.symbol_type
760
+
761
+ required_data=patt.required_data
762
+ excluded_data=patt.excluded_data
763
+ string_set=patt.string_set
764
+ all_characters_set=patt.all_characters_set
765
+
766
+ required_chars=Array.new
767
+ required_data.each {|rd|
768
+ required_chars<<rd if rd.size==1
769
+ }
770
+ if (required_chars.flatten & excluded_data.flatten).size>0
771
+ 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}"
772
+ return ''
773
+ end
774
+
775
+ end
776
+
777
+ if text_to_validate.nil?
778
+ return false
779
+ end
780
+ detected_errors=Array.new
781
+
782
+ if text_to_validate.length<min_length
783
+ detected_errors.push(:min_length)
784
+ detected_errors.push(:length)
785
+ end
786
+ if text_to_validate.length>max_length
787
+ detected_errors.push(:max_length)
788
+ detected_errors.push(:length)
789
+ end
790
+
791
+ if symbol_type=='' #fixed text
792
+ if pattern.to_s!=text.to_s #not equal
793
+ detected_errors.push(:value)
794
+ detected_errors.push(:required_data)
795
+ end
796
+ else # pattern supplied
797
+ if symbol_type!='@'
798
+ if required_data.size>0
799
+ required_data.each {|rd|
800
+ if (text_to_validate.split(//) & rd).size==0
801
+ detected_errors.push(:value)
802
+ detected_errors.push(:required_data)
803
+ break
804
+ end
805
+ }
806
+ end
807
+ if excluded_data.size>0
808
+ if (excluded_data & text_to_validate.split(//)).size>0
809
+ detected_errors.push(:value)
810
+ detected_errors.push(:excluded_data)
811
+ end
812
+ end
813
+ string_set_not_allowed=all_characters_set-string_set
814
+ text_to_validate.split(//).each {|st|
815
+ if string_set_not_allowed.include?(st)
816
+ detected_errors.push(:value)
817
+ detected_errors.push(:string_set_not_allowed)
818
+ break
819
+ end
820
+ }
821
+ else #symbol_type=="@"
822
+ string=text_to_validate
823
+ wrong=%w(.. __ -- ._ _. .- -. _- -_ @. @_ @- .@ _@ -@ @@)
824
+ if !(Regexp.union(*wrong) === string) #don't include any or the wrong strings
825
+ if string.index('@').to_i>0 and
826
+ string[0..(string.index('@')-1)].scan(/([a-z0-9]+([\+\._\-][a-z0-9]|)*)/i).join==string[0..(string.index('@')-1)] and
827
+ string[(string.index('@')+1)..-1].scan(/([0-9a-z]+([\.-][a-z0-9]|)*)/i).join==string[string[(string.index('@')+1)..-1]]
828
+ error_regular_expression=false
829
+ else
830
+ error_regular_expression=true
831
+ end
832
+ else
833
+ error_regular_expression=true
834
+ end
835
+
836
+ if error_regular_expression
837
+ detected_errors.push(:value)
838
+ end
839
+
840
+ end
841
+ end
842
+
843
+ if expected_errors.size==0 and not_expected_errors.size==0
844
+ return detected_errors
845
+ else
846
+ if expected_errors & detected_errors == expected_errors
847
+ if (not_expected_errors & detected_errors).size > 0
848
+ return false
849
+ else
850
+ return true
851
+ end
852
+ else
853
+ return false
854
+ end
855
+ end
856
+ end
857
+
858
+ end
859
+
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: string_pattern
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mario Ruiz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-05-21 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: You can easily generate strings supplying a very simple pattern. Also
14
+ you can validate if a text fulfill an specific pattern or even generate a string
15
+ following a pattern and returning wrong length, value... for testing your applications.
16
+ email: marioruizs@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files:
20
+ - LICENSE
21
+ - README.md
22
+ files:
23
+ - LICENSE
24
+ - README.md
25
+ - lib/string/pattern/add_to_ruby.rb
26
+ - lib/string_pattern.rb
27
+ homepage: https://github.com/MarioRuiz/string_pattern
28
+ licenses:
29
+ - MIT
30
+ metadata: {}
31
+ post_install_message:
32
+ rdoc_options: []
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ requirements: []
46
+ rubyforge_project:
47
+ rubygems_version: 2.7.6
48
+ signing_key:
49
+ specification_version: 4
50
+ summary: 'Generates easily random string following a simple pattern. ''10-20:Xn/x/''.generate
51
+ #>qBstvc6JN8ra'
52
+ test_files: []