roadie 2.4.3 → 3.0.0.pre1
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 +7 -0
- data/.gitignore +3 -0
- data/.travis.yml +9 -14
- data/.yardopts +1 -1
- data/Changelog.md +22 -10
- data/Gemfile +3 -0
- data/Guardfile +11 -1
- data/README.md +165 -163
- data/Rakefile +2 -19
- data/lib/roadie.rb +14 -69
- data/lib/roadie/asset_provider.rb +7 -58
- data/lib/roadie/asset_scanner.rb +92 -0
- data/lib/roadie/document.rb +103 -0
- data/lib/roadie/errors.rb +57 -0
- data/lib/roadie/filesystem_provider.rb +21 -62
- data/lib/roadie/inliner.rb +71 -218
- data/lib/roadie/markup_improver.rb +88 -0
- data/lib/roadie/null_provider.rb +13 -0
- data/lib/roadie/null_url_rewriter.rb +12 -0
- data/lib/roadie/provider_list.rb +67 -0
- data/lib/roadie/rspec.rb +1 -0
- data/lib/roadie/rspec/asset_provider.rb +49 -0
- data/lib/roadie/selector.rb +42 -18
- data/lib/roadie/style_block.rb +33 -0
- data/lib/roadie/style_properties.rb +29 -0
- data/lib/roadie/style_property.rb +93 -0
- data/lib/roadie/stylesheet.rb +65 -0
- data/lib/roadie/url_generator.rb +126 -0
- data/lib/roadie/url_rewriter.rb +84 -0
- data/lib/roadie/version.rb +1 -1
- data/roadie.gemspec +6 -10
- data/spec/fixtures/big_em.css +1 -0
- data/spec/fixtures/stylesheets/green.css +1 -0
- data/spec/integration_spec.rb +125 -95
- data/spec/lib/roadie/asset_scanner_spec.rb +153 -0
- data/spec/lib/roadie/css_not_found_spec.rb +16 -0
- data/spec/lib/roadie/document_spec.rb +123 -0
- data/spec/lib/roadie/filesystem_provider_spec.rb +25 -72
- data/spec/lib/roadie/inliner_spec.rb +105 -537
- data/spec/lib/roadie/markup_improver_spec.rb +78 -0
- data/spec/lib/roadie/null_provider_spec.rb +21 -0
- data/spec/lib/roadie/null_url_rewriter_spec.rb +19 -0
- data/spec/lib/roadie/provider_list_spec.rb +81 -0
- data/spec/lib/roadie/selector_spec.rb +7 -5
- data/spec/lib/roadie/style_block_spec.rb +35 -0
- data/spec/lib/roadie/style_properties_spec.rb +61 -0
- data/spec/lib/roadie/style_property_spec.rb +82 -0
- data/spec/lib/roadie/stylesheet_spec.rb +41 -0
- data/spec/lib/roadie/test_provider_spec.rb +29 -0
- data/spec/lib/roadie/url_generator_spec.rb +120 -0
- data/spec/lib/roadie/url_rewriter_spec.rb +79 -0
- data/spec/shared_examples/asset_provider.rb +11 -0
- data/spec/shared_examples/url_rewriter.rb +23 -0
- data/spec/spec_helper.rb +5 -60
- data/spec/support/have_node_matcher.rb +2 -2
- data/spec/support/have_selector_matcher.rb +1 -1
- data/spec/support/have_styling_matcher.rb +48 -14
- data/spec/support/test_provider.rb +13 -0
- metadata +73 -177
- data/Appraisals +0 -15
- data/gemfiles/rails_3.0.gemfile +0 -7
- data/gemfiles/rails_3.0.gemfile.lock +0 -123
- data/gemfiles/rails_3.1.gemfile +0 -7
- data/gemfiles/rails_3.1.gemfile.lock +0 -126
- data/gemfiles/rails_3.2.gemfile +0 -7
- data/gemfiles/rails_3.2.gemfile.lock +0 -124
- data/gemfiles/rails_4.0.gemfile +0 -7
- data/gemfiles/rails_4.0.gemfile.lock +0 -119
- data/lib/roadie/action_mailer_extensions.rb +0 -95
- data/lib/roadie/asset_pipeline_provider.rb +0 -28
- data/lib/roadie/css_file_not_found.rb +0 -22
- data/lib/roadie/railtie.rb +0 -39
- data/lib/roadie/style_declaration.rb +0 -42
- data/spec/fixtures/app/assets/stylesheets/integration.css +0 -10
- data/spec/fixtures/public/stylesheets/integration.css +0 -10
- data/spec/fixtures/views/integration_mailer/marketing.html.erb +0 -2
- data/spec/fixtures/views/integration_mailer/notification.html.erb +0 -8
- data/spec/fixtures/views/integration_mailer/notification.text.erb +0 -6
- data/spec/lib/roadie/action_mailer_extensions_spec.rb +0 -227
- data/spec/lib/roadie/asset_pipeline_provider_spec.rb +0 -65
- data/spec/lib/roadie/css_file_not_found_spec.rb +0 -29
- data/spec/lib/roadie/style_declaration_spec.rb +0 -49
- data/spec/lib/roadie_spec.rb +0 -101
- data/spec/shared_examples/asset_provider_examples.rb +0 -11
- data/spec/support/anonymous_mailer.rb +0 -21
- data/spec/support/change_url_options.rb +0 -5
- data/spec/support/parse_styling.rb +0 -25
data/Rakefile
CHANGED
@@ -1,29 +1,12 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'bundler/setup'
|
3
|
-
require 'appraisal'
|
4
3
|
|
5
4
|
Bundler::GemHelper.install_tasks
|
6
5
|
|
7
|
-
begin
|
8
|
-
require 'rspec'
|
9
|
-
rescue Bundler::BundlerError => e
|
10
|
-
$stderr.puts e.message
|
11
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
12
|
-
exit e.status_code
|
13
|
-
end
|
14
|
-
|
15
|
-
require 'rspec/core/rake_task'
|
16
|
-
|
17
6
|
desc "Run specs"
|
18
|
-
|
19
|
-
|
20
|
-
t.rspec_opts = ["-c"]
|
7
|
+
task :spec do
|
8
|
+
sh "bundle exec rspec -f progress"
|
21
9
|
end
|
22
10
|
|
23
11
|
desc "Default: Run specs"
|
24
12
|
task :default => :spec
|
25
|
-
|
26
|
-
namespace :spec do
|
27
|
-
desc 'Run specs against all supported versions of Rails'
|
28
|
-
task :all => ["appraisal:install", "appraisal", "spec"]
|
29
|
-
end
|
data/lib/roadie.rb
CHANGED
@@ -1,79 +1,24 @@
|
|
1
1
|
module Roadie
|
2
|
-
class << self
|
3
|
-
# Shortcut for inlining CSS using {Inliner}
|
4
|
-
# @see Inliner
|
5
|
-
def inline_css(*args)
|
6
|
-
Roadie::Inliner.new(*args).execute
|
7
|
-
end
|
8
|
-
|
9
|
-
# Shortcut to Rails.application
|
10
|
-
def app
|
11
|
-
Rails.application
|
12
|
-
end
|
13
|
-
|
14
|
-
# Returns all available providers
|
15
|
-
def providers
|
16
|
-
[AssetPipelineProvider, FilesystemProvider]
|
17
|
-
end
|
18
|
-
|
19
|
-
# Returns the value of +config.roadie.enabled+.
|
20
|
-
#
|
21
|
-
# Roadie will disable all processing if this config is set to +false+. If
|
22
|
-
# you just want to disable CSS inlining without disabling the rest of
|
23
|
-
# Roadie, pass +css: nil+ to the +defaults+ method inside your mailers.
|
24
|
-
def enabled?
|
25
|
-
config.roadie.enabled
|
26
|
-
end
|
27
|
-
|
28
|
-
# Returns the active provider
|
29
|
-
#
|
30
|
-
# If no provider has been configured a new provider will be instantiated
|
31
|
-
# depending on if the asset pipeline is enabled or not.
|
32
|
-
#
|
33
|
-
# If +config.assets.enabled+ is +true+, the {AssetPipelineProvider} will be used
|
34
|
-
# while {FilesystemProvider} will be used if it is set to +false+.
|
35
|
-
#
|
36
|
-
# @see AssetPipelineProvider
|
37
|
-
# @see FilesystemProvider
|
38
|
-
def current_provider
|
39
|
-
return config.roadie.provider if config.roadie.provider
|
40
|
-
|
41
|
-
if assets_enabled?
|
42
|
-
AssetPipelineProvider.new
|
43
|
-
else
|
44
|
-
FilesystemProvider.new
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# Returns the value of +config.roadie.after_inlining+
|
49
|
-
#
|
50
|
-
def after_inlining_handler
|
51
|
-
config.roadie.after_inlining
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
def config
|
56
|
-
Roadie.app.config
|
57
|
-
end
|
58
|
-
|
59
|
-
def assets_enabled?
|
60
|
-
# In Rails 4.0, config.assets.enabled is nil by default, so we need to
|
61
|
-
# explicitly make sure it's not false rather than checking for a
|
62
|
-
# truthy value.
|
63
|
-
config.respond_to?(:assets) and config.assets and config.assets.enabled != false
|
64
|
-
end
|
65
|
-
end
|
66
2
|
end
|
67
3
|
|
68
4
|
require 'roadie/version'
|
69
|
-
require 'roadie/
|
5
|
+
require 'roadie/errors'
|
6
|
+
|
7
|
+
require 'roadie/stylesheet'
|
70
8
|
require 'roadie/selector'
|
71
|
-
require 'roadie/
|
9
|
+
require 'roadie/style_property'
|
10
|
+
require 'roadie/style_properties'
|
11
|
+
require 'roadie/style_block'
|
72
12
|
|
73
13
|
require 'roadie/asset_provider'
|
74
|
-
require 'roadie/
|
14
|
+
require 'roadie/provider_list'
|
75
15
|
require 'roadie/filesystem_provider'
|
16
|
+
require 'roadie/null_provider'
|
76
17
|
|
18
|
+
require 'roadie/asset_scanner'
|
19
|
+
require 'roadie/markup_improver'
|
20
|
+
require 'roadie/url_generator'
|
21
|
+
require 'roadie/url_rewriter'
|
22
|
+
require 'roadie/null_url_rewriter'
|
77
23
|
require 'roadie/inliner'
|
78
|
-
|
79
|
-
require 'roadie/railtie' if defined?(Rails)
|
24
|
+
require 'roadie/document'
|
@@ -1,62 +1,11 @@
|
|
1
1
|
module Roadie
|
2
|
-
#
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
# find("posts/comment.css")
|
10
|
-
attr_reader :prefix
|
11
|
-
|
12
|
-
# @param [String] prefix Prefix of assets as seen from the browser
|
13
|
-
# @see #prefix
|
14
|
-
def initialize(prefix = "/assets")
|
15
|
-
@prefix = prefix
|
16
|
-
@quoted_prefix = prepare_prefix(prefix)
|
2
|
+
# This module can be included in your own code to help you implement the
|
3
|
+
# standard behavior for asset providers.
|
4
|
+
#
|
5
|
+
# It helps you by declaring {#find_stylesheet!} in the terms of #find_stylesheet in your own class.
|
6
|
+
module AssetProvider
|
7
|
+
def find_stylesheet!(name)
|
8
|
+
find_stylesheet(name) or raise CssNotFound, name
|
17
9
|
end
|
18
|
-
|
19
|
-
# Iterates all the passed elements and calls {#find} on them, joining the results with a newline.
|
20
|
-
#
|
21
|
-
# @example
|
22
|
-
# MyProvider.all("first", "second.css", :third)
|
23
|
-
#
|
24
|
-
# @param [Array] files The target files to be loaded together
|
25
|
-
# @raise [CSSFileNotFound] In case any of the elements is not found
|
26
|
-
# @see #find
|
27
|
-
def all(files)
|
28
|
-
files.map { |file| find(file) }.join("\n")
|
29
|
-
end
|
30
|
-
|
31
|
-
# @abstract Implement in your own subclass
|
32
|
-
#
|
33
|
-
# Return the CSS contents of the file specified. A provider should not care about
|
34
|
-
# the +.css+ extension; it can, however, behave differently if it's passed or not.
|
35
|
-
#
|
36
|
-
# If the asset cannot be found, the method should raise {CSSFileNotFound}.
|
37
|
-
#
|
38
|
-
# @example
|
39
|
-
# MyProvider.find("mystyle")
|
40
|
-
# MyProvider.find("mystyle.css")
|
41
|
-
# MyProvider.find(:mystyle)
|
42
|
-
#
|
43
|
-
# @param [String] name Name of the file requested
|
44
|
-
# @raise [CSSFileNotFound] In case any of the elements is not found
|
45
|
-
def find(name)
|
46
|
-
raise "Not implemented"
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
def prepare_prefix(prefix)
|
51
|
-
if prefix =~ /^\//
|
52
|
-
"/?#{Regexp.quote(prefix[1, prefix.size])}"
|
53
|
-
else
|
54
|
-
Regexp.quote(prefix)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def remove_prefix(name)
|
59
|
-
name.sub(/^#{@quoted_prefix}\/?/, '').sub(%r{^/}, '').gsub(%r{//+}, '/')
|
60
|
-
end
|
61
10
|
end
|
62
11
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Roadie
|
2
|
+
# @api private
|
3
|
+
#
|
4
|
+
# The asset scanner's main usage is finding and/or extracting styles from a
|
5
|
+
# DOM tree. Referenced styles will be found using the provided asset
|
6
|
+
# provider.
|
7
|
+
#
|
8
|
+
# Any style declaration tagged with +data-roadie-ignore+ will be ignored.
|
9
|
+
class AssetScanner
|
10
|
+
attr_reader :dom, :asset_provider
|
11
|
+
|
12
|
+
# @param [Nokogiri::HTML::Document] dom
|
13
|
+
# @param [#find_stylesheet!] asset_provider
|
14
|
+
def initialize(dom, asset_provider)
|
15
|
+
@dom = dom
|
16
|
+
@asset_provider = asset_provider
|
17
|
+
end
|
18
|
+
|
19
|
+
# Looks for all non-ignored stylesheets and returns them.
|
20
|
+
#
|
21
|
+
# This method will *not* mutate the DOM and is safe to call multiple times.
|
22
|
+
#
|
23
|
+
# The order of the array corresponds with the document order in the DOM.
|
24
|
+
#
|
25
|
+
# @see #extract_css
|
26
|
+
# @return [Enumerable<Stylesheet>] every found stylesheet
|
27
|
+
def find_css
|
28
|
+
@dom.css(STYLE_ELEMENT_QUERY).map { |element| read_stylesheet(element) }.compact
|
29
|
+
end
|
30
|
+
|
31
|
+
# Looks for all non-ignored stylesheets, removes their references from the
|
32
|
+
# DOM and then returns them.
|
33
|
+
#
|
34
|
+
# This will mutate the DOM tree.
|
35
|
+
#
|
36
|
+
# The order of the array corresponds with the document order in the DOM.
|
37
|
+
#
|
38
|
+
# @see #find_css
|
39
|
+
# @return [Enumerable<Stylesheet>] every extracted stylesheet
|
40
|
+
def extract_css
|
41
|
+
@dom.css(STYLE_ELEMENT_QUERY).map { |element|
|
42
|
+
stylesheet = read_stylesheet(element)
|
43
|
+
element.remove if stylesheet
|
44
|
+
stylesheet
|
45
|
+
}.compact
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
STYLE_ELEMENT_QUERY = (
|
51
|
+
"style:not([data-roadie-ignore]), " +
|
52
|
+
# TODO: When using Nokogiri 1.6.1 and later; we may use a double :not here
|
53
|
+
# instead of the extra code inside #read_stylesheet, and the #compact
|
54
|
+
# call in #find_css.
|
55
|
+
"link[rel=stylesheet][href]:not([data-roadie-ignore])"
|
56
|
+
).freeze
|
57
|
+
|
58
|
+
# Cleans out stupid CDATA and/or HTML comments from the style text
|
59
|
+
# TinyMCE causes this, allegedly
|
60
|
+
CLEANING_MATCHER = /
|
61
|
+
(^\s* # Beginning-of-lines matches
|
62
|
+
(<!\[CDATA\[)|
|
63
|
+
(<!--+)
|
64
|
+
)|( # End-of-line matches
|
65
|
+
(--+>)|
|
66
|
+
(\]\]>)
|
67
|
+
$)
|
68
|
+
/x.freeze
|
69
|
+
|
70
|
+
def read_stylesheet(element)
|
71
|
+
if element.name == "style"
|
72
|
+
read_style_element element
|
73
|
+
else
|
74
|
+
read_link_element element
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def read_style_element(element)
|
79
|
+
Stylesheet.new "(inline)", clean_css(element.text.strip)
|
80
|
+
end
|
81
|
+
|
82
|
+
def read_link_element(element)
|
83
|
+
if element['media'] != "print" && element["href"]
|
84
|
+
asset_provider.find_stylesheet! element['href']
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def clean_css(css)
|
89
|
+
css.gsub(CLEANING_MATCHER, '')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Roadie
|
2
|
+
# The main entry point for Roadie. A document represents a working unit and
|
3
|
+
# is built with the input HTML and the configuration options you need.
|
4
|
+
#
|
5
|
+
# A Document must never be used from two threads at the same time. Reusing
|
6
|
+
# Documents is discouraged.
|
7
|
+
#
|
8
|
+
# Stylesheets are added to the HTML from three different sources:
|
9
|
+
# 1. Stylesheets inside the document ( +<style>+ elements)
|
10
|
+
# 2. Stylesheets referenced by the DOM ( +<link>+ elements)
|
11
|
+
# 3. The internal stylesheet (see {#add_css})
|
12
|
+
#
|
13
|
+
# The internal stylesheet is used last and gets the highest priority. The
|
14
|
+
# rest is used in the same order as browsers are supposed to use them.
|
15
|
+
#
|
16
|
+
# @attr [#call] before_transformation Callback to call just before {#transform}ation is begun. Will be called with the parsed DOM tree.
|
17
|
+
# @attr [#call] after_transformation Callback to call just before {#transform}ation is completed. Will be called with the current DOM tree.
|
18
|
+
class Document
|
19
|
+
attr_reader :html, :asset_providers
|
20
|
+
|
21
|
+
# URL options. If none are given no URL rewriting will take place.
|
22
|
+
# @see UrlGenerator#initialize
|
23
|
+
attr_accessor :url_options
|
24
|
+
|
25
|
+
attr_accessor :before_transformation, :after_transformation
|
26
|
+
|
27
|
+
# @param [String] html the input HTML
|
28
|
+
def initialize(html)
|
29
|
+
@html = html
|
30
|
+
@asset_providers = ProviderList.wrap(FilesystemProvider.new)
|
31
|
+
@css = ""
|
32
|
+
end
|
33
|
+
|
34
|
+
# Append additional CSS to the document's internal stylesheet.
|
35
|
+
# @param [String] new_css
|
36
|
+
def add_css(new_css)
|
37
|
+
@css << "\n\n" << new_css
|
38
|
+
end
|
39
|
+
|
40
|
+
# Transform the input HTML and returns the processed HTML.
|
41
|
+
#
|
42
|
+
# Before the transformation begins, the {#before_transformation} callback will be
|
43
|
+
# called with the parsed HTML tree, and after all work is complete the
|
44
|
+
# {#after_transformation} callback will be invoked.
|
45
|
+
#
|
46
|
+
# Most of the work is delegated to other classes. A list of them can be seen below.
|
47
|
+
#
|
48
|
+
# @see MarkupImprover MarkupImprover (improves the markup of the DOM)
|
49
|
+
# @see Inliner Inliner (inlines the stylesheets)
|
50
|
+
# @see UrlRewriter UrlRewriter (rewrites URLs and makes them absolute)
|
51
|
+
#
|
52
|
+
# @return [String] the transformed HTML
|
53
|
+
def transform
|
54
|
+
dom = Nokogiri::HTML.parse html
|
55
|
+
|
56
|
+
callback before_transformation, dom
|
57
|
+
|
58
|
+
improve dom
|
59
|
+
inline dom
|
60
|
+
rewrite_urls dom
|
61
|
+
|
62
|
+
callback after_transformation, dom
|
63
|
+
|
64
|
+
# #dup is called since it fixed a few segfaults in certain versions of Nokogiri
|
65
|
+
dom.dup.to_html
|
66
|
+
end
|
67
|
+
|
68
|
+
# Assign new asset providers. The supplied list will be wrapped in a {ProviderList} using {ProviderList.wrap}.
|
69
|
+
def asset_providers=(list)
|
70
|
+
@asset_providers = ProviderList.wrap(list)
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
def stylesheet
|
75
|
+
Stylesheet.new "(Document styles)", @css
|
76
|
+
end
|
77
|
+
|
78
|
+
def improve(dom)
|
79
|
+
MarkupImprover.new(dom, html).improve
|
80
|
+
end
|
81
|
+
|
82
|
+
def inline(dom)
|
83
|
+
dom_stylesheets = AssetScanner.new(dom, asset_providers).extract_css
|
84
|
+
Inliner.new(dom_stylesheets + [stylesheet]).inline(dom)
|
85
|
+
end
|
86
|
+
|
87
|
+
def rewrite_urls(dom)
|
88
|
+
make_url_rewriter.transform_dom(dom)
|
89
|
+
end
|
90
|
+
|
91
|
+
def make_url_rewriter
|
92
|
+
if url_options
|
93
|
+
UrlRewriter.new(UrlGenerator.new(url_options))
|
94
|
+
else
|
95
|
+
NullUrlRewriter.new
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def callback(callable, dom)
|
100
|
+
callable.(dom) if callable.respond_to?(:call)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Roadie
|
2
|
+
# Base class for all Roadie errors. Rescue this if you want to catch errors
|
3
|
+
# from Roadie.
|
4
|
+
#
|
5
|
+
# If Roadie raises an error that does not inherit this class, please report
|
6
|
+
# it as a bug.
|
7
|
+
class Error < RuntimeError; end
|
8
|
+
|
9
|
+
# Raised when a declaration which cannot be parsed is encountered.
|
10
|
+
#
|
11
|
+
# A declaration is something like "font-size: 12pt;".
|
12
|
+
class UnparseableDeclaration < Error; end
|
13
|
+
|
14
|
+
# Raised when Roadie encounters an invalid URL which cannot be parsed by
|
15
|
+
# Ruby's +URI+ class.
|
16
|
+
#
|
17
|
+
# This could be a hint that something in your HTML or CSS is broken.
|
18
|
+
class InvalidUrlPath < Error
|
19
|
+
# The original error, raised from +URI+.
|
20
|
+
attr_reader :cause
|
21
|
+
|
22
|
+
def initialize(given_path, cause = nil)
|
23
|
+
@cause = cause
|
24
|
+
if cause
|
25
|
+
cause_message = " Caused by: #{cause}"
|
26
|
+
else
|
27
|
+
cause_message = ""
|
28
|
+
end
|
29
|
+
super "Cannot use path \"#{given_path}\" in URL generation.#{cause_message}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Raised when an asset provider cannot find a stylesheet.
|
34
|
+
#
|
35
|
+
# If you are writing your own asset provider, make sure to raise this in the
|
36
|
+
# +#find_stylesheet!+ method.
|
37
|
+
#
|
38
|
+
# @see AssetProvider
|
39
|
+
class CssNotFound < Error
|
40
|
+
# The name of the stylesheet that cannot be found
|
41
|
+
attr_reader :css_name
|
42
|
+
|
43
|
+
def initialize(css_name, extra_message = nil)
|
44
|
+
@css_name = css_name
|
45
|
+
super build_message(extra_message)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def build_message(extra_message)
|
50
|
+
if extra_message
|
51
|
+
%(Could not find stylesheet "#{css_name}": #{extra_message})
|
52
|
+
else
|
53
|
+
%(Could not find stylesheet "#{css_name}")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|