excession 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,281 @@
1
+ module Excession
2
+ class CssRegexHueMod
3
+
4
+ HASHSIX = /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})(\s|;|})/i
5
+ HASHTHREE = /#([a-f0-9])([a-f0-9])([a-f0-9])(\s|;|})/i
6
+ RGBCALL = /rgb\(\s*(-?[0-9]+)\s*,\s*(-?[0-9]+)\s*,\s*(-?[0-9]+)\)/i
7
+ RGBPCTCALL = /rgb\(\s*(-?[0-9]+)\s*%\s*,\s*(-?[0-9]+)\s*%\s*,\s*(-?[0-9]+)\s*%\s*\)/i
8
+
9
+
10
+ # Use this entry point.
11
+ def rotate_hue(angle_degrees, str)
12
+ replace_colours(str) do |hsl|
13
+ h,s,l = *hsl
14
+ [h+angle_degrees, s, l]
15
+ end
16
+ end
17
+
18
+
19
+
20
+ def rgb_to_hsl(rgbint)
21
+ rgb = rgbint.map{|i| i/255.0}
22
+ maxcolour = rgb.max
23
+ mincolour = rgb.min
24
+
25
+ #puts "maxcolour: #{maxcolour}"
26
+ #puts "mincolour: #{mincolour}"
27
+
28
+ cdiff = (maxcolour-mincolour)
29
+ csum = (maxcolour + mincolour)
30
+
31
+ #puts "cdiff: #{cdiff}"
32
+ #puts "csum: #{csum}"
33
+
34
+ l = csum/2
35
+ #puts "l: #{l}"
36
+ h,s = 0,0
37
+ if maxcolour != mincolour
38
+ s = l < 0.5 ? cdiff/csum : cdiff/(2.0-csum)
39
+ #puts "s: #{s}"
40
+ r,g,b = rgb
41
+ h = if r == maxcolour
42
+ (g-b)/cdiff
43
+ elsif g == maxcolour
44
+ 2.0+(b-r)/cdiff
45
+ else
46
+ 4.0+(r-g)/cdiff
47
+ end
48
+ #puts "h: #{h}"
49
+ end
50
+
51
+ return [(h*360)%360,s,l]
52
+ end
53
+
54
+ def hsl_to_rgb(hsl)
55
+ hdeg,s,l = *hsl
56
+
57
+ rgb = nil
58
+ if s == 0
59
+ rgb = [l,l,l]
60
+ else
61
+ temp2 = l < 0.5 ? l*(1+s) : l+s-l*s
62
+ temp1 = 2.0*l-temp2
63
+ h = hdeg/360.0
64
+ temp3 = [h+1.0/3.0, h, h-1.0/3.0].map{|i| i < 0 ? i+1 : (i > 1 ? i-1 : i)}
65
+ rgb = temp3.map do |i|
66
+ if 6.0*i < 1
67
+ temp1 + (temp2-temp1)*6.0*i
68
+ elsif 2*i < 1
69
+ temp2
70
+ elsif 3*i < 2
71
+ temp1 + (temp2-temp1)*((2.0/3.0)-i)*6.0
72
+ else
73
+ temp1
74
+ end
75
+ end
76
+ end
77
+ rgb.map{|i| (i*255).floor}
78
+ end
79
+
80
+ def rgb_to_hashsix(rgb)
81
+ "#" + rgb.map do |i|
82
+ str = i.to_s(16)
83
+ raise "Invalid colour (#{rgb.inspect})!" if str.length > 2
84
+ str="0"+str if str.length<2
85
+ str
86
+ end.join
87
+ end
88
+
89
+ def modify_hsl(hsl, &blk)
90
+ newhsl = blk.call(hsl)
91
+ newhsl[0] %= 360
92
+ newhsl
93
+ end
94
+
95
+ def modify_rgb(rgb, &blk)
96
+ rgb_to_hashsix(hsl_to_rgb(modify_hsl(rgb_to_hsl(rgb), &blk)))
97
+ end
98
+
99
+ def replace_colours(str, &blk)
100
+
101
+ str.gsub!(HASHSIX) do
102
+ hexr, hexg, hexb, tend = $1, $2, $3, $4
103
+ modify_rgb([hexr, hexg, hexb].map(&:hex), &blk)+tend
104
+ end
105
+
106
+ str.gsub!(HASHTHREE) do
107
+ hexr, hexg, hexb, tend = $1, $2, $3, $4
108
+ modify_rgb([hexr*2,hexg*2,hexb*2].map(&:hex), &blk)+tend
109
+ end
110
+
111
+ str.gsub!(RGBCALL) do
112
+ strr, strg, strb = $1, $2, $3
113
+ modify_rgb([strr, strg, strb].map{|s|Integer(s)}, &blk)
114
+ end
115
+
116
+ str.gsub!(RGBPCTCALL) do
117
+ strr, strg, strb = $1, $2, $3
118
+ modify_rgb([strr, strg, strb].
119
+ map{|s|Integer(s)}.
120
+ map{|i| (i/100.0) * 255 }, # Don't just multiply by 2.55, it's not accurate
121
+ &blk)
122
+ end
123
+
124
+ str
125
+ end
126
+
127
+ end # class CssRegexHueMod
128
+ end # module Excession
129
+
130
+
131
+ =begin
132
+ COLOUR_LOOKUP = {
133
+ "AliceBlue" =>"#F0F8FF",
134
+ "AntiqueWhite" =>"#FAEBD7",
135
+ "Aqua" =>"#00FFFF",
136
+ "Aquamarine" =>"#7FFFD4",
137
+ "Azure" =>"#F0FFFF",
138
+ "Beige" =>"#F5F5DC",
139
+ "Bisque" =>"#FFE4C4",
140
+ "Black" =>"#000000",
141
+ "BlanchedAlmond" =>"#FFEBCD",
142
+ "Blue" =>"#0000FF",
143
+ "BlueViolet" =>"#8A2BE2",
144
+ "Brown" =>"#A52A2A",
145
+ "BurlyWood" =>"#DEB887",
146
+ "CadetBlue" =>"#5F9EA0",
147
+ "Chartreuse" =>"#7FFF00",
148
+ "Chocolate" =>"#D2691E",
149
+ "Coral" =>"#FF7F50",
150
+ "CornflowerBlue" =>"#6495ED",
151
+ "Cornsilk" =>"#FFF8DC",
152
+ "Crimson" =>"#DC143C",
153
+ "Cyan" =>"#00FFFF",
154
+ "DarkBlue" =>"#00008B",
155
+ "DarkCyan" =>"#008B8B",
156
+ "DarkGoldenRod" =>"#B8860B",
157
+ "DarkGray" =>"#A9A9A9",
158
+ "DarkGrey" =>"#A9A9A9",
159
+ "DarkGreen" =>"#006400",
160
+ "DarkKhaki" =>"#BDB76B",
161
+ "DarkMagenta" =>"#8B008B",
162
+ "DarkOliveGreen" =>"#556B2F",
163
+ "Darkorange" =>"#FF8C00",
164
+ "DarkOrchid" =>"#9932CC",
165
+ "DarkRed" =>"#8B0000",
166
+ "DarkSalmon" =>"#E9967A",
167
+ "DarkSeaGreen" =>"#8FBC8F",
168
+ "DarkSlateBlue" =>"#483D8B",
169
+ "DarkSlateGray" =>"#2F4F4F",
170
+ "DarkSlateGrey" =>"#2F4F4F",
171
+ "DarkTurquoise" =>"#00CED1",
172
+ "DarkViolet" =>"#9400D3",
173
+ "DeepPink" =>"#FF1493",
174
+ "DeepSkyBlue" =>"#00BFFF",
175
+ "DimGray" =>"#696969",
176
+ "DimGrey" =>"#696969",
177
+ "DodgerBlue" =>"#1E90FF",
178
+ "FireBrick" =>"#B22222",
179
+ "FloralWhite" =>"#FFFAF0",
180
+ "ForestGreen" =>"#228B22",
181
+ "Fuchsia" =>"#FF00FF",
182
+ "Gainsboro" =>"#DCDCDC",
183
+ "GhostWhite" =>"#F8F8FF",
184
+ "Gold" =>"#FFD700",
185
+ "GoldenRod" =>"#DAA520",
186
+ "Gray" =>"#808080",
187
+ "Grey" =>"#808080",
188
+ "Green" =>"#008000",
189
+ "GreenYellow" =>"#ADFF2F",
190
+ "HoneyDew" =>"#F0FFF0",
191
+ "HotPink" =>"#FF69B4",
192
+ "IndianRed" =>"#CD5C5C",
193
+ "Indigo" =>"#4B0082",
194
+ "Ivory" =>"#FFFFF0",
195
+ "Khaki" =>"#F0E68C",
196
+ "Lavender" =>"#E6E6FA",
197
+ "LavenderBlush" =>"#FFF0F5",
198
+ "LawnGreen" =>"#7CFC00",
199
+ "LemonChiffon" =>"#FFFACD",
200
+ "LightBlue" =>"#ADD8E6",
201
+ "LightCoral" =>"#F08080",
202
+ "LightCyan" =>"#E0FFFF",
203
+ "LightGoldenRodYellow" =>"#FAFAD2",
204
+ "LightGray" =>"#D3D3D3",
205
+ "LightGrey" =>"#D3D3D3",
206
+ "LightGreen" =>"#90EE90",
207
+ "LightPink" =>"#FFB6C1",
208
+ "LightSalmon" =>"#FFA07A",
209
+ "LightSeaGreen" =>"#20B2AA",
210
+ "LightSkyBlue" =>"#87CEFA",
211
+ "LightSlateGray" =>"#778899",
212
+ "LightSlateGrey" =>"#778899",
213
+ "LightSteelBlue" =>"#B0C4DE",
214
+ "LightYellow" =>"#FFFFE0",
215
+ "Lime" =>"#00FF00",
216
+ "LimeGreen" =>"#32CD32",
217
+ "Linen" =>"#FAF0E6",
218
+ "Magenta" =>"#FF00FF",
219
+ "Maroon" =>"#800000",
220
+ "MediumAquaMarine" =>"#66CDAA",
221
+ "MediumBlue" =>"#0000CD",
222
+ "MediumOrchid" =>"#BA55D3",
223
+ "MediumPurple" =>"#9370D8",
224
+ "MediumSeaGreen" =>"#3CB371",
225
+ "MediumSlateBlue" =>"#7B68EE",
226
+ "MediumSpringGreen" =>"#00FA9A",
227
+ "MediumTurquoise" =>"#48D1CC",
228
+ "MediumVioletRed" =>"#C71585",
229
+ "MidnightBlue" =>"#191970",
230
+ "MintCream" =>"#F5FFFA",
231
+ "MistyRose" =>"#FFE4E1",
232
+ "Moccasin" =>"#FFE4B5",
233
+ "NavajoWhite" =>"#FFDEAD",
234
+ "Navy" =>"#000080",
235
+ "OldLace" =>"#FDF5E6",
236
+ "Olive" =>"#808000",
237
+ "OliveDrab" =>"#6B8E23",
238
+ "Orange" =>"#FFA500",
239
+ "OrangeRed" =>"#FF4500",
240
+ "Orchid" =>"#DA70D6",
241
+ "PaleGoldenRod" =>"#EEE8AA",
242
+ "PaleGreen" =>"#98FB98",
243
+ "PaleTurquoise" =>"#AFEEEE",
244
+ "PaleVioletRed" =>"#D87093",
245
+ "PapayaWhip" =>"#FFEFD5",
246
+ "PeachPuff" =>"#FFDAB9",
247
+ "Peru" =>"#CD853F",
248
+ "Pink" =>"#FFC0CB",
249
+ "Plum" =>"#DDA0DD",
250
+ "PowderBlue" =>"#B0E0E6",
251
+ "Purple" =>"#800080",
252
+ "Red" =>"#FF0000",
253
+ "RosyBrown" =>"#BC8F8F",
254
+ "RoyalBlue" =>"#4169E1",
255
+ "SaddleBrown" =>"#8B4513",
256
+ "Salmon" =>"#FA8072",
257
+ "SandyBrown" =>"#F4A460",
258
+ "SeaGreen" =>"#2E8B57",
259
+ "SeaShell" =>"#FFF5EE",
260
+ "Sienna" =>"#A0522D",
261
+ "Silver" =>"#C0C0C0",
262
+ "SkyBlue" =>"#87CEEB",
263
+ "SlateBlue" =>"#6A5ACD",
264
+ "SlateGray" =>"#708090",
265
+ "SlateGrey" =>"#708090",
266
+ "Snow" =>"#FFFAFA",
267
+ "SpringGreen" =>"#00FF7F",
268
+ "SteelBlue" =>"#4682B4",
269
+ "Tan" =>"#D2B48C",
270
+ "Teal" =>"#008080",
271
+ "Thistle" =>"#D8BFD8",
272
+ "Tomato" =>"#FF6347",
273
+ "Turquoise" =>"#40E0D0",
274
+ "Violet" =>"#EE82EE",
275
+ "Wheat" =>"#F5DEB3",
276
+ "White" =>"#FFFFFF",
277
+ "WhiteSmoke" =>"#F5F5F5",
278
+ "Yellow" =>"#FFFF00",
279
+ "YellowGreen" =>"#9ACD32"
280
+ }
281
+ =end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ module Excession
4
+
5
+ module Parser
6
+
7
+ def self.parse(str)
8
+ CssTransform.new.apply(CssParser.new.parse(str))
9
+ end # def self.parse
10
+
11
+
12
+
13
+ class CssTransform < Parslet::Transform
14
+ rule(:comment => simple(:content)){CommentNode.new(content)}
15
+ rule(:whitespace => simple(:content)){WhitespaceNode.new(content)}
16
+ rule(:selectors => simple(:selectors)){SelectorsNode.new(selectors)}
17
+ rule(:ruleset => simple(:ruleset)){RulesetNode.new(ruleset)}
18
+ rule(:children => sequence(:children)){CssFile.new(children)}
19
+ end
20
+
21
+
22
+ class CssFile < Struct.new(:children)
23
+
24
+ end
25
+
26
+
27
+ class CommentNode < Struct.new(:content)
28
+ end
29
+
30
+ class WhitespaceNode < Struct.new(:content)
31
+ end
32
+
33
+ class SelectorsNode < Struct.new(:selectors)
34
+ end
35
+
36
+ class RulesetNode < Struct.new(:selectors, :children)
37
+ end
38
+
39
+
40
+ end # class Parser
41
+
42
+
43
+
44
+
45
+
46
+
47
+ end # module Excession
@@ -0,0 +1,391 @@
1
+ # encoding: utf-8
2
+ require 'parslet'
3
+
4
+ module Excession
5
+
6
+ module Parser
7
+
8
+
9
+ class CssParser < Parslet::Parser
10
+ def initialize(strict=false)
11
+ @strict=strict
12
+ super()
13
+ end
14
+
15
+ rule(:h){ match["0-9a-fA-F"] }
16
+ rule(:nonascii){ match["\200-\377".force_encoding("BINARY")] }
17
+ rule(:unicode){
18
+ str("\\") >> h.repeat(1,6) >> (str("\r\n") | match[" \t\r\n\f"]).maybe
19
+ }
20
+ rule(:escape){
21
+ (unicode | (str("\\\\") >> match["\r\n\f0-9a-fA-F"].absnt? >> any))
22
+ }
23
+ rule(:nmstart){ match["_a-zA-Z"] | nonascii | escape }
24
+ rule(:nmchar){ match["_a-zA-Z0-9-"] | nonascii | escape }
25
+ rule(:nl){ str("\n") | str("\r\n") | str("\r") | str("\f") }
26
+ rule(:dqstring_contents){
27
+ (
28
+ (match["\n\r\f\""].absnt? >> any) |
29
+ (str("\\\\") >> nl) |
30
+ escape
31
+ ).repeat
32
+ }
33
+ rule(:sqstring_contents){
34
+ (
35
+ (match["\n\r\f'"].absnt? >> any) |
36
+ (str("\\\\") >> nl) |
37
+ escape
38
+ ).repeat
39
+ }
40
+ rule(:string1){ str('"') >> dqstring_contents >> str('"') }
41
+ rule(:string2){ str("'") >> sqstring_contents >> str("'") }
42
+ rule(:badstring1){ str('"') >> dqstring_contents >> str("\\").maybe }
43
+ rule(:badstring2){ str("'") >> sqstring_contents >> str("\\").maybe }
44
+ rule(:badcomment1){
45
+ str("/*") >>
46
+ (match["*"].absnt? >> any).repeat >>
47
+ str("*").repeat(1) >>
48
+ (
49
+ match["/*"].absnt? >> any >>
50
+ (match["*"].absnt? >> any).repeat >>
51
+ str("*").repeat(1)
52
+ ).repeat
53
+ }
54
+ rule(:badcomment2){
55
+ str("/*") >>
56
+ (match["*"].absnt? >> any).repeat >>
57
+ (
58
+ str("*").repeat(1) >>
59
+ match["/*"].absnt? >> any >>
60
+ (match["*"].absnt? >> any).repeat
61
+ ).repeat
62
+ }
63
+
64
+
65
+ # These are used to get the JS in an expression() declaration.
66
+ # Since we don't care much for parsing JS here, I'm just using
67
+ # the rule that valid JS must have balanced parens, and ignore
68
+ # unbalanced parens in comments and strings. For now.
69
+ # Thanks, IE.
70
+ rule(:js_chars){ (match["()"].absnt? >> any).repeat(1) }
71
+ rule(:js_bracketed){ str("(") >> js_balancing.maybe >> str(")") }
72
+ rule(:js_balancing){ ( js_chars | js_bracketed ).repeat(1) }
73
+
74
+
75
+ rule(:s){ match[" \t\r\n\f"].repeat(1) }
76
+ rule(:w){ s.repeat(0) }
77
+
78
+ rule(:baduri1){
79
+ str("url(") >> w >>
80
+ (
81
+ match['!#$%&*-\[\]-~'] |
82
+ nonascii |
83
+ escape
84
+ ).repeat >>
85
+ w
86
+ }
87
+
88
+ rule(:string){ string1 | string2 }
89
+
90
+ rule(:baduri2){ str("url(") >> w >> string >> w }
91
+
92
+ rule(:badstring){ badstring1 | badstring2 }
93
+ rule(:baduri3){ str("url(") >> w >> badstring }
94
+
95
+
96
+ rule(:comment){
97
+ str("/*") >>
98
+ (
99
+ match["*"].absnt? >> any
100
+ ).repeat >>
101
+ str("*").repeat(1) >>
102
+ (
103
+ match["*/"].absnt? >> any >>
104
+ (match["*"].absnt? >> any).repeat >>
105
+ str("*").repeat(1)
106
+ ).repeat >>
107
+ str("/")
108
+ }
109
+
110
+
111
+ rule(:ident){
112
+ str("-").maybe >> nmstart >> nmchar.repeat
113
+ }
114
+
115
+ rule(:name){ nmchar.repeat(1) }
116
+ rule(:num){
117
+ (
118
+ match["0-9"].repeat(0) >>
119
+ str(".") >>
120
+ match["0-9"].repeat(1)
121
+ ) |
122
+ match["0-9"].repeat(1)
123
+ }
124
+
125
+
126
+ rule(:badcomment){ badcomment1 | badcomment2 }
127
+
128
+ rule(:baduri){ baduri2 | baduri3 | baduri1 }
129
+
130
+ rule(:url){
131
+ (
132
+ match['!#$%&*-~'] |
133
+ nonascii |
134
+ escape
135
+ ).repeat
136
+ }
137
+
138
+ # Case insensitive character match with escaped character codes.
139
+ #
140
+ # TODO: The CSS2.1 spec allows all letters apart from
141
+ # a,c,d and e to be specified like "\g". This is not supported
142
+ # here.
143
+ def cimatch(char)
144
+ upper = char.upcase.force_encoding("BINARY")
145
+ lower = char.downcase.force_encoding("BINARY")
146
+ return match["#{upper}#{lower}"] |
147
+ ( str("\\") >>
148
+ str("0").repeat(0,4) >>
149
+ (str(upper[0].ord.to_s(16)) | str(lower[0].ord.to_s(16))) >>
150
+ (str("\r\n") | match[" \t\r\n\f"]).maybe )
151
+ end
152
+
153
+
154
+ def cimatch_word(word)
155
+ word.each_char.map{|c| self.cimatch(c)}.reduce(:>>)
156
+ end
157
+
158
+
159
+ rule(:sym_comment){ comment.as(:comment) }
160
+ # NB: Deviation. Comments are ignored in the 2.1 grammar, but I
161
+ # want to preserve them. I've made the S symbol cover comments
162
+ # as well.
163
+ rule(:sym_s){ sym_comment | s.as(:s) }
164
+ rule(:sym_s_star){ sym_s.repeat }
165
+ rule(:sym_badcomment){ badcomment.as(:badcomment) }
166
+ rule(:sym_cdo){ str("<!--").as(:cdo) }
167
+ rule(:sym_cdc){ str("-->").as(:cdc) }
168
+ rule(:sym_includes){ str("~=").as(:includes) }
169
+ rule(:sym_dashmatch){ str("|=").as(:dashmatch) }
170
+ rule(:sym_string){ string.as(:string) }
171
+ rule(:sym_badstring){ badstring.as(:badstring) }
172
+ rule(:sym_ident){ ident.as(:ident) }
173
+
174
+ rule(:sym_hash){ (str("#") >> name).as(:hash) }
175
+
176
+ rule(:sym_import_sym){
177
+ (str("@") >> cimatch_word("import")).as(:import_sym)
178
+ }
179
+ rule(:sym_page_sym){
180
+ (str("@") >> cimatch_word("page")).as(:page_sym)
181
+ }
182
+ rule(:sym_media_sym){
183
+ (str("@") >> cimatch_word("media")).as(:media_sym)
184
+ }
185
+
186
+ rule(:sym_charset_sym){
187
+ str("@charset ").as(:charset_sym)
188
+ }
189
+
190
+ rule(:sym_important_sym){
191
+ # NB deviation: s is a w in the spec
192
+ (str("!") >>
193
+ (comment | s).repeat >>
194
+ cimatch_word("important")
195
+ ).as(:important_sym)
196
+ }
197
+
198
+
199
+ rule(:sym_ems){
200
+ (num.as(:num) >> cimatch_word("em").as(:unit)).as(:ems)
201
+ }
202
+ rule(:sym_exs){
203
+ (num.as(:num) >> cimatch_word("ex").as(:unit)).as(:exs)
204
+ }
205
+ rule(:sym_length){
206
+ units = %w{px cm mm in pt pc}
207
+ unit_matcher = units.map{|u| cimatch_word(u)}.reduce(:|)
208
+
209
+ (num.as(:num) >> unit_matcher.as(:unit)).as(:length)
210
+ }
211
+ rule(:sym_angle){
212
+ units = %w{deg rad grad}
213
+ unit_matcher = units.map{|u| cimatch_word(u)}.reduce(:|)
214
+
215
+ (num.as(:num) >> unit_matcher.as(:unit)).as(:angle)
216
+ }
217
+ rule(:sym_time){
218
+ units = %w{ms s}
219
+ unit_matcher = units.map{|u| cimatch_word(u)}.reduce(:|)
220
+
221
+ (num.as(:num) >> unit_matcher.as(:unit)).as(:time)
222
+ }
223
+ rule(:sym_freq){
224
+ units = %w{hz khz}
225
+ unit_matcher = units.map{|u| cimatch_word(u)}.reduce(:|)
226
+
227
+ (num.as(:num) >> unit_matcher.as(:unit)).as(:freq)
228
+ }
229
+ rule(:sym_dimension){
230
+ (num.as(:num) >> ident.as(:unit)).as(:dimension)
231
+ }
232
+ rule(:sym_percentage){
233
+ (num.as(:num) >> str("%").as(:unit)).as(:percentage)
234
+ }
235
+ rule(:sym_number){ (num.as(:num)).as(:number) }
236
+ rule(:sym_uri){
237
+ (cimatch_word("url") >> str("(") >>
238
+ (string.as(:string) | url.as(:url)) >>
239
+ str(")")).as(:uri)
240
+ }
241
+ rule(:sym_js){ js_balancing }
242
+
243
+ rule(:sym_baduri){ baduri.as(:baduri) }
244
+
245
+ rule(:sym_function){ (ident.as(:name) >> str("(")).as(:function) }
246
+ rule(:sym_expression){ cimatch_word("expression") >> str("(") }
247
+
248
+
249
+
250
+ rule(:prod_hexcolor){ sym_hash >> sym_s_star }
251
+
252
+ rule(:prod_operator){ match["/,"] >> sym_s_star }
253
+ rule(:prod_unary_operator){ match["-+"] }
254
+ rule(:prod_combinator){ match["+>"] >> sym_s_star }
255
+
256
+ rule(:prod_function){
257
+ sym_function >> sym_s_star >> prod_function_arglist >> str(")") >> sym_s_star
258
+ }
259
+
260
+ rule(:prod_expression){
261
+ sym_expression >> sym_s_star >> sym_js.as(:js) >> str(")") >> sym_s_star
262
+ }
263
+
264
+ rule(:prod_maybe_named_arg){
265
+ ((sym_ident >> str("=")).maybe >> prod_term)
266
+ }
267
+
268
+ rule(:prod_function_arglist){
269
+ if @strict
270
+ prod_expr
271
+ else
272
+ # This works around IE, which allows things like:
273
+ # filter: alpha(opacity=90)
274
+ prod_maybe_named_arg >>
275
+ ( prod_operator.maybe >>
276
+ prod_maybe_named_arg ).repeat
277
+ end
278
+ }
279
+
280
+ rule(:prod_term){
281
+ # expression() is a deprecated IE extension which allows arbitrary
282
+ # JS expressions (!) to be used for property values. This was a STUPID
283
+ # IDEA, but it's still used to give IE6 approximately modern functionality.
284
+ ( @strict ? prod_function : (prod_expression | prod_function) ) |
285
+ ( prod_unary_operator.maybe >>
286
+ ( sym_percentage | sym_length | sym_ems | sym_exs | sym_angle |
287
+ sym_time | sym_freq | sym_number ) >>
288
+ sym_s_star ) |
289
+ ( ( sym_string | sym_uri | sym_ident ) >> sym_s_star ) |
290
+ prod_hexcolor
291
+ }
292
+
293
+
294
+ rule(:prod_expr){
295
+ prod_term >> ( prod_operator.maybe >> prod_term ).repeat
296
+ }
297
+
298
+ rule(:prod_prio){ sym_important_sym >> sym_s_star }
299
+ rule(:prod_property){ sym_ident >> sym_s_star }
300
+ rule(:prod_declaration){
301
+ base = ( prod_property.as(:property) >> str(":") >>
302
+ sym_s_star >> prod_expr.as(:value) >> prod_prio.maybe )
303
+ # Only old IE versions need to pay attention to this. Or rather,
304
+ # this is used to flag declarations as only applying to old IE versions,
305
+ # because they don't correctly ignore the declaration.
306
+ @strict ? base : ( str("*").maybe.as(:star) >> base )
307
+ }
308
+
309
+ rule(:prod_pseudo){
310
+ str(":") >> ( ( sym_function >> sym_s_star >>
311
+ ( sym_ident >> sym_s_star ).maybe >> str(")") ) |
312
+ sym_ident)
313
+ }
314
+
315
+ rule(:prod_attrib){
316
+ str("[") >> sym_s_star >> sym_ident.as(:key) >> sym_s_star >>
317
+ (
318
+ ( sym_includes | sym_dashmatch | str("=") ) >> sym_s_star >>
319
+ ( sym_string | sym_ident ).as(:value) >> sym_s_star
320
+ ).maybe >>
321
+ str("]")
322
+ }
323
+
324
+ rule(:prod_element_name){ sym_ident | str("*") }
325
+ rule(:prod_class){ str(".") >> sym_ident }
326
+
327
+ rule(:prod_simple_selector){
328
+ ( prod_element_name >>
329
+ ( sym_hash | prod_class | prod_attrib | prod_pseudo ).repeat ) |
330
+ ( sym_hash | prod_class | prod_attrib | prod_pseudo ).repeat(1)
331
+ }
332
+
333
+ rule(:prod_selector){
334
+ prod_simple_selector.as(:parent) >>
335
+ ( ( prod_combinator >> prod_selector.as(:child) ) |
336
+ ( sym_s.repeat(1) >> ( prod_combinator.maybe >> prod_selector.as(:child) ).maybe )
337
+ ).maybe
338
+ }
339
+
340
+ rule(:prod_ruleset){
341
+ prod_selector >>
342
+ ( str(",") >> sym_s_star >> prod_selector ).repeat >>
343
+ str("{") >> sym_s_star >>
344
+ prod_declaration.maybe >>
345
+ ( str(";") >> sym_s_star >> prod_declaration.maybe
346
+ ).repeat >>
347
+ str("}") >> sym_s_star
348
+ }
349
+
350
+ rule(:prod_pseudo_page){ str(":") >> sym_ident >> sym_s_star }
351
+ rule(:prod_page){ sym_page_sym >> sym_s_star >>
352
+ prod_pseudo_page.maybe >> str("{") >> sym_s_star >>
353
+ prod_declaration.maybe >>
354
+ ( str(";") >> sym_s_star >> prod_declaration.maybe
355
+ ).repeat >>
356
+ str("}") >> sym_s_star
357
+ }
358
+
359
+ rule(:prod_medium){ sym_ident >> sym_s_star }
360
+ rule(:prod_media_list){
361
+ # NB str(",") is for the missing COMMA symbol from the grammar
362
+ prod_medium >> (str(",") >> sym_s_star >> prod_medium).repeat
363
+ }
364
+ rule(:prod_media){
365
+ sym_media_sym >> sym_s_star >> prod_media_list >> str("{") >> sym_s_star >>
366
+ prod_ruleset.repeat >>
367
+ str("}") >> sym_s_star
368
+ }
369
+
370
+ rule(:prod_import){
371
+ sym_import_sym >> sym_s_star >> (sym_string | sym_uri) >> sym_s_star >>
372
+ prod_media_list.maybe >>
373
+ str(";") >> sym_s_star
374
+ }
375
+
376
+ rule(:prod_stylesheet){
377
+ ( sym_charset_sym >> sym_string >> str(";") ).maybe >>
378
+ ( sym_s | sym_cdo | sym_cdc ).repeat >>
379
+ ( prod_import >>
380
+ ( ( sym_cdo >> sym_s_star ) | (sym_cdc >> sym_s_star ) ).repeat ).repeat >>
381
+ ( ( prod_ruleset | prod_media | prod_page ) >>
382
+ ( ( sym_cdo >> sym_s_star ) | (sym_cdc >> sym_s_star ) ).repeat ).repeat
383
+ }
384
+
385
+
386
+ root(:prod_stylesheet)
387
+ end # class CssLexer
388
+
389
+
390
+ end # module Parser
391
+ end # module Excession
@@ -0,0 +1,3 @@
1
+ module Excession
2
+ VERSION="0.0.3"
3
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: excession
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 3
9
+ version: 0.0.3
10
+ platform: ruby
11
+ authors:
12
+ - Alex Young
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-01-20 00:00:00 +00:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: |
22
+ Excession is a collection of code for parsing and otherwise
23
+ munging CSS files. It has sprung from a need to be able to
24
+ programmatically modify colours in a site's style sheets.
25
+
26
+ email:
27
+ - alex@blackkettle.org
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files: []
33
+
34
+ files:
35
+ - lib/excession/parser.rb
36
+ - lib/excession/version.rb
37
+ - lib/excession/css_regex_hue_mod.rb
38
+ - lib/excession/parser/css_parser.rb
39
+ has_rdoc: true
40
+ homepage: http://github.com/regularfry/excession
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options: []
45
+
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ segments:
60
+ - 1
61
+ - 3
62
+ - 6
63
+ version: 1.3.6
64
+ requirements: []
65
+
66
+ rubyforge_project:
67
+ rubygems_version: 1.3.6
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: Useful code for handling CSS files
71
+ test_files: []
72
+