isomorfeus-mailer 2.0.0.rc5 → 2.0.0.rc6
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 +4 -4
- data/LICENSE +4 -0
- data/lib/isomorfeus/html2text.rb +268 -0
- data/lib/isomorfeus/mailer/version.rb +1 -1
- data/lib/isomorfeus-mailer.rb +2 -1
- metadata +20 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98507154da2d33348d785c83bfec5f8260aa0fd93b945c8cbb6ae87f7f0391ce
|
4
|
+
data.tar.gz: 9a9255bb1f5dea7fd0b079db6e71ecd12db31ae7c0a0db5c941ad49439dcda3f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68a4488a9a5aed3f102aa208c28f5ff084b7a6af9b08c7af6877b7695fed0b35d8f0396520e44d6916d5cea417c138978ba638b38ec483a4af37886d43ffb9c8
|
7
|
+
data.tar.gz: 7a0219c4a75ae76886ba4fc9ca8719413a1b1b8ec276c96b70ba21aa15c3c3b323e9c25dea979c7fc1b50a0dbd4497dc89269169ee5cb299b234996ef573ed8a
|
data/LICENSE
CHANGED
@@ -19,3 +19,7 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
21
|
SOFTWARE.
|
22
|
+
|
23
|
+
file lib/isomorfeus/html2text.rb originally taken from https://github.com/soundasleep/html2text_ruby:
|
24
|
+
|
25
|
+
MIT License as above, Copyright 2015 Jevon Wright
|
@@ -0,0 +1,268 @@
|
|
1
|
+
class Html2Text
|
2
|
+
VERSION = "0.3.1"
|
3
|
+
|
4
|
+
attr_reader :doc
|
5
|
+
|
6
|
+
def initialize(doc)
|
7
|
+
@doc = doc
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.convert(html)
|
11
|
+
html = html.to_s
|
12
|
+
|
13
|
+
if is_office_document?(html)
|
14
|
+
# Emulate the CSS rendering of Office documents
|
15
|
+
html = html.gsub("<p class=MsoNormal>", "<br>")
|
16
|
+
.gsub("<o:p> </o:p>", "<br>")
|
17
|
+
.gsub("<o:p></o:p>", "")
|
18
|
+
end
|
19
|
+
|
20
|
+
if !html.include?("<html")
|
21
|
+
# Stop Nokogiri from inserting in <p> tags
|
22
|
+
html = "<div>#{html}</div>"
|
23
|
+
end
|
24
|
+
|
25
|
+
html = fix_newlines(replace_entities(html))
|
26
|
+
doc = Nokogiri::HTML(html)
|
27
|
+
|
28
|
+
Html2Text.new(doc).convert
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.fix_newlines(text)
|
32
|
+
text.gsub("\r\n", "\n").gsub("\r", "\n")
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.replace_entities(text)
|
36
|
+
text.gsub(" ", " ").gsub("\u00a0", " ").gsub("‌", "")
|
37
|
+
end
|
38
|
+
|
39
|
+
def convert
|
40
|
+
output = iterate_over(doc)
|
41
|
+
output = remove_leading_and_trailing_whitespace(output)
|
42
|
+
output = remove_unnecessary_empty_lines(output)
|
43
|
+
return output.strip
|
44
|
+
end
|
45
|
+
|
46
|
+
DO_NOT_TOUCH_WHITESPACE = "<do-not-touch-whitespace>"
|
47
|
+
|
48
|
+
def remove_leading_and_trailing_whitespace(text)
|
49
|
+
# ignore any <pre> blocks, which we don't want to interact with
|
50
|
+
pre_blocks = text.split(DO_NOT_TOUCH_WHITESPACE)
|
51
|
+
|
52
|
+
output = []
|
53
|
+
pre_blocks.each.with_index do |block, index|
|
54
|
+
if index % 2 == 0
|
55
|
+
output << block.gsub(/[ \t]*\n[ \t]*/im, "\n").gsub(/ *\t */im, "\t")
|
56
|
+
else
|
57
|
+
output << block
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
output.join("")
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def self.is_office_document?(text)
|
67
|
+
text.include?("urn:schemas-microsoft-com:office")
|
68
|
+
end
|
69
|
+
|
70
|
+
def remove_unnecessary_empty_lines(text)
|
71
|
+
text.gsub(/\n\n\n*/im, "\n\n")
|
72
|
+
end
|
73
|
+
|
74
|
+
def trimmed_whitespace(text)
|
75
|
+
# Replace whitespace characters with a space (equivalent to \s)
|
76
|
+
# and force any text encoding into UTF-8
|
77
|
+
if text.valid_encoding?
|
78
|
+
text.gsub(/[\t\n\f\r ]+/im, " ")
|
79
|
+
else
|
80
|
+
text.force_encoding("WINDOWS-1252")
|
81
|
+
return trimmed_whitespace(text.encode("UTF-16be", invalid: :replace, replace: "?").encode('UTF-8'))
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def iterate_over(node)
|
86
|
+
return "\n" if node.name.downcase == "br" && next_node_is_text?(node)
|
87
|
+
|
88
|
+
return trimmed_whitespace(node.text) if node.text?
|
89
|
+
|
90
|
+
if ["style", "head", "title", "meta", "script"].include?(node.name.downcase)
|
91
|
+
return ""
|
92
|
+
end
|
93
|
+
|
94
|
+
if node.name.downcase == "pre"
|
95
|
+
return "\n#{DO_NOT_TOUCH_WHITESPACE}#{node.text}#{DO_NOT_TOUCH_WHITESPACE}"
|
96
|
+
end
|
97
|
+
|
98
|
+
output = []
|
99
|
+
|
100
|
+
output << prefix_whitespace(node)
|
101
|
+
output += node.children.map do |child|
|
102
|
+
if !child.name.nil?
|
103
|
+
iterate_over(child)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
output << suffix_whitespace(node)
|
107
|
+
|
108
|
+
output = output.compact.join("") || ""
|
109
|
+
|
110
|
+
if !node.name.nil?
|
111
|
+
if node.name.downcase == "a"
|
112
|
+
output = wrap_link(node, output)
|
113
|
+
elsif node.name.downcase == "img"
|
114
|
+
output = image_text(node)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
return output
|
119
|
+
end
|
120
|
+
|
121
|
+
def prefix_whitespace(node)
|
122
|
+
case node.name.downcase
|
123
|
+
when "hr"
|
124
|
+
"\n---------------------------------------------------------------\n"
|
125
|
+
|
126
|
+
when "h1", "h2", "h3", "h4", "h5", "h6", "ol", "ul"
|
127
|
+
"\n\n"
|
128
|
+
|
129
|
+
when "p"
|
130
|
+
"\n\n"
|
131
|
+
|
132
|
+
when "tr"
|
133
|
+
"\n"
|
134
|
+
|
135
|
+
when "div"
|
136
|
+
if node.parent.name == "div" && (node.parent.text.strip == node.text.strip)
|
137
|
+
""
|
138
|
+
else
|
139
|
+
"\n"
|
140
|
+
end
|
141
|
+
|
142
|
+
when "td", "th"
|
143
|
+
"\t"
|
144
|
+
|
145
|
+
when "li"
|
146
|
+
"- "
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def suffix_whitespace(node)
|
151
|
+
case node.name.downcase
|
152
|
+
when "h1", "h2", "h3", "h4", "h5", "h6"
|
153
|
+
# add another line
|
154
|
+
"\n\n"
|
155
|
+
|
156
|
+
when "p"
|
157
|
+
"\n\n"
|
158
|
+
|
159
|
+
when "br"
|
160
|
+
if next_node_name(node) != "div" && next_node_name(node) != nil
|
161
|
+
"\n"
|
162
|
+
end
|
163
|
+
|
164
|
+
when "li"
|
165
|
+
"\n"
|
166
|
+
|
167
|
+
when "div"
|
168
|
+
if next_node_is_text?(node)
|
169
|
+
"\n"
|
170
|
+
elsif next_node_name(node) != "div" && next_node_name(node) != nil
|
171
|
+
"\n"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# links are returned in [text](link) format
|
177
|
+
def wrap_link(node, output)
|
178
|
+
href = node.attribute("href")
|
179
|
+
name = node.attribute("name")
|
180
|
+
|
181
|
+
output = output.strip
|
182
|
+
|
183
|
+
# remove double [[ ]]s from linking images
|
184
|
+
if output[0] == "[" && output[-1] == "]"
|
185
|
+
output = output[1, output.length - 2]
|
186
|
+
|
187
|
+
# for linking images, the title of the <a> overrides the title of the <img>
|
188
|
+
if node.attribute("title")
|
189
|
+
output = node.attribute("title").to_s
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# if there is no link text, but a title attr
|
194
|
+
if output.empty? && node.attribute("title")
|
195
|
+
output = node.attribute("title").to_s
|
196
|
+
end
|
197
|
+
|
198
|
+
if href.nil?
|
199
|
+
if !name.nil?
|
200
|
+
output = "[#{output}]"
|
201
|
+
end
|
202
|
+
else
|
203
|
+
href = href.to_s
|
204
|
+
|
205
|
+
if href != output && href != "mailto:#{output}" &&
|
206
|
+
href != "http://#{output}" && href != "https://#{output}"
|
207
|
+
if output.empty?
|
208
|
+
output = href
|
209
|
+
else
|
210
|
+
output = "[#{output}](#{href})"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
case next_node_name(node)
|
216
|
+
when "h1", "h2", "h3", "h4", "h5", "h6"
|
217
|
+
output += "\n"
|
218
|
+
end
|
219
|
+
|
220
|
+
output
|
221
|
+
end
|
222
|
+
|
223
|
+
def image_text(node)
|
224
|
+
if node.attribute("title")
|
225
|
+
"[" + node.attribute("title").to_s + "]"
|
226
|
+
elsif node.attribute("alt")
|
227
|
+
"[" + node.attribute("alt").to_s + "]"
|
228
|
+
else
|
229
|
+
""
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def next_node_name(node)
|
234
|
+
next_node = node.next_sibling
|
235
|
+
while next_node != nil
|
236
|
+
break if next_node.element?
|
237
|
+
next_node = next_node.next_sibling
|
238
|
+
end
|
239
|
+
|
240
|
+
if next_node && next_node.element?
|
241
|
+
next_node.name.downcase
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def next_node_is_text?(node)
|
246
|
+
return !node.next_sibling.nil? && node.next_sibling.text? && !node.next_sibling.text.strip.empty?
|
247
|
+
end
|
248
|
+
|
249
|
+
def previous_node_name(node)
|
250
|
+
previous_node = node.previous_sibling
|
251
|
+
while previous_node != nil
|
252
|
+
break if previous_node.element?
|
253
|
+
previous_node = previous_node.previous_sibling
|
254
|
+
end
|
255
|
+
|
256
|
+
if previous_node && previous_node.element?
|
257
|
+
previous_node.name.downcase
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def previous_node_is_text?(node)
|
262
|
+
return !node.previous_sibling.nil? && node.previous_sibling.text? && !node.previous_sibling.text.strip.empty?
|
263
|
+
end
|
264
|
+
|
265
|
+
# def previous_node_is_not_text?(node)
|
266
|
+
# return node.previous_sibling.nil? || !node.previous_sibling.text? || node.previous_sibling.text.strip.empty?
|
267
|
+
# end
|
268
|
+
end
|
data/lib/isomorfeus-mailer.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: isomorfeus-mailer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.rc6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Biedermann
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '6.1'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: html2text
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 0.3.1
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 0.3.1
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: mailhandler
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,28 +128,28 @@ dependencies:
|
|
142
128
|
requirements:
|
143
129
|
- - '='
|
144
130
|
- !ruby/object:Gem::Version
|
145
|
-
version: 2.0.0.
|
131
|
+
version: 2.0.0.rc6
|
146
132
|
type: :runtime
|
147
133
|
prerelease: false
|
148
134
|
version_requirements: !ruby/object:Gem::Requirement
|
149
135
|
requirements:
|
150
136
|
- - '='
|
151
137
|
- !ruby/object:Gem::Version
|
152
|
-
version: 2.0.0.
|
138
|
+
version: 2.0.0.rc6
|
153
139
|
- !ruby/object:Gem::Dependency
|
154
140
|
name: isomorfeus
|
155
141
|
requirement: !ruby/object:Gem::Requirement
|
156
142
|
requirements:
|
157
143
|
- - '='
|
158
144
|
- !ruby/object:Gem::Version
|
159
|
-
version: 2.0.0.
|
145
|
+
version: 2.0.0.rc6
|
160
146
|
type: :development
|
161
147
|
prerelease: false
|
162
148
|
version_requirements: !ruby/object:Gem::Requirement
|
163
149
|
requirements:
|
164
150
|
- - '='
|
165
151
|
- !ruby/object:Gem::Version
|
166
|
-
version: 2.0.0.
|
152
|
+
version: 2.0.0.rc6
|
167
153
|
- !ruby/object:Gem::Dependency
|
168
154
|
name: rake
|
169
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,6 +178,20 @@ dependencies:
|
|
192
178
|
- - "~>"
|
193
179
|
- !ruby/object:Gem::Version
|
194
180
|
version: 3.10.0
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: rspec-collection_matchers
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: 1.2.0
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - "~>"
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: 1.2.0
|
195
195
|
description: Write mail template components and send mail.
|
196
196
|
email: jan@kursator.de
|
197
197
|
executables: []
|
@@ -201,6 +201,7 @@ files:
|
|
201
201
|
- LICENSE
|
202
202
|
- README.md
|
203
203
|
- lib/isomorfeus-mailer.rb
|
204
|
+
- lib/isomorfeus/html2text.rb
|
204
205
|
- lib/isomorfeus/mailer/config.rb
|
205
206
|
- lib/isomorfeus/mailer/imports.rb
|
206
207
|
- lib/isomorfeus/mailer/version.rb
|