Class: Hermeneutics::HeaderExt

Inherits:
Object
  • Object
show all
Defined in:
lib/hermeneutics/escape.rb

Overview

Header field contents (RFC 2047) encoding

Examples

HeaderExt.encode "Jörg Müller"
                              #=> "=?utf-8?Q?J=C3=B6rg_M=C3=BCller?="
HeaderExt.decode "=?UTF-8?Q?J=C3=B6rg_M=C3=BCller?="
                              #=> "Jörg Müller"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params = nil) ⇒ HeaderExt

:call-seq:

new( [ parameters] )    -> con

Creates a HeaderExt converter.

See the encode method for an explanation of the parameters.

Examples

con = HeaderExt.new
con = HeaderExt.new base64: true, limit: 32, lower: true
con = HeaderExt.new mask: /["'()]/


537
538
539
540
541
542
543
544
545
546
# File 'lib/hermeneutics/escape.rb', line 537

def initialize params = nil
  if params then
    @base64 = params.delete :base64
    @limit  = params.delete :limit
    @lower  = params.delete :lower
    @mask   = params.delete :mask
    params.empty? or
      raise ArgumentError, "invalid parameter: #{params.keys.first}."
  end
end

Class Method Details

.decode(str) ⇒ Object

:call-seq:

decode( str)     -> str

Remove header field style escapes.

HeaderExt.decode "=?UTF-8?Q?J=C3=B6rg_M=C3=BCller?="
                              #=> "Jörg Müller"


727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
# File 'lib/hermeneutics/escape.rb', line 727

def decode str
  r, e = [], []
  v, l = nil, nil
  lexer str do |type,piece|
    case type
      when :decoded then
        e.push piece.encoding
        if l == :space and (v == :decoded or not v) then
          r.pop
        elsif l == :plain then
          r.push SPACE
        end
      when :space then
        nil
      when :plain then
        if l == :decoded then
          r.push SPACE
        end
    end
    r.push piece
    v, l = l, type
  end
  if l == :space and v == :decoded then
    r.pop
  end
  e.uniq!
  begin
    r.join
  rescue EncodingError
    raise if e.empty?
    f = e.shift
    r.each { |x| x.encode! f }
    retry
  end
end

.encode(str) ⇒ Object

:call-seq:

encode( str)   -> str

Use the standard content encoding.



706
707
708
# File 'lib/hermeneutics/escape.rb', line 706

def encode str
  std.encode str
end

.encode_whole(str) ⇒ Object

:call-seq:

encode_whole( str)   -> str

Use the standard content encoding.



715
716
717
# File 'lib/hermeneutics/escape.rb', line 715

def encode_whole str
  std.encode_whole str
end

.lexer(str) ⇒ Object



763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
# File 'lib/hermeneutics/escape.rb', line 763

def lexer str
  while str do
    str =~ /(\s+)|\B=\?(\S*?)\?([QB])\?(\S*?)\?=\B/i
    if $1 then
      yield :plain, $` unless $`.empty?
      yield :space, $&
    elsif $2 then
      yield :plain, $` unless $`.empty?
      d = unmask $2, $3, $4
      yield :decoded, d
    else
      yield :plain, str
    end
    str = $'.notempty?
  end
end

.needs?(str) ⇒ Boolean

:call-seq:

needs? str  -> true or false

Use the standard content encoding.

Returns:

  • (Boolean)


697
698
699
# File 'lib/hermeneutics/escape.rb', line 697

def needs? str
  std.needs? str
end

.stdObject

The standard header content encoding has a word break limit of 64.



688
689
690
# File 'lib/hermeneutics/escape.rb', line 688

def std
  @std ||= new limit: 64
end

Instance Method Details

#decode(str) ⇒ Object



680
681
682
# File 'lib/hermeneutics/escape.rb', line 680

def decode str
  self.class.decode str
end

#encode(str) ⇒ Object

:call-seq:

encode( str)   -> str

Create a header field style encoded string. The following parameters will be evaluated:

:base64    # build ?B? instead of ?Q?
:limit     # break words longer than this
:lower     # build lower case ?b? and ?q?
:mask      # a regular expression detecting characters to mask

The result will not contain any 8-bit characters. The encoding will be kept although it won’t have a meaning.

The parameter :mask will have no influence on the masking itself but will guarantee characters to be masked.

Examples

yodel = "Holleri du dödl di, diri diri dudl dö."

con = HeaderExt.new
con.encode yodel
  #=> "Holleri du =?UTF-8?Q?d=C3=B6dl?= di, diri diri dudl =?UTF-8?Q?d=C3=B6=2E?="

yodel.encode! "iso8859-1"
con.encode yodel
  #=> "Holleri du =?ISO8859-1?Q?d=F6dl?= di, diri diri dudl =?ISO8859-1?Q?d=F6=2E?="

e = ""
e.encode! "utf-8"      ; con.encode e      #=> "=?UTF-8?Q?=E2=82=AC?="
e.encode! "iso8859-15" ; con.encode e      #=> "=?ISO8859-15?Q?=A4?="
e.encode! "ms-ansi"    ; con.encode e      #=> "=?MS-ANSI?Q?=80?="

con = HeaderExt.new mask: /["'()]/
con.encode "'Stop!' said Fred."
  #=> "=?UTF-8?Q?=27Stop=21=27?= said Fred."


595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
# File 'lib/hermeneutics/escape.rb', line 595

def encode str
  do_encoding str do
    # I don't like this kind of programming style but it seems to work. BS
    r, enc = "", ""
    while str =~ /\S+/ do
      if needs? $& then
        (enc.notempty? || r) << $`
        enc << $&
      else
        if not enc.empty? then
          r << (mask enc)
          enc.clear
        end
        r << $` << $&
      end
      str = $'
    end
    if not enc.empty? then
      enc << str
      r << (mask enc)
    else
      r << str
    end
    r
  end
end

#encode_whole(str) ⇒ Object

:call-seq:

encode_whole( str)   -> str

The unlike encode the whole string as one piece will be encoded.

yodel = "Holleri du dödl di, diri diri dudl dö."
HeaderExt.encode_whole yodel
  #=> "=?UTF-8?Q?Holleri_du_d=C3=B6dl_di,_diri_diri_dudl_d=C3=B6=2E?="


631
632
633
634
635
# File 'lib/hermeneutics/escape.rb', line 631

def encode_whole str
  do_encoding str do
    mask str
  end
end

#needs?(str) ⇒ Boolean

:call-seq:

needs? str  -> true or false

Check whether a string needs encoding.

Returns:

  • (Boolean)


553
554
555
# File 'lib/hermeneutics/escape.rb', line 553

def needs? str
  (not str.ascii_only? or str =~ @mask) and true or false
end