premailer-rails3 1.2.0 → 1.3.0

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