regru-premailer 1.7.7 → 1.7.8

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.
data/.gitignore CHANGED
@@ -8,4 +8,4 @@ doc/
8
8
  .yardoc/
9
9
  *.sw?
10
10
  pkg/
11
-
11
+ *.sublime-*
@@ -0,0 +1 @@
1
+ cext.enabled=true
@@ -4,5 +4,6 @@ rvm:
4
4
  - 1.8.7
5
5
  - 1.9.2
6
6
  - 1.9.3
7
+ - 2.0.0
7
8
  - jruby
8
9
  - ree
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
- source :rubygems
1
+ source "https://rubygems.org"
2
+
2
3
  gem 'css_parser', :git => 'git://github.com/alexdunae/css_parser.git'
3
4
  gem 'webmock', :group => [:development, :test]
4
5
 
@@ -139,7 +139,9 @@ class Premailer
139
139
 
140
140
  unless styles.empty?
141
141
  style_tag = "\n<style type=\"text/css\">\n#{styles}</style>\n"
142
- if body = doc.search('body')
142
+ if head = doc.search('head')
143
+ head.append(style_tag)
144
+ elsif body = doc.search('body')
143
145
  body.append(style_tag)
144
146
  else
145
147
  doc.inner_html= doc.inner_html << style_tag
@@ -112,7 +112,7 @@ class Premailer
112
112
  @processed_doc = doc
113
113
  if is_xhtml?
114
114
  # we don't want to encode carriage returns
115
- @processed_doc.to_xhtml(:encoding => nil).gsub(/&\#xD;/i, "\r")
115
+ @processed_doc.to_xhtml(:encoding => nil).gsub(/&\#(xD|13);/i, "\r")
116
116
  else
117
117
  @processed_doc.to_html
118
118
  end
@@ -129,11 +129,17 @@ class Premailer
129
129
  unmergable_rules.each_selector(:all, :force_important => true) do |selector, declarations, specificity|
130
130
  styles += "#{selector} { #{declarations} }\n"
131
131
  end
132
-
132
+
133
133
  unless styles.empty?
134
134
  style_tag = "<style type=\"text/css\">\n#{styles}></style>"
135
- if body = doc.search('body')
136
- doc.at_css('body').children.before(::Nokogiri::XML.fragment(style_tag))
135
+ if head = doc.search('head')
136
+ doc.at_css('head').add_child(::Nokogiri::XML.fragment(style_tag))
137
+ elsif body = doc.search('body')
138
+ if doc.at_css('body').children && !doc.at_css('body').children.empty?
139
+ doc.at_css('body').children.before(::Nokogiri::XML.fragment(style_tag))
140
+ else
141
+ doc.at_css('body').add_child(::Nokogiri::XML.fragment(style_tag))
142
+ end
137
143
  else
138
144
  doc.inner_html = style_tag += doc.inner_html
139
145
  end
@@ -191,7 +197,7 @@ class Premailer
191
197
  doc = nil
192
198
 
193
199
  # Handle HTML entities
194
- if @options[:replace_html_entities] == true and thing.is_a?(String)
200
+ if @options[:replace_html_entities] == true and thing.is_a?(String)
195
201
  if RUBY_VERSION =~ /1.9/
196
202
  html_entity_ruby_version = "1.9"
197
203
  elsif RUBY_VERSION =~ /1.8/
@@ -213,6 +219,11 @@ class Premailer
213
219
  doc = ::Nokogiri::HTML(thing, nil, @options[:input_encoding] || default_encoding) {|c| c.recover }
214
220
  end
215
221
 
222
+ # Fix for removing any CDATA tags inserted per https://github.com/sparklemotion/nokogiri/issues/311
223
+ doc.search("style").children.each do |child|
224
+ child.swap(child.text()) if child.cdata?
225
+ end
226
+
216
227
  return doc
217
228
  end
218
229
 
@@ -14,20 +14,36 @@ module HtmlToPlainText
14
14
  he = HTMLEntities.new
15
15
  txt = he.decode(txt)
16
16
 
17
- # replace image by their alt attribute
18
- txt.gsub!(/<img.+?alt=\"([^\"]*)\"[^>]*\/>/i, '\1')
19
-
20
- # replace image by their alt attribute
21
- txt.gsub!(/<img.+?alt=\"([^\"]*)\"[^>]*\/>/i, '\1')
22
- txt.gsub!(/<img.+?alt='([^\']*)\'[^>]*\/>/i, '\1')
17
+ # replace images with their alt attributes
18
+ # for img tags with "" for attribute quotes
19
+ # with or without closing tag
20
+ # eg. the following formats:
21
+ # <img alt="" />
22
+ # <img alt="">
23
+ txt.gsub!(/<img.+?alt=\"([^\"]*)\"[^>]*\>/i, '\1')
24
+
25
+ # for img tags with '' for attribute quotes
26
+ # with or without closing tag
27
+ # eg. the following formats:
28
+ # <img alt='' />
29
+ # <img alt=''>
30
+ txt.gsub!(/<img.+?alt=\'([^\']*)\'[^>]*\>/i, '\1')
23
31
 
24
32
  # links
25
- txt.gsub!(/<a.+?href=\"(mailto:)?([^\"]*)\"[^>]*>((.|\s)+?)<\/a>/i) do |s|
26
- $3.strip + ' ( ' + $2.strip + ' )'
33
+ txt.gsub!(/<a.+?href=\"(mailto:)?([^\"]*)\"[^>]*>((.|\s)*?)<\/a>/i) do |s|
34
+ if $3.empty?
35
+ ''
36
+ else
37
+ $3.strip + ' ( ' + $2.strip + ' )'
38
+ end
27
39
  end
28
40
 
29
- txt.gsub!(/<a.+?href='(mailto:)?([^\']*)\'[^>]*>((.|\s)+?)<\/a>/i) do |s|
30
- $3.strip + ' ( ' + $2.strip + ' )'
41
+ txt.gsub!(/<a.+?href='(mailto:)?([^\']*)\'[^>]*>((.|\s)*?)<\/a>/i) do |s|
42
+ if $3.empty?
43
+ ''
44
+ else
45
+ $3.strip + ' ( ' + $2.strip + ' )'
46
+ end
31
47
  end
32
48
 
33
49
 
@@ -291,21 +291,26 @@ protected
291
291
 
292
292
  # Load CSS included in <tt>style</tt> and <tt>link</tt> tags from an HTML document.
293
293
  def load_css_from_html! # :nodoc:
294
- if tags = @doc.search("link[@rel='stylesheet'], style")
294
+ if (@options[:adapter] == :nokogiri)
295
+ tags = @doc.search("link[@rel='stylesheet']", "//style[not(contains(@data-premailer,'ignore'))]")
296
+ else
297
+ tags = @doc.search("link[@rel='stylesheet'], style:not([@data-premailer='ignore'])")
298
+ end
299
+ if tags
295
300
  tags.each do |tag|
296
301
  if tag.to_s.strip =~ /^\<link/i && tag.attributes['href'] && media_type_ok?(tag.attributes['media']) && @options[:include_link_tags]
297
302
  # A user might want to <link /> to a local css file that is also mirrored on the site
298
303
  # but the local one is different (e.g. newer) than the live file, premailer will now choose the local file
299
-
304
+
300
305
  if tag.attributes['href'].to_s.include? @base_url.to_s and @html_file.kind_of?(String)
301
306
  link_uri = File.join(File.dirname(@html_file), tag.attributes['href'].to_s.sub!(@base_url.to_s, ''))
302
307
  end
303
-
308
+
304
309
  # if the file does not exist locally, try to grab the remote reference
305
310
  if link_uri.nil? or not File.exists?(link_uri)
306
311
  link_uri = Premailer.resolve_link(tag.attributes['href'].to_s, @html_file)
307
312
  end
308
-
313
+
309
314
  if Premailer.local_data?(link_uri)
310
315
  $stderr.puts "Loading css from local file: " + link_uri if @options[:verbose]
311
316
  load_css_from_local_file!(link_uri)
@@ -337,10 +342,9 @@ public
337
342
 
338
343
  # @private
339
344
  def media_type_ok?(media_types)
345
+ media_types = media_types.to_s
340
346
  return true if media_types.nil? or media_types.empty?
341
347
  media_types.split(/[\s]+|,/).any? { |media_type| media_type.strip =~ /screen|handheld|all/i }
342
- rescue
343
- true
344
348
  end
345
349
 
346
350
  def append_query_string(doc, qs)
@@ -360,7 +364,7 @@ public
360
364
  doc.search('a').each do|el|
361
365
  href = el.attributes['href'].to_s.strip
362
366
  next if href.nil? or href.empty?
363
-
367
+
364
368
  next if href[0,1] =~ /[\#\{\[\<\%]/ # don't bother with anchors or special-looking links
365
369
 
366
370
  begin
@@ -1,4 +1,4 @@
1
1
  class Premailer
2
2
  # Premailer version.
3
- VERSION = '1.7.7'.freeze
3
+ VERSION = '1.7.8'.freeze
4
4
  end
@@ -1,4 +1,7 @@
1
- $LOAD_PATH.unshift(File.expand_path('./lib', File.dirname(__FILE__)))
1
+ GEM_ROOT = File.dirname(__FILE__).freeze unless defined?(GEM_ROOT)
2
+
3
+ lib_path = File.expand_path('lib', GEM_ROOT)
4
+ $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include? lib_path
2
5
 
3
6
  require 'premailer/version'
4
7
 
@@ -17,9 +20,10 @@ Gem::Specification.new do |s|
17
20
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
18
21
  s.add_dependency('css_parser', '>= 1.1.9')
19
22
  s.add_dependency('htmlentities', '>= 4.0.0')
23
+ s.add_development_dependency "bundler", "~> 1.3"
24
+ s.add_development_dependency('rake', ['~> 0.8', '!= 0.9.0'])
20
25
  s.add_development_dependency('hpricot', '>= 0.8.3')
21
26
  s.add_development_dependency('nokogiri', '>= 1.4.4')
22
- s.add_development_dependency('rake', ['~> 0.8', '!= 0.9.0'])
23
27
  s.add_development_dependency('yard', '~> 0.7.3')
24
28
  s.add_development_dependency('redcarpet', '~> 1.17.2')
25
29
  end
@@ -2,25 +2,23 @@ $:.unshift File.expand_path('../lib', __FILE__)
2
2
 
3
3
  require 'rake'
4
4
  require 'rake/testtask'
5
- require 'rubygems/package_task'
6
- require 'fileutils'
7
- require 'premailer'
5
+ require 'rake'
6
+ require "bundler/gem_tasks"
7
+ require 'yard'
8
8
 
9
- def gemspec
10
- @gemspec ||= begin
11
- file = File.expand_path('../premailer.gemspec', __FILE__)
12
- eval(File.read(file), binding, file)
13
- end
14
- end
9
+ GEM_ROOT = File.dirname(__FILE__).freeze unless defined?(GEM_ROOT)
15
10
 
16
- Gem::PackageTask.new(gemspec) do |pkg|
17
- pkg.need_tar = true
18
- end
11
+ lib_path = File.expand_path('lib', GEM_ROOT)
12
+ $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include? lib_path
13
+
14
+ require 'premailer/version'
19
15
 
20
16
  task :default => [:test]
21
17
 
22
18
  desc 'Parse a URL and write out the output.'
23
19
  task :inline do
20
+ require 'premailer'
21
+
24
22
  url = ENV['url']
25
23
  output = ENV['output']
26
24
 
@@ -30,15 +28,17 @@ task :inline do
30
28
  end
31
29
 
32
30
  premailer = Premailer.new(url, :warn_level => Premailer::Warnings::SAFE, :verbose => true, :adapter => :nokogiri)
33
- fout = File.open(output, "w")
34
- fout.puts premailer.to_inline_css
35
- fout.close
31
+ File.open(output, "w") do |fout|
32
+ fout.puts premailer.to_inline_css
33
+ end
36
34
 
37
35
  puts "Succesfully parsed '#{url}' into '#{output}'"
38
36
  puts premailer.warnings.length.to_s + ' CSS warnings were found'
39
37
  end
40
38
 
41
39
  task :text do
40
+ require 'premailer'
41
+
42
42
  url = ENV['url']
43
43
  output = ENV['output']
44
44
 
@@ -48,9 +48,9 @@ task :text do
48
48
  end
49
49
 
50
50
  premailer = Premailer.new(url, :warn_level => Premailer::Warnings::SAFE)
51
- fout = File.open(output, "w")
52
- fout.puts premailer.to_plain_text
53
- fout.close
51
+ File.open(output, "w") do |fout|
52
+ fout.puts premailer.to_plain_text
53
+ end
54
54
 
55
55
  puts "Succesfully parsed '#{url}' into '#{output}'"
56
56
  end
@@ -60,12 +60,6 @@ Rake::TestTask.new do |t|
60
60
  t.verbose = false
61
61
  end
62
62
 
63
-
64
- begin
65
- require 'yard'
66
-
67
- YARD::Rake::YardocTask.new
68
- rescue LoadError
69
- $stderr.puts "Please install YARD with: gem install yard"
63
+ YARD::Rake::YardocTask.new do |yard|
64
+ yard.options << "--title='premailer #{Premailer::VERSION}'"
70
65
  end
71
-
@@ -102,6 +102,20 @@ END_HTML
102
102
  assert lens.max <= 20
103
103
  end
104
104
 
105
+ def test_img_alt_tags
106
+ # ensure html imag tags that aren't self-closed are parsed,
107
+ # along with accepting both '' and "" as attribute quotes
108
+
109
+ # <img alt="" />
110
+ assert_plaintext 'Example ( http://example.com/ )', '<a href="http://example.com/"><img src="http://example.ru/hello.jpg" alt="Example"/></a>'
111
+ # <img alt="">
112
+ assert_plaintext 'Example ( http://example.com/ )', '<a href="http://example.com/"><img src="http://example.ru/hello.jpg" alt="Example"></a>'
113
+ # <img alt='' />
114
+ assert_plaintext 'Example ( http://example.com/ )', "<a href='http://example.com/'><img src='http://example.ru/hello.jpg' alt='Example'/></a>"
115
+ # <img alt=''>
116
+ assert_plaintext 'Example ( http://example.com/ )', "<a href='http://example.com/'><img src='http://example.ru/hello.jpg' alt='Example'></a>"
117
+ end
118
+
105
119
  def test_links
106
120
  # basic
107
121
  assert_plaintext 'Link ( http://example.com/ )', '<a href="http://example.com/">Link</a>'
@@ -134,6 +148,9 @@ END_HTML
134
148
 
135
149
  # unsubscribe
136
150
  assert_plaintext 'Link ( [[!unsubscribe]] )', '<a href="[[!unsubscribe]]">Link</a>'
151
+
152
+ # empty link gets dropped, and shouldn't run forever
153
+ 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}")
137
154
  end
138
155
 
139
156
  # see https://github.com/alexdunae/premailer/issues/72
@@ -115,10 +115,10 @@ END_HTML
115
115
 
116
116
  premailer = Premailer.new(html, :with_html_string => true, :preserve_styles => false, :adapter => adapter)
117
117
  premailer.to_inline_css
118
- assert_nil premailer.processed_doc.at('head link')
118
+ assert_nil premailer.processed_doc.at('body link')
119
119
 
120
120
  # should be preserved as unmergeable
121
- assert_match /red !important/i, premailer.processed_doc.at('body style').inner_html
121
+ assert_match /red !important/i, premailer.processed_doc.at('head style').inner_html
122
122
  end
123
123
  end
124
124
 
@@ -131,7 +131,7 @@ END_HTML
131
131
 
132
132
  premailer = Premailer.new(html, :with_html_string => true, :verbose => true)
133
133
  premailer.to_inline_css
134
- assert_match /a\:hover[\s]*\{[\s]*color\:[\s]*red[\s]*!important;[\s]*\}/i, premailer.processed_doc.at('body style').inner_html
134
+ assert_match /a\:hover[\s]*\{[\s]*color\:[\s]*red[\s]*!important;[\s]*\}/i, premailer.processed_doc.at('head style').inner_html
135
135
  end
136
136
 
137
137
  def test_unmergable_rules_with_no_body
@@ -1,4 +1,5 @@
1
- # encoding: UTF-8
1
+ # -*- encoding: UTF-8 -*-
2
+
2
3
  require File.expand_path(File.dirname(__FILE__)) + '/helper'
3
4
 
4
5
  class TestPremailer < Premailer::TestCase
@@ -234,7 +235,7 @@ END_HTML
234
235
  end
235
236
 
236
237
  def test_input_encoding
237
- html_special_characters = "Ää, Öö, Üü".encode("UTF-8")
238
+ html_special_characters = "Ää, Öö, Üü"
238
239
  expected_html = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html><body><p>" + html_special_characters + "</p></body></html>\n"
239
240
  pm = Premailer.new(html_special_characters, :with_html_string => true, :adapter => :nokogiri, :input_encoding => "UTF-8")
240
241
  assert_equal expected_html, pm.to_inline_css
@@ -242,14 +243,14 @@ END_HTML
242
243
 
243
244
  def test_meta_encoding_downcase
244
245
  meta_encoding = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
245
- expected_html = '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'
246
+ expected_html = Regexp.new(Regexp.escape('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'), Regexp::IGNORECASE)
246
247
  pm = Premailer.new(meta_encoding, :with_html_string => true, :adapter => :nokogiri, :input_encoding => "utf-8")
247
248
  assert_match expected_html, pm.to_inline_css
248
249
  end
249
250
 
250
251
  def test_meta_encoding_upcase
251
252
  meta_encoding = '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'
252
- expected_html = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
253
+ expected_html = Regexp.new(Regexp.escape('<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'), Regexp::IGNORECASE)
253
254
  pm = Premailer.new(meta_encoding, :with_html_string => true, :adapter => :nokogiri, :input_encoding => "UTF-8")
254
255
  assert_match expected_html, pm.to_inline_css
255
256
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: regru-premailer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.7
4
+ version: 1.7.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-29 00:00:00.000000000 Z
12
+ date: 2013-10-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: css_parser
@@ -44,29 +44,51 @@ dependencies:
44
44
  - !ruby/object:Gem::Version
45
45
  version: 4.0.0
46
46
  - !ruby/object:Gem::Dependency
47
- name: hpricot
47
+ name: bundler
48
48
  requirement: !ruby/object:Gem::Requirement
49
49
  none: false
50
50
  requirements:
51
- - - ! '>='
51
+ - - ~>
52
52
  - !ruby/object:Gem::Version
53
- version: 0.8.3
53
+ version: '1.3'
54
54
  type: :development
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  none: false
58
58
  requirements:
59
- - - ! '>='
59
+ - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: 0.8.3
61
+ version: '1.3'
62
62
  - !ruby/object:Gem::Dependency
63
- name: nokogiri
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '0.8'
70
+ - - ! '!='
71
+ - !ruby/object:Gem::Version
72
+ version: 0.9.0
73
+ type: :development
74
+ prerelease: false
75
+ version_requirements: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ~>
79
+ - !ruby/object:Gem::Version
80
+ version: '0.8'
81
+ - - ! '!='
82
+ - !ruby/object:Gem::Version
83
+ version: 0.9.0
84
+ - !ruby/object:Gem::Dependency
85
+ name: hpricot
64
86
  requirement: !ruby/object:Gem::Requirement
65
87
  none: false
66
88
  requirements:
67
89
  - - ! '>='
68
90
  - !ruby/object:Gem::Version
69
- version: 1.4.4
91
+ version: 0.8.3
70
92
  type: :development
71
93
  prerelease: false
72
94
  version_requirements: !ruby/object:Gem::Requirement
@@ -74,29 +96,23 @@ dependencies:
74
96
  requirements:
75
97
  - - ! '>='
76
98
  - !ruby/object:Gem::Version
77
- version: 1.4.4
99
+ version: 0.8.3
78
100
  - !ruby/object:Gem::Dependency
79
- name: rake
101
+ name: nokogiri
80
102
  requirement: !ruby/object:Gem::Requirement
81
103
  none: false
82
104
  requirements:
83
- - - ~>
84
- - !ruby/object:Gem::Version
85
- version: '0.8'
86
- - - ! '!='
105
+ - - ! '>='
87
106
  - !ruby/object:Gem::Version
88
- version: 0.9.0
107
+ version: 1.4.4
89
108
  type: :development
90
109
  prerelease: false
91
110
  version_requirements: !ruby/object:Gem::Requirement
92
111
  none: false
93
112
  requirements:
94
- - - ~>
95
- - !ruby/object:Gem::Version
96
- version: '0.8'
97
- - - ! '!='
113
+ - - ! '>='
98
114
  - !ruby/object:Gem::Version
99
- version: 0.9.0
115
+ version: 1.4.4
100
116
  - !ruby/object:Gem::Dependency
101
117
  name: yard
102
118
  requirement: !ruby/object:Gem::Requirement
@@ -138,6 +154,7 @@ extensions: []
138
154
  extra_rdoc_files: []
139
155
  files:
140
156
  - .gitignore
157
+ - .jrubyrc
141
158
  - .travis.yml
142
159
  - .yardopts
143
160
  - Gemfile
@@ -193,12 +210,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
193
210
  - - ! '>='
194
211
  - !ruby/object:Gem::Version
195
212
  version: '0'
213
+ segments:
214
+ - 0
215
+ hash: -4588317262745199697
196
216
  required_rubygems_version: !ruby/object:Gem::Requirement
197
217
  none: false
198
218
  requirements:
199
219
  - - ! '>='
200
220
  - !ruby/object:Gem::Version
201
221
  version: '0'
222
+ segments:
223
+ - 0
224
+ hash: -4588317262745199697
202
225
  requirements: []
203
226
  rubyforge_project:
204
227
  rubygems_version: 1.8.24
@@ -230,3 +253,4 @@ test_files:
230
253
  - test/test_misc.rb
231
254
  - test/test_premailer.rb
232
255
  - test/test_warnings.rb
256
+ has_rdoc: true