diff --git a/Gemfile.lock b/Gemfile.lock index 8f745e9..9d7ae0f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,36 +2,35 @@ 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 @@ -39,6 +38,7 @@ GEM 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) @@ -47,8 +47,8 @@ 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) @@ -56,15 +56,16 @@ GEM 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) @@ -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) diff --git a/lib/roadie.rb b/lib/roadie.rb index a975353..d6f680b 100644 --- a/lib/roadie.rb +++ b/lib/roadie.rb @@ -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] targets Stylesheet names - without extensions # @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' diff --git a/lib/roadie/action_mailer_extensions.rb b/lib/roadie/action_mailer_extensions.rb index 7b1dceb..b2b1d13 100644 --- a/lib/roadie/action_mailer_extensions.rb +++ b/lib/roadie/action_mailer_extensions.rb @@ -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) @@ -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 diff --git a/lib/roadie/inliner.rb b/lib/roadie/inliner.rb index 788c9c5..7d855d4 100644 --- a/lib/roadie/inliner.rb +++ b/lib/roadie/inliner.rb @@ -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 @@ -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 diff --git a/roadie.gemspec b/roadie.gemspec index 91e569b..8d10ede 100644 --- a/roadie.gemspec +++ b/roadie.gemspec @@ -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' diff --git a/spec/fixtures/public/stylesheets/bar.css b/spec/fixtures/app/assets/stylesheets/bar.css similarity index 100% rename from spec/fixtures/public/stylesheets/bar.css rename to spec/fixtures/app/assets/stylesheets/bar.css diff --git a/spec/fixtures/public/stylesheets/foo.css b/spec/fixtures/app/assets/stylesheets/foo.css similarity index 100% rename from spec/fixtures/public/stylesheets/foo.css rename to spec/fixtures/app/assets/stylesheets/foo.css diff --git a/spec/fixtures/public/stylesheets/green_paragraphs.css b/spec/fixtures/app/assets/stylesheets/green_paragraphs.css similarity index 100% rename from spec/fixtures/public/stylesheets/green_paragraphs.css rename to spec/fixtures/app/assets/stylesheets/green_paragraphs.css diff --git a/spec/fixtures/public/stylesheets/integration.css b/spec/fixtures/app/assets/stylesheets/integration.css similarity index 100% rename from spec/fixtures/public/stylesheets/integration.css rename to spec/fixtures/app/assets/stylesheets/integration.css diff --git a/spec/fixtures/public/stylesheets/large_purple_paragraphs.css b/spec/fixtures/app/assets/stylesheets/large_purple_paragraphs.css similarity index 100% rename from spec/fixtures/public/stylesheets/large_purple_paragraphs.css rename to spec/fixtures/app/assets/stylesheets/large_purple_paragraphs.css diff --git a/spec/fixtures/app/assets/stylesheets/subdirectory/findme.css b/spec/fixtures/app/assets/stylesheets/subdirectory/findme.css new file mode 100644 index 0000000..cbb5d46 --- /dev/null +++ b/spec/fixtures/app/assets/stylesheets/subdirectory/findme.css @@ -0,0 +1 @@ +can you really find me? \ No newline at end of file diff --git a/spec/fixtures/app/assets/stylesheets/subdirectory/red_paragraphs.css b/spec/fixtures/app/assets/stylesheets/subdirectory/red_paragraphs.css new file mode 100644 index 0000000..d9a4c4e --- /dev/null +++ b/spec/fixtures/app/assets/stylesheets/subdirectory/red_paragraphs.css @@ -0,0 +1 @@ +p { color: green; } diff --git a/spec/integration_spec.rb b/spec/integration_spec.rb index 1d73a24..e21cb8f 100644 --- a/spec/integration_spec.rb +++ b/spec/integration_spec.rb @@ -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 diff --git a/spec/lib/roadie/action_mailer_extensions_spec.rb b/spec/lib/roadie/action_mailer_extensions_spec.rb index aaaa3de..6058538 100644 --- a/spec/lib/roadie/action_mailer_extensions_spec.rb +++ b/spec/lib/roadie/action_mailer_extensions_spec.rb @@ -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 @@ -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 diff --git a/spec/lib/roadie/inliner_spec.rb b/spec/lib/roadie/inliner_spec.rb index e1473cb..1bb5198 100644 --- a/spec/lib/roadie/inliner_spec.rb +++ b/spec/lib/roadie/inliner_spec.rb @@ -157,7 +157,20 @@ def rendering(html, options = {}) rendering(<<-HTML).should have_styling('color' => 'green').at_selector('p') - + + + +

+ + + HTML + end + + it "inlines styles from the linked stylesheet in subdirectory" do + rendering(<<-HTML).should have_styling('color' => 'green').at_selector('p') + + +

@@ -170,8 +183,8 @@ def rendering(html, options = {}) html = <<-HTML - - + +

@@ -189,8 +202,8 @@ def rendering(html, options = {}) rendering(<<-HTML).should_not have_selector('link') - - + + @@ -203,7 +216,7 @@ def rendering(html, options = {}) rendering(<<-HTML).should_not have_styling('color' => 'green').at_selector('p') - +

@@ -216,7 +229,7 @@ def rendering(html, options = {}) rendering(<<-HTML).should have_selector('link') - + @@ -230,7 +243,7 @@ def rendering(html, options = {}) rendering(<<-HTML).should_not have_styling('color' => 'green').at_selector('p') - +

@@ -243,7 +256,7 @@ def rendering(html, options = {}) rendering(<<-HTML).should have_selector('link') - + @@ -284,7 +297,7 @@ def rendering(html, options = {}) html = <<-HTML - + @@ -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 @@ -304,7 +317,7 @@ def rendering(html, options = {}) html = <<-HTML - +

diff --git a/spec/lib/roadie_spec.rb b/spec/lib/roadie_spec.rb index 8e16cfa..5bded11 100644 --- a/spec/lib/roadie_spec.rb +++ b/spec/lib/roadie_spec.rb @@ -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 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b060346..68ad337 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -17,12 +17,18 @@ Dir['./spec/support/**/*'].each { |file| require file } require 'action_mailer' +require 'sprockets' require 'roadie' class TestApplication def config OpenStruct.new(:action_mailer => OpenStruct.new(:default_url_options => {:host => "example.com"})) end + def assets + env = Sprockets::Environment.new + env.append_path FixturesPath + env + end end if defined?(Rails) @@ -34,5 +40,5 @@ def self.application; TestApplication.new; end end end -FixturesPath = Pathname.new(File.dirname(__FILE__)).join('fixtures') +FixturesPath = Pathname.new(File.dirname(__FILE__)).join('fixtures','app','assets','stylesheets')