premailer 1.23.0 → 1.29.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.
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
1
2
  require 'nokogiri'
2
3
 
3
4
  class Premailer
4
5
  module Adapter
5
6
  # NokogiriFast adapter
6
7
  module NokogiriFast
8
+ WIDTH_AND_HEIGHT = ['width', 'height'].freeze
7
9
 
8
10
  include AdapterHelper::RgbToHex
9
11
  # Merge CSS into the HTML document.
@@ -25,34 +27,33 @@ class Premailer
25
27
 
26
28
  # Iterate through the rules and merge them into the HTML
27
29
  @css_parser.each_selector(:all) do |selector, declaration, specificity, media_types|
28
-
29
30
  # Save un-mergable rules separately
30
- selector.gsub!(/:link([\s]*)+/i) { |m| $1 }
31
+ selector.gsub!(/:link([\s]*)+/i) { |_m| $1 }
31
32
 
32
33
  # Convert element names to lower case
33
- selector.gsub!(/([\s]|^)([\w]+)/) { |m| $1.to_s + $2.to_s.downcase }
34
+ selector.gsub!(/([\s]|^)([\w]+)/) { |_m| $1.to_s + $2.to_s.downcase }
34
35
 
35
- if Premailer.is_media_query?(media_types) || selector =~ Premailer::RE_UNMERGABLE_SELECTORS
36
- @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration), media_types) unless @options[:preserve_styles]
36
+ if Premailer.media_query?(media_types) || selector =~ Premailer::RE_UNMERGABLE_SELECTORS
37
+ @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selectors: selector, block: declaration), media_types) unless @options[:preserve_styles]
37
38
  else
38
39
  begin
39
- if selector =~ Premailer::RE_RESET_SELECTORS
40
+ if Premailer::RE_RESET_SELECTORS.match?(selector) && !!@options[:preserve_reset]
40
41
  # this is in place to preserve the MailChimp CSS reset: http://github.com/mailchimp/Email-Blueprints/
41
42
  # however, this doesn't mean for testing pur
42
- @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless !@options[:preserve_reset]
43
+ @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selectors: selector, block: declaration))
43
44
  end
44
45
 
45
46
  # Try the new index based technique. If not supported, fall back to the old brute force one.
46
47
  nodes = match_selector(index, all_nodes, descendants, selector) || doc.search(selector)
47
48
  nodes.each do |el|
48
- if el.elem? and (el.name != 'head' and el.parent.name != 'head')
49
+ if el.elem? && ((el.name != 'head') && (el.parent.name != 'head'))
49
50
  # Add a style attribute or append to the existing one
50
51
  block = "[SPEC=#{specificity}[#{declaration}]]"
51
52
  el['style'] = (el.attributes['style'].to_s ||= '') + ' ' + block
52
53
  end
53
54
  end
54
55
  rescue ::Nokogiri::SyntaxError, RuntimeError, ArgumentError
55
- $stderr.puts "CSS syntax error with selector: #{selector}" if @options[:verbose]
56
+ warn "CSS syntax error with selector: #{selector}" if @options[:verbose]
56
57
  next
57
58
  end
58
59
  end
@@ -66,13 +67,11 @@ class Premailer
66
67
  style = el.attributes['style'].to_s
67
68
 
68
69
  declarations = []
69
- style.scan(/\[SPEC\=([\d]+)\[(.[^\]\]]*)\]\]/).each do |declaration|
70
- begin
71
- rs = CssParser::RuleSet.new(nil, declaration[1].to_s, declaration[0].to_i)
72
- declarations << rs
73
- rescue ArgumentError => e
74
- raise e if @options[:rule_set_exceptions]
75
- end
70
+ style.scan(/\[SPEC=([\d]+)\[(.[^\]]*)\]\]/m).each do |declaration|
71
+ rs = CssParser::RuleSet.new(block: declaration[1].to_s, specificity: declaration[0].to_i)
72
+ declarations << rs
73
+ rescue ArgumentError => e
74
+ raise e if @options[:rule_set_exceptions]
76
75
  end
77
76
 
78
77
  # Perform style folding
@@ -84,9 +83,9 @@ class Premailer
84
83
  end
85
84
 
86
85
  # Duplicate CSS attributes as HTML attributes
87
- if Premailer::RELATED_ATTRIBUTES.has_key?(el.name) && @options[:css_to_attributes]
86
+ if Premailer::RELATED_ATTRIBUTES.key?(el.name) && @options[:css_to_attributes]
88
87
  Premailer::RELATED_ATTRIBUTES[el.name].each do |css_attr, html_attr|
89
- if el[html_attr].nil? and not merged[css_attr].empty?
88
+ if el[html_attr].nil? && !merged[css_attr].empty?
90
89
  new_val = merged[css_attr].dup
91
90
 
92
91
  # Remove url() function wrapper
@@ -96,7 +95,7 @@ class Premailer
96
95
  new_val.gsub!(/;$|\s*!important/, '').strip!
97
96
 
98
97
  # For width and height tags, remove px units
99
- new_val.gsub!(/(\d+)px/, '\1') if %w[width height].include?(html_attr)
98
+ new_val.gsub!(/(\d+)px/, '\1') if WIDTH_AND_HEIGHT.include?(html_attr)
100
99
 
101
100
  # For color-related tags, convert RGB to hex if specified by options
102
101
  new_val = ensure_hex(new_val) if css_attr.end_with?('color') && @options[:rgb_to_hex_attributes]
@@ -105,7 +104,7 @@ class Premailer
105
104
  end
106
105
 
107
106
  unless @options[:preserve_style_attribute]
108
- merged.instance_variable_get("@declarations").tap do |declarations|
107
+ merged.instance_variable_get(:@declarations).tap do |declarations|
109
108
  declarations.delete(css_attr)
110
109
  end
111
110
  end
@@ -121,9 +120,9 @@ class Premailer
121
120
 
122
121
  doc = write_unmergable_css_rules(doc, @unmergable_rules) unless @options[:drop_unmergeable_css_rules]
123
122
 
124
- if @options[:remove_classes] or @options[:remove_comments]
123
+ if @options[:remove_classes] || @options[:remove_comments]
125
124
  doc.traverse do |el|
126
- if el.comment? and @options[:remove_comments]
125
+ if el.comment? && @options[:remove_comments]
127
126
  el.remove
128
127
  elsif el.element?
129
128
  el.remove_attribute('class') if @options[:remove_classes]
@@ -135,7 +134,7 @@ class Premailer
135
134
  # find all anchor's targets and hash them
136
135
  targets = []
137
136
  doc.search("a[@href^='#']").each do |el|
138
- target = el.get_attribute('href')[1..-1]
137
+ target = el.get_attribute('href')[1..]
139
138
  targets << target
140
139
  el.set_attribute('href', "#" + Digest::SHA256.hexdigest(target))
141
140
  end
@@ -157,7 +156,7 @@ class Premailer
157
156
  end
158
157
 
159
158
  @processed_doc = doc
160
- if is_xhtml?
159
+ if xhtml?
161
160
  # we don't want to encode carriage returns
162
161
  @processed_doc.to_xhtml(:encoding => @options[:output_encoding]).gsub(/&\#(xD|13);/i, "\r")
163
162
  else
@@ -181,15 +180,14 @@ class Premailer
181
180
  else
182
181
  style_tag = doc.create_element "style", styles
183
182
  head = doc.at_css('head')
184
- head ||= doc.root.first_element_child.add_previous_sibling(doc.create_element "head") if doc.root && doc.root.first_element_child
185
- head ||= doc.add_child(doc.create_element "head")
183
+ head ||= doc.root.first_element_child.add_previous_sibling(doc.create_element("head")) if doc.root&.first_element_child
184
+ head ||= doc.add_child(doc.create_element("head"))
186
185
  head << style_tag
187
186
  end
188
187
  end
189
188
  doc
190
189
  end
191
190
 
192
-
193
191
  # Converts the HTML document to a format suitable for plain-text e-mail.
194
192
  #
195
193
  # If present, uses the <body> element as its base; otherwise uses the whole document.
@@ -199,17 +197,17 @@ class Premailer
199
197
  html_src = ''
200
198
  begin
201
199
  html_src = @doc.at("body").inner_html
202
- rescue;
200
+ rescue StandardError
203
201
  end
204
202
 
205
- html_src = @doc.to_html unless html_src and not html_src.empty?
203
+ html_src = @doc.to_html unless html_src && !html_src.empty?
206
204
  convert_to_text(html_src, @options[:line_length], @html_encoding)
207
205
  end
208
206
 
209
207
  # Gets the original HTML as a string.
210
208
  # @return [String] HTML.
211
209
  def to_s
212
- if is_xhtml?
210
+ if xhtml?
213
211
  @doc.to_xhtml(:encoding => nil)
214
212
  else
215
213
  @doc.to_html(:encoding => nil)
@@ -223,13 +221,13 @@ class Premailer
223
221
  thing = nil
224
222
 
225
223
  # TODO: duplicate options
226
- if @options[:with_html_string] or @options[:inline] or input.respond_to?(:read)
224
+ if @options[:with_html_string] || @options[:inline] || input.respond_to?(:read)
227
225
  thing = input
228
226
  elsif @is_local_file
229
227
  @base_dir = File.dirname(input)
230
228
  thing = File.open(input, 'r')
231
229
  else
232
- thing = URI.open(input)
230
+ thing = URI.parse(input).open
233
231
  end
234
232
 
235
233
  if thing.respond_to?(:read)
@@ -240,7 +238,7 @@ class Premailer
240
238
  doc = nil
241
239
 
242
240
  # Handle HTML entities
243
- if @options[:replace_html_entities] == true and thing.is_a?(String)
241
+ if (@options[:replace_html_entities] == true) && thing.is_a?(String)
244
242
  HTML_ENTITIES.map do |entity, replacement|
245
243
  thing.gsub! entity, replacement
246
244
  end
@@ -249,15 +247,15 @@ class Premailer
249
247
  doc = if @options[:html_fragment]
250
248
  ::Nokogiri::HTML.fragment(thing, encoding)
251
249
  else
252
- ::Nokogiri::HTML(thing, nil, encoding) { |c| c.recover }
250
+ ::Nokogiri::HTML(thing, nil, encoding, &:recover)
253
251
  end
254
252
 
255
253
  # Fix for removing any CDATA tags from both style and script tags inserted per
256
254
  # https://github.com/sparklemotion/nokogiri/issues/311 and
257
255
  # https://github.com/premailer/premailer/issues/199
258
- %w(style script).each do |tag|
256
+ ['style', 'script'].each do |tag|
259
257
  doc.search(tag).children.each do |child|
260
- child.swap(child.text()) if child.cdata?
258
+ child.swap(child.text) if child.cdata?
261
259
  end
262
260
  end
263
261
 
@@ -281,7 +279,7 @@ class Premailer
281
279
  page.traverse do |node|
282
280
  all_nodes.push(node)
283
281
 
284
- if node != page then
282
+ if node != page
285
283
  index_ancestry(page, node, node.parent, descendants)
286
284
  end
287
285
 
@@ -292,7 +290,7 @@ class Premailer
292
290
  # Index the node by all class attributes it possesses.
293
291
  # Classes are modestly selective. Usually more than tag names
294
292
  # but less selective than ids.
295
- if node.has_attribute?("class") then
293
+ if node.has_attribute?("class")
296
294
  node.get_attribute("class").split(/\s+/).each do |c|
297
295
  c = '.' + c
298
296
  index[c] = (index[c] || Set.new).add(node)
@@ -301,7 +299,7 @@ class Premailer
301
299
 
302
300
  # Index the node by its "id" attribute if it has one.
303
301
  # This is usually the most selective of the three.
304
- if node.has_attribute?("id") then
302
+ if node.has_attribute?("id")
305
303
  id = '#' + node.get_attribute("id")
306
304
  index[id] = (index[id] || Set.new).add(node)
307
305
  end
@@ -314,7 +312,7 @@ class Premailer
314
312
  index.default = Set.new
315
313
  descendants.default = Set.new
316
314
 
317
- return index, Set.new(all_nodes), descendants
315
+ [index, Set.new(all_nodes), descendants]
318
316
  end
319
317
 
320
318
  # @param doc The top level document
@@ -323,9 +321,9 @@ class Premailer
323
321
  # @param descendants The running hash map of node -> set of nodes that maps descendants of a node.
324
322
  # @return The descendants argument after updating it.
325
323
  def index_ancestry(doc, elem, parent, descendants)
326
- if parent then
324
+ if parent
327
325
  descendants[parent] = (descendants[parent] || Set.new).add(elem)
328
- if doc != parent then
326
+ if doc != parent
329
327
  index_ancestry(doc, elem, parent.parent, descendants)
330
328
  end
331
329
  end
@@ -354,14 +352,14 @@ class Premailer
354
352
  # It will return nil when such a selector is passed, so you can take
355
353
  # action on the falsity of the return value.
356
354
  def match_selector(index, all_nodes, descendants, selector)
357
- if /[^-a-zA-Z0-9_\s.#]/.match(selector) then
355
+ if /[^-a-zA-Z0-9_\s.#]/.match?(selector)
358
356
  return nil
359
357
  end
360
358
 
361
359
  take_children = false
362
360
  selector.split(/\s+/).reduce(all_nodes) do |base, spec|
363
361
  desc = base
364
- if take_children then
362
+ if take_children
365
363
  desc = Set.new
366
364
  base.each do |n|
367
365
  desc.merge(descendants[n])
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
1
2
  class Premailer
2
3
  module Adapter
3
4
  # Nokogiri adapter
4
5
  module Nokogumbo
6
+ WIDTH_AND_HEIGHT = ['width', 'height'].freeze
5
7
 
6
8
  include AdapterHelper::RgbToHex
7
9
  # Merge CSS into the HTML document.
@@ -19,19 +21,19 @@ class Premailer
19
21
  # Iterate through the rules and merge them into the HTML
20
22
  @css_parser.each_selector(:all) do |selector, declaration, specificity, media_types|
21
23
  # Save un-mergable rules separately
22
- selector.gsub!(/:link([\s]*)+/i) { |m| $1 }
24
+ selector.gsub!(/:link([\s]*)+/i) { |_m| $1 }
23
25
 
24
26
  # Convert element names to lower case
25
- 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 }
26
28
 
27
- if Premailer.is_media_query?(media_types) || selector =~ Premailer::RE_UNMERGABLE_SELECTORS
28
- @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration), media_types) unless @options[:preserve_styles]
29
+ if Premailer.media_query?(media_types) || selector =~ Premailer::RE_UNMERGABLE_SELECTORS
30
+ @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selectors: selector, block: declaration), media_types) unless @options[:preserve_styles]
29
31
  else
30
32
  begin
31
- if selector =~ Premailer::RE_RESET_SELECTORS
33
+ if Premailer::RE_RESET_SELECTORS.match?(selector) && !!@options[:preserve_reset]
32
34
  # this is in place to preserve the MailChimp CSS reset: http://github.com/mailchimp/Email-Blueprints/
33
35
  # however, this doesn't mean for testing pur
34
- @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless !@options[:preserve_reset]
36
+ @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selectors: selector, block: declaration))
35
37
  end
36
38
 
37
39
  # Change single ID CSS selectors into xpath so that we can match more
@@ -39,14 +41,14 @@ class Premailer
39
41
  selector.gsub!(/\A\#([\w_\-]+)\Z/, '*[@id=\1]')
40
42
 
41
43
  doc.search(selector).each do |el|
42
- if el.elem? and (el.name != 'head' and el.parent.name != 'head')
44
+ if el.elem? && ((el.name != 'head') && (el.parent.name != 'head'))
43
45
  # Add a style attribute or append to the existing one
44
46
  block = "[SPEC=#{specificity}[#{declaration}]]"
45
47
  el['style'] = (el.attributes['style'].to_s ||= '') + ' ' + block
46
48
  end
47
49
  end
48
50
  rescue ::Nokogiri::SyntaxError, RuntimeError, ArgumentError
49
- $stderr.puts "CSS syntax error with selector: #{selector}" if @options[:verbose]
51
+ warn "CSS syntax error with selector: #{selector}" if @options[:verbose]
50
52
  next
51
53
  end
52
54
  end
@@ -60,13 +62,11 @@ class Premailer
60
62
  style = el.attributes['style'].to_s
61
63
 
62
64
  declarations = []
63
- style.scan(/\[SPEC\=([\d]+)\[(.[^\]\]]*)\]\]/).each do |declaration|
64
- begin
65
- rs = CssParser::RuleSet.new(nil, declaration[1].to_s, declaration[0].to_i)
66
- declarations << rs
67
- rescue ArgumentError => e
68
- raise e if @options[:rule_set_exceptions]
69
- 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]
70
70
  end
71
71
 
72
72
  # Perform style folding
@@ -78,9 +78,9 @@ class Premailer
78
78
  end
79
79
 
80
80
  # Duplicate CSS attributes as HTML attributes
81
- if Premailer::RELATED_ATTRIBUTES.has_key?(el.name) && @options[:css_to_attributes]
81
+ if Premailer::RELATED_ATTRIBUTES.key?(el.name) && @options[:css_to_attributes]
82
82
  Premailer::RELATED_ATTRIBUTES[el.name].each do |css_attr, html_attr|
83
- if el[html_attr].nil? and not merged[css_attr].empty?
83
+ if el[html_attr].nil? && !merged[css_attr].empty?
84
84
  new_val = merged[css_attr].dup
85
85
 
86
86
  # Remove url() function wrapper
@@ -90,7 +90,7 @@ class Premailer
90
90
  new_val.gsub!(/;$|\s*!important/, '').strip!
91
91
 
92
92
  # For width and height tags, remove px units
93
- new_val.gsub!(/(\d+)px/, '\1') if %w[width height].include?(html_attr)
93
+ new_val.gsub!(/(\d+)px/, '\1') if WIDTH_AND_HEIGHT.include?(html_attr)
94
94
 
95
95
  # For color-related tags, convert RGB to hex if specified by options
96
96
  new_val = ensure_hex(new_val) if css_attr.end_with?('color') && @options[:rgb_to_hex_attributes]
@@ -99,7 +99,7 @@ class Premailer
99
99
  end
100
100
 
101
101
  unless @options[:preserve_style_attribute]
102
- merged.instance_variable_get("@declarations").tap do |declarations|
102
+ merged.instance_variable_get(:@declarations).tap do |declarations|
103
103
  declarations.delete(css_attr)
104
104
  end
105
105
  end
@@ -115,9 +115,9 @@ class Premailer
115
115
 
116
116
  doc = write_unmergable_css_rules(doc, @unmergable_rules) unless @options[:drop_unmergeable_css_rules]
117
117
 
118
- if @options[:remove_classes] or @options[:remove_comments]
118
+ if @options[:remove_classes] || @options[:remove_comments]
119
119
  doc.traverse do |el|
120
- if el.comment? and @options[:remove_comments]
120
+ if el.comment? && @options[:remove_comments]
121
121
  el.remove
122
122
  elsif el.element?
123
123
  el.remove_attribute('class') if @options[:remove_classes]
@@ -129,7 +129,7 @@ class Premailer
129
129
  # find all anchor's targets and hash them
130
130
  targets = []
131
131
  doc.search("a[@href^='#']").each do |el|
132
- target = el.get_attribute('href')[1..-1]
132
+ target = el.get_attribute('href')[1..]
133
133
  targets << target
134
134
  el.set_attribute('href', "#" + Digest::SHA256.hexdigest(target))
135
135
  end
@@ -151,7 +151,7 @@ class Premailer
151
151
  end
152
152
 
153
153
  @processed_doc = doc
154
- if is_xhtml?
154
+ if xhtml?
155
155
  # we don't want to encode carriage returns
156
156
  @processed_doc.to_xhtml(:encoding => @options[:output_encoding]).gsub(/&\#(xD|13);/i, "\r")
157
157
  else
@@ -175,15 +175,14 @@ class Premailer
175
175
  else
176
176
  style_tag = doc.create_element "style", styles
177
177
  head = doc.at_css('head')
178
- head ||= doc.root.first_element_child.add_previous_sibling(doc.create_element "head") if doc.root && doc.root.first_element_child
179
- 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"))
180
180
  head << style_tag
181
181
  end
182
182
  end
183
183
  doc
184
184
  end
185
185
 
186
-
187
186
  # Converts the HTML document to a format suitable for plain-text e-mail.
188
187
  #
189
188
  # If present, uses the <body> element as its base; otherwise uses the whole document.
@@ -193,17 +192,17 @@ class Premailer
193
192
  html_src = ''
194
193
  begin
195
194
  html_src = @doc.at("body").inner_html
196
- rescue;
195
+ rescue StandardError
197
196
  end
198
197
 
199
- 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?
200
199
  convert_to_text(html_src, @options[:line_length], @html_encoding)
201
200
  end
202
201
 
203
202
  # Gets the original HTML as a string.
204
203
  # @return [String] HTML.
205
204
  def to_s
206
- if is_xhtml?
205
+ if xhtml?
207
206
  @doc.to_xhtml(:encoding => nil)
208
207
  else
209
208
  @doc.to_html(:encoding => nil)
@@ -217,13 +216,13 @@ class Premailer
217
216
  thing = nil
218
217
 
219
218
  # TODO: duplicate options
220
- 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)
221
220
  thing = input
222
221
  elsif @is_local_file
223
222
  @base_dir = File.dirname(input)
224
223
  thing = File.open(input, 'r')
225
224
  else
226
- thing = URI.open(input)
225
+ thing = URI.parse(input).open
227
226
  end
228
227
 
229
228
  if thing.respond_to?(:read)
@@ -234,7 +233,7 @@ class Premailer
234
233
  doc = nil
235
234
 
236
235
  # Handle HTML entities
237
- if @options[:replace_html_entities] == true and thing.is_a?(String)
236
+ if (@options[:replace_html_entities] == true) && thing.is_a?(String)
238
237
  HTML_ENTITIES.map do |entity, replacement|
239
238
  thing.gsub! entity, replacement
240
239
  end
@@ -248,15 +247,14 @@ class Premailer
248
247
  # Fix for removing any CDATA tags from both style and script tags inserted per
249
248
  # https://github.com/sparklemotion/nokogiri/issues/311 and
250
249
  # https://github.com/premailer/premailer/issues/199
251
- %w(style script).each do |tag|
250
+ ['style', 'script'].each do |tag|
252
251
  doc.search(tag).children.each do |child|
253
- child.swap(child.text()) if child.cdata?
252
+ child.swap(child.text) if child.cdata?
254
253
  end
255
254
  end
256
255
 
257
256
  doc
258
257
  end
259
-
260
258
  end
261
259
  end
262
260
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # RGB helper for adapters, currently only nokogiri supported
2
3
 
3
4
  module AdapterHelper
@@ -6,7 +7,7 @@ module AdapterHelper
6
7
  str.to_i.to_s(16).rjust(2, '0').upcase
7
8
  end
8
9
 
9
- def is_rgb?(color)
10
+ def rgb?(color)
10
11
  pattern = %r{
11
12
  rgb
12
13
  \(\s* # literal open, with optional whitespace
@@ -15,7 +16,7 @@ module AdapterHelper
15
16
  (\d{1,3}) # capture 1-3 digits
16
17
  (?:\s*,\s*|\s+) # comma or whitespacee
17
18
  (\d{1,3}) # capture 1-3 digits
18
- \s*(?:\/\s*\d*\.?\d*%?)? # optional alpha modifier
19
+ \s*(?:/\s*\d*\.?\d*%?)? # optional alpha modifier
19
20
  \s*\) # literal close, with optional whitespace
20
21
  }x
21
22
 
@@ -23,7 +24,7 @@ module AdapterHelper
23
24
  end
24
25
 
25
26
  def ensure_hex(color)
26
- match_data = is_rgb?(color)
27
+ match_data = rgb?(color)
27
28
  if match_data
28
29
  "#{to_hex(match_data[1])}#{to_hex(match_data[2])}#{to_hex(match_data[3])}"
29
30
  else
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Premailer
2
3
  # Manages the adapter classes. Currently supports:
3
4
  #
@@ -5,7 +6,6 @@ class Premailer
5
6
  # * nokogiri_fast
6
7
  # * nokogumbo
7
8
  module Adapter
8
-
9
9
  autoload :Nokogiri, 'premailer/adapter/nokogiri'
10
10
  autoload :NokogiriFast, 'premailer/adapter/nokogiri_fast'
11
11
  autoload :Nokogumbo, 'premailer/adapter/nokogumbo'
@@ -14,13 +14,13 @@ class Premailer
14
14
  REQUIREMENT_MAP = [
15
15
  ["nokogiri", :nokogiri],
16
16
  ["nokogiri", :nokogiri_fast],
17
- ["nokogumbo", :nokogumbo],
18
- ]
17
+ ["nokogumbo", :nokogumbo]
18
+ ].freeze
19
19
 
20
20
  # Returns the adapter to use.
21
21
  def self.use
22
22
  return @use if @use
23
- self.use = self.default
23
+ self.use = default
24
24
  @use
25
25
  end
26
26
 
@@ -34,15 +34,13 @@ class Premailer
34
34
  return :nokogumbo if defined?(::Nokogumbo)
35
35
 
36
36
  REQUIREMENT_MAP.each do |(library, adapter)|
37
- begin
38
- require library
39
- return adapter
40
- rescue LoadError
41
- next
42
- end
37
+ require library
38
+ return adapter
39
+ rescue LoadError
40
+ next
43
41
  end
44
42
 
45
- raise RuntimeError.new("No suitable adapter for Premailer was found, please install nokogiri or nokogumbo")
43
+ raise "No suitable adapter for Premailer was found, please install nokogiri or nokogumbo"
46
44
  end
47
45
 
48
46
  # Sets the adapter to use.
@@ -56,10 +54,9 @@ class Premailer
56
54
  def self.find(adapter)
57
55
  return adapter if adapter.is_a?(Module)
58
56
 
59
- 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)
60
58
  rescue NameError
61
59
  raise ArgumentError, "Invalid adapter: #{adapter}"
62
60
  end
63
-
64
61
  end
65
62
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Premailer
2
3
  class CachedRuleSet < CssParser::RuleSet
3
4
  # we call this early to find errors but css-parser calls it in .merge again
@@ -1,19 +1,20 @@
1
+ # frozen_string_literal: true
1
2
  require 'optparse'
2
3
  require 'premailer'
3
4
 
4
5
  # defaults
5
6
  options = {
6
- :base_url => nil,
7
+ :base_url => nil,
7
8
  :link_query_string => nil,
8
- :remove_classes => false,
9
- :verbose => false,
10
- :line_length => 65,
11
- :adapter => :nokogiri,
9
+ :remove_classes => false,
10
+ :verbose => false,
11
+ :line_length => 65,
12
+ :adapter => :nokogiri
12
13
  }
13
14
 
14
15
  mode = :html
15
16
 
16
- opts = OptionParser.new do |opts|
17
+ parser = OptionParser.new do |opts|
17
18
  opts.banner = "Improve the rendering of HTML emails by making CSS inline among other things. Takes a path to a local file, a URL or a pipe as input.\n\n"
18
19
  opts.define_head "Usage: premailer <optional uri|optional path> [options]"
19
20
  opts.separator ""
@@ -53,11 +54,11 @@ opts = OptionParser.new do |opts|
53
54
  options[:remove_scripts] = true
54
55
  end
55
56
 
56
- 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|
57
58
  options[:line_length] = v
58
59
  end
59
60
 
60
- 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|
61
62
  options[:output_encoding] = "US-ASCII"
62
63
  end
63
64
 
@@ -79,9 +80,9 @@ opts = OptionParser.new do |opts|
79
80
  exit
80
81
  end
81
82
  end
82
- opts.parse!
83
+ parser.parse!
83
84
 
84
- $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]
85
86
 
86
87
  premailer = nil
87
88
  input = nil
@@ -98,7 +99,7 @@ end
98
99
  if input
99
100
  premailer = Premailer.new(input, options)
100
101
  else
101
- puts opts
102
+ puts parser
102
103
  exit 1
103
104
  end
104
105