csspool 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.DS_Store +0 -0
  2. data/CHANGELOG.txt +16 -0
  3. data/Manifest.txt +11 -0
  4. data/README.txt +11 -3
  5. data/Rakefile +2 -2
  6. data/lib/css/sac/conditions/attribute_condition.rb +4 -0
  7. data/lib/css/sac/conditions/combinator_condition.rb +4 -0
  8. data/lib/css/sac/conditions/condition.rb +8 -0
  9. data/lib/css/sac/lexical_unit.rb +98 -6
  10. data/lib/css/sac/parser.rb +15 -4
  11. data/lib/css/sac/selectors/child_selector.rb +4 -0
  12. data/lib/css/sac/selectors/conditional_selector.rb +4 -0
  13. data/lib/css/sac/selectors/descendant_selector.rb +4 -0
  14. data/lib/css/sac/selectors/element_selector.rb +4 -0
  15. data/lib/css/sac/selectors/selector.rb +8 -0
  16. data/lib/css/sac/selectors/sibling_selector.rb +4 -0
  17. data/lib/css/sac.rb +1 -0
  18. data/lib/css/stylesheet/rule.rb +12 -0
  19. data/lib/css/stylesheet/stylesheet.rb +94 -0
  20. data/lib/css/stylesheet.rb +3 -0
  21. data/lib/csspool.rb +1 -0
  22. data/lib/parser.y +2 -2
  23. data/test/test_attribute_condition.rb +9 -0
  24. data/test/test_child_selector.rb +12 -0
  25. data/test/test_combinator_condition.rb +9 -0
  26. data/test/test_condition.rb +18 -0
  27. data/test/test_conditional_selector.rb +12 -0
  28. data/test/test_descendant_selector.rb +12 -0
  29. data/test/test_element_selector.rb +9 -0
  30. data/test/test_lexical_color.rb +49 -0
  31. data/test/test_lexical_function.rb +31 -0
  32. data/test/test_lexical_ident.rb +30 -0
  33. data/test/test_lexical_number.rb +68 -0
  34. data/test/test_lexical_string.rb +23 -0
  35. data/test/test_lexical_unit.rb +11 -1
  36. data/test/test_lexical_uri.rb +28 -0
  37. data/test/test_parser.rb +16 -0
  38. data/test/test_selector.rb +18 -1
  39. data/test/test_selector_parser.rb +8 -0
  40. data/test/test_sibling_selector.rb +9 -0
  41. data/test/test_stylesheet.rb +95 -0
  42. metadata +13 -2
data/.DS_Store CHANGED
Binary file
data/CHANGELOG.txt CHANGED
@@ -1,3 +1,19 @@
1
+ == 0.2.0
2
+
3
+ * Added CSS::SAC::Parser#parse_rule to parse a single rule.
4
+ * Added CSS::StyleSheet#find_rule for finding a particular rule.
5
+ * Added CSS::StyleSheet#rules_matching for finding all rules matching a node.
6
+ * Added CSS::StyleSheet#create_rule for creating a new rule.
7
+ * Added CSS::StyleSheet#find_all_rules_matching for finding all rules that match
8
+ any node in the passed in document.
9
+ * Added .eql? to selector AST
10
+ * Added .hash to selector AST
11
+ * Added .eql? to LexicalUnits
12
+ * Added .hash to LexicalUnits
13
+ * Added CSS::StyleSheet#to_css
14
+ * Added CSS::StyleSheet#reduce!
15
+ * CSS::StyleSheet is now the default document handler
16
+
1
17
  == 0.1.1
2
18
 
3
19
  * Added specificity to selectors.
data/Manifest.txt CHANGED
@@ -32,6 +32,10 @@ lib/css/sac/selectors/simple_selector.rb
32
32
  lib/css/sac/token.rb
33
33
  lib/css/sac/tokenizer.rb
34
34
  lib/css/sac/visitable.rb
35
+ lib/css/stylesheet.rb
36
+ lib/css/stylesheet/rule.rb
37
+ lib/css/stylesheet/stylesheet.rb
38
+ lib/csspool.rb
35
39
  lib/parser.y
36
40
  lib/property_parser.y
37
41
  lib/property_parser.y.erb
@@ -50,7 +54,13 @@ test/test_descendant_selector.rb
50
54
  test/test_element_selector.rb
51
55
  test/test_id_condition.rb
52
56
  test/test_lexeme.rb
57
+ test/test_lexical_color.rb
58
+ test/test_lexical_function.rb
59
+ test/test_lexical_ident.rb
60
+ test/test_lexical_number.rb
61
+ test/test_lexical_string.rb
53
62
  test/test_lexical_unit.rb
63
+ test/test_lexical_uri.rb
54
64
  test/test_one_of_condition.rb
55
65
  test/test_parse_error.rb
56
66
  test/test_parser.rb
@@ -61,6 +71,7 @@ test/test_selector_parser.rb
61
71
  test/test_sibling_selector.rb
62
72
  test/test_simple_selector.rb
63
73
  test/test_specificity.rb
74
+ test/test_stylesheet.rb
64
75
  test/test_token.rb
65
76
  test/test_tokenizer.rb
66
77
  test/test_xpath.rb
data/README.txt CHANGED
@@ -18,7 +18,15 @@ Building CSSpool requires:
18
18
 
19
19
  - rubygems, hoe, flexmock
20
20
 
21
- == Example
21
+ == Examples
22
+
23
+ === Tidy a stylesheet
24
+
25
+ parser = CSS::SAC::Parser.new
26
+ doc = parser.parse(File.read(ARGV[0]))
27
+ puts doc.to_css
28
+
29
+ === Find custom attributes
22
30
 
23
31
  This example prints out all properties from a particular CSS file.
24
32
 
@@ -41,8 +49,8 @@ See SAC[http://www.w3.org/Style/CSS/SAC/] for more information on SAC.
41
49
 
42
50
  == Authors
43
51
 
44
- * {Aaron Patterson}[http://tenderlovemaking.com] <aaronp@rubyforge.com>
45
- * {John Barnette}[http://geeksomnia.com] <jbarnette@rubyforge.com>
52
+ * {Aaron Patterson}[http://tenderlovemaking.com] <aaronp@rubyforge.org>
53
+ * {John Barnette}[http://geeksomnia.com] <jbarnette@rubyforge.org>
46
54
 
47
55
  == LICENSE
48
56
 
data/Rakefile CHANGED
@@ -7,14 +7,14 @@ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "lib")
7
7
  GENERATED_PARSER = "lib/css/sac/generated_parser.rb"
8
8
  GENERATED_PROPERTY_PARSER = "lib/css/sac/generated_property_parser.rb"
9
9
 
10
- Hoe.new('csspool', '0.1.1') do |p|
10
+ Hoe.new('csspool', '0.2.0') do |p|
11
11
  p.rubyforge_name = 'csspool'
12
12
  p.author = 'Aaron Patterson'
13
13
  p.email = 'aaronp@rubyforge.org'
14
14
  p.summary = "Parses CSS"
15
15
  p.description = p.paragraphs_of('README.txt', 3).join("\n\n")
16
16
  p.url = p.paragraphs_of('README.txt', 1).first.strip
17
- p.changes = p.paragraphs_of('CHANGELOG.txt', 0..2).join("\n\n")
17
+ p.changes = p.paragraphs_of('CHANGELOG.txt', 0..1).join("\n\n")
18
18
  p.clean_globs = [GENERATED_PARSER]
19
19
  end
20
20
 
@@ -46,6 +46,10 @@ module CSS
46
46
  super && local_name == other.local_name && value == other.value &&
47
47
  specified == other.specified
48
48
  end
49
+
50
+ def hash
51
+ [local_name, value, specified].hash
52
+ end
49
53
  end
50
54
  end
51
55
  end
@@ -30,6 +30,10 @@ module CSS
30
30
  def ==(other)
31
31
  super && first == other.first && second == other.second
32
32
  end
33
+
34
+ def hash
35
+ [first, second].hash
36
+ end
33
37
  end
34
38
  end
35
39
  end
@@ -14,6 +14,14 @@ module CSS
14
14
  self.class === other && condition_type == other.condition_type
15
15
  end
16
16
 
17
+ def hash
18
+ condition_type.hash
19
+ end
20
+
21
+ def eql?(other)
22
+ self == other
23
+ end
24
+
17
25
  def to_css
18
26
  nil
19
27
  end
@@ -9,6 +9,14 @@ module CSS
9
9
  :parameters,
10
10
  :function_name
11
11
 
12
+ def ==(other)
13
+ self.class === other && self.lexical_unit_type == other.lexical_unit_type
14
+ end
15
+
16
+ def eql?(other)
17
+ self == other
18
+ end
19
+
12
20
  alias :to_s :string_value
13
21
  end
14
22
 
@@ -25,22 +33,51 @@ module CSS
25
33
  self.parameters = params
26
34
  self.lexical_unit_type = FUNCTIONS[self.function_name] || :SAC_FUNCTION
27
35
  end
36
+
37
+ def ==(other)
38
+ super && %w{ function_name parameters }.all? { |x|
39
+ self.send(x.to_sym) == other.send(x.to_sym)
40
+ }
41
+ end
42
+
43
+ def hash
44
+ ([self.function_name] + parameters).hash
45
+ end
28
46
  end
29
47
 
30
48
  class Color < LexicalUnit
31
49
  def initialize(value)
32
50
  self.string_value = value
33
51
  self.lexical_unit_type = :SAC_RGBCOLOR
34
- if value =~ /^#(\d{1,2})(\d{1,2})(\d{1,2})$/
35
- self.parameters = [
36
- Number.new($1.hex, '', :SAC_INTEGER),
37
- Number.new($2.hex, '', :SAC_INTEGER),
38
- Number.new($3.hex, '', :SAC_INTEGER)
39
- ]
52
+ if value =~ /^#([A-F\d]{1,2})([A-F\d]{1,2})([A-F\d]{1,2})$/
53
+ self.parameters = [$1, $2, $3].map { |x|
54
+ x.length == 1 ? (x * 2).hex : x.hex
55
+ }.map { |x|
56
+ Number.new(x, '', :SAC_INTEGER)
57
+ }
40
58
  else
41
59
  self.parameters = [LexicalIdent.new(value)]
42
60
  end
43
61
  end
62
+
63
+ def ==(other)
64
+ super && self.parameters == other.parameters
65
+ end
66
+
67
+ def hash
68
+ self.parameters.hash
69
+ end
70
+
71
+ def to_s
72
+ if self.parameters.length < 3
73
+ super
74
+ else
75
+ hex = self.parameters.map { |x|
76
+ sprintf("%02X", x.integer_value).split('').uniq
77
+ }.flatten
78
+ hex.length != 3 ? super : "##{hex.join()}"
79
+ end
80
+ end
44
81
  end
45
82
 
46
83
  class LexicalString < LexicalUnit
@@ -48,6 +85,14 @@ module CSS
48
85
  self.string_value = value
49
86
  self.lexical_unit_type = :SAC_STRING_VALUE
50
87
  end
88
+
89
+ def ==(other)
90
+ super && self.string_value == other.string_value
91
+ end
92
+
93
+ def hash
94
+ self.string_value.hash
95
+ end
51
96
  end
52
97
 
53
98
  class LexicalIdent < LexicalUnit
@@ -55,6 +100,14 @@ module CSS
55
100
  self.string_value = value
56
101
  self.lexical_unit_type = :SAC_IDENT
57
102
  end
103
+
104
+ def ==(other)
105
+ super && self.string_value == other.string_value
106
+ end
107
+
108
+ def hash
109
+ self.string_value.hash
110
+ end
58
111
  end
59
112
 
60
113
  class LexicalURI < LexicalUnit
@@ -62,6 +115,18 @@ module CSS
62
115
  self.string_value = value.gsub(/^url\(/, '').gsub(/\)$/, '')
63
116
  self.lexical_unit_type = :SAC_URI
64
117
  end
118
+
119
+ def ==(other)
120
+ super && self.string_value == other.string_value
121
+ end
122
+
123
+ def hash
124
+ self.string_value.hash
125
+ end
126
+
127
+ def to_s
128
+ "url(#{string_value})"
129
+ end
65
130
  end
66
131
 
67
132
  class Number < LexicalUnit
@@ -106,6 +171,33 @@ module CSS
106
171
  self.lexical_unit_type = UNITS[self.dimension_unit_text] ||
107
172
  (value =~ /\./ ? :SAC_NUMBER : :SAC_INTEGER)
108
173
  end
174
+
175
+ def ==(other)
176
+ return true if self.float_value == 0 && other.float_value == 0
177
+ return false unless super
178
+
179
+ %w{ float_value integer_value dimension_unit_text }.all? { |x|
180
+ self.send(x.to_sym) == other.send(x.to_sym)
181
+ }
182
+ end
183
+
184
+ def hash
185
+ if self.float_value == 0
186
+ self.float_value.hash
187
+ else
188
+ %w{ float_value integer_value dimension_unit_text }.map { |x|
189
+ self.send(x.to_sym)
190
+ }.hash
191
+ end
192
+ end
193
+
194
+ def to_s
195
+ if self.float_value == 0
196
+ "0"
197
+ else
198
+ super
199
+ end
200
+ end
109
201
  end
110
202
  end
111
203
  end
@@ -14,15 +14,15 @@ module CSS
14
14
  module SAC
15
15
  class Parser < CSS::SAC::GeneratedParser
16
16
  # The version of CSSPool you're using
17
- VERSION = '0.1.1'
17
+ VERSION = '0.2.0'
18
18
 
19
19
  TOKENIZER = Tokenizer.new
20
20
 
21
21
  attr_accessor :document_handler, :error_handler, :logger
22
22
 
23
- def initialize(document_handler = nil)
23
+ def initialize(document_handler = StyleSheet.new(self))
24
24
  @error_handler = ErrorHandler.new
25
- @document_handler = document_handler || DocumentHandler.new()
25
+ @document_handler = document_handler
26
26
  @property_parser = PropertyParser.new()
27
27
  @tokenizer = TOKENIZER
28
28
  @logger = nil
@@ -40,7 +40,18 @@ module CSS
40
40
  end
41
41
 
42
42
  alias :parse :parse_style_sheet
43
- alias :parse_rule :parse_style_sheet
43
+
44
+ def parse_rule(rule)
45
+ returner = Class.new(DocumentHandler) {
46
+ attr_accessor :selector
47
+ alias :start_selector :selector=
48
+ }.new
49
+ old_document_handler = self.document_handler
50
+ self.document_handler = returner
51
+ self.parse("#{rule} { }")
52
+ self.document_handler = old_document_handler
53
+ returner.selector
54
+ end
44
55
 
45
56
  # Returns the parser version. We return CSS2, but its actually
46
57
  # CSS2.1. No font-face tags. Sorry.
@@ -30,6 +30,10 @@ module CSS
30
30
  def ==(other)
31
31
  super && parent == other.parent && selector == other.selector
32
32
  end
33
+
34
+ def hash
35
+ [parent, selector].hash
36
+ end
33
37
  end
34
38
  end
35
39
  end
@@ -37,6 +37,10 @@ module CSS
37
37
  def ==(other)
38
38
  super && condition == other.condition && selector == other.selector
39
39
  end
40
+
41
+ def hash
42
+ [condition, selector].hash
43
+ end
40
44
  end
41
45
  end
42
46
  end
@@ -30,6 +30,10 @@ module CSS
30
30
  def ==(other)
31
31
  super && selector == other.selector && ancestor == other.ancestor
32
32
  end
33
+
34
+ def hash
35
+ [selector, ancestor].hash
36
+ end
33
37
  end
34
38
  end
35
39
  end
@@ -29,6 +29,10 @@ module CSS
29
29
  def ==(other)
30
30
  super && name == other.name
31
31
  end
32
+
33
+ def hash
34
+ name.hash
35
+ end
32
36
  end
33
37
  end
34
38
  end
@@ -14,6 +14,14 @@ module CSS
14
14
  self.class === other && selector_type == other.selector_type
15
15
  end
16
16
 
17
+ def hash
18
+ selector_type.hash
19
+ end
20
+
21
+ def eql?(other)
22
+ self == other
23
+ end
24
+
17
25
  def =~(node)
18
26
  MatchesVisitor.new(node).accept(self)
19
27
  end
@@ -29,6 +29,10 @@ module CSS
29
29
  def ==(other)
30
30
  super && selector == other.selector && sibling == other.sibling
31
31
  end
32
+
33
+ def hash
34
+ [selector, sibling].hash
35
+ end
32
36
  end
33
37
  end
34
38
  end
data/lib/css/sac.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "css/sac/parser"
2
+ require "css/stylesheet"
2
3
 
3
4
  module CSS
4
5
  module SAC
@@ -0,0 +1,12 @@
1
+ require 'set'
2
+ module CSS
3
+ class StyleSheet
4
+ class Rule
5
+ attr_accessor :selector, :properties
6
+ def initialize(selector, properties = [])
7
+ @selector = selector
8
+ @properties = Set.new(properties)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,94 @@
1
+ module CSS
2
+ class StyleSheet < CSS::SAC::DocumentHandler
3
+ attr_reader :rules
4
+
5
+ def initialize(sac)
6
+ @sac = sac
7
+ @rules = []
8
+ @current_rules = []
9
+ end
10
+
11
+ def start_selector(selectors)
12
+ selectors.each { |selector|
13
+ @current_rules << Rule.new(selector)
14
+ }
15
+ end
16
+
17
+ def end_selector(selectors)
18
+ @rules += @current_rules
19
+ @current_rules = []
20
+ reduce!
21
+ end
22
+
23
+ def find_rule(rule)
24
+ rule = self.create_rule(rule) if rule.is_a?(String)
25
+ rules.find { |x| x.selector == rule.selector }
26
+ end
27
+ alias :[] :find_rule
28
+
29
+ # Find all rules used in +hpricot_document+
30
+ def find_all_rules_matching(hpricot_document)
31
+ used_rules = []
32
+ hpricot_document.search('//').each do |node|
33
+ if matching = (rules_matching(node))
34
+ used_rules += matching
35
+ end
36
+ end
37
+ used_rules.uniq
38
+ end
39
+
40
+ # Find all rules that match +node+. +node+ must quack like an Hpricot
41
+ # node.
42
+ def rules_matching(node)
43
+ rules.find_all { |rule|
44
+ rule.selector =~ node
45
+ }
46
+ end
47
+ alias :=~ :rules_matching
48
+
49
+ def create_rule(rule)
50
+ Rule.new(@sac.parse_rule(rule).first)
51
+ end
52
+
53
+ def property(name, value, important)
54
+ @current_rules.each { |selector|
55
+ selector.properties << [name, value, important]
56
+ }
57
+ end
58
+
59
+ # Get a hash of rules by property
60
+ def rules_by_property
61
+ rules_by_property = Hash.new { |h,k| h[k] = [] }
62
+ @rules.each { |sel|
63
+ props = sel.properties.to_a.sort_by { |x| x.hash } # HACK?
64
+ rules_by_property[props] << sel
65
+ }
66
+ rules_by_property
67
+ end
68
+
69
+ def to_css
70
+ rules_by_property.map do |properties, rules|
71
+ rules.map { |rule| rule.selector.to_css }.sort.join(', ') + " {\n" +
72
+ properties.map { |key,value,important|
73
+ # Super annoying. If the property is font-family, its supposed to
74
+ # be commas
75
+ join_val = ('font-family' == key) ? ', ' : ' '
76
+ values = [value].flatten.join(join_val)
77
+ "#{key}:#{values}#{important ? ' !important' : ''};"
78
+ }.join("\n") + "\n}"
79
+ end.sort.join("\n")
80
+ end
81
+
82
+ private
83
+ # Remove duplicate rules
84
+ def reduce!
85
+ unique_rules = {}
86
+ @rules.each do |rule|
87
+ (unique_rules[rule.selector] ||= rule).properties += rule.properties
88
+ end
89
+ @rules = unique_rules.values
90
+ self
91
+ end
92
+ end
93
+ end
94
+
@@ -0,0 +1,3 @@
1
+ require "css/stylesheet/stylesheet"
2
+ require "css/stylesheet/rule"
3
+
data/lib/csspool.rb ADDED
@@ -0,0 +1 @@
1
+ require 'css/sac'
data/lib/parser.y CHANGED
@@ -203,7 +203,7 @@ rule
203
203
  |
204
204
  ;
205
205
  expr
206
- : term operator expr { result = [val[0], val.last] }
206
+ : term operator expr { result = val }
207
207
  | term
208
208
  ;
209
209
  term
@@ -227,7 +227,7 @@ rule
227
227
  ;
228
228
  function
229
229
  : FUNCTION s_0toN expr ')' s_0toN {
230
- result = Function.new(val[0], val[2].flatten)
230
+ result = Function.new(val[0], val[2].flatten.select { |x| x !~ /,/ })
231
231
  }
232
232
  | FUNCTION s_0toN expr error ')' s_0toN { yyerrok; result = [val[0], val[2], val[3]] }
233
233
  ;
@@ -1,6 +1,15 @@
1
1
  require File.dirname(__FILE__) + "/helper"
2
2
 
3
3
  class AttributeConditionTest < ConditionTestCase
4
+ def test_hash
5
+ first = AttributeCondition.new(1, 1, 1)
6
+ second = AttributeCondition.new(1, 1, 1)
7
+ assert_equal first.hash, second.hash
8
+
9
+ third = AttributeCondition.new(2, 1, 1)
10
+ assert_not_equal first.hash, third.hash
11
+ end
12
+
4
13
  def test_equals2
5
14
  first = AttributeCondition.new(1, 1, 1)
6
15
  second = AttributeCondition.new(1, 1, 1)
@@ -1,6 +1,18 @@
1
1
  require File.dirname(__FILE__) + "/helper"
2
2
 
3
3
  class ChildSelectorTest < SelectorTestCase
4
+ def test_hash
5
+ first = ChildSelector.new(1,1)
6
+ second = ChildSelector.new(1,1)
7
+ assert_equal first.hash, second.hash
8
+
9
+ third = ChildSelector.new(1,2)
10
+ assert_not_equal first.hash, third.hash
11
+
12
+ fourth = ChildSelector.new(2,1)
13
+ assert_not_equal first.hash, fourth.hash
14
+ end
15
+
4
16
  def test_equals2
5
17
  first = ChildSelector.new(1,1)
6
18
  second = ChildSelector.new(1,1)
@@ -10,6 +10,15 @@ class CombinatorConditionTest < ConditionTestCase
10
10
  assert_not_equal first, third
11
11
  end
12
12
 
13
+ def test_hash
14
+ first = CombinatorCondition.new(1,1)
15
+ second = CombinatorCondition.new(1,1)
16
+ assert_equal first.hash, second.hash
17
+
18
+ third = CombinatorCondition.new(1,2)
19
+ assert_not_equal first.hash, third.hash
20
+ end
21
+
13
22
  def test_equals_tilde
14
23
  first = ClassCondition.new('foo')
15
24
  second = AttributeCondition.new('name', 'aaron', true)
@@ -10,4 +10,22 @@ class ConditionTest < ConditionTestCase
10
10
  assert_not_equal first, third
11
11
  assert_not_equal first, 1
12
12
  end
13
+
14
+ def test_eql?
15
+ first = Condition.new(1)
16
+ second = Condition.new(1)
17
+ assert first.eql?(second)
18
+
19
+ third = Condition.new(2)
20
+ assert !first.eql?(third)
21
+ end
22
+
23
+ def test_hash
24
+ first = Condition.new(1)
25
+ second = Condition.new(1)
26
+ assert_equal first.hash, second.hash
27
+
28
+ third = Condition.new(2)
29
+ assert_not_equal first.hash, third.hash
30
+ end
13
31
  end
@@ -1,6 +1,18 @@
1
1
  require File.dirname(__FILE__) + "/helper"
2
2
 
3
3
  class ConditionalSelectorTest < SelectorTestCase
4
+ def test_hash
5
+ first = ConditionalSelector.new(1,1)
6
+ second = ConditionalSelector.new(1,1)
7
+ assert_equal first.hash, second.hash
8
+
9
+ third = ConditionalSelector.new(1,2)
10
+ assert_not_equal first.hash, third.hash
11
+
12
+ fourth = ConditionalSelector.new(2,1)
13
+ assert_not_equal first.hash, fourth.hash
14
+ end
15
+
4
16
  def test_equals2
5
17
  first = ConditionalSelector.new(1,1)
6
18
  second = ConditionalSelector.new(1,1)
@@ -1,6 +1,18 @@
1
1
  require File.dirname(__FILE__) + "/helper"
2
2
 
3
3
  class DescendantSelectorTest < SelectorTestCase
4
+ def test_hash
5
+ first = DescendantSelector.new(1,1)
6
+ second = DescendantSelector.new(1,1)
7
+ assert_equal first.hash, second.hash
8
+
9
+ third = DescendantSelector.new(1,2)
10
+ assert_not_equal first.hash, third.hash
11
+
12
+ fourth = DescendantSelector.new(2,1)
13
+ assert_not_equal first.hash, fourth.hash
14
+ end
15
+
4
16
  def test_equals2
5
17
  first = DescendantSelector.new(1,1)
6
18
  second = DescendantSelector.new(1,1)
@@ -1,6 +1,15 @@
1
1
  require File.dirname(__FILE__) + "/helper"
2
2
 
3
3
  class ElementSelectorTest < SelectorTestCase
4
+ def test_hash
5
+ first = ElementSelector.new(1)
6
+ second = ElementSelector.new(1)
7
+ assert_equal first.hash, second.hash
8
+
9
+ third = ElementSelector.new(2)
10
+ assert_not_equal first.hash, third.hash
11
+ end
12
+
4
13
  def test_equals2
5
14
  first = ElementSelector.new(1)
6
15
  second = ElementSelector.new(1)
@@ -0,0 +1,49 @@
1
+ require File.dirname(__FILE__) + "/helper"
2
+
3
+ class LexicalColorTest < Test::Unit::TestCase
4
+ include CSS::SAC
5
+
6
+ def test_to_s
7
+ first = Color.new('#FFFFFF')
8
+ assert_equal('#FFF', first.to_s)
9
+
10
+ second = Color.new('#FEFEFE')
11
+ assert_equal('#FEFEFE', second.to_s)
12
+
13
+ third = Color.new('red')
14
+ assert_equal('red', third.to_s)
15
+
16
+ fourth = Color.new('#0066FF')
17
+ assert_equal('#06F', fourth.to_s)
18
+ end
19
+
20
+ def test_hash
21
+ first = Color.new('#FFFFFF')
22
+ second = Color.new('#FFFFFF')
23
+ assert_equal first.hash, second.hash
24
+
25
+ third = Color.new('red')
26
+ assert_not_equal first.hash, third.hash
27
+ end
28
+
29
+ def test_equals2
30
+ first = Color.new('#FFFFFF')
31
+ second = Color.new('#FFFFFF')
32
+ assert_equal(first, second)
33
+
34
+ third = Color.new('#FFF')
35
+ assert_equal(first, third)
36
+
37
+ fourth = Color.new('#FFA')
38
+ assert_not_equal(first, fourth)
39
+ end
40
+
41
+ def test_equals2_string
42
+ first = Color.new('red')
43
+ second = Color.new('red')
44
+ assert_equal(first, second)
45
+
46
+ third = Color.new('#FFF')
47
+ assert_not_equal(first, third)
48
+ end
49
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + "/helper"
2
+
3
+ class LexicalFunctionTest < Test::Unit::TestCase
4
+ include CSS::SAC
5
+
6
+ def test_to_s
7
+ first = Function.new('counter(', %w{ 1 2 3 4 })
8
+ assert_equal('counter(1, 2, 3, 4)', first.to_s)
9
+ end
10
+
11
+ def test_equals2
12
+ first = Function.new('counter(', %w{ 1 2 3 4 })
13
+ second = Function.new('counter(', %w{ 1 2 3 4 })
14
+ assert_equal(first, second)
15
+
16
+ third = Function.new('rect(', %w{ 1 2 3 4 })
17
+ assert_not_equal(first, third)
18
+
19
+ fourth = Function.new('counter(', %w{ 1 2 3 5 })
20
+ assert_not_equal(first, fourth)
21
+ end
22
+
23
+ def test_hash
24
+ first = Function.new('counter(', %w{ 1 2 3 4 })
25
+ second = Function.new('counter(', %w{ 1 2 3 4 })
26
+ assert_equal first.hash, second.hash
27
+
28
+ third = Function.new('counter(', %w{ 1 2 4 4 })
29
+ assert_not_equal first.hash, third.hash
30
+ end
31
+ end
@@ -0,0 +1,30 @@
1
+ require File.dirname(__FILE__) + "/helper"
2
+
3
+ class LexicalIdentTest < Test::Unit::TestCase
4
+ include CSS::SAC
5
+
6
+ def test_equals2
7
+ first = LexicalIdent.new('one')
8
+ second = LexicalIdent.new('one')
9
+ assert_equal first, second
10
+
11
+ third = LexicalIdent.new('two')
12
+ assert_not_equal first, third
13
+ end
14
+
15
+ def test_eql?
16
+ first = LexicalIdent.new('one')
17
+ second = LexicalIdent.new('one')
18
+
19
+ assert first.eql?(second)
20
+ end
21
+
22
+ def test_hash
23
+ first = LexicalIdent.new('one')
24
+ second = LexicalIdent.new('one')
25
+ assert_equal first.hash, second.hash
26
+
27
+ third = LexicalIdent.new('two')
28
+ assert_not_equal first.hash, third.hash
29
+ end
30
+ end
@@ -0,0 +1,68 @@
1
+ require File.dirname(__FILE__) + "/helper"
2
+
3
+ class LexicalNumberTest < Test::Unit::TestCase
4
+ def test_to_s
5
+ first = CSS::SAC::Number.new('10', 'px')
6
+ assert_equal('10px', first.to_s)
7
+
8
+ second = CSS::SAC::Number.new('0', 'em')
9
+ assert_equal('0', second.to_s)
10
+ end
11
+
12
+ def test_hash
13
+ first = CSS::SAC::Number.new('10', 'px')
14
+ second = CSS::SAC::Number.new('10', 'px')
15
+ assert_equal first.hash, second.hash
16
+
17
+ third = CSS::SAC::Number.new('11', 'px')
18
+ assert_not_equal first.hash, third.hash
19
+
20
+ fourth = CSS::SAC::Number.new('10', 'em')
21
+ assert_not_equal first.hash, fourth.hash
22
+ end
23
+
24
+ def test_hash_0_unit
25
+ first = CSS::SAC::Number.new('0', 'px')
26
+ second = CSS::SAC::Number.new('0', 'px')
27
+ assert_equal first.hash, second.hash
28
+
29
+ third = CSS::SAC::Number.new('0', 'em')
30
+ assert_equal first.hash, third.hash
31
+ end
32
+
33
+ def test_equals2
34
+ first = CSS::SAC::Number.new('10', 'px')
35
+ second = CSS::SAC::Number.new('10', 'px')
36
+ assert_equal first, second
37
+
38
+ third = CSS::SAC::Number.new('10', 'ex')
39
+ assert_not_equal first, third
40
+
41
+ fourth = CSS::SAC::Number.new('11', 'px')
42
+ assert_equal(11, fourth.integer_value)
43
+ assert_not_equal first, fourth
44
+ end
45
+
46
+ def test_equals2_zero
47
+ first = CSS::SAC::Number.new('0', 'px')
48
+ second = CSS::SAC::Number.new('0', 'em')
49
+ assert_equal first, second
50
+
51
+ first_float = CSS::SAC::Number.new('0.0', 'px')
52
+ second_float = CSS::SAC::Number.new('0.0', 'em')
53
+ assert_equal first_float, second_float
54
+
55
+ third_float = CSS::SAC::Number.new('0.1', 'em')
56
+ assert_equal 0.1, third_float.float_value
57
+ assert_not_equal first_float, third_float
58
+ end
59
+
60
+ def test_equals2_type
61
+ first = CSS::SAC::Number.new(10, '', :SAC_INTEGER)
62
+ second = CSS::SAC::Number.new(10, '', :SAC_INTEGER)
63
+ assert_equal first, second
64
+
65
+ third = CSS::SAC::Number.new(11, '', :SAC_INTEGER)
66
+ assert_not_equal first, third
67
+ end
68
+ end
@@ -0,0 +1,23 @@
1
+ require File.dirname(__FILE__) + "/helper"
2
+
3
+ class LexicalStringTest < Test::Unit::TestCase
4
+ include CSS::SAC
5
+
6
+ def test_equals2
7
+ first = LexicalString.new('hey bro')
8
+ second = LexicalString.new('hey bro')
9
+ assert_equal(first, second)
10
+
11
+ third = LexicalString.new('hey bro again')
12
+ assert_not_equal(first, third)
13
+ end
14
+
15
+ def test_hash
16
+ first = LexicalString.new('hey bro')
17
+ second = LexicalString.new('hey bro')
18
+ assert_equal(first.hash, second.hash)
19
+
20
+ third = LexicalString.new('hey bro!')
21
+ assert_not_equal(first.hash, third.hash)
22
+ end
23
+ end
@@ -1,6 +1,8 @@
1
1
  require File.dirname(__FILE__) + "/helper"
2
2
 
3
3
  class LexicalUnitTest < Test::Unit::TestCase
4
+ include CSS::SAC
5
+
4
6
  def setup
5
7
  @sac = CSS::SAC::Parser.new()
6
8
  end
@@ -13,6 +15,14 @@ class LexicalUnitTest < Test::Unit::TestCase
13
15
  flexmock_verify
14
16
  end
15
17
 
18
+ def test_equals2
19
+ first = LexicalUnit.new
20
+ second = LexicalUnit.new
21
+ assert_equal(first, second)
22
+ second.lexical_unit_type = 'asdfadsf'
23
+ assert_not_equal(first, second)
24
+ end
25
+
16
26
  def test_color
17
27
  flexmock(@sac.document_handler).
18
28
  should_receive(:property).with('background-color', on { |list|
@@ -20,7 +30,7 @@ class LexicalUnitTest < Test::Unit::TestCase
20
30
  list.first.lexical_unit_type == :SAC_RGBCOLOR &&
21
31
  list.first.string_value == "#345" &&
22
32
  list.first.parameters.length == 3 &&
23
- list.first.parameters.map { |x| x.integer_value } == [3,4,5] &&
33
+ list.first.parameters.map { |x| x.integer_value } == [51,68,85] &&
24
34
  list.first.integer_value.nil?
25
35
  }, false).once
26
36
 
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + "/helper"
2
+
3
+ class LexicalURITest < Test::Unit::TestCase
4
+ include CSS::SAC
5
+
6
+ def test_to_s
7
+ first = LexicalURI.new('url(http://tenderlovemaking.com/)')
8
+ assert_equal('url(http://tenderlovemaking.com/)', first.to_s)
9
+ end
10
+
11
+ def test_hash
12
+ first = LexicalURI.new('url(http://tenderlovemaking.com/)')
13
+ second = LexicalURI.new('url(http://tenderlovemaking.com/)')
14
+ assert_equal first.hash, second.hash
15
+
16
+ third = LexicalURI.new('url(http://www.tenderlovemaking.com/)')
17
+ assert_not_equal first.hash, third.hash
18
+ end
19
+
20
+ def test_equals2
21
+ first = LexicalURI.new('url(http://tenderlovemaking.com/)')
22
+ second = LexicalURI.new('url(http://tenderlovemaking.com/)')
23
+ assert_equal first, second
24
+
25
+ third = LexicalURI.new('url(http://www.tenderlovemaking.com/)')
26
+ assert_not_equal first, third
27
+ end
28
+ end
data/test/test_parser.rb CHANGED
@@ -10,6 +10,22 @@ class ParserTest < Test::Unit::TestCase
10
10
  flexmock_close
11
11
  end
12
12
 
13
+ def test_parse_rule
14
+ class << @sac.document_handler
15
+ attr_accessor :selector
16
+ alias :start_selector :selector=
17
+ end
18
+ @sac.parse('h1 > div { }')
19
+
20
+ expected_rule = @sac.document_handler.selector
21
+ assert expected_rule
22
+
23
+ rule = @sac.parse_rule('h1 > div')
24
+ assert rule
25
+ assert_equal 1, rule.length
26
+ assert_equal expected_rule, rule
27
+ end
28
+
13
29
  def test_page
14
30
  flexmock(@sac.document_handler).
15
31
  should_receive(:start_page).ordered.
@@ -3,12 +3,20 @@ require File.dirname(__FILE__) + "/helper"
3
3
  class SelectorTest < SelectorTestCase
4
4
  class MySelector < Selector; end
5
5
 
6
+ def test_hash
7
+ first = Selector.new(1)
8
+ second = Selector.new(1)
9
+ assert_equal first.hash, second.hash
10
+
11
+ third = Selector.new(2)
12
+ assert_not_equal first.hash, third.hash
13
+ end
14
+
6
15
  def test_equals2
7
16
  first = Selector.new(1)
8
17
  second = Selector.new(1)
9
18
  assert_equal first, second
10
19
 
11
-
12
20
  third = Selector.new(2)
13
21
  assert_not_equal first, third
14
22
 
@@ -16,4 +24,13 @@ class SelectorTest < SelectorTestCase
16
24
  assert_equal first, fourth
17
25
  assert_not_equal first, 1
18
26
  end
27
+
28
+ def test_eql?
29
+ first = Selector.new(1)
30
+ second = Selector.new(1)
31
+ assert first.eql?(second)
32
+
33
+ third = Selector.new(2)
34
+ assert !first.eql?(third)
35
+ end
19
36
  end
@@ -17,6 +17,14 @@ class SelectorParserTest < Test::Unit::TestCase
17
17
  assert_equal(2, selectors.length)
18
18
  end
19
19
 
20
+ def test_eql?
21
+ @sac.parse('h1, h1 { }')
22
+ selectors = @sac.document_handler.selectors
23
+ assert_equal(2, selectors.length)
24
+ assert_equal selectors[0], selectors[1]
25
+ assert selectors[0].eql?(selectors[1])
26
+ end
27
+
20
28
  def test_adjacent
21
29
  @sac.parse('h1 + h2 { }')
22
30
  selectors = @sac.document_handler.selectors
@@ -1,6 +1,15 @@
1
1
  require File.dirname(__FILE__) + "/helper"
2
2
 
3
3
  class SiblingSelectorTest < SelectorTestCase
4
+ def test_hash
5
+ first = SiblingSelector.new(1,1)
6
+ second = SiblingSelector.new(1,1)
7
+ assert_equal first.hash, second.hash
8
+
9
+ third = SiblingSelector.new(1,2)
10
+ assert_not_equal first.hash, third.hash
11
+ end
12
+
4
13
  def test_equals2
5
14
  first = SiblingSelector.new(1,1)
6
15
  second = SiblingSelector.new(1,1)
@@ -0,0 +1,95 @@
1
+ require File.dirname(__FILE__) + "/helper"
2
+
3
+ class StyleSheetTest < SelectorTestCase
4
+ def setup
5
+ @sac = CSS::SAC::Parser.new
6
+ end
7
+
8
+ def test_rules_matching
9
+ doc = @sac.parse("div > p { letter-spacing: 1px; }")
10
+ node = parent_child_tree('div', 'p')
11
+ expected = doc.rules.first
12
+
13
+ found = doc.rules_matching(node)
14
+ assert_equal 1, found.length
15
+ assert_equal expected.selector, found.first.selector
16
+
17
+ found2 = (doc =~ node)
18
+ assert_equal 1, found2.length
19
+ assert_equal expected.selector, found2.first.selector
20
+ end
21
+
22
+ def test_find_rule
23
+ doc = @sac.parse("h1 { letter-spacing: 1px; }")
24
+ expected = doc.rules.first
25
+ assert_equal expected, doc.find_rule('h1')
26
+ assert_equal expected, doc['h1']
27
+ assert_equal expected, doc[expected]
28
+ end
29
+
30
+ def test_create_rule
31
+ doc = @sac.parse("h1 { letter-spacing: 1px; }")
32
+ rule = doc.create_rule('h1')
33
+ assert_equal doc.rules.first.selector, rule.selector
34
+ end
35
+
36
+ def test_reduce!
37
+ doc = @sac.parse(<<END
38
+ h1 {
39
+ background-color: red;
40
+ border-color: green;
41
+ }
42
+ h1 { letter-spacing: 1px; }
43
+ END
44
+ )
45
+ assert_equal(1, doc.rules.length)
46
+ end
47
+
48
+ def test_rules_by_property
49
+ doc = @sac.parse(<<END
50
+ h1 {
51
+ background-color: red;
52
+ padding: 100px;
53
+ border-color: green;
54
+ }
55
+ div {
56
+ border-color: green;
57
+ background-color: red;
58
+ padding: 100px;
59
+ }
60
+ END
61
+ )
62
+ assert_equal(2, doc.rules.length)
63
+ assert_equal(doc.rules[0].properties, doc.rules[1].properties)
64
+ assert_equal(1, doc.rules_by_property.keys.length)
65
+ assert_equal(2, doc.rules_by_property.values.first.length)
66
+ end
67
+
68
+ def test_to_css
69
+ doc = @sac.parse(<<END
70
+ h1 {
71
+ background-color: red;
72
+ padding: 100px;
73
+ border-color: green;
74
+ }
75
+ div {
76
+ border-color: green;
77
+ background-color: red;
78
+ padding: 100px;
79
+ }
80
+ .marquee { background: url(images/sfx1_bg.gif) bottom repeat-x;}
81
+ SELECT {font-family: Arial, Verdana, Geneva, sans-serif; font-size: small; }
82
+ END
83
+ )
84
+ css = doc.to_css
85
+ assert_match('div, h1 {', css)
86
+
87
+ [ 'border-color:green;',
88
+ 'background-color:red;',
89
+ 'url(images/sfx1_bg.gif',
90
+ 'Arial, Verdana, Geneva, sans-serif;',
91
+ 'padding:100px;'].each do |attribute|
92
+ assert_match(attribute, css)
93
+ end
94
+ end
95
+ end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: csspool
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.1
7
- date: 2007-11-17 00:00:00 -08:00
6
+ version: 0.2.0
7
+ date: 2007-11-28 00:00:00 -08:00
8
8
  summary: Parses CSS
9
9
  require_paths:
10
10
  - lib
@@ -63,6 +63,10 @@ files:
63
63
  - lib/css/sac/token.rb
64
64
  - lib/css/sac/tokenizer.rb
65
65
  - lib/css/sac/visitable.rb
66
+ - lib/css/stylesheet.rb
67
+ - lib/css/stylesheet/rule.rb
68
+ - lib/css/stylesheet/stylesheet.rb
69
+ - lib/csspool.rb
66
70
  - lib/parser.y
67
71
  - lib/property_parser.y
68
72
  - lib/property_parser.y.erb
@@ -81,7 +85,13 @@ files:
81
85
  - test/test_element_selector.rb
82
86
  - test/test_id_condition.rb
83
87
  - test/test_lexeme.rb
88
+ - test/test_lexical_color.rb
89
+ - test/test_lexical_function.rb
90
+ - test/test_lexical_ident.rb
91
+ - test/test_lexical_number.rb
92
+ - test/test_lexical_string.rb
84
93
  - test/test_lexical_unit.rb
94
+ - test/test_lexical_uri.rb
85
95
  - test/test_one_of_condition.rb
86
96
  - test/test_parse_error.rb
87
97
  - test/test_parser.rb
@@ -92,6 +102,7 @@ files:
92
102
  - test/test_sibling_selector.rb
93
103
  - test/test_simple_selector.rb
94
104
  - test/test_specificity.rb
105
+ - test/test_stylesheet.rb
95
106
  - test/test_token.rb
96
107
  - test/test_tokenizer.rb
97
108
  - test/test_xpath.rb