inline-style 0.4.10 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +7 -1
- data/README.rdoc +2 -9
- data/inline-style.gemspec +1 -0
- data/lib/inline-style.rb +55 -58
- data/lib/inline-style/css_parser_wrapper.rb +6 -19
- data/lib/inline-style/csspool_wrapper.rb +6 -23
- data/lib/inline-style/{mail/interceptor.rb → mail-interceptor.rb} +1 -0
- data/lib/inline-style/{rack/middleware.rb → rack-middleware.rb} +0 -0
- data/lib/inline-style/rule.rb +18 -0
- data/lib/inline-style/version.rb +1 -1
- data/spec/css_inlining_spec.rb +9 -10
- data/spec/css_parsing_spec.rb +146 -0
- data/spec/fixtures/all.css +2 -2
- data/spec/fixtures/boletin.html +2 -1
- data/spec/fixtures/inline.html +60 -60
- data/spec/interceptor_spec.rb +7 -16
- data/spec/rack_middleware_spec.rb +1 -1
- data/spec/spec_helper.rb +4 -2
- metadata +25 -22
- data/lib/inline-style/selector.rb +0 -41
- data/spec/css_parsers_spec.rb +0 -53
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
inline-style (0.4.
|
4
|
+
inline-style (0.4.10)
|
5
5
|
css_parser
|
6
|
+
facets
|
6
7
|
maca-fork-csspool
|
7
8
|
nokogiri
|
8
9
|
|
@@ -12,6 +13,7 @@ GEM
|
|
12
13
|
activesupport (3.0.4)
|
13
14
|
css_parser (1.1.5)
|
14
15
|
diff-lcs (1.1.2)
|
16
|
+
facets (2.9.1)
|
15
17
|
ffi (1.0.7)
|
16
18
|
rake (>= 0.8.7)
|
17
19
|
i18n (0.5.0)
|
@@ -42,8 +44,12 @@ PLATFORMS
|
|
42
44
|
ruby
|
43
45
|
|
44
46
|
DEPENDENCIES
|
47
|
+
css_parser
|
48
|
+
facets
|
45
49
|
inline-style!
|
50
|
+
maca-fork-csspool
|
46
51
|
mail
|
52
|
+
nokogiri
|
47
53
|
rack
|
48
54
|
rspec
|
49
55
|
rspec-core
|
data/README.rdoc
CHANGED
@@ -24,8 +24,8 @@ Useful for html email: some clients (gmail, et all) won't render non inline styl
|
|
24
24
|
|
25
25
|
require 'inline-style'
|
26
26
|
|
27
|
-
html = File.read("
|
28
|
-
puts InlineStyle.process(html, :stylesheets_paths => "
|
27
|
+
html = File.read("./index.html")
|
28
|
+
puts InlineStyle.process(html, :stylesheets_paths => "./styles")
|
29
29
|
|
30
30
|
index.html contains:
|
31
31
|
|
@@ -115,20 +115,13 @@ If using ActionMailer (which wraps mail):
|
|
115
115
|
|
116
116
|
ActionMailer::Base.register_interceptor \
|
117
117
|
InlineStyle::Mail::Interceptor.new(:stylesheets_path => 'public')
|
118
|
-
|
119
118
|
|
120
|
-
== Issues:
|
121
|
-
|
122
|
-
* It supports pseudo classes according to W3C specification for style in style attribute: http://www.w3.org/TR/css-style-attr, although browsers
|
123
|
-
doesn't seems to.
|
124
|
-
|
125
119
|
|
126
120
|
== Requirements:
|
127
121
|
|
128
122
|
nokogiri && (css_parser || maca-fork-csspool)
|
129
123
|
|
130
124
|
|
131
|
-
|
132
125
|
== Install:
|
133
126
|
|
134
127
|
sudo gem install inline-style
|
data/inline-style.gemspec
CHANGED
data/lib/inline-style.rb
CHANGED
@@ -3,9 +3,9 @@ require 'open-uri'
|
|
3
3
|
|
4
4
|
$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
5
5
|
|
6
|
-
require "inline-style/
|
7
|
-
require "inline-style/rack
|
8
|
-
require "inline-style/mail
|
6
|
+
require "inline-style/rule"
|
7
|
+
require "inline-style/rack-middleware" # This two may be should be required by user if she needs it
|
8
|
+
require "inline-style/mail-interceptor"
|
9
9
|
|
10
10
|
class InlineStyle
|
11
11
|
CSSParser =
|
@@ -20,82 +20,79 @@ class InlineStyle
|
|
20
20
|
# @param [String, Nokogiri::HTML::Document] html Html or Nokogiri html to be inlined
|
21
21
|
# @param [Hash] opts Processing options
|
22
22
|
#
|
23
|
-
# @option opts [String] :stylesheets_path (
|
23
|
+
# @option opts [String] :stylesheets_path (ENV['DOCUMENT_ROOT'])
|
24
24
|
# Stylesheets root path or app's public directory where the stylesheets are to be found
|
25
|
-
# @option opts [boolean] :pseudo (false)
|
26
|
-
# If set to true will inline style for pseudo classes according to the W3C specification:
|
27
|
-
# http://www.w3.org/TR/css-style-attr.
|
28
|
-
# Should probably be left as false because browsers don't seem to comply with the specification for pseudo class style in the style attribute.
|
29
25
|
def self.process html, opts = {}
|
30
26
|
new(html, opts).process
|
31
27
|
end
|
32
28
|
|
33
29
|
def initialize html, opts = {}
|
34
|
-
@
|
35
|
-
@
|
36
|
-
@
|
30
|
+
@stylesheets_path = opts[:stylesheets_path] || ENV['DOCUMENT_ROOT'] || '.'
|
31
|
+
@html = html
|
32
|
+
@dom = String === html ? Nokogiri.HTML(html) : html
|
37
33
|
end
|
38
34
|
|
39
35
|
def process
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
path << "##{ node['id'] }" if node['id']
|
52
|
-
path << ".#{ node['class'].scan(/\S+/).join('.') }" if node['class']
|
53
|
-
|
54
|
-
CSSParser.new("#{path}{#{node['style']}}").each_rule_set do |rule|
|
55
|
-
rule.each_selector do |selector_inner|
|
56
|
-
nodes[node].push selector_inner
|
57
|
-
end
|
36
|
+
nodes_with_rules.each_pair do |node, rules|
|
37
|
+
rules = rules.sort_by{ |sel| "#{sel.specificity}%04d" % rules.index(sel) }
|
38
|
+
|
39
|
+
styles = []
|
40
|
+
rules.each do |rule|
|
41
|
+
next if rule.dynamic_pseudo_class
|
42
|
+
rule.declarations.each do |declaration|
|
43
|
+
if defined = styles.assoc(declaration.first)
|
44
|
+
styles[styles.index(defined)] = declaration # overrides defined declaration
|
45
|
+
else
|
46
|
+
styles << declaration
|
58
47
|
end
|
59
48
|
end
|
60
49
|
end
|
61
|
-
end
|
62
50
|
|
63
|
-
|
64
|
-
|
65
|
-
selectors = selectors.reject {|sel| !@pseudo && sel.pseudo? }
|
66
|
-
using_pseudo = selectors.any? &:pseudo?
|
67
|
-
|
68
|
-
node['style'] = selectors.collect do |selector|
|
69
|
-
if using_pseudo && !selector.pseudo?
|
70
|
-
"{#{selector.inline_declarations}}"
|
71
|
-
else
|
72
|
-
selector.inline_declarations
|
73
|
-
end
|
74
|
-
end.join(' ').strip
|
51
|
+
style = styles.map{ |declaration| declaration.join(': ') }.join('; ')
|
52
|
+
node['style'] = "#{style};" unless style.empty?
|
75
53
|
end
|
76
|
-
|
77
|
-
html_already_parsed? ? @dom : @dom.to_s
|
54
|
+
pre_parsed? ? @dom : @dom.to_s
|
78
55
|
end
|
79
56
|
|
80
57
|
private
|
81
|
-
def
|
82
|
-
|
58
|
+
def nodes_with_rules
|
59
|
+
nodes, body = {}, @dom.css('body')
|
60
|
+
|
61
|
+
parse_css.rules.each do |rule|
|
62
|
+
body.css(rule.selector).each do |node|
|
63
|
+
nodes[node] ||= []
|
64
|
+
nodes[node].push rule
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
body.css('[style]').each do |node|
|
69
|
+
nodes[node] ||= []
|
70
|
+
nodes[node].push Rule.new ':inline', node['style'], '1000' # :inline is not really a pseudoclass
|
71
|
+
end
|
72
|
+
|
73
|
+
nodes
|
83
74
|
end
|
84
75
|
|
85
|
-
def
|
86
|
-
@html
|
76
|
+
def pre_parsed?
|
77
|
+
@html == @dom
|
87
78
|
end
|
88
79
|
|
89
80
|
# Returns parsed CSS
|
90
|
-
def
|
91
|
-
@
|
92
|
-
next unless
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
81
|
+
def extract_css
|
82
|
+
@dom.css('style, link[rel=stylesheet]').collect do |node|
|
83
|
+
next unless /^$|screen|all/ === node['media'].to_s
|
84
|
+
node.remove
|
85
|
+
|
86
|
+
if node.name == 'style'
|
87
|
+
node.content
|
88
|
+
else
|
89
|
+
uri = %r{^https?://} === node['href'] ? node['href'] : File.join(@stylesheets_path, node['href'].sub(/\?.+$/,''))
|
90
|
+
open(uri).read
|
91
|
+
end
|
92
|
+
end.join("\n")
|
93
|
+
end
|
94
|
+
|
95
|
+
def parse_css
|
96
|
+
CSSParser.new extract_css
|
100
97
|
end
|
101
98
|
end
|
@@ -2,26 +2,13 @@ require 'css_parser'
|
|
2
2
|
|
3
3
|
class InlineStyle
|
4
4
|
class CssParserWrapper
|
5
|
-
|
6
|
-
@parser = ::CssParser::Parser.new
|
7
|
-
@parser.add_block! css_code
|
8
|
-
end
|
9
|
-
|
10
|
-
def each_rule_set(&blk)
|
11
|
-
@parser.each_rule_set do |rule_set|
|
12
|
-
yield Ruleset.new(rule_set)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class Ruleset
|
17
|
-
def initialize(ruleset)
|
18
|
-
@ruleset = ruleset
|
19
|
-
end
|
5
|
+
attr_accessor :rules
|
20
6
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
7
|
+
def initialize(css_code)
|
8
|
+
parser, @rules = CssParser::Parser.new, []
|
9
|
+
parser.add_block! css_code
|
10
|
+
parser.each_rule_set do |rule_set|
|
11
|
+
rule_set.each_selector { |sel, dec, spec| @rules << Rule.new(sel, dec, '%04d' % spec.to_i) }
|
25
12
|
end
|
26
13
|
end
|
27
14
|
end
|
@@ -1,29 +1,12 @@
|
|
1
1
|
class InlineStyle
|
2
2
|
class CSSPoolWrapper
|
3
|
+
attr_accessor :rules
|
3
4
|
|
4
|
-
def initialize
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
@parser.rule_sets.each do |rule_set|
|
10
|
-
yield Ruleset.new(rule_set)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class Ruleset
|
15
|
-
|
16
|
-
def initialize(ruleset)
|
17
|
-
@ruleset = ruleset
|
18
|
-
end
|
19
|
-
|
20
|
-
def each_selector(&blk)
|
21
|
-
@ruleset.selectors.each do |selector|
|
22
|
-
yield InlineStyle::Selector.new(selector.to_s,
|
23
|
-
selector.declarations.map{ |d| d.to_s.squeeze(' ') }.join.strip,
|
24
|
-
selector.specificity.inject(0) {|t, s| t+s})
|
25
|
-
end
|
26
|
-
end
|
5
|
+
def initialize css_code
|
6
|
+
parser = CSSPool.CSS css_code
|
7
|
+
@rules = parser.rule_sets.map do |rule_set|
|
8
|
+
rule_set.selectors.map { |sel| Rule.new(sel.to_s, sel.declarations.join, "0#{sel.specificity.join}") }
|
9
|
+
end.flatten
|
27
10
|
end
|
28
11
|
end
|
29
12
|
end
|
File without changes
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class InlineStyle
|
2
|
+
# A simple abstraction of the data we get back from the parsers. CSSPool
|
3
|
+
# actually already does this for us but CSSParser does not so we need
|
4
|
+
# to create the abstraction ourselves.
|
5
|
+
class Rule
|
6
|
+
DYNAMIC_PSEUDO_CLASSES = %w(link visited active hover focus target enabled disabled checked)
|
7
|
+
DYNAMIC_PSEUDO_CLASSES_MATCHER = /:(#{DYNAMIC_PSEUDO_CLASSES.join('|')})$/
|
8
|
+
|
9
|
+
attr_reader :selector, :declarations, :specificity, :dynamic_pseudo_class
|
10
|
+
|
11
|
+
def initialize selector, declarations, specificity
|
12
|
+
@specificity = specificity
|
13
|
+
@selector, @dynamic_pseudo_class = selector.split DYNAMIC_PSEUDO_CLASSES_MATCHER
|
14
|
+
@selector.sub! /$^/, '*'
|
15
|
+
@declarations = declarations.scan /\s*([^:]+):\s*([^;]+);/
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/inline-style/version.rb
CHANGED
data/spec/css_inlining_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require "spec_helper"
|
|
3
3
|
describe InlineStyle do
|
4
4
|
shared_examples_for 'inlines styles' do
|
5
5
|
before do
|
6
|
-
processed = InlineStyle.process File.read("#{FIXTURES}/boletin.html"), :
|
6
|
+
processed = InlineStyle.process File.read("#{FIXTURES}/boletin.html"), :stylesheets_path => FIXTURES
|
7
7
|
@processed = Nokogiri.HTML(processed)
|
8
8
|
end
|
9
9
|
|
@@ -16,7 +16,7 @@ describe InlineStyle do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
it "should extract styles from linked stylesheet with media 'all'" do
|
19
|
-
@processed.css('#izq').first['style'].should match_style /
|
19
|
+
@processed.css('#izq').first['style'].should match_style /border: none;/
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should ignore styles from linked stylesheet with media other than screen" do
|
@@ -27,11 +27,6 @@ describe InlineStyle do
|
|
27
27
|
@processed.css('a').first['style'].should_not match_style /^:hover \{background-color: #8ae0ea; color: #126b5d;\}$/
|
28
28
|
end
|
29
29
|
|
30
|
-
it "should should process pseudo classes" do
|
31
|
-
processed = InlineStyle.process Nokogiri.HTML(File.read("#{FIXTURES}/boletin.html")), :pseudo => true
|
32
|
-
processed.css('a').first['style'].should match_style /^:hover \{background-color: #8ae0ea; color: #126b5d;\}$/
|
33
|
-
end
|
34
|
-
|
35
30
|
it 'should process location-based pseudo classes' do
|
36
31
|
@processed.at_css('#izq')['style'].should match_style /padding: 1.0px;/
|
37
32
|
end
|
@@ -40,9 +35,13 @@ describe InlineStyle do
|
|
40
35
|
@processed.css('#logos #der').first['style'].should match_style /float: right;/
|
41
36
|
end
|
42
37
|
|
43
|
-
|
44
|
-
|
45
|
-
|
38
|
+
it 'should not override rules defined inline' do
|
39
|
+
@processed.css('#aviso').first['style'].should match_style /color: green;/
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should overwrite rule previously defined' do
|
43
|
+
@processed.css('#izq').first['style'].should_not match_style /padding: 0.0;/
|
44
|
+
end
|
46
45
|
|
47
46
|
describe 'Box model' do
|
48
47
|
before do
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe 'CSS parsing' do
|
4
|
+
shared_examples_for 'parses css' do
|
5
|
+
describe 'parsing tag selector' do
|
6
|
+
before do
|
7
|
+
@wrapper = subject.new 'p {background-color: black; padding: 0.0 0.0 0.0 0.0}'
|
8
|
+
end
|
9
|
+
|
10
|
+
it { @wrapper.should have(1).rules }
|
11
|
+
|
12
|
+
describe 'rule' do
|
13
|
+
before { @rule = @wrapper.rules.first }
|
14
|
+
it { @rule.specificity.should == '0001' }
|
15
|
+
it { @rule.declarations.should == [['background-color', 'black'], ['padding', '0.0 0.0 0.0 0.0']] }
|
16
|
+
it { @rule.selector.should == 'p' }
|
17
|
+
it { @rule.dynamic_pseudo_class.should be_nil }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'parsing body tag selector' do
|
22
|
+
before do
|
23
|
+
@wrapper = subject.new 'body {background-color: black; padding: 0.0 0.0 0.0 0.0}'
|
24
|
+
end
|
25
|
+
|
26
|
+
it { @wrapper.should have(1).rules }
|
27
|
+
|
28
|
+
describe 'rule' do
|
29
|
+
before { @rule = @wrapper.rules.first }
|
30
|
+
it { @rule.specificity.should == '0001' }
|
31
|
+
it { @rule.declarations.should == [['background-color', 'black'], ['padding', '0.0 0.0 0.0 0.0']] }
|
32
|
+
it { @rule.selector.should == 'body' }
|
33
|
+
it { @rule.dynamic_pseudo_class.should be_nil }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'parsing tag and class selector' do
|
38
|
+
before do
|
39
|
+
@wrapper = subject.new 'div.article {background-color: black; padding: 0.0 0.0 0.0 0.0}'
|
40
|
+
end
|
41
|
+
|
42
|
+
it { @wrapper.should have(1).rules }
|
43
|
+
|
44
|
+
describe 'rule' do
|
45
|
+
before { @rule = @wrapper.rules.first }
|
46
|
+
it { @rule.specificity.should == '0011' }
|
47
|
+
it { @rule.declarations.should == [['background-color', 'black'], ['padding', '0.0 0.0 0.0 0.0']] }
|
48
|
+
it { @rule.selector.should == 'div.article' }
|
49
|
+
it { @rule.dynamic_pseudo_class.should be_nil }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'parsing tag, class and id selector' do
|
54
|
+
before do
|
55
|
+
@wrapper = subject.new 'div#headline.article {background-color: black; padding: 0.0 0.0 0.0 0.0}'
|
56
|
+
end
|
57
|
+
|
58
|
+
it { @wrapper.should have(1).rules }
|
59
|
+
|
60
|
+
describe 'rule' do
|
61
|
+
before { @rule = @wrapper.rules.first }
|
62
|
+
it { @rule.specificity.should == '0111' }
|
63
|
+
it { @rule.declarations.should == [['background-color', 'black'], ['padding', '0.0 0.0 0.0 0.0']] }
|
64
|
+
it { @rule.selector.should == 'div#headline.article' }
|
65
|
+
it { @rule.dynamic_pseudo_class.should be_nil }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'parsing tag selector' do
|
70
|
+
before do
|
71
|
+
@wrapper = subject.new 'p, div {background-color: black; padding: 0.0 0.0 0.0 0.0}'
|
72
|
+
end
|
73
|
+
|
74
|
+
it { @wrapper.should have(2).rules }
|
75
|
+
|
76
|
+
describe 'first rule' do
|
77
|
+
before { @rule = @wrapper.rules.first }
|
78
|
+
it { @rule.specificity.should == '0001' }
|
79
|
+
it { @rule.declarations.should == [['background-color', 'black'], ['padding', '0.0 0.0 0.0 0.0']] }
|
80
|
+
it { @rule.selector.should == 'p' }
|
81
|
+
it { @rule.dynamic_pseudo_class.should be_nil }
|
82
|
+
end
|
83
|
+
|
84
|
+
describe 'last rule' do
|
85
|
+
before { @rule = @wrapper.rules.last }
|
86
|
+
it { @rule.specificity.should == '0001' }
|
87
|
+
it { @rule.declarations.should == [['background-color', 'black'], ['padding', '0.0 0.0 0.0 0.0']] }
|
88
|
+
it { @rule.selector.should == 'div' }
|
89
|
+
it { @rule.dynamic_pseudo_class.should be_nil }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'dynamic pseudo selectors' do
|
94
|
+
InlineStyle::Rule::DYNAMIC_PSEUDO_CLASSES.each do |pseudo_class|
|
95
|
+
describe "parsing tag with :#{pseudo_class}" do
|
96
|
+
before { @dynamic_pseudo_class = pseudo_class }
|
97
|
+
it_should_behave_like 'parses dynamic pseudo selector'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
shared_examples_for 'parses dynamic pseudo selector' do
|
104
|
+
describe 'with tag' do
|
105
|
+
before do
|
106
|
+
@wrapper = subject.new "p:#{@dynamic_pseudo_class} {background-color: black; padding: 0.0 0.0 0.0 0.0}"
|
107
|
+
end
|
108
|
+
|
109
|
+
it { @wrapper.should have(1).rules }
|
110
|
+
|
111
|
+
describe 'rule' do
|
112
|
+
before { @rule = @wrapper.rules.first }
|
113
|
+
# it { @rule.specificity.should == '011' }
|
114
|
+
it { @rule.declarations.should == [['background-color', 'black'], ['padding', '0.0 0.0 0.0 0.0']] }
|
115
|
+
it { @rule.selector.should == 'p' }
|
116
|
+
it { @rule.dynamic_pseudo_class.should == @dynamic_pseudo_class }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe 'without tag' do
|
121
|
+
before do
|
122
|
+
@wrapper = subject.new ":#{@dynamic_pseudo_class} {background-color: black; padding: 0.0 0.0 0.0 0.0}"
|
123
|
+
end
|
124
|
+
|
125
|
+
it { @wrapper.should have(1).rules }
|
126
|
+
|
127
|
+
describe 'rule' do
|
128
|
+
before { @rule = @wrapper.rules.first }
|
129
|
+
# it { @rule.specificity.should == '011' }
|
130
|
+
it { @rule.declarations.should == [['background-color', 'black'], ['padding', '0.0 0.0 0.0 0.0']] }
|
131
|
+
it { @rule.selector.should == '*' }
|
132
|
+
it { @rule.dynamic_pseudo_class.should == @dynamic_pseudo_class }
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe InlineStyle::CssParserWrapper do
|
138
|
+
subject { InlineStyle::CssParserWrapper }
|
139
|
+
it_should_behave_like 'parses css'
|
140
|
+
end
|
141
|
+
|
142
|
+
describe InlineStyle::CssParserWrapper do
|
143
|
+
subject { InlineStyle::CSSPoolWrapper }
|
144
|
+
it_should_behave_like 'parses css'
|
145
|
+
end
|
146
|
+
end
|
data/spec/fixtures/all.css
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
#izq {
|
2
|
-
|
3
|
-
}
|
2
|
+
border: none;
|
3
|
+
}
|
data/spec/fixtures/boletin.html
CHANGED
@@ -52,6 +52,7 @@ p {
|
|
52
52
|
#aviso {
|
53
53
|
padding: 25px 0;
|
54
54
|
text-align: center;
|
55
|
+
color: blue;
|
55
56
|
}
|
56
57
|
|
57
58
|
dl.categoria dt {
|
@@ -143,7 +144,7 @@ div#contacto a {
|
|
143
144
|
|
144
145
|
|
145
146
|
<div id="header">
|
146
|
-
<div id="aviso">Si usted no puede visualizar correctamente este boletín haga <a href="http://localhost:3000/boletines/noviembre-2009">click aquí</a></div>
|
147
|
+
<div id="aviso" style='color: green;'>Si usted no puede visualizar correctamente este boletín haga <a href="http://localhost:3000/boletines/noviembre-2009">click aquí</a></div>
|
147
148
|
<div id="banner"><span id="cenart">CENART</span> Noviembre 2009</div>
|
148
149
|
</div>
|
149
150
|
|
data/spec/fixtures/inline.html
CHANGED
@@ -6,97 +6,97 @@
|
|
6
6
|
</title>
|
7
7
|
<link href="/print.css?1248460539" rel="stylesheet" media="print" type="text/css">
|
8
8
|
</head>
|
9
|
-
<body style='font:
|
10
|
-
<div id="header" style="margin: 0
|
11
|
-
<div id="aviso" style="margin: 0
|
9
|
+
<body style='margin: 0; padding: 0; font: 13px "Lucida Grande", Lucida, Verdana, sans-serif; width: 680px; color: #373737; margin-left: auto; margin-right: auto;'>
|
10
|
+
<div id="header" style="margin: 0; padding: 0;">
|
11
|
+
<div id="aviso" style="margin: 0; padding: 25px 0; text-align: center; color: green;">Si usted no puede visualizar correctamente este boletín haga <a href="http://localhost:3000/boletines/noviembre-2009" style="margin: 0; padding: 0; color: #185d6b;">click aquí</a>
|
12
12
|
</div>
|
13
|
-
<div id="banner" style="margin:
|
14
|
-
<span id="cenart" style="margin: 0
|
13
|
+
<div id="banner" style="margin: 15px; padding: 0; text-align: right; color: #639b22;">
|
14
|
+
<span id="cenart" style="margin: 0; padding: 0; font-size: 20px;">CENART</span> Noviembre 2009</div>
|
15
15
|
</div>
|
16
16
|
|
17
17
|
|
18
18
|
|
19
19
|
|
20
20
|
|
21
|
-
<dl class="categoria" id="A" style="margin: 0
|
22
|
-
<dt style="margin: 0
|
23
|
-
<dd style="margin: 0
|
21
|
+
<dl class="categoria" id="A" style="margin: 0; padding: 0;">
|
22
|
+
<dt style="margin: 0; padding: 10px; font-size: 20px; background-color: #416517; border-bottom: 1px dashed #a6a6a6; color: #a0bf57;">A</dt>
|
23
|
+
<dd style="margin: 0; padding: 0;">
|
24
24
|
|
25
25
|
|
26
|
-
<dl class="evento non" style="margin: 0
|
27
|
-
<dt style="margin: 0
|
26
|
+
<dl class="evento non" style="margin: 0; padding: 30px 25px 20px 35px; border-bottom: 1px dashed #a6a6a6; background-color: #d9e3cf;">
|
27
|
+
<dt style="margin: 0; padding: 0; font-size: 20px; background-color: #416517; border-bottom: 1px dashed #a6a6a6; color: #a0bf57; background: none; font-weight: bold; border: none;"><a href="" style="margin: 0; padding: 0; color: #185d6b;">1</a></dt>
|
28
28
|
|
29
|
-
<dd class="descripcion" style="margin: 0
|
30
|
-
<p style="margin: 0
|
29
|
+
<dd class="descripcion" style="margin: 10px 0; padding: 0; text-align: justify;">
|
30
|
+
<p style="margin: 10px 0; padding: 0;">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
|
31
31
|
</dd>
|
32
|
-
<dd class="fechas" style="margin: 0
|
33
|
-
<b style="margin: 0
|
34
|
-
<dd class="locacion" style="margin: 0
|
35
|
-
<b style="margin: 0
|
36
|
-
<dd class="precio" style="margin: 0
|
37
|
-
<b style="margin: 0
|
38
|
-
<dd class="precio" style="margin: 0
|
39
|
-
<b style="margin: 0
|
32
|
+
<dd class="fechas" style="margin: 10px 0; padding: 0; text-align: justify;">
|
33
|
+
<b style="margin: 0; padding: 0; color: #185d6b;">Fechas: </b>Fecha</dd>
|
34
|
+
<dd class="locacion" style="margin: 10px 0; padding: 0; text-align: justify;">
|
35
|
+
<b style="margin: 0; padding: 0; color: #185d6b;">Lugar: </b>Lugar</dd>
|
36
|
+
<dd class="precio" style="margin: 10px 0; padding: 0; text-align: justify;">
|
37
|
+
<b style="margin: 0; padding: 0; color: #185d6b;">Público: </b>Público</dd>
|
38
|
+
<dd class="precio" style="margin: 10px 0; padding: 0; text-align: justify;">
|
39
|
+
<b style="margin: 0; padding: 0; color: #185d6b;">Precio: </b>Precio</dd>
|
40
40
|
</dl>
|
41
41
|
</dd>
|
42
42
|
</dl>
|
43
|
-
<dl class="categoria" id="B" style="margin: 0
|
44
|
-
<dt style="margin: 0
|
45
|
-
<dd style="margin: 0
|
43
|
+
<dl class="categoria" id="B" style="margin: 0; padding: 0;">
|
44
|
+
<dt style="margin: 0; padding: 10px; font-size: 20px; background-color: #416517; border-bottom: 1px dashed #a6a6a6; color: #a0bf57;">B</dt>
|
45
|
+
<dd style="margin: 0; padding: 0;">
|
46
46
|
|
47
47
|
|
48
|
-
<dl class="evento par" style="margin: 0
|
49
|
-
<dt style="margin: 0
|
48
|
+
<dl class="evento par" style="margin: 0; padding: 30px 25px 20px 35px; border-bottom: 1px dashed #a6a6a6; background-color: #cfdfe3;">
|
49
|
+
<dt style="margin: 0; padding: 0; font-size: 20px; background-color: #416517; border-bottom: 1px dashed #a6a6a6; color: #a0bf57; background: none; font-weight: bold; border: none;"><a href="" style="margin: 0; padding: 0; color: #185d6b;">1</a></dt>
|
50
50
|
|
51
|
-
<dd class="descripcion" style="margin: 0
|
52
|
-
<p style="margin: 0
|
51
|
+
<dd class="descripcion" style="margin: 10px 0; padding: 0; text-align: justify;">
|
52
|
+
<p style="margin: 10px 0; padding: 0;">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
|
53
53
|
</dd>
|
54
|
-
<dd class="fechas" style="margin: 0
|
55
|
-
<b style="margin: 0
|
56
|
-
<dd class="locacion" style="margin: 0
|
57
|
-
<b style="margin: 0
|
58
|
-
<dd class="precio" style="margin: 0
|
59
|
-
<b style="margin: 0
|
60
|
-
<dd class="precio" style="margin: 0
|
61
|
-
<b style="margin: 0
|
54
|
+
<dd class="fechas" style="margin: 10px 0; padding: 0; text-align: justify;">
|
55
|
+
<b style="margin: 0; padding: 0; color: #185d6b;">Fechas: </b>Fecha</dd>
|
56
|
+
<dd class="locacion" style="margin: 10px 0; padding: 0; text-align: justify;">
|
57
|
+
<b style="margin: 0; padding: 0; color: #185d6b;">Lugar: </b>Lugar</dd>
|
58
|
+
<dd class="precio" style="margin: 10px 0; padding: 0; text-align: justify;">
|
59
|
+
<b style="margin: 0; padding: 0; color: #185d6b;">Público: </b>Público</dd>
|
60
|
+
<dd class="precio" style="margin: 10px 0; padding: 0; text-align: justify;">
|
61
|
+
<b style="margin: 0; padding: 0; color: #185d6b;">Precio: </b>Precio</dd>
|
62
62
|
</dl>
|
63
63
|
</dd>
|
64
64
|
</dl>
|
65
|
-
<dl class="categoria" id="C" style="margin: 0
|
66
|
-
<dt style="margin: 0
|
67
|
-
<dd style="margin: 0
|
65
|
+
<dl class="categoria" id="C" style="margin: 0; padding: 0;">
|
66
|
+
<dt style="margin: 0; padding: 10px; font-size: 20px; background-color: #416517; border-bottom: 1px dashed #a6a6a6; color: #a0bf57;">C</dt>
|
67
|
+
<dd style="margin: 0; padding: 0;">
|
68
68
|
|
69
69
|
|
70
|
-
<dl class="evento non" style="margin: 0
|
71
|
-
<dt style="margin: 0
|
70
|
+
<dl class="evento non" style="margin: 0; padding: 30px 25px 20px 35px; border-bottom: 1px dashed #a6a6a6; background-color: #d9e3cf;">
|
71
|
+
<dt style="margin: 0; padding: 0; font-size: 20px; background-color: #416517; border-bottom: 1px dashed #a6a6a6; color: #a0bf57; background: none; font-weight: bold; border: none;"><a href="" style="margin: 0; padding: 0; color: #185d6b;">1</a></dt>
|
72
72
|
|
73
|
-
<dd class="descripcion" style="margin: 0
|
74
|
-
<p style="margin: 0
|
73
|
+
<dd class="descripcion" style="margin: 10px 0; padding: 0; text-align: justify;">
|
74
|
+
<p style="margin: 10px 0; padding: 0;">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
|
75
75
|
</dd>
|
76
|
-
<dd class="fechas" style="margin: 0
|
77
|
-
<b style="margin: 0
|
78
|
-
<dd class="locacion" style="margin: 0
|
79
|
-
<b style="margin: 0
|
80
|
-
<dd class="precio" style="margin: 0
|
81
|
-
<b style="margin: 0
|
82
|
-
<dd class="precio" style="margin: 0
|
83
|
-
<b style="margin: 0
|
76
|
+
<dd class="fechas" style="margin: 10px 0; padding: 0; text-align: justify;">
|
77
|
+
<b style="margin: 0; padding: 0; color: #185d6b;">Fechas: </b>Fecha</dd>
|
78
|
+
<dd class="locacion" style="margin: 10px 0; padding: 0; text-align: justify;">
|
79
|
+
<b style="margin: 0; padding: 0; color: #185d6b;">Lugar: </b>Lugar</dd>
|
80
|
+
<dd class="precio" style="margin: 10px 0; padding: 0; text-align: justify;">
|
81
|
+
<b style="margin: 0; padding: 0; color: #185d6b;">Público: </b>Público</dd>
|
82
|
+
<dd class="precio" style="margin: 10px 0; padding: 0; text-align: justify;">
|
83
|
+
<b style="margin: 0; padding: 0; color: #185d6b;">Precio: </b>Precio</dd>
|
84
84
|
</dl>
|
85
85
|
</dd>
|
86
86
|
</dl>
|
87
|
-
<div id="footer" style="margin: 0
|
88
|
-
<div id="direccion" style="margin: 0
|
89
|
-
<b style="margin: 0
|
90
|
-
ipsum<br style="margin: 0
|
91
|
-
dolor<br style="margin: 0
|
92
|
-
sit<br style="margin: 0
|
87
|
+
<div id="footer" style="margin: 0; padding: 0;">
|
88
|
+
<div id="direccion" style="margin: 0; padding: 30px 25px 20px 35px;">
|
89
|
+
<b style="margin: 0; padding: 0; color: #5f792d;">lorem</b><br style="margin: 0; padding: 0;">
|
90
|
+
ipsum<br style="margin: 0; padding: 0;">
|
91
|
+
dolor<br style="margin: 0; padding: 0;">
|
92
|
+
sit<br style="margin: 0; padding: 0;">
|
93
93
|
</div>
|
94
94
|
|
95
|
-
<div id="contacto" style="margin: 0
|
96
|
-
contacto <br style="margin: 0
|
95
|
+
<div id="contacto" style="margin: 0; padding: 30px 25px 20px 35px;">
|
96
|
+
contacto <br style="margin: 0; padding: 0;"><a href="mailto:mail@host.org" style="margin: 0; padding: 0; color: #185d6b; font-weight: bold; font-size: 1.2em;">mail@host.org</a>
|
97
97
|
</div>
|
98
|
-
<div id="logos" style="margin: 0
|
99
|
-
<img src="A" id="izq" alt="A" style="margin:
|
98
|
+
<div id="logos" style="margin: 0; padding: 0; width: 100%; margin-top: 40px; background-image: url('/images/boletines/Noviembre/logos_fondo.jpg');">
|
99
|
+
<img src="A" id="izq" alt="A" style="margin: 30px; padding: 1px; float: left; border: none; color: red;"><img src="B" id="der" alt="B" style="margin: 0; padding: 0; float: right;"><div class="clearer" style="margin: 0; padding: 0; clear: both;">
|
100
100
|
</div>
|
101
101
|
</div>
|
102
102
|
|
data/spec/interceptor_spec.rb
CHANGED
@@ -1,27 +1,16 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "inline-style/mail/interceptor"
|
3
|
-
require "mail"
|
1
|
+
require "#{ File.dirname __FILE__ }/spec_helper"
|
4
2
|
|
3
|
+
require 'mail'
|
5
4
|
Mail.defaults do
|
6
5
|
delivery_method :test
|
7
6
|
end
|
8
|
-
|
9
|
-
|
7
|
+
Mail.register_interceptor \
|
8
|
+
InlineStyle::Mail::Interceptor.new(:stylesheets_path => FIXTURES)
|
10
9
|
|
11
10
|
describe InlineStyle::Mail::Interceptor do
|
11
|
+
|
12
12
|
before do
|
13
13
|
Mail::TestMailer.deliveries.clear
|
14
|
-
class InlineStyle
|
15
|
-
remove_const :CSSParser
|
16
|
-
CSSParser = InlineStyle::CSSPoolWrapper
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
after do
|
21
|
-
class InlineStyle
|
22
|
-
remove_const :CSSParser
|
23
|
-
CSSParser = InlineStyle::CssParserWrapper
|
24
|
-
end
|
25
14
|
end
|
26
15
|
|
27
16
|
it 'should inline html e-mail' do
|
@@ -70,4 +59,6 @@ describe InlineStyle::Mail::Interceptor do
|
|
70
59
|
Mail::TestMailer.deliveries.first.parts[1].body.to_s.
|
71
60
|
should == File.read("#{ FIXTURES }/inline.html")
|
72
61
|
end
|
62
|
+
|
73
63
|
end
|
64
|
+
|
data/spec/spec_helper.rb
CHANGED
@@ -5,6 +5,8 @@ require 'rack/mock'
|
|
5
5
|
|
6
6
|
require "inline-style"
|
7
7
|
require "inline-style/csspool_wrapper"
|
8
|
+
|
9
|
+
gem 'maca-fork-csspool'
|
8
10
|
require "csspool"
|
9
11
|
|
10
12
|
FIXTURES = "#{File.dirname __FILE__}/fixtures"
|
@@ -40,11 +42,11 @@ module InlineStyleMatchers
|
|
40
42
|
end
|
41
43
|
|
42
44
|
def failure_message
|
43
|
-
"expected #{@
|
45
|
+
"expected #{@actual} to match #{@style}"
|
44
46
|
end
|
45
47
|
|
46
48
|
def negative_failure_message
|
47
|
-
"expected #{@
|
49
|
+
"expected #{@actual} not to match #{@style}"
|
48
50
|
end
|
49
51
|
end
|
50
52
|
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inline-style
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
4
|
+
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
7
|
+
- 5
|
8
|
+
- 0
|
9
|
+
version: 0.5.0
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Macario Ortega
|
@@ -16,7 +15,7 @@ autorequire:
|
|
16
15
|
bindir: bin
|
17
16
|
cert_chain: []
|
18
17
|
|
19
|
-
date: 2011-03-
|
18
|
+
date: 2011-03-24 00:00:00 -06:00
|
20
19
|
default_executable:
|
21
20
|
dependencies:
|
22
21
|
- !ruby/object:Gem::Dependency
|
@@ -27,7 +26,6 @@ dependencies:
|
|
27
26
|
requirements:
|
28
27
|
- - ">="
|
29
28
|
- !ruby/object:Gem::Version
|
30
|
-
hash: 3
|
31
29
|
segments:
|
32
30
|
- 0
|
33
31
|
version: "0"
|
@@ -41,7 +39,6 @@ dependencies:
|
|
41
39
|
requirements:
|
42
40
|
- - ">="
|
43
41
|
- !ruby/object:Gem::Version
|
44
|
-
hash: 3
|
45
42
|
segments:
|
46
43
|
- 0
|
47
44
|
version: "0"
|
@@ -55,7 +52,6 @@ dependencies:
|
|
55
52
|
requirements:
|
56
53
|
- - ">="
|
57
54
|
- !ruby/object:Gem::Version
|
58
|
-
hash: 3
|
59
55
|
segments:
|
60
56
|
- 0
|
61
57
|
version: "0"
|
@@ -69,7 +65,6 @@ dependencies:
|
|
69
65
|
requirements:
|
70
66
|
- - ">="
|
71
67
|
- !ruby/object:Gem::Version
|
72
|
-
hash: 3
|
73
68
|
segments:
|
74
69
|
- 0
|
75
70
|
version: "0"
|
@@ -83,40 +78,50 @@ dependencies:
|
|
83
78
|
requirements:
|
84
79
|
- - ">="
|
85
80
|
- !ruby/object:Gem::Version
|
86
|
-
hash: 3
|
87
81
|
segments:
|
88
82
|
- 0
|
89
83
|
version: "0"
|
90
84
|
type: :runtime
|
91
85
|
version_requirements: *id005
|
92
86
|
- !ruby/object:Gem::Dependency
|
93
|
-
name:
|
87
|
+
name: facets
|
94
88
|
prerelease: false
|
95
89
|
requirement: &id006 !ruby/object:Gem::Requirement
|
96
90
|
none: false
|
97
91
|
requirements:
|
98
92
|
- - ">="
|
99
93
|
- !ruby/object:Gem::Version
|
100
|
-
hash: 3
|
101
94
|
segments:
|
102
95
|
- 0
|
103
96
|
version: "0"
|
104
97
|
type: :runtime
|
105
98
|
version_requirements: *id006
|
106
99
|
- !ruby/object:Gem::Dependency
|
107
|
-
name:
|
100
|
+
name: css_parser
|
108
101
|
prerelease: false
|
109
102
|
requirement: &id007 !ruby/object:Gem::Requirement
|
110
103
|
none: false
|
111
104
|
requirements:
|
112
105
|
- - ">="
|
113
106
|
- !ruby/object:Gem::Version
|
114
|
-
hash: 3
|
115
107
|
segments:
|
116
108
|
- 0
|
117
109
|
version: "0"
|
118
110
|
type: :runtime
|
119
111
|
version_requirements: *id007
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: maca-fork-csspool
|
114
|
+
prerelease: false
|
115
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
segments:
|
121
|
+
- 0
|
122
|
+
version: "0"
|
123
|
+
type: :runtime
|
124
|
+
version_requirements: *id008
|
120
125
|
description: Inlines CSS for html email delivery
|
121
126
|
email:
|
122
127
|
- macarui@gmail.com
|
@@ -140,12 +145,12 @@ files:
|
|
140
145
|
- lib/inline-style.rb
|
141
146
|
- lib/inline-style/css_parser_wrapper.rb
|
142
147
|
- lib/inline-style/csspool_wrapper.rb
|
143
|
-
- lib/inline-style/mail
|
144
|
-
- lib/inline-style/rack
|
145
|
-
- lib/inline-style/
|
148
|
+
- lib/inline-style/mail-interceptor.rb
|
149
|
+
- lib/inline-style/rack-middleware.rb
|
150
|
+
- lib/inline-style/rule.rb
|
146
151
|
- lib/inline-style/version.rb
|
147
152
|
- spec/css_inlining_spec.rb
|
148
|
-
- spec/
|
153
|
+
- spec/css_parsing_spec.rb
|
149
154
|
- spec/fixtures/all.css
|
150
155
|
- spec/fixtures/boletin.html
|
151
156
|
- spec/fixtures/box-model.html
|
@@ -171,7 +176,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
171
176
|
requirements:
|
172
177
|
- - ">="
|
173
178
|
- !ruby/object:Gem::Version
|
174
|
-
hash: 3
|
175
179
|
segments:
|
176
180
|
- 0
|
177
181
|
version: "0"
|
@@ -180,14 +184,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
180
184
|
requirements:
|
181
185
|
- - ">="
|
182
186
|
- !ruby/object:Gem::Version
|
183
|
-
hash: 3
|
184
187
|
segments:
|
185
188
|
- 0
|
186
189
|
version: "0"
|
187
190
|
requirements: []
|
188
191
|
|
189
192
|
rubyforge_project:
|
190
|
-
rubygems_version: 1.
|
193
|
+
rubygems_version: 1.3.7
|
191
194
|
signing_key:
|
192
195
|
specification_version: 3
|
193
196
|
summary: Inlines CSS for html email delivery
|
@@ -1,41 +0,0 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# A simple abstraction of the data we get back from the parsers. CSSPool
|
4
|
-
# actually already does this for us but CSSParser does not so we need
|
5
|
-
# to create the abstraction ourselves.
|
6
|
-
class InlineStyle
|
7
|
-
class Selector < Struct.new :selector_text, :declarations, :specificity
|
8
|
-
# A slightly adjusted version of the selector_text that should be
|
9
|
-
# used for finding nodes. Will remove the pseudo selector and prepend
|
10
|
-
# 'body '.
|
11
|
-
def search
|
12
|
-
selector_text.dup.tap do |s|
|
13
|
-
state_based_pseudo_selectors.each {|p| s.gsub! /:#{p}$/, ''}
|
14
|
-
s.insert(0, 'body ') unless s =~ /^body/
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# For the most part is just declarations unless a pseudo selector.
|
19
|
-
# Then it uses the inline pseudo declarations
|
20
|
-
def inline_declarations
|
21
|
-
if pseudo?
|
22
|
-
"\n#{ selector_text.gsub /\w(?=:)/, '' } {#{ declarations }}"
|
23
|
-
else
|
24
|
-
declarations
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
# Is this selector using a pseudo class?
|
29
|
-
def pseudo?
|
30
|
-
state_based_pseudo_selectors.any? {|p| selector_text.end_with? ":#{p}"}
|
31
|
-
end
|
32
|
-
|
33
|
-
# A list of state based pseudo selectors (like hover) that should
|
34
|
-
# be handled based on the pseudo option. Unlike position-based
|
35
|
-
# pseudo selectors (like :first-child) which once resolved to the
|
36
|
-
# correct node effectively get inlined like a normal selector.
|
37
|
-
def state_based_pseudo_selectors
|
38
|
-
%w(link visited active hover focus target enabled disabled checked)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
data/spec/css_parsers_spec.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe InlineStyle::CssParserWrapper do
|
4
|
-
|
5
|
-
it 'should wrap css_parser' do
|
6
|
-
rs_count = 0
|
7
|
-
sel_count = 0
|
8
|
-
selectors = %w(p b i)
|
9
|
-
decs = ['color: black;', 'color: black;', 'color: green; text-decoration: none;']
|
10
|
-
spes = [1, 1, 1]
|
11
|
-
p = InlineStyle::CssParserWrapper.new "p, b {color: black}\ni {color: green; text-decoration: none}"
|
12
|
-
|
13
|
-
p.each_rule_set do |rs|
|
14
|
-
rs_count += 1
|
15
|
-
rs.each_selector do |sel|
|
16
|
-
sel_count += 1
|
17
|
-
sel.selector_text.should == selectors.shift
|
18
|
-
sel.declarations.should == decs.shift
|
19
|
-
sel.specificity.should == spes.shift
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
rs_count.should == 2
|
24
|
-
sel_count.should == 3
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
describe InlineStyle::CSSPoolWrapper do
|
30
|
-
|
31
|
-
it 'should wrap csspool' do
|
32
|
-
rs_count = 0
|
33
|
-
sel_count = 0
|
34
|
-
selectors = %w(p b i)
|
35
|
-
decs = ['color: black;', 'color: black;', 'color: green; text-decoration: none;']
|
36
|
-
spes = [1, 1, 1]
|
37
|
-
p = InlineStyle::CSSPoolWrapper.new "p, b {color: black}\ni {color: green; text-decoration: none}"
|
38
|
-
|
39
|
-
p.each_rule_set do |rs|
|
40
|
-
rs_count += 1
|
41
|
-
rs.each_selector do |sel|
|
42
|
-
sel_count += 1
|
43
|
-
sel.selector_text.should == selectors.shift
|
44
|
-
sel.declarations.should == decs.shift
|
45
|
-
sel.specificity.should == spes.shift
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
rs_count.should == 2
|
50
|
-
sel_count.should == 3
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|