premailer-rails3 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - jruby-18mode # JRuby in 1.8 mode
5
+ - jruby-19mode # JRuby in 1.9 mode
6
+ - rbx-18mode
7
+ - rbx-19mode
8
+ - 1.8.7
data/README.md CHANGED
@@ -1,4 +1,6 @@
1
- # Premailer Rails 3 README
1
+ # premailer-rails3
2
+
3
+ [![Build Status](https://secure.travis-ci.org/fphilipe/premailer-rails3.png?branch=master)](http://travis-ci.org/fphilipe/premailer-rails3) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/fphilipe/premailer-rails3)
2
4
 
3
5
  This gem is a no config solution for the wonderful
4
6
  [Premailer gem](https://github.com/alexdunae/premailer) to be used with Rails 3.
@@ -14,14 +16,16 @@ By default it inlines all the CSS files that are linked to in the HTML:
14
16
 
15
17
  Don't worry about the host in the CSS URL since this will be ignored.
16
18
 
17
- If no CSS file is linked to in the HTML it will try to load a default CSS file
18
- `email.css`.
19
+ If no CSS file is linked to in the HTML and no inline `<style type="text/css">`
20
+ is presnet, it will try to load a default CSS file `email.css`.
19
21
 
20
22
  Every CSS file (including the default `email.css`) is loaded from within the
21
23
  app. The retrieval of the file depends on your assets configuration:
22
24
 
23
25
  * Rails 3.1 asset pipeline: It will load the compiled version of the CSS asset
24
- which is normally located in `app/assets/stylesheets/`.
26
+ which is normally located in `app/assets/stylesheets/`. If the asset can't be
27
+ found (e.g. it is only available on a CDN and not locally), it will be
28
+ HTTP requested.
25
29
 
26
30
  * Classic static assets: It will try to load the CSS file located in
27
31
  `public/stylesheets/`
@@ -54,8 +58,8 @@ pass these options on to the underlying premailer instance, specify them in an
54
58
  initializer:
55
59
 
56
60
  ```ruby
57
- PremailerRails.config.merge(:preserve_styles => true,
58
- :remove_ids => true)
61
+ PremailerRails.config.merge!(:preserve_styles => true,
62
+ :remove_ids => true)
59
63
  ```
60
64
 
61
65
  For a list of options, refer to the [Premailer documentation](http://rubydoc.info/gems/premailer/1.7.3/Premailer:initialize)
@@ -65,10 +69,16 @@ The default configs are:
65
69
  ```ruby
66
70
  {
67
71
  :input_encoding => 'UTF-8',
72
+ :inputencoding => 'UTF-8',
68
73
  :generate_text_part => true
69
74
  }
70
75
  ```
71
76
 
77
+ The input encoding option [changed](https://github.com/alexdunae/premailer/commit/5f5cbb4ac181299a7e73d3eca11f3cf546585364)
78
+ at some point. To make sure this option works regardless of the premailer
79
+ version, the old and new setting is specified. If you want to use another
80
+ encoding make sure to specify the right one or both.
81
+
72
82
  If you don't want to generate a text part from the html part, set the config
73
83
  `:generate_text_part` to false.
74
84
 
@@ -1,4 +1,5 @@
1
1
  require 'premailer'
2
+ require 'premailer-rails3/css_loaders'
2
3
  require 'premailer-rails3/css_helper'
3
4
  require 'premailer-rails3/premailer'
4
5
  require 'premailer-rails3/hook'
@@ -6,6 +7,7 @@ require 'premailer-rails3/hook'
6
7
  module PremailerRails
7
8
  @config = {
8
9
  :input_encoding => 'UTF-8',
10
+ :inputencoding => 'UTF-8',
9
11
  :generate_text_part => true
10
12
  }
11
13
  class << self
@@ -5,74 +5,56 @@ module PremailerRails
5
5
  module CSSHelper
6
6
  extend self
7
7
 
8
- @@css_cache = {}
8
+ @cache = {}
9
+ attr :cache
9
10
 
11
+ STRATEGIES = [
12
+ CSSLoaders::CacheLoader,
13
+ CSSLoaders::HassleLoader,
14
+ CSSLoaders::AssetPipelineLoader,
15
+ CSSLoaders::FileSystemLoader
16
+ ]
17
+
18
+ # Returns all linked CSS files concatenated as string.
10
19
  def css_for_doc(doc)
11
- css = doc.search('link[@type="text/css"]').map { |link|
12
- url = link.attributes['href'].to_s
13
- load_css_at_path(url) unless url.blank?
14
- }.reject(&:blank?).join("\n")
15
- css = load_css_at_path(:default) if css.blank?
16
- css
20
+ urls = css_urls_in_doc(doc)
21
+ if urls.empty?
22
+ load_css(:default) unless has_inline_css? doc
23
+ else
24
+ urls.map { |url| load_css(url) }.join("\n")
25
+ end
17
26
  end
18
27
 
19
28
  private
20
29
 
21
- def load_css_at_path(path)
22
- if path.is_a? String
23
- # Remove everything after ? including ?
24
- path = path[0..(path.index('?') - 1)] if path.include? '?'
25
- # Remove the host
26
- path = path.sub(/^https?\:\/\/[^\/]*/, '') if path.index('http') == 0
27
- end
28
-
29
- # Don't cache in development.
30
- if Rails.env.development? or not @@css_cache.include? path
31
- @@css_cache[path] =
32
- if defined? Hassle and Rails.configuration.middleware.include? Hassle
33
- file = path == :default ? '/stylesheets/email.css' : path
34
- File.read("#{Rails.root}/tmp/hassle#{file}")
35
- elsif assets_enabled?
36
- file = if path == :default
37
- 'email.css'
38
- else
39
- path.sub("#{Rails.configuration.assets.prefix}/", '') \
40
- .sub(/-.*\.css$/, '.css')
41
- end
42
- if asset = Rails.application.assets.find_asset(file)
43
- asset.to_s
44
- else
45
- request_and_unzip(file)
46
- end
47
- else
48
- file = path == :default ? '/stylesheets/email.css' : path
49
- File.read("#{Rails.root}/public#{file}")
50
- end
30
+ def css_urls_in_doc(doc)
31
+ doc.search('link[@type="text/css"]').map do |link|
32
+ link.attributes['href'].to_s
51
33
  end
34
+ end
52
35
 
53
- @@css_cache[path]
54
- rescue NoMethodError => ex
55
- # Log an error and return empty css:
56
- Rails.logger.try(:warn, ex.message)
57
- ''
36
+ def has_inline_css?(doc)
37
+ not doc.search('style[@type="text/css"]').empty?
58
38
  end
59
39
 
60
- def assets_enabled?
61
- Rails.configuration.assets.enabled rescue false
40
+ def load_css(url)
41
+ path = extract_path(url)
42
+
43
+ @cache[path] = STRATEGIES.each do |strategy|
44
+ css = strategy.load(path)
45
+ break css if css
46
+ end
62
47
  end
63
48
 
64
- def request_and_unzip(file)
65
- url = [
66
- Rails.configuration.action_controller.asset_host,
67
- Rails.configuration.assets.prefix.sub(/^\//, ''),
68
- Rails.configuration.assets.digests[file]
69
- ].join('/')
70
- response = Kernel.open(url)
71
- begin
72
- Zlib::GzipReader.new(response).read
73
- rescue Zlib::GzipFile::Error
74
- response.rewind
75
- response.read
49
+ # Extracts the path of a url.
50
+ def extract_path(url)
51
+ if url.is_a? String
52
+ # Remove everything after ? including ?
53
+ url = url[0..(url.index('?') - 1)] if url.include? '?'
54
+ # Remove the host
55
+ url = url.sub(/^https?\:\/\/[^\/]*/, '') if url.index('http') == 0
56
+ else
57
+ url
76
58
  end
77
59
  end
78
60
  end
@@ -0,0 +1,91 @@
1
+ module PremailerRails
2
+ module CSSLoaders
3
+ # Loads the CSS from cache when not in development env.
4
+ module CacheLoader
5
+ extend self
6
+
7
+ def load(path)
8
+ unless Rails.env.development?
9
+ CSSHelper.cache[path]
10
+ end
11
+ end
12
+ end
13
+
14
+ # Loads the CSS from Hassle middleware if present.
15
+ module HassleLoader
16
+ extend self
17
+
18
+ def load(path)
19
+ if hassle_enabled?
20
+ File.read("#{Rails.root}/tmp/hassle#{normalized_path(path)}")
21
+ end
22
+ end
23
+
24
+ def hassle_enabled?
25
+ Rails.configuration.middleware.include? Hassle rescue false
26
+ end
27
+
28
+ def normalized_path(path)
29
+ path == :default ? '/stylesheets/email.css' : path
30
+ end
31
+ end
32
+
33
+ # Loads the CSS from the asset pipeline.
34
+ module AssetPipelineLoader
35
+ extend self
36
+
37
+ def load(path)
38
+ if assets_enabled?
39
+ file = file_name(path)
40
+ if asset = Rails.application.assets.find_asset(file)
41
+ asset.to_s
42
+ else
43
+ request_and_unzip(file)
44
+ end
45
+ end
46
+ end
47
+
48
+ def assets_enabled?
49
+ Rails.configuration.assets.enabled rescue false
50
+ end
51
+
52
+ def file_name(path)
53
+ if path == :default
54
+ 'email.css'
55
+ else
56
+ path.sub("#{Rails.configuration.assets.prefix}/", '') \
57
+ .sub(/-.*\.css$/, '.css')
58
+ end
59
+ end
60
+
61
+ def request_and_unzip(file)
62
+ url = [
63
+ Rails.configuration.action_controller.asset_host,
64
+ Rails.configuration.assets.prefix.sub(/^\//, ''),
65
+ Rails.configuration.assets.digests[file]
66
+ ].join('/')
67
+ response = Kernel.open(url)
68
+
69
+ begin
70
+ Zlib::GzipReader.new(response).read
71
+ rescue Zlib::GzipFile::Error, Zlib::Error
72
+ response.rewind
73
+ response.read
74
+ end
75
+ end
76
+ end
77
+
78
+ # Loads the CSS from the file system.
79
+ module FileSystemLoader
80
+ extend self
81
+
82
+ def load(path)
83
+ File.read("#{Rails.root}/public#{normalized_path(path)}")
84
+ end
85
+
86
+ def normalized_path(path)
87
+ path == :default ? '/stylesheets/email.css' : path
88
+ end
89
+ end
90
+ end
91
+ end
@@ -1,3 +1,3 @@
1
1
  module PremailerRails
2
- VERSION = "1.2.0"
2
+ VERSION = '1.3.0'
3
3
  end
@@ -28,11 +28,15 @@ module Fixtures
28
28
  links << LINK % "http://example.com/#{file}"
29
29
  end
30
30
 
31
- TEMPLATE % links.join("\n")
31
+ TEMPLATE % links.join
32
32
  end
33
33
 
34
34
  def with_no_css_link
35
35
  with_css_links
36
36
  end
37
+
38
+ def with_style_block
39
+ TEMPLATE % '<style type="text/css">p { color: red; }</style>'
40
+ end
37
41
  end
38
42
  end
@@ -19,6 +19,24 @@ module Fixtures
19
19
  </html>
20
20
  HTML
21
21
 
22
+ HTML_PART_WITH_CSS = <<-HTML
23
+ <html>
24
+ <head>
25
+ <style type="text/css">
26
+ p { color: red; }
27
+ </style>
28
+ </head>
29
+ <body>
30
+ <p>
31
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
32
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
33
+ veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
34
+ commodo consequat.
35
+ </p>
36
+ </body>
37
+ </html>
38
+ HTML
39
+
22
40
  TEXT_PART = <<-TEXT
23
41
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
24
42
  incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
@@ -2,10 +2,10 @@ require 'spec_helper'
2
2
 
3
3
  describe PremailerRails::CSSHelper do
4
4
  # Reset the CSS cache
5
- after { PremailerRails::CSSHelper.send(:class_variable_set, '@@css_cache', {}) }
5
+ after { PremailerRails::CSSHelper.send(:instance_variable_set, '@cache', {}) }
6
6
 
7
- def load_css_at_path(path)
8
- PremailerRails::CSSHelper.send(:load_css_at_path, path)
7
+ def load_css(path)
8
+ PremailerRails::CSSHelper.send(:load_css, path)
9
9
  end
10
10
 
11
11
  def css_for_doc(doc)
@@ -21,11 +21,11 @@ describe PremailerRails::CSSHelper do
21
21
 
22
22
  it 'should return the content of both files concatenated' do
23
23
  PremailerRails::CSSHelper \
24
- .expects(:load_css_at_path) \
24
+ .expects(:load_css) \
25
25
  .with('http://example.com/stylesheets/base.css') \
26
26
  .returns('content of base.css')
27
27
  PremailerRails::CSSHelper \
28
- .expects(:load_css_at_path) \
28
+ .expects(:load_css) \
29
29
  .with('http://example.com/stylesheets/font.css') \
30
30
  .returns('content of font.css')
31
31
 
@@ -33,49 +33,53 @@ describe PremailerRails::CSSHelper do
33
33
  end
34
34
  end
35
35
 
36
- context 'when HTML contains no linked CSS file' do
36
+ context 'when HTML contains style tag' do
37
37
  let(:files) { [] }
38
+ end
39
+
40
+ context 'when HTML contains no linked CSS file' do
41
+ let(:html) { Fixtures::HTML.with_style_block }
38
42
 
39
- it 'should return the content of the default file' do
43
+ it 'should not load the default file' do
40
44
  PremailerRails::CSSHelper \
41
- .expects(:load_css_at_path) \
45
+ .expects(:load_css) \
42
46
  .with(:default) \
43
- .returns('content of default css file')
47
+ .never
44
48
 
45
- css_for_doc(doc).should == 'content of default css file'
49
+ css_for_doc(doc).should be_nil
46
50
  end
47
51
  end
48
52
  end
49
53
 
50
- describe '#load_css_at_path' do
54
+ describe '#load_css' do
51
55
  context 'when path is a url' do
52
56
  it 'should load the CSS at the local path' do
53
57
  File.expects(:read).with('RAILS_ROOT/public/stylesheets/base.css')
54
58
 
55
- load_css_at_path('http://example.com/stylesheets/base.css?test')
59
+ load_css('http://example.com/stylesheets/base.css?test')
56
60
  end
57
61
  end
58
62
 
59
63
  context 'when file is cached' do
60
64
  it 'should return the cached value' do
61
- cache = PremailerRails::CSSHelper.send(:class_variable_get, '@@css_cache')
65
+ cache = PremailerRails::CSSHelper.send(:instance_variable_get, '@cache')
62
66
  cache['/stylesheets/base.css'] = 'content of base.css'
63
67
 
64
- load_css_at_path('http://example.com/stylesheets/base.css') \
68
+ load_css('http://example.com/stylesheets/base.css') \
65
69
  .should == 'content of base.css'
66
70
  end
67
71
  end
68
72
 
69
73
  context 'when in development mode' do
70
74
  it 'should not return cached values' do
71
- cache = PremailerRails::CSSHelper.send(:class_variable_get, '@@css_cache')
75
+ cache = PremailerRails::CSSHelper.send(:instance_variable_get, '@cache')
72
76
  cache['/stylesheets/base.css'] = 'cached content of base.css'
73
77
  File.expects(:read) \
74
78
  .with('RAILS_ROOT/public/stylesheets/base.css') \
75
79
  .returns('new content of base.css')
76
80
  Rails.env.stubs(:development?).returns(true)
77
81
 
78
- load_css_at_path('http://example.com/stylesheets/base.css') \
82
+ load_css('http://example.com/stylesheets/base.css') \
79
83
  .should == 'new content of base.css'
80
84
  end
81
85
  end
@@ -90,7 +94,7 @@ describe PremailerRails::CSSHelper do
90
94
  .with('RAILS_ROOT/tmp/hassle/stylesheets/email.css') \
91
95
  .returns('content of default css')
92
96
 
93
- load_css_at_path(:default).should == 'content of default css'
97
+ load_css(:default).should == 'content of default css'
94
98
  end
95
99
 
96
100
  it 'should return the content of the file compiled by Hassle' do
@@ -98,7 +102,7 @@ describe PremailerRails::CSSHelper do
98
102
  .with('RAILS_ROOT/tmp/hassle/stylesheets/base.css') \
99
103
  .returns('content of base.css')
100
104
 
101
- load_css_at_path('http://example.com/stylesheets/base.css') \
105
+ load_css('http://example.com/stylesheets/base.css') \
102
106
  .should == 'content of base.css'
103
107
  end
104
108
  end
@@ -118,7 +122,7 @@ describe PremailerRails::CSSHelper do
118
122
  .with('email.css') \
119
123
  .returns(mock(:to_s => 'content of default css'))
120
124
 
121
- load_css_at_path(:default).should == 'content of default css'
125
+ load_css(:default).should == 'content of default css'
122
126
  end
123
127
 
124
128
  it 'should return the content of the file compiled by Rails' do
@@ -126,7 +130,7 @@ describe PremailerRails::CSSHelper do
126
130
  .with('base.css') \
127
131
  .returns(mock(:to_s => 'content of base.css'))
128
132
 
129
- load_css_at_path('http://example.com/assets/base.css') \
133
+ load_css('http://example.com/assets/base.css') \
130
134
  .should == 'content of base.css'
131
135
  end
132
136
 
@@ -136,7 +140,7 @@ describe PremailerRails::CSSHelper do
136
140
  .with('base.css') \
137
141
  .returns(mock(:to_s => 'content of base.css'))
138
142
 
139
- load_css_at_path(
143
+ load_css(
140
144
  'http://example.com/assets/base-089e35bd5d84297b8d31ad552e433275.css'
141
145
  ).should == 'content of base.css'
142
146
  end
@@ -165,7 +169,7 @@ describe PremailerRails::CSSHelper do
165
169
  it 'should request the file' do
166
170
  Kernel.expects(:open).with(url).returns(string_io)
167
171
 
168
- load_css_at_path(
172
+ load_css(
169
173
  'http://example.com/assets/base.css'
170
174
  ).should == 'content of base.css'
171
175
  end
@@ -173,7 +177,7 @@ describe PremailerRails::CSSHelper do
173
177
  it 'should request the same file when path contains file fingerprint' do
174
178
  Kernel.expects(:open).with(url).returns(string_io)
175
179
 
176
- load_css_at_path(
180
+ load_css(
177
181
  'http://example.com/assets/base-089e35bd5d84297b8d31ad552e433275.css'
178
182
  ).should == 'content of base.css'
179
183
  end
@@ -186,7 +190,7 @@ describe PremailerRails::CSSHelper do
186
190
  .with('RAILS_ROOT/public/stylesheets/email.css') \
187
191
  .returns('content of default css')
188
192
 
189
- load_css_at_path(:default).should == 'content of default css'
193
+ load_css(:default).should == 'content of default css'
190
194
  end
191
195
 
192
196
  it 'should return the content of the static file' do
@@ -194,7 +198,7 @@ describe PremailerRails::CSSHelper do
194
198
  .with('RAILS_ROOT/public/stylesheets/base.css') \
195
199
  .returns('content of base.css')
196
200
 
197
- load_css_at_path('http://example.com/stylesheets/base.css') \
201
+ load_css('http://example.com/stylesheets/base.css') \
198
202
  .should == 'content of base.css'
199
203
  end
200
204
  end
@@ -16,11 +16,21 @@ describe PremailerRails::Premailer do
16
16
  end
17
17
 
18
18
  describe '#to_inline_css' do
19
- it 'should return the HTML with the CSS inlined' do
20
- PremailerRails::CSSHelper.stubs(:css_for_doc).returns('p { color: red; }')
21
- html = Fixtures::Message::HTML_PART
22
- premailer = PremailerRails::Premailer.new(html)
23
- premailer.to_inline_css.should include '<p style="color: red;">'
19
+ context 'when inline CSS block present' do
20
+ it 'should return the HTML with the CSS inlined' do
21
+ PremailerRails::CSSHelper.stubs(:css_for_doc).returns('p { color: red; }')
22
+ html = Fixtures::Message::HTML_PART
23
+ premailer = PremailerRails::Premailer.new(html)
24
+ premailer.to_inline_css.should include '<p style="color: red;">'
25
+ end
26
+ end
27
+
28
+ context 'when CSS is loaded externally' do
29
+ it 'should return the HTML with the CSS inlined' do
30
+ html = Fixtures::Message::HTML_PART_WITH_CSS
31
+ premailer = PremailerRails::Premailer.new(html)
32
+ premailer.to_inline_css.should include '<p style="color: red;">'
33
+ end
24
34
  end
25
35
  end
26
36
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: premailer-rails3
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
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: 2012-06-12 00:00:00.000000000 Z
12
+ date: 2012-07-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: premailer
@@ -151,6 +151,7 @@ extra_rdoc_files: []
151
151
  files:
152
152
  - .gitignore
153
153
  - .rspec
154
+ - .travis.yml
154
155
  - CHANGELOG.md
155
156
  - Gemfile
156
157
  - LICENSE
@@ -158,6 +159,7 @@ files:
158
159
  - Rakefile
159
160
  - lib/premailer-rails3.rb
160
161
  - lib/premailer-rails3/css_helper.rb
162
+ - lib/premailer-rails3/css_loaders.rb
161
163
  - lib/premailer-rails3/hook.rb
162
164
  - lib/premailer-rails3/premailer.rb
163
165
  - lib/premailer-rails3/version.rb