premailer-rails 1.9.2 → 1.9.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0bcfc086df0af15eaab84de807f48b52d0210d40
4
- data.tar.gz: 4379b96a4be95002b4cafcb094b7db201ccde437
3
+ metadata.gz: 88c3e4cb9ff7a5d1bcf7437242957d0882d5c783
4
+ data.tar.gz: b89082332333a80f33437e2f424a3c77cf33ce88
5
5
  SHA512:
6
- metadata.gz: 8767537172dd6c4d2b7601949524b039151de25a3a585efea14874b03de820e00e2618f07defdea841330cf2fb7254cd08a5331fd0c9f16edbdd4e8a5401ea61
7
- data.tar.gz: 069b054a1127bc31a6eec936b7e6311256b7b95c6b464644cfb14ef9819710e8ffce73b36965f6e2fcacdabe194cedb3c83d3af3a7dcf327d4cd05b1cfae3ecf
6
+ metadata.gz: 16f4d14dcad194bc945ab41f360b88669428408d21e9035ac8c05b1c91095fb51f6658ec160f0ea3b8a1085acb17d253f45cc319d9862060802e2a6121c8e91a
7
+ data.tar.gz: a7bd533d813480744b008ac7ba60418588e8c183aaec38c34df993e248ea613b7e3b1744df170180d06a76b589813dc233abf7bafacb72c278b212e0c6d797b3
@@ -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.2
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("#{::Rails.configuration.assets.prefix}/", '')
24
- .sub(/-(\h{32}|\h{64})\.css$/, '.css')
28
+ .sub(/\A#{prefix}/, '')
29
+ .sub(/-(\h{32}|\h{64})\.css\z/, '.css')
25
30
  end
26
31
  end
27
32
  end
@@ -7,7 +7,7 @@ class Premailer
7
7
  def load(url)
8
8
  path = URI(url).path
9
9
  file_path = "public#{path}"
10
- File.read(file_path) if File.exist?(file_path)
10
+ File.read(file_path) if File.file?(file_path)
11
11
  end
12
12
  end
13
13
  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
- # Reset the CSS cache:
5
- after do
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
- def css_for_doc(doc)
14
- Premailer::Rails::CSSHelper.css_for_doc(doc)
15
- end
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
- def expect_file(path, content='file content')
18
- allow(File).to receive(:exist?).with(path).and_return(true)
19
- expect(File).to receive(:read).with(path).and_return(content)
20
- end
13
+ def css_for_url(path)
14
+ Premailer::Rails::CSSHelper.css_for_url(path)
15
+ end
21
16
 
22
- describe '#css_for_doc' do
23
- let(:html) { Fixtures::HTML.with_css_links(*files) }
24
- let(:doc) { Nokogiri(html) }
17
+ def css_for_doc(doc)
18
+ Premailer::Rails::CSSHelper.css_for_doc(doc)
19
+ end
25
20
 
26
- context 'when HTML contains linked CSS files' do
27
- let(:files) { %w[ stylesheets/base.css stylesheets/font.css ] }
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
- it 'returns the content of both files concatenated' do
30
- allow(Premailer::Rails::CSSHelper).to \
31
- receive(:css_for_url)
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
- expect(css_for_doc(doc)).to eq("content of base.css\ncontent of font.css")
40
- end
41
- end
30
+ context 'when HTML contains linked CSS files' do
31
+ let(:files) { %w[ stylesheets/base.css stylesheets/font.css ] }
42
32
 
43
- context 'when HTML contains ignored links' do
44
- let(:files) { ['ignore.css', 'data-premailer' => 'ignore'] }
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
- it 'ignores links' do
47
- expect(Premailer::Rails::CSSHelper).to_not receive(:css_for_url)
48
- css_for_doc(doc)
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
- describe '#css_for_url' do
54
- context 'when path is a url' do
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
- css_for_url('http://example.com/stylesheets/base.css?test')
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
- context 'when path is a relative url' do
63
- it 'loads the CSS at the local path' do
64
- expect_file('public/stylesheets/base.css')
65
- css_for_url('/stylesheets/base.css?test')
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
- context 'when file is cached' do
70
- it 'returns the cached value' do
71
- Premailer::Rails::CSSLoaders::CacheLoader.store(
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
- expect(css_for_url('http://example.com/stylesheets/base.css')).to \
77
- eq('content of base.css')
78
- end
79
- end
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
- context 'when in development mode' do
82
- it 'does not return cached values' do
83
- Premailer::Rails::CSSLoaders::CacheLoader.store(
84
- 'http://example.com/stylesheets/base.css',
85
- 'cached content of base.css'
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
- context 'when Rails asset pipeline is used' do
96
- before do
97
- allow(Rails.configuration).to receive(:assets).and_return(double(prefix: '/assets'))
98
- end
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
- context 'and a precompiled file exists' do
101
- it 'returns that file' do
102
- path = '/assets/email-digest.css'
103
- content = 'read from file'
104
- expect_file("public#{path}", content)
105
- expect(css_for_url(path)).to eq(content)
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
- it 'returns the content of the file compiled by Rails' do
110
- expect(Rails.application.assets).to \
111
- receive(:find_asset)
112
- .with('base.css')
113
- .and_return(double(to_s: 'content of base.css'))
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
- expect(css_for_url('http://example.com/assets/base.css')).to \
116
- eq('content of base.css')
117
- end
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
- it 'returns same file when path contains file fingerprint' do
120
- expect(Rails.application.assets).to \
121
- receive(:find_asset)
122
- .with('base.css')
123
- .and_return(double(to_s: 'content of base.css'))
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
- expect(css_for_url(
126
- 'http://example.com/assets/base-089e35bd5d84297b8d31ad552e433275.css'
127
- )).to eq('content of base.css')
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
- context 'when asset can not be found' do
131
- let(:response) { 'content of base.css' }
132
- let(:path) { '/assets/base-089e35bd5d84297b8d31ad552e433275.css' }
133
- let(:url) { "http://assets.example.com#{path}" }
134
- let(:asset_host) { 'http://assets.example.com' }
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
- before do
137
- allow(Rails.application.assets).to \
138
- receive(:find_asset).and_return(nil)
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
- config = double(asset_host: asset_host)
141
- allow(Rails.configuration).to \
142
- receive(:action_controller).and_return(config)
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
- uri_satisfaction = satisfy { |uri| uri.to_s == url }
145
- allow(Net::HTTP).to \
146
- receive(:get).with(uri_satisfaction).and_return(response)
147
- end
143
+ before do
144
+ allow(Rails.application.assets).to \
145
+ receive(:find_asset).and_return(nil)
148
146
 
149
- it 'requests the file' do
150
- expect(css_for_url(url)).to eq('content of base.css')
151
- end
147
+ config = double(asset_host: asset_host)
148
+ allow(Rails.configuration).to \
149
+ receive(:action_controller).and_return(config)
152
150
 
153
- context 'when file url does not include the host' do
154
- it 'requests the file using the asset host as host' do
155
- expect(css_for_url(path)).to eq('content of base.css')
156
- end
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
- context 'and the asset host uses protocol relative scheme' do
159
- let(:asset_host) { '//assets.example.com' }
156
+ it 'requests the file' do
157
+ expect(css_for_url(url)).to eq('content of base.css')
158
+ end
160
159
 
161
- it 'requests the file using http as the scheme' do
162
- expect(css_for_url(path)).to eq('content of base.css')
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
- context 'when static stylesheets are used' do
170
- it 'returns the content of the static file' do
171
- content = 'content of base.css'
172
- expect_file('public/stylesheets/base.css', content)
173
- loaded_content = css_for_url('http://example.com/stylesheets/base.css')
174
- expect(loaded_content).to eq(content)
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
- assets = double(prefix: '/assets')
6
- config = double(assets: assets)
7
- allow(Rails).to receive(:configuration).and_return(config)
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 proc as asset host' do
43
- let(:asset_host) { ->{ 'example.com' } }
44
- it { is_expected.to eq(URI("http://example.com/assets/foo.css")) }
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.2
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-04-10 00:00:00.000000000 Z
11
+ date: 2016-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: premailer