less 0.8.8 → 1.2.21

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 (88) hide show
  1. data/CHANGELOG +62 -0
  2. data/README.md +24 -6
  3. data/Rakefile +28 -37
  4. data/VERSION +1 -1
  5. data/bin/lessc +41 -11
  6. data/less.gemspec +85 -16
  7. data/lib/less/command.rb +47 -28
  8. data/lib/less/engine/grammar/common.tt +29 -0
  9. data/lib/less/engine/grammar/entity.tt +144 -0
  10. data/lib/less/engine/grammar/less.tt +341 -0
  11. data/lib/less/engine/nodes/element.rb +281 -0
  12. data/lib/less/engine/nodes/entity.rb +79 -0
  13. data/lib/less/engine/nodes/function.rb +93 -0
  14. data/lib/less/engine/nodes/literal.rb +171 -0
  15. data/lib/less/engine/nodes/property.rb +232 -0
  16. data/lib/less/engine/nodes/ruleset.rb +12 -0
  17. data/lib/less/engine/nodes/selector.rb +44 -0
  18. data/lib/less/engine/nodes.rb +9 -0
  19. data/lib/less/engine.rb +44 -140
  20. data/lib/less/ext.rb +60 -0
  21. data/lib/less.rb +25 -13
  22. data/spec/command_spec.rb +3 -7
  23. data/spec/css/accessors.css +18 -0
  24. data/spec/css/big.css +3768 -0
  25. data/spec/css/colors.css +14 -0
  26. data/spec/css/comments.css +9 -0
  27. data/spec/css/css-3.css +21 -0
  28. data/spec/css/css.css +50 -0
  29. data/spec/css/dash-prefix.css +12 -0
  30. data/spec/css/functions.css +6 -0
  31. data/spec/css/import-with-extra-paths.css +8 -0
  32. data/spec/css/import-with-partial-in-extra-path.css +6 -0
  33. data/spec/css/import.css +12 -0
  34. data/spec/css/lazy-eval.css +1 -0
  35. data/spec/css/mixins-args.css +32 -0
  36. data/spec/css/mixins.css +28 -0
  37. data/spec/css/operations.css +28 -0
  38. data/spec/css/parens.css +20 -0
  39. data/spec/css/rulesets.css +17 -0
  40. data/spec/css/scope.css +11 -0
  41. data/spec/css/selectors.css +13 -0
  42. data/spec/css/strings.css +12 -0
  43. data/spec/css/variables.css +8 -0
  44. data/spec/css/whitespace.css +7 -0
  45. data/spec/engine_spec.rb +107 -15
  46. data/spec/less/accessors.less +20 -0
  47. data/spec/less/big.less +1264 -0
  48. data/spec/less/colors.less +35 -0
  49. data/spec/less/comments.less +46 -0
  50. data/spec/less/css-3.less +52 -0
  51. data/spec/less/css.less +104 -0
  52. data/spec/less/dash-prefix.less +21 -0
  53. data/spec/less/exceptions/mixed-units-error.less +3 -0
  54. data/spec/less/exceptions/name-error-1.0.less +3 -0
  55. data/spec/less/exceptions/syntax-error-1.0.less +3 -0
  56. data/spec/less/extra_import_path/extra.less +1 -0
  57. data/spec/less/extra_import_path/import/import-test-a.css +1 -0
  58. data/spec/less/extra_import_path/import/import-test-a.less +4 -0
  59. data/spec/less/functions.less +6 -0
  60. data/spec/less/hidden.less +25 -0
  61. data/spec/less/import/import-test-a.less +2 -0
  62. data/spec/less/import/import-test-b.less +8 -0
  63. data/spec/less/import/import-test-c.less +7 -0
  64. data/spec/less/import/import-test-d.css +1 -0
  65. data/spec/less/import-with-extra-paths.less +4 -0
  66. data/spec/less/import.less +8 -0
  67. data/spec/less/lazy-eval.less +6 -0
  68. data/spec/less/literal-css.less +11 -0
  69. data/spec/less/mixins-args.less +59 -0
  70. data/spec/less/mixins.less +43 -0
  71. data/spec/less/operations.less +39 -0
  72. data/spec/less/parens.less +26 -0
  73. data/spec/less/rulesets.less +30 -0
  74. data/spec/less/scope.less +32 -0
  75. data/spec/less/selectors.less +24 -0
  76. data/spec/less/strings.less +14 -0
  77. data/spec/less/variables.less +29 -0
  78. data/spec/less/whitespace.less +34 -0
  79. data/spec/spec.css +50 -25
  80. data/spec/spec_helper.rb +4 -1
  81. metadata +96 -15
  82. data/lib/less/tree.rb +0 -82
  83. data/spec/css/less-0.8.5.css +0 -24
  84. data/spec/css/less-0.8.6.css +0 -24
  85. data/spec/css/less-0.8.7.css +0 -24
  86. data/spec/css/less-0.8.8.css +0 -25
  87. data/spec/spec.less +0 -128
  88. data/spec/tree_spec.rb +0 -5
@@ -0,0 +1,232 @@
1
+ module Less
2
+ module Node
3
+ class Property < String
4
+ include Entity
5
+
6
+ attr_accessor :value
7
+
8
+ def initialize key, value = nil, parent = nil
9
+ super key, parent
10
+ value = if value.is_a? Array
11
+ value.each {|v| v.parent = self if v.respond_to? :parent }.
12
+ map {|v| v.is_a?(Expression) ? v : Expression.new(v, self) }
13
+ elsif value.nil?
14
+ []
15
+ else
16
+ value
17
+ end
18
+ @value = value.is_a?(Expression) ? value : Expression.new(value, self)
19
+ @value.parent = self
20
+ @value.delimiter = ','
21
+ # puts "new property #{to_s}: #{value} => #{@value}, contains: #{@value[0].class}"
22
+ # puts
23
+ end
24
+
25
+ def parent= obj
26
+ @parent = obj
27
+ value.parent = self
28
+ end
29
+
30
+ def copy
31
+ clone.tap {|c| c.value = value.copy }
32
+ end
33
+
34
+ def << token
35
+ token = Node::Anonymous.new(*token) unless token.is_a? Entity or token.respond_to? :to_ruby
36
+ token.parent = self if token.respond_to? :parent
37
+ @value << token
38
+ end
39
+
40
+ def empty?; !@value || @value.empty? end
41
+
42
+ def inspect
43
+ self + (empty?? "" : ": `#{value.map {|i| i.to_s } * ' | '}`")
44
+ end
45
+
46
+ def == other
47
+ self.to_s == other.to_s
48
+ end
49
+
50
+ def eql? other
51
+ self == other and value.eql? other.value
52
+ end
53
+
54
+ def to_s
55
+ super
56
+ end
57
+
58
+ def nearest node
59
+ parent.nearest node
60
+ end
61
+
62
+ def evaluate env = nil
63
+ # puts "evaluating property `#{to_s}`: #{value.inspect}"
64
+ if value.is_a?(Expression) #Value
65
+ # puts "value is a Value"
66
+ value.map {|e| e.evaluate(env) } #6
67
+ else
68
+ # puts "value is a #{value.class}"
69
+ [value.evaluate(env)]
70
+ end
71
+
72
+
73
+ end
74
+
75
+ def to_css env = nil
76
+ # puts "property.to_css `#{to_s}` env:#{env ? env.variables : "nil"}"
77
+ val = evaluate(env)
78
+ "#{self}: #{if val.respond_to? :to_css
79
+ val.to_css
80
+ else
81
+ # p val
82
+ # puts "#{val.class} #{val.first.class}"
83
+ val.map {|i| i.to_css }.join(", ")
84
+ end};"
85
+ end
86
+ end
87
+
88
+ class Variable < Property
89
+ attr_reader :declaration
90
+
91
+ def initialize key, value = nil, parent = nil
92
+ @declaration = value ? true : false
93
+ super key.delete('@'), value, parent
94
+ end
95
+
96
+ def inspect
97
+ "@#{super}"
98
+ end
99
+
100
+ def to_s
101
+ "@#{super}"
102
+ end
103
+
104
+ def evaluate env = nil
105
+ if declaration
106
+ # puts "evaluating DEC"
107
+ value.evaluate #2
108
+ else
109
+ # puts "evaluating #{to_s} par: #{parent} env: #{env ? env.variables : "nil"}"
110
+ begin
111
+ var = (env || self.parent).nearest(to_s) #3
112
+ rescue VariableNameError
113
+ var = self.parent.nearest(to_s)
114
+ end
115
+ var.evaluate
116
+ end
117
+ end
118
+
119
+ def to_ruby
120
+ evaluate.to_ruby
121
+ end
122
+
123
+ def to_css env = nil
124
+ val = evaluate env
125
+ if val.respond_to? :to_css
126
+ env ? val.to_css(env) : val.to_css
127
+ else
128
+ val.map {|i| env ? i.to_css(env) : i.to_css }.join ', '
129
+ end
130
+ end
131
+ end
132
+
133
+ class Expression < Array
134
+ attr_accessor :parent, :delimiter
135
+
136
+ def initialize ary, parent = nil, delimiter = ' '
137
+ self.parent = parent
138
+ self.delimiter = delimiter
139
+ # puts "new expression #{ary} |#{delimiter}|"
140
+ super(ary.is_a?(Array) ? ary : [ary].flatten)
141
+ end
142
+
143
+ def expressions; select {|i| i.kind_of? Expression } end
144
+ def variables; select {|i| i.kind_of? Variable } end
145
+ def operators; select {|i| i.is_a? Operator } end
146
+ def entities; select {|i| i.kind_of? Entity } end
147
+ def literals; select {|i| i.kind_of? Literal } end
148
+
149
+ def parent= obj
150
+ @parent = obj
151
+ each {|e| e.parent = obj if e.respond_to? :parent }
152
+ end
153
+
154
+ def inspect
155
+ '[' + map {|i| i.inspect }.join(', ') + ']'
156
+ end
157
+
158
+ def delimiter= d
159
+ @delimiter = d.strip + ' '
160
+ end
161
+
162
+ def flatten
163
+ self
164
+ end
165
+
166
+ def terminal?
167
+ expressions.empty? #&& variables.empty?
168
+ end
169
+
170
+ def to_css env = nil
171
+ # puts "TOCSS, delim: |#{@delimiter}|"
172
+ map do |i|
173
+ i.parent = self.parent
174
+ i.respond_to?(:to_css) ? i.to_css() : i.to_s
175
+ end * @delimiter
176
+ end
177
+
178
+ def to_ruby
179
+ map do |i|
180
+ i.respond_to?(:to_ruby) ? i.to_ruby : i.to_s
181
+ end
182
+ end
183
+
184
+ #
185
+ # Evaluates the expression and instantiates a new Literal with the result
186
+ # ex: [#111, +, #111] will evaluate to a Color node, with value #222
187
+ #
188
+ def evaluate env = nil
189
+ # puts "expression #{self.inspect} env: #{env ? env.variables : "nil"}"
190
+ if size > 2 or !terminal?
191
+ # puts " SIZE > 2 or !terminal"
192
+
193
+ # puts "--- sub evaluation ---"
194
+
195
+ # Replace self with an evaluated sub-expression
196
+ evaled = self.class.new(map {|e| e.respond_to?(:evaluate) ? e.evaluate(env) : e }, parent, delimiter) #5
197
+
198
+ # puts "======================"
199
+ # puts "evaled => #{evaled.inspect}"
200
+
201
+ unit = evaled.literals.map do |node|
202
+ node.unit
203
+ end.compact.uniq.tap do |ary|
204
+ raise MixedUnitsError, evaled * ' ' if ary.size > 1 && !evaled.operators.empty?
205
+ end.join
206
+
207
+ entity = evaled.literals.find {|e| e.unit == unit } || evaled.literals.first || evaled.entities.first
208
+ result = evaled.operators.empty?? evaled : eval(evaled.to_ruby.join)
209
+
210
+ # puts "entity is a #{entity.class}"
211
+ # puts "delimiter is |#{@delimiter}|"
212
+
213
+ case result
214
+ when Entity then result
215
+ when Expression then result.one?? result.first : self.class.new(result, parent, delimiter)
216
+ else entity.class.new(result, *(unit if entity.class == Node::Number))
217
+ end
218
+ elsif size == 1
219
+ if first.is_a? Variable
220
+ first.evaluate(env)
221
+ elsif first.is_a? Function
222
+ first.evaluate(env)
223
+ else
224
+ first
225
+ end
226
+ else
227
+ self
228
+ end
229
+ end
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,12 @@
1
+ module Less
2
+ module Node
3
+ class Ruleset < Array
4
+ def initialize elements = []
5
+ super elements
6
+ end
7
+
8
+ def to_css
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,44 @@
1
+ module Less
2
+ module Node
3
+ class Selector < String
4
+ include Entity
5
+
6
+ Selectors = {
7
+ :Descendant => '',
8
+ :Child => '>',
9
+ :Adjacent => '+',
10
+ :PseudoClass => ':',
11
+ :PseudoElement => '::',
12
+ :Sibling => '~'
13
+ }
14
+
15
+ def initialize
16
+ super Selectors[ self.class.to_s.split('::').last.to_sym ]
17
+ end
18
+
19
+ def self.[] key
20
+ Node.const_get(Selectors.find {|k, v| v == key }.first)
21
+ end
22
+ end
23
+
24
+ class Descendant < Selector
25
+ def to_css; " " end
26
+ end
27
+
28
+ class Child < Selector
29
+ def to_css; " #{self} " end
30
+ end
31
+
32
+ class Adjacent < Selector
33
+ def to_css; " #{self} " end
34
+ end
35
+
36
+ class PseudoClass < Selector
37
+ def to_css; self end
38
+ end
39
+
40
+ class PseudoElement < Selector
41
+ def to_css; self end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,9 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'engine/nodes/entity'
4
+ require 'engine/nodes/function'
5
+ require 'engine/nodes/ruleset'
6
+ require 'engine/nodes/element'
7
+ require 'engine/nodes/property'
8
+ require 'engine/nodes/literal'
9
+ require 'engine/nodes/selector'
data/lib/less/engine.rb CHANGED
@@ -1,148 +1,52 @@
1
- module Less
2
- class Engine < String
3
- # Compound properties, such as `border: 1px solid black`
4
- COMPOUND = ['font', 'background', 'border']
5
- REGEX = {
6
- :path => /([#.][->#.\w ]+)?( ?> ?)?/, # #header > .title
7
- :selector => /[-\w #.,>*:\(\)]/, # .cow .milk > a
8
- :variable => /@([-\w]+)/, # @milk-white
9
- :property => /@[-\w]+|[-a-z]+/, # font-size
10
- :color => /#([a-zA-Z0-9]{3,6})\b/, # #f0f0f0
11
- :number => /\d+(?>\.\d+)?/, # 24.8
12
- :unit => /px|em|pt|cm|mm|%/ # em
13
- }
14
- REGEX[:numeric] = /#{REGEX[:number]}(#{REGEX[:unit]})?/
15
- REGEX[:operand] = /#{REGEX[:color]}|#{REGEX[:numeric]}/
16
-
17
- def initialize s
18
- super
19
- @tree = Tree.new self.hashify
20
- end
1
+ $:.unshift File.dirname(__FILE__)
21
2
 
22
- def compile
23
- #
24
- # Parse the variables and mixins
25
- #
26
- # We use symbolic keys, such as :mixins, to store LESS-only data,
27
- # each branch has its own :mixins => [], and :variables => {}
28
- # Once a declaration has been recognised as LESS-specific, it is copied
29
- # in the appropriate data structure in that branch. The declaration itself
30
- # can then be deleted.
31
- #
32
- @tree = @tree.traverse :leaf do |key, value, path, node|
33
- matched = if match = key.match( REGEX[:variable] )
34
- node[:variables] ||= Tree.new
35
- node[:variables][ match.captures.first ] = value
36
- elsif value == :mixin
37
- node[:mixins] ||= []
38
- node[:mixins] << key
39
- end
40
- node.delete key if matched # Delete the property if it's LESS-specific
41
- end
42
-
43
- #
44
- # Evaluate mixins
45
- #
46
- @tree = @tree.traverse :branch do |path, node|
47
- if node.include? :mixins
48
- node[:mixins].each do |m|
49
- @tree.find( :mixin, m.delete(' ').split('>') ).each {|k, v| node[ k ] = v }
50
- end
51
- end
52
- end
53
-
54
- # Call `evaluate` on variables, such as '@dark: @light / 2'
55
- @tree = @tree.traverse :branch do |path, node|
56
- node.vars.each do |key, value|
57
- evaluate key, value, path, node.vars
58
- end if node.vars?
59
- end
60
-
61
- # Call `evaluate` on css properties, such as 'font-size: @big'
62
- @tree = @tree.traverse :leaf do |key, value, path, node|
63
- evaluate key, value, path, node
64
- end
65
-
66
- #
67
- # Evaluate operations (2+2)
68
- #
69
- # Units are: 1px, 1em, 1%, #111
70
- @tree = @tree.traverse :leaf do |key, value, path, node|
71
- node[ key ] = value.gsub /(#{REGEX[:operand]}(\s?)[-+\/*](\4))+(#{REGEX[:operand]})/ do |operation|
72
- raise CompoundOperationError, "#{key}: #{value}" if COMPOUND.include? key # Disallow operations on compound declarations
73
- if (unit = operation.scan(/#{REGEX[:numeric]}|(#)/i).flatten.compact.uniq).size <= 1
74
- unit = unit.join
75
- operation = if unit == '#'
76
- evaluate = lambda do |v|
77
- result = eval v
78
- unit + ( result.zero?? '000' : result.to_s(16) )
79
- end
80
- operation.gsub REGEX[:color] do
81
- hex = $1 * ( $1.size < 6 ? 6 / $1.size : 1 )
82
- hex.to_i(16)
83
- end.delete unit
84
- else
85
- evaluate = lambda {|v| eval( v ).to_s + unit }
86
- operation.gsub REGEX[:unit], ''
87
- end.to_s
88
- next if operation.match /[a-z]/i
89
- evaluate.call operation
90
- else
91
- raise MixedUnitsError, value
92
- end
93
- end
3
+ require 'engine/nodes'
4
+
5
+ begin
6
+ require 'engine/parser'
7
+ rescue LoadError
8
+ Treetop.load File.join(LESS_GRAMMAR, 'less.tt')
9
+ end
10
+
11
+ module Less
12
+ class Engine
13
+ attr_reader :css, :less
14
+
15
+ def initialize obj, options = {}
16
+ @less = if obj.is_a? File
17
+ @path = File.dirname File.expand_path(obj.path)
18
+ obj.read
19
+ elsif obj.is_a? String
20
+ obj.dup
21
+ else
22
+ raise ArgumentError, "argument must be an instance of File or String!"
94
23
  end
24
+
25
+ @options = options
26
+ @parser = StyleSheetParser.new
95
27
  end
96
- alias render compile
97
-
98
- #
99
- # Evaluate variables
100
- #
101
- def evaluate key, expression, path, node
102
- if expression.is_a? String and expression.include? '@' # There's a var to evaluate
103
- expression.scan /#{REGEX[:path]}#{REGEX[:variable]}/ do |var|
104
- name = var.last
105
- var = var.join.delete ' '
106
-
107
- value = if var.include? '>'
108
- @tree.find :var, var.split('>') # Try finding it in a specific namespace
109
- else
110
- node.var(var) or @tree.nearest var, path # Try local first, then nearest scope
111
- end
112
-
113
- if value
114
- # Substitute variable with value
115
- node[ key ] = node[ key ].gsub /#{REGEX[:path]}@#{name}/, value
116
- else
117
- node.delete key # Discard the declaration if the variable wasn't found
118
- end
119
- end
28
+
29
+ def parse build = true, env = Node::Element.new
30
+ root = @parser.parse(self.prepare)
31
+
32
+ return root unless build
33
+
34
+ if root
35
+ @tree = root.build env.tap {|e| e.file = @path }
36
+ else
37
+ raise SyntaxError, @parser.failure_message(@options[:color])
120
38
  end
39
+
40
+ @tree
121
41
  end
122
-
123
- def to_css chain = :desc
124
- self.compile.to_css chain
42
+ alias :to_tree :parse
43
+
44
+ def to_css
45
+ @css || @css = self.parse.group.to_css
125
46
  end
126
-
127
- def hashify
128
- #
129
- # Parse the LESS structure into a hash
130
- #
131
- ###
132
- # less: color: black;
133
- # hashify: "color" => "black"
134
- #
135
- hash = self.gsub(/\t+/, ' '). # Tabs
136
- gsub(/\r\n/, "\n"). # m$
137
- gsub(/\/\/.*/, ''). # Comments //
138
- gsub(/\/\*.*?\*\//m, ''). # Comments /*
139
- gsub(/"/, "'"). # " => '
140
- gsub(/("|')(.+?)(\1)/) { $1 + CGI.escape( $2 ) + $1 }. # Escape string values
141
- gsub(/(#{REGEX[:property]}):\s*(.+?)\s*(;|(?=\}))/,'"\1"=>"\2",'). # Rules
142
- gsub(/\}/, "},"). # Closing }
143
- gsub(/( *)(#{REGEX[:selector]}+?)[ \n]*(?=\{)/m, '\1"\2"=>'). # Selectors
144
- gsub(/([.#][->\w .#]+);/, '"\\1" => :mixin,') # Mixins
145
- eval "{" + hash + "}" # Return {hash}
47
+
48
+ def prepare
49
+ @less.gsub(/\r\n/, "\n").gsub(/\t/, ' ')
146
50
  end
147
51
  end
148
- end
52
+ end
data/lib/less/ext.rb ADDED
@@ -0,0 +1,60 @@
1
+ module Treetop
2
+ module Runtime
3
+ class CompiledParser
4
+ def failure_message color
5
+ o = color ? Mutter.new.clear : lambda {|i, *args| i }
6
+ return nil unless (tf = terminal_failures) && tf.size > 0
7
+ msg = "on line #{failure_line}: expected " + (
8
+ tf.size == 1 ?
9
+ o[tf[0].expected_string, :yellow] :
10
+ "one of #{o[tf.map {|f| f.expected_string }.uniq * ' ', :yellow]}"
11
+ )
12
+ f = input[failure_index]
13
+ got = case f
14
+ when "\n" then o['\n', :cyan]
15
+ when nil then o["EOF", :cyan]
16
+ when ' ' then o["white-space", :cyan]
17
+ else o[f.chr, :yellow]
18
+ end
19
+ msg += " got #{got} after:\n\n#{input[index...failure_index]}\n"
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ class Object
26
+ def verbose
27
+ $verbose = true
28
+ yield
29
+ ensure
30
+ $verbose = false
31
+ end
32
+
33
+ def tap
34
+ yield self
35
+ self
36
+ end
37
+ end
38
+
39
+ class Array
40
+ def dissolve
41
+ ary = flatten.compact
42
+ case ary.size
43
+ when 0 then []
44
+ when 1 then first
45
+ else ary
46
+ end
47
+ end
48
+
49
+ def one?
50
+ size == 1
51
+ end
52
+ end
53
+
54
+ unless :symbol.respond_to?(:to_proc)
55
+ class Symbol
56
+ def to_proc
57
+ Proc.new {|*args| args.shift.__send__(self, *args) }
58
+ end
59
+ end
60
+ end
data/lib/less.rb CHANGED
@@ -1,24 +1,36 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
1
  require 'cgi'
2
+ require 'treetop'
3
+ require 'mutter'
4
+ require 'delegate'
5
+
6
+ LESS_ROOT = File.expand_path(File.dirname(__FILE__))
7
+ LESS_PARSER = File.join(LESS_ROOT, 'less', 'engine', 'parser.rb')
8
+ LESS_GRAMMAR = File.join(LESS_ROOT, 'less', 'engine', 'grammar')
4
9
 
10
+ $LESS_LOAD_PATH = []
11
+
12
+ $:.unshift File.dirname(__FILE__)
13
+
14
+ require 'less/ext'
5
15
  require 'less/command'
6
16
  require 'less/engine'
7
- require 'less/tree'
8
17
 
9
18
  module Less
10
- MixedUnitsError = Class.new(Exception)
11
- PathError = Class.new(Exception)
12
- CompoundOperationError = Class.new(Exception)
19
+ MixedUnitsError = Class.new(RuntimeError)
20
+ PathError = Class.new(RuntimeError)
21
+ VariableNameError = Class.new(NameError)
22
+ MixinNameError = Class.new(NameError)
23
+ SyntaxError = Class.new(RuntimeError)
24
+ ImportError = Class.new(RuntimeError)
25
+ CompileError = Class.new(RuntimeError)
26
+
27
+ $verbose = false
13
28
 
14
29
  def self.version
15
- File.read( File.join( File.dirname(__FILE__), '..', 'VERSION') )
30
+ File.read( File.join( File.dirname(__FILE__), '..', 'VERSION') ).strip
16
31
  end
17
- end
18
32
 
19
- class Hash
20
- # Convert a hash into a Tree
21
- def to_tree
22
- Less::Tree.new self
33
+ def self.parse less
34
+ Engine.new(less).to_css
23
35
  end
24
- end
36
+ end
data/spec/command_spec.rb CHANGED
@@ -2,11 +2,11 @@ require File.dirname(__FILE__) + '/spec_helper'
2
2
 
3
3
  module LessCommandSpecHelper
4
4
  def required_options
5
- {:source => File.dirname(__FILE__) + '/spec.less'}
5
+ {:source => File.dirname(__FILE__) + '/less/css.less', :destination => File.dirname(__FILE__) + '/spec.css' }
6
6
  end
7
7
 
8
8
  def valid_options
9
- {:destination => File.dirname(__FILE__) + '/spec.css', :watch => true, :chain => true, :debug => false}.merge(required_options)
9
+ {:destination => File.dirname(__FILE__) + '/spec.css', :watch => true, :debug => false}.merge(required_options)
10
10
  end
11
11
  end
12
12
 
@@ -48,10 +48,6 @@ describe Less::Command do
48
48
  @command.options[:watch].should == valid_options[:watch]
49
49
  end
50
50
 
51
- it "should set the chain" do
52
- @command.options[:chain].should == valid_options[:chain]
53
- end
54
-
55
51
  it "should set the debug" do
56
52
  @command.options[:debug].should == valid_options[:debug]
57
53
  end
@@ -80,7 +76,7 @@ describe Less::Command do
80
76
  end
81
77
 
82
78
  it "should attempt to re-compile" do
83
- @command.should_receive(:compile).with().once
79
+ @command.should_receive(:parse).with().once
84
80
  end
85
81
  end
86
82
 
@@ -0,0 +1,18 @@
1
+ .magic-box {
2
+ content: "gold";
3
+ width: 60cm;
4
+ height: 40cm;
5
+ }
6
+ .magic-box #lock { color: silver; }
7
+ #accessors {
8
+ content: "gold";
9
+ width: 60cm;
10
+ }
11
+ .unlock {
12
+ content: "gold";
13
+ width: 60cm;
14
+ height: 40cm;
15
+ color: silver;
16
+ border-color: orange;
17
+ }
18
+ .unlock #lock { color: silver; }