Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Added email address example

  • Loading branch information...
commit ff42c5f4e08d42fecb95b1b4b3270010bd86e2b4 1 parent ed08be6
Michael Jackson authored February 20, 2011
161  examples/email.citrus
... ...
@@ -0,0 +1,161 @@
  1
+# A grammar for email addresses that closely conforms to RFC 5322, with the
  2
+# notable exception that this grammar does not allow for folding white space
  3
+# or comments within atoms.
  4
+grammar EmailAddress
  5
+  root addr-spec
  6
+
  7
+  # ALPHA           =  %x41-5A / %x61-7A   ; A-Z / a-z
  8
+  rule ALPHA
  9
+    [A-Za-z]
  10
+  end
  11
+
  12
+  # DIGIT           =  %x30-39
  13
+  #                        ; 0-9
  14
+  rule DIGIT
  15
+    [0-9]
  16
+  end
  17
+
  18
+  # DQUOTE          =  %x22
  19
+  #                        ; " (Double Quote)
  20
+  rule DQUOTE
  21
+    '"'
  22
+  end
  23
+
  24
+  # NO-WS-CTL       =       %d1-8 /         ; US-ASCII control characters
  25
+  #                         %d11 /          ;  that do not include the
  26
+  #                         %d12 /          ;  carriage return, line feed,
  27
+  #                         %d14-31 /       ;  and white space characters
  28
+  #                         %d127
  29
+  rule NO-WS-CTL
  30
+    [\x01-\x08\x0B\x0C\x0E-\x1F\x7F]
  31
+  end
  32
+
  33
+  # quoted-pair     =       ("\" text) / obs-qp
  34
+  rule quoted-pair
  35
+    ("\\" text) | obs-qp
  36
+  end
  37
+
  38
+  # atext           =   ALPHA / DIGIT /    ; Printable US-ASCII
  39
+  #                     "!" / "#" /        ;  characters not including
  40
+  #                     "$" / "%" /        ;  specials.  Used for atoms.
  41
+  #                     "&" / "'" /
  42
+  #                     "*" / "+" /
  43
+  #                     "-" / "/" /
  44
+  #                     "=" / "?" /
  45
+  #                     "^" / "_" /
  46
+  #                     "`" / "{" /
  47
+  #                     "|" / "}" /
  48
+  #                     "~"
  49
+  rule atext
  50
+    ALPHA | DIGIT | [!\#$\%&'*+-/=?^_`{|}~]
  51
+  end
  52
+
  53
+  # atom            =       [CFWS] 1*atext [CFWS]
  54
+  rule atom
  55
+    atext 1*
  56
+  end
  57
+
  58
+  # dot-atom-text   =       1*atext *("." 1*atext)
  59
+  rule dot-atom-text
  60
+    atext 1* ("." atext 1*)*
  61
+  end
  62
+
  63
+  # dot-atom        =       [CFWS] dot-atom-text [CFWS]
  64
+  rule dot-atom
  65
+    dot-atom-text
  66
+  end
  67
+
  68
+  # qtext           =   %d33 /             ; Printable US-ASCII
  69
+  #                     %d35-91 /          ;  characters not including
  70
+  #                     %d93-126 /         ;  "\" or the quote character
  71
+  #                     obs-qtext
  72
+  rule qtext
  73
+    [\x21\x23-\x5B\x5D-\x7E] | obs-qtext
  74
+  end
  75
+
  76
+  # qcontent        =       qtext / quoted-pair
  77
+  rule qcontent
  78
+    qtext | quoted-pair
  79
+  end
  80
+
  81
+  # quoted-string   =       [CFWS]
  82
+  #                         DQUOTE *([FWS] qcontent) [FWS] DQUOTE
  83
+  #                         [CFWS]
  84
+  rule quoted-string
  85
+    '"' qcontent* '"'
  86
+  end
  87
+
  88
+  # word            =       atom / quoted-string
  89
+  rule word
  90
+    atom | quoted-string
  91
+  end
  92
+
  93
+  # addr-spec       =       local-part "@" domain
  94
+  rule addr-spec
  95
+    local-part "@" domain
  96
+  end
  97
+
  98
+  # local-part      =       dot-atom / quoted-string / obs-local-part
  99
+  rule local-part
  100
+    dot-atom | quoted-string | obs-local-part
  101
+  end
  102
+
  103
+  # domain          =       dot-atom / domain-literal / obs-domain
  104
+  rule domain
  105
+    dot-atom | domain-literal | obs-domain
  106
+  end
  107
+
  108
+  # domain-literal  =       [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
  109
+  rule domain-literal
  110
+    "[" dtext* "]"
  111
+  end
  112
+
  113
+  # dtext           =   %d33-90 /          ; Printable US-ASCII
  114
+  #                     %d94-126 /         ;  characters not including
  115
+  #                     obs-dtext          ;  "[", "]", or "\"
  116
+  rule dtext
  117
+    [\x21-\x5A\x5E-\x7E] | obs-dtext
  118
+  end
  119
+
  120
+  # text            =   %d1-9 /            ; Characters excluding CR
  121
+  #                     %d11 /             ;  and LF
  122
+  #                     %d12 /
  123
+  #                     %d14-127
  124
+  rule text
  125
+    [\x01-\x09\x0B\x0C\x0E-\x7F]
  126
+  end
  127
+
  128
+  # obs-NO-WS-CTL   =   %d1-8 /            ; US-ASCII control
  129
+  #                     %d11 /             ;  characters that do not
  130
+  #                     %d12 /             ;  include the carriage
  131
+  #                     %d14-31 /          ;  return, line feed, and
  132
+  #                     %d127              ;  white space characters
  133
+  rule obs-NO-WS-CTL
  134
+    [\x01-\x08\x0B\x0C\x0E-\x1F\x7F]
  135
+  end
  136
+
  137
+  # obs-qtext       =   obs-NO-WS-CTL
  138
+  rule obs-qtext
  139
+    obs-NO-WS-CTL
  140
+  end
  141
+
  142
+  # obs-qp          =   "\" (%d0 / obs-NO-WS-CTL / LF / CR)
  143
+  rule obs-qp
  144
+    "\\" ("\x00" | obs-NO-WS-CTL | "\n" | "\r")
  145
+  end
  146
+
  147
+  # obs-local-part  =       word *("." word)
  148
+  rule obs-local-part
  149
+    word ("." word)*
  150
+  end
  151
+
  152
+  # obs-domain      =       atom *("." atom)
  153
+  rule obs-domain
  154
+    atom ("." atom)*
  155
+  end
  156
+
  157
+  # obs-dtext       =   obs-NO-WS-CTL / quoted-pair
  158
+  rule obs-dtext
  159
+    obs-NO-WS-CTL | quoted-pair
  160
+  end
  161
+end
178  examples/email_test.rb
... ...
@@ -0,0 +1,178 @@
  1
+# This file contains a suite of tests for the EmailAddress grammar
  2
+# found in email.citrus.
  3
+
  4
+require 'citrus'
  5
+Citrus.require File.expand_path('../email', __FILE__)
  6
+require 'test/unit'
  7
+
  8
+class EmailAddressTest < Test::Unit::TestCase
  9
+  def test_addr_spec_valid
  10
+    addresses = %w[
  11
+      l3tt3rsAndNumb3rs@domain.com
  12
+      has-dash@domain.com
  13
+      hasApostrophe.o'leary@domain.org
  14
+      uncommonTLD@domain.museum
  15
+      uncommonTLD@domain.travel
  16
+      uncommonTLD@domain.mobi
  17
+      countryCodeTLD@domain.uk
  18
+      countryCodeTLD@domain.rw
  19
+      lettersInDomain@911.com
  20
+      underscore_inLocal@domain.net
  21
+      IPInsteadOfDomain@127.0.0.1
  22
+      subdomain@sub.domain.com
  23
+      local@dash-inDomain.com
  24
+      dot.inLocal@foo.com
  25
+      a@singleLetterLocal.org
  26
+      singleLetterDomain@x.org
  27
+      &*=?^+{}'~@validCharsInLocal.net
  28
+      foor@bar.newTLD
  29
+    ]
  30
+
  31
+    addresses.each do |address|
  32
+      match = EmailAddress.parse(address)
  33
+      assert(match)
  34
+      assert_equal(address, match)
  35
+    end
  36
+  end
  37
+
  38
+  # NO-WS-CTL       =       %d1-8 /         ; US-ASCII control characters
  39
+  #                         %d11 /          ;  that do not include the
  40
+  #                         %d12 /          ;  carriage return, line feed,
  41
+  #                         %d14-31 /       ;  and white space characters
  42
+  #                         %d127
  43
+  def test_no_ws_ctl
  44
+    chars = chars_no_ws_ctl
  45
+
  46
+    chars.each do |c|
  47
+      match = EmailAddress.parse(c, :root => :'NO-WS-CTL')
  48
+      assert(match)
  49
+      assert_equal(c, match)
  50
+    end
  51
+  end
  52
+
  53
+  # quoted-pair     =       ("\" text) / obs-qp
  54
+  def test_quoted_pair
  55
+    chars = chars_quoted_pair
  56
+
  57
+    chars.each do |c|
  58
+      match = EmailAddress.parse(c, :root => :'quoted-pair')
  59
+      assert(match)
  60
+      assert_equal(c, match)
  61
+    end
  62
+  end
  63
+
  64
+  # atext           =   ALPHA / DIGIT /    ; Printable US-ASCII
  65
+  #                     "!" / "#" /        ;  characters not including
  66
+  #                     "$" / "%" /        ;  specials.  Used for atoms.
  67
+  #                     "&" / "'" /
  68
+  #                     "*" / "+" /
  69
+  #                     "-" / "/" /
  70
+  #                     "=" / "?" /
  71
+  #                     "^" / "_" /
  72
+  #                     "`" / "{" /
  73
+  #                     "|" / "}" /
  74
+  #                     "~"
  75
+  def test_atext
  76
+    chars  = ('A'..'Z').to_a
  77
+    chars += ('a'..'z').to_a
  78
+    chars += ('0'..'9').to_a
  79
+    chars.push(*%w[! # $ % & ' * + - / = ? ^ _ ` { | } ~])
  80
+
  81
+    chars.each do |c|
  82
+      match = EmailAddress.parse(c, :root => :atext)
  83
+      assert(match)
  84
+      assert_equal(c, match)
  85
+    end
  86
+  end
  87
+
  88
+  # qtext           =   %d33 /             ; Printable US-ASCII
  89
+  #                     %d35-91 /          ;  characters not including
  90
+  #                     %d93-126 /         ;  "\" or the quote character
  91
+  #                     obs-qtext
  92
+  def test_qtext
  93
+    chars  = ["\x21"]
  94
+    chars += ("\x23".."\x5B").to_a
  95
+    chars += ("\x5D".."\x7E").to_a
  96
+
  97
+    # obs-qtext
  98
+    chars += chars_obs_no_ws_ctl
  99
+
  100
+    chars.each do |c|
  101
+      match = EmailAddress.parse(c, :root => :qtext)
  102
+      assert(match)
  103
+      assert_equal(c, match)
  104
+    end
  105
+  end
  106
+
  107
+  # dtext           =   %d33-90 /          ; Printable US-ASCII
  108
+  #                     %d94-126 /         ;  characters not including
  109
+  #                     obs-dtext          ;  "[", "]", or "\"
  110
+  def test_dtext
  111
+    chars  = ("\x21".."\x5A").to_a
  112
+    chars += ("\x5E".."\x7E").to_a
  113
+
  114
+    # obs-dtext
  115
+    chars += chars_obs_no_ws_ctl
  116
+    chars += chars_quoted_pair
  117
+
  118
+    chars.each do |c|
  119
+      match = EmailAddress.parse(c, :root => :dtext)
  120
+      assert(match)
  121
+      assert_equal(c, match)
  122
+    end
  123
+  end
  124
+
  125
+  # text            =   %d1-9 /            ; Characters excluding CR
  126
+  #                     %d11 /             ;  and LF
  127
+  #                     %d12 /
  128
+  #                     %d14-127
  129
+  def test_text
  130
+    chars = chars_text
  131
+
  132
+    chars.each do |c|
  133
+      match = EmailAddress.parse(c, :root => :text)
  134
+      assert(match)
  135
+      assert_equal(c, match)
  136
+    end
  137
+  end
  138
+
  139
+  # [\x01-\x08\x0B\x0C\x0E-\x1F\x7F]
  140
+  def chars_no_ws_ctl
  141
+    chars  = ("\x01".."\x08").to_a
  142
+    chars << "\x0B"
  143
+    chars << "\x0C"
  144
+    chars += ("\x0E".."\x1F").to_a
  145
+    chars << "\x7F"
  146
+    chars
  147
+  end
  148
+
  149
+  # [\x01-\x09\x0B\x0C\x0E-\x7F]
  150
+  def chars_text
  151
+    chars  = ("\x01".."\x09").to_a
  152
+    chars << "\x0B"
  153
+    chars << "\x0C"
  154
+    chars += ("\x0E".."\x7F").to_a
  155
+    chars
  156
+  end
  157
+
  158
+  # [\x01-\x08\x0B\x0C\x0E-\x1F\x7F]
  159
+  def chars_obs_no_ws_ctl
  160
+    chars_no_ws_ctl
  161
+  end
  162
+
  163
+  # ("\\" text) | obs-qp
  164
+  def chars_quoted_pair
  165
+    chars  = chars_text.map {|c| "\\" + c }
  166
+    chars += chars_obs_qp
  167
+    chars
  168
+  end
  169
+
  170
+  # "\\" ("\x00" | obs-NO-WS-CTL | "\n" | "\r")
  171
+  def chars_obs_qp
  172
+    chars  = ["\x00"]
  173
+    chars += chars_obs_no_ws_ctl
  174
+    chars << "\n"
  175
+    chars << "\r"
  176
+    chars.map {|c| "\\" + c }
  177
+  end
  178
+end

0 notes on commit ff42c5f

Please sign in to comment.
Something went wrong with that request. Please try again.