roadie 2.4.3 → 3.0.0
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 +10 -14
- data/.yardopts +1 -1
- data/Changelog.md +38 -5
- data/Gemfile +3 -4
- data/Guardfile +12 -1
- data/README.md +168 -164
- data/Rakefile +2 -19
- data/lib/roadie.rb +15 -68
- 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 +30 -60
- data/lib/roadie/inliner.rb +72 -217
- 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 +71 -0
- data/lib/roadie/rspec.rb +1 -0
- data/lib/roadie/rspec/asset_provider.rb +49 -0
- data/lib/roadie/selector.rb +43 -18
- data/lib/roadie/style_attribute_builder.rb +25 -0
- data/lib/roadie/style_block.rb +32 -0
- data/lib/roadie/style_property.rb +93 -0
- data/lib/roadie/stylesheet.rb +65 -0
- data/lib/roadie/upgrade_guide.rb +36 -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 +8 -11
- 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 +17 -0
- data/spec/lib/roadie/document_spec.rb +123 -0
- data/spec/lib/roadie/filesystem_provider_spec.rb +44 -68
- 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 +89 -0
- data/spec/lib/roadie/selector_spec.rb +15 -10
- data/spec/lib/roadie/style_attribute_builder_spec.rb +29 -0
- data/spec/lib/roadie/style_block_spec.rb +35 -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 +121 -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 +6 -60
- data/spec/support/have_attribute_matcher.rb +2 -2
- data/spec/support/have_node_matcher.rb +4 -4
- data/spec/support/have_selector_matcher.rb +3 -3
- data/spec/support/have_styling_matcher.rb +51 -15
- data/spec/support/test_provider.rb +13 -0
- metadata +86 -175
- 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
@@ -0,0 +1,13 @@
|
|
1
|
+
module Roadie
|
2
|
+
# An asset provider that returns empty stylesheets for any name.
|
3
|
+
#
|
4
|
+
# Use it to ignore missing assets or in your tests when you need a provider
|
5
|
+
# but you do not care what it contains or that it is even referenced at all.
|
6
|
+
class NullProvider
|
7
|
+
def find_stylesheet(name) empty_stylesheet end
|
8
|
+
def find_stylesheet!(name) empty_stylesheet end
|
9
|
+
|
10
|
+
private
|
11
|
+
def empty_stylesheet() Stylesheet.new "(null)", "" end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Roadie
|
2
|
+
# @api private
|
3
|
+
# Null Object for the URL rewriter role.
|
4
|
+
#
|
5
|
+
# Used whenever client does not pass any URL options and no URL rewriting
|
6
|
+
# should take place.
|
7
|
+
class NullUrlRewriter
|
8
|
+
def initialize(generator = nil) end
|
9
|
+
def transform_dom(dom) end
|
10
|
+
def transform_css(css) end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Roadie
|
4
|
+
# An asset provider that just composes a list of other asset providers.
|
5
|
+
#
|
6
|
+
# Give it a list of providers and they will all be tried in order.
|
7
|
+
#
|
8
|
+
# {ProviderList} behaves like an Array, *and* an asset provider, and can be coerced into an array.
|
9
|
+
class ProviderList
|
10
|
+
extend Forwardable
|
11
|
+
include Enumerable
|
12
|
+
include AssetProvider
|
13
|
+
|
14
|
+
# Wrap a single provider, or a list of providers into a {ProviderList}.
|
15
|
+
#
|
16
|
+
# @overload wrap(provider_list)
|
17
|
+
# @param [ProviderList] provider_list An actual instance of {ProviderList}.
|
18
|
+
# @return The passed in provider_list
|
19
|
+
#
|
20
|
+
# @overload wrap(provider)
|
21
|
+
# @param [asset provider] provider
|
22
|
+
# @return a new {ProviderList} with just the passed provider in it
|
23
|
+
#
|
24
|
+
# @overload wrap(provider1, provider2, ...)
|
25
|
+
# @return a new {ProviderList} with all the passed providers in it.
|
26
|
+
def self.wrap(*providers)
|
27
|
+
if providers.size == 1 && providers.first.class == self
|
28
|
+
providers.first
|
29
|
+
else
|
30
|
+
new(providers.flatten)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(providers)
|
35
|
+
@providers = providers
|
36
|
+
end
|
37
|
+
|
38
|
+
# @return [Stylesheet, nil]
|
39
|
+
def find_stylesheet(name)
|
40
|
+
@providers.each do |provider|
|
41
|
+
css = provider.find_stylesheet(name)
|
42
|
+
return css if css
|
43
|
+
end
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
# ProviderList can be coerced to an array. This makes Array#flatten work
|
48
|
+
# with it, among other things.
|
49
|
+
def to_ary() to_a end
|
50
|
+
|
51
|
+
# @!method each
|
52
|
+
# @see Array#each
|
53
|
+
# @!method size
|
54
|
+
# @see Array#size
|
55
|
+
# @!method empty?
|
56
|
+
# @see Array#empty?
|
57
|
+
# @!method push
|
58
|
+
# @see Array#push
|
59
|
+
# @!method <<
|
60
|
+
# @see Array#<<
|
61
|
+
# @!method pop
|
62
|
+
# @see Array#pop
|
63
|
+
# @!method unshift
|
64
|
+
# @see Array#unshift
|
65
|
+
# @!method shift
|
66
|
+
# @see Array#shift
|
67
|
+
# @!method last
|
68
|
+
# @see Array#last
|
69
|
+
def_delegators :@providers, :each, :size, :empty?, :push, :<<, :pop, :unshift, :shift, :last
|
70
|
+
end
|
71
|
+
end
|
data/lib/roadie/rspec.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'roadie/rspec/asset_provider'
|
@@ -0,0 +1,49 @@
|
|
1
|
+
shared_examples_for "roadie asset provider" do |options|
|
2
|
+
valid_name = options[:valid_name] or raise "You must provide a :valid_name option to the shared examples"
|
3
|
+
invalid_name = options[:invalid_name] or raise "You must provide an :invalid_name option to the shared examples"
|
4
|
+
|
5
|
+
def verify_stylesheet(stylesheet)
|
6
|
+
expect(stylesheet).to_not be_nil
|
7
|
+
|
8
|
+
# Name
|
9
|
+
expect(stylesheet.name).to be_a(String)
|
10
|
+
expect(stylesheet.name).to_not be_empty
|
11
|
+
|
12
|
+
# We do not want to force clients to always return non-empty files.
|
13
|
+
# Stylesheet#initialize should crash when given a non-valid CSS (like nil,
|
14
|
+
# for example)
|
15
|
+
# expect(stylesheet.blocks).to_not be_empty
|
16
|
+
end
|
17
|
+
|
18
|
+
it "responds to #find_stylesheet" do
|
19
|
+
expect(subject).to respond_to(:find_stylesheet)
|
20
|
+
expect(subject.method(:find_stylesheet).arity).to eq 1
|
21
|
+
end
|
22
|
+
|
23
|
+
it "responds to #find_stylesheet!" do
|
24
|
+
expect(subject).to respond_to(:find_stylesheet!)
|
25
|
+
expect(subject.method(:find_stylesheet!).arity).to eq 1
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#find_stylesheet" do
|
29
|
+
it "can find a stylesheet" do
|
30
|
+
verify_stylesheet subject.find_stylesheet(valid_name)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "cannot find an invalid stylesheet" do
|
34
|
+
expect(subject.find_stylesheet(invalid_name)).to be_nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#find_stylesheet!" do
|
39
|
+
it "can find a stylesheet" do
|
40
|
+
verify_stylesheet subject.find_stylesheet!(valid_name)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "raises Roadie::CssNotFound on invalid stylesheets" do
|
44
|
+
expect {
|
45
|
+
subject.find_stylesheet!(invalid_name)
|
46
|
+
}.to raise_error Roadie::CssNotFound, Regexp.new(Regexp.quote(invalid_name))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/roadie/selector.rb
CHANGED
@@ -1,24 +1,46 @@
|
|
1
1
|
module Roadie
|
2
|
+
# @api private
|
3
|
+
#
|
4
|
+
# A selector is a domain object for a CSS selector, such as:
|
5
|
+
# body
|
6
|
+
# a:hover
|
7
|
+
# input::placeholder
|
8
|
+
# p:nth-of-child(4n+1) .important a img
|
9
|
+
#
|
10
|
+
# "Selectors" such as "strong, em" are actually two selectors and should be
|
11
|
+
# represented as two instances of this class.
|
12
|
+
#
|
13
|
+
# This class can also calculate specificity for the selector and answer a few
|
14
|
+
# questions about them.
|
15
|
+
#
|
16
|
+
# Selectors can be coerced into Strings, so they should be transparent to use
|
17
|
+
# anywhere a String is expected.
|
2
18
|
class Selector
|
3
|
-
def initialize(selector)
|
19
|
+
def initialize(selector, specificity = nil)
|
4
20
|
@selector = selector.to_s.strip
|
21
|
+
@specificity = specificity
|
5
22
|
end
|
6
23
|
|
24
|
+
# Returns the specificity of the selector, calculating it if needed.
|
7
25
|
def specificity
|
8
26
|
@specificity ||= CssParser.calculate_specificity selector
|
9
27
|
end
|
10
28
|
|
29
|
+
# Returns whenever or not a selector can be inlined.
|
30
|
+
# It's impossible to inline properties that applies to a pseudo element
|
31
|
+
# (like +::placeholder+, +::before+) or a pseudo function (like +:active+).
|
32
|
+
#
|
33
|
+
# We cannot inline styles that appear inside "@" constructs, like +@keyframes+.
|
11
34
|
def inlinable?
|
12
35
|
!(pseudo_element? || at_rule? || pseudo_function?)
|
13
36
|
end
|
14
37
|
|
15
|
-
def to_s
|
16
|
-
selector
|
17
|
-
end
|
18
|
-
|
38
|
+
def to_s() selector end
|
19
39
|
def to_str() to_s end
|
20
40
|
def inspect() selector.inspect end
|
21
41
|
|
42
|
+
# {Selector}s are equal to other {Selector}s if, and only if, their string
|
43
|
+
# representations are equal.
|
22
44
|
def ==(other)
|
23
45
|
if other.is_a?(self.class)
|
24
46
|
other.selector == selector
|
@@ -28,23 +50,26 @@ module Roadie
|
|
28
50
|
end
|
29
51
|
|
30
52
|
protected
|
31
|
-
|
53
|
+
attr_reader :selector
|
32
54
|
|
33
55
|
private
|
34
|
-
|
35
|
-
|
36
|
-
|
56
|
+
BAD_PSEUDO_FUNCTIONS = %w[
|
57
|
+
:active :focus :hover :link :target :visited
|
58
|
+
:-ms-input-placeholder :-moz-placeholder
|
59
|
+
:before :after
|
60
|
+
:enabled :disabled :checked
|
61
|
+
].freeze
|
37
62
|
|
38
|
-
|
39
|
-
|
40
|
-
|
63
|
+
def pseudo_element?
|
64
|
+
selector.include? '::'
|
65
|
+
end
|
41
66
|
|
42
|
-
|
43
|
-
|
44
|
-
|
67
|
+
def at_rule?
|
68
|
+
selector[0, 1] == '@'
|
69
|
+
end
|
45
70
|
|
46
|
-
|
47
|
-
|
48
|
-
|
71
|
+
def pseudo_function?
|
72
|
+
BAD_PSEUDO_FUNCTIONS.any? { |bad| selector.include?(bad) }
|
73
|
+
end
|
49
74
|
end
|
50
75
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Roadie
|
2
|
+
class StyleAttributeBuilder
|
3
|
+
def initialize
|
4
|
+
@styles = []
|
5
|
+
end
|
6
|
+
|
7
|
+
def <<(style)
|
8
|
+
@styles << style
|
9
|
+
end
|
10
|
+
|
11
|
+
def attribute_string
|
12
|
+
stable_sort(@styles).map(&:to_s).join(';')
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def stable_sort(list)
|
17
|
+
# Ruby's sort is unstable for performance reasons. We need it to be
|
18
|
+
# stable, e.g. to preserve order of elements that are compared equal in
|
19
|
+
# the sorting.
|
20
|
+
# We can accomplish this by using the original array index as a second
|
21
|
+
# comparator for when the first one is equal.
|
22
|
+
list.each_with_index.sort_by { |item, index| [item, index] }.map(&:first)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Roadie
|
4
|
+
# @api private
|
5
|
+
# A style block is the combination of a {Selector} and a list of {StyleProperty}.
|
6
|
+
class StyleBlock
|
7
|
+
extend Forwardable
|
8
|
+
attr_reader :selector, :properties
|
9
|
+
|
10
|
+
# @param [Selector] selector
|
11
|
+
# @param [Array<StyleProperty>] properties
|
12
|
+
def initialize(selector, properties)
|
13
|
+
@selector = selector
|
14
|
+
@properties = properties
|
15
|
+
end
|
16
|
+
|
17
|
+
# @!method specificity
|
18
|
+
# @see Selector#specificity
|
19
|
+
# @!method inlinable?
|
20
|
+
# @see Selector#inlinable?
|
21
|
+
def_delegators :selector, :specificity, :inlinable?
|
22
|
+
# @!method selector_string
|
23
|
+
# @see Selector#to_s
|
24
|
+
def_delegator :selector, :to_s, :selector_string
|
25
|
+
|
26
|
+
# String representation of the style block. This is valid CSS and can be
|
27
|
+
# used in the DOM.
|
28
|
+
def to_s
|
29
|
+
"#{selector}{#{properties.map(&:to_s).join(';')}}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Roadie
|
2
|
+
# @api private
|
3
|
+
# Domain object for a CSS property such as "color: red !important".
|
4
|
+
#
|
5
|
+
# @attr_reader [String] property name of the property (such as "font-size").
|
6
|
+
# @attr_reader [String] value value of the property (such as "5px solid green").
|
7
|
+
# @attr_reader [Boolean] important if the property is "!important".
|
8
|
+
# @attr_reader [Integer] specificity specificity of parent {Selector}. Used to compare/sort.
|
9
|
+
class StyleProperty
|
10
|
+
include Comparable
|
11
|
+
|
12
|
+
attr_reader :value, :important, :specificity
|
13
|
+
|
14
|
+
# @todo Rename #property to #name
|
15
|
+
attr_reader :property
|
16
|
+
|
17
|
+
# Parse a property string.
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# property = Roadie::StyleProperty.parse("color: green")
|
21
|
+
# property.property # => "color"
|
22
|
+
# property.value # => "green"
|
23
|
+
# property.important? # => false
|
24
|
+
def self.parse(declaration, specificity)
|
25
|
+
allocate.send :read_declaration!, declaration, specificity
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(property, value, important, specificity)
|
29
|
+
@property = property
|
30
|
+
@value = value
|
31
|
+
@important = important
|
32
|
+
@specificity = specificity
|
33
|
+
end
|
34
|
+
|
35
|
+
def important?
|
36
|
+
@important
|
37
|
+
end
|
38
|
+
|
39
|
+
# Compare another {StyleProperty}. Important styles are "greater than"
|
40
|
+
# non-important ones; otherwise the specificity declares order.
|
41
|
+
def <=>(other)
|
42
|
+
if important == other.important
|
43
|
+
specificity <=> other.specificity
|
44
|
+
else
|
45
|
+
important ? 1 : -1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
[property, value_with_important].join(':')
|
51
|
+
end
|
52
|
+
|
53
|
+
def inspect
|
54
|
+
"#{to_s} (#{specificity})"
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
def read_declaration!(declaration, specificity)
|
59
|
+
if (matches = DECLARATION_MATCHER.match(declaration))
|
60
|
+
initialize matches[:property], matches[:value].strip, !!matches[:important], specificity
|
61
|
+
self
|
62
|
+
else
|
63
|
+
raise UnparseableDeclaration, "Cannot parse declaration #{declaration.inspect}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
DECLARATION_MATCHER = %r{
|
69
|
+
\A\s*
|
70
|
+
(?:
|
71
|
+
# !important declaration
|
72
|
+
(?<property>[^:]+):\s?
|
73
|
+
(?<value>.*?)
|
74
|
+
(?<important>\s!important)
|
75
|
+
;?
|
76
|
+
|
|
77
|
+
# normal declaration
|
78
|
+
(?<property>[^:]+):\s?
|
79
|
+
(?<value>[^;]+)
|
80
|
+
;?
|
81
|
+
)
|
82
|
+
\s*\Z
|
83
|
+
}x.freeze
|
84
|
+
|
85
|
+
def value_with_important
|
86
|
+
if important
|
87
|
+
"#{value} !important"
|
88
|
+
else
|
89
|
+
value
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Roadie
|
2
|
+
# Domain object that represents a stylesheet (from disc, perhaps).
|
3
|
+
#
|
4
|
+
# It has a name and a list of {StyleBlock}s.
|
5
|
+
#
|
6
|
+
# @attr_reader [String] name the name of the stylesheet ("stylesheets/main.css", "Admin user styles", etc.). The name of the stylesheet will be visible if any errors occur.
|
7
|
+
# @attr_reader [Array<StyleBlock>] blocks
|
8
|
+
class Stylesheet
|
9
|
+
attr_reader :name, :blocks
|
10
|
+
|
11
|
+
# Parses the CSS string into a {StyleBlock}s and stores it.
|
12
|
+
#
|
13
|
+
# @param [String] name
|
14
|
+
# @param [String] css
|
15
|
+
def initialize(name, css)
|
16
|
+
@name = name
|
17
|
+
@blocks = parse_blocks(css)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @yield [selector, properties]
|
21
|
+
# @yieldparam [Selector] selector
|
22
|
+
# @yieldparam [Array<StyleProperty>] properties
|
23
|
+
def each_inlinable_block(&block)
|
24
|
+
# #map and then #each in order to support chained enumerations, etc. if
|
25
|
+
# no block is provided
|
26
|
+
inlinable_blocks.map { |style_block|
|
27
|
+
[style_block.selector, style_block.properties]
|
28
|
+
}.each(&block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
blocks.join("\n")
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def inlinable_blocks
|
37
|
+
blocks.select(&:inlinable?)
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_blocks(css)
|
41
|
+
blocks = []
|
42
|
+
setup_parser(css).each_selector do |selector_string, declarations, specificity|
|
43
|
+
blocks << create_style_block(selector_string, declarations, specificity)
|
44
|
+
end
|
45
|
+
blocks
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_style_block(selector_string, declarations, specificity)
|
49
|
+
StyleBlock.new(
|
50
|
+
Selector.new(selector_string, specificity),
|
51
|
+
parse_declarations(declarations, specificity)
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
def setup_parser(css)
|
56
|
+
parser = CssParser::Parser.new
|
57
|
+
parser.add_block! css
|
58
|
+
parser
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_declarations(declarations, specificity)
|
62
|
+
declarations.split(';').map { |declaration| StyleProperty.parse(declaration, specificity) }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|