email_address_validator 1.0.0 → 2.0.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/Gemfile +1 -1
- data/Gemfile.lock +9 -13
- data/grammars/rfc2822.kpeg +1 -1
- data/grammars/rfc822.kpeg +4 -4
- data/lib/email_address_validator.rb +6 -2
- data/lib/email_address_validator/domain-parser.rb +185 -144
- data/lib/email_address_validator/rfc2822-parser.rb +1593 -1552
- data/lib/email_address_validator/rfc822-parser.rb +669 -629
- data/lib/email_address_validator/version.rb +1 -1
- data/spec/email_address_validator_spec.rb +4 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2cc3e2b1d36178731391c09de74d8ee9c378f5f6
|
4
|
+
data.tar.gz: 30b987b6aed56e55292fea9240f272613d63fc8a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8dd649a91a55f24208cffdfd3f681b80e8b31759c728b2ef8ca355a0a398697d70cd022de075ab61d346e0918255bd8071930ef2f5210dbc7110e63b53f8a162
|
7
|
+
data.tar.gz: 8620453673d42a5e172e4afe70af4c84f271780c875a8e1a6f61c71ebf5ef12511af9c74e915493294355df7eaec629fef9238bfe9fefe36a4b3be0e6140eae6
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -3,22 +3,18 @@ GEM
|
|
3
3
|
specs:
|
4
4
|
diff-lcs (1.2.5)
|
5
5
|
rake (10.3.2)
|
6
|
-
rspec (
|
7
|
-
rspec-core (~>
|
8
|
-
rspec-expectations (~>
|
9
|
-
rspec-mocks (~>
|
10
|
-
rspec-core (
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
rspec-support (~> 3.1.0)
|
15
|
-
rspec-mocks (3.1.3)
|
16
|
-
rspec-support (~> 3.1.0)
|
17
|
-
rspec-support (3.1.2)
|
6
|
+
rspec (2.99.0)
|
7
|
+
rspec-core (~> 2.99.0)
|
8
|
+
rspec-expectations (~> 2.99.0)
|
9
|
+
rspec-mocks (~> 2.99.0)
|
10
|
+
rspec-core (2.99.2)
|
11
|
+
rspec-expectations (2.99.2)
|
12
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
13
|
+
rspec-mocks (2.99.3)
|
18
14
|
|
19
15
|
PLATFORMS
|
20
16
|
ruby
|
21
17
|
|
22
18
|
DEPENDENCIES
|
23
19
|
rake
|
24
|
-
rspec
|
20
|
+
rspec (~> 2.0)
|
data/grammars/rfc2822.kpeg
CHANGED
data/grammars/rfc822.kpeg
CHANGED
@@ -19,16 +19,16 @@ CRLF = CR LF
|
|
19
19
|
|
20
20
|
linear_white_space = (CRLF? LWSP_char)+
|
21
21
|
|
22
|
-
atom = /[^\]\x00-\x20 \x7F\x80-\xFF()<>@,;:\\".\[]+/
|
22
|
+
atom = /[^\]\x00-\x20 \x7F\x80-\xFF()<>@,;:\\".\[]+/n
|
23
23
|
|
24
|
-
ctext = /[^)\\\x0D\x80-\xFF(]+/
|
24
|
+
ctext = /[^)\\\x0D\x80-\xFF(]+/n
|
25
25
|
| linear_white_space
|
26
26
|
|
27
27
|
|
28
|
-
dtext = /[^\]\\\x0D\x80-\xFF\[]+/
|
28
|
+
dtext = /[^\]\\\x0D\x80-\xFF\[]+/n
|
29
29
|
| linear_white_space
|
30
30
|
|
31
|
-
qtext = /[^"\\\x0D\x80-\xFF]+/
|
31
|
+
qtext = /[^"\\\x0D\x80-\xFF]+/n
|
32
32
|
| linear_white_space
|
33
33
|
|
34
34
|
|
@@ -52,7 +52,9 @@ module EmailAddressValidator
|
|
52
52
|
end
|
53
53
|
|
54
54
|
# Shorthand for +EmailAddressParser.validate_2822_addr
|
55
|
-
def self.validate_addr(addr, validate_domain=false)
|
55
|
+
def self.validate_addr(addr, validate_domain=false)
|
56
|
+
validate_2822_addr addr, validate_domain
|
57
|
+
end
|
56
58
|
|
57
59
|
# Validates +addr+ against the addr_spec portion of RFC 2822.
|
58
60
|
# This is what most people actually want out of an email validator
|
@@ -65,7 +67,9 @@ module EmailAddressValidator
|
|
65
67
|
end
|
66
68
|
|
67
69
|
# Shorthand for +EmailAddressParser.validate_2822
|
68
|
-
def self.validate(addr, validate_domain=false)
|
70
|
+
def self.validate(addr, validate_domain=false)
|
71
|
+
validate_2822 addr, validate_domain
|
72
|
+
end
|
69
73
|
|
70
74
|
# Validates an email address according to RFC 2822
|
71
75
|
# This validates addresses against the full spec, which
|
@@ -1,8 +1,19 @@
|
|
1
1
|
class EmailAddressValidator::DomainParser
|
2
|
-
#
|
2
|
+
# :stopdoc:
|
3
|
+
|
4
|
+
# This is distinct from setup_parser so that a standalone parser
|
5
|
+
# can redefine #initialize and still have access to the proper
|
6
|
+
# parser setup code.
|
7
|
+
def initialize(str, debug=false)
|
8
|
+
setup_parser(str, debug)
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
# Prepares for parsing +str+. If you define a custom initialize you must
|
14
|
+
# call this method before #parse
|
3
15
|
def setup_parser(str, debug=false)
|
4
|
-
|
5
|
-
@pos = 0
|
16
|
+
set_string str, 0
|
6
17
|
@memoizations = Hash.new { |h,k| h[k] = {} }
|
7
18
|
@result = nil
|
8
19
|
@failed_rule = nil
|
@@ -11,22 +22,10 @@ class EmailAddressValidator::DomainParser
|
|
11
22
|
setup_foreign_grammar
|
12
23
|
end
|
13
24
|
|
14
|
-
def setup_foreign_grammar
|
15
|
-
end
|
16
|
-
|
17
|
-
# This is distinct from setup_parser so that a standalone parser
|
18
|
-
# can redefine #initialize and still have access to the proper
|
19
|
-
# parser setup code.
|
20
|
-
#
|
21
|
-
def initialize(str, debug=false)
|
22
|
-
setup_parser(str, debug)
|
23
|
-
end
|
24
|
-
|
25
25
|
attr_reader :string
|
26
|
-
attr_reader :
|
27
|
-
attr_accessor :pos
|
26
|
+
attr_reader :failing_rule_offset
|
27
|
+
attr_accessor :result, :pos
|
28
28
|
|
29
|
-
# STANDALONE START
|
30
29
|
def current_column(target=pos)
|
31
30
|
if c = string.rindex("\n", target-1)
|
32
31
|
return target - c - 1
|
@@ -54,12 +53,19 @@ class EmailAddressValidator::DomainParser
|
|
54
53
|
lines
|
55
54
|
end
|
56
55
|
|
57
|
-
|
56
|
+
|
58
57
|
|
59
58
|
def get_text(start)
|
60
59
|
@string[start..@pos-1]
|
61
60
|
end
|
62
61
|
|
62
|
+
# Sets the string and current parsing position for the parser.
|
63
|
+
def set_string string, pos
|
64
|
+
@string = string
|
65
|
+
@string_size = string ? string.size : 0
|
66
|
+
@pos = pos
|
67
|
+
end
|
68
|
+
|
63
69
|
def show_pos
|
64
70
|
width = 10
|
65
71
|
if @pos < width
|
@@ -166,19 +172,19 @@ class EmailAddressValidator::DomainParser
|
|
166
172
|
return nil
|
167
173
|
end
|
168
174
|
|
169
|
-
if "".respond_to? :
|
175
|
+
if "".respond_to? :ord
|
170
176
|
def get_byte
|
171
|
-
if @pos >= @
|
177
|
+
if @pos >= @string_size
|
172
178
|
return nil
|
173
179
|
end
|
174
180
|
|
175
|
-
s = @string
|
181
|
+
s = @string[@pos].ord
|
176
182
|
@pos += 1
|
177
183
|
s
|
178
184
|
end
|
179
185
|
else
|
180
186
|
def get_byte
|
181
|
-
if @pos >= @
|
187
|
+
if @pos >= @string_size
|
182
188
|
return nil
|
183
189
|
end
|
184
190
|
|
@@ -189,41 +195,37 @@ class EmailAddressValidator::DomainParser
|
|
189
195
|
end
|
190
196
|
|
191
197
|
def parse(rule=nil)
|
198
|
+
# We invoke the rules indirectly via apply
|
199
|
+
# instead of by just calling them as methods because
|
200
|
+
# if the rules use left recursion, apply needs to
|
201
|
+
# manage that.
|
202
|
+
|
192
203
|
if !rule
|
193
|
-
_root
|
204
|
+
apply(:_root)
|
194
205
|
else
|
195
|
-
# This is not shared with code_generator.rb so this can be standalone
|
196
206
|
method = rule.gsub("-","_hyphen_")
|
197
|
-
|
207
|
+
apply :"_#{method}"
|
198
208
|
end
|
199
209
|
end
|
200
210
|
|
201
|
-
class LeftRecursive
|
202
|
-
def initialize(detected=false)
|
203
|
-
@detected = detected
|
204
|
-
end
|
205
|
-
|
206
|
-
attr_accessor :detected
|
207
|
-
end
|
208
|
-
|
209
211
|
class MemoEntry
|
210
212
|
def initialize(ans, pos)
|
211
213
|
@ans = ans
|
212
214
|
@pos = pos
|
213
|
-
@uses = 1
|
214
215
|
@result = nil
|
216
|
+
@set = false
|
217
|
+
@left_rec = false
|
215
218
|
end
|
216
219
|
|
217
|
-
attr_reader :ans, :pos, :
|
218
|
-
|
219
|
-
def inc!
|
220
|
-
@uses += 1
|
221
|
-
end
|
220
|
+
attr_reader :ans, :pos, :result, :set
|
221
|
+
attr_accessor :left_rec
|
222
222
|
|
223
223
|
def move!(ans, pos, result)
|
224
224
|
@ans = ans
|
225
225
|
@pos = pos
|
226
226
|
@result = result
|
227
|
+
@set = true
|
228
|
+
@left_rec = false
|
227
229
|
end
|
228
230
|
end
|
229
231
|
|
@@ -231,30 +233,61 @@ class EmailAddressValidator::DomainParser
|
|
231
233
|
old_pos = @pos
|
232
234
|
old_string = @string
|
233
235
|
|
234
|
-
|
235
|
-
@string = other.string
|
236
|
+
set_string other.string, other.pos
|
236
237
|
|
237
238
|
begin
|
238
239
|
if val = __send__(rule, *args)
|
239
240
|
other.pos = @pos
|
241
|
+
other.result = @result
|
240
242
|
else
|
241
243
|
other.set_failed_rule "#{self.class}##{rule}"
|
242
244
|
end
|
243
245
|
val
|
244
246
|
ensure
|
245
|
-
|
246
|
-
|
247
|
+
set_string old_string, old_pos
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def apply_with_args(rule, *args)
|
252
|
+
memo_key = [rule, args]
|
253
|
+
if m = @memoizations[memo_key][@pos]
|
254
|
+
@pos = m.pos
|
255
|
+
if !m.set
|
256
|
+
m.left_rec = true
|
257
|
+
return nil
|
258
|
+
end
|
259
|
+
|
260
|
+
@result = m.result
|
261
|
+
|
262
|
+
return m.ans
|
263
|
+
else
|
264
|
+
m = MemoEntry.new(nil, @pos)
|
265
|
+
@memoizations[memo_key][@pos] = m
|
266
|
+
start_pos = @pos
|
267
|
+
|
268
|
+
ans = __send__ rule, *args
|
269
|
+
|
270
|
+
lr = m.left_rec
|
271
|
+
|
272
|
+
m.move! ans, @pos, @result
|
273
|
+
|
274
|
+
# Don't bother trying to grow the left recursion
|
275
|
+
# if it's failing straight away (thus there is no seed)
|
276
|
+
if ans and lr
|
277
|
+
return grow_lr(rule, args, start_pos, m)
|
278
|
+
else
|
279
|
+
return ans
|
280
|
+
end
|
281
|
+
|
282
|
+
return ans
|
247
283
|
end
|
248
284
|
end
|
249
285
|
|
250
286
|
def apply(rule)
|
251
287
|
if m = @memoizations[rule][@pos]
|
252
|
-
m.inc!
|
253
|
-
|
254
|
-
prev = @pos
|
255
288
|
@pos = m.pos
|
256
|
-
if m.
|
257
|
-
m.
|
289
|
+
if !m.set
|
290
|
+
m.left_rec = true
|
258
291
|
return nil
|
259
292
|
end
|
260
293
|
|
@@ -262,19 +295,20 @@ class EmailAddressValidator::DomainParser
|
|
262
295
|
|
263
296
|
return m.ans
|
264
297
|
else
|
265
|
-
|
266
|
-
m = MemoEntry.new(lr, @pos)
|
298
|
+
m = MemoEntry.new(nil, @pos)
|
267
299
|
@memoizations[rule][@pos] = m
|
268
300
|
start_pos = @pos
|
269
301
|
|
270
302
|
ans = __send__ rule
|
271
303
|
|
304
|
+
lr = m.left_rec
|
305
|
+
|
272
306
|
m.move! ans, @pos, @result
|
273
307
|
|
274
308
|
# Don't bother trying to grow the left recursion
|
275
309
|
# if it's failing straight away (thus there is no seed)
|
276
|
-
if ans and lr
|
277
|
-
return grow_lr(rule, start_pos, m)
|
310
|
+
if ans and lr
|
311
|
+
return grow_lr(rule, nil, start_pos, m)
|
278
312
|
else
|
279
313
|
return ans
|
280
314
|
end
|
@@ -283,12 +317,16 @@ class EmailAddressValidator::DomainParser
|
|
283
317
|
end
|
284
318
|
end
|
285
319
|
|
286
|
-
def grow_lr(rule, start_pos, m)
|
320
|
+
def grow_lr(rule, args, start_pos, m)
|
287
321
|
while true
|
288
322
|
@pos = start_pos
|
289
323
|
@result = m.result
|
290
324
|
|
291
|
-
|
325
|
+
if args
|
326
|
+
ans = __send__ rule, *args
|
327
|
+
else
|
328
|
+
ans = __send__ rule
|
329
|
+
end
|
292
330
|
return nil unless ans
|
293
331
|
|
294
332
|
break if @pos <= m.pos
|
@@ -314,7 +352,9 @@ class EmailAddressValidator::DomainParser
|
|
314
352
|
RuleInfo.new(name, rendered)
|
315
353
|
end
|
316
354
|
|
317
|
-
|
355
|
+
|
356
|
+
# :startdoc:
|
357
|
+
# :stopdoc:
|
318
358
|
def setup_foreign_grammar; end
|
319
359
|
|
320
360
|
# domain = < subdomain > &{ text.size < 255 }
|
@@ -322,22 +362,22 @@ class EmailAddressValidator::DomainParser
|
|
322
362
|
|
323
363
|
_save = self.pos
|
324
364
|
while true # sequence
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
365
|
+
_text_start = self.pos
|
366
|
+
_tmp = apply(:_subdomain)
|
367
|
+
if _tmp
|
368
|
+
text = get_text(_text_start)
|
369
|
+
end
|
370
|
+
unless _tmp
|
371
|
+
self.pos = _save
|
372
|
+
break
|
373
|
+
end
|
374
|
+
_save1 = self.pos
|
375
|
+
_tmp = begin; text.size < 255 ; end
|
376
|
+
self.pos = _save1
|
377
|
+
unless _tmp
|
378
|
+
self.pos = _save
|
379
|
+
end
|
332
380
|
break
|
333
|
-
end
|
334
|
-
_save1 = self.pos
|
335
|
-
_tmp = begin; text.size < 255 ; end
|
336
|
-
self.pos = _save1
|
337
|
-
unless _tmp
|
338
|
-
self.pos = _save
|
339
|
-
end
|
340
|
-
break
|
341
381
|
end # end sequence
|
342
382
|
|
343
383
|
set_failed_rule :_domain unless _tmp
|
@@ -350,31 +390,31 @@ class EmailAddressValidator::DomainParser
|
|
350
390
|
_save = self.pos
|
351
391
|
while true # choice
|
352
392
|
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
393
|
+
_save1 = self.pos
|
394
|
+
while true # sequence
|
395
|
+
_tmp = apply(:_subdomain)
|
396
|
+
unless _tmp
|
397
|
+
self.pos = _save1
|
398
|
+
break
|
399
|
+
end
|
400
|
+
_tmp = match_string(".")
|
401
|
+
unless _tmp
|
402
|
+
self.pos = _save1
|
403
|
+
break
|
404
|
+
end
|
405
|
+
_tmp = apply(:_label)
|
406
|
+
unless _tmp
|
407
|
+
self.pos = _save1
|
408
|
+
end
|
409
|
+
break
|
410
|
+
end # end sequence
|
371
411
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
412
|
+
break if _tmp
|
413
|
+
self.pos = _save
|
414
|
+
_tmp = apply(:_label)
|
415
|
+
break if _tmp
|
416
|
+
self.pos = _save
|
417
|
+
break
|
378
418
|
end # end choice
|
379
419
|
|
380
420
|
set_failed_rule :_subdomain unless _tmp
|
@@ -386,31 +426,31 @@ class EmailAddressValidator::DomainParser
|
|
386
426
|
|
387
427
|
_save = self.pos
|
388
428
|
while true # sequence
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
429
|
+
_tmp = apply(:_let_hyphen_dig)
|
430
|
+
unless _tmp
|
431
|
+
self.pos = _save
|
432
|
+
break
|
433
|
+
end
|
434
|
+
_text_start = self.pos
|
435
|
+
while true
|
436
|
+
_tmp = apply(:_let_hyphen_dig_hyphen_hyp)
|
437
|
+
break unless _tmp
|
438
|
+
end
|
439
|
+
_tmp = true
|
440
|
+
if _tmp
|
441
|
+
text = get_text(_text_start)
|
442
|
+
end
|
443
|
+
unless _tmp
|
444
|
+
self.pos = _save
|
445
|
+
break
|
446
|
+
end
|
447
|
+
_save2 = self.pos
|
448
|
+
_tmp = begin; text.size < 63 && (text.size == 0 || text[-1] != ?-) ; end
|
449
|
+
self.pos = _save2
|
450
|
+
unless _tmp
|
451
|
+
self.pos = _save
|
452
|
+
end
|
405
453
|
break
|
406
|
-
end
|
407
|
-
_save2 = self.pos
|
408
|
-
_tmp = begin; text.size < 63 && (text.size == 0 || text[-1] != ?-) ; end
|
409
|
-
self.pos = _save2
|
410
|
-
unless _tmp
|
411
|
-
self.pos = _save
|
412
|
-
end
|
413
|
-
break
|
414
454
|
end # end sequence
|
415
455
|
|
416
456
|
set_failed_rule :_label unless _tmp
|
@@ -422,13 +462,13 @@ class EmailAddressValidator::DomainParser
|
|
422
462
|
|
423
463
|
_save = self.pos
|
424
464
|
while true # choice
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
465
|
+
_tmp = apply(:_let_hyphen_dig)
|
466
|
+
break if _tmp
|
467
|
+
self.pos = _save
|
468
|
+
_tmp = match_string("-")
|
469
|
+
break if _tmp
|
470
|
+
self.pos = _save
|
471
|
+
break
|
432
472
|
end # end choice
|
433
473
|
|
434
474
|
set_failed_rule :_let_hyphen_dig_hyphen_hyp unless _tmp
|
@@ -440,13 +480,13 @@ class EmailAddressValidator::DomainParser
|
|
440
480
|
|
441
481
|
_save = self.pos
|
442
482
|
while true # choice
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
483
|
+
_tmp = apply(:_letter)
|
484
|
+
break if _tmp
|
485
|
+
self.pos = _save
|
486
|
+
_tmp = apply(:_digit)
|
487
|
+
break if _tmp
|
488
|
+
self.pos = _save
|
489
|
+
break
|
450
490
|
end # end choice
|
451
491
|
|
452
492
|
set_failed_rule :_let_hyphen_dig unless _tmp
|
@@ -472,19 +512,19 @@ class EmailAddressValidator::DomainParser
|
|
472
512
|
|
473
513
|
_save = self.pos
|
474
514
|
while true # sequence
|
475
|
-
|
476
|
-
|
477
|
-
|
515
|
+
_tmp = apply(:_domain)
|
516
|
+
unless _tmp
|
517
|
+
self.pos = _save
|
518
|
+
break
|
519
|
+
end
|
520
|
+
_save1 = self.pos
|
521
|
+
_tmp = get_byte
|
522
|
+
_tmp = _tmp ? nil : true
|
523
|
+
self.pos = _save1
|
524
|
+
unless _tmp
|
525
|
+
self.pos = _save
|
526
|
+
end
|
478
527
|
break
|
479
|
-
end
|
480
|
-
_save1 = self.pos
|
481
|
-
_tmp = get_byte
|
482
|
-
_tmp = _tmp ? nil : true
|
483
|
-
self.pos = _save1
|
484
|
-
unless _tmp
|
485
|
-
self.pos = _save
|
486
|
-
end
|
487
|
-
break
|
488
528
|
end # end sequence
|
489
529
|
|
490
530
|
set_failed_rule :_root unless _tmp
|
@@ -500,4 +540,5 @@ class EmailAddressValidator::DomainParser
|
|
500
540
|
Rules[:_letter] = rule_info("letter", "/[A-Za-z]/")
|
501
541
|
Rules[:_digit] = rule_info("digit", "/[0-9]/")
|
502
542
|
Rules[:_root] = rule_info("root", "domain !.")
|
543
|
+
# :startdoc:
|
503
544
|
end
|