Skip to content

Instantly share code, notes, and snippets.

@ykon
Last active December 26, 2019 15:04
Show Gist options
  • Save ykon/e24fa91654efee17cca428dc05573d40 to your computer and use it in GitHub Desktop.
Save ykon/e24fa91654efee17cca428dc05573d40 to your computer and use it in GitHub Desktop.
# typed: true
# Ruby 2.6 (Function Composition, filter)
require 'sorbet-runtime'
class MailHeader
extend T::Sig
TEST_FILE_PATH = '/tmp/__mail_header_test_file__'
sig {void}
def self.make_test_file()
if FileTest.file?(TEST_FILE_PATH)
return
end
text = <<-EOS
Received: from mail2.example.jp (mail2 [127.0.0.1])
by mail2.example.jp (Postfix) with SMTP id 8EA8999C0C2;
Tue, 23 Aug 2011 11:06:24 +0900 (JST)
Received: from mail1.example.jp (unknown [172.16.0.1])
by mail2.example.jp (Postfix) with SMTP;
Tue, 23 Aug 2011 11:06:24 +0900 (JST)
Received: from ([192.168.1.1]) (envelope sender: <test01@example.com>)
by mail1.example.jp with Active!Hunter esmtp server;
Tue, 23 Aug 2011 11:06:18 +0900
From: Taro Yamada <taro@example.com>
To: Jiro Tanaka <tanaka@example.jp>, Saburo Watanabe <watanabe@example.jp>,
Hanako Takahashi <takahashi@example.jp>
Date: Mon, 22 Aug 2011 19:06:14 -0700
Subject: Hello
Message-ID: <CA79398B.2383D%yamada@example.com>
In-Reply-To: <20110804105830.000013F2.0681@example.jp>
Content-Type: text/plain
MIME-Version: 1.0
Empty:
Hi Taro
This is a test message.
END
EOS
File.write(TEST_FILE_PATH, text.gsub(/\n/, "\r\n"))
end
sig {params(text: String).returns(T::Array[String])}
def self.split_header_body(text)
res = text.split("\r\n\r\n", 2)
if res.length != 2 then raise ArgumentError end
res
end
sig {params(header: String).returns(String)}
def self.unfold_header(header)
header.gsub(/\r\n[ \t]+/, ' ')
end
sig {params(line: String).returns(T.nilable(T::Array[T.nilable(String)]))}
def self.split_field(line)
m = line.match(/(\S+): *(.+)?/)
m.nil? ? nil : [m[1], m[2].nil? ? nil : T.must(m[2]).rstrip]
end
sig {params(header: String).returns(T::Hash[String, T::Array[T.nilable(String)]])}
def self.parse_header(header)
if header.empty? then raise ArgumentError end
header.lines.map(&:chomp)
.map(&method(:split_field))
.filter{|a| !a.nil?}
.group_by{|fn,_| fn}
.map{|k,v| [k.downcase, v.map{|h| h[1]}]}.to_h
end
sig {void}
def self.main()
make_test_file()
text = File.read(TEST_FILE_PATH)
header, _ = split_header_body(text)
puts (method(:unfold_header) >> method(:parse_header)).call(T.must(header))
end
end
if __FILE__ == $PROGRAM_NAME
MailHeader.main()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment