premailer-rails 1.9.7 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +4 -0
  3. data/CHANGELOG.md +6 -0
  4. data/Gemfile +8 -4
  5. data/README.md +20 -28
  6. data/VERSION +1 -1
  7. data/lib/premailer/rails.rb +2 -1
  8. data/lib/premailer/rails/css_helper.rb +29 -10
  9. data/lib/premailer/rails/css_loaders.rb +0 -1
  10. data/lib/premailer/rails/css_loaders/asset_pipeline_loader.rb +8 -11
  11. data/lib/premailer/rails/css_loaders/network_loader.rb +1 -1
  12. data/lib/premailer/rails/customized_premailer.rb +4 -4
  13. data/premailer-rails.gemspec +0 -1
  14. data/spec/integration/css_helper_spec.rb +155 -141
  15. data/spec/integration/delivery_spec.rb +13 -0
  16. data/spec/integration/hook_spec.rb +1 -1
  17. data/spec/rails_app/app/assets/config/manifest.js +3 -0
  18. data/spec/rails_app/app/assets/stylesheets/application.css +3 -0
  19. data/spec/rails_app/app/mailers/application_mailer.rb +4 -0
  20. data/spec/rails_app/app/mailers/welcome_mailer.rb +6 -0
  21. data/spec/rails_app/app/views/layouts/mailer.html.erb +11 -0
  22. data/spec/rails_app/app/views/welcome_mailer/welcome_email.html.erb +1 -0
  23. data/spec/rails_app/config.ru +5 -0
  24. data/spec/rails_app/config/application.rb +13 -0
  25. data/spec/rails_app/config/boot.rb +5 -0
  26. data/spec/rails_app/config/environment.rb +2 -0
  27. data/spec/rails_app/config/environments/test.rb +10 -0
  28. data/spec/rails_app/config/initializers/assets.rb +1 -0
  29. data/spec/rails_app/config/routes.rb +3 -0
  30. data/spec/spec_helper.rb +3 -8
  31. data/spec/unit/css_loaders/network_loader_spec.rb +1 -1
  32. data/spec/unit/customized_premailer_spec.rb +32 -40
  33. metadata +31 -24
  34. data/lib/premailer/rails/css_loaders/cache_loader.rb +0 -29
  35. data/spec/integration/hook_registration_spec.rb +0 -11
  36. data/spec/support/stubs/action_mailer.rb +0 -5
  37. data/spec/support/stubs/rails.rb +0 -51
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 34449fbe39f5a20061a3f6b389a95c4286b6a2cc
4
- data.tar.gz: 551a7262f0926f02554a6bea9c47eb4446d04d82
2
+ SHA256:
3
+ metadata.gz: 77899a5ba8ec23d6cf40d3b3d630f7872e92cbc959ba64ac528b31a658ae6f13
4
+ data.tar.gz: 4d13e28457b824306a517a7cff731fd83713654367562c9a7192e8a632d62aa2
5
5
  SHA512:
6
- metadata.gz: 507c28b394a9ec1fdf24e6a51b45f0cad7ac6b7ad3012f7c5993db164eeb1f100d9a410a10d4d5876f68cf9e8f9a3a2febf8a5cad5cc116823abaa84714ba8e7
7
- data.tar.gz: f3fb70d57c1acf9e196dadc98c53061ed45b2604c9a721e8eff194dd9e42b45243c5c07b4bcaa6b555ae97e5d163ba27c65cb6dcbfab61ed9b4f2168f813f853
6
+ metadata.gz: fc27f934b5772cc632cb7424013d31176afcdf47e60696479eb712c4ee85abe24a5d2524848e862e5a1489aea0778a789b1f2e96dc308df5caeb91a06f763e96
7
+ data.tar.gz: c3de5ed3a8625350eff2c07b30ed01cf418f6bb0a820e2244ad1e5c1018f495d8270e699539e21fbcac2e31c43d5e9fc36202b867b4d784c8955f8ea6338d13d
data/.gitignore CHANGED
@@ -2,3 +2,7 @@
2
2
  doc/
3
3
  Gemfile.lock
4
4
  coverage/
5
+ spec/rails_app/tmp/
6
+ spec/rails_app/log/
7
+ .ruby-version
8
+ /.bundle
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.10.0
4
+
5
+ - Drop support for hpricot now that premailer-rails also doesn't support it
6
+ - Use `Rails.application.assets_manifest` instead of `Rails.application.assets` in Asset Pipeline loader (@kirs, #201)
7
+ - Introduce `:strategies` config option that allows to control CSS fetching stragies
8
+
3
9
  ## v1.9.7
4
10
 
5
11
  - Use `Rails.root` in `FileSystemLoader` (@stanhu, #195)
data/Gemfile CHANGED
@@ -2,16 +2,20 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- action_mailer_version = ENV.fetch('ACTION_MAILER_VERSION', '5')
5
+ rails_version = ENV.fetch('ACTION_MAILER_VERSION', '5')
6
6
 
7
- if action_mailer_version == 'master'
7
+ if rails_version == 'master'
8
8
  git 'git://github.com/rails/rails.git' do
9
- gem 'actionmailer'
9
+ gem 'rails'
10
10
  end
11
+ gem 'sprockets-rails', github: 'rails/sprockets-rails'
12
+ gem 'arel', github: 'rails/arel'
11
13
  else
12
- gem 'actionmailer', "~> #{action_mailer_version}"
14
+ gem 'rails', "~> #{rails_version}"
13
15
  end
14
16
 
17
+ gem 'byebug'
18
+
15
19
  platforms :rbx do
16
20
  gem 'rubysl'
17
21
  gem 'racc'
data/README.md CHANGED
@@ -39,34 +39,34 @@ styled emails without having to set anything up.
39
39
  Whenever premailer-rails processes an email, it collects the URLs of all linked
40
40
  stylesheets (`<link rel="stylesheet" href="css_url">`). Then, for each of these
41
41
  URLs, it tries to get the content through a couple of strategies. As long as
42
- a strategy does not return anything, the next one is used. The strategies and
43
- their order are as follows:
42
+ a strategy does not return anything, the next one is used. The strategies
43
+ available are:
44
44
 
45
- 1. **Cache:** If there's a file in cache matching that URL, the cache content
46
- is returned. The cache right now is rather rudimentary. Whenever a CSS file
47
- is retrieved, it is stored in memory such that subsequent requests to the
48
- same file are faster. The caching is disabled inside Rails in the
49
- development environment.
50
-
51
- 2. **File System:** If there's a file inside `public/` with the same path as in
45
+ - `:filesystem`: If there's a file inside `public/` with the same path as in
52
46
  the URL, it is read from disk. E.g. if the URL is
53
47
  `http://cdn.example.com/assets/email.css` the contents of the file located
54
48
  at `public/assets/email.css` gets returned if it exists.
55
49
 
56
- 3. **Asset Pipeline:** If Rails is available and the asset pipeline is enabled,
50
+ - `:asset_pipeline`: If Rails is available and the asset pipeline is enabled,
57
51
  the file is retrieved through the asset pipeline. E.g. if the URL is
58
52
  `http://cdn.example.com/assets/email-fingerprint123.css`, the file
59
53
  `email.css` is requested from the asset pipeline. That is, the fingerprint
60
54
  and the prefix (in this case `assets` is the prefix) are stripped before
61
55
  requesting it from the asset pipeline.
62
56
 
63
- 4. **Network:** As a last resort, the URL is simply requested and the response
64
- body is used. This is usefull when the assets are not bundled in the
57
+ - `:network`: As a last resort, the URL is simply requested and the response
58
+ body is used. This is useful when the assets are not bundled in the
65
59
  application and only available on a CDN. On Heroku e.g. you can add assets
66
60
  to your `.slugignore` causing your assets to not be available to the app
67
61
  (and thus resulting in a smaller app) and deploy the assets to a CDN such
68
62
  as S3/CloudFront.
69
63
 
64
+ You can configure which strategies you want to use as well as specify their
65
+ order. Refer to the *Configuration* section for more on this.
66
+
67
+ Note that the retrieved CSS is cached when the gem is running with Rails in
68
+ production.
69
+
70
70
  ## Installation
71
71
 
72
72
  Simply add the gem to your `Gemfile`:
@@ -75,20 +75,12 @@ Simply add the gem to your `Gemfile`:
75
75
  gem 'premailer-rails'
76
76
  ```
77
77
 
78
- premailer-rails requires either [nokogiri] or [hpricot]. It doesn't list them as
79
- a dependency so you can choose which one to use. Since hpricot is no longer
80
- maintained, I suggest you to go with nokogiri. Add either one to your `Gemfile`:
81
-
82
- ```ruby
83
- gem 'nokogiri'
84
- # or
85
- gem 'hpricot'
86
- ```
87
-
88
- If both gems are loaded for some reason, premailer chooses hpricot.
89
-
90
- You can also explicitly configure the apapter as documented
91
- [here](https://github.com/premailer/premailer#adapters).
78
+ premailer-rails and premailer require a gem that is used to parse the email's
79
+ HTML. For a list of supported gems and how to select which one to use, please
80
+ refer to the [*Adapter*
81
+ section](https://github.com/premailer/premailer#adapters) of premailer. Note
82
+ that there is no hard dependency from either gem so you should add one yourself.
83
+ Also note that this gem is only tested with [nokogiri].
92
84
 
93
85
  ## Configuration
94
86
 
@@ -107,7 +99,8 @@ configs are:
107
99
  ```ruby
108
100
  {
109
101
  input_encoding: 'UTF-8',
110
- generate_text_part: true
102
+ generate_text_part: true,
103
+ strategies: [:filesystem, :asset_pipeline, :network]
111
104
  }
112
105
  ```
113
106
 
@@ -185,7 +178,6 @@ premailer-rails is released under the MIT license. See the [license file].
185
178
  [premailer]: https://github.com/premailer/premailer
186
179
  [actionmailer]: https://github.com/rails/rails/tree/master/actionmailer
187
180
  [nokogiri]: https://github.com/sparklemotion/nokogiri
188
- [hpricot]: https://github.com/hpricot/hpricot
189
181
 
190
182
  [premailer documentation]: http://rubydoc.info/gems/premailer/1.7.3/Premailer:initialize
191
183
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.9.7
1
+ 1.10.0
@@ -11,7 +11,8 @@ class Premailer
11
11
  module Rails
12
12
  @config = {
13
13
  input_encoding: 'UTF-8',
14
- generate_text_part: true
14
+ generate_text_part: true,
15
+ strategies: [:filesystem, :asset_pipeline, :network]
15
16
  }
16
17
  class << self
17
18
  attr_accessor :config
@@ -5,12 +5,8 @@ class Premailer
5
5
 
6
6
  FileNotFound = Class.new(StandardError)
7
7
 
8
- STRATEGIES = [
9
- CSSLoaders::CacheLoader,
10
- CSSLoaders::FileSystemLoader,
11
- CSSLoaders::AssetPipelineLoader,
12
- CSSLoaders::NetworkLoader
13
- ]
8
+ attr_accessor :cache
9
+ self.cache = {}
14
10
 
15
11
  # Returns all linked CSS files concatenated as string.
16
12
  def css_for_doc(doc)
@@ -18,8 +14,10 @@ class Premailer
18
14
  end
19
15
 
20
16
  def css_for_url(url)
21
- load_css(url).tap do |content|
22
- CSSLoaders::CacheLoader.store(url, content)
17
+ if cache_enabled?
18
+ load_css_with_cache(url)
19
+ else
20
+ load_css(url)
23
21
  end
24
22
  end
25
23
 
@@ -36,14 +34,35 @@ class Premailer
36
34
  end
37
35
  end
38
36
 
37
+ def load_css_with_cache(url)
38
+ self.cache[url] ||= load_css(url)
39
+ end
40
+
41
+ def cache_enabled?
42
+ defined?(::Rails) && ::Rails.env.production?
43
+ end
44
+
39
45
  def load_css(url)
40
- STRATEGIES.each do |strategy|
41
- css = strategy.load(url)
46
+ Premailer::Rails.config.fetch(:strategies).each do |strategy|
47
+ css = find_strategy(strategy).load(url)
42
48
  return css.force_encoding('UTF-8') if css
43
49
  end
44
50
 
45
51
  raise FileNotFound, %{File with URL "#{url}" could not be loaded by any strategy.}
46
52
  end
53
+
54
+ def find_strategy(key)
55
+ case key
56
+ when :filesystem
57
+ CSSLoaders::FileSystemLoader
58
+ when :asset_pipeline
59
+ CSSLoaders::AssetPipelineLoader
60
+ when :network
61
+ CSSLoaders::NetworkLoader
62
+ else
63
+ key
64
+ end
65
+ end
47
66
  end
48
67
  end
49
68
  end
@@ -1,6 +1,5 @@
1
1
  require 'uri'
2
2
 
3
- require 'premailer/rails/css_loaders/cache_loader'
4
3
  require 'premailer/rails/css_loaders/file_system_loader'
5
4
  require 'premailer/rails/css_loaders/asset_pipeline_loader'
6
5
  require 'premailer/rails/css_loaders/network_loader'
@@ -5,18 +5,11 @@ class Premailer
5
5
  extend self
6
6
 
7
7
  def load(url)
8
- if asset_pipeline_present?
9
- file = file_name(url)
10
- asset = ::Rails.application.assets.find_asset(file)
11
- asset.to_s if asset
12
- end
13
- end
8
+ return unless asset_pipeline_present?
14
9
 
15
- def asset_pipeline_present?
16
- defined?(::Rails) &&
17
- ::Rails.respond_to?(:application) &&
18
- ::Rails.application.respond_to?(:assets) &&
19
- ::Rails.application.assets
10
+ file = file_name(url)
11
+ ::Rails.application.assets_manifest.find_sources(file).first
12
+ rescue Errno::ENOENT => _error
20
13
  end
21
14
 
22
15
  def file_name(url)
@@ -29,6 +22,10 @@ class Premailer
29
22
  .sub(/\A#{prefix}/, '')
30
23
  .sub(/-(\h{32}|\h{64})\.css\z/, '.css')
31
24
  end
25
+
26
+ def asset_pipeline_present?
27
+ defined?(::Rails) && ::Rails.application && ::Rails.application.assets_manifest
28
+ end
32
29
  end
33
30
  end
34
31
  end
@@ -14,7 +14,7 @@ class Premailer
14
14
 
15
15
  if uri.host.present?
16
16
  return uri if uri.scheme.present?
17
- URI("http://#{uri.to_s}")
17
+ URI("http:#{uri}")
18
18
  elsif asset_host_present?
19
19
  scheme, host = asset_host(url).split(%r{:?//})
20
20
  scheme, host = host, scheme if host.nil?
@@ -4,10 +4,10 @@ class Premailer
4
4
  def initialize(html)
5
5
  # In order to pass the CSS as string to super it is necessary to access
6
6
  # the parsed HTML beforehand. To do so, the adapter needs to be
7
- # initialized. The ::Premailer::Adaptor handles the discovery of a
8
- # suitable adaptor (Nokogiri or Hpricot). To make load_html work, an
9
- # adaptor needs to be included and @options[:with_html_string] needs to
10
- # be set. For further information, refer to ::Premailer#initialize.
7
+ # initialized. The ::Premailer::Adapter handles the discovery of
8
+ # a suitable adapter. To make load_html work, an adapter needs to be
9
+ # included and @options[:with_html_string] needs to be set. For further
10
+ # information, refer to ::Premailer#initialize.
11
11
  @options = Rails.config.merge(with_html_string: true)
12
12
  Premailer.send(:include, Adapter.find(Adapter.use))
13
13
  doc = load_html(html)
@@ -26,6 +26,5 @@ Gem::Specification.new do |s|
26
26
 
27
27
  s.add_development_dependency 'rspec', '~> 3.3'
28
28
  s.add_development_dependency 'nokogiri'
29
- s.add_development_dependency 'hpricot' unless RUBY_PLATFORM == 'java'
30
29
  s.add_development_dependency 'coveralls' if RUBY_ENGINE == 'ruby'
31
30
  end
@@ -1,186 +1,200 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Premailer::Rails::CSSHelper do
4
- [ :Nokogiri, :Hpricot ].each do |adapter|
5
- next if adapter == :Hpricot and RUBY_PLATFORM == 'java'
4
+ # Reset the CSS cache:
5
+ after do
6
+ Premailer::Rails::CSSHelper.cache = {}
7
+ end
6
8
 
7
- context "when adapter is #{adapter}" do
8
- # Reset the CSS cache:
9
- after do
10
- Premailer::Rails::CSSLoaders::CacheLoader.clear!
11
- end
9
+ def css_for_url(path)
10
+ Premailer::Rails::CSSHelper.css_for_url(path)
11
+ end
12
12
 
13
- def css_for_url(path)
14
- Premailer::Rails::CSSHelper.css_for_url(path)
15
- end
13
+ def css_for_doc(doc)
14
+ Premailer::Rails::CSSHelper.css_for_doc(doc)
15
+ end
16
+
17
+ def expect_file(path, content='file content')
18
+ path = "#{Rails.root}/#{path}"
19
+ allow(File).to receive(:file?).with(path).and_return(true)
20
+ expect(File).to receive(:read).with(path).and_return(content)
21
+ end
16
22
 
17
- def css_for_doc(doc)
18
- Premailer::Rails::CSSHelper.css_for_doc(doc)
23
+ describe '#css_for_doc' do
24
+ let(:html) { Fixtures::HTML.with_css_links(*files) }
25
+ let(:doc) { Nokogiri(html) }
26
+
27
+ context 'when HTML contains linked CSS files' do
28
+ let(:files) { %w[ stylesheets/base.css stylesheets/font.css ] }
29
+
30
+ it 'returns the content of both files concatenated' do
31
+ allow(Premailer::Rails::CSSHelper).to \
32
+ receive(:css_for_url)
33
+ .with('http://example.com/stylesheets/base.css')
34
+ .and_return('content of base.css')
35
+ allow(Premailer::Rails::CSSHelper).to \
36
+ receive(:css_for_url)
37
+ .with('http://example.com/stylesheets/font.css')
38
+ .and_return('content of font.css')
39
+
40
+ expect(css_for_doc(doc)).to eq("content of base.css\ncontent of font.css")
19
41
  end
42
+ end
20
43
 
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)
44
+ context 'when HTML contains ignored links' do
45
+ let(:files) { ['ignore.css', 'data-premailer' => 'ignore'] }
46
+
47
+ it 'ignores links' do
48
+ expect(Premailer::Rails::CSSHelper).to_not receive(:css_for_url)
49
+ css_for_doc(doc)
24
50
  end
51
+ end
52
+ end
25
53
 
26
- describe '#css_for_doc' do
27
- let(:html) { Fixtures::HTML.with_css_links(*files) }
28
- let(:doc) { send(adapter, html) }
54
+ describe '#css_for_url' do
55
+ context 'when path is a url' do
56
+ it 'loads the CSS at the local path' do
57
+ expect_file('public/stylesheets/base.css')
29
58
 
30
- context 'when HTML contains linked CSS files' do
31
- let(:files) { %w[ stylesheets/base.css stylesheets/font.css ] }
59
+ css_for_url('http://example.com/stylesheets/base.css?test')
60
+ end
61
+ end
32
62
 
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')
63
+ context 'when path is a relative url' do
64
+ it 'loads the CSS at the local path' do
65
+ expect_file('public/stylesheets/base.css')
66
+ css_for_url('/stylesheets/base.css?test')
67
+ end
68
+ end
42
69
 
43
- expect(css_for_doc(doc)).to eq("content of base.css\ncontent of font.css")
44
- end
45
- end
70
+ context 'when cache is enabled' do
71
+ before do
72
+ allow(Premailer::Rails::CSSHelper).to receive(:cache_enabled?).and_return(true)
73
+ end
46
74
 
47
- context 'when HTML contains ignored links' do
48
- let(:files) { ['ignore.css', 'data-premailer' => 'ignore'] }
75
+ context 'when file is cached' do
76
+ it 'returns the cached value' do
77
+ Premailer::Rails::CSSHelper.cache['http://example.com/stylesheets/base.css'] = 'content of base.css'
49
78
 
50
- it 'ignores links' do
51
- expect(Premailer::Rails::CSSHelper).to_not receive(:css_for_url)
52
- css_for_doc(doc)
53
- end
79
+ expect(css_for_url('http://example.com/stylesheets/base.css')).to \
80
+ eq('content of base.css')
54
81
  end
55
82
  end
83
+ end
56
84
 
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')
85
+ context 'when cache is disabled' do
86
+ before do
87
+ allow(Premailer::Rails::CSSHelper).to receive(:cache_enabled?).and_return(false)
88
+ end
61
89
 
62
- css_for_url('http://example.com/stylesheets/base.css?test')
63
- end
64
- end
90
+ it 'does not return cached values' do
91
+ Premailer::Rails::CSSHelper.cache['http://example.com/stylesheets/base.css'] = 'cached content'
92
+ content = 'new content of base.css'
93
+ expect_file('public/stylesheets/base.css', content)
65
94
 
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
95
+ expect(css_for_url('http://example.com/stylesheets/base.css')).to eq(content)
96
+ end
97
+ end
72
98
 
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
- )
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
79
106
 
80
- expect(css_for_url('http://example.com/stylesheets/base.css')).to \
81
- eq('content of base.css')
82
- 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)
83
113
  end
114
+ end
84
115
 
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
97
- end
116
+ context "when find_sources raises Errno::ENOENT" do
117
+ let(:response) { 'content of base.css' }
118
+ let(:uri) { URI('http://example.com/assets/base.css') }
98
119
 
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
120
+ it "falls back to Net::HTTP" do
121
+ expect(Rails.application.assets_manifest).to \
122
+ receive(:find_sources)
123
+ .with('base.css')
124
+ .and_raise(Errno::ENOENT)
106
125
 
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
126
+ allow(Net::HTTP).to \
127
+ receive(:get).with(uri).and_return(response)
128
+ expect(css_for_url('http://example.com/assets/base.css')).to \
129
+ eq(response)
130
+ end
131
+ end
115
132
 
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'))
133
+ it 'returns the content of the file compiled by Rails' do
134
+ expect(Rails.application.assets_manifest).to \
135
+ receive(:find_sources)
136
+ .with('base.css')
137
+ .and_return(['content of base.css'])
121
138
 
122
- expect(css_for_url('http://example.com/assets/base.css')).to \
123
- eq('content of base.css')
124
- end
139
+ expect(css_for_url('http://example.com/assets/base.css')).to \
140
+ eq('content of base.css')
141
+ end
125
142
 
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'))
143
+ it 'returns same file when path contains file fingerprint' do
144
+ expect(Rails.application.assets_manifest).to \
145
+ receive(:find_sources)
146
+ .with('base.css')
147
+ .and_return(['content of base.css'])
131
148
 
132
- expect(css_for_url(
133
- 'http://example.com/assets/base-089e35bd5d84297b8d31ad552e433275.css'
134
- )).to eq('content of base.css')
135
- end
149
+ expect(css_for_url(
150
+ 'http://example.com/assets/base-089e35bd5d84297b8d31ad552e433275.css'
151
+ )).to eq('content of base.css')
152
+ end
136
153
 
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' }
154
+ context 'when asset can not be found' do
155
+ let(:response) { 'content of base.css' }
156
+ let(:path) { '/assets/base-089e35bd5d84297b8d31ad552e433275.css' }
157
+ let(:url) { "http://assets.example.com#{path}" }
158
+ let(:asset_host) { 'http://assets.example.com' }
142
159
 
143
- before do
144
- allow(Rails.application.assets).to \
145
- receive(:find_asset).and_return(nil)
160
+ before do
161
+ allow(Rails.application.assets_manifest).to \
162
+ receive(:find_sources).and_return([])
146
163
 
147
- config = double(asset_host: asset_host)
148
- allow(Rails.configuration).to \
149
- receive(:action_controller).and_return(config)
164
+ config = double(asset_host: asset_host)
165
+ allow(Rails.configuration).to \
166
+ receive(:action_controller).and_return(config)
150
167
 
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
168
+ allow(Net::HTTP).to \
169
+ receive(:get).with(URI(url)).and_return(response)
170
+ end
155
171
 
156
- it 'requests the file' do
157
- expect(css_for_url(url)).to eq('content of base.css')
158
- end
172
+ it 'requests the file' do
173
+ expect(css_for_url(url)).to eq('content of base.css')
174
+ end
159
175
 
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
176
+ context 'when file url does not include the host' do
177
+ it 'requests the file using the asset host as host' do
178
+ expect(css_for_url(path)).to eq('content of base.css')
179
+ end
164
180
 
165
- context 'and the asset host uses protocol relative scheme' do
166
- let(:asset_host) { '//assets.example.com' }
181
+ context 'and the asset host uses protocol relative scheme' do
182
+ let(:asset_host) { '//assets.example.com' }
167
183
 
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
184
+ it 'requests the file using http as the scheme' do
185
+ expect(css_for_url(path)).to eq('content of base.css')
172
186
  end
173
187
  end
174
188
  end
189
+ end
190
+ end
175
191
 
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
192
+ context 'when static stylesheets are used' do
193
+ it 'returns the content of the static file' do
194
+ content = 'content of base.css'
195
+ expect_file('public/stylesheets/base.css', content)
196
+ loaded_content = css_for_url('http://example.com/stylesheets/base.css')
197
+ expect(loaded_content).to eq(content)
184
198
  end
185
199
  end
186
200
  end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ActionMailer::Base delivery' do
4
+ it 'delivers email with inlined CSS' do
5
+ WelcomeMailer.welcome_email("world").deliver_now
6
+
7
+ mail = ActionMailer::Base.deliveries.last
8
+ expect(mail).to be_present
9
+ body = mail.html_part.body.to_s
10
+ expect(body).to be_present
11
+ expect(body).to include(%{<p style="font-size: 12px;">Hello world</p>})
12
+ end
13
+ end
@@ -91,7 +91,7 @@ describe Premailer::Rails::Hook do
91
91
 
92
92
  it 'does not replace any message part' do
93
93
  expect { run_hook(message) }.to_not \
94
- change { message.all_parts.map(&:content_type) }
94
+ change { message.all_parts.map(&:content_type).sort }
95
95
  end
96
96
  end
97
97
 
@@ -0,0 +1,3 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../javascripts .js
3
+ //= link_directory ../stylesheets .css
@@ -0,0 +1,3 @@
1
+ p {
2
+ font-size: 12px;
3
+ }
@@ -0,0 +1,4 @@
1
+ class ApplicationMailer < ActionMailer::Base
2
+ default from: 'from@example.com'
3
+ layout 'mailer'
4
+ end
@@ -0,0 +1,6 @@
1
+ class WelcomeMailer < ApplicationMailer
2
+ def welcome_email(greeting)
3
+ @greeting = greeting
4
+ mail to: "example@example.com"
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5
+ <link rel="stylesheet" href="/assets/application.css"/>
6
+ </head>
7
+
8
+ <body>
9
+ <%= yield %>
10
+ </body>
11
+ </html>
@@ -0,0 +1 @@
1
+ <p>Hello <%= @greeting %></p>
@@ -0,0 +1,5 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require_relative 'config/environment'
4
+
5
+ run Rails.application
@@ -0,0 +1,13 @@
1
+ require_relative 'boot'
2
+
3
+ require "action_mailer/railtie"
4
+ require "action_view/railtie"
5
+ require "sprockets/railtie"
6
+ require "rails/test_unit/railtie"
7
+
8
+ Bundler.require(*Rails.groups)
9
+
10
+ module Dummy
11
+ class Application < Rails::Application
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # Set up gems listed in the Gemfile.
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
3
+
4
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5
+ $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
@@ -0,0 +1,2 @@
1
+ require_relative 'application'
2
+ Rails.application.initialize!
@@ -0,0 +1,10 @@
1
+ Rails.application.configure do
2
+ config.cache_classes = true
3
+ config.eager_load = false
4
+ config.consider_all_requests_local = true
5
+ config.action_controller.perform_caching = false
6
+ config.action_dispatch.show_exceptions = false
7
+ config.action_controller.allow_forgery_protection = false
8
+ config.action_mailer.delivery_method = :test
9
+ config.active_support.deprecation = :stderr
10
+ end
@@ -0,0 +1 @@
1
+ Rails.application.config.assets.version = '1.0'
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ root 'application#main'
3
+ end
data/spec/spec_helper.rb CHANGED
@@ -11,16 +11,11 @@ if RUBY_ENGINE == 'ruby'
11
11
  end
12
12
  end
13
13
 
14
- # Temporary fix for missing require. See
15
- # https://github.com/rails/rails/pull/28835
16
- require 'active_support/rescuable'
14
+ # Configure Rails Environment
15
+ ENV["RAILS_ENV"] = "test"
16
+ require File.expand_path("../../spec/rails_app/config/environment.rb", __FILE__)
17
17
 
18
- require 'premailer/rails'
19
-
20
- require 'support/stubs/action_mailer'
21
- require 'support/stubs/rails'
22
18
  require 'support/fixtures/message'
23
19
  require 'support/fixtures/html'
24
20
 
25
- require 'hpricot' unless RUBY_PLATFORM == 'java'
26
21
  require 'nokogiri'
@@ -18,7 +18,7 @@ describe Premailer::Rails::CSSLoaders::NetworkLoader do
18
18
 
19
19
  context 'with a protocol relative URL' do
20
20
  let(:url) { '//example.com/test.css' }
21
- it { is_expected.to eq(URI("http://#{url}")) }
21
+ it { is_expected.to eq(URI("http:#{url}")) }
22
22
  end
23
23
 
24
24
  context 'with a file path' do
@@ -1,51 +1,43 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Premailer::Rails::CustomizedPremailer do
4
- [ :nokogiri, :hpricot ].each do |adapter|
5
- next if adapter == :hpricot and RUBY_PLATFORM == 'java'
4
+ describe '#to_plain_text' do
5
+ it 'includes the text from the HTML part' do
6
+ premailer =
7
+ Premailer::Rails::CustomizedPremailer
8
+ .new(Fixtures::Message::HTML_PART)
9
+ expect(premailer.to_plain_text.gsub(/\s/, ' ').strip).to \
10
+ eq(Fixtures::Message::TEXT_PART.gsub(/\s/, ' ').strip)
11
+ end
12
+ end
6
13
 
7
- context "when adapter is #{adapter}" do
8
- before { allow(Premailer::Adapter).to receive(:use).and_return(adapter) }
14
+ describe '#to_inline_css' do
15
+ let(:regex) { %r{<p style=("|')color: ?red;?\1>} }
9
16
 
10
- describe '#to_plain_text' do
11
- it 'includes the text from the HTML part' do
12
- premailer =
13
- Premailer::Rails::CustomizedPremailer
14
- .new(Fixtures::Message::HTML_PART)
15
- expect(premailer.to_plain_text.gsub(/\s/, ' ').strip).to \
16
- eq(Fixtures::Message::TEXT_PART.gsub(/\s/, ' ').strip)
17
- end
17
+ context 'when inline CSS block present' do
18
+ it 'returns the HTML with the CSS inlined' do
19
+ allow(Premailer::Rails::CSSHelper).to \
20
+ receive(:css_for_doc).and_return('p { color: red; }')
21
+ html = Fixtures::Message::HTML_PART
22
+ premailer = Premailer::Rails::CustomizedPremailer.new(html)
23
+ expect(premailer.to_inline_css).to match(regex)
18
24
  end
25
+ end
19
26
 
20
- describe '#to_inline_css' do
21
- let(:regex) { %r{<p style=("|')color: ?red;?\1>} }
22
-
23
- context 'when inline CSS block present' do
24
- it 'returns the HTML with the CSS inlined' do
25
- allow(Premailer::Rails::CSSHelper).to \
26
- receive(:css_for_doc).and_return('p { color: red; }')
27
- html = Fixtures::Message::HTML_PART
28
- premailer = Premailer::Rails::CustomizedPremailer.new(html)
29
- expect(premailer.to_inline_css).to match(regex)
30
- end
31
- end
32
-
33
- context 'when CSS is loaded externally' do
34
- it 'returns the HTML with the CSS inlined' do
35
- html = Fixtures::Message::HTML_PART_WITH_CSS
36
- premailer = Premailer::Rails::CustomizedPremailer.new(html)
37
- expect(premailer.to_inline_css).to match(regex)
38
- end
39
- end
27
+ context 'when CSS is loaded externally' do
28
+ it 'returns the HTML with the CSS inlined' do
29
+ html = Fixtures::Message::HTML_PART_WITH_CSS
30
+ premailer = Premailer::Rails::CustomizedPremailer.new(html)
31
+ expect(premailer.to_inline_css).to match(regex)
32
+ end
33
+ end
40
34
 
41
- context 'when HTML contains unicode' do
42
- it 'does not mess those up' do
43
- html = Fixtures::Message::HTML_PART_WITH_UNICODE
44
- premailer = Premailer::Rails::CustomizedPremailer.new(html)
45
- expect(premailer.to_inline_css).to \
46
- include(Fixtures::Message::UNICODE_STRING)
47
- end
48
- end
35
+ context 'when HTML contains unicode' do
36
+ it 'does not mess those up' do
37
+ html = Fixtures::Message::HTML_PART_WITH_UNICODE
38
+ premailer = Premailer::Rails::CustomizedPremailer.new(html)
39
+ expect(premailer.to_inline_css).to \
40
+ include(Fixtures::Message::UNICODE_STRING)
49
41
  end
50
42
  end
51
43
  end
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.7
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philipe Fatio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-26 00:00:00.000000000 Z
11
+ date: 2017-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: premailer
@@ -78,20 +78,6 @@ dependencies:
78
78
  - - ">="
79
79
  - !ruby/object:Gem::Version
80
80
  version: '0'
81
- - !ruby/object:Gem::Dependency
82
- name: hpricot
83
- requirement: !ruby/object:Gem::Requirement
84
- requirements:
85
- - - ">="
86
- - !ruby/object:Gem::Version
87
- version: '0'
88
- type: :development
89
- prerelease: false
90
- version_requirements: !ruby/object:Gem::Requirement
91
- requirements:
92
- - - ">="
93
- - !ruby/object:Gem::Version
94
- version: '0'
95
81
  - !ruby/object:Gem::Dependency
96
82
  name: coveralls
97
83
  requirement: !ruby/object:Gem::Requirement
@@ -149,7 +135,6 @@ files:
149
135
  - lib/premailer/rails/css_helper.rb
150
136
  - lib/premailer/rails/css_loaders.rb
151
137
  - lib/premailer/rails/css_loaders/asset_pipeline_loader.rb
152
- - lib/premailer/rails/css_loaders/cache_loader.rb
153
138
  - lib/premailer/rails/css_loaders/file_system_loader.rb
154
139
  - lib/premailer/rails/css_loaders/network_loader.rb
155
140
  - lib/premailer/rails/customized_premailer.rb
@@ -158,13 +143,24 @@ files:
158
143
  - lib/premailer/rails/version.rb
159
144
  - premailer-rails.gemspec
160
145
  - spec/integration/css_helper_spec.rb
161
- - spec/integration/hook_registration_spec.rb
146
+ - spec/integration/delivery_spec.rb
162
147
  - spec/integration/hook_spec.rb
148
+ - spec/rails_app/app/assets/config/manifest.js
149
+ - spec/rails_app/app/assets/stylesheets/application.css
150
+ - spec/rails_app/app/mailers/application_mailer.rb
151
+ - spec/rails_app/app/mailers/welcome_mailer.rb
152
+ - spec/rails_app/app/views/layouts/mailer.html.erb
153
+ - spec/rails_app/app/views/welcome_mailer/welcome_email.html.erb
154
+ - spec/rails_app/config.ru
155
+ - spec/rails_app/config/application.rb
156
+ - spec/rails_app/config/boot.rb
157
+ - spec/rails_app/config/environment.rb
158
+ - spec/rails_app/config/environments/test.rb
159
+ - spec/rails_app/config/initializers/assets.rb
160
+ - spec/rails_app/config/routes.rb
163
161
  - spec/spec_helper.rb
164
162
  - spec/support/fixtures/html.rb
165
163
  - spec/support/fixtures/message.rb
166
- - spec/support/stubs/action_mailer.rb
167
- - spec/support/stubs/rails.rb
168
164
  - spec/unit/css_loaders/asset_pipeline_loader_spec.rb
169
165
  - spec/unit/css_loaders/file_system_loader_spec.rb
170
166
  - spec/unit/css_loaders/network_loader_spec.rb
@@ -190,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
190
186
  version: '0'
191
187
  requirements: []
192
188
  rubyforge_project:
193
- rubygems_version: 2.6.11
189
+ rubygems_version: 2.7.2
194
190
  signing_key:
195
191
  specification_version: 4
196
192
  summary: Easily create styled HTML emails in Rails.
@@ -213,13 +209,24 @@ test_files:
213
209
  - example/config/secrets.yml
214
210
  - example/test/mailers/previews/example_mailer_preview.rb
215
211
  - spec/integration/css_helper_spec.rb
216
- - spec/integration/hook_registration_spec.rb
212
+ - spec/integration/delivery_spec.rb
217
213
  - spec/integration/hook_spec.rb
214
+ - spec/rails_app/app/assets/config/manifest.js
215
+ - spec/rails_app/app/assets/stylesheets/application.css
216
+ - spec/rails_app/app/mailers/application_mailer.rb
217
+ - spec/rails_app/app/mailers/welcome_mailer.rb
218
+ - spec/rails_app/app/views/layouts/mailer.html.erb
219
+ - spec/rails_app/app/views/welcome_mailer/welcome_email.html.erb
220
+ - spec/rails_app/config.ru
221
+ - spec/rails_app/config/application.rb
222
+ - spec/rails_app/config/boot.rb
223
+ - spec/rails_app/config/environment.rb
224
+ - spec/rails_app/config/environments/test.rb
225
+ - spec/rails_app/config/initializers/assets.rb
226
+ - spec/rails_app/config/routes.rb
218
227
  - spec/spec_helper.rb
219
228
  - spec/support/fixtures/html.rb
220
229
  - spec/support/fixtures/message.rb
221
- - spec/support/stubs/action_mailer.rb
222
- - spec/support/stubs/rails.rb
223
230
  - spec/unit/css_loaders/asset_pipeline_loader_spec.rb
224
231
  - spec/unit/css_loaders/file_system_loader_spec.rb
225
232
  - spec/unit/css_loaders/network_loader_spec.rb
@@ -1,29 +0,0 @@
1
- class Premailer
2
- module Rails
3
- module CSSLoaders
4
- module CacheLoader
5
- extend self
6
-
7
- @cache = {}
8
-
9
- def load(url)
10
- @cache[url] unless development_env?
11
- end
12
-
13
- def store(url, content)
14
- @cache[url] ||= content unless development_env?
15
- end
16
-
17
- def clear!
18
- @cache = {}
19
- end
20
-
21
- def development_env?
22
- defined?(::Rails) &&
23
- ::Rails.respond_to?(:env) &&
24
- ::Rails.env.development?
25
- end
26
- end
27
- end
28
- end
29
- end
@@ -1,11 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'ActionMailer::Base.register_interceptor' do
4
- it 'registers interceptors' do
5
- expect(ActionMailer::Base).to \
6
- receive(:register_interceptor).with(Premailer::Rails::Hook)
7
- expect(ActionMailer::Base).to \
8
- receive(:register_preview_interceptor).with(Premailer::Rails::Hook)
9
- load 'premailer/rails.rb'
10
- end
11
- end
@@ -1,5 +0,0 @@
1
- module ActionMailer
2
- class Base
3
- def self.register_interceptor(x); end
4
- end
5
- end
@@ -1,51 +0,0 @@
1
- module Rails
2
- extend self
3
-
4
- module Configuration
5
- extend self
6
- end
7
-
8
- module Env
9
- extend self
10
-
11
- def development?
12
- false
13
- end
14
- end
15
-
16
- module Application
17
- extend self
18
-
19
- module Assets
20
- extend self
21
- end
22
-
23
- def assets
24
- Assets
25
- end
26
- end
27
-
28
- class Railtie
29
- class Configuration
30
- def after_initialize
31
- yield
32
- end
33
- end
34
-
35
- def self.config
36
- Configuration.new
37
- end
38
- end
39
-
40
- def env
41
- Env
42
- end
43
-
44
- def configuration
45
- Configuration
46
- end
47
-
48
- def application
49
- Application
50
- end
51
- end