class Hermeneutics::Addr::Token

Attributes

data[RW]
quot[RW]
sym[RW]

Public Class Methods

new(sym, data = nil, quot = nil) click to toggle source
# File lib/hermeneutics/addrs.rb, line 170
def initialize sym, data = nil, quot = nil
  @sym, @data, @quot = sym, data, quot
end

Private Class Methods

compile(l, &block) click to toggle source
# File lib/hermeneutics/addrs.rb, line 443
def compile l, &block
  l = unspace l
  l = uncomment l
  g = split_groups l
  groups_compile g, &block
end
escaped(h, c) click to toggle source
# File lib/hermeneutics/addrs.rb, line 329
def escaped h, c
  if h then
    [h].pack "H2"
  else
    case c
      when "n" then "\n"
      when "r" then "\r"
      when "t" then "\t"
      when "f" then "\f"
      when "v" then "\v"
      when "b" then "\b"
      when "a" then "\a"
      when "e" then "\e"
      when "0" then "\0"
      else          c
    end
  end
end
find_one_of(l, s, t) click to toggle source
# File lib/hermeneutics/addrs.rb, line 563
def find_one_of l, s, t
  l.each_with_index { |e,i|
    if e === s then
      return i, nil
    elsif e === t then
      return nil, i
    end
  }
  nil
end
groups_compile(g) { |a, k| ... } click to toggle source
# File lib/hermeneutics/addrs.rb, line 450
def groups_compile g
  if block_given? then
    g.each { |k,v|
      split_list v do |m,r|
        a = new m, r
        yield a, k
      end
    }
    return
  end
  t = []
  groups_compile g do |a,| t.push a end
  t
end
lex_bslash(h, str) click to toggle source
# File lib/hermeneutics/addrs.rb, line 352
def lex_bslash h, str
  str.slice! /\A(?:x(..)|.)/
  y = escaped $1, $&
  Token[ :char, y, true]
end
lex_dquote(h, str) click to toggle source
# File lib/hermeneutics/addrs.rb, line 364
def lex_dquote h, str
  str.slice! /\A((?:[^\\"]|\\.)*)"?/
  y = $1.gsub /\\(x(..)|.)/ do |c,x|
    escaped x, c
  end
  Token[ :char, y, true]
end
lex_other(h, str) click to toggle source
# File lib/hermeneutics/addrs.rb, line 371
def lex_other h, str
  until str.empty? or SPECIAL.has_key? str.head do
    h << (str.eat 1)
  end
  Token[ :char, h]
end
lex_space(h, str) click to toggle source
# File lib/hermeneutics/addrs.rb, line 348
def lex_space h, str
  str.slice! /\A\s*/
  :space
end
lex_squote(h, str) click to toggle source
# File lib/hermeneutics/addrs.rb, line 357
def lex_squote h, str
  str.slice! /\A((?:[^\\']|\\.)*)'?/
  y = $1.gsub /\\(x(..)|.)/ do |c,x|
    escaped x, c
  end
  Token[ :char, y, true]
end
lexer(str) { |t| ... } click to toggle source
# File lib/hermeneutics/addrs.rb, line 291
def lexer str
  if block_given? then
    while str =~ /./m do
      h, str = $&, $'
      t = SPECIAL[ h]
      if respond_to? t, true then
        t = send t, h, str
      end
      unless Token === t then
        t = Token[ *t]
      end
      yield t
    end
  else
    r = []
    lexer str do |t| r.push t end
    r
  end
end
lexer_decode(str) { |Token| ... } click to toggle source
# File lib/hermeneutics/addrs.rb, line 311
def lexer_decode str, &block
  if block_given? then
    HeaderExt.lexer str do |k,s|
      case k
        when :decoded then yield Token[ :char, s, true]
        when :plain   then lexer s, &block
        when :space   then yield Token[ :space]
      end
    end
  else
    r = []
    lexer_decode str do |t| r.push t end
    r
  end
end
matches(l, *tokens) click to toggle source
# File lib/hermeneutics/addrs.rb, line 465
def matches l, *tokens
  z = tokens.zip l
  z.each { |(s,e)|
    e === s or return
  }
  true
end
parse(str, &block) click to toggle source

Parse a line from a string that was entered by the user.

x = "Meier, Hans <hmei@example.com>, foo@example.net"
Addr.parse x do |a,g|
  puts a.quote
end

# Output:
  "Meier, Hans" <hmei@example.com>
  <foo@example.net>
# File lib/hermeneutics/addrs.rb, line 417
def parse str, &block
  l = Token.lexer str
  compile l, &block
end
parse_decode(str, &block) click to toggle source

Parse a line from a mail header field and make addresses of it.

Internally the encoding class HeaderExt will be used.

x = "some: =?utf-8?q?M=C3=B6ller=2C_Fritz?= <fmoeller@example.com>"
Addr.parse_decode x do |addr,group|
  puts group.to_s
  puts addr.quote
end

# Output:
#   some
#   "Möller, Fritz" <fmoeller@example.com>
# File lib/hermeneutics/addrs.rb, line 436
def parse_decode str, &block
  l = Token.lexer_decode str
  compile l, &block
end
split_groups(l) click to toggle source
# File lib/hermeneutics/addrs.rb, line 515
def split_groups l
  g = []
  n = nil
  while l.any? do
    n = if matches l, :text, :colon then
      e = l.shift
      l.shift
      e.to_s
    end
    s = []
    until matches l, :semicol or l.empty? do
      s.push l.shift
    end
    l.shift
    g.push [ n, s]
  end
  g
end
split_list(l) { |Token, real&&Token| ... } click to toggle source
# File lib/hermeneutics/addrs.rb, line 534
def split_list l
  while l.any? do
    if matches l, :text, :comma, :text, :lang then
      t = l.first.to_s
      if t =~ /[^a-z0-9_]/ then
        e = Token[ :text, []]
        e.data.push l.shift
        e.data.push l.shift, Token[ :space]
        e.data.push l.shift
        l.unshift e
      end
    end
    a, c = find_one_of l, :lang, :comma
    if a then
      real = l.shift a if a.nonzero?
      l.shift
      a, c = find_one_of l, :rang, :comma
      mail = l.shift a||c||l.length
      l.shift
      l.shift if matches l, :comma
    else
      mail = l.shift c||l.length
      l.shift
      real = nil
    end
    yield Token[ :addr, mail], real&&Token[ :text, real]
  end
end
uncomment(l) click to toggle source
# File lib/hermeneutics/addrs.rb, line 499
def uncomment l
  r = []
  while l.any? do
    if matches l, :lparen then
      l.shift
      l = uncomment l
      until matches l, :rparen or l.empty? do
        l.shift
      end
      l.shift
    end
    r.push l.shift
  end
  r
end
unspace(l) click to toggle source
# File lib/hermeneutics/addrs.rb, line 473
def unspace l
  r = []
  while l.any? do
    if matches l, :space then
      l.shift
      next
    end
    if matches l, :char then
      e = Token[ :text, [ l.shift]]
      loop do
        if matches l, :char then
          e.data.push l.shift
        elsif matches l, :space, :char then
          e.data.push l.shift
          e.data.push l.shift
        else
          break
        end
      end
      l.unshift e
    end
    r.push l.shift
  end
  r
end

Public Instance Methods

===(oth) click to toggle source
# File lib/hermeneutics/addrs.rb, line 180
def === oth
  case oth
    when Symbol then @sym == oth
    when Token  then self == oth
  end
end
compact!() click to toggle source
# File lib/hermeneutics/addrs.rb, line 234
def compact!
  case @sym
    when :text then
      return if @data.length <= 1
      @data = [ Token[ :char, text, needs_quote?]]
    when :addr then
      d = []
      while @data.any? do
        x, y = d.last, @data.shift
        if y === :char and x === :char then
          x.data << y.data
          x.quot ||= y.quot
        else
          y.compact!
          d.push y
        end
      end
      @data = d
  end
end
encode() click to toggle source
# File lib/hermeneutics/addrs.rb, line 224
def encode
  case @sym
    when :addr  then data_map_join { |x| x.quote }
    when :text  then data_map_join { |x| x.encode }
    when :char  then encoded
    when :space then " "
    else             SPECIAL_CHARS[ @sym]||""
  end
end
force_encoding(enc) click to toggle source
# File lib/hermeneutics/addrs.rb, line 187
def force_encoding enc
  case @sym
    when :text  then @data.each { |x| x.force_encoding enc }
    when :char  then @data.force_encoding enc
  end
end
inspect() click to toggle source
# File lib/hermeneutics/addrs.rb, line 174
def inspect
  d = ": #{@data.inspect}" if @data
  d << " Q" if @quot
  "<##@sym#{d}>"
end
needs_quote?() click to toggle source
# File lib/hermeneutics/addrs.rb, line 255
def needs_quote?
  case @sym
    when :text  then @data.find { |x| x.needs_quote? }
    when :char  then @quot
    when :space then false
    when :addr  then false
    else             true
  end
end
quote() click to toggle source
# File lib/hermeneutics/addrs.rb, line 211
def quote
  case @sym
    when :text,
         :addr  then data_map_join { |x| x.quote }
    when :char  then quoted
    when :space then " "
    else             SPECIAL_CHARS[ @sym]||""
  end
rescue Encoding::CompatibilityError
  force_encoding Encoding::ASCII_8BIT
  retry
end
text() click to toggle source
# File lib/hermeneutics/addrs.rb, line 198
def text
  case @sym
    when :addr  then data_map_join { |x| x.quote }
    when :text  then data_map_join { |x| x.text }
    when :char  then @data
    when :space then " "
    else             SPECIAL_CHARS[ @sym]||""
  end
rescue Encoding::CompatibilityError
  force_encoding Encoding::ASCII_8BIT
  retry
end
to_s() click to toggle source
# File lib/hermeneutics/addrs.rb, line 194
def to_s
  text
end

Private Instance Methods

data_map_join() { |x| ... } click to toggle source
# File lib/hermeneutics/addrs.rb, line 267
def data_map_join
  @data.map { |x| yield x }.join
end
encoded() click to toggle source
# File lib/hermeneutics/addrs.rb, line 280
def encoded
  if @quot or HeaderExt.needs? @data then
    c = HeaderExt.new Addr.encoding_parameters
    c.encode_whole @data
  else
    @data
  end
end
quoted() click to toggle source
# File lib/hermeneutics/addrs.rb, line 271
def quoted
  if @quot then
    q = @data.gsub "\"" do |c| "\\" + c end
    %Q%"#{q}"%
  else
    @data
  end
end