csspool 2.0.0 → 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.
- 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
|