cloudhead-less 1.1.13 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/less.gemspec +4 -2
- data/lib/ext.rb +1 -12
- data/lib/less/command.rb +2 -1
- data/lib/less/engine/grammar/common.tt +1 -1
- data/lib/less/engine/grammar/entity.tt +4 -4
- data/lib/less/engine/grammar/less.tt +100 -65
- data/lib/less/engine/nodes/element.rb +48 -7
- data/lib/less/engine/nodes/entity.rb +3 -3
- data/lib/less/engine/nodes/function.rb +9 -4
- data/lib/less/engine/nodes/literal.rb +8 -4
- data/lib/less/engine/nodes/property.rb +63 -11
- data/lib/less/engine/nodes/selector.rb +1 -1
- data/spec/css/css-3.css +9 -0
- data/spec/css/mixins-args.css +17 -0
- data/spec/engine_spec.rb +4 -3
- data/spec/less/css-3.less +12 -0
- data/spec/less/hidden.less +25 -0
- data/spec/less/literal-css.less +11 -0
- data/spec/less/mixins-args.less +30 -0
- metadata +5 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.0
|
data/less.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{less}
|
5
|
-
s.version = "1.
|
5
|
+
s.version = "1.2.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["cloudhead"]
|
9
|
-
s.date = %q{2009-08-
|
9
|
+
s.date = %q{2009-08-31}
|
10
10
|
s.default_executable = %q{lessc}
|
11
11
|
s.description = %q{LESS is leaner CSS}
|
12
12
|
s.email = %q{self@cloudhead.net}
|
@@ -160,12 +160,14 @@ Gem::Specification.new do |s|
|
|
160
160
|
"spec/less/exceptions/name-error-1.0.less",
|
161
161
|
"spec/less/exceptions/syntax-error-1.0.less",
|
162
162
|
"spec/less/functions.less",
|
163
|
+
"spec/less/hidden.less",
|
163
164
|
"spec/less/import.less",
|
164
165
|
"spec/less/import/import-test-a.less",
|
165
166
|
"spec/less/import/import-test-b.less",
|
166
167
|
"spec/less/import/import-test-c.less",
|
167
168
|
"spec/less/import/import-test-d.css",
|
168
169
|
"spec/less/lazy-eval.less",
|
170
|
+
"spec/less/literal-css.less",
|
169
171
|
"spec/less/mixins-args.less",
|
170
172
|
"spec/less/mixins.less",
|
171
173
|
"spec/less/operations.less",
|
data/lib/ext.rb
CHANGED
@@ -27,11 +27,6 @@ class Object
|
|
27
27
|
yield self
|
28
28
|
self
|
29
29
|
end
|
30
|
-
|
31
|
-
def log(s = '') puts "* #{s}" if $verbose end
|
32
|
-
def log!(s = '') puts "* #{s}" end
|
33
|
-
def error(s) $stderr.puts s end
|
34
|
-
def error!(s) raise Exception, s end
|
35
30
|
end
|
36
31
|
|
37
32
|
class Array
|
@@ -49,16 +44,10 @@ class Array
|
|
49
44
|
end
|
50
45
|
end
|
51
46
|
|
52
|
-
class Class
|
53
|
-
def to_sym
|
54
|
-
self.to_s.to_sym
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
47
|
unless :symbol.respond_to?(:to_proc)
|
59
48
|
class Symbol
|
60
49
|
def to_proc
|
61
|
-
|
50
|
+
Proc.new {|*args| args.shift.__send__(self, *args) }
|
62
51
|
end
|
63
52
|
end
|
64
53
|
end
|
data/lib/less/command.rb
CHANGED
@@ -93,7 +93,7 @@ module Less
|
|
93
93
|
|
94
94
|
def err s = '', type = ''
|
95
95
|
type = type.strip + ' ' unless type.empty?
|
96
|
-
print "#{RED["! #{type}Error"]}: #{s}"
|
96
|
+
$stderr.print "#{RED["! #{type}Error"]}: #{s}"
|
97
97
|
if @options[:growl]
|
98
98
|
growl = Growl.new
|
99
99
|
growl.title = "LESS"
|
@@ -101,6 +101,7 @@ module Less
|
|
101
101
|
growl.run
|
102
102
|
false
|
103
103
|
end
|
104
|
+
return 1
|
104
105
|
end
|
105
106
|
end
|
106
107
|
end
|
@@ -5,7 +5,7 @@ module Less
|
|
5
5
|
# Entity: Any whitespace delimited token
|
6
6
|
#
|
7
7
|
rule entity
|
8
|
-
function /
|
8
|
+
url / function / accessor / keyword / variable / literal / font
|
9
9
|
end
|
10
10
|
|
11
11
|
rule fonts
|
@@ -21,13 +21,13 @@ module Less
|
|
21
21
|
end
|
22
22
|
|
23
23
|
rule font
|
24
|
-
[a-zA-Z] [-a-zA-Z0-9]* {
|
24
|
+
[a-zA-Z] [-a-zA-Z0-9]* !ns {
|
25
25
|
def build
|
26
26
|
Node::Keyword.new(text_value)
|
27
27
|
end
|
28
28
|
} / string {
|
29
29
|
def build
|
30
|
-
Node::
|
30
|
+
Node::Quoted.new(text_value)
|
31
31
|
end
|
32
32
|
}
|
33
33
|
end
|
@@ -46,7 +46,7 @@ module Less
|
|
46
46
|
end
|
47
47
|
} / string {
|
48
48
|
def build
|
49
|
-
Node::
|
49
|
+
Node::Quoted.new(text_value)
|
50
50
|
end
|
51
51
|
}
|
52
52
|
end
|
@@ -4,7 +4,7 @@ module Less
|
|
4
4
|
include Entity
|
5
5
|
|
6
6
|
rule primary
|
7
|
-
(declaration /
|
7
|
+
(import / declaration / mixin / ruleset / comment)* {
|
8
8
|
def build env = Less::Element.new
|
9
9
|
elements.map do |e|
|
10
10
|
e.build env if e.respond_to? :build
|
@@ -21,56 +21,47 @@ module Less
|
|
21
21
|
# div, .class, body > p {...}
|
22
22
|
#
|
23
23
|
rule ruleset
|
24
|
-
selectors "{" ws primary ws "}" ws {
|
24
|
+
selectors "{" ws primary ws "}" s hide:(';'?) ws {
|
25
25
|
def build env
|
26
26
|
# Build the ruleset for each selector
|
27
27
|
selectors.build(env, :ruleset).each do |sel|
|
28
|
+
sel.hide unless hide.empty?
|
28
29
|
primary.build sel
|
29
30
|
end
|
30
31
|
end
|
31
|
-
|
32
|
+
# Mixin Declaration
|
33
|
+
} / '@' name:[-a-zA-Z0-9_]+ s parameters ws "{" ws primary ws "}" ws {
|
34
|
+
def build env
|
35
|
+
env << Node::Mixin.new(name.text_value, parameters.build(env))
|
36
|
+
primary.build env.last
|
37
|
+
#env.last
|
38
|
+
end
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
rule mixin
|
43
|
+
ws selectors ';' ws {
|
32
44
|
def build env
|
33
45
|
selectors.build(env, :mixin).each do |path|
|
34
46
|
rules = path.inject(env.root) do |current, node|
|
35
47
|
current.descend(node.selector, node) or raise MixinNameError, path.join
|
36
48
|
end.rules
|
37
49
|
env.rules += rules
|
50
|
+
#env.mix(rules)
|
38
51
|
end
|
39
52
|
end
|
40
|
-
}
|
41
|
-
end
|
42
|
-
|
43
|
-
rule import
|
44
|
-
ws "@import" S url:(string / url) medias? s ';' ws {
|
53
|
+
} / name:('@' [-a-zA-Z0-9_]+) args:(arguments?) s ';' {
|
45
54
|
def build env
|
46
|
-
|
47
|
-
|
48
|
-
if File.exist? path
|
49
|
-
imported = Less::Engine.new(File.new(path)).to_tree
|
50
|
-
env.rules += imported.rules
|
51
|
-
else
|
52
|
-
raise ImportError, path
|
53
|
-
end
|
54
|
-
end
|
55
|
-
}
|
56
|
-
end
|
55
|
+
mix = env.nearest(name.text_value, :mixin) or raise MixinNameError, name.text_value
|
56
|
+
params = args.build.map {|i| Node::Expression.new i } unless args.empty?
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
Node::String.new CGI.unescape(path.text_value)
|
62
|
-
end
|
63
|
-
|
64
|
-
def value
|
65
|
-
build
|
58
|
+
env.mix ((params.nil? || params.empty?) ?
|
59
|
+
mix.rules + mix.params :
|
60
|
+
mix.pass(params, env))
|
66
61
|
end
|
67
62
|
}
|
68
63
|
end
|
69
|
-
|
70
|
-
rule medias
|
71
|
-
[-a-z]+ (s ',' s [a-z]+)*
|
72
|
-
end
|
73
|
-
|
64
|
+
|
74
65
|
rule selectors
|
75
66
|
ws selector tail:(s ',' ws selector)* ws {
|
76
67
|
def build env, method
|
@@ -89,7 +80,7 @@ module Less
|
|
89
80
|
# div > p a {...}
|
90
81
|
#
|
91
82
|
rule selector
|
92
|
-
sel:(s select element s)+
|
83
|
+
sel:(s select element s)+ '' {
|
93
84
|
def ruleset env
|
94
85
|
sel.elements.inject(env) do |node, e|
|
95
86
|
node << Node::Element.new(e.element.text_value, e.select.text_value)
|
@@ -104,16 +95,78 @@ module Less
|
|
104
95
|
end
|
105
96
|
}
|
106
97
|
end
|
98
|
+
|
99
|
+
rule parameters
|
100
|
+
'(' s ')' {
|
101
|
+
def build env
|
102
|
+
[]
|
103
|
+
end
|
104
|
+
} / '(' parameter tail:(s ',' s parameter)* ')' {
|
105
|
+
def build env
|
106
|
+
all.map do |e|
|
107
|
+
e.build(env)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def all
|
112
|
+
[parameter] + tail.elements.map {|e| e.parameter }
|
113
|
+
end
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
rule parameter
|
118
|
+
variable s ':' s expressions {
|
119
|
+
def build env
|
120
|
+
Node::Variable.new(variable.text_value, expressions.build(env), env)
|
121
|
+
end
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
rule import
|
126
|
+
ws "@import" S url:(string / url) medias? s ';' ws {
|
127
|
+
def build env
|
128
|
+
path = File.join(env.root.file || Dir.pwd, url.value)
|
129
|
+
path += '.less' unless path =~ /\.(le|c)ss$/
|
130
|
+
if File.exist? path
|
131
|
+
imported = Less::Engine.new(File.new(path)).to_tree
|
132
|
+
env.rules += imported.rules
|
133
|
+
else
|
134
|
+
raise ImportError, path
|
135
|
+
end
|
136
|
+
end
|
137
|
+
}
|
138
|
+
end
|
139
|
+
|
140
|
+
rule url
|
141
|
+
'url(' path:(string / [-a-zA-Z0-9_%$/.&=:;#+?]+) ')' {
|
142
|
+
def build env = nil
|
143
|
+
Node::Function.new('url', value)
|
144
|
+
end
|
145
|
+
|
146
|
+
def value
|
147
|
+
Node::Quoted.new CGI.unescape(path.text_value)
|
148
|
+
end
|
149
|
+
}
|
150
|
+
end
|
151
|
+
|
152
|
+
rule medias
|
153
|
+
[-a-z]+ (s ',' s [a-z]+)*
|
154
|
+
end
|
107
155
|
|
108
156
|
#
|
109
157
|
# @my-var: 12px;
|
110
158
|
# height: 100%;
|
111
159
|
#
|
112
160
|
rule declaration
|
113
|
-
ws name:(ident / variable) s ':' s expressions s (';'/ ws &'}') ws {
|
161
|
+
ws name:(ident / variable) s ':' s expressions tail:(ws ',' ws expressions)* s (';'/ ws &'}') ws {
|
114
162
|
def build env
|
163
|
+
result = all.map {|e| e.build(env) if e.respond_to? :build }.compact
|
115
164
|
env << (name.text_value =~ /^@/ ?
|
116
|
-
Node::Variable : Node::Property).new(name.text_value,
|
165
|
+
Node::Variable : Node::Property).new(name.text_value, result, env)
|
166
|
+
end
|
167
|
+
|
168
|
+
def all
|
169
|
+
[expressions] + tail.elements.map {|f| f.expressions }
|
117
170
|
end
|
118
171
|
# Empty rule
|
119
172
|
} / ws ident s ':' s ';' ws
|
@@ -125,7 +178,7 @@ module Less
|
|
125
178
|
rule expressions
|
126
179
|
# Operation
|
127
180
|
expression tail:(operator expression)+ {
|
128
|
-
def build env
|
181
|
+
def build env = nil
|
129
182
|
all.map {|e| e.build(env) }.dissolve
|
130
183
|
end
|
131
184
|
|
@@ -134,7 +187,7 @@ module Less
|
|
134
187
|
end
|
135
188
|
# Space-delimited expressions
|
136
189
|
} / expression tail:(WS expression)* i:important? {
|
137
|
-
def build env
|
190
|
+
def build env = nil
|
138
191
|
all.map {|e| e.build(env) if e.respond_to? :build }.compact
|
139
192
|
end
|
140
193
|
|
@@ -151,12 +204,13 @@ module Less
|
|
151
204
|
|
152
205
|
rule expression
|
153
206
|
'(' s expressions s ')' {
|
154
|
-
def build env
|
207
|
+
def build env = nil
|
155
208
|
Node::Expression.new(['('] + expressions.build(env).flatten + [')'])
|
156
209
|
end
|
157
210
|
} / entity '' {
|
158
|
-
def build env
|
159
|
-
entity.method(:build).arity.zero?? entity.build : entity.build(env)
|
211
|
+
def build env = nil
|
212
|
+
e = entity.method(:build).arity.zero?? entity.build : entity.build(env)
|
213
|
+
e.respond_to?(:dissolve) ? e.dissolve : e
|
160
214
|
end
|
161
215
|
}
|
162
216
|
end
|
@@ -164,7 +218,7 @@ module Less
|
|
164
218
|
# !important
|
165
219
|
rule important
|
166
220
|
s '!' s 'important' {
|
167
|
-
def build env
|
221
|
+
def build env = nil
|
168
222
|
Node::Keyword.new(text_value.strip)
|
169
223
|
end
|
170
224
|
}
|
@@ -246,13 +300,13 @@ module Less
|
|
246
300
|
rule function
|
247
301
|
name:([-a-zA-Z_]+) arguments {
|
248
302
|
def build
|
249
|
-
Node::Function.new(name.text_value,
|
303
|
+
Node::Function.new(name.text_value, arguments.build)
|
250
304
|
end
|
251
305
|
}
|
252
306
|
end
|
253
307
|
|
254
308
|
rule arguments
|
255
|
-
'(' s
|
309
|
+
'(' s expressions s tail:(',' s expressions s)* ')' {
|
256
310
|
def build
|
257
311
|
all.map do |e|
|
258
312
|
e.build if e.respond_to? :build
|
@@ -260,30 +314,11 @@ module Less
|
|
260
314
|
end
|
261
315
|
|
262
316
|
def all
|
263
|
-
[
|
264
|
-
end
|
265
|
-
}
|
266
|
-
end
|
267
|
-
|
268
|
-
rule argument
|
269
|
-
color / number unit {
|
270
|
-
def build
|
271
|
-
Node::Number.new number.text_value, unit.text_value
|
272
|
-
end
|
273
|
-
} / string {
|
274
|
-
def build
|
275
|
-
Node::String.new text_value
|
276
|
-
end
|
277
|
-
} / [a-zA-Z]+ '=' dimension {
|
278
|
-
def build
|
279
|
-
Node::Anonymous.new text_value
|
280
|
-
end
|
281
|
-
} / [-a-zA-Z0-9_%$/.&=:;#+?]+ {
|
282
|
-
def build
|
283
|
-
Node::String.new text_value
|
317
|
+
[expressions] + tail.elements.map {|e| e.expressions }
|
284
318
|
end
|
285
|
-
} /
|
319
|
+
} / '(' s ')' {
|
286
320
|
def build
|
321
|
+
[]
|
287
322
|
end
|
288
323
|
}
|
289
324
|
end
|
@@ -76,7 +76,9 @@ module Less
|
|
76
76
|
def identifiers; @rules.select {|r| r.kind_of? Property } end
|
77
77
|
def properties; @rules.select {|r| r.instance_of? Property } end
|
78
78
|
def variables; @rules.select {|r| r.instance_of? Variable } end
|
79
|
-
def elements; @rules.select {|r| r.
|
79
|
+
def elements; @rules.select {|r| r.kind_of? Element } end
|
80
|
+
def mixins; @rules.select {|r| r.instance_of? Mixin } end
|
81
|
+
def parameters; [] end
|
80
82
|
|
81
83
|
# Select a child element
|
82
84
|
# TODO: Implement full selector syntax & merge with descend()
|
@@ -84,7 +86,7 @@ module Less
|
|
84
86
|
case key
|
85
87
|
when Entity
|
86
88
|
@rules.find {|i| i.eql? key }
|
87
|
-
when
|
89
|
+
when String
|
88
90
|
@rules.find {|i| i.to_s == key }
|
89
91
|
else raise ArgumentError
|
90
92
|
end
|
@@ -117,7 +119,13 @@ module Less
|
|
117
119
|
self[element.name] if self[element.name].selector.class == selector.class
|
118
120
|
end
|
119
121
|
end
|
120
|
-
|
122
|
+
|
123
|
+
def mix arr = []
|
124
|
+
@rules += arr.map do |r|
|
125
|
+
r.copy.tap {|i| i.parent = self }
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
121
129
|
#
|
122
130
|
# Add an arbitrary node to this element
|
123
131
|
#
|
@@ -158,10 +166,10 @@ module Less
|
|
158
166
|
end
|
159
167
|
|
160
168
|
#
|
161
|
-
# Find the nearest
|
169
|
+
# Find the nearest node in the hierarchy or raise a NameError
|
162
170
|
#
|
163
|
-
def nearest ident
|
164
|
-
ary = ident =~ /^[.#]/ ? :elements : :variables
|
171
|
+
def nearest ident, type = nil
|
172
|
+
ary = type || ident =~ /^[.#]/ ? :elements : :variables
|
165
173
|
path.map do |node|
|
166
174
|
node.send(ary).find {|i| i.to_s == ident }
|
167
175
|
end.compact.first.tap do |result|
|
@@ -188,11 +196,44 @@ module Less
|
|
188
196
|
|
189
197
|
(root?? "\n" : "") + [
|
190
198
|
indent[ depth ] + self.to_s,
|
191
|
-
put[ properties ],
|
192
199
|
put[ variables ],
|
200
|
+
put[ properties ],
|
193
201
|
elements.map {|i| i.inspect( depth + 1 ) } * "\n"
|
194
202
|
].reject(&:empty?).join("\n") + "\n" + indent[ depth ]
|
195
203
|
end
|
196
204
|
end
|
205
|
+
|
206
|
+
class Mixin < Element
|
207
|
+
attr_accessor :params
|
208
|
+
|
209
|
+
def initialize name, params = []
|
210
|
+
super name
|
211
|
+
@params = params.each do |param|
|
212
|
+
param.parent = self
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def variables
|
217
|
+
@params + super
|
218
|
+
end
|
219
|
+
|
220
|
+
def pass args, parent
|
221
|
+
params.zip(args).map do |a, b|
|
222
|
+
b ? Node::Variable.new(a.to_s, Expression.new([b])) : a
|
223
|
+
end + identifiers + elements
|
224
|
+
end
|
225
|
+
|
226
|
+
def parameters
|
227
|
+
@params
|
228
|
+
end
|
229
|
+
|
230
|
+
def to_s
|
231
|
+
'@' + name
|
232
|
+
end
|
233
|
+
|
234
|
+
def to_css *args
|
235
|
+
""
|
236
|
+
end
|
237
|
+
end
|
197
238
|
end
|
198
239
|
end
|
@@ -57,20 +57,20 @@ module Less
|
|
57
57
|
# An anonymous node, for all the 'other' stuff
|
58
58
|
# which doesn't need any specific functionality.
|
59
59
|
#
|
60
|
-
class Anonymous <
|
60
|
+
class Anonymous < String
|
61
61
|
include Entity
|
62
62
|
end
|
63
63
|
|
64
64
|
#
|
65
65
|
# + * - /
|
66
66
|
#
|
67
|
-
class Operator <
|
67
|
+
class Operator < String
|
68
68
|
def to_ruby
|
69
69
|
self
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
class Paren <
|
73
|
+
class Paren < String
|
74
74
|
def to_ruby
|
75
75
|
self
|
76
76
|
end
|
@@ -48,12 +48,17 @@ module Less
|
|
48
48
|
#
|
49
49
|
# it calls functions from the Functions module
|
50
50
|
#
|
51
|
-
class Function <
|
51
|
+
class Function < String
|
52
52
|
include Entity
|
53
53
|
include Functions
|
54
54
|
|
55
|
-
def initialize name,
|
56
|
-
@args = args.
|
55
|
+
def initialize name, args
|
56
|
+
@args = if args.is_a? Array
|
57
|
+
Value.new(args, self)
|
58
|
+
else
|
59
|
+
[args]
|
60
|
+
end
|
61
|
+
|
57
62
|
super name
|
58
63
|
end
|
59
64
|
|
@@ -67,7 +72,7 @@ module Less
|
|
67
72
|
# If the function isn't found, we just print it out,
|
68
73
|
# this is the case for url(), for example,
|
69
74
|
#
|
70
|
-
def evaluate
|
75
|
+
def evaluate context = nil
|
71
76
|
if Functions.available.include? self.to_sym
|
72
77
|
send to_sym, *@args
|
73
78
|
else
|
@@ -17,7 +17,7 @@ module Less
|
|
17
17
|
|
18
18
|
def initialize r, g, b, a = 1.0
|
19
19
|
@r, @g, @b = [r, g, b].map do |c|
|
20
|
-
normalize(c.is_a?(
|
20
|
+
normalize(c.is_a?(String) ? c.to_i(16) : c)
|
21
21
|
end
|
22
22
|
@a = normalize(a, 1.0)
|
23
23
|
end
|
@@ -94,7 +94,11 @@ module Less
|
|
94
94
|
def to_s
|
95
95
|
"#{super}#@unit"
|
96
96
|
end
|
97
|
-
|
97
|
+
|
98
|
+
def dup
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
98
102
|
def to_ruby
|
99
103
|
self.to_f
|
100
104
|
end
|
@@ -111,7 +115,7 @@ module Less
|
|
111
115
|
#
|
112
116
|
# "hello world"
|
113
117
|
#
|
114
|
-
class
|
118
|
+
class Quoted < String
|
115
119
|
include Literal
|
116
120
|
|
117
121
|
attr_reader :quotes, :content
|
@@ -152,7 +156,7 @@ module Less
|
|
152
156
|
#
|
153
157
|
# ex: red, small, border-collapse
|
154
158
|
#
|
155
|
-
class Keyword <
|
159
|
+
class Keyword < String
|
156
160
|
include Entity
|
157
161
|
|
158
162
|
def to_css
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Less
|
2
2
|
module Node
|
3
|
-
class Property <
|
3
|
+
class Property < String
|
4
4
|
include Entity
|
5
5
|
|
6
6
|
attr_accessor :value
|
@@ -15,11 +15,20 @@ module Less
|
|
15
15
|
else
|
16
16
|
value
|
17
17
|
end
|
18
|
-
|
19
|
-
@value =
|
18
|
+
|
19
|
+
@value = value.is_a?(Value) ? value : Value.new(value, self)
|
20
20
|
@eval = false # Store the first evaluation in here
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
|
+
def parent= obj
|
24
|
+
@parent = obj
|
25
|
+
value.parent = self
|
26
|
+
end
|
27
|
+
|
28
|
+
def copy
|
29
|
+
clone.tap {|c| c.value = value.copy }
|
30
|
+
end
|
31
|
+
|
23
32
|
def << token
|
24
33
|
token = Node::Anonymous.new(*token) unless token.is_a? Entity or token.respond_to? :to_ruby
|
25
34
|
token.parent = self if token.respond_to? :parent
|
@@ -50,12 +59,12 @@ module Less
|
|
50
59
|
end
|
51
60
|
|
52
61
|
# TODO: @eval and @value should be merged
|
53
|
-
def evaluate
|
54
|
-
@eval ||= value.evaluate
|
62
|
+
def evaluate
|
63
|
+
@eval ||= value.is_a?(Value) ? value.map {|e| e.evaluate } : [value.evaluate]
|
55
64
|
end
|
56
65
|
|
57
66
|
def to_css
|
58
|
-
"#{self}: #{evaluate.to_css};"
|
67
|
+
"#{self}: #{evaluate.map {|i| i.to_css }.join(", ")};"
|
59
68
|
end
|
60
69
|
end
|
61
70
|
|
@@ -88,7 +97,42 @@ module Less
|
|
88
97
|
end
|
89
98
|
|
90
99
|
def to_css
|
91
|
-
evaluate
|
100
|
+
evaluate
|
101
|
+
if @eval.respond_to? :to_css
|
102
|
+
@eval.to_css
|
103
|
+
else
|
104
|
+
@eval.map {|i| i.to_css }.join ', '
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
class Value < Array
|
110
|
+
attr_reader :parent
|
111
|
+
|
112
|
+
def initialize ary, parent = nil
|
113
|
+
@parent = parent
|
114
|
+
if ary.size == 1 && !ary.first.is_a?(Array)
|
115
|
+
super [Expression.new([ary.first])]
|
116
|
+
else
|
117
|
+
super ary.map {|e| e.is_a?(Expression) ? e : Expression.new(e, self) }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def parent= obj
|
122
|
+
@parent = obj
|
123
|
+
each {|e| e.parent = obj if e.respond_to? :parent }
|
124
|
+
end
|
125
|
+
|
126
|
+
def evaluate
|
127
|
+
map {|e| e.evaluate }.dissolve
|
128
|
+
end
|
129
|
+
|
130
|
+
def copy
|
131
|
+
first.copy
|
132
|
+
end
|
133
|
+
|
134
|
+
def to_css
|
135
|
+
map {|e| e.to_css } * ', '
|
92
136
|
end
|
93
137
|
end
|
94
138
|
|
@@ -97,7 +141,7 @@ module Less
|
|
97
141
|
|
98
142
|
def initialize ary, parent = nil
|
99
143
|
self.parent = parent
|
100
|
-
super ary
|
144
|
+
super ary.dup
|
101
145
|
end
|
102
146
|
|
103
147
|
def expressions; select {|i| i.kind_of? Expression } end
|
@@ -114,10 +158,18 @@ module Less
|
|
114
158
|
'[' + map {|i| i.inspect }.join(', ') + ']'
|
115
159
|
end
|
116
160
|
|
161
|
+
def flatten
|
162
|
+
self
|
163
|
+
end
|
164
|
+
|
117
165
|
def terminal?
|
118
166
|
expressions.empty?
|
119
167
|
end
|
120
|
-
|
168
|
+
|
169
|
+
def copy
|
170
|
+
self.class.new(map {|i| i.dup }, parent)
|
171
|
+
end
|
172
|
+
|
121
173
|
def to_css
|
122
174
|
map do |i|
|
123
175
|
i.respond_to?(:to_css) ? i.to_css : i.to_s
|
@@ -145,7 +197,7 @@ module Less
|
|
145
197
|
raise MixedUnitsError, self * ' ' if ary.size > 1 && !operators.empty?
|
146
198
|
end.join
|
147
199
|
|
148
|
-
entity = literals.find {|e| e.unit == unit } || entities.first
|
200
|
+
entity = literals.find {|e| e.unit == unit } || literals.first || entities.first
|
149
201
|
result = operators.empty?? self : eval(to_ruby.join)
|
150
202
|
|
151
203
|
case result
|
data/spec/css/css-3.css
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
.comma-delimited {
|
2
|
+
background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
|
3
|
+
text-shadow: -1px -1px 1px red, 6px 5px 5px yellow;
|
4
|
+
-moz-box-shadow: 0pt 0pt 2px rgba(255, 255, 255, 0.4) inset, 0pt 4px 6px rgba(255, 255, 255, 0.4) inset;
|
5
|
+
}
|
6
|
+
@font-face {
|
7
|
+
font-family: Headline;
|
8
|
+
src: local(Futura-Medium), url(fonts.svg#MyGeometricModern) format("svg");
|
9
|
+
}
|
1
10
|
p:not([class*="lead"]) { color: black; }
|
2
11
|
a[href^="http://"], a[href$="http://"] { color: black; }
|
3
12
|
p::before { color: black; }
|
data/spec/css/mixins-args.css
CHANGED
data/spec/engine_spec.rb
CHANGED
@@ -84,16 +84,17 @@ describe Less::Engine do
|
|
84
84
|
|
85
85
|
it "should handle custom functions" do
|
86
86
|
module Less::Functions
|
87
|
-
def color
|
87
|
+
def color args
|
88
|
+
arg = args.first
|
88
89
|
Less::Node::Color.new("99", "99", "99") if arg == "evil red"
|
89
90
|
end
|
90
91
|
|
91
92
|
def increment a
|
92
|
-
Less::Node::Number.new(a.to_i + 1)
|
93
|
+
Less::Node::Number.new(a.evaluate.to_i + 1)
|
93
94
|
end
|
94
95
|
|
95
96
|
def add a, b
|
96
|
-
Less::Node::Number.new(a + b)
|
97
|
+
Less::Node::Number.new(a.evaluate + b.evaluate)
|
97
98
|
end
|
98
99
|
end
|
99
100
|
lessify(:functions).should == css(:functions)
|
data/spec/less/css-3.less
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
.comma-delimited {
|
2
|
+
background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
|
3
|
+
text-shadow: -1px -1px 1px red, 6px 5px 5px yellow;
|
4
|
+
-moz-box-shadow: 0pt 0pt 2px rgba(255, 255, 255, 0.4) inset,
|
5
|
+
0pt 4px 6px rgba(255, 255, 255, 0.4) inset;
|
6
|
+
}
|
7
|
+
@font-face {
|
8
|
+
font-family: Headline;
|
9
|
+
src: local(Futura-Medium),
|
10
|
+
url(fonts.svg#MyGeometricModern) format("svg");
|
11
|
+
}
|
12
|
+
|
1
13
|
p:not([class*="lead"]) {
|
2
14
|
color: black;
|
3
15
|
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
.hidden {
|
2
|
+
color: transparent;
|
3
|
+
.inside {
|
4
|
+
width: 0%;
|
5
|
+
}
|
6
|
+
};
|
7
|
+
|
8
|
+
.fully-hidden {
|
9
|
+
color: none;
|
10
|
+
};
|
11
|
+
|
12
|
+
.visible {
|
13
|
+
width: 100%;
|
14
|
+
.hidden {
|
15
|
+
color: black;
|
16
|
+
};
|
17
|
+
}
|
18
|
+
|
19
|
+
.mix {
|
20
|
+
.hidden;
|
21
|
+
}
|
22
|
+
|
23
|
+
.mix2 {
|
24
|
+
.visible;
|
25
|
+
}
|
data/spec/less/mixins-args.less
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
@mixin (@a: 1px, @b: 50%) {
|
2
|
+
width: @a * 5;
|
3
|
+
height: @b - 1%;
|
4
|
+
}
|
5
|
+
|
6
|
+
@hidden() {
|
7
|
+
color: transparent;
|
8
|
+
}
|
9
|
+
|
10
|
+
.two-args {
|
11
|
+
color: blue;
|
12
|
+
@mixin(2px, 100%);
|
13
|
+
}
|
14
|
+
|
15
|
+
.one-arg {
|
16
|
+
@mixin(3px);
|
17
|
+
}
|
18
|
+
|
19
|
+
.no-parens {
|
20
|
+
@mixin;
|
21
|
+
}
|
22
|
+
|
23
|
+
.no-args {
|
24
|
+
@mixin();
|
25
|
+
}
|
26
|
+
|
27
|
+
.var-args {
|
28
|
+
@var: 9;
|
29
|
+
@mixin(@var, @var * 2);
|
30
|
+
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudhead-less
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
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-08-
|
12
|
+
date: 2009-08-31 00:00:00 -07:00
|
13
13
|
default_executable: lessc
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -167,12 +167,14 @@ files:
|
|
167
167
|
- spec/less/exceptions/name-error-1.0.less
|
168
168
|
- spec/less/exceptions/syntax-error-1.0.less
|
169
169
|
- spec/less/functions.less
|
170
|
+
- spec/less/hidden.less
|
170
171
|
- spec/less/import.less
|
171
172
|
- spec/less/import/import-test-a.less
|
172
173
|
- spec/less/import/import-test-b.less
|
173
174
|
- spec/less/import/import-test-c.less
|
174
175
|
- spec/less/import/import-test-d.css
|
175
176
|
- spec/less/lazy-eval.less
|
177
|
+
- spec/less/literal-css.less
|
176
178
|
- spec/less/mixins-args.less
|
177
179
|
- spec/less/mixins.less
|
178
180
|
- spec/less/operations.less
|
@@ -188,7 +190,6 @@ files:
|
|
188
190
|
- spec/spec_helper.rb
|
189
191
|
has_rdoc: false
|
190
192
|
homepage: http://www.lesscss.org
|
191
|
-
licenses:
|
192
193
|
post_install_message:
|
193
194
|
rdoc_options:
|
194
195
|
- --charset=UTF-8
|
@@ -209,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
209
210
|
requirements: []
|
210
211
|
|
211
212
|
rubyforge_project: less
|
212
|
-
rubygems_version: 1.
|
213
|
+
rubygems_version: 1.2.0
|
213
214
|
signing_key:
|
214
215
|
specification_version: 3
|
215
216
|
summary: LESS compiler
|