csspool 0.2.6 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. data/.autotest +16 -0
  2. data/{CHANGELOG.txt → CHANGELOG.rdoc} +10 -0
  3. data/Manifest.txt +60 -72
  4. data/README.rdoc +78 -0
  5. data/Rakefile +9 -52
  6. data/lib/csspool/collection.rb +50 -0
  7. data/lib/csspool/css/charset.rb +7 -0
  8. data/lib/csspool/css/declaration.rb +8 -0
  9. data/lib/csspool/css/document.rb +34 -0
  10. data/lib/csspool/css/document_handler.rb +51 -0
  11. data/lib/csspool/css/import_rule.rb +15 -0
  12. data/lib/csspool/css/media.rb +7 -0
  13. data/lib/csspool/css/rule_set.rb +12 -0
  14. data/lib/csspool/css.rb +7 -0
  15. data/lib/csspool/lib_croco/cr_additional_sel.rb +46 -0
  16. data/lib/csspool/lib_croco/cr_attr_sel.rb +16 -0
  17. data/lib/csspool/lib_croco/cr_doc_handler.rb +24 -0
  18. data/lib/csspool/lib_croco/cr_num.rb +13 -0
  19. data/lib/csspool/lib_croco/cr_parser.rb +11 -0
  20. data/lib/csspool/lib_croco/cr_parsing_location.rb +17 -0
  21. data/lib/csspool/lib_croco/cr_pseudo.rb +14 -0
  22. data/lib/csspool/lib_croco/cr_rgb.rb +18 -0
  23. data/lib/csspool/lib_croco/cr_selector.rb +34 -0
  24. data/lib/csspool/lib_croco/cr_simple_sel.rb +54 -0
  25. data/lib/csspool/lib_croco/cr_term.rb +97 -0
  26. data/lib/csspool/lib_croco/glist.rb +21 -0
  27. data/lib/csspool/lib_croco.rb +78 -0
  28. data/lib/csspool/node.rb +5 -0
  29. data/lib/csspool/sac/document.rb +35 -0
  30. data/lib/csspool/sac/parser.rb +122 -0
  31. data/lib/csspool/sac.rb +2 -0
  32. data/lib/csspool/selector.rb +32 -0
  33. data/lib/csspool/selectors/additional.rb +6 -0
  34. data/lib/csspool/selectors/attribute.rb +21 -0
  35. data/lib/csspool/selectors/class.rb +11 -0
  36. data/lib/csspool/selectors/id.rb +11 -0
  37. data/lib/csspool/selectors/pseudo_class.rb +13 -0
  38. data/lib/csspool/selectors/simple.rb +22 -0
  39. data/lib/csspool/selectors/type.rb +6 -0
  40. data/lib/csspool/selectors/universal.rb +6 -0
  41. data/lib/csspool/selectors.rb +8 -0
  42. data/lib/csspool/terms/function.rb +17 -0
  43. data/lib/csspool/terms/hash.rb +6 -0
  44. data/lib/csspool/terms/ident.rb +15 -0
  45. data/lib/csspool/terms/number.rb +14 -0
  46. data/lib/csspool/terms/rgb.rb +23 -0
  47. data/lib/csspool/terms/string.rb +6 -0
  48. data/lib/csspool/terms/uri.rb +6 -0
  49. data/lib/csspool/terms.rb +7 -0
  50. data/lib/csspool/visitable.rb +18 -0
  51. data/lib/csspool/visitors/comparable.rb +78 -0
  52. data/lib/csspool/visitors/to_css.rb +201 -0
  53. data/lib/csspool/visitors/visitor.rb +17 -0
  54. data/lib/csspool/visitors.rb +3 -0
  55. data/lib/csspool.rb +18 -1
  56. data/test/css/test_document.rb +13 -0
  57. data/test/css/test_import_rule.rb +42 -0
  58. data/test/helper.rb +62 -6
  59. data/test/sac/test_parser.rb +115 -0
  60. data/test/sac/test_properties.rb +43 -0
  61. data/test/sac/test_terms.rb +134 -0
  62. data/test/test_collection.rb +81 -0
  63. data/test/test_parser.rb +75 -241
  64. data/test/test_selector.rb +45 -34
  65. data/test/visitors/test_comparable.rb +72 -0
  66. data/test/visitors/test_to_css.rb +141 -0
  67. metadata +98 -85
  68. data/README.txt +0 -79
  69. data/lib/css/sac/conditions/attribute_condition.rb +0 -56
  70. data/lib/css/sac/conditions/begin_hyphen_condition.rb +0 -22
  71. data/lib/css/sac/conditions/class_condition.rb +0 -22
  72. data/lib/css/sac/conditions/combinator_condition.rb +0 -40
  73. data/lib/css/sac/conditions/condition.rb +0 -35
  74. data/lib/css/sac/conditions/id_condition.rb +0 -27
  75. data/lib/css/sac/conditions/one_of_condition.rb +0 -22
  76. data/lib/css/sac/conditions/pseudo_class_condition.rb +0 -24
  77. data/lib/css/sac/conditions.rb +0 -5
  78. data/lib/css/sac/document_handler.rb +0 -67
  79. data/lib/css/sac/error_handler.rb +0 -14
  80. data/lib/css/sac/generated_parser.rb +0 -999
  81. data/lib/css/sac/generated_property_parser.rb +0 -9214
  82. data/lib/css/sac/lexeme.rb +0 -29
  83. data/lib/css/sac/lexical_unit.rb +0 -203
  84. data/lib/css/sac/parse_exception.rb +0 -6
  85. data/lib/css/sac/parser.rb +0 -115
  86. data/lib/css/sac/property_parser.rb +0 -47
  87. data/lib/css/sac/selectors/child_selector.rb +0 -40
  88. data/lib/css/sac/selectors/conditional_selector.rb +0 -49
  89. data/lib/css/sac/selectors/descendant_selector.rb +0 -40
  90. data/lib/css/sac/selectors/element_selector.rb +0 -39
  91. data/lib/css/sac/selectors/selector.rb +0 -31
  92. data/lib/css/sac/selectors/sibling_selector.rb +0 -39
  93. data/lib/css/sac/selectors/simple_selector.rb +0 -25
  94. data/lib/css/sac/selectors.rb +0 -5
  95. data/lib/css/sac/token.rb +0 -27
  96. data/lib/css/sac/tokenizer.rb +0 -187
  97. data/lib/css/sac/visitable.rb +0 -106
  98. data/lib/css/sac.rb +0 -14
  99. data/lib/css/stylesheet/rule.rb +0 -20
  100. data/lib/css/stylesheet/stylesheet.rb +0 -96
  101. data/lib/css/stylesheet.rb +0 -3
  102. data/lib/parser.y +0 -308
  103. data/lib/property_parser.y +0 -2346
  104. data/lib/property_parser.y.erb +0 -1321
  105. data/test/condition_test_case.rb +0 -6
  106. data/test/selector_test_case.rb +0 -20
  107. data/test/test_all.rb +0 -4
  108. data/test/test_attribute_condition.rb +0 -39
  109. data/test/test_begin_hyphen_condition.rb +0 -15
  110. data/test/test_child_selector.rb +0 -60
  111. data/test/test_class_condition.rb +0 -15
  112. data/test/test_combinator_condition.rb +0 -38
  113. data/test/test_condition.rb +0 -31
  114. data/test/test_conditional_selector.rb +0 -44
  115. data/test/test_descendant_selector.rb +0 -64
  116. data/test/test_element_selector.rb +0 -31
  117. data/test/test_error_recovery.rb +0 -28
  118. data/test/test_id_condition.rb +0 -16
  119. data/test/test_lexeme.rb +0 -39
  120. data/test/test_lexical_color.rb +0 -49
  121. data/test/test_lexical_function.rb +0 -31
  122. data/test/test_lexical_ident.rb +0 -30
  123. data/test/test_lexical_number.rb +0 -68
  124. data/test/test_lexical_string.rb +0 -23
  125. data/test/test_lexical_unit.rb +0 -106
  126. data/test/test_lexical_uri.rb +0 -28
  127. data/test/test_one_of_condition.rb +0 -15
  128. data/test/test_parse_error.rb +0 -199
  129. data/test/test_property_parser.rb +0 -593
  130. data/test/test_selector_as_string.rb +0 -94
  131. data/test/test_selector_parser.rb +0 -178
  132. data/test/test_sibling_selector.rb +0 -42
  133. data/test/test_simple_selector.rb +0 -9
  134. data/test/test_specificity.rb +0 -76
  135. data/test/test_stylesheet.rb +0 -95
  136. data/test/test_token.rb +0 -24
  137. data/test/test_tokenizer.rb +0 -127
  138. data/test/test_xpath.rb +0 -105
@@ -1,187 +0,0 @@
1
- require "css/sac/lexeme"
2
- require "css/sac/token"
3
-
4
- module CSS
5
- module SAC
6
- class Tokenizer
7
- def initialize(&block)
8
- @lexemes = []
9
- @macros = {}
10
-
11
- # http://www.w3.org/TR/CSS21/syndata.html
12
- macro(:h, /([0-9a-f])/ )
13
- macro(:nonascii, /([\200-\377])/ )
14
- macro(:nl, /(\n|\r\n|\r|\f)/ )
15
- macro(:unicode, /(\\#{m(:h)}{1,6}(\r\n|[ \t\r\n\f])?)/ )
16
- macro(:escape, /(#{m(:unicode)}|\\[^\r\n\f0-9a-f])/ )
17
- macro(:nmstart, /([_a-z]|#{m(:nonascii)}|#{m(:escape)})/ )
18
- macro(:nmchar, /([_a-z0-9-]|#{m(:nonascii)}|#{m(:escape)})/ )
19
- macro(:string1, /(\"([^\n\r\f\\\"]|\\#{m(:nl)}|#{m(:escape)})*\")/ )
20
- macro(:string2, /(\'([^\n\r\f\\']|\\#{m(:nl)}|#{m(:escape)})*\')/ )
21
- macro(:invalid1, /(\"([^\n\r\f\\\"]|\\#{m(:nl)}|#{m(:escape)})*)/ )
22
- macro(:invalid2, /(\'([^\n\r\f\\']|\\#{m(:nl)}|#{m(:escape)})*)/ )
23
- macro(:comment, /(\/\*[^*]*\*+([^\/*][^*]*\*+)*\/)/ )
24
- macro(:ident, /(-?#{m(:nmstart)}#{m(:nmchar)}*)/ )
25
- macro(:name, /(#{m(:nmchar)}+)/ )
26
- macro(:num, /([0-9]+|[0-9]*\.[0-9]+)/ )
27
- macro(:string, /(#{m(:string1)}|#{m(:string2)})/ )
28
- macro(:invalid, /(#{m(:invalid1)}|#{m(:invalid2)})/ )
29
- macro(:url, /(([!#\$%&*-~]|#{m(:nonascii)}|#{m(:escape)})*)/ )
30
- macro(:s, /([ \t\r\n\f]+)/ )
31
- macro(:w, /(#{m(:s)}?)/ )
32
- macro(:A, /(a|\\0{0,4}(41|61)(\r\n|[ \t\r\n\f])?)/ )
33
- macro(:C, /(c|\\0{0,4}(43|63)(\r\n|[ \t\r\n\f])?)/ )
34
- macro(:D, /(d|\\0{0,4}(44|64)(\r\n|[ \t\r\n\f])?)/ )
35
- macro(:E, /(e|\\0{0,4}(45|65)(\r\n|[ \t\r\n\f])?)/ )
36
- macro(:G, /(g|\\0{0,4}(47|67)(\r\n|[ \t\r\n\f])?|\\g)/ )
37
- macro(:H, /(h|\\0{0,4}(48|68)(\r\n|[ \t\r\n\f])?|\\h)/ )
38
- macro(:I, /(i|\\0{0,4}(49|69)(\r\n|[ \t\r\n\f])?|\\i)/ )
39
- macro(:K, /(k|\\0{0,4}(4b|6b)(\r\n|[ \t\r\n\f])?|\\k)/ )
40
- macro(:M, /(m|\\0{0,4}(4d|6d)(\r\n|[ \t\r\n\f])?|\\m)/ )
41
- macro(:N, /(n|\\0{0,4}(4e|6e)(\r\n|[ \t\r\n\f])?|\\n)/ )
42
- macro(:O, /(o|\\0{0,4}(51|71)(\r\n|[ \t\r\n\f])?|\\o)/ )
43
- macro(:P, /(p|\\0{0,4}(50|70)(\r\n|[ \t\r\n\f])?|\\p)/ )
44
- macro(:R, /(r|\\0{0,4}(52|72)(\r\n|[ \t\r\n\f])?|\\r)/ )
45
- macro(:S, /(s|\\0{0,4}(53|73)(\r\n|[ \t\r\n\f])?|\\s)/ )
46
- macro(:T, /(t|\\0{0,4}(54|74)(\r\n|[ \t\r\n\f])?|\\t)/ )
47
- macro(:X, /(x|\\0{0,4}(58|78)(\r\n|[ \t\r\n\f])?|\\x)/ )
48
- macro(:Z, /(z|\\0{0,4}(5a|7a)(\r\n|[ \t\r\n\f])?|\\z)/ )
49
-
50
- #token :COMMENT do |patterns|
51
- # patterns << /\/\*[^*]*\*+([^\/*][^*]*\*+)*\//
52
- # patterns << /#{m(:s)}+\/\*[^*]*\*+([^\/*][^*]*\*+)*\//
53
- #end
54
-
55
- token(:LBRACE, /#{m(:w)}\{/)
56
- token(:PLUS, /#{m(:w)}\+/)
57
- token(:GREATER, /#{m(:w)}>/)
58
- token(:COMMA, /#{m(:w)},/)
59
-
60
- token(:S, /#{m(:s)}/)
61
-
62
- #token :URI do |patterns|
63
- # patterns << /url\(#{m(:w)}#{m(:string)}#{m(:w)}\)/
64
- # patterns << /url\(#{m(:w)}#{m(:url)}#{m(:w)}\)/
65
- #end
66
-
67
- token(:FUNCTION, /#{m(:ident)}\(/)
68
- token(:IDENT, /#{m(:ident)}/)
69
-
70
- token(:CDO, /<!--/)
71
- token(:CDC, /-->/)
72
- token(:INCLUDES, /~=/)
73
- token(:DASHMATCH, /\|=/)
74
- #token(:STRING, /#{m(:string)}/)
75
- token(:INVALID, /#{m(:invalid)}/)
76
- token(:HASH, /##{m(:name)}/)
77
- token(:IMPORT_SYM, /@#{m(:I)}#{m(:M)}#{m(:P)}#{m(:O)}#{m(:R)}#{m(:T)}/)
78
- token(:PAGE_SYM, /@#{m(:P)}#{m(:A)}#{m(:G)}#{m(:E)}/)
79
- token(:MEDIA_SYM, /@#{m(:M)}#{m(:E)}#{m(:D)}#{m(:I)}#{m(:A)}/)
80
- token(:CHARSET_SYM, /@#{m(:C)}#{m(:H)}#{m(:A)}#{m(:R)}#{m(:S)}#{m(:E)}#{m(:T)}/)
81
- token(:IMPORTANT_SYM, /!(#{m(:w)}|#{m(:comment)})*#{m(:I)}#{m(:M)}#{m(:P)}#{m(:O)}#{m(:R)}#{m(:T)}#{m(:A)}#{m(:N)}#{m(:T)}/)
82
- token(:EMS, /#{m(:num)}#{m(:E)}#{m(:M)}/)
83
- token(:EXS, /#{m(:num)}#{m(:E)}#{m(:X)}/)
84
-
85
- token :LENGTH do |patterns|
86
- patterns << /#{m(:num)}#{m(:P)}#{m(:X)}/
87
- patterns << /#{m(:num)}#{m(:C)}#{m(:M)}/
88
- patterns << /#{m(:num)}#{m(:M)}#{m(:M)}/
89
- patterns << /#{m(:num)}#{m(:I)}#{m(:N)}/
90
- patterns << /#{m(:num)}#{m(:P)}#{m(:T)}/
91
- patterns << /#{m(:num)}#{m(:P)}#{m(:C)}/
92
- end
93
-
94
- token :ANGLE do |patterns|
95
- patterns << /#{m(:num)}#{m(:D)}#{m(:E)}#{m(:G)}/
96
- patterns << /#{m(:num)}#{m(:R)}#{m(:A)}#{m(:D)}/
97
- patterns << /#{m(:num)}#{m(:G)}#{m(:R)}#{m(:A)}#{m(:D)}/
98
- end
99
-
100
- token :TIME do |patterns|
101
- patterns << /#{m(:num)}#{m(:M)}#{m(:S)}/
102
- patterns << /#{m(:num)}#{m(:S)}/
103
- end
104
-
105
- token :FREQ do |patterns|
106
- patterns << /#{m(:num)}#{m(:H)}#{m(:Z)}/
107
- patterns << /#{m(:num)}#{m(:K)}#{m(:H)}#{m(:Z)}/
108
- end
109
-
110
- token(:DIMENSION, /#{m(:num)}#{m(:ident)}/)
111
- token(:PERCENTAGE, /#{m(:num)}%/)
112
- token(:NUMBER, /#{m(:num)}/)
113
-
114
-
115
- yield self if block_given?
116
- end
117
-
118
- def tokenize(input_data)
119
- tokens = []
120
- pos = 0
121
-
122
- comment_pattern = /\/\*.*?\*\//m
123
- comments = input_data.scan(comment_pattern)
124
- non_comments = input_data.split(comment_pattern)
125
-
126
- # Handle a small edge case, if our CSS is *only* comments,
127
- # the split, zip, scan trick won't work
128
- if non_comments.length == 0
129
- tokens = comments.map { |x| Token.new(:COMMENT, x, nil) }
130
- else
131
- non_comments.zip(comments).each do |non_comment, comment|
132
- non_comment.split(/url\([^\)]*\)/m).zip(
133
- non_comment.scan(/url\([^\)]*\)/m)
134
- ).each do |non_url, url|
135
- non_url.split(/"[^"]*"|'[^']*'/m).zip(
136
- non_url.scan(/"[^"]*"|'[^']*'/m)
137
- ).each do |non_string, quoted_string|
138
- if non_string.length > 0 && non_string =~ /\A\s*\Z/m
139
- tokens << Token.new(:S, non_string, nil)
140
- else
141
- non_string.split(/[ \t\r\n\f]*(?![{}+>]*)/m).zip(
142
- non_string.scan(/[ \t\r\n\f]*(?![{}+>]*)/m)
143
- ).each do |string, whitespace|
144
- until string.empty?
145
- token = nil
146
- @lexemes.each do |lexeme|
147
- match = lexeme.pattern.match(string)
148
- if match
149
- token = Token.new(lexeme.name, match.to_s, pos)
150
- break
151
- end
152
- end
153
-
154
- token ||= DelimiterToken.new(/^./.match(string).to_s, pos)
155
-
156
- tokens << token
157
- string = string.slice(Range.new(token.value.length, -1))
158
- pos += token.value.length
159
- end
160
- tokens << Token.new(:S, whitespace, nil) if whitespace
161
- end
162
- end
163
- tokens << Token.new(:STRING, quoted_string, nil) if quoted_string
164
- end
165
- tokens << Token.new(:URI, url, nil) if url
166
- end
167
- tokens << Token.new(:COMMENT, comment, nil) if comment
168
- end
169
- end
170
-
171
- tokens
172
- end
173
-
174
- private
175
-
176
- def token(name, pattern=nil, &block)
177
- @lexemes << Lexeme.new(name, pattern, &block)
178
- end
179
-
180
- def macro(name, regex=nil)
181
- regex ? @macros[name] = regex : @macros[name].source
182
- end
183
-
184
- alias :m :macro
185
- end
186
- end
187
- end
@@ -1,106 +0,0 @@
1
- module CSS
2
- module SAC
3
- module Visitable # :nodoc:
4
- # Based off the visitor pattern from RubyGarden
5
- def accept(visitor, &block)
6
- klass = self.class.ancestors.find { |klass|
7
- visitor.respond_to?("visit_#{klass.name.split(/::/)[-1]}")
8
- }
9
-
10
- if klass
11
- visitor.send(:"visit_#{klass.name.split(/::/)[-1]}", self, &block)
12
- else
13
- raise "No visitor for '#{self.class}'"
14
- end
15
- end
16
- end
17
-
18
- class MatchesVisitor
19
- def initialize(node)
20
- @node = node
21
- end
22
-
23
- def accept(target)
24
- target.accept(self)
25
- end
26
-
27
- def visit_SimpleSelector(o)
28
- return false if @node.nil?
29
- return false unless @node.respond_to?(:name)
30
- true
31
- end
32
-
33
- def visit_ElementSelector(o)
34
- return false unless visit_SimpleSelector(o) # *sigh*
35
- o.name == @node.name
36
- end
37
-
38
- def visit_ChildSelector(o)
39
- return false unless visit_SimpleSelector(o) # *sigh*
40
- return false unless @node.respond_to?(:parent)
41
- return false if @node.parent.nil?
42
- return false unless o.selector.accept(self)
43
- @node = @node.parent
44
- o.parent.accept(self)
45
- end
46
-
47
- def visit_DescendantSelector(o)
48
- return false unless visit_SimpleSelector(o) # *sigh*
49
- return false unless @node.respond_to?(:parent)
50
- return false if @node.parent.nil?
51
- return false unless o.selector.accept(self)
52
-
53
- @node = @node.parent
54
- loop {
55
- return true if o.ancestor.accept(self)
56
- return false unless @node.respond_to?(:parent)
57
- @node = @node.parent
58
- }
59
- end
60
-
61
- def visit_SiblingSelector(o)
62
- return false unless visit_SimpleSelector(o) # *sigh*
63
- return false unless @node.respond_to?(:next_sibling)
64
- return false if @node.next_sibling.nil?
65
- return false unless o.selector.accept(self)
66
- @node = @node.next_sibling
67
- o.sibling.accept(self)
68
- end
69
-
70
- def visit_ConditionalSelector(o)
71
- return false unless visit_SimpleSelector(o) # *sigh*
72
- [o.selector, o.condition].compact.all? { |x|
73
- x.accept(self)
74
- }
75
- end
76
-
77
- def visit_AttributeCondition(o)
78
- return false unless @node.respond_to?(:attributes)
79
- return false unless @node.attributes[o.local_name]
80
- @node.attributes[o.local_name] == o.value
81
- end
82
-
83
- def visit_BeginHyphenCondition(o)
84
- return false unless @node.respond_to?(:attributes)
85
- return false unless @node.attributes[o.local_name]
86
- @node.attributes[o.local_name] =~ /^#{o.value}/
87
- end
88
-
89
- def visit_CombinatorCondition(o)
90
- o.first.accept(self) && o.second.accept(self)
91
- end
92
-
93
- def visit_OneOfCondition(o)
94
- return false unless @node.respond_to?(:attributes)
95
- return false unless @node.attributes[o.local_name]
96
- @node.attributes[o.local_name].split.any? { |attribute|
97
- attribute == o.value
98
- }
99
- end
100
-
101
- def visit_PseudoClassCondition(o)
102
- false # Fuck pseudo classes. --Aaron
103
- end
104
- end
105
- end
106
- end
data/lib/css/sac.rb DELETED
@@ -1,14 +0,0 @@
1
- require "css/sac/parser"
2
- require "css/stylesheet"
3
-
4
- module CSS
5
- module SAC
6
- class << self
7
- def parse(text)
8
- parser = CSS::SAC::Parser.new
9
- parser.parse(text)
10
- parser
11
- end
12
- end
13
- end
14
- end
@@ -1,20 +0,0 @@
1
- require 'set'
2
- module CSS
3
- class StyleSheet
4
- class Rule
5
- include Comparable
6
-
7
- attr_accessor :selector, :properties, :index
8
- def initialize(selector, index, properties = [])
9
- @selector = selector
10
- @properties = Set.new(properties)
11
- @index = index
12
- end
13
-
14
- def <=>(other)
15
- comp = selector.specificity <=> other.selector.specificity
16
- comp == 0 ? index <=> other.index : comp
17
- end
18
- end
19
- end
20
- end
@@ -1,96 +0,0 @@
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
- @selector_index = 0
10
- end
11
-
12
- def start_selector(selectors)
13
- selectors.each { |selector|
14
- @current_rules << Rule.new(selector, @selector_index)
15
- }
16
- end
17
-
18
- def end_selector(selectors)
19
- @rules += @current_rules
20
- @current_rules = []
21
- @selector_index += 1
22
- reduce!
23
- end
24
-
25
- def find_rule(rule)
26
- rule = self.create_rule(rule) if rule.is_a?(String)
27
- rules.find { |x| x.selector == rule.selector }
28
- end
29
- alias :[] :find_rule
30
-
31
- # Find all rules used in +hpricot_document+
32
- def find_all_rules_matching(hpricot_document)
33
- used_rules = []
34
- hpricot_document.search('//').each do |node|
35
- if matching = (rules_matching(node))
36
- used_rules += matching
37
- end
38
- end
39
- used_rules.uniq
40
- end
41
-
42
- # Find all rules that match +node+. +node+ must quack like an Hpricot
43
- # node.
44
- def rules_matching(node)
45
- rules.find_all { |rule|
46
- rule.selector =~ node
47
- }
48
- end
49
- alias :=~ :rules_matching
50
-
51
- def create_rule(rule)
52
- Rule.new(@sac.parse_rule(rule).first, @selector_index += 1)
53
- end
54
-
55
- def property(name, value, important)
56
- @current_rules.each { |selector|
57
- selector.properties << [name, value, important]
58
- }
59
- end
60
-
61
- # Get a hash of rules by property
62
- def rules_by_property
63
- rules_by_property = Hash.new { |h,k| h[k] = [] }
64
- @rules.each { |sel|
65
- props = sel.properties.to_a.sort_by { |x| x.hash } # HACK?
66
- rules_by_property[props] << sel
67
- }
68
- rules_by_property
69
- end
70
-
71
- def to_css
72
- rules_by_property.map do |properties, rules|
73
- rules.map { |rule| rule.selector.to_css }.sort.join(', ') + " {\n" +
74
- properties.map { |key,value,important|
75
- # Super annoying. If the property is font-family, its supposed to
76
- # be commas
77
- join_val = ('font-family' == key) ? ', ' : ' '
78
- values = [value].flatten.join(join_val)
79
- "#{key}:#{values}#{important ? ' !important' : ''};"
80
- }.join("\n") + "\n}"
81
- end.sort.join("\n")
82
- end
83
-
84
- private
85
- # Remove duplicate rules
86
- def reduce!
87
- unique_rules = {}
88
- @rules.each do |rule|
89
- (unique_rules[rule.selector] ||= rule).properties += rule.properties
90
- end
91
- @rules = unique_rules.values
92
- self
93
- end
94
- end
95
- end
96
-
@@ -1,3 +0,0 @@
1
- require "css/stylesheet/stylesheet"
2
- require "css/stylesheet/rule"
3
-