less 1.1.13 → 1.2.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/Rakefile +13 -41
  2. data/VERSION +1 -1
  3. data/bin/lessc +8 -2
  4. data/less.gemspec +13 -92
  5. data/lib/ext.rb +15 -19
  6. data/lib/less.rb +2 -2
  7. data/lib/less/command.rb +14 -15
  8. data/lib/less/engine.rb +3 -2
  9. data/lib/less/engine/grammar/common.tt +1 -1
  10. data/lib/less/engine/grammar/entity.tt +5 -5
  11. data/lib/less/engine/grammar/less.tt +107 -77
  12. data/lib/less/engine/nodes/element.rb +103 -24
  13. data/lib/less/engine/nodes/entity.rb +3 -3
  14. data/lib/less/engine/nodes/function.rb +11 -6
  15. data/lib/less/engine/nodes/literal.rb +8 -4
  16. data/lib/less/engine/nodes/property.rb +98 -38
  17. data/lib/less/engine/nodes/selector.rb +1 -1
  18. data/spec/css/css-3.css +14 -0
  19. data/spec/css/mixins-args.css +31 -0
  20. data/spec/css/variables.css +1 -0
  21. data/spec/css/whitespace.css +1 -0
  22. data/spec/engine_spec.rb +4 -3
  23. data/spec/less/css-3.less +30 -0
  24. data/spec/less/hidden.less +25 -0
  25. data/spec/less/import.less +1 -0
  26. data/spec/less/literal-css.less +11 -0
  27. data/spec/less/mixins-args.less +50 -0
  28. data/spec/less/variables.less +7 -1
  29. data/spec/less/whitespace.less +1 -0
  30. data/spec/spec_helper.rb +2 -2
  31. metadata +25 -94
  32. data/lib/vendor/treetop/.gitignore +0 -7
  33. data/lib/vendor/treetop/LICENSE +0 -19
  34. data/lib/vendor/treetop/README +0 -164
  35. data/lib/vendor/treetop/Rakefile +0 -19
  36. data/lib/vendor/treetop/benchmark/seqpar.gnuplot +0 -15
  37. data/lib/vendor/treetop/benchmark/seqpar.treetop +0 -16
  38. data/lib/vendor/treetop/benchmark/seqpar_benchmark.rb +0 -107
  39. data/lib/vendor/treetop/bin/tt +0 -28
  40. data/lib/vendor/treetop/lib/treetop.rb +0 -8
  41. data/lib/vendor/treetop/lib/treetop/bootstrap_gen_1_metagrammar.rb +0 -45
  42. data/lib/vendor/treetop/lib/treetop/compiler.rb +0 -6
  43. data/lib/vendor/treetop/lib/treetop/compiler/grammar_compiler.rb +0 -42
  44. data/lib/vendor/treetop/lib/treetop/compiler/lexical_address_space.rb +0 -17
  45. data/lib/vendor/treetop/lib/treetop/compiler/metagrammar.rb +0 -3097
  46. data/lib/vendor/treetop/lib/treetop/compiler/metagrammar.treetop +0 -408
  47. data/lib/vendor/treetop/lib/treetop/compiler/node_classes.rb +0 -19
  48. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/anything_symbol.rb +0 -18
  49. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/atomic_expression.rb +0 -14
  50. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/character_class.rb +0 -24
  51. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/choice.rb +0 -31
  52. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/declaration_sequence.rb +0 -24
  53. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/grammar.rb +0 -28
  54. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/inline_module.rb +0 -27
  55. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/nonterminal.rb +0 -13
  56. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/optional.rb +0 -19
  57. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/parenthesized_expression.rb +0 -9
  58. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/parsing_expression.rb +0 -138
  59. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/parsing_rule.rb +0 -55
  60. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/predicate.rb +0 -45
  61. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/repetition.rb +0 -55
  62. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/sequence.rb +0 -68
  63. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/terminal.rb +0 -20
  64. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/transient_prefix.rb +0 -9
  65. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/treetop_file.rb +0 -9
  66. data/lib/vendor/treetop/lib/treetop/compiler/ruby_builder.rb +0 -113
  67. data/lib/vendor/treetop/lib/treetop/ruby_extensions.rb +0 -2
  68. data/lib/vendor/treetop/lib/treetop/ruby_extensions/string.rb +0 -42
  69. data/lib/vendor/treetop/lib/treetop/runtime.rb +0 -5
  70. data/lib/vendor/treetop/lib/treetop/runtime/compiled_parser.rb +0 -105
  71. data/lib/vendor/treetop/lib/treetop/runtime/interval_skip_list.rb +0 -4
  72. data/lib/vendor/treetop/lib/treetop/runtime/interval_skip_list/head_node.rb +0 -15
  73. data/lib/vendor/treetop/lib/treetop/runtime/interval_skip_list/interval_skip_list.rb +0 -200
  74. data/lib/vendor/treetop/lib/treetop/runtime/interval_skip_list/node.rb +0 -164
  75. data/lib/vendor/treetop/lib/treetop/runtime/syntax_node.rb +0 -72
  76. data/lib/vendor/treetop/lib/treetop/runtime/terminal_parse_failure.rb +0 -16
  77. data/lib/vendor/treetop/lib/treetop/runtime/terminal_syntax_node.rb +0 -17
  78. data/lib/vendor/treetop/lib/treetop/version.rb +0 -9
  79. data/lib/vendor/treetop/spec/compiler/and_predicate_spec.rb +0 -36
  80. data/lib/vendor/treetop/spec/compiler/anything_symbol_spec.rb +0 -44
  81. data/lib/vendor/treetop/spec/compiler/character_class_spec.rb +0 -182
  82. data/lib/vendor/treetop/spec/compiler/choice_spec.rb +0 -80
  83. data/lib/vendor/treetop/spec/compiler/circular_compilation_spec.rb +0 -28
  84. data/lib/vendor/treetop/spec/compiler/failure_propagation_functional_spec.rb +0 -21
  85. data/lib/vendor/treetop/spec/compiler/grammar_compiler_spec.rb +0 -84
  86. data/lib/vendor/treetop/spec/compiler/grammar_spec.rb +0 -41
  87. data/lib/vendor/treetop/spec/compiler/nonterminal_symbol_spec.rb +0 -40
  88. data/lib/vendor/treetop/spec/compiler/not_predicate_spec.rb +0 -38
  89. data/lib/vendor/treetop/spec/compiler/one_or_more_spec.rb +0 -35
  90. data/lib/vendor/treetop/spec/compiler/optional_spec.rb +0 -37
  91. data/lib/vendor/treetop/spec/compiler/parenthesized_expression_spec.rb +0 -19
  92. data/lib/vendor/treetop/spec/compiler/parsing_rule_spec.rb +0 -32
  93. data/lib/vendor/treetop/spec/compiler/sequence_spec.rb +0 -115
  94. data/lib/vendor/treetop/spec/compiler/terminal_spec.rb +0 -81
  95. data/lib/vendor/treetop/spec/compiler/terminal_symbol_spec.rb +0 -37
  96. data/lib/vendor/treetop/spec/compiler/test_grammar.treetop +0 -7
  97. data/lib/vendor/treetop/spec/compiler/test_grammar.tt +0 -7
  98. data/lib/vendor/treetop/spec/compiler/test_grammar_do.treetop +0 -7
  99. data/lib/vendor/treetop/spec/compiler/zero_or_more_spec.rb +0 -56
  100. data/lib/vendor/treetop/spec/composition/a.treetop +0 -11
  101. data/lib/vendor/treetop/spec/composition/b.treetop +0 -11
  102. data/lib/vendor/treetop/spec/composition/c.treetop +0 -10
  103. data/lib/vendor/treetop/spec/composition/d.treetop +0 -10
  104. data/lib/vendor/treetop/spec/composition/f.treetop +0 -17
  105. data/lib/vendor/treetop/spec/composition/grammar_composition_spec.rb +0 -40
  106. data/lib/vendor/treetop/spec/composition/subfolder/e_includes_c.treetop +0 -15
  107. data/lib/vendor/treetop/spec/ruby_extensions/string_spec.rb +0 -32
  108. data/lib/vendor/treetop/spec/runtime/compiled_parser_spec.rb +0 -101
  109. data/lib/vendor/treetop/spec/runtime/interval_skip_list/delete_spec.rb +0 -147
  110. data/lib/vendor/treetop/spec/runtime/interval_skip_list/expire_range_spec.rb +0 -349
  111. data/lib/vendor/treetop/spec/runtime/interval_skip_list/insert_and_delete_node.rb +0 -385
  112. data/lib/vendor/treetop/spec/runtime/interval_skip_list/insert_spec.rb +0 -660
  113. data/lib/vendor/treetop/spec/runtime/interval_skip_list/interval_skip_list_spec.graffle +0 -6175
  114. data/lib/vendor/treetop/spec/runtime/interval_skip_list/interval_skip_list_spec.rb +0 -58
  115. data/lib/vendor/treetop/spec/runtime/interval_skip_list/palindromic_fixture.rb +0 -23
  116. data/lib/vendor/treetop/spec/runtime/interval_skip_list/palindromic_fixture_spec.rb +0 -164
  117. data/lib/vendor/treetop/spec/runtime/interval_skip_list/spec_helper.rb +0 -84
  118. data/lib/vendor/treetop/spec/runtime/syntax_node_spec.rb +0 -53
  119. data/lib/vendor/treetop/spec/spec_helper.rb +0 -106
  120. data/lib/vendor/treetop/spec/spec_suite.rb +0 -4
  121. data/lib/vendor/treetop/treetop.gemspec +0 -17
@@ -4,7 +4,7 @@ module Less
4
4
  include Entity
5
5
 
6
6
  rule primary
7
- (declaration / ruleset / import / comment)* {
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,44 @@ 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
- } / ws selectors ';' ws {
32
+ # Mixin Declaration
33
+ } / '.' name:[-a-zA-Z0-9_]+ ws parameters ws "{" ws primary ws "}" ws {
34
+ def build env
35
+ env << Node::Mixin::Def.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
+ name:('.' [-a-zA-Z0-9_]+) args:(arguments) s ';' ws {
44
+ def build env
45
+ definition = env.nearest(name.text_value, :mixin) or raise MixinNameError, name.text_value
46
+ params = args.build.map {|i| Node::Expression.new i } unless args.empty?
47
+ env << Node::Mixin::Call.new(definition, params || [], env)
48
+ end
49
+ } / ws selectors ';' ws {
32
50
  def build env
33
51
  selectors.build(env, :mixin).each do |path|
34
52
  rules = path.inject(env.root) do |current, node|
35
- current.descend(node.selector, node) or raise MixinNameError, path.join
53
+ current.descend(node.selector, node) or raise MixinNameError, selectors.text_value
36
54
  end.rules
37
55
  env.rules += rules
56
+ #env.mix(rules)
38
57
  end
39
58
  end
40
- }
41
- end
42
-
43
- rule import
44
- ws "@import" S url:(string / url) medias? s ';' ws {
45
- def build env
46
- path = File.join(env.root.file || Dir.pwd, url.value)
47
- path += '.less' unless path =~ /\.(le|c)ss$/
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
- }
59
+ }
56
60
  end
57
-
58
- rule url
59
- 'url(' path:(string / [-a-zA-Z0-9_%$/.&=:;#+?]+) ')' {
60
- def build env = nil
61
- Node::String.new CGI.unescape(path.text_value)
62
- end
63
61
 
64
- def value
65
- build
66
- end
67
- }
68
- end
69
-
70
- rule medias
71
- [-a-z]+ (s ',' s [a-z]+)*
72
- end
73
-
74
62
  rule selectors
75
63
  ws selector tail:(s ',' ws selector)* ws {
76
64
  def build env, method
@@ -89,7 +77,7 @@ module Less
89
77
  # div > p a {...}
90
78
  #
91
79
  rule selector
92
- sel:(s select element s)+ arguments? {
80
+ sel:(s select element s)+ '' {
93
81
  def ruleset env
94
82
  sel.elements.inject(env) do |node, e|
95
83
  node << Node::Element.new(e.element.text_value, e.select.text_value)
@@ -104,16 +92,80 @@ module Less
104
92
  end
105
93
  }
106
94
  end
95
+
96
+ rule parameters
97
+ '(' s ')' {
98
+ def build env
99
+ []
100
+ end
101
+ } / '(' parameter tail:(s ',' s parameter)* ')' {
102
+ def build env
103
+ all.map do |e|
104
+ e.build(env)
105
+ end
106
+ end
107
+
108
+ def all
109
+ [parameter] + tail.elements.map {|e| e.parameter }
110
+ end
111
+ }
112
+ end
113
+
114
+ rule parameter
115
+ variable s ':' s expressions {
116
+ def build env
117
+ Node::Variable.new(variable.text_value, expressions.build(env), env)
118
+ end
119
+ }
120
+ end
121
+
122
+ rule import
123
+ ws "@import" S url:(string / url) medias? s ';' ws {
124
+ def build env
125
+ path = File.join(env.root.file || Dir.pwd, url.value)
126
+ path += '.less' unless path =~ /\.(le|c)ss$/
127
+ if File.exist? path
128
+ unless env.root.imported.include?(path)
129
+ env.root.imported << path
130
+ env.rules += Less::Engine.new(File.new(path)).to_tree.rules
131
+ end
132
+ else
133
+ raise ImportError, path
134
+ end
135
+ end
136
+ }
137
+ end
138
+
139
+ rule url
140
+ 'url(' path:(string / [-a-zA-Z0-9_%$/.&=:;#+?]+) ')' {
141
+ def build env = nil
142
+ Node::Function.new('url', value)
143
+ end
144
+
145
+ def value
146
+ Node::Quoted.new CGI.unescape(path.text_value)
147
+ end
148
+ }
149
+ end
150
+
151
+ rule medias
152
+ [-a-z]+ (s ',' s [a-z]+)*
153
+ end
107
154
 
108
155
  #
109
156
  # @my-var: 12px;
110
157
  # height: 100%;
111
158
  #
112
159
  rule declaration
113
- ws name:(ident / variable) s ':' s expressions s (';'/ ws &'}') ws {
160
+ ws name:(ident / variable) s ':' s expressions tail:(ws ',' ws expressions)* s (';'/ ws &'}') ws {
114
161
  def build env
162
+ result = all.map {|e| e.build(env) if e.respond_to? :build }.compact
115
163
  env << (name.text_value =~ /^@/ ?
116
- Node::Variable : Node::Property).new(name.text_value, expressions.build(env), env)
164
+ Node::Variable : Node::Property).new(name.text_value, result, env)
165
+ end
166
+
167
+ def all
168
+ [expressions] + tail.elements.map {|f| f.expressions }
117
169
  end
118
170
  # Empty rule
119
171
  } / ws ident s ':' s ';' ws
@@ -125,7 +177,7 @@ module Less
125
177
  rule expressions
126
178
  # Operation
127
179
  expression tail:(operator expression)+ {
128
- def build env
180
+ def build env = nil
129
181
  all.map {|e| e.build(env) }.dissolve
130
182
  end
131
183
 
@@ -134,7 +186,7 @@ module Less
134
186
  end
135
187
  # Space-delimited expressions
136
188
  } / expression tail:(WS expression)* i:important? {
137
- def build env
189
+ def build env = nil
138
190
  all.map {|e| e.build(env) if e.respond_to? :build }.compact
139
191
  end
140
192
 
@@ -151,12 +203,13 @@ module Less
151
203
 
152
204
  rule expression
153
205
  '(' s expressions s ')' {
154
- def build env
206
+ def build env = nil
155
207
  Node::Expression.new(['('] + expressions.build(env).flatten + [')'])
156
208
  end
157
209
  } / entity '' {
158
- def build env
159
- entity.method(:build).arity.zero?? entity.build : entity.build(env)
210
+ def build env = nil
211
+ e = entity.method(:build).arity.zero?? entity.build : entity.build(env)
212
+ e.respond_to?(:dissolve) ? e.dissolve : e
160
213
  end
161
214
  }
162
215
  end
@@ -164,7 +217,7 @@ module Less
164
217
  # !important
165
218
  rule important
166
219
  s '!' s 'important' {
167
- def build env
220
+ def build env = nil
168
221
  Node::Keyword.new(text_value.strip)
169
222
  end
170
223
  }
@@ -174,7 +227,7 @@ module Less
174
227
  # An identifier
175
228
  #
176
229
  rule ident
177
- '*'? '-'? [-a-z0-9_]+
230
+ '*'? '-'? [-a-z_] [-a-z0-9_]*
178
231
  end
179
232
 
180
233
  rule variable
@@ -189,18 +242,14 @@ module Less
189
242
  # div / .class / #id / input[type="text"] / lang(fr)
190
243
  #
191
244
  rule element
192
- (class_id / tag / ident) attribute* ('(' ident? attribute* ')')? / attribute+ / '@media' / '@font-face'
193
- end
194
-
195
- rule class_id
196
- tag? (class / id)+
245
+ ((class / id / tag / ident) attribute* ('(' (selector / number) ')')?)+ / attribute+ / '@media' / '@font-face'
197
246
  end
198
247
 
199
248
  #
200
249
  # [type="text"]
201
250
  #
202
251
  rule attribute
203
- '[' tag ([|~*$^]? '=') (tag / string) ']' / '[' (tag / string) ']'
252
+ '[' tag ([|~*$^]? '=') (string / [-a-zA-Z_0-9]+) ']' / '[' (tag / string) ']'
204
253
  end
205
254
 
206
255
  rule class
@@ -221,7 +270,7 @@ module Less
221
270
 
222
271
  # TODO: Merge this with attribute rule
223
272
  rule accessor
224
- ident:(class_id / tag) '[' attr:(string / variable) ']' {
273
+ ident:(class / id / tag) '[' attr:(string / variable) ']' {
225
274
  def build env
226
275
  env.nearest(ident.text_value)[attr.text_value.delete(%q["'])].evaluate
227
276
  end
@@ -246,13 +295,13 @@ module Less
246
295
  rule function
247
296
  name:([-a-zA-Z_]+) arguments {
248
297
  def build
249
- Node::Function.new(name.text_value, [arguments.build].flatten)
298
+ Node::Function.new(name.text_value, arguments.build)
250
299
  end
251
300
  }
252
301
  end
253
302
 
254
303
  rule arguments
255
- '(' s argument s tail:(',' s argument s)* ')' {
304
+ '(' s expressions s tail:(',' s expressions s)* ')' {
256
305
  def build
257
306
  all.map do |e|
258
307
  e.build if e.respond_to? :build
@@ -260,30 +309,11 @@ module Less
260
309
  end
261
310
 
262
311
  def all
263
- [argument] + tail.elements.map {|e| e.argument }
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
312
+ [expressions] + tail.elements.map {|e| e.expressions }
284
313
  end
285
- } / function / keyword other:(S keyword)* {
314
+ } / '(' s ')' {
286
315
  def build
316
+ []
287
317
  end
288
318
  }
289
319
  end
@@ -13,11 +13,11 @@ module Less
13
13
  include Entity
14
14
 
15
15
  attr_accessor :rules, :selector, :file,
16
- :set, :name
16
+ :set, :imported, :name
17
17
 
18
18
  def initialize name = "", selector = ''
19
19
  @name = name
20
- @set = []
20
+ @set, @imported = [], []
21
21
  @rules = [] # Holds all the nodes under this element's hierarchy
22
22
  @selector = Selector[selector.strip].new # descendant | child | adjacent
23
23
  end
@@ -73,10 +73,12 @@ module Less
73
73
  #
74
74
  # Accessors for the different nodes in @rules
75
75
  #
76
- def identifiers; @rules.select {|r| r.kind_of? Property } end
77
- def properties; @rules.select {|r| r.instance_of? Property } end
78
- def variables; @rules.select {|r| r.instance_of? Variable } end
79
- def elements; @rules.select {|r| r.instance_of? Element } end
76
+ def identifiers; @rules.select {|r| r.kind_of? Property } end
77
+ def properties; @rules.select {|r| r.instance_of? Property } end
78
+ def variables; @rules.select {|r| r.instance_of? Variable } end
79
+ def elements; @rules.select {|r| r.kind_of? Element } end
80
+ def mixins; @rules.select {|r| r.instance_of? Mixin::Call} 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 ::String
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
  #
@@ -137,35 +145,42 @@ module Less
137
145
  #
138
146
  # Entry point for the css conversion
139
147
  #
140
- def to_css path = []
148
+ def to_css path = [], env = nil
141
149
  path << @selector.to_css << name unless root?
142
150
 
143
- content = properties.map do |i|
144
- ' ' * 2 + i.to_css
151
+ # puts "to_css env: #{env ? env.variables : "nil"}"
152
+
153
+ content = (properties + mixins).map do |i|
154
+ ' ' * 2 + i.to_css(env)
145
155
  end.compact.reject(&:empty?) * "\n"
146
156
 
147
- content = content.include?("\n") ?
148
- "\n#{content}\n" : " #{content.strip} "
149
- ruleset = !content.strip.empty??
150
- "#{[path.reject(&:empty?).join.strip,
151
- *@set.map(&:name)].uniq * ', '} {#{content}}\n" : ""
157
+ content = content.include?("\n") ? "\n#{content}\n"
158
+ : " #{content.strip} "
159
+ ruleset = if is_a?(Mixin::Def)
160
+ content.strip
161
+ else
162
+ !content.strip.empty??
163
+ "#{[path.reject(&:empty?).join.strip,
164
+ *@set.map(&:name)].uniq * ', '} {#{content}}\n" : ""
165
+ end
152
166
 
153
- css = ruleset + elements.map do |i|
154
- i.to_css(path)
167
+ css = ruleset + elements.
168
+ reject {|e| e.is_a? Mixin::Def }.map do |i|
169
+ i.to_css(path, env)
155
170
  end.reject(&:empty?).join
156
- path.pop; path.pop
171
+ 2.times {path.pop}
157
172
  css
158
173
  end
159
174
 
160
175
  #
161
- # Find the nearest variable in the hierarchy or raise a NameError
176
+ # Find the nearest node in the hierarchy or raise a NameError
162
177
  #
163
- def nearest ident
164
- ary = ident =~ /^[.#]/ ? :elements : :variables
178
+ def nearest ident, type = nil
179
+ ary = type || ident =~ /^[.#]/ ? :elements : :variables
165
180
  path.map do |node|
166
181
  node.send(ary).find {|i| i.to_s == ident }
167
182
  end.compact.first.tap do |result|
168
- raise VariableNameError, ident unless result
183
+ raise VariableNameError, ("#{ident} in #{self.to_s}") unless result
169
184
  end
170
185
  end
171
186
 
@@ -188,11 +203,75 @@ module Less
188
203
 
189
204
  (root?? "\n" : "") + [
190
205
  indent[ depth ] + self.to_s,
191
- put[ properties ],
192
206
  put[ variables ],
207
+ put[ properties ],
208
+ put[ mixins ],
193
209
  elements.map {|i| i.inspect( depth + 1 ) } * "\n"
194
210
  ].reject(&:empty?).join("\n") + "\n" + indent[ depth ]
195
211
  end
196
212
  end
213
+
214
+ module Mixin
215
+ class Call
216
+ include Entity
217
+
218
+ def initialize mixin, params, parent
219
+ # puts "Initializing a Mixin::Call #{mixin}"
220
+ @mixin = mixin
221
+ self.parent = parent
222
+ @params = params.each do |e|
223
+ e.parent = self.parent
224
+ end
225
+ end
226
+
227
+ def to_css env = nil
228
+ # puts "\n\n"
229
+ # puts "call .#{@mixin.name} #{@params} <#{@params.class}>"
230
+ @mixin.call(@params.map {|e| e.evaluate(env) })
231
+ end
232
+
233
+ def inspect
234
+ "#{@mixin.to_s} (#{@params})"
235
+ end
236
+ end
237
+
238
+ class Def < Element
239
+ attr_accessor :params
240
+
241
+ def initialize name, params = []
242
+ super name
243
+ @params = params.each do |param|
244
+ param.parent = self
245
+ end
246
+ end
247
+
248
+ def call args = []
249
+ env = Element.new
250
+
251
+ @params.zip(args).each do |param, val|
252
+ env << (val ? Variable.new(param.to_s, Expression.new([val])) : param)
253
+ end
254
+
255
+ #b ? Node::Variable.new(a.to_s, Expression.new([b])) : a
256
+
257
+ # puts "#{self.inspect}"
258
+ # puts "env: #{env.variables} root?: #{env.root?}"
259
+ # puts "\nTOCSS"
260
+ to_css([], env)
261
+ end
262
+
263
+ def variables
264
+ params + super
265
+ end
266
+
267
+ def to_s
268
+ '.' + name
269
+ end
270
+
271
+ def to_css path, env
272
+ super(path, env)
273
+ end
274
+ end
275
+ end
197
276
  end
198
277
  end