cloudhead-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 -25
- 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 +42 -139
- 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 -23
- data/spec/spec.less +3 -4
- 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,154 +1,57 @@
|
|
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]+/, # 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
|
-
|
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
|
3
|
+
require 'engine/builder'
|
4
|
+
require 'engine/nodes'
|
42
5
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
6
|
+
module Less
|
7
|
+
class Engine
|
8
|
+
attr_reader :css, :less
|
9
|
+
|
10
|
+
def initialize obj
|
11
|
+
@less = if obj.is_a? File
|
12
|
+
@path = File.dirname(File.expand_path obj.path)
|
13
|
+
obj.read
|
14
|
+
elsif obj.is_a? String
|
15
|
+
obj.dup
|
16
|
+
else
|
17
|
+
raise ArgumentError, "argument must be an instance of File or String!"
|
64
18
|
end
|
65
19
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
20
|
+
begin
|
21
|
+
require Less::PARSER
|
22
|
+
rescue LoadError
|
23
|
+
Treetop.load Less::GRAMMAR
|
100
24
|
end
|
25
|
+
|
26
|
+
@parser = LessParser.new
|
101
27
|
end
|
102
|
-
alias render compile
|
103
28
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
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
|
29
|
+
def parse env = Node::Element.new
|
30
|
+
root = @parser.parse(self.prepare)
|
31
|
+
|
32
|
+
if root
|
33
|
+
@tree = root.build env.tap {|e| e.file = @path }
|
34
|
+
else
|
35
|
+
raise SyntaxError, @parser.failure_message
|
126
36
|
end
|
37
|
+
|
38
|
+
log @tree.inspect
|
39
|
+
|
40
|
+
@tree
|
127
41
|
end
|
42
|
+
alias :to_tree :parse
|
128
43
|
|
129
|
-
def to_css
|
130
|
-
|
44
|
+
def to_css
|
45
|
+
"/* Generated with Less #{Less.version} */\n\n" +
|
46
|
+
(@css || @css = self.parse.to_css)
|
131
47
|
end
|
132
48
|
|
133
|
-
def
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
# hashify: "color" => "black"
|
140
|
-
#
|
141
|
-
hash = self.gsub(/\r\n/, "\n"). # m$
|
142
|
-
gsub(/\/\/.*\n/, ''). # Comments //
|
143
|
-
gsub(/\/\*.*?\*\//m, ''). # Comments /*
|
144
|
-
gsub(/\s+/, ' '). # Replace \t\n
|
145
|
-
gsub(/"/, "'"). # " to '
|
146
|
-
gsub(/("|')(.*?)(\1)/) { $1 + CGI.escape( $2 ) + $1 }. # Escape string values
|
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}
|
49
|
+
def prepare
|
50
|
+
@less.gsub(/\r\n/, "\n"). # m$
|
51
|
+
gsub(/\t/, ' ') # Tabs to spaces
|
52
|
+
#gsub(/('|")(.*?)(\1)/) { $1 + CGI.escape( $2 ) + $1 } # Escape string values
|
53
|
+
# gsub(/\/\/.*\n/, ''). # Comments //
|
54
|
+
# gsub(/\/\*.*?\*\//m, '') # Comments /*
|
152
55
|
end
|
153
56
|
end
|
154
57
|
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; }
|