premailer-rails 1.3.2

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