premailer-rails 1.9.2 → 1.9.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +17 -0
- data/VERSION +1 -1
- data/lib/premailer/rails/css_helper.rb +5 -1
- data/lib/premailer/rails/css_loaders/asset_pipeline_loader.rb +7 -2
- data/lib/premailer/rails/css_loaders/file_system_loader.rb +1 -1
- data/lib/premailer/rails/css_loaders/network_loader.rb +3 -3
- data/spec/integration/css_helper_spec.rb +146 -137
- data/spec/unit/css_loaders/asset_pipeline_loader_spec.rb +13 -3
- data/spec/unit/css_loaders/network_loader_spec.rb +8 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88c3e4cb9ff7a5d1bcf7437242957d0882d5c783
|
4
|
+
data.tar.gz: b89082332333a80f33437e2f424a3c77cf33ce88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16f4d14dcad194bc945ab41f360b88669428408d21e9035ac8c05b1c91095fb51f6658ec160f0ea3b8a1085acb17d253f45cc319d9862060802e2a6121c8e91a
|
7
|
+
data.tar.gz: a7bd533d813480744b008ac7ba60418588e8c183aaec38c34df993e248ea613b7e3b1744df170180d06a76b589813dc233abf7bafacb72c278b212e0c6d797b3
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## v1.9.3
|
4
|
+
|
5
|
+
- Add support for rails' `relative_url_root` config
|
6
|
+
- Fix link tag removal under Hpricot
|
7
|
+
- Pass url to `asset_host` if it responds to `call`
|
8
|
+
- Fixed issue where urls may conflict with folder names.
|
9
|
+
|
3
10
|
## v1.9.2
|
4
11
|
|
5
12
|
- Update rails dependency to allow rails 5
|
data/README.md
CHANGED
@@ -121,6 +121,11 @@ If you're using this gem outside of Rails, you'll need to call
|
|
121
121
|
is done ideally in some kind of initializer, depending on the framework you're
|
122
122
|
using.
|
123
123
|
|
124
|
+
premailer-rails reads all stylesheet `<link>` tags, inlines the linked CSS
|
125
|
+
and removes the tags. If you wish to ignore a certain tag, e.g. one that links to
|
126
|
+
external fonts such as Google Fonts, you can add a `data-premailer="ignore"`
|
127
|
+
attribute.
|
128
|
+
|
124
129
|
## Usage
|
125
130
|
|
126
131
|
premailer-rails processes all outgoing emails by default. If you wish to skip
|
@@ -141,6 +146,18 @@ even setting `skip_premailer: false` will cause premailer to be skipped. The
|
|
141
146
|
reason for that is that the `skip_premailer` is a simple header and the value is
|
142
147
|
transformed into a string, causing `'false'` to become truthy.
|
143
148
|
|
149
|
+
Emails are only processed upon delivery, i.e. when calling `#deliver` on the
|
150
|
+
email, or when [previewing them in
|
151
|
+
rails](http://api.rubyonrails.org/v4.1.0/classes/ActionMailer/Base.html#class-ActionMailer::Base-label-Previewing+emails).
|
152
|
+
If you wish to manually trigger the inlining, you can do so by calling the hook:
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
mail = SomeMailer.some_message(args)
|
156
|
+
Premailer::Rails::Hook.perform(mail)
|
157
|
+
```
|
158
|
+
|
159
|
+
This will modify the email in place, useful e.g. in tests.
|
160
|
+
|
144
161
|
## Small Print
|
145
162
|
|
146
163
|
### Author
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.9.
|
1
|
+
1.9.3
|
@@ -27,7 +27,11 @@ class Premailer
|
|
27
27
|
|
28
28
|
def css_urls_in_doc(doc)
|
29
29
|
doc.search('link[@rel="stylesheet"]:not([@data-premailer="ignore"])').map do |link|
|
30
|
-
link.remove
|
30
|
+
if link.respond_to?(:remove)
|
31
|
+
link.remove
|
32
|
+
else
|
33
|
+
link.parent.children.delete(link)
|
34
|
+
end
|
31
35
|
link.attributes['href'].to_s
|
32
36
|
end
|
33
37
|
end
|
@@ -19,9 +19,14 @@ class Premailer
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def file_name(url)
|
22
|
+
prefix = [
|
23
|
+
::Rails.configuration.relative_url_root,
|
24
|
+
::Rails.configuration.assets.prefix,
|
25
|
+
'/'
|
26
|
+
].join
|
22
27
|
URI(url).path
|
23
|
-
.sub(
|
24
|
-
.sub(/-(\h{32}|\h{64})\.css
|
28
|
+
.sub(/\A#{prefix}/, '')
|
29
|
+
.sub(/-(\h{32}|\h{64})\.css\z/, '.css')
|
25
30
|
end
|
26
31
|
end
|
27
32
|
end
|
@@ -16,7 +16,7 @@ class Premailer
|
|
16
16
|
return uri if uri.scheme.present?
|
17
17
|
URI("http://#{uri.to_s}")
|
18
18
|
elsif asset_host_present?
|
19
|
-
scheme, host = asset_host.split(%r{:?//})
|
19
|
+
scheme, host = asset_host(url).split(%r{:?//})
|
20
20
|
scheme, host = host, scheme if host.nil?
|
21
21
|
scheme = 'http' if scheme.blank?
|
22
22
|
path = url
|
@@ -28,9 +28,9 @@ class Premailer
|
|
28
28
|
::Rails.configuration.action_controller.asset_host.present?
|
29
29
|
end
|
30
30
|
|
31
|
-
def asset_host
|
31
|
+
def asset_host(url)
|
32
32
|
config = ::Rails.configuration.action_controller.asset_host
|
33
|
-
config.respond_to?(:call) ? config.call : config
|
33
|
+
config.respond_to?(:call) ? config.call(url) : config
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
@@ -1,177 +1,186 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Premailer::Rails::CSSHelper do
|
4
|
-
|
5
|
-
|
6
|
-
Premailer::Rails::CSSLoaders::CacheLoader.clear!
|
7
|
-
end
|
8
|
-
|
9
|
-
def css_for_url(path)
|
10
|
-
Premailer::Rails::CSSHelper.css_for_url(path)
|
11
|
-
end
|
4
|
+
[ :Nokogiri, :Hpricot ].each do |adapter|
|
5
|
+
next if adapter == :Hpricot and RUBY_PLATFORM == 'java'
|
12
6
|
|
13
|
-
|
14
|
-
|
15
|
-
|
7
|
+
context "when adapter is #{adapter}" do
|
8
|
+
# Reset the CSS cache:
|
9
|
+
after do
|
10
|
+
Premailer::Rails::CSSLoaders::CacheLoader.clear!
|
11
|
+
end
|
16
12
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
13
|
+
def css_for_url(path)
|
14
|
+
Premailer::Rails::CSSHelper.css_for_url(path)
|
15
|
+
end
|
21
16
|
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
def css_for_doc(doc)
|
18
|
+
Premailer::Rails::CSSHelper.css_for_doc(doc)
|
19
|
+
end
|
25
20
|
|
26
|
-
|
27
|
-
|
21
|
+
def expect_file(path, content='file content')
|
22
|
+
allow(File).to receive(:file?).with(path).and_return(true)
|
23
|
+
expect(File).to receive(:read).with(path).and_return(content)
|
24
|
+
end
|
28
25
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
.with('http://example.com/stylesheets/base.css')
|
33
|
-
.and_return('content of base.css')
|
34
|
-
allow(Premailer::Rails::CSSHelper).to \
|
35
|
-
receive(:css_for_url)
|
36
|
-
.with('http://example.com/stylesheets/font.css')
|
37
|
-
.and_return('content of font.css')
|
26
|
+
describe '#css_for_doc' do
|
27
|
+
let(:html) { Fixtures::HTML.with_css_links(*files) }
|
28
|
+
let(:doc) { send(adapter, html) }
|
38
29
|
|
39
|
-
|
40
|
-
|
41
|
-
end
|
30
|
+
context 'when HTML contains linked CSS files' do
|
31
|
+
let(:files) { %w[ stylesheets/base.css stylesheets/font.css ] }
|
42
32
|
|
43
|
-
|
44
|
-
|
33
|
+
it 'returns the content of both files concatenated' do
|
34
|
+
allow(Premailer::Rails::CSSHelper).to \
|
35
|
+
receive(:css_for_url)
|
36
|
+
.with('http://example.com/stylesheets/base.css')
|
37
|
+
.and_return('content of base.css')
|
38
|
+
allow(Premailer::Rails::CSSHelper).to \
|
39
|
+
receive(:css_for_url)
|
40
|
+
.with('http://example.com/stylesheets/font.css')
|
41
|
+
.and_return('content of font.css')
|
45
42
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
43
|
+
expect(css_for_doc(doc)).to eq("content of base.css\ncontent of font.css")
|
44
|
+
end
|
45
|
+
end
|
52
46
|
|
53
|
-
|
54
|
-
|
55
|
-
it 'loads the CSS at the local path' do
|
56
|
-
expect_file('public/stylesheets/base.css')
|
47
|
+
context 'when HTML contains ignored links' do
|
48
|
+
let(:files) { ['ignore.css', 'data-premailer' => 'ignore'] }
|
57
49
|
|
58
|
-
|
50
|
+
it 'ignores links' do
|
51
|
+
expect(Premailer::Rails::CSSHelper).to_not receive(:css_for_url)
|
52
|
+
css_for_doc(doc)
|
53
|
+
end
|
54
|
+
end
|
59
55
|
end
|
60
|
-
end
|
61
56
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
67
|
-
end
|
57
|
+
describe '#css_for_url' do
|
58
|
+
context 'when path is a url' do
|
59
|
+
it 'loads the CSS at the local path' do
|
60
|
+
expect_file('public/stylesheets/base.css')
|
68
61
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
'http://example.com/stylesheets/base.css',
|
73
|
-
'content of base.css'
|
74
|
-
)
|
62
|
+
css_for_url('http://example.com/stylesheets/base.css?test')
|
63
|
+
end
|
64
|
+
end
|
75
65
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
66
|
+
context 'when path is a relative url' do
|
67
|
+
it 'loads the CSS at the local path' do
|
68
|
+
expect_file('public/stylesheets/base.css')
|
69
|
+
css_for_url('/stylesheets/base.css?test')
|
70
|
+
end
|
71
|
+
end
|
80
72
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
content = 'new content of base.css'
|
88
|
-
expect_file('public/stylesheets/base.css', content)
|
89
|
-
allow(Rails.env).to receive(:development?).and_return(true)
|
90
|
-
|
91
|
-
expect(css_for_url('http://example.com/stylesheets/base.css')).to eq(content)
|
92
|
-
end
|
93
|
-
end
|
73
|
+
context 'when file is cached' do
|
74
|
+
it 'returns the cached value' do
|
75
|
+
Premailer::Rails::CSSLoaders::CacheLoader.store(
|
76
|
+
'http://example.com/stylesheets/base.css',
|
77
|
+
'content of base.css'
|
78
|
+
)
|
94
79
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
80
|
+
expect(css_for_url('http://example.com/stylesheets/base.css')).to \
|
81
|
+
eq('content of base.css')
|
82
|
+
end
|
83
|
+
end
|
99
84
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
85
|
+
context 'when in development mode' do
|
86
|
+
it 'does not return cached values' do
|
87
|
+
Premailer::Rails::CSSLoaders::CacheLoader.store(
|
88
|
+
'http://example.com/stylesheets/base.css',
|
89
|
+
'cached content of base.css'
|
90
|
+
)
|
91
|
+
content = 'new content of base.css'
|
92
|
+
expect_file('public/stylesheets/base.css', content)
|
93
|
+
allow(Rails.env).to receive(:development?).and_return(true)
|
94
|
+
|
95
|
+
expect(css_for_url('http://example.com/stylesheets/base.css')).to eq(content)
|
96
|
+
end
|
106
97
|
end
|
107
|
-
end
|
108
98
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
99
|
+
context 'when Rails asset pipeline is used' do
|
100
|
+
before do
|
101
|
+
allow(Rails.configuration)
|
102
|
+
.to receive(:assets).and_return(double(prefix: '/assets'))
|
103
|
+
allow(Rails.configuration)
|
104
|
+
.to receive(:relative_url_root).and_return(nil)
|
105
|
+
end
|
114
106
|
|
115
|
-
|
116
|
-
|
117
|
-
|
107
|
+
context 'and a precompiled file exists' do
|
108
|
+
it 'returns that file' do
|
109
|
+
path = '/assets/email-digest.css'
|
110
|
+
content = 'read from file'
|
111
|
+
expect_file("public#{path}", content)
|
112
|
+
expect(css_for_url(path)).to eq(content)
|
113
|
+
end
|
114
|
+
end
|
118
115
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
116
|
+
it 'returns the content of the file compiled by Rails' do
|
117
|
+
expect(Rails.application.assets).to \
|
118
|
+
receive(:find_asset)
|
119
|
+
.with('base.css')
|
120
|
+
.and_return(double(to_s: 'content of base.css'))
|
124
121
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
end
|
122
|
+
expect(css_for_url('http://example.com/assets/base.css')).to \
|
123
|
+
eq('content of base.css')
|
124
|
+
end
|
129
125
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
126
|
+
it 'returns same file when path contains file fingerprint' do
|
127
|
+
expect(Rails.application.assets).to \
|
128
|
+
receive(:find_asset)
|
129
|
+
.with('base.css')
|
130
|
+
.and_return(double(to_s: 'content of base.css'))
|
135
131
|
|
136
|
-
|
137
|
-
|
138
|
-
|
132
|
+
expect(css_for_url(
|
133
|
+
'http://example.com/assets/base-089e35bd5d84297b8d31ad552e433275.css'
|
134
|
+
)).to eq('content of base.css')
|
135
|
+
end
|
139
136
|
|
140
|
-
|
141
|
-
|
142
|
-
|
137
|
+
context 'when asset can not be found' do
|
138
|
+
let(:response) { 'content of base.css' }
|
139
|
+
let(:path) { '/assets/base-089e35bd5d84297b8d31ad552e433275.css' }
|
140
|
+
let(:url) { "http://assets.example.com#{path}" }
|
141
|
+
let(:asset_host) { 'http://assets.example.com' }
|
143
142
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
end
|
143
|
+
before do
|
144
|
+
allow(Rails.application.assets).to \
|
145
|
+
receive(:find_asset).and_return(nil)
|
148
146
|
|
149
|
-
|
150
|
-
|
151
|
-
|
147
|
+
config = double(asset_host: asset_host)
|
148
|
+
allow(Rails.configuration).to \
|
149
|
+
receive(:action_controller).and_return(config)
|
152
150
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
151
|
+
uri_satisfaction = satisfy { |uri| uri.to_s == url }
|
152
|
+
allow(Net::HTTP).to \
|
153
|
+
receive(:get).with(uri_satisfaction).and_return(response)
|
154
|
+
end
|
157
155
|
|
158
|
-
|
159
|
-
|
156
|
+
it 'requests the file' do
|
157
|
+
expect(css_for_url(url)).to eq('content of base.css')
|
158
|
+
end
|
160
159
|
|
161
|
-
|
162
|
-
|
160
|
+
context 'when file url does not include the host' do
|
161
|
+
it 'requests the file using the asset host as host' do
|
162
|
+
expect(css_for_url(path)).to eq('content of base.css')
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'and the asset host uses protocol relative scheme' do
|
166
|
+
let(:asset_host) { '//assets.example.com' }
|
167
|
+
|
168
|
+
it 'requests the file using http as the scheme' do
|
169
|
+
expect(css_for_url(path)).to eq('content of base.css')
|
170
|
+
end
|
171
|
+
end
|
163
172
|
end
|
164
173
|
end
|
165
174
|
end
|
166
|
-
end
|
167
|
-
end
|
168
175
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
176
|
+
context 'when static stylesheets are used' do
|
177
|
+
it 'returns the content of the static file' do
|
178
|
+
content = 'content of base.css'
|
179
|
+
expect_file('public/stylesheets/base.css', content)
|
180
|
+
loaded_content = css_for_url('http://example.com/stylesheets/base.css')
|
181
|
+
expect(loaded_content).to eq(content)
|
182
|
+
end
|
183
|
+
end
|
175
184
|
end
|
176
185
|
end
|
177
186
|
end
|
@@ -2,9 +2,9 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Premailer::Rails::CSSLoaders::AssetPipelineLoader do
|
4
4
|
before do
|
5
|
-
|
6
|
-
|
7
|
-
allow(Rails).to receive(:
|
5
|
+
allow(Rails.configuration)
|
6
|
+
.to receive(:assets).and_return(double(prefix: '/assets'))
|
7
|
+
allow(Rails.configuration).to receive(:relative_url_root).and_return(nil)
|
8
8
|
end
|
9
9
|
|
10
10
|
describe ".file_name" do
|
@@ -17,6 +17,16 @@ describe Premailer::Rails::CSSLoaders::AssetPipelineLoader do
|
|
17
17
|
it { is_expected.to eq('application.css') }
|
18
18
|
end
|
19
19
|
|
20
|
+
context "when asset file path contains prefix and relative_url_root is set" do
|
21
|
+
before do
|
22
|
+
allow(Rails.configuration)
|
23
|
+
.to receive(:relative_url_root).and_return('/foo')
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:asset) { '/foo/assets/application.css' }
|
27
|
+
it { is_expected.to eq('application.css') }
|
28
|
+
end
|
29
|
+
|
20
30
|
context "when asset file path contains 32 chars fingerprint" do
|
21
31
|
let(:asset) { 'application-6776f581a4329e299531e1d52aa59832.css' }
|
22
32
|
it { is_expected.to eq('application.css') }
|
@@ -39,9 +39,14 @@ describe Premailer::Rails::CSSLoaders::NetworkLoader do
|
|
39
39
|
it { is_expected.to eq(URI("http://example.com/assets/foo.css")) }
|
40
40
|
end
|
41
41
|
|
42
|
-
context 'and a
|
43
|
-
let(:asset_host) {
|
44
|
-
|
42
|
+
context 'and a callable object as asset host' do
|
43
|
+
let(:asset_host) { double }
|
44
|
+
|
45
|
+
it 'calls #call with the asset path as argument' do
|
46
|
+
expect(asset_host).to receive(:call).with(url).and_return(
|
47
|
+
'http://example.com')
|
48
|
+
expect(subject).to eq(URI('http://example.com/assets/foo.css'))
|
49
|
+
end
|
45
50
|
end
|
46
51
|
|
47
52
|
context 'without an asset host' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: premailer-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.9.
|
4
|
+
version: 1.9.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Philipe Fatio
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: premailer
|