excession 0.0.3

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.
@@ -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
+