less 1.0.16 → 1.1.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,271 @@
1
+ module Less
2
+ grammar StyleSheet
3
+ include Common
4
+ include Entity
5
+
6
+ rule primary
7
+ (declaration / ruleset / import / comment)+ <Builder> / declaration* <Builder> / import* <Builder> / comment*
8
+ end
9
+
10
+ rule comment
11
+ ws '/*' (!'*/' . )* '*/' ws / ws '//' (!"\n" .)* "\n" ws
12
+ end
13
+
14
+ #
15
+ # div, .class, body > p {...}
16
+ #
17
+ rule ruleset
18
+ selectors "{" ws primary ws "}" ws {
19
+ def build env
20
+ # Build the ruleset for each selector
21
+ selectors.build(env, :ruleset).each do |sel|
22
+ primary.build sel
23
+ end
24
+ end
25
+ } / ws selectors ';' ws {
26
+ def build env
27
+ selectors.build(env, :mixin).each do |path|
28
+ rules = path.inject(env.root) do |current, node|
29
+ current.descend(node.selector, node) or raise MixinNameError, path.join
30
+ end.rules
31
+ env.rules += rules
32
+ end
33
+ end
34
+ }
35
+ end
36
+
37
+ rule import
38
+ "@import" S url:(string / url) medias? s ';' ws {
39
+ def build env
40
+ path = File.join(env.root.file, url.value)
41
+ path += '.less' unless path =~ /\.(le|c)ss$/
42
+ if File.exist? path
43
+ imported = Less::Engine.new(File.new(path)).to_tree
44
+ env.rules += imported.rules
45
+ else
46
+ raise ImportError, path
47
+ end
48
+ end
49
+ }
50
+ end
51
+
52
+ rule url
53
+ 'url(' path:(string / [-a-zA-Z0-9_%$/.&=:;#+?]+) ')' {
54
+ def build env = nil
55
+ Node::String.new CGI.unescape(path.text_value)
56
+ end
57
+
58
+ def value
59
+ build
60
+ end
61
+ }
62
+ end
63
+
64
+ rule medias
65
+ [-a-z]+ (s ',' s [a-z]+)*
66
+ end
67
+
68
+ rule selectors
69
+ ws selector tail:(s ',' ws selector)* ws {
70
+ def build env, method
71
+ all.map do |e|
72
+ e.send(method, env) if e.respond_to? method
73
+ end.compact
74
+ end
75
+
76
+ def all
77
+ [selector] + tail.elements.map {|e| e.selector }
78
+ end
79
+ }
80
+ end
81
+
82
+ #
83
+ # div > p a {...}
84
+ #
85
+ rule selector
86
+ sel:(s select element s)+ arguments? {
87
+ def ruleset env
88
+ sel.elements.inject(env) do |node, e|
89
+ node << Node::Element.new(e.element.text_value, e.select.text_value)
90
+ node.last
91
+ end
92
+ end
93
+
94
+ def mixin env
95
+ sel.elements.map do |e|
96
+ Node::Element.new(e.element.text_value, e.select.text_value)
97
+ end
98
+ end
99
+ }
100
+ end
101
+
102
+ #
103
+ # @my-var: 12px;
104
+ # height: 100%;
105
+ #
106
+ rule declaration
107
+ ws name:(ident / variable) s ':' s expressions s (';'/ ws &'}') ws {
108
+ def build env
109
+ env << (name.text_value =~ /^@/ ?
110
+ Node::Variable : Node::Property).new(name.text_value, expressions.build(env), env)
111
+ end
112
+ # Empty rule
113
+ } / ws ident s ':' s ';' ws
114
+ end
115
+
116
+ #
117
+ # An operation or compound value
118
+ #
119
+ rule expressions
120
+ # Operation
121
+ expression tail:(operator expression)+ {
122
+ def build env
123
+ all.map {|e| e.build(env) }.dissolve
124
+ end
125
+
126
+ def all
127
+ [expression] + tail.elements.map {|i| [i.operator, i.expression] }.flatten.compact
128
+ end
129
+ # Space-delimited expressions
130
+ } / expression tail:(WS expression)* {
131
+ def build env
132
+ all.map {|e| e.build(env) if e.respond_to? :build }.compact
133
+ end
134
+
135
+ def all
136
+ [expression] + tail.elements.map {|f| f.expression }
137
+ end
138
+ }
139
+ end
140
+
141
+ rule expression
142
+ '(' s expressions s ')' {
143
+ def build env
144
+ Node::Expression.new(['('] + expressions.build(env).flatten + [')'])
145
+ end
146
+ } / entity '' {
147
+ def build env
148
+ entity.method(:build).arity.zero?? entity.build : entity.build(env)
149
+ end
150
+ }
151
+ end
152
+
153
+ #
154
+ # An identifier
155
+ #
156
+ rule ident
157
+ '*'? '-'? [-a-z0-9_]+
158
+ end
159
+
160
+ rule variable
161
+ '@' [-a-zA-Z0-9_]+ {
162
+ def build
163
+ Node::Variable.new(text_value)
164
+ end
165
+ }
166
+ end
167
+
168
+ #
169
+ # div / .class / #id / input[type="text"] / lang(fr)
170
+ #
171
+ rule element
172
+ (class_id / tag / ident) attribute* ('(' ident? attribute* ')')? / attribute+ / '@media' / '@font-face'
173
+ end
174
+
175
+ rule class_id
176
+ tag? (class / id)+
177
+ end
178
+
179
+ #
180
+ # [type="text"]
181
+ #
182
+ rule attribute
183
+ '[' tag ([|~*$^]? '=') (tag / string) ']' / '[' (tag / string) ']'
184
+ end
185
+
186
+ rule class
187
+ '.' [_a-z] [-a-zA-Z0-9_]*
188
+ end
189
+
190
+ rule id
191
+ '#' [_a-z] [-a-zA-Z0-9_]*
192
+ end
193
+
194
+ rule tag
195
+ [a-zA-Z] [-a-zA-Z]* [0-9]? / '*'
196
+ end
197
+
198
+ rule select
199
+ (s [+>~] s / s ':' / S)?
200
+ end
201
+
202
+ # TODO: Merge this with attribute rule
203
+ rule accessor
204
+ ident:(class_id / tag) '[' attr:(string / variable) ']' {
205
+ def build env
206
+ env.nearest(ident.text_value)[attr.text_value.delete(%q["'])].evaluate
207
+ end
208
+ }
209
+ end
210
+
211
+ rule operator
212
+ S [-+*/] S {
213
+ def build env
214
+ Node::Operator.new(text_value.strip)
215
+ end
216
+ } / [-+*/] {
217
+ def build env
218
+ Node::Operator.new(text_value)
219
+ end
220
+ }
221
+ end
222
+
223
+ #
224
+ # Functions and arguments
225
+ #
226
+ rule function
227
+ name:([-a-zA-Z_]+) arguments {
228
+ def build
229
+ Node::Function.new(name.text_value, [arguments.build].flatten)
230
+ end
231
+ }
232
+ end
233
+
234
+ rule arguments
235
+ '(' s argument s tail:(',' s argument s)* ')' {
236
+ def build
237
+ all.map do |e|
238
+ e.build if e.respond_to? :build
239
+ end.compact
240
+ end
241
+
242
+ def all
243
+ [argument] + tail.elements.map {|e| e.argument }
244
+ end
245
+ }
246
+ end
247
+
248
+ rule argument
249
+ color / number unit {
250
+ def build
251
+ Node::Number.new number.text_value, unit.text_value
252
+ end
253
+ } / string {
254
+ def build
255
+ Node::String.new text_value
256
+ end
257
+ } / [a-zA-Z]+ '=' dimension {
258
+ def build
259
+ Node::Anonymous.new text_value
260
+ end
261
+ } / [-a-zA-Z0-9_%$/.&=:;#+?]+ {
262
+ def build
263
+ Node::String.new text_value
264
+ end
265
+ } / function / keyword other:(S keyword)* {
266
+ def build
267
+ end
268
+ }
269
+ end
270
+ end
271
+ end
@@ -36,6 +36,10 @@ module Less
36
36
 
37
37
  rgba hue[ h + 1/3 ], hue[ h ], hue[ h - 1/3 ], a
38
38
  end
39
+
40
+ def self.available
41
+ self.instance_methods.map(&:to_sym)
42
+ end
39
43
  end
40
44
 
41
45
  module Node
@@ -45,31 +49,30 @@ module Less
45
49
  # it calls functions from the Functions module
46
50
  #
47
51
  class Function < ::String
48
- include Functions
49
52
  include Entity
53
+ include Functions
50
54
 
51
55
  def initialize name, *args
52
56
  @args = args.flatten
53
57
  super name
54
58
  end
55
-
59
+
56
60
  def to_css
57
61
  self.evaluate.to_css
58
62
  end
59
63
 
60
64
  #
61
65
  # Call the function
62
- #
63
- def evaluate
64
- send self.to_sym, *@args
65
- end
66
-
67
66
  #
68
67
  # If the function isn't found, we just print it out,
69
68
  # this is the case for url(), for example,
70
69
  #
71
- def method_missing meth, *args
72
- Node::Anonymous.new("#{meth}(#{args.map(&:to_css) * ', '})")
70
+ def evaluate
71
+ if Functions.available.include? self.to_sym
72
+ send to_sym, *@args
73
+ else
74
+ Node::Anonymous.new("#{to_sym}(#{@args.map(&:to_css) * ', '})")
75
+ end
73
76
  end
74
77
  end
75
78
  end
@@ -4,4 +4,13 @@
4
4
  width: 36;
5
5
  padding: 2px 36px;
6
6
  }
7
- .more-parens { padding: 8 4 4 4px; }
7
+ .more-parens {
8
+ padding: 8 4 4 4px;
9
+ width: 96;
10
+ height: 113;
11
+ margin: 12;
12
+ }
13
+ .nested-parens {
14
+ width: 71;
15
+ height: 6;
16
+ }
@@ -9,7 +9,13 @@
9
9
  .more-parens {
10
10
  @var: (2 * 2);
11
11
  padding: (2 * @var) 4 4 (@var * 1px);
12
- //width: (@var * @var) * 6;
12
+ width: (@var * @var) * 6;
13
+ height: (7 * 7) + (8 * 8);
14
+ margin: 4 * (5 + 5) / 2 - (@var * 2);
13
15
  //margin: (6 * 6)px;
14
- //height: (7 * 7) + (8 * 8);
15
16
  }
17
+
18
+ .nested-parens {
19
+ width: 2 * (4 * (2 + (1 + 6))) - 1;
20
+ height: ((2+3)*(2+3) / (9-4)) + 1;
21
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: less
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.16
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - cloudhead
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-23 00:00:00 -04:00
12
+ date: 2009-07-27 00:00:00 -04:00
13
13
  default_executable: lessc
14
14
  dependencies: []
15
15
 
@@ -30,11 +30,14 @@ files:
30
30
  - VERSION
31
31
  - bin/lessc
32
32
  - less.gemspec
33
+ - lib/ext.rb
33
34
  - lib/less.rb
34
35
  - lib/less/command.rb
35
36
  - lib/less/engine.rb
36
37
  - lib/less/engine/builder.rb
37
- - lib/less/engine/less.tt
38
+ - lib/less/engine/grammar/common.tt
39
+ - lib/less/engine/grammar/entity.tt
40
+ - lib/less/engine/grammar/less.tt
38
41
  - lib/less/engine/nodes.rb
39
42
  - lib/less/engine/nodes/element.rb
40
43
  - lib/less/engine/nodes/entity.rb
@@ -43,7 +46,6 @@ files:
43
46
  - lib/less/engine/nodes/property.rb
44
47
  - lib/less/engine/nodes/ruleset.rb
45
48
  - lib/less/engine/nodes/selector.rb
46
- - lib/less/engine/parser.rb
47
49
  - lib/vendor/treetop/.gitignore
48
50
  - lib/vendor/treetop/LICENSE
49
51
  - lib/vendor/treetop/README
@@ -1,422 +0,0 @@
1
- grammar Less
2
- rule primary
3
- (declaration / ruleset / import / comment)+ <Builder> / declaration* <Builder> / import* <Builder> / comment*
4
- end
5
-
6
- rule comment
7
- ws '/*' (!'*/' . )* '*/' ws / ws '//' (!"\n" .)* "\n" ws
8
- end
9
-
10
- #
11
- # div, .class, body > p {...}
12
- #
13
- rule ruleset
14
- selectors "{" ws primary ws "}" ws {
15
- def build env
16
- # Build the ruleset for each selector
17
- selectors.build(env, :ruleset).each do |sel|
18
- primary.build sel
19
- end
20
- end
21
- } / ws selectors ';' ws {
22
- def build env
23
- selectors.build(env, :mixin).each do |path|
24
- rules = path.inject(env.root) do |current, node|
25
- current.descend(node.selector, node) or raise MixinNameError, path.join
26
- end.rules
27
- env.rules += rules
28
- end
29
- end
30
- }
31
- end
32
-
33
- rule import
34
- "@import" S url:(string / url) medias? s ';' ws {
35
- def build env
36
- path = File.join(env.root.file, url.value)
37
- path += '.less' unless path =~ /\.(le|c)ss$/
38
- if File.exist? path
39
- imported = Less::Engine.new(File.new(path)).to_tree
40
- env.rules += imported.rules
41
- else
42
- raise ImportError, path
43
- end
44
- end
45
- }
46
- end
47
-
48
- rule url
49
- 'url(' path:(string / [-a-zA-Z0-9_%$/.&=:;#+?]+) ')' {
50
- def build env = nil
51
- Node::String.new CGI.unescape(path.text_value)
52
- end
53
-
54
- def value
55
- build
56
- end
57
- }
58
- end
59
-
60
- rule medias
61
- [-a-z]+ (s ',' s [a-z]+)*
62
- end
63
-
64
- rule selectors
65
- ws selector tail:(s ',' ws selector)* ws {
66
- def build env, method
67
- all.map do |e|
68
- e.send(method, env) if e.respond_to? method
69
- end.compact
70
- end
71
-
72
- def all
73
- [selector] + tail.elements.map {|e| e.selector }
74
- end
75
- }
76
- end
77
-
78
- #
79
- # div > p a {...}
80
- #
81
- rule selector
82
- sel:(s select element s)+ arguments? {
83
- def ruleset env
84
- sel.elements.inject(env) do |node, e|
85
- node << Node::Element.new(e.element.text_value, e.select.text_value)
86
- node.last
87
- end
88
- end
89
-
90
- def mixin env
91
- sel.elements.map do |e|
92
- Node::Element.new(e.element.text_value, e.select.text_value)
93
- end
94
- end
95
- }
96
- end
97
-
98
- #
99
- # @my-var: 12px;
100
- # height: 100%;
101
- #
102
- rule declaration
103
- ws name:(ident / variable) s ':' s expressions s (';'/ ws &'}') ws {
104
- def build env
105
- env << (name.text_value =~ /^@/ ?
106
- Node::Variable : Node::Property).new(name.text_value, expressions.build(env), env)
107
-
108
- end
109
- # Empty rule
110
- } / ws ident s ':' s ';' ws
111
- end
112
-
113
- rule expressions
114
- expression+ {
115
- def build env
116
- elements.map do |e|
117
- e.build(env) if e.respond_to? :build
118
- end.compact
119
- end
120
- }
121
- end
122
-
123
- #
124
- # An operation or compound value
125
- #
126
- rule expression
127
- s '(' s expressions s ')' s {
128
- def build env
129
- Node::Expression.new(['('] + expressions.build(env).flatten + [')'])
130
- end
131
- } / entity tail:(operator entity)* ws {
132
- def build env
133
- exp = all.map do |e|
134
- e.method(:build).arity.zero??
135
- e.build : e.build(env) if e.respond_to? :build
136
- end.dissolve
137
- exp.is_a?(Array) ? Node::Expression.new(exp) : exp
138
- end
139
-
140
- def all
141
- [entity] + tail.elements.map {|i| [i.operator, i.entity] }.flatten.compact
142
- end
143
- }
144
- end
145
-
146
- #
147
- # Entity: Any whitespace delimited token
148
- #
149
- rule entity
150
- function / fonts / keyword / accessor / variable / literal / important
151
- end
152
-
153
- rule fonts
154
- font family:(s ',' s font)+ {
155
- def build
156
- Node::FontFamily.new(all.map(&:build))
157
- end
158
-
159
- def all
160
- [font] + family.elements.map {|f| f.font }
161
- end
162
- }
163
- end
164
-
165
- rule font
166
- [a-zA-Z] [-a-zA-Z0-9]* {
167
- def build
168
- Node::Keyword.new(text_value)
169
- end
170
- } / string {
171
- def build
172
- Node::String.new(text_value)
173
- end
174
- }
175
- end
176
-
177
- #
178
- # An identifier
179
- #
180
- rule ident
181
- '*'? '-'? [-a-z0-9_]+
182
- end
183
-
184
- rule variable
185
- '@' [-a-zA-Z0-9_]+ {
186
- def build
187
- Node::Variable.new(text_value)
188
- end
189
- }
190
- end
191
-
192
- #
193
- # div / .class / #id / input[type="text"] / lang(fr)
194
- #
195
- rule element
196
- (class_id / tag / ident) attribute* ('(' ident? attribute* ')')? / attribute+ / '@media' / '@font-face'
197
- end
198
-
199
- rule class_id
200
- tag? (class / id)+
201
- end
202
-
203
- #
204
- # [type="text"]
205
- #
206
- rule attribute
207
- '[' tag ([|~*$^]? '=') (tag / string) ']' / '[' (tag / string) ']'
208
- end
209
-
210
- rule class
211
- '.' [_a-z] [-a-zA-Z0-9_]*
212
- end
213
-
214
- rule id
215
- '#' [_a-z] [-a-zA-Z0-9_]*
216
- end
217
-
218
- rule tag
219
- [a-zA-Z] [-a-zA-Z]* [0-9]? / '*'
220
- end
221
-
222
- rule select
223
- (s [+>~] s / s ':' / S)?
224
- end
225
-
226
- # TODO: Merge this with attribute rule
227
- rule accessor
228
- ident:(class_id / tag) '[' attr:(string / variable) ']' {
229
- def build env
230
- env.nearest(ident.text_value)[attr.text_value.delete(%q["'])].evaluate
231
- end
232
- }
233
- end
234
-
235
- rule operator
236
- S [-+*/] S {
237
- def build
238
- Node::Operator.new(text_value.strip)
239
- end
240
- } / [-+*/] {
241
- def build
242
- Node::Operator.new(text_value)
243
- end
244
- }
245
- end
246
-
247
- #
248
- # Tokens which don't need to be evaluated
249
- #
250
- rule literal
251
- color / (dimension / [-a-z]+) '/' dimension {
252
- def build
253
- Node::Anonymous.new(text_value)
254
- end
255
- } / number unit {
256
- def build
257
- Node::Number.new(number.text_value, unit.text_value)
258
- end
259
- } / string {
260
- def build
261
- Node::String.new(text_value)
262
- end
263
- }
264
- end
265
-
266
- # !important
267
- rule important
268
- '!important' {
269
- def build
270
- Node::Keyword.new(text_value)
271
- end
272
- }
273
- end
274
-
275
- #
276
- # `blue`, `small`, `normal` etc.
277
- #
278
- rule keyword
279
- [-a-zA-Z]+ !ns {
280
- def build
281
- Node::Keyword.new(text_value)
282
- end
283
- }
284
- end
285
-
286
- #
287
- # 'hello world' / "hello world"
288
- #
289
- rule string
290
- "'" content:(!"'" . )* "'" {
291
- def value
292
- content.text_value
293
- end
294
- } / ["] content:(!["] . )* ["] {
295
- def value
296
- content.text_value
297
- end
298
- }
299
- end
300
-
301
- #
302
- # Numbers & Units
303
- #
304
- rule dimension
305
- number unit
306
- end
307
-
308
- rule number
309
- '-'? [0-9]* '.' [0-9]+ / '-'? [0-9]+
310
- end
311
-
312
- rule unit
313
- ('px'/'em'/'pc'/'%'/'pt'/'cm'/'mm')?
314
- end
315
-
316
- #
317
- # Color
318
- #
319
- rule color
320
- '#' rgb {
321
- def build
322
- Node::Color.new(*rgb.build)
323
- end
324
- } / fn:(('hsl'/'rgb') 'a'?) arguments {
325
- def build
326
- Node::Function.new(fn.text_value, arguments.build.flatten)
327
- end
328
- }
329
- end
330
-
331
- #
332
- # 00ffdd / 0fd
333
- #
334
- rule rgb
335
- r:(hex hex) g:(hex hex) b:(hex hex) {
336
- def build
337
- [r.text_value, g.text_value, b.text_value]
338
- end
339
- } / r:hex g:hex b:hex {
340
- def build
341
- [r.text_value, g.text_value, b.text_value].map {|c| c * 2 }
342
- end
343
- }
344
- end
345
-
346
- rule hex
347
- [a-fA-F0-9]
348
- end
349
-
350
- #
351
- # Functions and arguments
352
- #
353
- rule function
354
- name:([-a-zA-Z_]+) arguments {
355
- def build
356
- Node::Function.new(name.text_value, [arguments.build].flatten)
357
- end
358
- }
359
- end
360
-
361
- rule arguments
362
- '(' s argument s tail:(',' s argument s)* ')' {
363
- def build
364
- all.map do |e|
365
- e.build if e.respond_to? :build
366
- end.compact
367
- end
368
-
369
- def all
370
- [argument] + tail.elements.map {|e| e.argument }
371
- end
372
- }
373
- end
374
-
375
- rule argument
376
- color {
377
- def build
378
- Node::Color.new text_value
379
- end
380
- } / number unit {
381
- def build
382
- Node::Number.new number.text_value, unit.text_value
383
- end
384
- } / string {
385
- def build
386
- Node::String.new text_value
387
- end
388
- } / [a-zA-Z]+ '=' dimension {
389
- def build
390
- Node::Anonymous.new text_value
391
- end
392
- } / [-a-zA-Z0-9_%$/.&=:;#+?]+ {
393
- def build
394
- Node::String.new text_value
395
- end
396
- }
397
- end
398
-
399
- #
400
- # Whitespace
401
- #
402
- rule s
403
- [ ]*
404
- end
405
-
406
- rule S
407
- [ ]+
408
- end
409
-
410
- rule ws
411
- [\n ]*
412
- end
413
-
414
- rule WS
415
- [\n ]+
416
- end
417
-
418
- # Non-space char
419
- rule ns
420
- ![ ;\n] .
421
- end
422
- end