xdissent-less 0.8.12 → 1.0.0
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.
- data/README.md +10 -1
- data/Rakefile +21 -2
- data/VERSION +1 -1
- data/bin/lessc +0 -8
- data/less.gemspec +48 -15
- data/lib/less/command.rb +24 -29
- data/lib/less/engine/builder.rb +13 -0
- data/lib/less/engine/less.tt +379 -0
- data/lib/less/engine/nodes/element.rb +153 -0
- data/lib/less/engine/nodes/entity.rb +59 -0
- data/lib/less/engine/nodes/function.rb +61 -0
- data/lib/less/engine/nodes/literal.rb +132 -0
- data/lib/less/engine/nodes/property.rb +120 -0
- data/lib/less/engine/nodes/selector.rb +39 -0
- data/lib/less/engine/nodes.rb +8 -0
- data/lib/less/engine/parser.rb +3854 -0
- data/lib/less/engine.rb +61 -118
- data/lib/less.rb +65 -10
- data/spec/command_spec.rb +2 -6
- data/spec/css/accessors-1.0.css +20 -0
- data/spec/css/big-1.0.css +3770 -0
- data/spec/css/comments-1.0.css +11 -0
- data/spec/css/css-1.0.css +40 -0
- data/spec/css/functions-1.0.css +8 -0
- data/spec/css/import-1.0.css +13 -0
- data/spec/css/mixins-1.0.css +30 -0
- data/spec/css/operations-1.0.css +30 -0
- data/spec/css/rulesets-1.0.css +19 -0
- data/spec/css/scope-1.0.css +16 -0
- data/spec/css/strings-1.0.css +14 -0
- data/spec/css/variables-1.0.css +7 -0
- data/spec/css/whitespace-1.0.css +11 -0
- data/spec/engine_spec.rb +66 -18
- data/spec/less/accessors-1.0.less +20 -0
- data/spec/less/big-1.0.less +4810 -0
- data/spec/less/colors-1.0.less +0 -0
- data/spec/less/comments-1.0.less +46 -0
- data/spec/less/css-1.0.less +82 -0
- data/spec/less/exceptions/mixed-units-error.less +0 -0
- data/spec/less/exceptions/name-error-1.0.less +0 -0
- data/spec/less/exceptions/syntax-error-1.0.less +0 -0
- data/spec/less/functions-1.0.less +6 -0
- data/spec/less/import/import-test-a.less +2 -0
- data/spec/less/import/import-test-b.less +8 -0
- data/spec/less/import/import-test-c.less +5 -0
- data/spec/less/import-1.0.less +7 -0
- data/spec/less/mixins-1.0.less +43 -0
- data/spec/less/operations-1.0.less +39 -0
- data/spec/less/rulesets-1.0.less +30 -0
- data/spec/less/scope-1.0.less +33 -0
- data/spec/less/strings-1.0.less +14 -0
- data/spec/less/variables-1.0.less +16 -0
- data/spec/less/whitespace-1.0.less +21 -0
- data/spec/spec.css +81 -24
- data/spec/spec.less +2 -3
- data/spec/spec_helper.rb +4 -1
- metadata +46 -13
- data/lib/less/tree.rb +0 -82
- data/spec/css/less-0.8.10.css +0 -30
- data/spec/css/less-0.8.11.css +0 -31
- data/spec/css/less-0.8.12.css +0 -28
- data/spec/css/less-0.8.5.css +0 -24
- data/spec/css/less-0.8.6.css +0 -24
- data/spec/css/less-0.8.7.css +0 -24
- data/spec/css/less-0.8.8.css +0 -25
- data/spec/tree_spec.rb +0 -5
data/lib/less/engine.rb
CHANGED
@@ -1,25 +1,18 @@
|
|
1
|
-
|
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
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
62
|
-
|
63
|
-
|
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
|
-
|
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
|
77
|
+
alias :to_tree :parse
|
103
78
|
|
104
|
-
|
105
|
-
|
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
|
130
|
-
|
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
|
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
|
-
|
11
|
-
|
12
|
-
|
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
|
20
|
-
|
21
|
-
|
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, :
|
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(:
|
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; }
|