email_reply_trimmer 0.1.12 → 0.2.0

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.
Files changed (38) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +1 -0
  3. data/Gemfile.lock +78 -17
  4. data/README.md +4 -4
  5. data/Rakefile +3 -6
  6. data/devenv.lock +184 -0
  7. data/devenv.nix +4 -0
  8. data/devenv.yaml +8 -0
  9. data/email_reply_trimmer.gemspec +4 -2
  10. data/lib/email_reply_trimmer/delimiter_matcher.rb +3 -2
  11. data/lib/email_reply_trimmer/email_header_matcher.rb +6 -5
  12. data/lib/email_reply_trimmer/embedded_email_matcher.rb +3 -2
  13. data/lib/email_reply_trimmer/empty_line_matcher.rb +1 -0
  14. data/lib/email_reply_trimmer/quote_matcher.rb +1 -0
  15. data/lib/email_reply_trimmer/signature_matcher.rb +2 -1
  16. data/lib/email_reply_trimmer.rb +83 -53
  17. data/test/before/forwarded_apple.txt +1 -0
  18. data/test/before/forwarded_gmail.txt +1 -0
  19. data/test/elided/block_code_spacers.txt +0 -0
  20. data/test/elided/forwarded_apple.txt +15 -0
  21. data/test/elided/forwarded_gmail.txt +15 -0
  22. data/test/elided/spam_1.txt +75 -0
  23. data/test/elided/spam_2.txt +152 -0
  24. data/test/emails/block_code_spacers.txt +13 -0
  25. data/test/emails/forwarded_apple.txt +17 -0
  26. data/test/emails/forwarded_gmail.txt +17 -0
  27. data/test/emails/spam_1.txt +75 -0
  28. data/test/emails/spam_2.txt +174 -0
  29. data/test/embedded/forwarded_apple.txt +13 -0
  30. data/test/embedded/forwarded_gmail.txt +14 -0
  31. data/test/test_email_matcher.rb +1 -0
  32. data/test/test_email_reply_trimmer.rb +6 -1
  33. data/test/trimmed/block_code_spacers.txt +13 -0
  34. data/test/trimmed/forwarded_apple.txt +1 -0
  35. data/test/trimmed/forwarded_gmail.txt +1 -0
  36. data/test/trimmed/spam_1.txt +0 -0
  37. data/test/trimmed/spam_2.txt +21 -0
  38. metadata +47 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: c6d1c0ab5d84950fc4aba02e7b9edbd6c0fabd44
4
- data.tar.gz: e895017cee98f971b69057efc009a014ad738bd0
2
+ SHA256:
3
+ metadata.gz: 9914eb793e4bbfa4f291097707acb2af27f491507b0e52b0e1433df3c1fb1f0d
4
+ data.tar.gz: 2c519cd4b6fe2db1dc3b12201c8a5bd540fbf274537610069b73d34bb3e0566f
5
5
  SHA512:
6
- metadata.gz: c9b776fa074024dd86bf367d66ff4631f721db08a6f1e77f08e3952096bc25e1225524c10f564be7c8e204f9696e41130fbae5bc3e2de66d63bc9fa2cd6ee3c3
7
- data.tar.gz: ff55cb8bbfcedb3c0284839e92ff2c4161123b78cb9c5fe7601a9b04268c69633dcb714fe967c605bcb07fc43b619804312ecf0503ca3ed993c092f0a5d6883f
6
+ metadata.gz: b0687f10183b5472c816d433c3f654dd085b8d615ef223c54e97e61e893c47752ed20eb5b1354c7d184ab84075de3c3fa492c76191b1fc0cfdcfc48a1d661b34
7
+ data.tar.gz: 3d740b872f6116bd0c59d2d1b19e405191f1c25c619e5564a602eebed3691323761292d7a063f7f224bacd668f2ede622eac085f7a5b7bad3b90570ac3b018b9
data/Gemfile CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  source 'https://rubygems.org'
2
3
 
3
4
  # Specify your gem's dependencies in email_reply_trimmer.gemspec
data/Gemfile.lock CHANGED
@@ -1,28 +1,88 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- email_reply_trimmer (0.1.11)
4
+ email_reply_trimmer (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- ast (2.4.0)
10
- minitest (5.11.3)
11
- parallel (1.12.1)
12
- parser (2.4.0.2)
13
- ast (~> 2.3)
14
- powerpack (0.1.1)
15
- rainbow (3.0.0)
16
- rake (12.3.0)
17
- rubocop (0.52.1)
9
+ activesupport (8.0.0)
10
+ base64
11
+ benchmark (>= 0.3)
12
+ bigdecimal
13
+ concurrent-ruby (~> 1.0, >= 1.3.1)
14
+ connection_pool (>= 2.2.5)
15
+ drb
16
+ i18n (>= 1.6, < 2)
17
+ logger (>= 1.4.2)
18
+ minitest (>= 5.1)
19
+ securerandom (>= 0.3)
20
+ tzinfo (~> 2.0, >= 2.0.5)
21
+ uri (>= 0.13.1)
22
+ ast (2.4.2)
23
+ base64 (0.2.0)
24
+ benchmark (0.4.0)
25
+ bigdecimal (3.1.8)
26
+ concurrent-ruby (1.3.4)
27
+ connection_pool (2.4.1)
28
+ drb (2.2.1)
29
+ i18n (1.14.6)
30
+ concurrent-ruby (~> 1.0)
31
+ json (2.8.2)
32
+ language_server-protocol (3.17.0.3)
33
+ logger (1.6.1)
34
+ minitest (5.25.2)
35
+ parallel (1.26.3)
36
+ parser (3.3.6.0)
37
+ ast (~> 2.4.1)
38
+ racc
39
+ racc (1.8.1)
40
+ rack (3.1.8)
41
+ rainbow (3.1.1)
42
+ rake (12.3.3)
43
+ regexp_parser (2.9.2)
44
+ rubocop (1.69.0)
45
+ json (~> 2.3)
46
+ language_server-protocol (>= 3.17.0)
18
47
  parallel (~> 1.10)
19
- parser (>= 2.4.0.2, < 3.0)
20
- powerpack (~> 0.1)
48
+ parser (>= 3.3.0.2)
21
49
  rainbow (>= 2.2.2, < 4.0)
50
+ regexp_parser (>= 2.4, < 3.0)
51
+ rubocop-ast (>= 1.36.1, < 2.0)
22
52
  ruby-progressbar (~> 1.7)
23
- unicode-display_width (~> 1.0, >= 1.0.1)
24
- ruby-progressbar (1.9.0)
25
- unicode-display_width (1.3.0)
53
+ unicode-display_width (>= 2.4.0, < 4.0)
54
+ rubocop-ast (1.36.2)
55
+ parser (>= 3.3.1.0)
56
+ rubocop-capybara (2.21.0)
57
+ rubocop (~> 1.41)
58
+ rubocop-discourse (3.8.6)
59
+ activesupport (>= 6.1)
60
+ rubocop (>= 1.59.0)
61
+ rubocop-capybara (>= 2.0.0)
62
+ rubocop-factory_bot (>= 2.0.0)
63
+ rubocop-rails (>= 2.25.0)
64
+ rubocop-rspec (>= 3.0.1)
65
+ rubocop-rspec_rails (>= 2.30.0)
66
+ rubocop-factory_bot (2.26.1)
67
+ rubocop (~> 1.61)
68
+ rubocop-rails (2.27.0)
69
+ activesupport (>= 4.2.0)
70
+ rack (>= 1.1)
71
+ rubocop (>= 1.52.0, < 2.0)
72
+ rubocop-ast (>= 1.31.1, < 2.0)
73
+ rubocop-rspec (3.2.0)
74
+ rubocop (~> 1.61)
75
+ rubocop-rspec_rails (2.30.0)
76
+ rubocop (~> 1.61)
77
+ rubocop-rspec (~> 3, >= 3.0.1)
78
+ ruby-progressbar (1.13.0)
79
+ securerandom (0.3.2)
80
+ tzinfo (2.0.6)
81
+ concurrent-ruby (~> 1.0)
82
+ unicode-display_width (3.1.2)
83
+ unicode-emoji (~> 4.0, >= 4.0.4)
84
+ unicode-emoji (4.0.4)
85
+ uri (1.0.2)
26
86
 
27
87
  PLATFORMS
28
88
  ruby
@@ -31,7 +91,8 @@ DEPENDENCIES
31
91
  email_reply_trimmer!
32
92
  minitest (~> 5)
33
93
  rake (~> 12)
34
- rubocop (~> 0.52.1)
94
+ rubocop
95
+ rubocop-discourse
35
96
 
36
97
  BUNDLED WITH
37
- 1.16.1
98
+ 2.5.22
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Discourse Email Reply Trimmer [![Build Status](https://api.travis-ci.org/discourse/email_reply_trimmer.svg?branch=master)](https://travis-ci.org/discourse/email_reply_trimmer)
1
+ # Discourse Email Reply Trimmer
2
2
 
3
3
  EmailReplyTrimmer is a small library to trim replies from plain text email.
4
4
 
@@ -16,6 +16,6 @@ Run `rake` to run the tests.
16
16
 
17
17
  ## Inspirations
18
18
 
19
- - [GitHub's Email Reply Parser](https://github.com/github/email_reply_parser)
20
- - [MailGun's Talon](https://github.com/mailgun/talon)
21
- - [Vitor R. Carvalho's Learning to Extract Signature and Reply Lines from Email](http://www.cs.cmu.edu/~vitor/papers/sigFilePaper_finalversion.pdf)
19
+ - [GitHub's Email Reply Parser](https://github.com/github/email_reply_parser)
20
+ - [MailGun's Talon](https://github.com/mailgun/talon)
21
+ - [Vitor R. Carvalho's Learning to Extract Signature and Reply Lines from Email](http://www.cs.cmu.edu/~vitor/papers/sigFilePaper_finalversion.pdf)
data/Rakefile CHANGED
@@ -1,10 +1,7 @@
1
- def name
2
- @name ||= Dir["*.gemspec"].first.split(".").first
3
- end
1
+ # frozen_string_literal: true
4
2
 
5
- def version
6
- @version ||= File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*['"](?'version'\d+\.\d+\.\d+)['"]/, "version"]
7
- end
3
+ name = Dir["*.gemspec"].first.split(".").first
4
+ version = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*['"](?'version'\d+\.\d+\.\d+)['"]/, "version"]
8
5
 
9
6
  task default: :test
10
7
 
data/devenv.lock ADDED
@@ -0,0 +1,184 @@
1
+ {
2
+ "nodes": {
3
+ "devenv": {
4
+ "locked": {
5
+ "dir": "src/modules",
6
+ "lastModified": 1732830318,
7
+ "owner": "cachix",
8
+ "repo": "devenv",
9
+ "rev": "51abcb75d471a215c800937d4e30dc765d305c6d",
10
+ "type": "github"
11
+ },
12
+ "original": {
13
+ "dir": "src/modules",
14
+ "owner": "cachix",
15
+ "repo": "devenv",
16
+ "type": "github"
17
+ }
18
+ },
19
+ "flake-compat": {
20
+ "flake": false,
21
+ "locked": {
22
+ "lastModified": 1732722421,
23
+ "owner": "edolstra",
24
+ "repo": "flake-compat",
25
+ "rev": "9ed2ac151eada2306ca8c418ebd97807bb08f6ac",
26
+ "type": "github"
27
+ },
28
+ "original": {
29
+ "owner": "edolstra",
30
+ "repo": "flake-compat",
31
+ "type": "github"
32
+ }
33
+ },
34
+ "flake-compat_2": {
35
+ "flake": false,
36
+ "locked": {
37
+ "lastModified": 1732722421,
38
+ "owner": "edolstra",
39
+ "repo": "flake-compat",
40
+ "rev": "9ed2ac151eada2306ca8c418ebd97807bb08f6ac",
41
+ "type": "github"
42
+ },
43
+ "original": {
44
+ "owner": "edolstra",
45
+ "repo": "flake-compat",
46
+ "type": "github"
47
+ }
48
+ },
49
+ "flake-utils": {
50
+ "inputs": {
51
+ "systems": "systems"
52
+ },
53
+ "locked": {
54
+ "lastModified": 1731533236,
55
+ "owner": "numtide",
56
+ "repo": "flake-utils",
57
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
58
+ "type": "github"
59
+ },
60
+ "original": {
61
+ "owner": "numtide",
62
+ "repo": "flake-utils",
63
+ "type": "github"
64
+ }
65
+ },
66
+ "gitignore": {
67
+ "inputs": {
68
+ "nixpkgs": [
69
+ "pre-commit-hooks",
70
+ "nixpkgs"
71
+ ]
72
+ },
73
+ "locked": {
74
+ "lastModified": 1709087332,
75
+ "owner": "hercules-ci",
76
+ "repo": "gitignore.nix",
77
+ "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
78
+ "type": "github"
79
+ },
80
+ "original": {
81
+ "owner": "hercules-ci",
82
+ "repo": "gitignore.nix",
83
+ "type": "github"
84
+ }
85
+ },
86
+ "nixpkgs": {
87
+ "locked": {
88
+ "lastModified": 1732617236,
89
+ "owner": "nixos",
90
+ "repo": "nixpkgs",
91
+ "rev": "af51545ec9a44eadf3fe3547610a5cdd882bc34e",
92
+ "type": "github"
93
+ },
94
+ "original": {
95
+ "owner": "nixos",
96
+ "ref": "nixpkgs-unstable",
97
+ "repo": "nixpkgs",
98
+ "type": "github"
99
+ }
100
+ },
101
+ "nixpkgs-ruby": {
102
+ "inputs": {
103
+ "flake-compat": "flake-compat",
104
+ "flake-utils": "flake-utils",
105
+ "nixpkgs": [
106
+ "nixpkgs"
107
+ ]
108
+ },
109
+ "locked": {
110
+ "lastModified": 1730958464,
111
+ "owner": "bobvanderlinden",
112
+ "repo": "nixpkgs-ruby",
113
+ "rev": "93bd040be2856ba0e44a33db6360e8c9c0c09aa1",
114
+ "type": "github"
115
+ },
116
+ "original": {
117
+ "owner": "bobvanderlinden",
118
+ "repo": "nixpkgs-ruby",
119
+ "type": "github"
120
+ }
121
+ },
122
+ "nixpkgs-stable": {
123
+ "locked": {
124
+ "lastModified": 1732749044,
125
+ "owner": "NixOS",
126
+ "repo": "nixpkgs",
127
+ "rev": "0c5b4ecbed5b155b705336aa96d878e55acd8685",
128
+ "type": "github"
129
+ },
130
+ "original": {
131
+ "owner": "NixOS",
132
+ "ref": "nixos-24.05",
133
+ "repo": "nixpkgs",
134
+ "type": "github"
135
+ }
136
+ },
137
+ "pre-commit-hooks": {
138
+ "inputs": {
139
+ "flake-compat": "flake-compat_2",
140
+ "gitignore": "gitignore",
141
+ "nixpkgs": [
142
+ "nixpkgs"
143
+ ],
144
+ "nixpkgs-stable": "nixpkgs-stable"
145
+ },
146
+ "locked": {
147
+ "lastModified": 1732021966,
148
+ "owner": "cachix",
149
+ "repo": "pre-commit-hooks.nix",
150
+ "rev": "3308484d1a443fc5bc92012435d79e80458fe43c",
151
+ "type": "github"
152
+ },
153
+ "original": {
154
+ "owner": "cachix",
155
+ "repo": "pre-commit-hooks.nix",
156
+ "type": "github"
157
+ }
158
+ },
159
+ "root": {
160
+ "inputs": {
161
+ "devenv": "devenv",
162
+ "nixpkgs": "nixpkgs",
163
+ "nixpkgs-ruby": "nixpkgs-ruby",
164
+ "pre-commit-hooks": "pre-commit-hooks"
165
+ }
166
+ },
167
+ "systems": {
168
+ "locked": {
169
+ "lastModified": 1681028828,
170
+ "owner": "nix-systems",
171
+ "repo": "default",
172
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
173
+ "type": "github"
174
+ },
175
+ "original": {
176
+ "owner": "nix-systems",
177
+ "repo": "default",
178
+ "type": "github"
179
+ }
180
+ }
181
+ },
182
+ "root": "root",
183
+ "version": 7
184
+ }
data/devenv.nix ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ languages.ruby.enable = true;
3
+ languages.ruby.version = "3.2";
4
+ }
data/devenv.yaml ADDED
@@ -0,0 +1,8 @@
1
+ inputs:
2
+ nixpkgs-ruby:
3
+ url: github:bobvanderlinden/nixpkgs-ruby
4
+ inputs:
5
+ nixpkgs:
6
+ follows: nixpkgs
7
+ nixpkgs:
8
+ url: github:nixos/nixpkgs/nixpkgs-unstable
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_relative "lib/email_reply_trimmer"
2
3
 
3
4
  Gem::Specification.new do |s|
@@ -9,7 +10,7 @@ Gem::Specification.new do |s|
9
10
  s.description = "EmailReplyTrimmer is a small library to trim replies from plain text email."
10
11
 
11
12
  s.authors = ["Régis Hanol"]
12
- s.email = ["regis+rubygems@hanol.fr"]
13
+ s.email = ["rubygems@hanol.fr"]
13
14
 
14
15
  s.homepage = "https://github.com/discourse/email_reply_trimmer"
15
16
  s.license = "MIT"
@@ -20,5 +21,6 @@ Gem::Specification.new do |s|
20
21
 
21
22
  s.add_development_dependency 'rake', '~> 12'
22
23
  s.add_development_dependency 'minitest', '~> 5'
23
- s.add_development_dependency 'rubocop', '~> 0.52.1'
24
+ s.add_development_dependency 'rubocop'
25
+ s.add_development_dependency 'rubocop-discourse'
24
26
  end
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  class DelimiterMatcher
2
3
 
3
- DELIMITER_CHARACTERS ||= "-_,=+~#*ᐧ—"
4
- DELIMITER_REGEX ||= /^[[:blank:]]*[#{Regexp.escape(DELIMITER_CHARACTERS)}]+[[:blank:]]*$/
4
+ DELIMITER_CHARACTERS = "-_,=+~#*ᐧ—"
5
+ DELIMITER_REGEX = /^[[:blank:]]*[#{Regexp.escape(DELIMITER_CHARACTERS)}]+[[:blank:]]*$/
5
6
 
6
7
  def self.match?(line)
7
8
  line =~ DELIMITER_REGEX
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
1
2
  class EmailHeaderMatcher
2
3
 
3
- EMAIL_HEADERS_WITH_DATE_MARKERS ||= [
4
+ EMAIL_HEADERS_WITH_DATE_MARKERS = [
4
5
  # Norwegian
5
6
  ["Sendt"],
6
7
  # English
@@ -25,11 +26,11 @@ class EmailHeaderMatcher
25
26
  ["发送时间"],
26
27
  ]
27
28
 
28
- EMAIL_HEADERS_WITH_DATE_REGEXES ||= EMAIL_HEADERS_WITH_DATE_MARKERS.map do |header|
29
+ EMAIL_HEADERS_WITH_DATE_REGEXES = EMAIL_HEADERS_WITH_DATE_MARKERS.map do |header|
29
30
  /^[[:blank:]*]*(?:#{header.join("|")})[[:blank:]*]*:.*\d+/
30
31
  end
31
32
 
32
- EMAIL_HEADERS_WITH_TEXT_MARKERS ||= [
33
+ EMAIL_HEADERS_WITH_TEXT_MARKERS = [
33
34
  # Norwegian
34
35
  ["Fra", "Til", "Emne"],
35
36
  # English
@@ -52,11 +53,11 @@ class EmailHeaderMatcher
52
53
  ["发件人", "收件人", "主题"],
53
54
  ]
54
55
 
55
- EMAIL_HEADERS_WITH_TEXT_REGEXES ||= EMAIL_HEADERS_WITH_TEXT_MARKERS.map do |header|
56
+ EMAIL_HEADERS_WITH_TEXT_REGEXES = EMAIL_HEADERS_WITH_TEXT_MARKERS.map do |header|
56
57
  /^[[:blank:]*]*(?:#{header.join("|")})[[:blank:]*]*:.*[[:word:]]+/i
57
58
  end
58
59
 
59
- EMAIL_HEADER_REGEXES ||= [
60
+ EMAIL_HEADER_REGEXES = [
60
61
  EMAIL_HEADERS_WITH_DATE_REGEXES,
61
62
  EMAIL_HEADERS_WITH_TEXT_REGEXES,
62
63
  ].flatten
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class EmbeddedEmailMatcher
2
3
 
3
4
  # On Wed, Sep 25, 2013, at 03:57 PM, jorge_castro wrote:
@@ -11,7 +12,7 @@ class EmbeddedEmailMatcher
11
12
  # Em seg, 27 de jul de 2015 17:13, Neil Lalonde <info@discourse.org> escreveu:
12
13
  # El jueves, 21 de noviembre de 2013, codinghorror escribió:
13
14
  # At 6/16/2016 08:32 PM, you wrote:
14
- ON_DATE_SOMEONE_WROTE_REGEXES ||= [
15
+ ON_DATE_SOMEONE_WROTE_REGEXES = [
15
16
  # Chinese
16
17
  /^[[:blank:]<>-]*在 (?:(?!\b(?>在|写道)\b).)+?写道[[:blank:].:>-]*$/im,
17
18
  # Dutch
@@ -72,7 +73,7 @@ class EmbeddedEmailMatcher
72
73
  end
73
74
 
74
75
  # Max Mustermann <try_discourse@discoursemail.com> schrieb am Fr., 28. Apr. 2017 um 11:53 Uhr:
75
- SOMEONE_WROTE_ON_DATE_REGEXES ||= [
76
+ SOMEONE_WROTE_ON_DATE_REGEXES = [
76
77
  # English
77
78
  /^.+\bwrote\b[[:space:]]+\bon\b.+[^:]+:/,
78
79
  # German
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class EmptyLineMatcher
2
3
 
3
4
  def self.match?(line)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class QuoteMatcher
2
3
 
3
4
  def self.match?(line)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class SignatureMatcher
2
3
 
3
4
  # Envoyé depuis mon iPhone
@@ -13,7 +14,7 @@ class SignatureMatcher
13
14
  # (sent from a phone)
14
15
  # (Sent from mobile device)
15
16
  # 從我的 iPhone 傳送
16
- SIGNATURE_REGEXES ||= [
17
+ SIGNATURE_REGEXES = [
17
18
  # Chinese
18
19
  /^[[:blank:]]*從我的 iPhone 傳送/i,
19
20
  # English