xdissent-less 0.8.12 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/README.md +10 -1
  2. data/Rakefile +21 -2
  3. data/VERSION +1 -1
  4. data/bin/lessc +0 -8
  5. data/less.gemspec +48 -15
  6. data/lib/less/command.rb +24 -29
  7. data/lib/less/engine/builder.rb +13 -0
  8. data/lib/less/engine/less.tt +379 -0
  9. data/lib/less/engine/nodes/element.rb +153 -0
  10. data/lib/less/engine/nodes/entity.rb +59 -0
  11. data/lib/less/engine/nodes/function.rb +61 -0
  12. data/lib/less/engine/nodes/literal.rb +132 -0
  13. data/lib/less/engine/nodes/property.rb +120 -0
  14. data/lib/less/engine/nodes/selector.rb +39 -0
  15. data/lib/less/engine/nodes.rb +8 -0
  16. data/lib/less/engine/parser.rb +3854 -0
  17. data/lib/less/engine.rb +61 -118
  18. data/lib/less.rb +65 -10
  19. data/spec/command_spec.rb +2 -6
  20. data/spec/css/accessors-1.0.css +20 -0
  21. data/spec/css/big-1.0.css +3770 -0
  22. data/spec/css/comments-1.0.css +11 -0
  23. data/spec/css/css-1.0.css +40 -0
  24. data/spec/css/functions-1.0.css +8 -0
  25. data/spec/css/import-1.0.css +13 -0
  26. data/spec/css/mixins-1.0.css +30 -0
  27. data/spec/css/operations-1.0.css +30 -0
  28. data/spec/css/rulesets-1.0.css +19 -0
  29. data/spec/css/scope-1.0.css +16 -0
  30. data/spec/css/strings-1.0.css +14 -0
  31. data/spec/css/variables-1.0.css +7 -0
  32. data/spec/css/whitespace-1.0.css +11 -0
  33. data/spec/engine_spec.rb +66 -18
  34. data/spec/less/accessors-1.0.less +20 -0
  35. data/spec/less/big-1.0.less +4810 -0
  36. data/spec/less/colors-1.0.less +0 -0
  37. data/spec/less/comments-1.0.less +46 -0
  38. data/spec/less/css-1.0.less +82 -0
  39. data/spec/less/exceptions/mixed-units-error.less +0 -0
  40. data/spec/less/exceptions/name-error-1.0.less +0 -0
  41. data/spec/less/exceptions/syntax-error-1.0.less +0 -0
  42. data/spec/less/functions-1.0.less +6 -0
  43. data/spec/less/import/import-test-a.less +2 -0
  44. data/spec/less/import/import-test-b.less +8 -0
  45. data/spec/less/import/import-test-c.less +5 -0
  46. data/spec/less/import-1.0.less +7 -0
  47. data/spec/less/mixins-1.0.less +43 -0
  48. data/spec/less/operations-1.0.less +39 -0
  49. data/spec/less/rulesets-1.0.less +30 -0
  50. data/spec/less/scope-1.0.less +33 -0
  51. data/spec/less/strings-1.0.less +14 -0
  52. data/spec/less/variables-1.0.less +16 -0
  53. data/spec/less/whitespace-1.0.less +21 -0
  54. data/spec/spec.css +81 -24
  55. data/spec/spec.less +2 -3
  56. data/spec/spec_helper.rb +4 -1
  57. metadata +46 -13
  58. data/lib/less/tree.rb +0 -82
  59. data/spec/css/less-0.8.10.css +0 -30
  60. data/spec/css/less-0.8.11.css +0 -31
  61. data/spec/css/less-0.8.12.css +0 -28
  62. data/spec/css/less-0.8.5.css +0 -24
  63. data/spec/css/less-0.8.6.css +0 -24
  64. data/spec/css/less-0.8.7.css +0 -24
  65. data/spec/css/less-0.8.8.css +0 -25
  66. data/spec/tree_spec.rb +0 -5
data/lib/less/engine.rb CHANGED
@@ -1,25 +1,18 @@
1
- module Less
2
- class Engine < String
3
- # Compound properties, such as `border: 1px solid black`
4
- COMPOUND = {'font' => true, 'background' => false, 'border' => false }
5
- REGEX = {
6
- :path => /([#.][->#.\w ]+)?( ?> ?)?/, # #header > .title
7
- :selector => /[-\w #.,>*+:\(\)\=\[\]']/, # .cow .milk > a
8
- :variable => /@([-\w]+)/, # @milk-white
9
- :property => /@[-\w]+|[-a-z*0-9_]+/, # 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
3
+ <<<<<<< HEAD:lib/less/engine.rb
4
+ def compile
5
+ #
6
+ # Parse the import statements
7
+ #
8
+
9
+ @tree = @tree.traverse :leaf do |key, value, path, node|
10
+ if value == :import
11
+ node.delete key
12
+ node.replace( Engine.new( File.read( key ) ).compile.to_tree.update(node) )
13
+ end
14
+ end
15
+
23
16
  #
24
17
  # Parse the variables and mixins
25
18
  #
@@ -29,6 +22,7 @@ module Less
29
22
  # in the appropriate data structure in that branch. The declaration itself
30
23
  # can then be deleted.
31
24
  #
25
+
32
26
  @tree = @tree.traverse :leaf do |key, value, path, node|
33
27
  matched = if match = key.match( REGEX[:variable] )
34
28
  node[:variables] ||= Tree.new
@@ -39,116 +33,65 @@ module Less
39
33
  end
40
34
  node.delete key if matched # Delete the property if it's LESS-specific
41
35
  end
36
+ =======
37
+ require 'engine/builder'
38
+ require 'engine/nodes'
39
+ >>>>>>> cloudhead/master:lib/less/engine.rb
42
40
 
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
41
+ module Less
42
+ class Engine
43
+ attr_reader :css, :less
44
+
45
+ def initialize obj
46
+ @less = if obj.is_a? File
47
+ @path = File.dirname(File.expand_path obj.path)
48
+ obj.read
49
+ elsif obj.is_a? String
50
+ obj.dup
51
+ else
52
+ raise ArgumentError, "argument must be an instance of File or String!"
52
53
  end
53
54
 
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?
55
+ begin
56
+ require Less::PARSER
57
+ rescue LoadError
58
+ Treetop.load Less::GRAMMAR
59
59
  end
60
+
61
+ @parser = LessParser.new
62
+ end
63
+
64
+ def parse env = Node::Element.new
65
+ root = @parser.parse(self.prepare)
60
66
 
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
67
+ if root
68
+ @tree = root.build env.tap {|e| e.file = @path }
69
+ else
70
+ raise SyntaxError, @parser.failure_message
64
71
  end
65
72
 
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
- # Disallow operations on certain compound declarations
73
- if COMPOUND[ key ]
74
- next value
75
- else
76
- raise CompoundOperationError, "#{key}: #{value}"
77
- end if COMPOUND.include? key
78
-
79
- if (unit = operation.scan(/#{REGEX[:numeric]}|(#)/i).flatten.compact.uniq).size <= 1
80
- unit = unit.join
81
- operation = if unit == '#'
82
- evaluate = lambda do |v|
83
- result = eval v
84
- unit + ( result.zero?? '000' : result.to_s(16) )
85
- end
86
- operation.gsub REGEX[:color] do
87
- hex = $1 * ( $1.size < 6 ? 6 / $1.size : 1 )
88
- hex.to_i(16)
89
- end.delete unit
90
- else
91
- evaluate = lambda {|v| eval( v ).to_s + unit }
92
- operation.gsub REGEX[:unit], ''
93
- end.to_s
94
- next if operation.match /[a-z]/i
95
- evaluate.call operation
96
- else
97
- raise MixedUnitsError, value
98
- end
99
- end
100
- end
73
+ log @tree.inspect
74
+
75
+ @tree
101
76
  end
102
- alias render compile
77
+ alias :to_tree :parse
103
78
 
104
- #
105
- # Evaluate variables
106
- #
107
- def evaluate key, expression, path, node
108
- if expression.is_a? String and expression.include? '@' # There's a var to evaluate
109
- expression.scan /#{REGEX[:path]}#{REGEX[:variable]}/ do |var|
110
- name = var.last
111
- var = var.join.delete ' '
112
-
113
- value = if var.include? '>'
114
- @tree.find :var, var.split('>') # Try finding it in a specific namespace
115
- else
116
- node.var(var) or @tree.nearest var, path # Try local first, then nearest scope
117
- end
118
-
119
- if value
120
- # Substitute variable with value
121
- node[ key ] = node[ key ].gsub /#{REGEX[:path]}@#{name}/, value
122
- else
123
- node.delete key # Discard the declaration if the variable wasn't found
124
- end
125
- end
126
- end
79
+ def to_css
80
+ "/* Generated with Less #{Less.version} */\n\n" +
81
+ (@css || @css = self.parse.to_css)
127
82
  end
128
83
 
129
- def to_css chain = :desc
130
- self.compile.to_css chain
84
+ def prepare
85
+ @less.gsub(/\r\n/, "\n"). # m$
86
+ gsub(/\t/, ' ') # Tabs to spaces
87
+ #gsub(/('|")(.*?)(\1)/) { $1 + CGI.escape( $2 ) + $1 } # Escape string values
88
+ # gsub(/\/\/.*\n/, ''). # Comments //
89
+ # gsub(/\/\*.*?\*\//m, '') # Comments /*
131
90
  end
132
91
 
133
- def hashify
134
- #
135
- # Parse the LESS structure into a hash
136
- #
137
- ###
138
- # less: color: black;
139
- # hashify: "color" => "black"
140
- #
141
- hash = self.gsub(/\r\n/, "\n"). # m$
142
- gsub(/"/, "'"). # " to '
143
- gsub(/'(.*?)'/) { "'" + CGI.escape( $1 ) + "'" }. # Escape string values
144
- gsub(/\/\/.*\n/, ''). # Comments //
145
- gsub(/\/\*.*?\*\//m, ''). # Comments /*
146
- gsub(/\s+/, ' '). # Replace \t\n
147
- gsub(/(#{REGEX[:property]}): *([^\{\}]+?) *(;|(?=\}))/,'"\1"=>"\2",'). # Rules
148
- gsub(/\}/, "},"). # Closing }
149
- gsub(/([, ]*)(#{REGEX[:selector]}+?)[ \n]*(?=\{)/, '\1"\2"=>'). # Selectors
150
- gsub(/([.#][->\w .#]+);/, '"\\1" => :mixin,') # Mixins
151
- eval "{#{ hash }}" # Return {hash}
92
+ def to_tree
93
+ @tree
152
94
  end
95
+
153
96
  end
154
97
  end
data/lib/less.rb CHANGED
@@ -1,24 +1,79 @@
1
- $:.unshift File.dirname(__FILE__)
1
+ $:.unshift File.dirname(__FILE__), File.join(File.dirname(__FILE__), 'vendor', 'treetop', 'lib')
2
2
 
3
+ require 'rubygems'
3
4
  require 'cgi'
5
+ require 'delegate'
6
+ require 'treetop'
4
7
 
5
8
  require 'less/command'
6
9
  require 'less/engine'
7
- require 'less/tree'
8
10
 
9
11
  module Less
10
- MixedUnitsError = Class.new(Exception)
11
- PathError = Class.new(Exception)
12
- CompoundOperationError = Class.new(Exception)
12
+ PARSER = 'lib/less/engine/parser.rb'
13
+ GRAMMAR = 'lib/less/engine/less.tt'
14
+
15
+ MixedUnitsError = Class.new(Exception)
16
+ PathError = Class.new(Exception)
17
+ VariableNameError = Class.new(NameError)
18
+ MixinNameError = Class.new(NameError)
19
+ SyntaxError = Class.new(RuntimeError)
20
+ ImportError = Class.new(Exception)
21
+
22
+ $verbose = false
13
23
 
14
24
  def self.version
15
- File.read( File.join( File.dirname(__FILE__), '..', 'VERSION') )
25
+ File.read( File.join( File.dirname(__FILE__), '..', 'VERSION') ).strip
26
+ end
27
+
28
+ def self.parse less
29
+ Engine.new(less).to_css
30
+ end
31
+ end
32
+
33
+ module Treetop
34
+ module Runtime
35
+ class CompiledParser
36
+ def failure_message
37
+ return nil unless (tf = terminal_failures) && tf.size > 0
38
+ "on line #{failure_line}: expected " + (
39
+ tf.size == 1 ?
40
+ tf[0].expected_string :
41
+ "one of #{tf.map {|f| f.expected_string }.uniq * ' '}"
42
+ ) +
43
+ " got `#{input[failure_index]}`" +
44
+ " after:\n\n#{input[index...failure_index]}\n"
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ class Object
51
+ def verbose
52
+ $verbose = true
53
+ yield
54
+ ensure
55
+ $verbose = false
56
+ end
57
+
58
+ def tap
59
+ yield self
60
+ self
61
+ end
62
+
63
+ def log(s = '') puts "* #{s}" if $verbose end
64
+ def log!(s = '') puts "* #{s}" end
65
+ def error(s) $stderr.puts s end
66
+ def error!(s) raise CradleError, s end
67
+ end
68
+
69
+ class Class
70
+ def to_sym
71
+ self.to_s.to_sym
16
72
  end
17
73
  end
18
74
 
19
- class Hash
20
- # Convert a hash into a Tree
21
- def to_tree
22
- Less::Tree.new self
75
+ class Symbol
76
+ def to_proc
77
+ proc {|obj, *args| obj.send(self, *args) }
23
78
  end
24
79
  end
data/spec/command_spec.rb CHANGED
@@ -6,7 +6,7 @@ module LessCommandSpecHelper
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,20 @@
1
+ /* Generated with Less 1.0.0 */
2
+
3
+ .magic-box {
4
+ content: "gold";
5
+ width: 60cm;
6
+ height: 40cm;
7
+ }
8
+ .magic-box #lock { color: silver; }
9
+ #accessors {
10
+ content: "gold";
11
+ width: 60cm;
12
+ }
13
+ .unlock {
14
+ content: "gold";
15
+ width: 60cm;
16
+ height: 40cm;
17
+ color: silver;
18
+ border-color: orange;
19
+ }
20
+ .unlock #lock { color: silver; }