less 1.1.13 → 1.2.9

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