email_reply_parser 0.5.9 → 0.5.10
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 +5 -5
- data/README.md +1 -1
- data/email_reply_parser.gemspec +6 -36
- data/lib/email_reply_parser.rb +4 -10
- data/test/email_reply_parser_test.rb +38 -28
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1d5b9fdfe30fe4feec4e1b84c68b25180b5da4cbe6aa8cebae7d7b725c6918c6
|
4
|
+
data.tar.gz: e046ee4ce446ee8a54d2e669ae1cd10bc0ae7e5f9e55c28d439991f7c8311965
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e4680771a08970cf019ad1bbeb7a2de56b34df351cca6a6a10aaeebff681eff71e4e2fce7809667ab9e5d1505506d5835d8e180dae731825c97a1ef3ae30cf8
|
7
|
+
data.tar.gz: cef0b121c8c201116348fa880274191b1020ed189c11b0c49a8f13e5d00b619a40aeac8eafe1fb09e908e9ff179d3b47692212364192fe3d7adde33a2c6cfc5f
|
data/README.md
CHANGED
data/email_reply_parser.gemspec
CHANGED
@@ -1,60 +1,33 @@
|
|
1
1
|
$LOAD_PATH.unshift '.'
|
2
2
|
require 'lib/email_reply_parser'
|
3
3
|
|
4
|
-
## This is the rakegem gemspec template. Make sure you read and understand
|
5
|
-
## all of the comments. Some sections require modification, and others can
|
6
|
-
## be deleted if you don't need them. Once you understand the contents of
|
7
|
-
## this file, feel free to delete any comments that begin with two hash marks.
|
8
|
-
## You can find comprehensive Gem::Specification documentation, at
|
9
|
-
## http://docs.rubygems.org/read/chapter/20
|
10
4
|
Gem::Specification.new do |s|
|
11
5
|
s.specification_version = 2 if s.respond_to? :specification_version=
|
12
6
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
13
7
|
s.rubygems_version = '1.3.5'
|
8
|
+
s.license = 'MIT'
|
14
9
|
|
15
|
-
## Leave these as is they will be modified for you by the rake gemspec task.
|
16
|
-
## If your rubyforge_project name is different, then edit it and comment out
|
17
|
-
## the sub! line in the Rakefile
|
18
10
|
s.name = 'email_reply_parser'
|
19
11
|
s.version = EmailReplyParser::VERSION
|
20
12
|
s.date = Time.now.strftime('%Y-%m-%d')
|
21
|
-
s.rubyforge_project = 'email_reply_parser'
|
22
13
|
|
23
|
-
|
24
|
-
|
25
|
-
s.
|
26
|
-
|
14
|
+
s.summary = "EmailReplyParser is a small library to parse plain text " \
|
15
|
+
"email content."
|
16
|
+
s.description = "EmailReplyParser is a small library to parse plain text " \
|
17
|
+
"email content. This is what GitHub uses to display comments " \
|
18
|
+
"that were created from email replies."
|
27
19
|
|
28
|
-
## List the primary authors. If there are a bunch of authors, it's probably
|
29
|
-
## better to set the email to an email list or something. If you don't have
|
30
|
-
## a custom homepage, consider using your GitHub URL or the like.
|
31
20
|
s.authors = ["Rick Olson"]
|
32
21
|
s.email = 'technoweenie@gmail.com'
|
33
22
|
s.homepage = 'http://github.com/github/email_reply_parser'
|
34
23
|
|
35
|
-
## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
|
36
|
-
## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
|
37
24
|
s.require_paths = %w[lib]
|
38
25
|
|
39
|
-
## This sections is only necessary if you have C extensions.
|
40
|
-
#s.require_paths << 'ext'
|
41
|
-
#s.extensions = %w[ext/extconf.rb]
|
42
|
-
|
43
|
-
## If your gem includes any executables, list them here.
|
44
|
-
#s.executables = ["name"]
|
45
|
-
#s.default_executable = 'name'
|
46
|
-
|
47
|
-
## Specify any RDoc options here. You'll want to add your README and
|
48
|
-
## LICENSE files to the extra_rdoc_files list.
|
49
26
|
s.rdoc_options = ["--charset=UTF-8"]
|
50
27
|
s.extra_rdoc_files = %w[README.md LICENSE]
|
51
28
|
|
52
|
-
## List your runtime dependencies here. Runtime dependencies are those
|
53
|
-
## that are needed for an end user to actually USE your code.
|
54
29
|
#s.add_dependency('DEPNAME', [">= 1.1.0", "< 2.0.0"])
|
55
30
|
|
56
|
-
## List your development dependencies here. Development dependencies are
|
57
|
-
## those that are only needed during development
|
58
31
|
#s.add_development_dependency('DEVDEPNAME', [">= 1.1.0", "< 2.0.0"])
|
59
32
|
|
60
33
|
## Leave this section as-is. It will be automatically generated from the
|
@@ -93,8 +66,5 @@ Gem::Specification.new do |s|
|
|
93
66
|
]
|
94
67
|
# = MANIFEST =
|
95
68
|
|
96
|
-
## Test files will be grabbed from the file list. Make sure the path glob
|
97
|
-
## matches what you actually use.
|
98
69
|
s.test_files = s.files.select { |path| path =~ /^test\/.*_test\.rb/ }
|
99
70
|
end
|
100
|
-
|
data/lib/email_reply_parser.rb
CHANGED
@@ -30,7 +30,7 @@ require 'strscan'
|
|
30
30
|
#
|
31
31
|
# [mail]: https://github.com/mikel/mail
|
32
32
|
class EmailReplyParser
|
33
|
-
VERSION = "0.5.
|
33
|
+
VERSION = "0.5.10"
|
34
34
|
|
35
35
|
# Public: Splits an email body into a list of Fragments.
|
36
36
|
#
|
@@ -132,14 +132,8 @@ class EmailReplyParser
|
|
132
132
|
|
133
133
|
private
|
134
134
|
EMPTY = "".freeze
|
135
|
-
SIGNATURE = '(?m)(--\s*$|__\s*$|\w-$)|(^(\w+\s
|
136
|
-
|
137
|
-
begin
|
138
|
-
require 're2'
|
139
|
-
SIG_REGEX = RE2::Regexp.new(SIGNATURE)
|
140
|
-
rescue LoadError
|
141
|
-
SIG_REGEX = Regexp.new(SIGNATURE)
|
142
|
-
end
|
135
|
+
SIGNATURE = '(?m)(--\s*$|__\s*$|\w-$)|(^(\w+\s+){1,3}ym morf tneS$)'
|
136
|
+
SIG_REGEX = Regexp.new(SIGNATURE)
|
143
137
|
|
144
138
|
### Line-by-Line Parsing
|
145
139
|
|
@@ -188,7 +182,7 @@ class EmailReplyParser
|
|
188
182
|
#
|
189
183
|
# Returns true if the line is a valid header, or false.
|
190
184
|
def quote_header?(line)
|
191
|
-
line =~ /^:etorw.*nO$/
|
185
|
+
line =~ /^:etorw.*nO$/ || line =~ /^.*:(morF|tneS|oT|tcejbuS)$/
|
192
186
|
end
|
193
187
|
|
194
188
|
# Builds the fragment string and reverses it, after all lines have been
|
@@ -50,10 +50,10 @@ I am currently using the Java HTTP API.\n", reply.fragments[0].to_s
|
|
50
50
|
assert_equal [false, true, false, false, true],
|
51
51
|
reply.fragments.map { |f| f.signature? }
|
52
52
|
|
53
|
-
assert_match
|
54
|
-
assert_match
|
55
|
-
assert_match
|
56
|
-
assert_match
|
53
|
+
assert_match(/^Oh thanks.\n\nHaving/, reply.fragments[0].to_s)
|
54
|
+
assert_match(/^-A/, reply.fragments[1].to_s)
|
55
|
+
assert_match(/^On [^\:]+\:/, reply.fragments[2].to_s)
|
56
|
+
assert_match(/^_/, reply.fragments[4].to_s)
|
57
57
|
end
|
58
58
|
|
59
59
|
def test_reads_bottom_post
|
@@ -68,10 +68,10 @@ I am currently using the Java HTTP API.\n", reply.fragments[0].to_s
|
|
68
68
|
reply.fragments.map { |f| f.hidden? }
|
69
69
|
|
70
70
|
assert_equal "Hi,", reply.fragments[0].to_s
|
71
|
-
assert_match
|
72
|
-
assert_match
|
73
|
-
assert_match
|
74
|
-
assert_match
|
71
|
+
assert_match(/^On [^\:]+\:/, reply.fragments[1].to_s)
|
72
|
+
assert_match(/^You can list/, reply.fragments[2].to_s)
|
73
|
+
assert_match(/^> /, reply.fragments[3].to_s)
|
74
|
+
assert_match(/^_/, reply.fragments[5].to_s)
|
75
75
|
end
|
76
76
|
|
77
77
|
def test_reads_inline_replies
|
@@ -85,11 +85,11 @@ I am currently using the Java HTTP API.\n", reply.fragments[0].to_s
|
|
85
85
|
assert_equal [false, false, false, false, true, true, true],
|
86
86
|
reply.fragments.map { |f| f.hidden? }
|
87
87
|
|
88
|
-
assert_match
|
89
|
-
assert_match
|
88
|
+
assert_match(/^On [^\:]+\:/, reply.fragments[0].to_s)
|
89
|
+
assert_match(/^I will reply/, reply.fragments[1].to_s)
|
90
90
|
assert_match "okay?", reply.fragments[2].to_s
|
91
|
-
assert_match
|
92
|
-
assert_match
|
91
|
+
assert_match(/^and under this./, reply.fragments[3].to_s)
|
92
|
+
assert_match(/inline/, reply.fragments[4].to_s)
|
93
93
|
assert_equal "\n", reply.fragments[5].to_s
|
94
94
|
assert_equal "--\nHey there, this is my signature\n", reply.fragments[6].to_s
|
95
95
|
end
|
@@ -97,9 +97,9 @@ I am currently using the Java HTTP API.\n", reply.fragments[0].to_s
|
|
97
97
|
def test_recognizes_date_string_above_quote
|
98
98
|
reply = email :email_1_4
|
99
99
|
|
100
|
-
assert_match
|
101
|
-
assert_match
|
102
|
-
assert_match
|
100
|
+
assert_match(/^Awesome/, reply.fragments[0].to_s)
|
101
|
+
assert_match(/^On/, reply.fragments[1].to_s)
|
102
|
+
assert_match(/Loader/, reply.fragments[1].to_s)
|
103
103
|
end
|
104
104
|
|
105
105
|
def test_a_complex_body_with_only_one_fragment
|
@@ -115,23 +115,28 @@ I am currently using the Java HTTP API.\n", reply.fragments[0].to_s
|
|
115
115
|
assert_equal [false, false], reply.fragments.map { |f| f.quoted? }
|
116
116
|
assert_equal [false, true], reply.fragments.map { |f| f.signature? }
|
117
117
|
assert_equal [false, true], reply.fragments.map { |f| f.hidden? }
|
118
|
-
assert_match
|
118
|
+
assert_match(/^-- \nrick/, reply.fragments[1].to_s)
|
119
119
|
end
|
120
120
|
|
121
121
|
def test_deals_with_multiline_reply_headers
|
122
122
|
reply = email :email_1_6
|
123
123
|
|
124
|
-
assert_match
|
125
|
-
assert_match
|
126
|
-
assert_match
|
124
|
+
assert_match(/^I get/, reply.fragments[0].to_s)
|
125
|
+
assert_match(/^On/, reply.fragments[1].to_s)
|
126
|
+
assert_match(/Was this/, reply.fragments[1].to_s)
|
127
127
|
end
|
128
128
|
|
129
129
|
def test_deals_with_windows_line_endings
|
130
130
|
reply = email :email_1_7
|
131
131
|
|
132
|
-
assert_match
|
133
|
-
assert_match
|
134
|
-
assert_match
|
132
|
+
assert_match(/:\+1:/, reply.fragments[0].to_s)
|
133
|
+
assert_match(/^On/, reply.fragments[1].to_s)
|
134
|
+
assert_match(/Steps 0-2/, reply.fragments[1].to_s)
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_handles_non_ascii_characters
|
138
|
+
non_ascii_body = "Here’s a test."
|
139
|
+
assert_equal non_ascii_body, EmailReplyParser.parse_reply(non_ascii_body)
|
135
140
|
end
|
136
141
|
|
137
142
|
def test_does_not_modify_input_string
|
@@ -155,6 +160,11 @@ I am currently using the Java HTTP API.\n", reply.fragments[0].to_s
|
|
155
160
|
assert_equal "Outlook with a reply directly above line", EmailReplyParser.parse_reply(body)
|
156
161
|
end
|
157
162
|
|
163
|
+
def test_parse_out_just_top_for_outlook_with_no_line
|
164
|
+
body = IO.read EMAIL_FIXTURE_PATH.join("email_2_3.txt").to_s
|
165
|
+
assert_equal "Outlook with a reply directly above line", EmailReplyParser.parse_reply(body)
|
166
|
+
end
|
167
|
+
|
158
168
|
def test_parse_out_sent_from_iPhone
|
159
169
|
body = IO.read EMAIL_FIXTURE_PATH.join("email_iPhone.txt").to_s
|
160
170
|
assert_equal "Here is another email", EmailReplyParser.parse_reply(body)
|
@@ -188,14 +198,14 @@ I am currently using the Java HTTP API.\n", reply.fragments[0].to_s
|
|
188
198
|
|
189
199
|
def test_one_is_not_on
|
190
200
|
reply = email("email_one_is_not_on")
|
191
|
-
assert_match
|
192
|
-
assert_match
|
201
|
+
assert_match(/One outstanding question/, reply.fragments[0].to_s)
|
202
|
+
assert_match(/^On Oct 1, 2012/, reply.fragments[1].to_s)
|
193
203
|
end
|
194
204
|
|
195
205
|
def test_mulitple_on
|
196
206
|
reply = email("greedy_on")
|
197
|
-
assert_match
|
198
|
-
assert_match
|
207
|
+
assert_match(/^On your remote host/, reply.fragments[0].to_s)
|
208
|
+
assert_match(/^On 9 Jan 2014/, reply.fragments[1].to_s)
|
199
209
|
assert_equal [false, true, false], reply.fragments.map { |f| f.quoted? }
|
200
210
|
assert_equal [false, false, false], reply.fragments.map { |f| f.signature? }
|
201
211
|
assert_equal [false, true, true], reply.fragments.map { |f| f.hidden? }
|
@@ -203,8 +213,8 @@ I am currently using the Java HTTP API.\n", reply.fragments[0].to_s
|
|
203
213
|
|
204
214
|
def test_pathological_emails
|
205
215
|
t0 = Time.now
|
206
|
-
|
207
|
-
assert (Time.now - t0) < 1, "Took too long, upgrade to re2 gem."
|
216
|
+
email("pathological")
|
217
|
+
assert (Time.now - t0) < 1, "Took too long, upgrade to re2 gem. See https://rubygems.org/gems/re2"
|
208
218
|
end
|
209
219
|
|
210
220
|
def test_doesnt_remove_signature_delimiter_in_mid_line
|
metadata
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: email_reply_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rick Olson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-08-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description:
|
13
|
+
description: EmailReplyParser is a small library to parse plain text email content.
|
14
|
+
This is what GitHub uses to display comments that were created from email replies.
|
14
15
|
email: technoweenie@gmail.com
|
15
16
|
executables: []
|
16
17
|
extensions: []
|
@@ -47,7 +48,8 @@ files:
|
|
47
48
|
- test/emails/greedy_on.txt
|
48
49
|
- test/emails/pathological.txt
|
49
50
|
homepage: http://github.com/github/email_reply_parser
|
50
|
-
licenses:
|
51
|
+
licenses:
|
52
|
+
- MIT
|
51
53
|
metadata: {}
|
52
54
|
post_install_message:
|
53
55
|
rdoc_options:
|
@@ -65,11 +67,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
65
67
|
- !ruby/object:Gem::Version
|
66
68
|
version: '0'
|
67
69
|
requirements: []
|
68
|
-
|
69
|
-
rubygems_version: 2.6.6
|
70
|
+
rubygems_version: 3.0.1
|
70
71
|
signing_key:
|
71
72
|
specification_version: 2
|
72
|
-
summary:
|
73
|
+
summary: EmailReplyParser is a small library to parse plain text email content.
|
73
74
|
test_files:
|
74
75
|
- test/email_reply_parser_test.rb
|
75
|
-
has_rdoc:
|