premailer-rails 1.3.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b7fe7ad5147d3f2fc55adfb214b582cf36cb6e8d
4
+ data.tar.gz: c89ed93ba60d97da47d9052a4021ec9464ca6f61
5
+ SHA512:
6
+ metadata.gz: 51cfbedc2689258c5bf481d573365b25c7116ebccdad4be79115d68e10515cfe5651c77e9d34fd31f70c5b0170f7e86b0b02c3fa5a887627be81157bf9c8f479
7
+ data.tar.gz: f39cd91e3c94347be787f47a2aa6487a27c046d007981a164ad30d394924d0f64b38743bd708e2b5d56c3f14dce07de3bd5caefc06a4a3d41ec993fd0019bceb
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ doc/
3
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format doc
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ script: "bundle exec rspec"
3
+ rvm:
4
+ - 2.0.0
5
+ - 1.9.3
6
+ - 1.8.7
7
+ - jruby-18mode # JRuby in 1.8 mode
8
+ - jruby-19mode # JRuby in 1.9 mode
9
+ - rbx-18mode
10
+ - rbx-19mode
data/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ ## v1.1.0
4
+
5
+ - Fixed several bugs
6
+
7
+ - Strip asset digest from CSS path
8
+
9
+ - Improve nokogiri support
10
+
11
+ - Request CSS file if asset is not found locally
12
+
13
+ This allows you to host all your assets on a CDN and deploy the
14
+ app without the `app/assets` folder.
15
+
16
+ Thanks to everyone who contributed!
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in premailer-rails3.gemspec
4
+ gemspec
5
+
6
+ platforms :jruby do
7
+ gem "jruby-openssl"
8
+ end
data/LICENSE ADDED
@@ -0,0 +1,14 @@
1
+ Copyright (C) 2011-2012 Philipe Fatio (fphilipe)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
+ documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
5
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
6
+ persons to whom the Software is furnished to do so, subject to the following conditions:
7
+
8
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of
9
+ the Software.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
14
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # premailer-rails
2
+
3
+ [![Build Status](https://travis-ci.org/fphilipe/premailer-rails.png)](https://travis-ci.org/fphilipe/premailer-rails)
4
+ [![Gem Version](https://badge.fury.io/rb/premailer-rails.png)](http://badge.fury.io/rb/premailer-rails)
5
+ [![Dependency Status](https://gemnasium.com/fphilipe/premailer-rails.png)](https://gemnasium.com/fphilipe/premailer-rails)
6
+ [![Code Climate](https://codeclimate.com/github/fphilipe/premailer-rails.png)](https://codeclimate.com/github/fphilipe/premailer-rails)
7
+
8
+ This gem is a no config solution for the wonderful
9
+ [Premailer gem](https://github.com/alexdunae/premailer) to be used with Rails.
10
+ It uses interceptors which were introduced in Rails 3 and tweaks all mails which
11
+ are `deliver`ed and adds a plain text part to them and inlines all CSS rules
12
+ into the HTML part.
13
+
14
+ By default it inlines all the CSS files that are linked to in the HTML:
15
+
16
+ ```html
17
+ <link type='text/css' ... />
18
+ ```
19
+
20
+ Don't worry about the host in the CSS URL since this will be ignored.
21
+
22
+ Every CSS file is loaded from within the app.
23
+ The retrieval of the file depends on your assets configuration:
24
+
25
+ * Rails 3.1 asset pipeline: It will load the compiled version of the CSS asset
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.
29
+
30
+ * Classic static assets: It will try to load the CSS file located in
31
+ `public/stylesheets/`
32
+
33
+ * [Hassle](https://github.com/pedro/hassle): It will try to load the
34
+ compiled CSS file located in the default Hassle location
35
+ `tmp/hassle/stylesheets/`
36
+
37
+ ## Installation
38
+
39
+ Simply add the gem to your Gemfile in your Rails project:
40
+
41
+ gem 'premailer-rails'
42
+
43
+ premailer-rails requires either nokogiri or hpricot. It doesn't list them as a
44
+ dependency so you can choose which one to use.
45
+
46
+ gem 'nokogiri'
47
+ # or
48
+ gem 'hpricot'
49
+
50
+ If both are loaded for some reason, premailer chooses hpricot.
51
+
52
+ That's it!
53
+
54
+ ## Configuration
55
+
56
+ Premailer itself accepts a number of options. In order for premailer-rails to
57
+ pass these options on to the underlying premailer instance, specify them in an
58
+ initializer:
59
+
60
+ ```ruby
61
+ Premailer::Rails.config.merge!(:preserve_styles => true,
62
+ :remove_ids => true)
63
+ ```
64
+
65
+ For a list of options, refer to the [Premailer documentation](http://rubydoc.info/gems/premailer/1.7.3/Premailer:initialize)
66
+
67
+ The default configs are:
68
+
69
+ ```ruby
70
+ {
71
+ :input_encoding => 'UTF-8',
72
+ :inputencoding => 'UTF-8',
73
+ :generate_text_part => true
74
+ }
75
+ ```
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
+
82
+ If you don't want to generate a text part from the html part, set the config
83
+ `:generate_text_part` to false.
84
+
85
+ Note that the options `:with_html_string` and `:css_string` are used to make
86
+ this gem work and will thus be overridden.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.3.2
@@ -0,0 +1,23 @@
1
+ require 'premailer'
2
+ require 'action_mailer'
3
+
4
+ require 'premailer/rails/css_loaders'
5
+ require 'premailer/rails/css_helper'
6
+ require 'premailer/rails/customized_premailer'
7
+ require 'premailer/rails/hook'
8
+ require 'premailer/rails/nokogiri_fix'
9
+
10
+ class Premailer
11
+ module Rails
12
+ @config = {
13
+ :input_encoding => 'UTF-8',
14
+ :inputencoding => 'UTF-8',
15
+ :generate_text_part => true
16
+ }
17
+ class << self
18
+ attr_accessor :config
19
+ end
20
+ end
21
+ end
22
+
23
+ ActionMailer::Base.register_interceptor(Premailer::Rails::Hook)
@@ -0,0 +1,58 @@
1
+ require 'open-uri'
2
+ require 'zlib'
3
+
4
+ class Premailer
5
+ module Rails
6
+ module CSSHelper
7
+ extend self
8
+
9
+ @cache = {}
10
+ attr :cache
11
+
12
+ STRATEGIES = [
13
+ CSSLoaders::CacheLoader,
14
+ CSSLoaders::AssetPipelineLoader,
15
+ CSSLoaders::FileSystemLoader
16
+ ]
17
+
18
+ # Returns all linked CSS files concatenated as string.
19
+ def css_for_doc(doc)
20
+ urls = css_urls_in_doc(doc)
21
+ urls.map { |url| load_css(url) }.join("\n")
22
+ end
23
+
24
+ private
25
+
26
+ def css_urls_in_doc(doc)
27
+ doc.search('link[@type="text/css"]').map do |link|
28
+ link.attributes['href'].to_s
29
+ end
30
+ end
31
+
32
+ def has_inline_css?(doc)
33
+ not doc.search('style[@type="text/css"]').empty?
34
+ end
35
+
36
+ def load_css(url)
37
+ path = extract_path(url)
38
+
39
+ @cache[path] = STRATEGIES.each do |strategy|
40
+ css = strategy.load(path)
41
+ break css if css
42
+ end
43
+ end
44
+
45
+ # Extracts the path of a url.
46
+ def extract_path(url)
47
+ if url.is_a? String
48
+ # Remove everything after ? including ?
49
+ url = url[0..(url.index('?') - 1)] if url.include? '?'
50
+ # Remove the host
51
+ url = url.sub(/^https?\:\/\/[^\/]*/, '') if url.index('http') == 0
52
+ end
53
+
54
+ url
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,66 @@
1
+ class Premailer
2
+ module Rails
3
+ module CSSLoaders
4
+ # Loads the CSS from cache when not in development env.
5
+ module CacheLoader
6
+ extend self
7
+
8
+ def load(path)
9
+ unless ::Rails.env.development?
10
+ CSSHelper.cache[path]
11
+ end
12
+ end
13
+ end
14
+
15
+ # Loads the CSS from the asset pipeline.
16
+ module AssetPipelineLoader
17
+ extend self
18
+
19
+ def load(path)
20
+ if assets_enabled?
21
+ file = file_name(path)
22
+ if asset = ::Rails.application.assets.find_asset(file)
23
+ asset.to_s
24
+ else
25
+ request_and_unzip(file)
26
+ end
27
+ end
28
+ end
29
+
30
+ def assets_enabled?
31
+ ::Rails.configuration.assets.enabled rescue false
32
+ end
33
+
34
+ def file_name(path)
35
+ path.sub("#{::Rails.configuration.assets.prefix}/", '') \
36
+ .sub(/-.*\.css$/, '.css')
37
+ end
38
+
39
+ def request_and_unzip(file)
40
+ url = [
41
+ ::Rails.configuration.action_controller.asset_host,
42
+ ::Rails.configuration.assets.prefix.sub(/^\//, ''),
43
+ ::Rails.configuration.assets.digests[file]
44
+ ].join('/')
45
+ response = Kernel.open(url)
46
+
47
+ begin
48
+ Zlib::GzipReader.new(response).read
49
+ rescue Zlib::GzipFile::Error, Zlib::Error
50
+ response.rewind
51
+ response.read
52
+ end
53
+ end
54
+ end
55
+
56
+ # Loads the CSS from the file system.
57
+ module FileSystemLoader
58
+ extend self
59
+
60
+ def load(path)
61
+ File.read("#{::Rails.root}/public#{path}")
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,20 @@
1
+ class Premailer
2
+ module Rails
3
+ class CustomizedPremailer < ::Premailer
4
+ def initialize(html)
5
+ # In order to pass the CSS as string to super it is necessary to access
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.
11
+ @options = Rails.config.merge(:with_html_string => true)
12
+ Premailer.send(:include, Adapter.find(Adapter.use))
13
+ doc = load_html(html)
14
+
15
+ options = @options.merge(:css_string => CSSHelper.css_for_doc(doc))
16
+ super(html, options)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,45 @@
1
+ class Premailer
2
+ module Rails
3
+ class Hook
4
+ def self.delivering_email(message)
5
+ # If the mail only has one part, it may be stored in message.body. In that
6
+ # case, if the mail content type is text/html, the body part will be the
7
+ # html body.
8
+ if message.html_part
9
+ html_body = message.html_part.body.to_s
10
+ needs_multipart = true
11
+ message.parts.delete(message.html_part)
12
+ elsif message.content_type =~ /text\/html/
13
+ html_body = message.body.to_s
14
+ message.body = nil
15
+ needs_multipart = Rails.config[:generate_text_part]
16
+ end
17
+
18
+ if html_body
19
+ premailer = CustomizedPremailer.new(html_body)
20
+ charset = message.charset
21
+
22
+ if needs_multipart
23
+ # IMPORTANT: Plain text part must be generated before CSS is inlined.
24
+ # Not doing so results in CSS declarations visible in the plain text
25
+ # part.
26
+ if Rails.config[:generate_text_part] \
27
+ and not message.text_part
28
+ message.text_part do
29
+ content_type "text/plain; charset=#{charset}"
30
+ body premailer.to_plain_text
31
+ end
32
+ end
33
+
34
+ message.html_part do
35
+ content_type "text/html; charset=#{charset}"
36
+ body premailer.to_inline_css
37
+ end
38
+ else
39
+ message.body = premailer.to_inline_css
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,13 @@
1
+ require 'premailer/adapter/nokogiri'
2
+
3
+ Premailer::Adapter::Nokogiri.module_eval do
4
+ # Patch load_html method to fix character encoding issues.
5
+ def load_html(html)
6
+ if RUBY_VERSION.to_f >= 1.9
7
+ html = html.force_encoding('UTF-8').encode!
8
+ ::Nokogiri::HTML(html) {|c| c.recover }
9
+ else
10
+ ::Nokogiri::HTML(html, nil, 'UTF-8') {|c| c.recover }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,20 @@
1
+ class Premailer
2
+ module Rails
3
+ class CustomizedPremailer < ::Premailer
4
+ def initialize(html)
5
+ # In order to pass the CSS as string to super it is necessary to access
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.
11
+ @options = Rails.config.merge(:with_html_string => true)
12
+ Premailer.send(:include, Adapter.find(Adapter.use))
13
+ doc = load_html(html)
14
+
15
+ options = @options.merge(:css_string => CSSHelper.css_for_doc(doc))
16
+ super(html, options)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ class Premailer
2
+ module Rails
3
+ VERSION = File.read(
4
+ File.expand_path('../../../../VERSION', __FILE__)
5
+ ).strip
6
+ end
7
+ end
@@ -0,0 +1,23 @@
1
+ require 'premailer'
2
+ require 'action_mailer'
3
+
4
+ require 'premailer/rails/css_loaders'
5
+ require 'premailer/rails/css_helper'
6
+ require 'premailer/rails/customized_premailer'
7
+ require 'premailer/rails/hook'
8
+ require 'premailer/rails/nokogiri_fix'
9
+
10
+ class Premailer
11
+ module Rails
12
+ @config = {
13
+ :input_encoding => 'UTF-8',
14
+ :inputencoding => 'UTF-8',
15
+ :generate_text_part => true
16
+ }
17
+ class << self
18
+ attr_accessor :config
19
+ end
20
+ end
21
+ end
22
+
23
+ ActionMailer::Base.register_interceptor(Premailer::Rails::Hook)
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "premailer/rails/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "premailer-rails"
7
+ s.version = Premailer::Rails::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Philipe Fatio"]
10
+ s.email = ["philipe.fatio@gmail.com"]
11
+ s.homepage = "https://github.com/fphilipe/premailer-rails"
12
+ s.summary = %q{Easily create styled HTML emails in Rails.}
13
+ s.description = %q{This gem brings you the power of the premailer gem to Rails
14
+ without any configuration needs. Create HTML emails,
15
+ include a CSS file as you do in a normal HTML document and
16
+ premailer will inline the included CSS.}
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+
23
+ s.add_dependency("premailer", ["~> 1.7"])
24
+ s.add_dependency("rails", [">= 3"])
25
+
26
+ s.add_development_dependency 'rspec-core'
27
+ s.add_development_dependency 'rspec-expectations'
28
+ s.add_development_dependency 'mocha'
29
+ s.add_development_dependency 'mail'
30
+ s.add_development_dependency 'nokogiri'
31
+ s.add_development_dependency 'hpricot'
32
+ end
@@ -0,0 +1,42 @@
1
+ module Fixtures
2
+ module HTML
3
+ extend self
4
+
5
+ TEMPLATE = <<-HTML
6
+ <html>
7
+ <head>
8
+ %s
9
+ </head>
10
+ <body>
11
+ <p>
12
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
13
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
14
+ veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
15
+ commodo consequat.
16
+ </p>
17
+ </body>
18
+ </html>
19
+ HTML
20
+
21
+ LINK = <<-LINK
22
+ <link rel='stylesheet' type='text/css' href='%s' />
23
+ LINK
24
+
25
+ def with_css_links(*files)
26
+ links = []
27
+ files.each do |file|
28
+ links << LINK % "http://example.com/#{file}"
29
+ end
30
+
31
+ TEMPLATE % links.join
32
+ end
33
+
34
+ def with_no_css_link
35
+ with_css_links
36
+ end
37
+
38
+ def with_style_block
39
+ TEMPLATE % '<style type="text/css">p { color: red; }</style>'
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,86 @@
1
+ require 'mail'
2
+
3
+ module Fixtures
4
+ module Message
5
+ extend self
6
+
7
+ HTML_PART = <<-HTML
8
+ <html>
9
+ <head>
10
+ </head>
11
+ <body>
12
+ <p>
13
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
14
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
15
+ veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
16
+ commodo consequat.
17
+ </p>
18
+ </body>
19
+ </html>
20
+ HTML
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
+
40
+ TEXT_PART = <<-TEXT
41
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
42
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
43
+ nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
44
+ TEXT
45
+
46
+ def with_parts(*part_types)
47
+ message = base_message
48
+
49
+ message.html_part do
50
+ body HTML_PART
51
+ content_type 'text/html; charset=UTF-8'
52
+ end if part_types.include? :html
53
+
54
+ message.text_part do
55
+ body TEXT_PART
56
+ content_type 'text/plain; charset=UTF-8'
57
+ end if part_types.include? :text
58
+
59
+ message
60
+ end
61
+
62
+ def with_body(body_type)
63
+ message = base_message
64
+
65
+ case body_type
66
+ when :html
67
+ message.body = HTML_PART
68
+ message.content_type 'text/html; charset=UTF-8'
69
+ when :text
70
+ message.body = TEXT_PART
71
+ message.content_type 'text/plain; charset=UTF-8'
72
+ end
73
+
74
+ message
75
+ end
76
+
77
+ private
78
+
79
+ def base_message
80
+ Mail.new do
81
+ to 'some@email.com'
82
+ subject 'testing premailer-rails3'
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,160 @@
1
+ require 'spec_helper'
2
+
3
+ describe Premailer::Rails::CSSHelper do
4
+ # Reset the CSS cache
5
+ after { Premailer::Rails::CSSHelper.send(:instance_variable_set, '@cache', {}) }
6
+
7
+ def load_css(path)
8
+ Premailer::Rails::CSSHelper.send(:load_css, path)
9
+ end
10
+
11
+ def css_for_doc(doc)
12
+ Premailer::Rails::CSSHelper.css_for_doc(doc)
13
+ end
14
+
15
+ describe '#css_for_doc' do
16
+ let(:html) { Fixtures::HTML.with_css_links(*files) }
17
+ let(:doc) { Hpricot(html) }
18
+
19
+ context 'when HTML contains linked CSS files' do
20
+ let(:files) { %w[ stylesheets/base.css stylesheets/font.css ] }
21
+
22
+ it 'should return the content of both files concatenated' do
23
+ Premailer::Rails::CSSHelper \
24
+ .expects(:load_css) \
25
+ .with('http://example.com/stylesheets/base.css') \
26
+ .returns('content of base.css')
27
+ Premailer::Rails::CSSHelper \
28
+ .expects(:load_css) \
29
+ .with('http://example.com/stylesheets/font.css') \
30
+ .returns('content of font.css')
31
+
32
+ css_for_doc(doc).should == "content of base.css\ncontent of font.css"
33
+ end
34
+ end
35
+ end
36
+
37
+ describe '#load_css' do
38
+ context 'when path is a url' do
39
+ it 'should load the CSS at the local path' do
40
+ File.expects(:read).with('RAILS_ROOT/public/stylesheets/base.css')
41
+
42
+ load_css('http://example.com/stylesheets/base.css?test')
43
+ end
44
+ end
45
+
46
+ context 'when path is a relative url' do
47
+ it 'should load the CSS at the local path' do
48
+ File.expects(:read).with('RAILS_ROOT/public/stylesheets/base.css')
49
+
50
+ load_css('/stylesheets/base.css?test')
51
+ end
52
+ end
53
+
54
+ context 'when file is cached' do
55
+ it 'should return the cached value' do
56
+ cache =
57
+ Premailer::Rails::CSSHelper.send(:instance_variable_get, '@cache')
58
+ cache['/stylesheets/base.css'] = 'content of base.css'
59
+
60
+ load_css('http://example.com/stylesheets/base.css') \
61
+ .should == 'content of base.css'
62
+ end
63
+ end
64
+
65
+ context 'when in development mode' do
66
+ it 'should not return cached values' do
67
+ cache =
68
+ Premailer::Rails::CSSHelper.send(:instance_variable_get, '@cache')
69
+ cache['/stylesheets/base.css'] = 'cached content of base.css'
70
+ File.expects(:read) \
71
+ .with('RAILS_ROOT/public/stylesheets/base.css') \
72
+ .returns('new content of base.css')
73
+ Rails.env.stubs(:development?).returns(true)
74
+
75
+ load_css('http://example.com/stylesheets/base.css') \
76
+ .should == 'new content of base.css'
77
+ end
78
+ end
79
+
80
+ context 'when Rails asset pipeline is used' do
81
+ before {
82
+ Rails.configuration.stubs(:assets).returns(
83
+ stub(
84
+ :enabled => true,
85
+ :prefix => '/assets'
86
+ )
87
+ )
88
+ }
89
+
90
+ it 'should return the content of the file compiled by Rails' do
91
+ Rails.application.assets.expects(:find_asset) \
92
+ .with('base.css') \
93
+ .returns(mock(:to_s => 'content of base.css'))
94
+
95
+ load_css('http://example.com/assets/base.css') \
96
+ .should == 'content of base.css'
97
+ end
98
+
99
+ it 'should return same file when path contains file fingerprint' do
100
+ Rails.application.assets \
101
+ .expects(:find_asset) \
102
+ .with('base.css') \
103
+ .returns(mock(:to_s => 'content of base.css'))
104
+
105
+ load_css(
106
+ 'http://example.com/assets/base-089e35bd5d84297b8d31ad552e433275.css'
107
+ ).should == 'content of base.css'
108
+ end
109
+
110
+ context 'when asset can not be found' do
111
+ before {
112
+ Rails.application.assets.stubs(:find_asset).returns(nil)
113
+ Rails.configuration.stubs(:action_controller).returns(
114
+ stub(:asset_host => 'http://example.com')
115
+ )
116
+ Rails.configuration.stubs(:assets).returns(
117
+ stub(
118
+ :enabled => true,
119
+ :prefix => '/assets',
120
+ :digests => {
121
+ 'base.css' => 'base-089e35bd5d84297b8d31ad552e433275.css'
122
+ }
123
+ )
124
+ )
125
+ }
126
+ let(:string_io) { StringIO.new('content of base.css') }
127
+ let(:url) {
128
+ 'http://example.com/assets/base-089e35bd5d84297b8d31ad552e433275.css'
129
+ }
130
+
131
+ it 'should request the file' do
132
+ Kernel.expects(:open).with(url).returns(string_io)
133
+
134
+ load_css(
135
+ 'http://example.com/assets/base.css'
136
+ ).should == 'content of base.css'
137
+ end
138
+
139
+ it 'should request the same file when path contains file fingerprint' do
140
+ Kernel.expects(:open).with(url).returns(string_io)
141
+
142
+ load_css(
143
+ 'http://example.com/assets/base-089e35bd5d84297b8d31ad552e433275.css'
144
+ ).should == 'content of base.css'
145
+ end
146
+ end
147
+ end
148
+
149
+ context 'when static stylesheets are used' do
150
+ it 'should return the content of the static file' do
151
+ File.expects(:read) \
152
+ .with('RAILS_ROOT/public/stylesheets/base.css') \
153
+ .returns('content of base.css')
154
+
155
+ load_css('http://example.com/stylesheets/base.css') \
156
+ .should == 'content of base.css'
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,62 @@
1
+ # coding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Premailer::Rails::CustomizedPremailer do
6
+ [ :nokogiri, :hpricot ].each do |adapter|
7
+ context "when adapter is #{adapter}" do
8
+ before { Premailer::Adapter.stubs(:use).returns(adapter) }
9
+
10
+ describe '#to_plain_text' do
11
+ it 'should include the text from the HTML part' do
12
+ premailer =
13
+ Premailer::Rails::CustomizedPremailer \
14
+ .new(Fixtures::Message::HTML_PART)
15
+ premailer.to_plain_text.gsub(/\s/, ' ').strip \
16
+ .should == Fixtures::Message::TEXT_PART.gsub(/\s/, ' ').strip
17
+ end
18
+ end
19
+
20
+ describe '#to_inline_css' do
21
+ context 'when inline CSS block present' do
22
+ it 'should return the HTML with the CSS inlined' do
23
+ Premailer::Rails::CSSHelper \
24
+ .stubs(:css_for_doc) \
25
+ .returns('p { color: red; }')
26
+ html = Fixtures::Message::HTML_PART
27
+ premailer = Premailer::Rails::CustomizedPremailer.new(html)
28
+ premailer.to_inline_css.should include '<p style="color: red;">'
29
+ end
30
+ end
31
+
32
+ context 'when CSS is loaded externally' do
33
+ it 'should return the HTML with the CSS inlined' do
34
+ html = Fixtures::Message::HTML_PART_WITH_CSS
35
+ premailer = Premailer::Rails::CustomizedPremailer.new(html)
36
+ premailer.to_inline_css.should include '<p style="color: red;">'
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ describe '.new' do
44
+ it 'should extract the CSS' do
45
+ Premailer::Rails::CSSHelper.expects(:css_for_doc)
46
+ Premailer::Rails::CustomizedPremailer.new('some html')
47
+ end
48
+
49
+ it 'should pass on the configs' do
50
+ Premailer::Rails.config = { :foo => :bar }
51
+ premailer = Premailer::Rails::CustomizedPremailer.new('some html')
52
+ premailer.instance_variable_get(:'@options')[:foo].should == :bar
53
+ end
54
+
55
+ it 'should not allow to override with_html_string' do
56
+ Premailer::Rails.config = { :with_html_string => false }
57
+ premailer = Premailer::Rails::CustomizedPremailer.new('some html')
58
+ options = premailer.instance_variable_get(:'@options')
59
+ options[:with_html_string].should == true
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ActionMailer::Base.register_interceptor' do
4
+ it 'should register interceptor Premailer::Rails::Hook' do
5
+ ActionMailer::Base \
6
+ .expects(:register_interceptor) \
7
+ .with(Premailer::Rails::Hook)
8
+ load 'premailer/rails3.rb'
9
+ end
10
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe Premailer::Rails::Hook do
4
+ describe '.delivering_email' do
5
+ before { File.stubs(:read).returns('') }
6
+ def run_hook(message)
7
+ Premailer::Rails::Hook.delivering_email(message)
8
+ end
9
+
10
+ context 'when message contains html part' do
11
+ let(:message) { Fixtures::Message.with_parts :html }
12
+
13
+ it 'should create a text part from the html part' do
14
+ Premailer::Rails::CustomizedPremailer \
15
+ .any_instance.expects(:to_plain_text)
16
+ run_hook(message)
17
+ message.text_part.should be_a Mail::Part
18
+ end
19
+
20
+ it 'should inline the css in the html part' do
21
+ Premailer::Rails::CustomizedPremailer \
22
+ .any_instance.expects(:to_inline_css)
23
+ run_hook(message)
24
+ end
25
+
26
+ it 'should not create a text part if disabled' do
27
+ Premailer::Rails::CustomizedPremailer \
28
+ .any_instance.expects(:to_plain_text).never
29
+ Premailer::Rails.config[:generate_text_part] = false
30
+ run_hook(message)
31
+ Premailer::Rails.config[:generate_text_part] = true
32
+ message.text_part.should be_nil
33
+ message.html_part.should be_a Mail::Part
34
+ end
35
+
36
+ it 'should not create an additional html part' do
37
+ run_hook(message)
38
+ message.parts.count { |i| i.content_type =~ /text\/html/ }.should == 1
39
+ end
40
+ end
41
+
42
+ context 'when message contains text part' do
43
+ let(:message) { Fixtures::Message.with_parts :text }
44
+
45
+ it 'should not modify the message' do
46
+ Premailer.expects(:new).never
47
+ run_hook(message)
48
+ end
49
+ end
50
+
51
+ context 'when message contains html and text part' do
52
+ let(:message) { Fixtures::Message.with_parts :html, :text }
53
+
54
+ it 'should not create a text part from the html part' do
55
+ Premailer::Rails::CustomizedPremailer \
56
+ .any_instance.expects(:to_plain_text).never
57
+ run_hook(message)
58
+ message.text_part.should be_a Mail::Part
59
+ end
60
+
61
+ it 'should inline the css in the html part' do
62
+ Premailer::Rails::CustomizedPremailer \
63
+ .any_instance.expects(:to_inline_css)
64
+ run_hook(message)
65
+ end
66
+ end
67
+
68
+ context 'when message contains html body' do
69
+ let(:message) { Fixtures::Message.with_body :html }
70
+
71
+ it 'should create a text part from the html part' do
72
+ Premailer::Rails::CustomizedPremailer \
73
+ .any_instance.expects(:to_plain_text)
74
+ run_hook(message)
75
+ end
76
+
77
+ it 'should create a html part and inline the css' do
78
+ Premailer::Rails::CustomizedPremailer \
79
+ .any_instance.expects(:to_inline_css)
80
+ run_hook(message)
81
+ message.html_part.should be_a Mail::Part
82
+ end
83
+
84
+ it 'should not create a text part if disabled' do
85
+ Premailer::Rails::CustomizedPremailer \
86
+ .any_instance.expects(:to_plain_text).never
87
+ Premailer::Rails.config[:generate_text_part] = false
88
+ run_hook(message)
89
+ Premailer::Rails.config[:generate_text_part] = true
90
+ message.text_part.should be_nil
91
+ message.html_part.should be_nil
92
+ message.body.should_not be_empty
93
+ end
94
+ end
95
+
96
+ context 'when message contains text body' do
97
+ let(:message) { Fixtures::Message.with_body :text }
98
+
99
+ it 'should not modify the message' do
100
+ Premailer.expects(:new).never
101
+ run_hook(message)
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Premailer::Rails do
4
+ describe '#config' do
5
+ subject { Premailer::Rails.config }
6
+ context 'when set' do
7
+ before { Premailer::Rails.config = { :foo => :bar } }
8
+ it { should == { :foo => :bar } }
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ require 'premailer/rails'
2
+
3
+ require 'stubs/action_mailer'
4
+ require 'stubs/rails'
5
+ require 'fixtures/message'
6
+ require 'fixtures/html'
7
+
8
+ require 'hpricot'
9
+ require 'nokogiri'
10
+
11
+ RSpec.configure do |config|
12
+ config.mock_with :mocha
13
+ end
@@ -0,0 +1,5 @@
1
+ module ActionMailer
2
+ class Base
3
+ def self.register_interceptor(x); end
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Dummy
2
+ def method_missing(m, *args)
3
+ self.class.new
4
+ end
5
+ end
@@ -0,0 +1,65 @@
1
+ require 'stubs/dummy'
2
+
3
+ class Logger
4
+ def self.try(*args); end
5
+ end
6
+
7
+ module Rails
8
+ extend self
9
+
10
+ module Configuration
11
+ extend self
12
+
13
+ module Middleware
14
+ extend self
15
+
16
+ def include?(what)
17
+ false
18
+ end
19
+ end
20
+
21
+ def middleware
22
+ Middleware
23
+ end
24
+ end
25
+
26
+ module Env
27
+ extend self
28
+
29
+ def development?
30
+ false
31
+ end
32
+ end
33
+
34
+ module Application
35
+ extend self
36
+
37
+ module Assets
38
+ extend self
39
+ end
40
+
41
+ def assets
42
+ Assets
43
+ end
44
+ end
45
+
46
+ def env
47
+ Env
48
+ end
49
+
50
+ def configuration
51
+ Configuration
52
+ end
53
+
54
+ def logger
55
+ Logger
56
+ end
57
+
58
+ def root
59
+ 'RAILS_ROOT'
60
+ end
61
+
62
+ def application
63
+ Application
64
+ end
65
+ end
metadata ADDED
@@ -0,0 +1,201 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: premailer-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.3.2
5
+ platform: ruby
6
+ authors:
7
+ - Philipe Fatio
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-03-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: premailer
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-core
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-expectations
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: mocha
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: mail
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: nokogiri
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: hpricot
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: |-
126
+ This gem brings you the power of the premailer gem to Rails
127
+ without any configuration needs. Create HTML emails,
128
+ include a CSS file as you do in a normal HTML document and
129
+ premailer will inline the included CSS.
130
+ email:
131
+ - philipe.fatio@gmail.com
132
+ executables: []
133
+ extensions: []
134
+ extra_rdoc_files: []
135
+ files:
136
+ - .gitignore
137
+ - .rspec
138
+ - .travis.yml
139
+ - CHANGELOG.md
140
+ - Gemfile
141
+ - LICENSE
142
+ - README.md
143
+ - Rakefile
144
+ - VERSION
145
+ - lib/premailer/rails.rb
146
+ - lib/premailer/rails/css_helper.rb
147
+ - lib/premailer/rails/css_loaders.rb
148
+ - lib/premailer/rails/customized_premailer.rb
149
+ - lib/premailer/rails/hook.rb
150
+ - lib/premailer/rails/nokogiri_fix.rb
151
+ - lib/premailer/rails/premailer.rb
152
+ - lib/premailer/rails/version.rb
153
+ - lib/premailer/rails3.rb
154
+ - premailer-rails.gemspec
155
+ - spec/fixtures/html.rb
156
+ - spec/fixtures/message.rb
157
+ - spec/lib/css_helper_spec.rb
158
+ - spec/lib/customized_premailer_spec.rb
159
+ - spec/lib/hook_registration_spec.rb
160
+ - spec/lib/hook_spec.rb
161
+ - spec/lib/premailer_rails_3_spec.rb
162
+ - spec/spec_helper.rb
163
+ - spec/stubs/action_mailer.rb
164
+ - spec/stubs/dummy.rb
165
+ - spec/stubs/rails.rb
166
+ homepage: https://github.com/fphilipe/premailer-rails
167
+ licenses: []
168
+ metadata: {}
169
+ post_install_message:
170
+ rdoc_options: []
171
+ require_paths:
172
+ - lib
173
+ required_ruby_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - '>='
176
+ - !ruby/object:Gem::Version
177
+ version: '0'
178
+ required_rubygems_version: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - '>='
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ requirements: []
184
+ rubyforge_project:
185
+ rubygems_version: 2.0.0
186
+ signing_key:
187
+ specification_version: 4
188
+ summary: Easily create styled HTML emails in Rails.
189
+ test_files:
190
+ - spec/fixtures/html.rb
191
+ - spec/fixtures/message.rb
192
+ - spec/lib/css_helper_spec.rb
193
+ - spec/lib/customized_premailer_spec.rb
194
+ - spec/lib/hook_registration_spec.rb
195
+ - spec/lib/hook_spec.rb
196
+ - spec/lib/premailer_rails_3_spec.rb
197
+ - spec/spec_helper.rb
198
+ - spec/stubs/action_mailer.rb
199
+ - spec/stubs/dummy.rb
200
+ - spec/stubs/rails.rb
201
+ has_rdoc: