csspool 0.1.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/CHANGELOG.txt +4 -0
- data/Manifest.txt +32 -0
- data/README.txt +71 -0
- data/Rakefile +56 -0
- data/lib/css/sac/attribute_condition.rb +78 -0
- data/lib/css/sac/condition.rb +21 -0
- data/lib/css/sac/document_handler.rb +67 -0
- data/lib/css/sac/error_handler.rb +14 -0
- data/lib/css/sac/generated_property_parser.rb +9214 -0
- data/lib/css/sac/lexeme.rb +29 -0
- data/lib/css/sac/lexical_unit.rb +111 -0
- data/lib/css/sac/parse_exception.rb +6 -0
- data/lib/css/sac/parser.rb +98 -0
- data/lib/css/sac/property_parser.rb +47 -0
- data/lib/css/sac/selectors.rb +87 -0
- data/lib/css/sac/token.rb +27 -0
- data/lib/css/sac/tokenizer.rb +186 -0
- data/lib/css/sac.rb +13 -0
- data/lib/parser.y +287 -0
- data/lib/property_parser.y +2346 -0
- data/lib/property_parser.y.erb +1321 -0
- data/test/helper.rb +7 -0
- data/test/test_all.rb +4 -0
- data/test/test_lexeme.rb +39 -0
- data/test/test_lexical_unit.rb +96 -0
- data/test/test_parse_error.rb +199 -0
- data/test/test_parser.rb +183 -0
- data/test/test_property_parser.rb +593 -0
- data/test/test_selector_as_string.rb +83 -0
- data/test/test_selector_parser.rb +170 -0
- data/test/test_token.rb +24 -0
- data/test/test_tokenizer.rb +117 -0
- metadata +88 -0
@@ -0,0 +1,170 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helper"
|
2
|
+
|
3
|
+
class SelectorParserTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@sac = CSS::SAC::Parser.new()
|
6
|
+
class << @sac.document_handler
|
7
|
+
attr_reader :selectors
|
8
|
+
def start_selector(selectors)
|
9
|
+
@selectors = selectors
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_multiple_selectors
|
15
|
+
@sac.parse('h1, h2 { }')
|
16
|
+
selectors = @sac.document_handler.selectors
|
17
|
+
assert_equal(2, selectors.length)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_adjacent
|
21
|
+
@sac.parse('h1 + h2 { }')
|
22
|
+
selectors = @sac.document_handler.selectors
|
23
|
+
assert_equal(1, selectors.length)
|
24
|
+
|
25
|
+
sel = selectors.first
|
26
|
+
assert_equal(:SAC_DIRECT_ADJACENT_SELECTOR, sel.selector_type)
|
27
|
+
|
28
|
+
sibling = sel.sibling_selector
|
29
|
+
assert sibling
|
30
|
+
assert_equal('h2', sibling.local_name)
|
31
|
+
|
32
|
+
first = sel.selector
|
33
|
+
assert first
|
34
|
+
assert_equal('h1', first.local_name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_descendant_non_direct
|
38
|
+
@sac.parse('h1 h2 { }')
|
39
|
+
selectors = @sac.document_handler.selectors
|
40
|
+
assert_equal(1, selectors.length)
|
41
|
+
|
42
|
+
sel = selectors.first
|
43
|
+
assert_equal(:SAC_DESCENDANT_SELECTOR, sel.selector_type)
|
44
|
+
|
45
|
+
ancestor = sel.ancestor_selector
|
46
|
+
assert ancestor
|
47
|
+
assert_equal('h1', ancestor.local_name)
|
48
|
+
|
49
|
+
me = sel.selector
|
50
|
+
assert me
|
51
|
+
assert_equal('h2', me.local_name)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_descendant_direct
|
55
|
+
@sac.parse('h1 > h2 { }')
|
56
|
+
selectors = @sac.document_handler.selectors
|
57
|
+
assert_equal(1, selectors.length)
|
58
|
+
|
59
|
+
sel = selectors.first
|
60
|
+
assert_equal(:SAC_CHILD_SELECTOR, sel.selector_type)
|
61
|
+
|
62
|
+
ancestor = sel.ancestor_selector
|
63
|
+
assert ancestor
|
64
|
+
assert_equal('h1', ancestor.local_name)
|
65
|
+
|
66
|
+
me = sel.selector
|
67
|
+
assert me
|
68
|
+
assert_equal('h2', me.local_name)
|
69
|
+
end
|
70
|
+
|
71
|
+
@@single_selector_tests = {
|
72
|
+
:id => {
|
73
|
+
:css => '#foo { }',
|
74
|
+
:value => '#foo',
|
75
|
+
:type => :SAC_ID_CONDITION,
|
76
|
+
},
|
77
|
+
:class => {
|
78
|
+
:css => '.foo { }',
|
79
|
+
:value => 'foo',
|
80
|
+
:type => :SAC_CLASS_CONDITION,
|
81
|
+
},
|
82
|
+
:attribute => {
|
83
|
+
:css => '[foo=bar] { }',
|
84
|
+
:value => 'bar',
|
85
|
+
:type => :SAC_ATTRIBUTE_CONDITION,
|
86
|
+
},
|
87
|
+
:pseudo => {
|
88
|
+
:css => ':clicked { }',
|
89
|
+
:value => 'clicked',
|
90
|
+
:type => :SAC_PSEUDO_CLASS_CONDITION,
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
@@multiple_selector_tests = {
|
95
|
+
:ids => {
|
96
|
+
:css => '#foo#bar#baz { }',
|
97
|
+
:values => %w{ #foo #bar #baz },
|
98
|
+
:types => [:SAC_ID_CONDITION] * 3,
|
99
|
+
},
|
100
|
+
:classes => {
|
101
|
+
:css => '.foo.bar.baz { }',
|
102
|
+
:values => %w{ foo bar baz },
|
103
|
+
:types => [:SAC_CLASS_CONDITION] * 3,
|
104
|
+
},
|
105
|
+
:attributes => {
|
106
|
+
:css => '[foo=bar][bar=baz] { }',
|
107
|
+
:values => %w{ bar baz },
|
108
|
+
:types => [:SAC_ATTRIBUTE_CONDITION] * 2,
|
109
|
+
},
|
110
|
+
:pseudo => {
|
111
|
+
:css => ':clicked:hover { }',
|
112
|
+
:values => %w{ clicked hover },
|
113
|
+
:types => [:SAC_PSEUDO_CLASS_CONDITION] * 2,
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
@@single_selector_tests.each do |name,tests|
|
118
|
+
define_method :"test_single_#{name}" do
|
119
|
+
@sac.parse(tests[:css])
|
120
|
+
selectors = @sac.document_handler.selectors
|
121
|
+
assert_equal(1, selectors.length)
|
122
|
+
|
123
|
+
selector = selectors.first
|
124
|
+
assert_nil selector.simple_selector
|
125
|
+
assert selector.condition
|
126
|
+
assert_equal(:SAC_CONDITIONAL_SELECTOR, selector.selector_type)
|
127
|
+
|
128
|
+
condition = selector.condition
|
129
|
+
assert_equal(tests[:type], condition.condition_type)
|
130
|
+
assert_equal(tests[:value], condition.value)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
@@multiple_selector_tests.each do |name,tests|
|
135
|
+
define_method :"test_multiple_#{name}" do
|
136
|
+
@sac.parse(tests[:css])
|
137
|
+
selectors = @sac.document_handler.selectors
|
138
|
+
assert_equal(1, selectors.length)
|
139
|
+
|
140
|
+
selector = selectors.first
|
141
|
+
assert_nil selector.simple_selector
|
142
|
+
assert selector.condition
|
143
|
+
assert_equal(:SAC_CONDITIONAL_SELECTOR, selector.selector_type)
|
144
|
+
|
145
|
+
combined = reduce_combinator_condition(selector.condition)
|
146
|
+
assert_equal(tests[:values].length, combined.length)
|
147
|
+
assert_equal(tests[:values], combined.map { |x| x.value })
|
148
|
+
assert_equal(tests[:types], combined.map { |x| x.condition_type })
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def reduce_combinator_condition(condition)
|
153
|
+
conditions = []
|
154
|
+
assert_equal(:SAC_AND_CONDITION, condition.condition_type)
|
155
|
+
first = condition.first_condition
|
156
|
+
second = condition.second_condition
|
157
|
+
|
158
|
+
assert first
|
159
|
+
assert second
|
160
|
+
assert_not_equal(:SAC_AND_CONDITION, first.condition_type)
|
161
|
+
conditions << first
|
162
|
+
|
163
|
+
if second.condition_type == :SAC_AND_CONDITION
|
164
|
+
conditions += reduce_combinator_condition(second)
|
165
|
+
else
|
166
|
+
conditions << second
|
167
|
+
end
|
168
|
+
conditions
|
169
|
+
end
|
170
|
+
end
|
data/test/test_token.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helper"
|
2
|
+
|
3
|
+
class TokenTest < Test::Unit::TestCase
|
4
|
+
include CSS
|
5
|
+
|
6
|
+
def test_tokens_have_a_name_value_and_position
|
7
|
+
token = SAC::Token.new(:foo, "bar", 14)
|
8
|
+
assert_equal(:foo, token.name)
|
9
|
+
assert_equal("bar", token.value)
|
10
|
+
assert_equal(14, token.position)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_to_racc_token_returns_a_name_value_array
|
14
|
+
assert_equal([:foo, "bar"], SAC::Token.new(:foo, "bar", 99).to_racc_token)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_delimiter_token_is_always_delim
|
18
|
+
assert_equal(:delim, SAC::DelimiterToken.new(";", 99).name)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_delimiter_token_just_returns_values_for_racc
|
22
|
+
assert_equal(%w(; ;), SAC::DelimiterToken.new(";", 99).to_racc_token)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helper"
|
2
|
+
|
3
|
+
class TokenizerTest < Test::Unit::TestCase
|
4
|
+
include CSS::SAC
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@tokenizer = Tokenizer.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_tokenize
|
11
|
+
assert_equal([], @tokenizer.tokenize(""))
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_parse_simple
|
15
|
+
text = '
|
16
|
+
@import "subs.css";
|
17
|
+
* { margin: 0px; }
|
18
|
+
body {
|
19
|
+
margin: 0px;
|
20
|
+
padding: 0px;
|
21
|
+
}'
|
22
|
+
|
23
|
+
assert_tokens(text,
|
24
|
+
[:IMPORT_SYM, "@import"],
|
25
|
+
[:STRING, "\"subs.css\""],
|
26
|
+
[:delim, ";"],
|
27
|
+
[:delim, "*"],
|
28
|
+
[:LBRACE, " {"],
|
29
|
+
[:IDENT, "margin"],
|
30
|
+
[:delim, ":"],
|
31
|
+
[:LENGTH, "0px"],
|
32
|
+
[:delim, ";"],
|
33
|
+
[:delim, "}"],
|
34
|
+
[:IDENT, "body"],
|
35
|
+
[:LBRACE, " {"],
|
36
|
+
[:IDENT, "margin"],
|
37
|
+
[:delim, ":"],
|
38
|
+
[:LENGTH, "0px"],
|
39
|
+
[:delim, ";"],
|
40
|
+
[:IDENT, "padding"],
|
41
|
+
[:delim, ":"],
|
42
|
+
[:LENGTH, "0px"],
|
43
|
+
[:delim, ";"],
|
44
|
+
[:delim, "}"])
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_at_import
|
48
|
+
tokens = @tokenizer.tokenize('@import "subs.css" print;')
|
49
|
+
assert_equal(6, tokens.length)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_at_media
|
53
|
+
assert_tokens('@media print { h1 { color: black; } }',
|
54
|
+
[:MEDIA_SYM, "@media"],
|
55
|
+
[:IDENT, "print"],
|
56
|
+
[:LBRACE, " {"],
|
57
|
+
[:IDENT, "h1"],
|
58
|
+
[:LBRACE, " {"],
|
59
|
+
[:IDENT, "color"],
|
60
|
+
[:delim, ":"],
|
61
|
+
[:IDENT, "black"],
|
62
|
+
[:delim, ";"],
|
63
|
+
[:delim, "}"],
|
64
|
+
[:delim, "}"])
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_at_page
|
68
|
+
tokens = @tokenizer.tokenize('@page print { color: black; }')
|
69
|
+
assert_equal(12, tokens.length)
|
70
|
+
|
71
|
+
tokens = @tokenizer.tokenize('@page :left { color: black; }')
|
72
|
+
assert_equal(13, tokens.length)
|
73
|
+
|
74
|
+
tokens = @tokenizer.tokenize('@page print :left { color: black; }')
|
75
|
+
assert_equal(15, tokens.length)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_two_strings
|
79
|
+
tokens = @tokenizer.tokenize('"one" "two"')
|
80
|
+
assert_equal(3, tokens.length)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_at_font_face
|
84
|
+
tokens = @tokenizer.tokenize('@font-face { color: black; }')
|
85
|
+
assert_equal(11, tokens.length)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_ignorable_at
|
89
|
+
tokens = @tokenizer.tokenize('@aaron { color: black; }')
|
90
|
+
assert_equal(11, tokens.length)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_function_token
|
94
|
+
assert_tokens("foo(aaron)", :FUNCTION, :IDENT, :delim)
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_an_example_of_assert_tokens
|
98
|
+
assert_tokens("body { color: pink; }",
|
99
|
+
:IDENT, :LBRACE, :IDENT, :delim, [:IDENT, "pink"], :delim, :delim)
|
100
|
+
end
|
101
|
+
|
102
|
+
def assert_tokens(text, *expected)
|
103
|
+
tokens = @tokenizer.tokenize(text).reject { |t| t.name == :S }
|
104
|
+
# puts tokens.collect { |t| [t.name, t.value].inspect }.join(",\n")
|
105
|
+
|
106
|
+
assert_equal(expected.size, tokens.size)
|
107
|
+
|
108
|
+
count = 1
|
109
|
+
|
110
|
+
tokens.zip(expected).each do |sets|
|
111
|
+
token, expected_name, expected_value = sets.flatten
|
112
|
+
assert_equal(expected_name, token.name, "token #{count} name")
|
113
|
+
assert_equal(expected_value, token.value, "token #{count} value") if expected_value
|
114
|
+
count += 1
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.4
|
3
|
+
specification_version: 1
|
4
|
+
name: csspool
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2007-11-02 00:00:00 -07:00
|
8
|
+
summary: Parses CSS
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: aaronp@rubyforge.org
|
12
|
+
homepage: http://csspool.rubyforge.org/
|
13
|
+
rubyforge_project: csspool
|
14
|
+
description: CSSpool (pronounced "cesspool") is a validating SAC parser for CSS. The parser calls methods on a document handler depending on what it has found. CSSPool currently only supports CSS 2.1. CSSPool will not yield invalid properties or selectors.
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Aaron Patterson
|
31
|
+
files:
|
32
|
+
- CHANGELOG.txt
|
33
|
+
- Manifest.txt
|
34
|
+
- README.txt
|
35
|
+
- Rakefile
|
36
|
+
- lib/css/sac.rb
|
37
|
+
- lib/css/sac/attribute_condition.rb
|
38
|
+
- lib/css/sac/condition.rb
|
39
|
+
- lib/css/sac/document_handler.rb
|
40
|
+
- lib/css/sac/error_handler.rb
|
41
|
+
- lib/css/sac/generated_property_parser.rb
|
42
|
+
- lib/css/sac/lexeme.rb
|
43
|
+
- lib/css/sac/lexical_unit.rb
|
44
|
+
- lib/css/sac/parse_exception.rb
|
45
|
+
- lib/css/sac/parser.rb
|
46
|
+
- lib/css/sac/property_parser.rb
|
47
|
+
- lib/css/sac/selectors.rb
|
48
|
+
- lib/css/sac/token.rb
|
49
|
+
- lib/css/sac/tokenizer.rb
|
50
|
+
- lib/parser.y
|
51
|
+
- lib/property_parser.y
|
52
|
+
- lib/property_parser.y.erb
|
53
|
+
- test/helper.rb
|
54
|
+
- test/test_all.rb
|
55
|
+
- test/test_lexeme.rb
|
56
|
+
- test/test_lexical_unit.rb
|
57
|
+
- test/test_parse_error.rb
|
58
|
+
- test/test_parser.rb
|
59
|
+
- test/test_property_parser.rb
|
60
|
+
- test/test_selector_as_string.rb
|
61
|
+
- test/test_selector_parser.rb
|
62
|
+
- test/test_token.rb
|
63
|
+
- test/test_tokenizer.rb
|
64
|
+
test_files:
|
65
|
+
- test/test_all.rb
|
66
|
+
rdoc_options:
|
67
|
+
- --main
|
68
|
+
- README.txt
|
69
|
+
extra_rdoc_files:
|
70
|
+
- CHANGELOG.txt
|
71
|
+
- Manifest.txt
|
72
|
+
- README.txt
|
73
|
+
executables: []
|
74
|
+
|
75
|
+
extensions: []
|
76
|
+
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
dependencies:
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: hoe
|
82
|
+
version_requirement:
|
83
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 1.3.0
|
88
|
+
version:
|