Skip to content

Commit

Permalink
Updated the gem to be compatible with Rails 3.1 asset pipeline.
Browse files Browse the repository at this point in the history
NOTE: Does not work with older Rails versions!
  • Loading branch information
Arttu Tervo committed Oct 12, 2011
1 parent 955d1c7 commit b728b81
Show file tree
Hide file tree
Showing 17 changed files with 95 additions and 77 deletions.
43 changes: 22 additions & 21 deletions Gemfile.lock
Expand Up @@ -2,43 +2,43 @@ PATH
remote: .
specs:
roadie (1.1.3)
actionmailer (~> 3.0)
actionmailer (~> 3.1.0)
css_parser
nokogiri (>= 1.4.4)
sprockets

GEM
remote: http://rubygems.org/
specs:
actionmailer (3.1.0)
actionpack (= 3.1.0)
actionmailer (3.1.1)
actionpack (= 3.1.1)
mail (~> 2.3.0)
actionpack (3.1.0)
activemodel (= 3.1.0)
activesupport (= 3.1.0)
actionpack (3.1.1)
activemodel (= 3.1.1)
activesupport (= 3.1.1)
builder (~> 3.0.0)
erubis (~> 2.7.0)
i18n (~> 0.6)
rack (~> 1.3.2)
rack-cache (~> 1.0.3)
rack-cache (~> 1.1)
rack-mount (~> 0.8.2)
rack-test (~> 0.6.1)
sprockets (~> 2.0.0)
activemodel (3.1.0)
activesupport (= 3.1.0)
bcrypt-ruby (~> 3.0.0)
sprockets (~> 2.0.2)
activemodel (3.1.1)
activesupport (= 3.1.1)
builder (~> 3.0.0)
i18n (~> 0.6)
activesupport (3.1.0)
activesupport (3.1.1)
multi_json (~> 1.0)
addressable (2.2.6)
bcrypt-ruby (3.0.0)
builder (3.0.0)
css_parser (1.2.5)
addressable
diff-lcs (1.1.3)
erubis (2.7.0)
hike (1.2.1)
i18n (0.6.0)
json (1.6.1)
mail (2.3.0)
i18n (>= 0.4.0)
mime-types (~> 1.16)
Expand All @@ -47,24 +47,25 @@ GEM
multi_json (1.0.3)
nokogiri (1.5.0)
polyglot (0.3.2)
rack (1.3.2)
rack-cache (1.0.3)
rack (1.3.4)
rack-cache (1.1)
rack (>= 0.4)
rack-mount (0.8.3)
rack (>= 1.0.0)
rack-ssl (1.3.2)
rack
rack-test (0.6.1)
rack (>= 1.0)
railties (3.1.0)
actionpack (= 3.1.0)
activesupport (= 3.1.0)
railties (3.1.1)
actionpack (= 3.1.1)
activesupport (= 3.1.1)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (~> 0.14.6)
rake (0.9.2)
rdoc (3.9.4)
rdoc (3.10)
json (~> 1.4)
rspec (2.6.0)
rspec-core (~> 2.6.0)
rspec-expectations (~> 2.6.0)
Expand All @@ -78,10 +79,10 @@ GEM
activesupport (~> 3.0)
railties (~> 3.0)
rspec (~> 2.6.0)
sprockets (2.0.0)
sprockets (2.0.2)
hike (~> 1.2)
rack (~> 1.0)
tilt (!= 1.3.0, ~> 1.1)
tilt (~> 1.1, != 1.3.0)
thor (0.14.6)
tilt (1.3.3)
treetop (1.4.10)
Expand Down
23 changes: 7 additions & 16 deletions lib/roadie.rb
Expand Up @@ -5,29 +5,20 @@ def self.inline_css(*args)
Roadie::Inliner.new(*args).execute
end

# Tries to load the CSS "names" specified in the +targets+ parameter inside the +root+ path.
# Tries to load the CSS "names" specified in the +targets+ parameter using the Rails asset pipeline.
#
# @example
# Roadie.load_css(Rails.root, %w[application newsletter])
# Roadie.load_css(%w[application newsletter])
#
# @param [Pathname] root The root path of your stylesheets
# @param [Array<String, Symbol>] targets Stylesheet names - <b>without extensions</b>
# @return [String] The combined contents of the CSS files
# @raise [CSSFileNotFound] When a target cannot be found under +[root]/[target].css+
def self.load_css(root, targets)
css_files_from_targets(root, targets).map do |file|
raise CSSFileNotFound, file unless file.exist?
file.read
# @raise [CSSFileNotFound] When a target cannot be found from Rails assets
def self.load_css(targets)
targets.map do |file|
raise CSSFileNotFound, file unless Rails.application.assets[file]
Rails.application.assets[file].to_s.strip
end.join("\n")
end

private
def self.css_files_from_targets(root, targets)
targets.map do |target|
target = "#{target}.css" unless target.to_s.end_with? '.css'
root.join(target)
end
end
end

require 'roadie/version'
Expand Down
6 changes: 1 addition & 5 deletions lib/roadie/action_mailer_extensions.rb
Expand Up @@ -32,10 +32,6 @@ def url_options
Rails.application.config.action_mailer.default_url_options
end

def stylesheet_root
Rails.root.join('public', 'stylesheets')
end

def inline_style_response(response)
if response[:content_type] == 'text/html'
response.merge :body => Roadie.inline_css(css_rules, response[:body], url_options)
Expand All @@ -50,7 +46,7 @@ def css_targets
end

def css_rules
@css_rules ||= Roadie.load_css(stylesheet_root, css_targets) if css_targets.present?
@css_rules ||= Roadie.load_css(css_targets) if css_targets.present?
end
end
end
14 changes: 7 additions & 7 deletions lib/roadie/inliner.rb
Expand Up @@ -25,12 +25,13 @@ class Inliner
#
# @param [String] css
# @param [String] html
# @param [Hash] url_options Supported keys: +:host+, +:port+ and +:protocol+
# @param [Hash] url_options Supported keys: +:host+, +:port+, +:protocol+ and +:asset_path_prefix:+
def initialize(css, html, url_options)
@css = css
@inline_css = []
@html = html
@url_options = url_options
@asset_path_prefix = (url_options && url_options[:asset_path_prefix] || "/assets/")
end

# Start the inlining and return the final HTML output
Expand Down Expand Up @@ -91,12 +92,11 @@ def add_missing_structure

def extract_link_elements
all_link_elements_to_be_inlined_with_url.each do |link, url|
# Joining on an "absolute" path ignores everything before the absoluted path
# so we have to remove the starting slash
url_path = url.path.sub(%r{^/}, '')
file_path = Rails.root.join('public', url_path)
raise CSSFileNotFound.new(file_path, link['href']) unless file_path.file?
@inline_css << file_path.read
# Remove asset path prefix from url and pass the rest to Rails asset pipeline
asset_filename = url.path.gsub(@asset_path_prefix, '')
asset = Rails.application.assets[asset_filename]
raise CSSFileNotFound.new(asset_filename, link['href']) if !asset
@inline_css << asset.to_s
link.remove
end
end
Expand Down
3 changes: 2 additions & 1 deletion roadie.gemspec
Expand Up @@ -16,7 +16,8 @@ Gem::Specification.new do |s|

s.add_dependency 'nokogiri', '>= 1.4.4'
s.add_dependency 'css_parser'
s.add_dependency 'actionmailer', '~> 3.0'
s.add_dependency 'actionmailer', '~> 3.1.0'
s.add_dependency 'sprockets'

s.add_development_dependency 'rspec-rails', '>= 2.0.0'

Expand Down
File renamed without changes.
File renamed without changes.
@@ -0,0 +1 @@
can you really find me?
@@ -0,0 +1 @@
p { color: green; }
5 changes: 5 additions & 0 deletions spec/integration_spec.rb
Expand Up @@ -5,6 +5,11 @@ class TestApplication
def config
OpenStruct.new(:action_mailer => OpenStruct.new(:default_url_options => {:host => "example.app.org"}))
end
def assets
env = ::Sprockets::Environment.new
env.append_path FixturesPath
env
end
end

class IntegrationMailer < ActionMailer::Base
Expand Down
8 changes: 4 additions & 4 deletions spec/lib/roadie/action_mailer_extensions_spec.rb
Expand Up @@ -80,17 +80,17 @@ def with_empty_html_response
end

it "loads css from Rails' stylesheet root" do
Roadie.should_receive(:load_css).with(Rails.root.join('public', 'stylesheets'), anything).and_return('')
Roadie.should_receive(:load_css).with(anything).and_return('')
CssLoadingMailer.use_default
end

it "loads the css specified in the default mailer settings" do
Roadie.should_receive(:load_css).with(anything, ['default_value']).and_return('')
Roadie.should_receive(:load_css).with(['default_value']).and_return('')
CssLoadingMailer.use_default
end

it "loads the css specified in the specific mailer action instead of the default choice" do
Roadie.should_receive(:load_css).with(anything, ['specific']).and_return('')
Roadie.should_receive(:load_css).with(['specific']).and_return('')
CssLoadingMailer.override(:specific)
end

Expand All @@ -100,7 +100,7 @@ def with_empty_html_response
end

it "loads multiple css files when given an array" do
Roadie.should_receive(:load_css).with(anything, ['specific', 'other']).and_return('')
Roadie.should_receive(:load_css).with(['specific', 'other']).and_return('')
CssLoadingMailer.override([:specific, :other])
end
end
39 changes: 26 additions & 13 deletions spec/lib/roadie/inliner_spec.rb
Expand Up @@ -157,7 +157,20 @@ def rendering(html, options = {})
rendering(<<-HTML).should have_styling('color' => 'green').at_selector('p')
<html>
<head>
<link rel="stylesheet" href="/stylesheets/green_paragraphs.css">
<link rel="stylesheet" href="/assets/green_paragraphs.css">
</head>
<body>
<p></p>
</body>
</html>
HTML
end

it "inlines styles from the linked stylesheet in subdirectory" do
rendering(<<-HTML).should have_styling('color' => 'green').at_selector('p')
<html>
<head>
<link rel="stylesheet" href="/assets/subdirectory/red_paragraphs.css">
</head>
<body>
<p></p>
Expand All @@ -170,8 +183,8 @@ def rendering(html, options = {})
html = <<-HTML
<html>
<head>
<link rel="stylesheet" href="/stylesheets/green_paragraphs.css">
<link rel="stylesheet" href="/stylesheets/large_purple_paragraphs.css">
<link rel="stylesheet" href="/assets/green_paragraphs.css">
<link rel="stylesheet" href="/assets/large_purple_paragraphs.css">
</head>
<body>
<p></p>
Expand All @@ -189,8 +202,8 @@ def rendering(html, options = {})
rendering(<<-HTML).should_not have_selector('link')
<html>
<head>
<link rel="stylesheet" href="/stylesheets/green_paragraphs.css">
<link rel="stylesheet" href="/stylesheets/large_purple_paragraphs.css">
<link rel="stylesheet" href="/assets/green_paragraphs.css">
<link rel="stylesheet" href="/assets/large_purple_paragraphs.css">
</head>
<body>
</body>
Expand All @@ -203,7 +216,7 @@ def rendering(html, options = {})
rendering(<<-HTML).should_not have_styling('color' => 'green').at_selector('p')
<html>
<head>
<link rel="stylesheet" href="/stylesheets/green_paragraphs.css" media="print">
<link rel="stylesheet" href="/assets/green_paragraphs.css" media="print">
</head>
<body>
<p></p>
Expand All @@ -216,7 +229,7 @@ def rendering(html, options = {})
rendering(<<-HTML).should have_selector('link')
<html>
<head>
<link rel="stylesheet" href="/stylesheets/green_paragraphs.css" media="print">
<link rel="stylesheet" href="/assets/green_paragraphs.css" media="print">
</head>
<body>
</body>
Expand All @@ -230,7 +243,7 @@ def rendering(html, options = {})
rendering(<<-HTML).should_not have_styling('color' => 'green').at_selector('p')
<html>
<head>
<link rel="stylesheet" href="/stylesheets/green_paragraphs.css" data-immutable="true">
<link rel="stylesheet" href="/assets/green_paragraphs.css" data-immutable="true">
</head>
<body>
<p></p>
Expand All @@ -243,7 +256,7 @@ def rendering(html, options = {})
rendering(<<-HTML).should have_selector('link')
<html>
<head>
<link rel="stylesheet" href="/stylesheets/green_paragraphs.css" data-immutable="true">
<link rel="stylesheet" href="/assets/green_paragraphs.css" data-immutable="true">
</head>
<body>
</body>
Expand Down Expand Up @@ -284,7 +297,7 @@ def rendering(html, options = {})
html = <<-HTML
<html>
<head>
<link rel="stylesheet" href="/stylesheets/not_found.css">
<link rel="stylesheet" href="/assets/not_found.css">
</head>
<body>
</body>
Expand All @@ -293,8 +306,8 @@ def rendering(html, options = {})

expect { rendering(html) }.to raise_error do |error|
error.should be_a(Roadie::CSSFileNotFound)
error.filename.should == Rails.root.join('public', 'stylesheets', 'not_found.css')
error.guess.should == '/stylesheets/not_found.css'
error.filename.should == Rails.application.assets['not_found.css']
error.guess.should == '/assets/not_found.css'
end
end
end
Expand All @@ -304,7 +317,7 @@ def rendering(html, options = {})
html = <<-HTML
<html>
<head>
<link rel="not_stylesheet" href="/stylesheets/green_paragraphs.css">
<link rel="not_stylesheet" href="/assets/green_paragraphs.css">
</head>
<body>
<p></p>
Expand Down
21 changes: 12 additions & 9 deletions spec/lib/roadie_spec.rb
Expand Up @@ -8,21 +8,24 @@
end
end

describe ".load_css(root, targets)" do
let(:fixtures_root) { Pathname.new(__FILE__).dirname.join('..', 'fixtures', 'public', 'stylesheets') }

it "loads files matching the target names under root/public/stylesheets" do
Roadie.load_css(fixtures_root, ['foo']).should == 'contents of foo'
Roadie.load_css(fixtures_root, ['foo.css']).should == 'contents of foo'
describe ".load_css(targets)" do
it "loads files matching the target names in Rails assets" do
Roadie.load_css(['foo']).should == 'contents of foo'
Roadie.load_css(['foo.css']).should == 'contents of foo'
end

it "loads files in order and join them with a newline" do
Roadie.load_css(fixtures_root, %w[foo bar]).should == "contents of foo\ncontents of bar"
Roadie.load_css(fixtures_root, %w[bar foo]).should == "contents of bar\ncontents of foo"
Roadie.load_css(%w[foo bar]).should == "contents of foo\ncontents of bar"
Roadie.load_css(%w[bar foo]).should == "contents of bar\ncontents of foo"
end

it "loads files also from asset subdirectories" do
Roadie.load_css(%w[foo subdirectory/findme.css]).should == "contents of foo\ncan you really find me?"
Roadie.load_css(%w[bar foo]).should == "contents of bar\ncontents of foo"
end

it "raises a Roadie::CSSFileNotFound error when a css file could not be found" do
expect { Roadie.load_css(fixtures_root, ['not_here']) }.to raise_error(Roadie::CSSFileNotFound, /not_here/)
expect { Roadie.load_css(['not_here']) }.to raise_error(Roadie::CSSFileNotFound, /not_here/)
end
end
end

0 comments on commit b728b81

Please sign in to comment.