premailer 1.8.4 → 1.8.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 83efaa991c6dd9a621f5ccb28f8eebca448b008e
4
- data.tar.gz: 8df7234ad7f2ca324168091ecdf67cfa880eda0d
3
+ metadata.gz: 7316d27a2fa70efed484e7c64733a351491f1cea
4
+ data.tar.gz: 6dd11b25df48ce0e73149ffdc25e6702de94ec21
5
5
  SHA512:
6
- metadata.gz: bedf9d58e364351088bf42da2e0b04f18392b9ea1960a07f1e4b6818a76a79058ce981671d41ac7ac2e92952017ca3cd203721a5ca61369a67307987ff9dfe9f
7
- data.tar.gz: 463e6b60e3ded167d9e1af0f9f5072933c151941f8e6ff8c0e2c932f4a56eebb306d50fcb4990888209de51718e84518c72c9bdc3fb04e29d8331afd3d8be2ae
6
+ metadata.gz: 9d5aed590607bd5cdbe7b629424c2b18832e5ee36c5688627216ea660c493edfb92a6f5d2f77e5d78b2b5cb502d2fb7f592adf3e0d624d58ced7b57ac7f6acdb
7
+ data.tar.gz: 107fb306346e6e35b146b7e327b0e2cc8cca1ded78f75687ed5281e090f08d50e7a9625335fbaffe066496e0c72f121b3389779751933900b7aec356d8b86791
@@ -6,10 +6,13 @@ rvm:
6
6
  - 1.9.3
7
7
  - 2.0.0
8
8
  - 2.1.0
9
+ - 2.2.0
9
10
  - ree
10
11
  gemfile:
11
12
  - Gemfile
12
13
  - gemfiles/.ruby187.gemfile
14
+ before_install:
15
+ - gem install bundler
13
16
  env:
14
17
  global:
15
18
  - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
@@ -23,5 +26,9 @@ matrix:
23
26
  gemfile: gemfiles/.ruby187.gemfile
24
27
  - rvm: 2.0.0
25
28
  gemfile: gemfiles/.ruby187.gemfile
29
+ - rvm: 2.1.0
30
+ gemfile: gemfiles/.ruby187.gemfile
31
+ - rvm: 2.2.0
32
+ gemfile: gemfiles/.ruby187.gemfile
26
33
  - rvm: ree
27
34
  gemfile: Gemfile
data/Gemfile CHANGED
@@ -12,3 +12,5 @@ gemspec
12
12
  gem "ripper", :group => :development, :platforms => :mri_18
13
13
 
14
14
  gem "coveralls", :require => false, :platforms => [:mri_19, :mri_20], :group => :development
15
+
16
+ gem 'test-unit', :group => [:development, :test], :platforms => [:mri_20, :mri_22]
data/README.md CHANGED
@@ -54,7 +54,7 @@ end
54
54
 
55
55
  ## Ruby Compatibility
56
56
 
57
- Premailer is tested on Ruby 1.8.7, Ruby 1.9.2, Ruby 1.9.3, and Ruby 2.0.0 . It also works on REE. JRuby support is close; contributors are welcome. Checkout the latest build status on the [Travis CI dashboard](http://travis-ci.org/#!/premailer/premailer).
57
+ Premailer is tested on Ruby 1.8.7, Ruby 1.9.2, Ruby 1.9.3, and Ruby 2.x.0 . It also works on REE. JRuby support is close; contributors are welcome. Checkout the latest build status on the [Travis CI dashboard](http://travis-ci.org/#!/premailer/premailer).
58
58
 
59
59
  ## Premailer-specific CSS
60
60
 
@@ -21,10 +21,10 @@ 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
29
  if Premailer.is_media_query?(media_types) || selector =~ Premailer::RE_UNMERGABLE_SELECTORS
30
30
  @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration), media_types) unless @options[:preserve_styles]
@@ -33,7 +33,7 @@ class Premailer
33
33
  if selector =~ Premailer::RE_RESET_SELECTORS
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(selector, declaration)) unless !@options[:preserve_reset]
36
+ @unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless !@options[:preserve_reset]
37
37
  end
38
38
 
39
39
  # Change single ID CSS selectors into xpath so that we can match more
@@ -47,7 +47,7 @@ class Premailer
47
47
  el['style'] = (el.attributes['style'].to_s ||= '') + ' ' + block
48
48
  end
49
49
  end
50
- rescue ::Nokogiri::SyntaxError, RuntimeError, ArgumentError
50
+ rescue ::Nokogiri::SyntaxError, RuntimeError, ArgumentError
51
51
  $stderr.puts "CSS syntax error with selector: #{selector}" if @options[:verbose]
52
52
  next
53
53
  end
@@ -76,7 +76,7 @@ class Premailer
76
76
  # Duplicate CSS attributes as HTML attributes
77
77
  if Premailer::RELATED_ATTRIBUTES.has_key?(el.name)
78
78
  Premailer::RELATED_ATTRIBUTES[el.name].each do |css_att, html_att|
79
- el[html_att] = merged[css_att].gsub(/url\('(.*)'\)/,'\1').gsub(/;$|\s*!important/, '').strip if el[html_att].nil? and not merged[css_att].empty?
79
+ el[html_att] = merged[css_att].gsub(/url\(['|"](.*)['|"]\)/, '\1').gsub(/;$|\s*!important/, '').strip if el[html_att].nil? and not merged[css_att].empty?
80
80
  end
81
81
  end
82
82
 
@@ -84,7 +84,9 @@ class Premailer
84
84
  merged.create_shorthand!
85
85
 
86
86
  # write the inline STYLE attribute
87
- el['style'] = Premailer.escape_string(merged.declarations_to_s).split(';').map(&:strip).sort.join('; ')
87
+ attributes = Premailer.escape_string(merged.declarations_to_s).split(';').map(&:strip)
88
+ attributes = attributes.map { |attr| [attr.split(':').first, attr] }.sort_by { |pair| pair.first }.map { |pair| pair[1] }
89
+ el['style'] = attributes.join('; ')
88
90
  end
89
91
 
90
92
  doc = write_unmergable_css_rules(doc, @unmergable_rules)
@@ -144,7 +146,7 @@ class Premailer
144
146
 
145
147
  unless styles.empty?
146
148
  style_tag = "<style type=\"text/css\">\n#{styles}</style>"
147
- if body = doc.search('body')
149
+ unless (body = doc.search('body')).empty?
148
150
  if doc.at_css('body').children && !doc.at_css('body').children.empty?
149
151
  doc.at_css('body').children.before(::Nokogiri::XML.fragment(style_tag))
150
152
  else
@@ -167,7 +169,8 @@ class Premailer
167
169
  html_src = ''
168
170
  begin
169
171
  html_src = @doc.at("body").inner_html
170
- rescue; end
172
+ rescue;
173
+ end
171
174
 
172
175
  html_src = @doc.to_html unless html_src and not html_src.empty?
173
176
  convert_to_text(html_src, @options[:line_length], @html_encoding)
@@ -213,13 +216,13 @@ class Premailer
213
216
  end
214
217
  end
215
218
  # Default encoding is ASCII-8BIT (binary) per http://groups.google.com/group/nokogiri-talk/msg/0b81ef0dc180dc74
216
- # However, we really don't want to hardcode this. ASCII-8BIG should be the default, but not the only option.
219
+ # However, we really don't want to hardcode this. ASCII-8BIT should be the default, but not the only option.
217
220
  if thing.is_a?(String) and RUBY_VERSION =~ /1.9/
218
221
  thing = thing.force_encoding(@options[:input_encoding]).encode!
219
- doc = ::Nokogiri::HTML(thing, nil, @options[:input_encoding]) {|c| c.recover }
222
+ doc = ::Nokogiri::HTML(thing, nil, @options[:input_encoding]) { |c| c.recover }
220
223
  else
221
224
  default_encoding = RUBY_PLATFORM == 'java' ? nil : 'BINARY'
222
- doc = ::Nokogiri::HTML(thing, nil, @options[:input_encoding] || default_encoding) {|c| c.recover }
225
+ doc = ::Nokogiri::HTML(thing, nil, @options[:input_encoding] || default_encoding) { |c| c.recover }
223
226
  end
224
227
 
225
228
  # Fix for removing any CDATA tags from both style and script tags inserted per
@@ -10,6 +10,11 @@ module HtmlToPlainText
10
10
  def convert_to_text(html, line_length = 65, from_charset = 'UTF-8')
11
11
  txt = html
12
12
 
13
+ # strip text ignored html. Useful for removing
14
+ # headers and footers that aren't needed in the
15
+ # text version
16
+ txt.gsub!(/<!-- start text\/html -->.*?<!-- end text\/html -->/m, '')
17
+
13
18
  # replace images with their alt attributes
14
19
  # for img tags with "" for attribute quotes
15
20
  # with or without closing tag
@@ -74,12 +74,13 @@ class Premailer
74
74
  'blockquote' => {'text-align' => 'align'},
75
75
  'body' => {'background-color' => 'bgcolor'},
76
76
  'table' => {
77
+ '-premailer-align' => 'align',
77
78
  'background-color' => 'bgcolor',
78
79
  'background-image' => 'background',
79
80
  '-premailer-width' => 'width',
80
81
  '-premailer-height' => 'height',
81
82
  '-premailer-cellpadding' => 'cellpadding',
82
- '-premailer-cellspacing' => 'cellspacing',
83
+ '-premailer-cellspacing' => 'cellspacing'
83
84
  },
84
85
  'tr' => {
85
86
  'text-align' => 'align',
@@ -100,7 +101,11 @@ class Premailer
100
101
  '-premailer-width' => 'width',
101
102
  '-premailer-height' => 'height'
102
103
  },
103
- 'img' => {'float' => 'align'}
104
+ 'img' => {
105
+ 'float' => 'align',
106
+ '-premailer-width' => 'width',
107
+ '-premailer-height' => 'height'
108
+ }
104
109
  }
105
110
 
106
111
  # URI of the HTML file used
@@ -193,6 +198,7 @@ class Premailer
193
198
  :output_encoding => nil,
194
199
  :replace_html_entities => false,
195
200
  :escape_url_attributes => true,
201
+ :unescaped_ampersand => false,
196
202
  :adapter => Adapter.use,
197
203
  }.merge(options)
198
204
 
@@ -289,7 +295,7 @@ protected
289
295
 
290
296
  if tag.attributes['href'].to_s.include? @base_url.to_s and @html_file.kind_of?(String)
291
297
  if @options[:with_html_string]
292
- link_uri = tag.attributes['href'].to_s.sub(@base_url.to_s, '').sub(/\A\/*/, '')
298
+ link_uri = tag.attributes['href'].to_s.sub(@base_url.to_s, '')
293
299
  else
294
300
  link_uri = File.join(File.dirname(@html_file), tag.attributes['href'].to_s.sub!(@base_url.to_s, ''))
295
301
  # if the file does not exist locally, try to grab the remote reference
@@ -371,7 +377,8 @@ public
371
377
  end
372
378
 
373
379
  if href.query and not href.query.empty?
374
- href.query = href.query + '&amp;' + qs
380
+ amp = @options[:unescaped_ampersand] ? '&' : '&amp;'
381
+ href.query = href.query + amp + qs
375
382
  else
376
383
  href.query = qs
377
384
  end
@@ -1,4 +1,4 @@
1
1
  class Premailer
2
2
  # Premailer version.
3
- VERSION = '1.8.4'.freeze
3
+ VERSION = '1.8.6'.freeze
4
4
  end
@@ -11,9 +11,9 @@ class Premailer::TestCase < Test::Unit::TestCase
11
11
  BASE_PATH = File.expand_path(File.dirname(__FILE__)) + '/files'
12
12
 
13
13
  def setup
14
- stub_request(:any, /premailer\.dev\/*/).to_return do |request|
14
+ stub_request(:any, /premailer\.dev\/*/).to_return do |request|
15
15
  file_path = BASE_PATH + URI.parse(request.uri).path
16
- if File.exists?(file_path)
16
+ if File.exists?(file_path)
17
17
  { :status => 200, :body => File.open(file_path) }
18
18
  else
19
19
  { :status => 404, :body => "#{file_path} not found" }
@@ -22,17 +22,17 @@ class Premailer::TestCase < Test::Unit::TestCase
22
22
 
23
23
  stub_request(:get, /my\.example\.com\:8080\/*/).to_return(:status => 200, :body => "", :headers => {})
24
24
  end
25
-
25
+
26
26
  def default_test; end
27
-
28
- protected
27
+
28
+ protected
29
29
  def local_setup(f = 'base.html', opts = {})
30
30
  base_file = BASE_PATH + '/' + f
31
31
  premailer = Premailer.new(base_file, opts)
32
32
  premailer.to_inline_css
33
33
  @doc = premailer.processed_doc
34
34
  end
35
-
35
+
36
36
  def remote_setup(f = 'base.html', opts = {})
37
37
  @premailer = Premailer.new(BASE_URI + "#{f}", opts)
38
38
  @premailer.to_inline_css
@@ -69,11 +69,23 @@ END_HTML
69
69
  assert_plaintext "* item 1\n* item 2", "<li class='123'>item 1</li> <li>item 2</li>\n"
70
70
  assert_plaintext "* item 1\n* item 2\n* item 3", "<li>item 1</li> \t\n <li>item 2</li> <li> item 3</li>\n"
71
71
  end
72
-
72
+
73
73
  def test_stripping_html
74
74
  assert_plaintext 'test text', "<p class=\"123'45 , att\" att=tester>test <span class='te\"st'>text</span>\n"
75
75
  end
76
76
 
77
+ def test_stripping_ignored_blocks
78
+ html = <<END_HTML
79
+ <p>test</p>
80
+ <!-- start text/html -->
81
+ <img src="logo.png" alt="logo">
82
+ <!-- end text/html -->
83
+ <p>text</p>
84
+ END_HTML
85
+ premailer = Premailer.new(html, :with_html_string => true)
86
+ assert_match /test\n\ntext/, premailer.to_plain_text
87
+ end
88
+
77
89
  def test_paragraphs_and_breaks
78
90
  assert_plaintext "Test text\n\nTest text", "<p>Test text</p><p>Test text</p>"
79
91
  assert_plaintext "Test text\n\nTest text", "\n<p>Test text</p>\n\n\n\t<p>Test text</p>\n"
@@ -81,7 +93,7 @@ END_HTML
81
93
  assert_plaintext "Test text\nTest text", "\n<p>Test text<br> \tTest text<br></p>\n"
82
94
  assert_plaintext "Test text\n\nTest text", "Test text<br><BR />Test text"
83
95
  end
84
-
96
+
85
97
  def test_headings
86
98
  assert_plaintext "****\nTest\n****", "<h1>Test</h1>"
87
99
  assert_plaintext "****\nTest\n****", "\t<h1>\nTest</h1> "
@@ -90,7 +102,7 @@ END_HTML
90
102
  assert_plaintext "----\nTest\n----", "<h2>Test</h2>"
91
103
  assert_plaintext "Test\n----", "<h3> <span class='a'>Test </span></h3>"
92
104
  end
93
-
105
+
94
106
  def test_wrapping_lines
95
107
  raw = ''
96
108
  100.times { raw += 'test ' }
@@ -103,7 +115,7 @@ END_HTML
103
115
  end
104
116
 
105
117
  def test_img_alt_tags
106
- # ensure html imag tags that aren't self-closed are parsed,
118
+ # ensure html imag tags that aren't self-closed are parsed,
107
119
  # along with accepting both '' and "" as attribute quotes
108
120
 
109
121
  # <img alt="" />
@@ -119,7 +131,7 @@ END_HTML
119
131
  def test_links
120
132
  # basic
121
133
  assert_plaintext 'Link ( http://example.com/ )', '<a href="http://example.com/">Link</a>'
122
-
134
+
123
135
  # nested html
124
136
  assert_plaintext 'Link ( http://example.com/ )', '<a href="http://example.com/"><span class="a">Link</span></a>'
125
137
 
@@ -131,13 +143,13 @@ END_HTML
131
143
 
132
144
  # complex link
133
145
  assert_plaintext 'Link ( http://example.com:80/~user?aaa=bb&c=d,e,f#foo )', '<a href="http://example.com:80/~user?aaa=bb&amp;c=d,e,f#foo">Link</a>'
134
-
146
+
135
147
  # attributes
136
148
  assert_plaintext 'Link ( http://example.com/ )', '<a title=\'title\' href="http://example.com/">Link</a>'
137
-
149
+
138
150
  # spacing
139
151
  assert_plaintext 'Link ( http://example.com/ )', '<a href=" http://example.com/ "> Link </a>'
140
-
152
+
141
153
  # multiple
142
154
  assert_plaintext 'Link A ( http://example.com/a/ ) Link B ( http://example.com/b/ )', '<a href="http://example.com/a/">Link A</a> <a href="http://example.com/b/">Link B</a>'
143
155
 
@@ -145,24 +157,24 @@ END_HTML
145
157
  assert_plaintext 'Link ( %%LINK%% )', '<a href="%%LINK%%">Link</a>'
146
158
  assert_plaintext 'Link ( [LINK] )', '<a href="[LINK]">Link</a>'
147
159
  assert_plaintext 'Link ( {LINK} )', '<a href="{LINK}">Link</a>'
148
-
160
+
149
161
  # unsubscribe
150
162
  assert_plaintext 'Link ( [[!unsubscribe]] )', '<a href="[[!unsubscribe]]">Link</a>'
151
163
 
152
164
  # empty link gets dropped, and shouldn't run forever
153
165
  assert_plaintext(("This is some more text\n\n" * 14 + "This is some more text"), "<a href=\"test\"></a>#{"\n<p>This is some more text</p>" * 15}")
154
166
  end
155
-
167
+
156
168
  # see https://github.com/alexdunae/premailer/issues/72
157
169
  def test_multiple_links_per_line
158
- assert_plaintext 'This is link1 ( http://www.google.com ) and link2 ( http://www.google.com ) is next.',
170
+ assert_plaintext 'This is link1 ( http://www.google.com ) and link2 ( http://www.google.com ) is next.',
159
171
  '<p>This is <a href="http://www.google.com" >link1</a> and <a href="http://www.google.com" >link2 </a> is next.</p>',
160
172
  nil, 10000
161
173
  end
162
174
 
163
175
  # see https://github.com/alexdunae/premailer/issues/72
164
176
  def test_links_within_headings
165
- assert_plaintext "****************************\nTest ( http://example.com/ )\n****************************",
177
+ assert_plaintext "****************************\nTest ( http://example.com/ )\n****************************",
166
178
  "<h1><a href='http://example.com/'>Test</a></h1>"
167
179
  end
168
180
 
@@ -12,36 +12,36 @@ class TestLinks < Premailer::TestCase
12
12
  def test_appending_link_query_string
13
13
  qs = 'utm_source=1234&tracking=good&amp;doublescape'
14
14
  opts = {:base_url => 'http://example.com/', :link_query_string => qs, :with_html_string => true, :adapter => :hpricot}
15
-
15
+
16
16
  appendable = [
17
- '/',
18
- opts[:base_url],
19
- 'https://example.com/tester',
20
- 'images/',
21
- "#{opts[:base_url]}test.html?cn=tf&amp;c=20&amp;ord=random",
22
- '?query=string'
17
+ '/',
18
+ opts[:base_url],
19
+ 'https://example.com/tester',
20
+ 'images/',
21
+ "#{opts[:base_url]}test.html?cn=tf&amp;c=20&amp;ord=random",
22
+ '?query=string'
23
23
  ]
24
-
24
+
25
25
  not_appendable = [
26
- '%DONOTCONVERT%',
27
- '{DONOTCONVERT}',
28
- '[DONOTCONVERT]',
29
- '<DONOTCONVERT>',
30
- '{@msg-txturl}',
31
- '[[!unsubscribe]]',
32
- '#relative',
33
- 'tel:5555551212',
34
- 'http://example.net/',
35
- 'mailto:premailer@example.com',
36
- 'ftp://example.com',
37
- 'gopher://gopher.floodgap.com/1/fun/twitpher'
26
+ '%DONOTCONVERT%',
27
+ '{DONOTCONVERT}',
28
+ '[DONOTCONVERT]',
29
+ '<DONOTCONVERT>',
30
+ '{@msg-txturl}',
31
+ '[[!unsubscribe]]',
32
+ '#relative',
33
+ 'tel:5555551212',
34
+ 'http://example.net/',
35
+ 'mailto:premailer@example.com',
36
+ 'ftp://example.com',
37
+ 'gopher://gopher.floodgap.com/1/fun/twitpher'
38
38
  ]
39
-
39
+
40
40
  html = appendable.collect {|url| "<a href='#{url}'>Link</a>" }
41
41
 
42
42
  premailer = Premailer.new(html.to_s, opts)
43
43
  premailer.to_inline_css
44
-
44
+
45
45
  premailer.processed_doc.search('a').each do |el|
46
46
  href = el.attributes['href'].to_s
47
47
  next if href.nil? or href.empty?
@@ -53,7 +53,7 @@ class TestLinks < Premailer::TestCase
53
53
 
54
54
  premailer = Premailer.new(html.to_s, opts)
55
55
  premailer.to_inline_css
56
-
56
+
57
57
  premailer.processed_doc.search('a').each do |el|
58
58
  href = el['href']
59
59
  next if href.nil? or href.empty?
@@ -66,35 +66,45 @@ class TestLinks < Premailer::TestCase
66
66
 
67
67
  premailer = Premailer.new("<a href='/test/?'>Link</a> <a href='/test/'>Link</a>", :link_query_string => qs, :with_html_string => true)
68
68
  premailer.to_inline_css
69
-
69
+
70
70
  premailer.processed_doc.search('a').each do |a|
71
71
  assert_equal '/test/?utm_source=1234', a['href'].to_s
72
72
  end
73
73
 
74
74
  premailer = Premailer.new("<a href='/test/?123&456'>Link</a>", :link_query_string => qs, :with_html_string => true)
75
75
  premailer.to_inline_css
76
-
76
+
77
77
  assert_equal '/test/?123&456&amp;utm_source=1234', premailer.processed_doc.at('a')['href']
78
78
  end
79
79
 
80
+ def test_unescape_ampersand
81
+ qs = 'utm_source=1234'
82
+
83
+ premailer = Premailer.new("<a href='/test/?q=query'>Link</a>", :link_query_string => qs, :with_html_string => true, :unescaped_ampersand => true)
84
+ premailer.to_inline_css
85
+
86
+ premailer.processed_doc.search('a').each do |a|
87
+ assert_equal '/test/?q=query&utm_source=1234', a['href'].to_s
88
+ end
89
+ end
80
90
 
81
91
  def test_preserving_links
82
92
  html = "<a href='http://example.com/index.php?pram1=one&pram2=two'>Link</a>"
83
93
  premailer = Premailer.new(html.to_s, :link_query_string => '', :with_html_string => true)
84
94
  premailer.to_inline_css
85
-
95
+
86
96
  assert_equal 'http://example.com/index.php?pram1=one&pram2=two', premailer.processed_doc.at('a')['href']
87
97
 
88
98
  html = "<a href='http://example.com/index.php?pram1=one&pram2=two'>Link</a>"
89
99
  premailer = Premailer.new(html.to_s, :link_query_string => 'qs', :with_html_string => true)
90
100
  premailer.to_inline_css
91
-
101
+
92
102
  assert_equal 'http://example.com/index.php?pram1=one&pram2=two&amp;qs', premailer.processed_doc.at('a')['href']
93
103
 
94
104
  end
95
105
 
96
106
  def test_resolving_urls_from_string
97
- ['test.html', '/test.html', './test.html',
107
+ ['test.html', '/test.html', './test.html',
98
108
  'test/../test.html', 'test/../test/../test.html'].each do |q|
99
109
  assert_equal 'http://example.com/test.html', Premailer.resolve_link(q, 'http://example.com/'), q
100
110
  end
@@ -104,18 +114,18 @@ class TestLinks < Premailer::TestCase
104
114
 
105
115
  def test_resolving_urls_from_uri
106
116
  base_uri = URI.parse('http://example.com/')
107
- ['test.html', '/test.html', './test.html',
117
+ ['test.html', '/test.html', './test.html',
108
118
  'test/../test.html', 'test/../test/../test.html'].each do |q|
109
119
  assert_equal 'http://example.com/test.html', Premailer.resolve_link(q, base_uri), q
110
120
  end
111
121
 
112
122
  base_uri = URI.parse('https://example.net:80/~basedir/')
113
123
  assert_equal 'https://example.net:80/~basedir/test.html?var=1#anchor', Premailer.resolve_link('test/../test/../test.html?var=1#anchor', base_uri)
114
-
124
+
115
125
  # base URI with a query string
116
126
  base_uri = URI.parse('http://example.com/dir/index.cfm?newsletterID=16')
117
127
  assert_equal 'http://example.com/dir/index.cfm?link=15', Premailer.resolve_link('?link=15', base_uri)
118
-
128
+
119
129
  # URI preceded by a space
120
130
  base_uri = URI.parse('http://example.com/')
121
131
  assert_equal 'http://example.com/path', Premailer.resolve_link(' path', base_uri)
@@ -143,25 +153,25 @@ class TestLinks < Premailer::TestCase
143
153
  doc = premailer.doc
144
154
 
145
155
  # unchanged links
146
- ['#l02', '#l03', '#l05', '#l06', '#l07', '#l08',
156
+ ['#l02', '#l03', '#l05', '#l06', '#l07', '#l08',
147
157
  '#l09', '#l10', '#l11', '#l12', '#l13'].each do |link_id|
148
158
  assert_equal doc.at(link_id).attributes['href'], pdoc.at(link_id).attributes['href'], link_id
149
159
  end
150
-
160
+
151
161
  assert_equal 'https://my.example.com:8080/', pdoc.at('#l01').attributes['href'].to_s
152
162
  assert_equal 'https://my.example.com:8080/images/', pdoc.at('#l04').attributes['href'].to_s
153
163
  end
154
164
 
155
165
  def test_convertable_inline_links
156
166
  convertable = [
157
- 'my/path/to',
158
- 'other/path',
159
- '/'
167
+ 'my/path/to',
168
+ 'other/path',
169
+ '/'
160
170
  ]
161
171
 
162
172
  html = convertable.collect {|url| "<a href='#{url}'>Link</a>" }
163
173
  premailer = Premailer.new(html.to_s, :base_url => "http://example.com", :with_html_string => true)
164
-
174
+
165
175
  premailer.processed_doc.search('a').each do |el|
166
176
  href = el.attributes['href'].to_s
167
177
  assert(href =~ /http:\/\/example.com/, "link #{href} is not absolute")
@@ -170,25 +180,25 @@ class TestLinks < Premailer::TestCase
170
180
 
171
181
  def test_non_convertable_inline_links
172
182
  not_convertable = [
173
- '%DONOTCONVERT%',
174
- '{DONOTCONVERT}',
175
- '[DONOTCONVERT]',
176
- '<DONOTCONVERT>',
177
- '{@msg-txturl}',
178
- '[[!unsubscribe]]',
179
- '#relative',
180
- 'tel:5555551212',
181
- 'mailto:premailer@example.com',
182
- 'ftp://example.com',
183
- 'gopher://gopher.floodgap.com/1/fun/twitpher',
184
- 'cid:13443452066.10392logo.jpeg@inline_attachment'
183
+ '%DONOTCONVERT%',
184
+ '{DONOTCONVERT}',
185
+ '[DONOTCONVERT]',
186
+ '<DONOTCONVERT>',
187
+ '{@msg-txturl}',
188
+ '[[!unsubscribe]]',
189
+ '#relative',
190
+ 'tel:5555551212',
191
+ 'mailto:premailer@example.com',
192
+ 'ftp://example.com',
193
+ 'gopher://gopher.floodgap.com/1/fun/twitpher',
194
+ 'cid:13443452066.10392logo.jpeg@inline_attachment'
185
195
  ]
186
-
196
+
187
197
  html = not_convertable.collect {|url| "<a href='#{url}'>Link</a>" }
188
198
 
189
199
  premailer = Premailer.new(html.to_s, :base_url => "example.com", :with_html_string => true)
190
200
  premailer.to_inline_css
191
-
201
+
192
202
  premailer.processed_doc.search('a').each do |el|
193
203
  href = el.attributes['href'].to_s
194
204
  assert not_convertable.include?(href), "link #{href} should not be converted: see #{not_convertable.inspect}"
@@ -28,10 +28,10 @@ class TestMisc < Premailer::TestCase
28
28
  </html>
29
29
  END_HTML
30
30
 
31
- premailer = Premailer.new(html, :with_html_string => true)
32
- premailer.to_inline_css
31
+ premailer = Premailer.new(html, :with_html_string => true)
32
+ premailer.to_inline_css
33
33
 
34
- assert_match /color\: red/i, premailer.processed_doc.at('p')['style']
34
+ assert_match /color\: red/i, premailer.processed_doc.at('p')['style']
35
35
  end
36
36
 
37
37
  def test_commented_out_styles_in_the_body
@@ -44,10 +44,10 @@ END_HTML
44
44
  </html>
45
45
  END_HTML
46
46
 
47
- premailer = Premailer.new(html, :with_html_string => true)
48
- premailer.to_inline_css
47
+ premailer = Premailer.new(html, :with_html_string => true)
48
+ premailer.to_inline_css
49
49
 
50
- assert_match /color\: red/i, premailer.processed_doc.at('p')['style']
50
+ assert_match /color\: red/i, premailer.processed_doc.at('p')['style']
51
51
  end
52
52
 
53
53
  def test_not_applying_styles_to_the_head
@@ -64,14 +64,14 @@ END_HTML
64
64
  END_HTML
65
65
 
66
66
  [:nokogiri, :hpricot].each do |adapter|
67
- premailer = Premailer.new(html, :with_html_string => true, :adapter => adapter)
68
- premailer.to_inline_css
67
+ premailer = Premailer.new(html, :with_html_string => true, :adapter => adapter)
68
+ premailer.to_inline_css
69
69
 
70
- h = premailer.processed_doc.at('head')
71
- assert_nil h['style']
70
+ h = premailer.processed_doc.at('head')
71
+ assert_nil h['style']
72
72
 
73
- t = premailer.processed_doc.at('title')
74
- assert_nil t['style']
73
+ t = premailer.processed_doc.at('title')
74
+ assert_nil t['style']
75
75
  end
76
76
  end
77
77
 
@@ -88,8 +88,8 @@ END_HTML
88
88
  </html>
89
89
  END_HTML
90
90
 
91
- premailer = Premailer.new(html, :with_html_string => true)
92
- premailer.to_inline_css
91
+ premailer = Premailer.new(html, :with_html_string => true)
92
+ premailer.to_inline_css
93
93
  premailer.processed_doc.search('p').each do |el|
94
94
  assert_match /red/i, el['style']
95
95
  end
@@ -108,22 +108,22 @@ END_HTML
108
108
  </html>
109
109
  END_HTML
110
110
  [:nokogiri, :hpricot].each do |adapter|
111
- premailer = Premailer.new(html, :with_html_string => true, :preserve_styles => true, :adapter => adapter)
112
- premailer.to_inline_css
113
- assert_equal 1, premailer.processed_doc.search('head link').length
114
- assert_equal 1, premailer.processed_doc.search('head style').length
111
+ premailer = Premailer.new(html, :with_html_string => true, :preserve_styles => true, :adapter => adapter)
112
+ premailer.to_inline_css
113
+ assert_equal 1, premailer.processed_doc.search('head link').length
114
+ assert_equal 1, premailer.processed_doc.search('head style').length
115
115
 
116
- premailer = Premailer.new(html, :with_html_string => true, :preserve_styles => false, :adapter => adapter)
117
- premailer.to_inline_css
118
- assert_nil premailer.processed_doc.at('body link')
116
+ premailer = Premailer.new(html, :with_html_string => true, :preserve_styles => false, :adapter => adapter)
117
+ premailer.to_inline_css
118
+ assert_nil premailer.processed_doc.at('body link')
119
119
 
120
120
  # should be preserved as unmergeable
121
121
 
122
- assert_match /color: red/i, premailer.processed_doc.at('body style').inner_html
122
+ assert_match /color: red/i, premailer.processed_doc.at('body style').inner_html
123
123
 
124
- assert_match /a:hover/i, premailer.processed_doc.at('style').inner_html
124
+ assert_match /a:hover/i, premailer.processed_doc.at('style').inner_html
125
125
 
126
- end
126
+ end
127
127
  end
128
128
 
129
129
  def test_unmergable_rules
@@ -133,13 +133,13 @@ END_HTML
133
133
  </body> </html>
134
134
  END_HTML
135
135
 
136
- premailer = Premailer.new(html, :with_html_string => true, :verbose => true)
137
- premailer.to_inline_css
136
+ premailer = Premailer.new(html, :with_html_string => true, :verbose => true)
137
+ premailer.to_inline_css
138
138
 
139
139
  # blue should be inlined
140
- assert_no_match /a\:hover[\s]*\{[\s]*color\:[\s]*blue[\s]*;[\s]*\}/i, premailer.processed_doc.at('body style').inner_html
140
+ assert_no_match /a\:hover[\s]*\{[\s]*color\:[\s]*blue[\s]*;[\s]*\}/i, premailer.processed_doc.at('body style').inner_html
141
141
  # red should remain in <style> block
142
- assert_match /a\:hover[\s]*\{[\s]*color\:[\s]*red;[\s]*\}/i, premailer.processed_doc.at('body style').inner_html
142
+ assert_match /a\:hover[\s]*\{[\s]*color\:[\s]*red;[\s]*\}/i, premailer.processed_doc.at('body style').inner_html
143
143
  end
144
144
 
145
145
  def test_unmergable_media_queries
@@ -188,11 +188,11 @@ END_HTML
188
188
  </html>
189
189
  END_HTML
190
190
 
191
- premailer = Premailer.new(html, :with_html_string => true)
191
+ premailer = Premailer.new(html, :with_html_string => true)
192
192
  assert_nothing_raised do
193
- premailer.to_inline_css
194
- end
195
- assert_match /a\:hover[\s]*\{[\s]*color\:[\s]*red;[\s]*\}/i, premailer.processed_doc.at('style').inner_html
193
+ premailer.to_inline_css
194
+ end
195
+ assert_match /a\:hover[\s]*\{[\s]*color\:[\s]*red;[\s]*\}/i, premailer.processed_doc.at('style').inner_html
196
196
  end
197
197
 
198
198
  # in response to https://github.com/alexdunae/premailer/issues#issue/7
@@ -206,11 +206,11 @@ END_HTML
206
206
  </html>
207
207
  END_HTML
208
208
 
209
- premailer = Premailer.new(html, :with_html_string => true)
209
+ premailer = Premailer.new(html, :with_html_string => true)
210
210
  assert_nothing_raised do
211
- premailer.to_inline_css
212
- end
213
- assert_match /color: red/, premailer.processed_doc.at('a').attributes['style'].to_s
211
+ premailer.to_inline_css
212
+ end
213
+ assert_match /color: red/, premailer.processed_doc.at('a').attributes['style'].to_s
214
214
  end
215
215
 
216
216
  # in response to https://github.com/alexdunae/premailer/issues#issue/7
@@ -234,10 +234,10 @@ END_HTML
234
234
  </tr>
235
235
  END_HTML
236
236
 
237
- premailer = Premailer.new(html, :with_html_string => true)
238
- premailer.to_inline_css
239
- assert_match /font-size: xx-large/, premailer.processed_doc.search('.style3').first.attributes['style'].to_s
240
- assert_match /background: #000080/, premailer.processed_doc.search('.style5').first.attributes['style'].to_s
237
+ premailer = Premailer.new(html, :with_html_string => true)
238
+ premailer.to_inline_css
239
+ assert_match /font-size: xx-large/, premailer.processed_doc.search('.style3').first.attributes['style'].to_s
240
+ assert_match /background: #000080/, premailer.processed_doc.search('.style5').first.attributes['style'].to_s
241
241
  end
242
242
 
243
243
  # in response to https://github.com/alexdunae/premailer/issues/56
@@ -254,7 +254,7 @@ END_HTML
254
254
  END_HTML
255
255
 
256
256
  premailer = Premailer.new(html, :with_html_string => true, :adapter => :nokogiri)
257
- premailer.to_inline_css
257
+ premailer.to_inline_css
258
258
  assert_equal 'color: green !important', premailer.processed_doc.search('p').first.attributes['style'].to_s
259
259
  end
260
260
 
@@ -274,7 +274,7 @@ END_HTML
274
274
  END_HTML
275
275
 
276
276
  premailer = Premailer.new(html, :with_html_string => true)
277
- premailer.to_inline_css
277
+ premailer.to_inline_css
278
278
 
279
279
  assert_match /margin: 0 auto/, premailer.processed_doc.search('#page').first.attributes['style'].to_s
280
280
  assert_match /border-style: solid none solid solid;/, premailer.processed_doc.search('p').first.attributes['style'].to_s
@@ -6,13 +6,13 @@ class TestPremailer < Premailer::TestCase
6
6
  def test_special_characters_nokogiri
7
7
  html = '<p>cédille c&eacute; & garçon gar&#231;on à &agrave; &nbsp; &amp; &copy;</p>'
8
8
  premailer = Premailer.new(html, :with_html_string => true, :adapter => :nokogiri)
9
- premailer.to_inline_css
9
+ premailer.to_inline_css
10
10
  assert_equal 'c&eacute;dille c&eacute; &amp; gar&ccedil;on gar&ccedil;on &agrave; &agrave; &nbsp; &amp; &copy;', premailer.processed_doc.at('p').inner_html
11
11
  end
12
12
 
13
13
  def test_special_characters_nokogiri_remote
14
14
  remote_setup('chars.html', :adapter => :nokogiri)
15
- @premailer.to_inline_css
15
+ @premailer.to_inline_css
16
16
  assert_equal 'c&eacute;dille c&eacute; &amp; gar&ccedil;on gar&ccedil;on &agrave; &agrave; &nbsp; &amp; &copy;', @premailer.processed_doc.at('p').inner_html
17
17
  end
18
18
 
@@ -29,7 +29,7 @@ class TestPremailer < Premailer::TestCase
29
29
  def test_special_characters_hpricot
30
30
  html = '<p>cédille c&eacute; & garçon gar&#231;on à &agrave; &nbsp; &amp;</p>'
31
31
  premailer = Premailer.new(html, :with_html_string => true, :adapter => :hpricot)
32
- premailer.to_inline_css
32
+ premailer.to_inline_css
33
33
  assert_equal 'c&eacute;dille c&eacute; &amp; gar&ccedil;on gar&ccedil;on &agrave; &agrave; &nbsp; &amp;', premailer.processed_doc.at('p').inner_html
34
34
  end
35
35
 
@@ -73,10 +73,10 @@ END_HTML
73
73
  qs = 'testing=123'
74
74
 
75
75
  [:nokogiri, :hpricot].each do |adapter|
76
- premailer = Premailer.new(html, :with_html_string => true, :link_query_string => qs, :adapter => adapter)
77
- premailer.to_inline_css
78
- assert_no_match /testing=123/, premailer.processed_doc.search('a').first.attributes['href'].to_s
79
- end
76
+ premailer = Premailer.new(html, :with_html_string => true, :link_query_string => qs, :adapter => adapter)
77
+ premailer.to_inline_css
78
+ assert_no_match /testing=123/, premailer.processed_doc.search('a').first.attributes['href'].to_s
79
+ end
80
80
  end
81
81
 
82
82
  def test_escaping_strings
@@ -176,7 +176,7 @@ END_HTML
176
176
  END_HTML
177
177
 
178
178
  [:nokogiri, :hpricot].each do |adapter|
179
- pm = Premailer.new(html, :with_html_string => true, :adapter => adapter, :escape_url_attributes => false)
179
+ pm = Premailer.new(html, :with_html_string => true, :adapter => adapter, :escape_url_attributes => false)
180
180
  pm.to_inline_css
181
181
  doc = pm.processed_doc
182
182
  assert_equal doc.at('#google')['href'], 'http://google.com'
@@ -194,14 +194,14 @@ END_HTML
194
194
  END_HTML
195
195
 
196
196
  [:nokogiri, :hpricot].each do |adapter|
197
- pm = Premailer.new(html, :with_html_string => true, :remove_ids => true, :adapter => adapter)
197
+ pm = Premailer.new(html, :with_html_string => true, :remove_ids => true, :adapter => adapter)
198
198
  pm.to_inline_css
199
199
  doc = pm.processed_doc
200
- assert_nil doc.at('#remove')
201
- assert_nil doc.at('#keep')
202
- hashed_id = doc.at('a')['href'][1..-1]
203
- assert_not_nil doc.at("\##{hashed_id}")
204
- end
200
+ assert_nil doc.at('#remove')
201
+ assert_nil doc.at('#keep')
202
+ hashed_id = doc.at('a')['href'][1..-1]
203
+ assert_not_nil doc.at("\##{hashed_id}")
204
+ end
205
205
  end
206
206
 
207
207
  def test_reset_contenteditable
@@ -213,12 +213,12 @@ END_HTML
213
213
  </body> </html>
214
214
  ___
215
215
  [:nokogiri, :hpricot].each do |adapter|
216
- pm = Premailer.new(html, :with_html_string => true, :reset_contenteditable => true, :adapter => adapter)
216
+ pm = Premailer.new(html, :with_html_string => true, :reset_contenteditable => true, :adapter => adapter)
217
217
  pm.to_inline_css
218
218
  doc = pm.processed_doc
219
- assert_nil doc.at('#editable')['contenteditable'],
220
- "#{adapter}: contenteditable attribute not removed"
221
- end
219
+ assert_nil doc.at('#editable')['contenteditable'],
220
+ "#{adapter}: contenteditable attribute not removed"
221
+ end
222
222
  end
223
223
 
224
224
  def test_carriage_returns_as_entities
@@ -256,12 +256,12 @@ END_HTML
256
256
  END_HTML
257
257
 
258
258
  [:nokogiri, :hpricot].each do |adapter|
259
- pm = Premailer.new(html, :with_html_string => true, :adapter => adapter)
259
+ pm = Premailer.new(html, :with_html_string => true, :adapter => adapter)
260
260
  pm.to_inline_css
261
261
  doc = pm.processed_doc
262
- assert_equal '500', doc.at('table')['width']
263
- assert_equal '20', doc.at('td')['height']
264
- end
262
+ assert_equal '500', doc.at('table')['width']
263
+ assert_equal '20', doc.at('td')['height']
264
+ end
265
265
  end
266
266
 
267
267
  def test_include_link_tags_option
@@ -334,4 +334,14 @@ END_HTML
334
334
  end
335
335
  end
336
336
 
337
+ def test_empty_html_nokogiri
338
+ html = ""
339
+ css = "a:hover {color:red;}"
340
+
341
+ assert_nothing_raised do
342
+ pm = Premailer.new(html, :with_html_string => true, :css_string => css, :adapter => :nokogiri)
343
+ pm.to_inline_css
344
+ end
345
+ end
346
+
337
347
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: premailer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.4
4
+ version: 1.8.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Dunae
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-01 00:00:00.000000000 Z
11
+ date: 2015-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: css_parser
@@ -203,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
203
203
  version: '0'
204
204
  requirements: []
205
205
  rubyforge_project:
206
- rubygems_version: 2.4.3
206
+ rubygems_version: 2.4.6
207
207
  signing_key:
208
208
  specification_version: 4
209
209
  summary: Preflight for HTML e-mail.