premailer 1.8.4 → 1.8.6

Sign up to get free protection for your applications and to get access to all the features.
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.