premailer 1.26.0 → 1.28.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.
@@ -21,19 +21,19 @@ class Premailer
21
21
  # Iterate through the rules and merge them into the HTML
22
22
  @css_parser.each_selector(:all) do |selector, declaration, specificity, media_types|
23
23
  # Save un-mergable rules separately
24
- selector.gsub!(/:link([\s]*)+/i) { |m| $1 }
24
+ selector.gsub!(/:link([\s]*)+/i) { |_m| $1 }
25
25
 
26
26
  # Convert element names to lower case
27
- selector.gsub!(/([\s]|^)([\w]+)/) { |m| $1.to_s + $2.to_s.downcase }
27
+ selector.gsub!(/([\s]|^)([\w]+)/) { |_m| $1.to_s + $2.to_s.downcase }
28
28
 
29
- if Premailer.is_media_query?(media_types) || selector =~ Premailer::RE_UNMERGABLE_SELECTORS
29
+ if Premailer.media_query?(media_types) || selector =~ Premailer::RE_UNMERGABLE_SELECTORS
30
30
  @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selectors: selector, block: declaration), media_types) unless @options[:preserve_styles]
31
31
  else
32
32
  begin
33
- if Premailer::RE_RESET_SELECTORS.match?(selector)
33
+ if Premailer::RE_RESET_SELECTORS.match?(selector) && !!@options[:preserve_reset]
34
34
  # this is in place to preserve the MailChimp CSS reset: http://github.com/mailchimp/Email-Blueprints/
35
35
  # however, this doesn't mean for testing pur
36
- @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selectors: selector, block: declaration)) unless !@options[:preserve_reset]
36
+ @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selectors: selector, block: declaration))
37
37
  end
38
38
 
39
39
  # Change single ID CSS selectors into xpath so that we can match more
@@ -41,14 +41,14 @@ class Premailer
41
41
  selector.gsub!(/\A\#([\w_\-]+)\Z/, '*[@id=\1]')
42
42
 
43
43
  doc.search(selector).each do |el|
44
- if el.elem? and (el.name != 'head' and el.parent.name != 'head')
44
+ if el.elem? && ((el.name != 'head') && (el.parent.name != 'head'))
45
45
  # Add a style attribute or append to the existing one
46
46
  block = "[SPEC=#{specificity}[#{declaration}]]"
47
47
  el['style'] = (el.attributes['style'].to_s ||= '') + ' ' + block
48
48
  end
49
49
  end
50
50
  rescue ::Nokogiri::SyntaxError, RuntimeError, ArgumentError
51
- $stderr.puts "CSS syntax error with selector: #{selector}" if @options[:verbose]
51
+ warn "CSS syntax error with selector: #{selector}" if @options[:verbose]
52
52
  next
53
53
  end
54
54
  end
@@ -62,13 +62,11 @@ class Premailer
62
62
  style = el.attributes['style'].to_s
63
63
 
64
64
  declarations = []
65
- style.scan(/\[SPEC\=([\d]+)\[(.[^\]\]]*)\]\]/).each do |declaration|
66
- begin
67
- rs = CssParser::RuleSet.new(block: declaration[1].to_s, specificity: declaration[0].to_i)
68
- declarations << rs
69
- rescue ArgumentError => e
70
- raise e if @options[:rule_set_exceptions]
71
- end
65
+ style.scan(/\[SPEC=([\d]+)\[(.[^\]]*)\]\]/m).each do |declaration|
66
+ rs = CssParser::RuleSet.new(block: declaration[1].to_s, specificity: declaration[0].to_i)
67
+ declarations << rs
68
+ rescue ArgumentError => e
69
+ raise e if @options[:rule_set_exceptions]
72
70
  end
73
71
 
74
72
  # Perform style folding
@@ -80,9 +78,9 @@ class Premailer
80
78
  end
81
79
 
82
80
  # Duplicate CSS attributes as HTML attributes
83
- if Premailer::RELATED_ATTRIBUTES.has_key?(el.name) && @options[:css_to_attributes]
81
+ if Premailer::RELATED_ATTRIBUTES.key?(el.name) && @options[:css_to_attributes]
84
82
  Premailer::RELATED_ATTRIBUTES[el.name].each do |css_attr, html_attr|
85
- if el[html_attr].nil? and not merged[css_attr].empty?
83
+ if el[html_attr].nil? && !merged[css_attr].empty?
86
84
  new_val = merged[css_attr].dup
87
85
 
88
86
  # Remove url() function wrapper
@@ -117,9 +115,9 @@ class Premailer
117
115
 
118
116
  doc = write_unmergable_css_rules(doc, @unmergable_rules) unless @options[:drop_unmergeable_css_rules]
119
117
 
120
- if @options[:remove_classes] or @options[:remove_comments]
118
+ if @options[:remove_classes] || @options[:remove_comments]
121
119
  doc.traverse do |el|
122
- if el.comment? and @options[:remove_comments]
120
+ if el.comment? && @options[:remove_comments]
123
121
  el.remove
124
122
  elsif el.element?
125
123
  el.remove_attribute('class') if @options[:remove_classes]
@@ -131,7 +129,7 @@ class Premailer
131
129
  # find all anchor's targets and hash them
132
130
  targets = []
133
131
  doc.search("a[@href^='#']").each do |el|
134
- target = el.get_attribute('href')[1..-1]
132
+ target = el.get_attribute('href')[1..]
135
133
  targets << target
136
134
  el.set_attribute('href', "#" + Digest::SHA256.hexdigest(target))
137
135
  end
@@ -153,7 +151,7 @@ class Premailer
153
151
  end
154
152
 
155
153
  @processed_doc = doc
156
- if is_xhtml?
154
+ if xhtml?
157
155
  # we don't want to encode carriage returns
158
156
  @processed_doc.to_xhtml(:encoding => @options[:output_encoding]).gsub(/&\#(xD|13);/i, "\r")
159
157
  else
@@ -177,15 +175,14 @@ class Premailer
177
175
  else
178
176
  style_tag = doc.create_element "style", styles
179
177
  head = doc.at_css('head')
180
- head ||= doc.root.first_element_child.add_previous_sibling(doc.create_element "head") if doc.root && doc.root.first_element_child
181
- head ||= doc.add_child(doc.create_element "head")
178
+ head ||= doc.root.first_element_child.add_previous_sibling(doc.create_element("head")) if doc.root&.first_element_child
179
+ head ||= doc.add_child(doc.create_element("head"))
182
180
  head << style_tag
183
181
  end
184
182
  end
185
183
  doc
186
184
  end
187
185
 
188
-
189
186
  # Converts the HTML document to a format suitable for plain-text e-mail.
190
187
  #
191
188
  # If present, uses the <body> element as its base; otherwise uses the whole document.
@@ -195,17 +192,17 @@ class Premailer
195
192
  html_src = ''
196
193
  begin
197
194
  html_src = @doc.at("body").inner_html
198
- rescue;
195
+ rescue StandardError
199
196
  end
200
197
 
201
- html_src = @doc.to_html unless html_src and not html_src.empty?
198
+ html_src = @doc.to_html unless html_src && !html_src.empty?
202
199
  convert_to_text(html_src, @options[:line_length], @html_encoding)
203
200
  end
204
201
 
205
202
  # Gets the original HTML as a string.
206
203
  # @return [String] HTML.
207
204
  def to_s
208
- if is_xhtml?
205
+ if xhtml?
209
206
  @doc.to_xhtml(:encoding => nil)
210
207
  else
211
208
  @doc.to_html(:encoding => nil)
@@ -219,13 +216,13 @@ class Premailer
219
216
  thing = nil
220
217
 
221
218
  # TODO: duplicate options
222
- if @options[:with_html_string] or @options[:inline] or input.respond_to?(:read)
219
+ if @options[:with_html_string] || @options[:inline] || input.respond_to?(:read)
223
220
  thing = input
224
221
  elsif @is_local_file
225
222
  @base_dir = File.dirname(input)
226
223
  thing = File.open(input, 'r')
227
224
  else
228
- thing = URI.open(input)
225
+ thing = URI.parse(input).open
229
226
  end
230
227
 
231
228
  if thing.respond_to?(:read)
@@ -236,7 +233,7 @@ class Premailer
236
233
  doc = nil
237
234
 
238
235
  # Handle HTML entities
239
- if @options[:replace_html_entities] == true and thing.is_a?(String)
236
+ if (@options[:replace_html_entities] == true) && thing.is_a?(String)
240
237
  HTML_ENTITIES.map do |entity, replacement|
241
238
  thing.gsub! entity, replacement
242
239
  end
@@ -252,13 +249,12 @@ class Premailer
252
249
  # https://github.com/premailer/premailer/issues/199
253
250
  ['style', 'script'].each do |tag|
254
251
  doc.search(tag).children.each do |child|
255
- child.swap(child.text()) if child.cdata?
252
+ child.swap(child.text) if child.cdata?
256
253
  end
257
254
  end
258
255
 
259
256
  doc
260
257
  end
261
-
262
258
  end
263
259
  end
264
260
  end
@@ -7,7 +7,7 @@ module AdapterHelper
7
7
  str.to_i.to_s(16).rjust(2, '0').upcase
8
8
  end
9
9
 
10
- def is_rgb?(color)
10
+ def rgb?(color)
11
11
  pattern = %r{
12
12
  rgb
13
13
  \(\s* # literal open, with optional whitespace
@@ -16,7 +16,7 @@ module AdapterHelper
16
16
  (\d{1,3}) # capture 1-3 digits
17
17
  (?:\s*,\s*|\s+) # comma or whitespacee
18
18
  (\d{1,3}) # capture 1-3 digits
19
- \s*(?:\/\s*\d*\.?\d*%?)? # optional alpha modifier
19
+ \s*(?:/\s*\d*\.?\d*%?)? # optional alpha modifier
20
20
  \s*\) # literal close, with optional whitespace
21
21
  }x
22
22
 
@@ -24,7 +24,7 @@ module AdapterHelper
24
24
  end
25
25
 
26
26
  def ensure_hex(color)
27
- match_data = is_rgb?(color)
27
+ match_data = rgb?(color)
28
28
  if match_data
29
29
  "#{to_hex(match_data[1])}#{to_hex(match_data[2])}#{to_hex(match_data[3])}"
30
30
  else
@@ -6,7 +6,6 @@ class Premailer
6
6
  # * nokogiri_fast
7
7
  # * nokogumbo
8
8
  module Adapter
9
-
10
9
  autoload :Nokogiri, 'premailer/adapter/nokogiri'
11
10
  autoload :NokogiriFast, 'premailer/adapter/nokogiri_fast'
12
11
  autoload :Nokogumbo, 'premailer/adapter/nokogumbo'
@@ -16,12 +15,12 @@ class Premailer
16
15
  ["nokogiri", :nokogiri],
17
16
  ["nokogiri", :nokogiri_fast],
18
17
  ["nokogumbo", :nokogumbo]
19
- ]
18
+ ].freeze
20
19
 
21
20
  # Returns the adapter to use.
22
21
  def self.use
23
22
  return @use if @use
24
- self.use = self.default
23
+ self.use = default
25
24
  @use
26
25
  end
27
26
 
@@ -35,12 +34,10 @@ class Premailer
35
34
  return :nokogumbo if defined?(::Nokogumbo)
36
35
 
37
36
  REQUIREMENT_MAP.each do |(library, adapter)|
38
- begin
39
- require library
40
- return adapter
41
- rescue LoadError
42
- next
43
- end
37
+ require library
38
+ return adapter
39
+ rescue LoadError
40
+ next
44
41
  end
45
42
 
46
43
  raise "No suitable adapter for Premailer was found, please install nokogiri or nokogumbo"
@@ -57,10 +54,9 @@ class Premailer
57
54
  def self.find(adapter)
58
55
  return adapter if adapter.is_a?(Module)
59
56
 
60
- Premailer::Adapter.const_get("#{adapter.to_s.split('_').map{|s| s.capitalize}.join}")
57
+ Premailer::Adapter.const_get(adapter.to_s.split('_').map(&:capitalize).join.to_s)
61
58
  rescue NameError
62
59
  raise ArgumentError, "Invalid adapter: #{adapter}"
63
60
  end
64
-
65
61
  end
66
62
  end
@@ -4,12 +4,12 @@ require 'premailer'
4
4
 
5
5
  # defaults
6
6
  options = {
7
- :base_url => nil,
7
+ :base_url => nil,
8
8
  :link_query_string => nil,
9
- :remove_classes => false,
10
- :verbose => false,
11
- :line_length => 65,
12
- :adapter => :nokogiri
9
+ :remove_classes => false,
10
+ :verbose => false,
11
+ :line_length => 65,
12
+ :adapter => :nokogiri
13
13
  }
14
14
 
15
15
  mode = :html
@@ -54,11 +54,11 @@ parser = OptionParser.new do |opts|
54
54
  options[:remove_scripts] = true
55
55
  end
56
56
 
57
- opts.on("-l", "--line-length N", Integer, "Line length for plaintext (default: #{options[:line_length].to_s})") do |v|
57
+ opts.on("-l", "--line-length N", Integer, "Line length for plaintext (default: #{options[:line_length]})") do |v|
58
58
  options[:line_length] = v
59
59
  end
60
60
 
61
- opts.on("-e", "--entities", "Output HTML entities instead of UTF-8 when using Nokogiri") do |v|
61
+ opts.on("-e", "--entities", "Output HTML entities instead of UTF-8 when using Nokogiri") do |_v|
62
62
  options[:output_encoding] = "US-ASCII"
63
63
  end
64
64
 
@@ -82,7 +82,7 @@ parser = OptionParser.new do |opts|
82
82
  end
83
83
  parser.parse!
84
84
 
85
- $stderr.puts "Processing in #{mode} mode with options #{options.inspect}" if options[:verbose]
85
+ warn "Processing in #{mode} mode with options #{options.inspect}" if options[:verbose]
86
86
 
87
87
  premailer = nil
88
88
  input = nil
@@ -1,10 +1,8 @@
1
- # coding: utf-8
2
1
  # frozen_string_literal: true
3
2
  require 'htmlentities'
4
3
 
5
4
  # Support functions for Premailer
6
5
  module HtmlToPlainText
7
-
8
6
  # Returns the text in UTF-8 format with all HTML tags removed
9
7
  #
10
8
  # HTML content can be omitted from the output by surrounding it in the following comments:
@@ -60,7 +58,7 @@ module HtmlToPlainText
60
58
 
61
59
  # handle headings (H1-H6)
62
60
  txt.gsub!(/(<\/h[1-6]>)/i, "\n\\1") # move closing tags to new lines
63
- txt.gsub!(/[\s]*<h([1-6]+)[^>]*>[\s]*(.*)[\s]*<\/h[1-6]+>/i) do |s|
61
+ txt.gsub!(/[\s]*<h([1-6]+)[^>]*>[\s]*(.*)[\s]*<\/h[1-6]+>/i) do |_s|
64
62
  hlevel = $1.to_i
65
63
 
66
64
  htext = $2
@@ -69,17 +67,21 @@ module HtmlToPlainText
69
67
 
70
68
  # determine maximum line length
71
69
  hlength = 0
72
- htext.each_line { |l| llength = l.strip.length; hlength = llength if llength > hlength }
70
+ htext.each_line do |l|
71
+ llength = l.strip.length
72
+ hlength = llength if llength > hlength
73
+ end
73
74
  hlength = line_length if hlength > line_length
74
75
 
75
- case hlevel
76
- when 1 # H1, asterisks above and below
77
- htext = ('*' * hlength) + "\n" + htext + "\n" + ('*' * hlength)
78
- when 2 # H1, dashes above and below
79
- htext = ('-' * hlength) + "\n" + htext + "\n" + ('-' * hlength)
80
- else # H3-H6, dashes below
81
- htext = htext + "\n" + ('-' * hlength)
82
- end
76
+ htext =
77
+ case hlevel
78
+ when 1 # H1, asterisks above and below
79
+ ('*' * hlength) + "\n" + htext + "\n" + ('*' * hlength)
80
+ when 2 # H1, dashes above and below
81
+ ('-' * hlength) + "\n" + htext + "\n" + ('-' * hlength)
82
+ else # H3-H6, dashes below
83
+ htext + "\n" + ('-' * hlength)
84
+ end
83
85
 
84
86
  "\n\n" + htext + "\n\n"
85
87
  end
@@ -118,8 +120,8 @@ module HtmlToPlainText
118
120
  txt.gsub!(/[\n]{3,}/, "\n\n")
119
121
 
120
122
  # the word messes up the parens
121
- txt.gsub!(/\(([ \n])(http[^)]+)([\n ])\)/) do |s|
122
- ($1 == "\n" ? $1 : '' ) + '( ' + $2 + ' )' + ($3 == "\n" ? $1 : '' )
123
+ txt.gsub!(/\(([ \n])(http[^)]+)([\n ])\)/) do |_s|
124
+ ($1 == "\n" ? $1 : '') + '( ' + $2 + ' )' + ($3 == "\n" ? $1 : '')
123
125
  end
124
126
 
125
127
  txt.strip