csspool 2.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/CHANGELOG.rdoc +6 -0
- data/Manifest.txt +10 -14
- data/README.rdoc +8 -21
- data/Rakefile +36 -2
- data/lib/csspool/collection.rb +2 -2
- data/lib/csspool/css/charset.rb +8 -2
- data/lib/csspool/css/declaration.rb +13 -2
- data/lib/csspool/css/document_handler.rb +3 -3
- data/lib/csspool/css/import_rule.rb +15 -3
- data/lib/csspool/css/media.rb +8 -2
- data/lib/csspool/css/parser.rb +1090 -0
- data/lib/csspool/css/parser.y +347 -0
- data/lib/csspool/css/rule_set.rb +8 -3
- data/lib/csspool/css/tokenizer.rb +228 -0
- data/lib/csspool/css/tokenizer.rex +96 -0
- data/lib/csspool/css.rb +1 -0
- data/lib/csspool/node.rb +29 -1
- data/lib/csspool/sac/document.rb +3 -3
- data/lib/csspool/sac/parser.rb +6 -112
- data/lib/csspool/terms/function.rb +1 -1
- data/lib/csspool/terms/ident.rb +1 -1
- data/lib/csspool/terms/number.rb +1 -1
- data/lib/csspool/terms/rgb.rb +1 -4
- data/lib/csspool/terms/string.rb +1 -1
- data/lib/csspool/visitors/children.rb +50 -0
- data/lib/csspool/visitors/comparable.rb +9 -3
- data/lib/csspool/visitors/iterator.rb +80 -0
- data/lib/csspool/visitors/to_css.rb +61 -45
- data/lib/csspool/visitors.rb +2 -0
- data/lib/csspool.rb +6 -3
- data/test/css/test_parser.rb +412 -0
- data/test/css/test_tokenizer.rb +320 -0
- data/test/helper.rb +2 -2
- data/test/sac/test_parser.rb +3 -8
- data/test/sac/test_terms.rb +128 -34
- data/test/test_collection.rb +1 -1
- data/test/test_parser.rb +1 -1
- data/test/visitors/test_children.rb +20 -0
- data/test/visitors/test_comparable.rb +31 -1
- data/test/visitors/test_each.rb +19 -0
- data/test/visitors/test_to_css.rb +125 -1
- metadata +90 -68
- data/lib/csspool/lib_croco/cr_additional_sel.rb +0 -46
- data/lib/csspool/lib_croco/cr_attr_sel.rb +0 -16
- data/lib/csspool/lib_croco/cr_doc_handler.rb +0 -24
- data/lib/csspool/lib_croco/cr_num.rb +0 -13
- data/lib/csspool/lib_croco/cr_parser.rb +0 -11
- data/lib/csspool/lib_croco/cr_parsing_location.rb +0 -17
- data/lib/csspool/lib_croco/cr_pseudo.rb +0 -14
- data/lib/csspool/lib_croco/cr_rgb.rb +0 -18
- data/lib/csspool/lib_croco/cr_selector.rb +0 -34
- data/lib/csspool/lib_croco/cr_simple_sel.rb +0 -54
- data/lib/csspool/lib_croco/cr_term.rb +0 -97
- data/lib/csspool/lib_croco/glist.rb +0 -21
- data/lib/csspool/lib_croco.rb +0 -78
- data/lib/csspool/visitable.rb +0 -18
data/lib/csspool/node.rb
CHANGED
@@ -1,5 +1,33 @@
|
|
1
1
|
module CSSPool
|
2
2
|
class Node
|
3
|
-
include
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def accept target
|
6
|
+
target.accept self
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_css
|
10
|
+
accept Visitors::ToCSS.new
|
11
|
+
end
|
12
|
+
alias :to_s :to_css
|
13
|
+
|
14
|
+
def == other
|
15
|
+
return false unless self.class == other.class
|
16
|
+
|
17
|
+
accept Visitors::Comparable.new other
|
18
|
+
end
|
19
|
+
alias :eql? :==
|
20
|
+
|
21
|
+
def each &block
|
22
|
+
Visitors::Iterator.new(block).accept self
|
23
|
+
end
|
24
|
+
|
25
|
+
def children
|
26
|
+
accept Visitors::Children.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def hash
|
30
|
+
@hash ||= children.map { |child| child.hash }.hash
|
31
|
+
end
|
4
32
|
end
|
5
33
|
end
|
data/lib/csspool/sac/document.rb
CHANGED
@@ -10,7 +10,7 @@ module CSSPool
|
|
10
10
|
def charset name, location
|
11
11
|
end
|
12
12
|
|
13
|
-
def import_style media_list, uri, default_ns, location
|
13
|
+
def import_style media_list, uri, default_ns = nil, location = {}
|
14
14
|
end
|
15
15
|
|
16
16
|
def start_selector selector_list
|
@@ -25,10 +25,10 @@ module CSSPool
|
|
25
25
|
def comment comment
|
26
26
|
end
|
27
27
|
|
28
|
-
def start_media media_list, parse_location
|
28
|
+
def start_media media_list, parse_location = {}
|
29
29
|
end
|
30
30
|
|
31
|
-
def end_media media_list, parse_location
|
31
|
+
def end_media media_list, parse_location = {}
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
data/lib/csspool/sac/parser.rb
CHANGED
@@ -1,121 +1,15 @@
|
|
1
1
|
module CSSPool
|
2
2
|
module SAC
|
3
|
-
class Parser
|
4
|
-
attr_accessor :
|
3
|
+
class Parser < CSSPool::CSS::Tokenizer
|
4
|
+
attr_accessor :handler
|
5
5
|
|
6
|
-
def initialize
|
7
|
-
@
|
8
|
-
@selector_stack = []
|
6
|
+
def initialize handler = CSSPool::CSS::DocumentHandler.new
|
7
|
+
@handler = handler
|
9
8
|
end
|
10
9
|
|
11
10
|
def parse string
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
private
|
16
|
-
def push selectors
|
17
|
-
@selector_stack << selectors
|
18
|
-
end
|
19
|
-
|
20
|
-
def pop
|
21
|
-
@selector_stack.pop
|
22
|
-
end
|
23
|
-
|
24
|
-
def parse_memory string, encoding
|
25
|
-
parser = LibCroco::CRParser.new(
|
26
|
-
LibCroco.cr_parser_new_from_buf(
|
27
|
-
string,
|
28
|
-
string.length,
|
29
|
-
5,
|
30
|
-
0
|
31
|
-
)
|
32
|
-
)
|
33
|
-
sac_handler =
|
34
|
-
LibCroco::CRDocHandler.new(LibCroco.cr_doc_handler_new)
|
35
|
-
|
36
|
-
selector_stack = []
|
37
|
-
media_stack = []
|
38
|
-
|
39
|
-
sac_handler[:start_document] = lambda { |parser|
|
40
|
-
@document.start_document
|
41
|
-
}
|
42
|
-
sac_handler[:end_document] = lambda { |parser|
|
43
|
-
@document.end_document
|
44
|
-
}
|
45
|
-
sac_handler[:charset] = lambda { |dh, name, location|
|
46
|
-
@document.charset(
|
47
|
-
LibCroco.cr_string_peek_raw_str(name).read_string,
|
48
|
-
LibCroco::CRParsingLocation.new(location).to_h
|
49
|
-
)
|
50
|
-
}
|
51
|
-
|
52
|
-
sac_handler[:import_style] = lambda { |dh, media_list, uri, ns, loc|
|
53
|
-
media_list = media_list.null? ? [] : LibCroco::GList.new(media_list)
|
54
|
-
media_list = media_list.to_a.map { |data|
|
55
|
-
LibCroco.cr_string_peek_raw_str(data).read_string
|
56
|
-
}
|
57
|
-
uri = uri.null? ? nil :
|
58
|
-
LibCroco.cr_string_peek_raw_str(uri).read_string
|
59
|
-
|
60
|
-
ns = ns.null? ? nil : LibCroco.cr_string_peek_raw_str(ns).read_string
|
61
|
-
|
62
|
-
@document.import_style(
|
63
|
-
media_list,
|
64
|
-
uri,
|
65
|
-
ns,
|
66
|
-
LibCroco::CRParsingLocation.new(loc).to_h
|
67
|
-
)
|
68
|
-
}
|
69
|
-
|
70
|
-
sac_handler[:start_selector] = lambda { |dh, list|
|
71
|
-
list = [LibCroco::CRSelector.new(list)]
|
72
|
-
pointer = list.last[:next]
|
73
|
-
until pointer.null?
|
74
|
-
list << LibCroco::CRSelector.new(pointer)
|
75
|
-
pointer = list.last[:next]
|
76
|
-
end
|
77
|
-
selector_stack.push list.map { |l| l.to_selector }
|
78
|
-
@document.start_selector selector_stack.last
|
79
|
-
}
|
80
|
-
|
81
|
-
sac_handler[:end_selector] = lambda { |dh, list|
|
82
|
-
@document.end_selector selector_stack.pop
|
83
|
-
}
|
84
|
-
|
85
|
-
sac_handler[:property] = lambda { |dh, name, expr, important|
|
86
|
-
expr_list = []
|
87
|
-
until expr.null?
|
88
|
-
expr_list << LibCroco::CRTerm.new(expr)
|
89
|
-
expr = expr_list.last[:next]
|
90
|
-
end
|
91
|
-
@document.property(
|
92
|
-
LibCroco.cr_string_peek_raw_str(name).read_string,
|
93
|
-
expr_list.map { |ex| ex.to_term },
|
94
|
-
important == 1
|
95
|
-
)
|
96
|
-
}
|
97
|
-
|
98
|
-
sac_handler[:comment] = lambda { |dh, comment|
|
99
|
-
@document.comment(
|
100
|
-
LibCroco.cr_string_peek_raw_str(comment).read_string
|
101
|
-
)
|
102
|
-
}
|
103
|
-
|
104
|
-
sac_handler[:start_media] = lambda { |dh,media_list,location|
|
105
|
-
media_list = LibCroco::GList.new(media_list)
|
106
|
-
media_stack << [media_list.to_a.map { |data|
|
107
|
-
LibCroco.cr_string_peek_raw_str(data).read_string
|
108
|
-
}, LibCroco::CRParsingLocation.new(location).to_h]
|
109
|
-
@document.start_media(*media_stack.last)
|
110
|
-
}
|
111
|
-
|
112
|
-
sac_handler[:end_media] = lambda { |dh,media_list|
|
113
|
-
@document.end_media(*media_stack.pop)
|
114
|
-
}
|
115
|
-
|
116
|
-
LibCroco.cr_parser_set_sac_handler(parser, sac_handler)
|
117
|
-
LibCroco.cr_parser_parse(parser)
|
118
|
-
LibCroco.cr_doc_handler_destroy(sac_handler)
|
11
|
+
scan_str string
|
12
|
+
@handler.document
|
119
13
|
end
|
120
14
|
end
|
121
15
|
end
|
data/lib/csspool/terms/ident.rb
CHANGED
data/lib/csspool/terms/number.rb
CHANGED
@@ -4,7 +4,7 @@ module CSSPool
|
|
4
4
|
attr_accessor :type
|
5
5
|
attr_accessor :unary_operator
|
6
6
|
|
7
|
-
def initialize
|
7
|
+
def initialize value, unary_operator = nil, type = nil, operator = nil, parse_location = {}
|
8
8
|
@type = type
|
9
9
|
@unary_operator = unary_operator
|
10
10
|
super(value, operator, parse_location)
|
data/lib/csspool/terms/rgb.rb
CHANGED
@@ -4,17 +4,14 @@ module CSSPool
|
|
4
4
|
attr_accessor :red
|
5
5
|
attr_accessor :green
|
6
6
|
attr_accessor :blue
|
7
|
-
attr_accessor :percentage
|
8
7
|
attr_accessor :parse_location
|
9
8
|
attr_accessor :operator
|
10
|
-
alias :percentage? :percentage
|
11
9
|
|
12
|
-
def initialize red, green, blue,
|
10
|
+
def initialize red, green, blue, operator = nil, parse_location = {}
|
13
11
|
super()
|
14
12
|
@red = red
|
15
13
|
@green = green
|
16
14
|
@blue = blue
|
17
|
-
@percentage = percentage
|
18
15
|
@operator = operator
|
19
16
|
@parse_location = parse_location
|
20
17
|
end
|
data/lib/csspool/terms/string.rb
CHANGED
@@ -0,0 +1,50 @@
|
|
1
|
+
module CSSPool
|
2
|
+
module Visitors
|
3
|
+
class Children < Visitor
|
4
|
+
visitor_for CSS::Document do |target|
|
5
|
+
children = []
|
6
|
+
[:charsets, :import_rules, :rule_sets].each do |member|
|
7
|
+
children += target.send(member)
|
8
|
+
end
|
9
|
+
children
|
10
|
+
end
|
11
|
+
|
12
|
+
visitor_for CSS::ImportRule do |target|
|
13
|
+
target.media
|
14
|
+
end
|
15
|
+
|
16
|
+
visitor_for CSS::Media,
|
17
|
+
CSS::Charset,
|
18
|
+
Selectors::Id,
|
19
|
+
Selectors::Class,
|
20
|
+
Selectors::PseudoClass,
|
21
|
+
Selectors::Attribute,
|
22
|
+
Terms::Ident,
|
23
|
+
Terms::String,
|
24
|
+
Terms::URI,
|
25
|
+
Terms::Number,
|
26
|
+
Terms::Hash,
|
27
|
+
Terms::Function,
|
28
|
+
Terms::Rgb do |target|
|
29
|
+
[]
|
30
|
+
end
|
31
|
+
|
32
|
+
visitor_for CSS::Declaration do |target|
|
33
|
+
target.expressions
|
34
|
+
end
|
35
|
+
|
36
|
+
visitor_for CSS::RuleSet do |target|
|
37
|
+
target.selectors + target.declarations
|
38
|
+
end
|
39
|
+
|
40
|
+
visitor_for Selector do |target|
|
41
|
+
target.simple_selectors
|
42
|
+
end
|
43
|
+
|
44
|
+
visitor_for Selectors::Type, Selectors::Universal, Selectors::Simple do |target|
|
45
|
+
target.additional_selectors
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -32,11 +32,18 @@ module CSSPool
|
|
32
32
|
}
|
33
33
|
end
|
34
34
|
|
35
|
-
visitor_for
|
35
|
+
visitor_for Selectors::PseudoClass do |target|
|
36
|
+
[:name, :extra].all? { |m|
|
37
|
+
target.send(m) == @other.send(m)
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
visitor_for CSS::Media, Selectors::Id, Selectors::Class do |target|
|
36
42
|
target.name == @other.name
|
37
43
|
end
|
38
44
|
|
39
|
-
visitor_for Selectors::Type
|
45
|
+
visitor_for Selectors::Type, Selectors::Universal,
|
46
|
+
Selectors::Simple do |target|
|
40
47
|
[:name, :combinator, :additional_selectors].all? { |m|
|
41
48
|
target.send(m) == @other.send(m)
|
42
49
|
}
|
@@ -69,7 +76,6 @@ module CSSPool
|
|
69
76
|
:red,
|
70
77
|
:green,
|
71
78
|
:blue,
|
72
|
-
:percentage,
|
73
79
|
:operator
|
74
80
|
].all? { |m| target.send(m) == @other.send(m) }
|
75
81
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module CSSPool
|
2
|
+
module Visitors
|
3
|
+
class Iterator < Visitor
|
4
|
+
def initialize block
|
5
|
+
@block = block
|
6
|
+
end
|
7
|
+
|
8
|
+
visitor_for CSS::Document do |target|
|
9
|
+
[:charsets, :import_rules, :rule_sets].each do |member|
|
10
|
+
target.send(member).each do |node|
|
11
|
+
node.accept self
|
12
|
+
end
|
13
|
+
end
|
14
|
+
@block.call target
|
15
|
+
end
|
16
|
+
|
17
|
+
visitor_for Selectors::Universal, Selectors::Simple do |target|
|
18
|
+
target.children.each do |node|
|
19
|
+
node.accept self
|
20
|
+
end
|
21
|
+
@block.call target
|
22
|
+
end
|
23
|
+
|
24
|
+
visitor_for CSS::Charset do |target|
|
25
|
+
@block.call target
|
26
|
+
end
|
27
|
+
|
28
|
+
visitor_for CSS::ImportRule do |target|
|
29
|
+
target.media.each do |node|
|
30
|
+
node.accept self
|
31
|
+
end
|
32
|
+
@block.call target
|
33
|
+
end
|
34
|
+
|
35
|
+
visitor_for CSS::Media,
|
36
|
+
Selectors::Id,
|
37
|
+
Selectors::Class,
|
38
|
+
Selectors::PseudoClass,
|
39
|
+
Selectors::Attribute,
|
40
|
+
Terms::Ident,
|
41
|
+
Terms::String,
|
42
|
+
Terms::URI,
|
43
|
+
Terms::Number,
|
44
|
+
Terms::Hash,
|
45
|
+
Terms::Function,
|
46
|
+
Terms::Rgb do |target|
|
47
|
+
@block.call target
|
48
|
+
end
|
49
|
+
|
50
|
+
visitor_for CSS::Declaration do |target|
|
51
|
+
target.expressions.each do |node|
|
52
|
+
node.accept self
|
53
|
+
end
|
54
|
+
@block.call target
|
55
|
+
end
|
56
|
+
|
57
|
+
visitor_for CSS::RuleSet do |target|
|
58
|
+
target.selectors.each do |node|
|
59
|
+
node.accept self
|
60
|
+
end
|
61
|
+
target.declarations.each do |node|
|
62
|
+
node.accept self
|
63
|
+
end
|
64
|
+
@block.call target
|
65
|
+
end
|
66
|
+
|
67
|
+
visitor_for Selector do |target|
|
68
|
+
target.simple_selectors.each { |ss| ss.accept self }
|
69
|
+
@block.call target
|
70
|
+
end
|
71
|
+
|
72
|
+
visitor_for Selectors::Type do |target|
|
73
|
+
target.additional_selectors.each do |node|
|
74
|
+
node.accept self
|
75
|
+
end
|
76
|
+
@block.call target
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -1,14 +1,23 @@
|
|
1
1
|
module CSSPool
|
2
2
|
module Visitors
|
3
3
|
class ToCSS < Visitor
|
4
|
+
|
5
|
+
CSS_IDENTIFIER_ILLEGAL_CHARACTERS =
|
6
|
+
(0..255).to_a.pack('U*').gsub(/[a-zA-Z0-9_-]/, '')
|
7
|
+
CSS_STRING_ESCAPE_MAP = {
|
8
|
+
"\\" => "\\\\",
|
9
|
+
"\"" => "\\\"",
|
10
|
+
"\n" => "\\a ", # CSS2 4.1.3 p3.2
|
11
|
+
"\r" => "\\\r",
|
12
|
+
"\f" => "\\\f"
|
13
|
+
}
|
14
|
+
|
4
15
|
def initialize
|
5
16
|
@indent_level = 0
|
6
17
|
@indent_space = ' '
|
7
18
|
end
|
8
19
|
|
9
20
|
visitor_for CSS::Document do |target|
|
10
|
-
media_hash = {}
|
11
|
-
|
12
21
|
# Default media list is []
|
13
22
|
current_media_type = []
|
14
23
|
|
@@ -24,7 +33,10 @@ module CSSPool
|
|
24
33
|
|
25
34
|
target.rule_sets.each { |rs|
|
26
35
|
if rs.media != current_media_type
|
27
|
-
|
36
|
+
media = " " + rs.media.map do |medium|
|
37
|
+
escape_css_identifier medium.name.value
|
38
|
+
end.join(', ')
|
39
|
+
tokens << "#{indent}@media#{media} {"
|
28
40
|
@indent_level += 1
|
29
41
|
end
|
30
42
|
|
@@ -40,16 +52,16 @@ module CSSPool
|
|
40
52
|
end
|
41
53
|
|
42
54
|
visitor_for CSS::Charset do |target|
|
43
|
-
"@charset \"#{target.name}\";"
|
55
|
+
"@charset \"#{escape_css_string target.name}\";"
|
44
56
|
end
|
45
57
|
|
46
58
|
visitor_for CSS::ImportRule do |target|
|
47
59
|
media = ''
|
48
|
-
media = " " + target.media.map
|
49
|
-
|
50
|
-
|
60
|
+
media = " " + target.media.map do |medium|
|
61
|
+
escape_css_identifier medium.name.value
|
62
|
+
end.join(', ') if target.media.length > 0
|
51
63
|
|
52
|
-
"#{indent}@import
|
64
|
+
"#{indent}@import #{target.uri.accept(self)}#{media};"
|
53
65
|
end
|
54
66
|
|
55
67
|
visitor_for CSS::RuleSet do |target|
|
@@ -63,7 +75,7 @@ module CSSPool
|
|
63
75
|
important = target.important? ? ' !important' : ''
|
64
76
|
|
65
77
|
indent {
|
66
|
-
"#{indent}#{target.property}: " + target.expressions.map { |exp|
|
78
|
+
"#{indent}#{escape_css_identifier target.property}: " + target.expressions.map { |exp|
|
67
79
|
|
68
80
|
op = '/' == exp.operator ? ' /' : exp.operator
|
69
81
|
|
@@ -76,7 +88,7 @@ module CSSPool
|
|
76
88
|
end
|
77
89
|
|
78
90
|
visitor_for Terms::Ident do |target|
|
79
|
-
target.value
|
91
|
+
escape_css_identifier target.value
|
80
92
|
end
|
81
93
|
|
82
94
|
visitor_for Terms::Hash do |target|
|
@@ -90,11 +102,11 @@ module CSSPool
|
|
90
102
|
end
|
91
103
|
|
92
104
|
visitor_for Terms::URI do |target|
|
93
|
-
"url(#{target.value})"
|
105
|
+
"url(\"#{escape_css_string target.value}\")"
|
94
106
|
end
|
95
107
|
|
96
108
|
visitor_for Terms::Function do |target|
|
97
|
-
"#{target.name}(" +
|
109
|
+
"#{escape_css_identifier target.name}(" +
|
98
110
|
target.params.map { |x|
|
99
111
|
[
|
100
112
|
x.operator,
|
@@ -108,13 +120,15 @@ module CSSPool
|
|
108
120
|
target.red,
|
109
121
|
target.green,
|
110
122
|
target.blue
|
111
|
-
].map { |c|
|
123
|
+
].map { |c|
|
124
|
+
c.accept(self)
|
125
|
+
}.join ', '
|
112
126
|
|
113
127
|
%{rgb(#{params})}
|
114
128
|
end
|
115
129
|
|
116
130
|
visitor_for Terms::String do |target|
|
117
|
-
"\"#{target.value}\""
|
131
|
+
"\"#{escape_css_string target.value}\""
|
118
132
|
end
|
119
133
|
|
120
134
|
visitor_for Selector do |target|
|
@@ -123,64 +137,50 @@ module CSSPool
|
|
123
137
|
|
124
138
|
visitor_for Selectors::Type do |target|
|
125
139
|
combo = {
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
3 => ' > '
|
140
|
+
:s => ' ',
|
141
|
+
:+ => ' + ',
|
142
|
+
:> => ' > '
|
130
143
|
}[target.combinator]
|
131
144
|
|
132
|
-
|
145
|
+
name = target.name == '*' ? '*' : escape_css_identifier(target.name)
|
146
|
+
[combo, name].compact.join +
|
133
147
|
target.additional_selectors.map { |as| as.accept self }.join
|
134
148
|
end
|
135
149
|
|
136
150
|
visitor_for Terms::Number do |target|
|
137
|
-
units = {
|
138
|
-
2 => 'em',
|
139
|
-
3 => 'ex',
|
140
|
-
4 => 'px',
|
141
|
-
5 => 'in',
|
142
|
-
6 => 'cm',
|
143
|
-
7 => 'mm',
|
144
|
-
8 => 'pt',
|
145
|
-
9 => 'pc',
|
146
|
-
10 => 'deg',
|
147
|
-
11 => 'rad',
|
148
|
-
12 => 'grad',
|
149
|
-
13 => 'ms',
|
150
|
-
14 => 's',
|
151
|
-
15 => 'Hz',
|
152
|
-
16 => 'kHz',
|
153
|
-
17 => '%',
|
154
|
-
}[target.type]
|
155
151
|
[
|
156
152
|
target.unary_operator == :minus ? '-' : nil,
|
157
153
|
target.value,
|
158
|
-
|
154
|
+
target.type
|
159
155
|
].compact.join
|
160
156
|
end
|
161
157
|
|
162
158
|
visitor_for Selectors::Id do |target|
|
163
|
-
"##{target.name}"
|
159
|
+
"##{escape_css_identifier target.name}"
|
164
160
|
end
|
165
161
|
|
166
162
|
visitor_for Selectors::Class do |target|
|
167
|
-
".#{target.name}"
|
163
|
+
".#{escape_css_identifier target.name}"
|
168
164
|
end
|
169
165
|
|
170
166
|
visitor_for Selectors::PseudoClass do |target|
|
171
|
-
|
167
|
+
if target.extra.nil?
|
168
|
+
":#{escape_css_identifier target.name}"
|
169
|
+
else
|
170
|
+
":#{escape_css_identifier target.name}(#{escape_css_identifier target.extra})"
|
171
|
+
end
|
172
172
|
end
|
173
173
|
|
174
174
|
visitor_for Selectors::Attribute do |target|
|
175
175
|
case target.match_way
|
176
176
|
when Selectors::Attribute::SET
|
177
|
-
"[#{target.name}]"
|
177
|
+
"[#{escape_css_identifier target.name}]"
|
178
178
|
when Selectors::Attribute::EQUALS
|
179
|
-
"[#{target.name}=\"#{target.value}\"]"
|
179
|
+
"[#{escape_css_identifier target.name}=\"#{escape_css_string target.value}\"]"
|
180
180
|
when Selectors::Attribute::INCLUDES
|
181
|
-
"[#{target.name} ~= \"#{target.value}\"]"
|
181
|
+
"[#{escape_css_identifier target.name} ~= \"#{escape_css_string target.value}\"]"
|
182
182
|
when Selectors::Attribute::DASHMATCH
|
183
|
-
"[#{target.name} |= \"#{target.value}\"]"
|
183
|
+
"[#{escape_css_identifier target.name} |= \"#{escape_css_string target.value}\"]"
|
184
184
|
else
|
185
185
|
raise "no matching matchway"
|
186
186
|
end
|
@@ -196,6 +196,22 @@ module CSSPool
|
|
196
196
|
end
|
197
197
|
"#{@indent_space * @indent_level}"
|
198
198
|
end
|
199
|
+
|
200
|
+
def escape_css_identifier text
|
201
|
+
# CSS2 4.1.3 p2
|
202
|
+
unsafe_chars = /[#{Regexp.escape CSS_IDENTIFIER_ILLEGAL_CHARACTERS}]/
|
203
|
+
text.gsub(/^\d|^\-(?=\-|\d)|#{unsafe_chars}/um) do |char|
|
204
|
+
if ':()-\\ ='.include? char
|
205
|
+
"\\#{char}"
|
206
|
+
else # I don't trust others to handle space termination well.
|
207
|
+
"\\#{char.unpack('U').first.to_s(16).rjust(6, '0')}"
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def escape_css_string text
|
213
|
+
text.gsub(/[\\"\n\r\f]/) {CSS_STRING_ESCAPE_MAP[$&]}
|
214
|
+
end
|
199
215
|
end
|
200
216
|
end
|
201
217
|
end
|
data/lib/csspool/visitors.rb
CHANGED
data/lib/csspool.rb
CHANGED
@@ -1,16 +1,19 @@
|
|
1
|
-
require 'csspool/visitable'
|
2
1
|
require 'csspool/node'
|
3
2
|
require 'csspool/selectors'
|
4
3
|
require 'csspool/terms'
|
5
4
|
require 'csspool/selector'
|
5
|
+
old = $-w
|
6
|
+
$-w = false
|
7
|
+
require 'csspool/css/parser'
|
8
|
+
$-w = old
|
9
|
+
require 'csspool/css/tokenizer'
|
6
10
|
require 'csspool/sac'
|
7
|
-
require 'csspool/lib_croco'
|
8
11
|
require 'csspool/css'
|
9
12
|
require 'csspool/visitors'
|
10
13
|
require 'csspool/collection'
|
11
14
|
|
12
15
|
module CSSPool
|
13
|
-
VERSION = "
|
16
|
+
VERSION = "3.0.0"
|
14
17
|
|
15
18
|
def self.CSS doc
|
16
19
|
CSSPool::CSS::Document.parse doc
|