regru-premailer 1.7.7 → 1.7.8

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