less 1.0.16 → 1.1.3
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/Rakefile +17 -6
- data/VERSION +1 -1
- data/bin/lessc +22 -0
- data/less.gemspec +6 -4
- data/lib/ext.rb +62 -0
- data/lib/less.rb +2 -64
- data/lib/less/command.rb +22 -6
- data/lib/less/engine.rb +7 -3
- data/lib/less/engine/grammar/common.tt +29 -0
- data/lib/less/engine/grammar/entity.tt +139 -0
- data/lib/less/engine/grammar/less.tt +271 -0
- data/lib/less/engine/nodes/function.rb +12 -9
- data/spec/css/parens.css +10 -1
- data/spec/less/parens.less +8 -2
- metadata +6 -4
- data/lib/less/engine/less.tt +0 -422
- data/lib/less/engine/parser.rb +0 -4296
data/Rakefile
CHANGED
@@ -61,19 +61,30 @@ end
|
|
61
61
|
|
62
62
|
begin
|
63
63
|
require 'lib/less'
|
64
|
+
require 'benchmark'
|
64
65
|
|
65
66
|
task :compile do
|
67
|
+
abort "compiling isn't necessary anymore."
|
66
68
|
puts "compiling #{LESS_GRAMMAR.split('/').last}..."
|
67
69
|
File.open(LESS_PARSER, 'w') {|f| f.write Treetop::Compiler::GrammarCompiler.new.ruby_source(LESS_GRAMMAR) }
|
68
70
|
end
|
69
71
|
|
70
72
|
task :benchmark do
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
73
|
+
#require 'profile'
|
74
|
+
puts "benchmarking... "
|
75
|
+
less, tree = File.read("spec/less/big.less"), nil
|
76
|
+
|
77
|
+
parse = Benchmark.measure do
|
78
|
+
tree = Less::Engine.new(less).parse(false)
|
79
|
+
end.total.round(2)
|
80
|
+
|
81
|
+
build = Benchmark.measure do
|
82
|
+
tree.build(Less::Node::Element.new)
|
83
|
+
end.total.round(2)
|
84
|
+
|
85
|
+
puts "parse: #{parse}s\nbuild: #{build}s"
|
86
|
+
puts "------------"
|
87
|
+
puts "total: #{parse + build}s"
|
77
88
|
end
|
78
89
|
end
|
79
90
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.1.3
|
data/bin/lessc
CHANGED
@@ -3,13 +3,23 @@
|
|
3
3
|
$:.unshift File.dirname(__FILE__) + "/../lib"
|
4
4
|
|
5
5
|
require 'optparse'
|
6
|
+
require 'rubygems'
|
6
7
|
require 'less'
|
7
8
|
|
9
|
+
begin
|
10
|
+
require 'growl'
|
11
|
+
rescue LoadError
|
12
|
+
Less::GROWL = false
|
13
|
+
else
|
14
|
+
Less::GROWL = true
|
15
|
+
end
|
16
|
+
|
8
17
|
# Argument defaults
|
9
18
|
options = {
|
10
19
|
:watch => false,
|
11
20
|
:compress => false,
|
12
21
|
:debug => false,
|
22
|
+
:growl => false
|
13
23
|
}
|
14
24
|
|
15
25
|
# Get arguments
|
@@ -22,6 +32,18 @@ opts = OptionParser.new do |o|
|
|
22
32
|
options[:watch] = true
|
23
33
|
end
|
24
34
|
|
35
|
+
# Growl
|
36
|
+
o.on("-g", "--growl", "growl notifications") do
|
37
|
+
if Less::GROWL && (Growl.installed? rescue false)
|
38
|
+
options[:growl] = true
|
39
|
+
elsif Less::GROWL
|
40
|
+
abort "Growl or 'growlnotify' wasn't found on your system."
|
41
|
+
else
|
42
|
+
abort "Growl gem not found, please install with: " +
|
43
|
+
"`sudo gem install visionmedia-growl -s http://gems.github.com`"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
25
47
|
# Compression needs a proper algorithm
|
26
48
|
#
|
27
49
|
# o.on("-x", "--compress", "compress css file") do
|
data/less.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{less}
|
5
|
-
s.version = "1.
|
5
|
+
s.version = "1.1.3"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["cloudhead"]
|
9
|
-
s.date = %q{2009-07-
|
9
|
+
s.date = %q{2009-07-27}
|
10
10
|
s.default_executable = %q{lessc}
|
11
11
|
s.description = %q{LESS is leaner CSS}
|
12
12
|
s.email = %q{self@cloudhead.net}
|
@@ -23,11 +23,14 @@ Gem::Specification.new do |s|
|
|
23
23
|
"VERSION",
|
24
24
|
"bin/lessc",
|
25
25
|
"less.gemspec",
|
26
|
+
"lib/ext.rb",
|
26
27
|
"lib/less.rb",
|
27
28
|
"lib/less/command.rb",
|
28
29
|
"lib/less/engine.rb",
|
29
30
|
"lib/less/engine/builder.rb",
|
30
|
-
"lib/less/engine/
|
31
|
+
"lib/less/engine/grammar/common.tt",
|
32
|
+
"lib/less/engine/grammar/entity.tt",
|
33
|
+
"lib/less/engine/grammar/less.tt",
|
31
34
|
"lib/less/engine/nodes.rb",
|
32
35
|
"lib/less/engine/nodes/element.rb",
|
33
36
|
"lib/less/engine/nodes/entity.rb",
|
@@ -36,7 +39,6 @@ Gem::Specification.new do |s|
|
|
36
39
|
"lib/less/engine/nodes/property.rb",
|
37
40
|
"lib/less/engine/nodes/ruleset.rb",
|
38
41
|
"lib/less/engine/nodes/selector.rb",
|
39
|
-
"lib/less/engine/parser.rb",
|
40
42
|
"lib/vendor/treetop/.gitignore",
|
41
43
|
"lib/vendor/treetop/LICENSE",
|
42
44
|
"lib/vendor/treetop/README",
|
data/lib/ext.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
module Treetop
|
2
|
+
module Runtime
|
3
|
+
class CompiledParser
|
4
|
+
def failure_message
|
5
|
+
return nil unless (tf = terminal_failures) && tf.size > 0
|
6
|
+
"on line #{failure_line}: expected " + (
|
7
|
+
tf.size == 1 ?
|
8
|
+
tf[0].expected_string :
|
9
|
+
"one of #{Less::YELLOW[tf.map {|f| f.expected_string }.uniq * ' ']}"
|
10
|
+
) +
|
11
|
+
" got #{Less::YELLOW[input[failure_index]]}" +
|
12
|
+
" after:\n\n#{input[index...failure_index]}\n"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Object
|
19
|
+
def verbose
|
20
|
+
$verbose = true
|
21
|
+
yield
|
22
|
+
ensure
|
23
|
+
$verbose = false
|
24
|
+
end
|
25
|
+
|
26
|
+
def tap
|
27
|
+
yield self
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def log(s = '') puts "* #{s}" if $verbose end
|
32
|
+
def log!(s = '') puts "* #{s}" end
|
33
|
+
def error(s) $stderr.puts s end
|
34
|
+
def error!(s) raise Exception, s end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Array
|
38
|
+
def dissolve
|
39
|
+
ary = flatten.compact
|
40
|
+
case ary.size
|
41
|
+
when 0 then []
|
42
|
+
when 1 then first
|
43
|
+
else ary
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def one?
|
48
|
+
size == 1
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Class
|
53
|
+
def to_sym
|
54
|
+
self.to_s.to_sym
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Symbol
|
59
|
+
def to_proc
|
60
|
+
proc {|obj, *args| obj.send(self, *args) }
|
61
|
+
end
|
62
|
+
end
|
data/lib/less.rb
CHANGED
@@ -7,8 +7,9 @@ require 'delegate'
|
|
7
7
|
|
8
8
|
LESS_ROOT = File.expand_path(File.dirname(__FILE__))
|
9
9
|
LESS_PARSER = File.join(LESS_ROOT, 'less', 'engine', 'parser.rb')
|
10
|
-
LESS_GRAMMAR = File.join(LESS_ROOT, 'less', 'engine', '
|
10
|
+
LESS_GRAMMAR = File.join(LESS_ROOT, 'less', 'engine', 'grammar')
|
11
11
|
|
12
|
+
require 'ext'
|
12
13
|
require 'less/command'
|
13
14
|
require 'less/engine'
|
14
15
|
|
@@ -30,66 +31,3 @@ module Less
|
|
30
31
|
Engine.new(less).to_css
|
31
32
|
end
|
32
33
|
end
|
33
|
-
|
34
|
-
module Treetop
|
35
|
-
module Runtime
|
36
|
-
class CompiledParser
|
37
|
-
def failure_message
|
38
|
-
return nil unless (tf = terminal_failures) && tf.size > 0
|
39
|
-
"on line #{failure_line}: expected " + (
|
40
|
-
tf.size == 1 ?
|
41
|
-
tf[0].expected_string :
|
42
|
-
"one of #{tf.map {|f| f.expected_string }.uniq * ' '}"
|
43
|
-
) +
|
44
|
-
" got `#{input[failure_index]}`" +
|
45
|
-
" after:\n\n#{input[index...failure_index]}\n"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
class Object
|
52
|
-
def verbose
|
53
|
-
$verbose = true
|
54
|
-
yield
|
55
|
-
ensure
|
56
|
-
$verbose = false
|
57
|
-
end
|
58
|
-
|
59
|
-
def tap
|
60
|
-
yield self
|
61
|
-
self
|
62
|
-
end
|
63
|
-
|
64
|
-
def log(s = '') puts "* #{s}" if $verbose end
|
65
|
-
def log!(s = '') puts "* #{s}" end
|
66
|
-
def error(s) $stderr.puts s end
|
67
|
-
def error!(s) raise Exception, s end
|
68
|
-
end
|
69
|
-
|
70
|
-
class Array
|
71
|
-
def dissolve
|
72
|
-
ary = flatten.compact
|
73
|
-
case ary.size
|
74
|
-
when 0 then []
|
75
|
-
when 1 then first
|
76
|
-
else ary
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def one?
|
81
|
-
size == 1
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
class Class
|
86
|
-
def to_sym
|
87
|
-
self.to_s.to_sym
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
class Symbol
|
92
|
-
def to_proc
|
93
|
-
proc {|obj, *args| obj.send(self, *args) }
|
94
|
-
end
|
95
|
-
end
|
data/lib/less/command.rb
CHANGED
@@ -1,4 +1,12 @@
|
|
1
1
|
module Less
|
2
|
+
ESC = "\033"
|
3
|
+
RESET = "#{ESC}[0m"
|
4
|
+
|
5
|
+
GREEN = lambda {|s| "#{ESC}[1;32m#{s}#{RESET}"}
|
6
|
+
RED = lambda {|s| "#{ESC}[1;31m#{s}#{RESET}"}
|
7
|
+
YELLOW = lambda {|s| "#{ESC}[1;33m#{s}#{RESET}"}
|
8
|
+
BOLD = lambda {|s| "#{ESC}[1m#{s}#{RESET}"}
|
9
|
+
|
2
10
|
class Command
|
3
11
|
attr_accessor :source, :destination, :options
|
4
12
|
|
@@ -59,19 +67,20 @@ module Less
|
|
59
67
|
File.open( @destination, "w" ) do |file|
|
60
68
|
file.write css
|
61
69
|
end
|
62
|
-
print "#{new ? '
|
70
|
+
print "#{GREEN['* ' + (new ? 'Created' : 'Updated')]} " +
|
71
|
+
"#{@destination.split('/').last}\n: " if watch?
|
63
72
|
rescue Errno::ENOENT => e
|
64
73
|
abort "#{e}"
|
65
74
|
rescue SyntaxError => e
|
66
|
-
err "#{e}\n", "
|
75
|
+
err "#{e}\n", "Syntax"
|
67
76
|
rescue MixedUnitsError => e
|
68
77
|
err "`#{e}` you're mixing units together! What do you expect?\n"
|
69
78
|
rescue PathError => e
|
70
79
|
err "`#{e}` was not found.\n", "Path"
|
71
80
|
rescue VariableNameError => e
|
72
|
-
err "
|
81
|
+
err "#{YELLOW[e]} is undefined.\n", "Name"
|
73
82
|
rescue MixinNameError => e
|
74
|
-
err "
|
83
|
+
err "#{YELLOW[e]} is undefined.\n", "Name"
|
75
84
|
else
|
76
85
|
true
|
77
86
|
end
|
@@ -84,7 +93,14 @@ module Less
|
|
84
93
|
|
85
94
|
def err s = '', type = ''
|
86
95
|
type = type.strip + ' ' unless type.empty?
|
87
|
-
print "!
|
96
|
+
print "#{RED["! #{type}Error"]}: #{s}"
|
97
|
+
if @options[:growl]
|
98
|
+
growl = Growl.new
|
99
|
+
growl.title = "LESS"
|
100
|
+
growl.message = "#{type}Error in #@source!"
|
101
|
+
growl.run
|
102
|
+
false
|
103
|
+
end
|
88
104
|
end
|
89
105
|
end
|
90
|
-
end
|
106
|
+
end
|
data/lib/less/engine.rb
CHANGED
@@ -6,7 +6,9 @@ require 'engine/nodes'
|
|
6
6
|
begin
|
7
7
|
require 'engine/parser'
|
8
8
|
rescue LoadError
|
9
|
-
Treetop.load LESS_GRAMMAR
|
9
|
+
Treetop.load File.join(LESS_GRAMMAR, 'common.tt')
|
10
|
+
Treetop.load File.join(LESS_GRAMMAR, 'entity.tt')
|
11
|
+
Treetop.load File.join(LESS_GRAMMAR, 'less.tt')
|
10
12
|
end
|
11
13
|
|
12
14
|
module Less
|
@@ -23,12 +25,14 @@ module Less
|
|
23
25
|
raise ArgumentError, "argument must be an instance of File or String!"
|
24
26
|
end
|
25
27
|
|
26
|
-
@parser =
|
28
|
+
@parser = StyleSheetParser.new
|
27
29
|
end
|
28
30
|
|
29
|
-
def parse env = Node::Element.new
|
31
|
+
def parse build = true, env = Node::Element.new
|
30
32
|
root = @parser.parse(self.prepare)
|
31
33
|
|
34
|
+
return root unless build
|
35
|
+
|
32
36
|
if root
|
33
37
|
@tree = root.build env.tap {|e| e.file = @path }
|
34
38
|
else
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Less
|
2
|
+
module StyleSheet
|
3
|
+
grammar Common
|
4
|
+
#
|
5
|
+
# Whitespace
|
6
|
+
#
|
7
|
+
rule s
|
8
|
+
[ ]*
|
9
|
+
end
|
10
|
+
|
11
|
+
rule S
|
12
|
+
[ ]+
|
13
|
+
end
|
14
|
+
|
15
|
+
rule ws
|
16
|
+
[\n ]*
|
17
|
+
end
|
18
|
+
|
19
|
+
rule WS
|
20
|
+
[\n ]+
|
21
|
+
end
|
22
|
+
|
23
|
+
# Non-space char
|
24
|
+
rule ns
|
25
|
+
![ ;\n] .
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
module Less
|
2
|
+
module StyleSheet
|
3
|
+
grammar Entity
|
4
|
+
#
|
5
|
+
# Entity: Any whitespace delimited token
|
6
|
+
#
|
7
|
+
rule entity
|
8
|
+
function / fonts / keyword / accessor / variable / literal / important
|
9
|
+
end
|
10
|
+
|
11
|
+
rule fonts
|
12
|
+
font family:(s ',' s font)+ {
|
13
|
+
def build
|
14
|
+
Node::FontFamily.new(all.map(&:build))
|
15
|
+
end
|
16
|
+
|
17
|
+
def all
|
18
|
+
[font] + family.elements.map {|f| f.font }
|
19
|
+
end
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
rule font
|
24
|
+
[a-zA-Z] [-a-zA-Z0-9]* {
|
25
|
+
def build
|
26
|
+
Node::Keyword.new(text_value)
|
27
|
+
end
|
28
|
+
} / string {
|
29
|
+
def build
|
30
|
+
Node::String.new(text_value)
|
31
|
+
end
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Tokens which don't need to be evaluated
|
37
|
+
#
|
38
|
+
rule literal
|
39
|
+
color / (dimension / [-a-z]+) '/' dimension {
|
40
|
+
def build
|
41
|
+
Node::Anonymous.new(text_value)
|
42
|
+
end
|
43
|
+
} / number unit {
|
44
|
+
def build
|
45
|
+
Node::Number.new(number.text_value, unit.text_value)
|
46
|
+
end
|
47
|
+
} / string {
|
48
|
+
def build
|
49
|
+
Node::String.new(text_value)
|
50
|
+
end
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
# !important
|
55
|
+
rule important
|
56
|
+
'!important' {
|
57
|
+
def build
|
58
|
+
Node::Keyword.new(text_value)
|
59
|
+
end
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# `blue`, `small`, `normal` etc.
|
65
|
+
#
|
66
|
+
rule keyword
|
67
|
+
[-a-zA-Z]+ !ns {
|
68
|
+
def build
|
69
|
+
Node::Keyword.new(text_value)
|
70
|
+
end
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# 'hello world' / "hello world"
|
76
|
+
#
|
77
|
+
rule string
|
78
|
+
"'" content:(!"'" . )* "'" {
|
79
|
+
def value
|
80
|
+
content.text_value
|
81
|
+
end
|
82
|
+
} / ["] content:(!["] . )* ["] {
|
83
|
+
def value
|
84
|
+
content.text_value
|
85
|
+
end
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Numbers & Units
|
91
|
+
#
|
92
|
+
rule dimension
|
93
|
+
number unit
|
94
|
+
end
|
95
|
+
|
96
|
+
rule number
|
97
|
+
'-'? [0-9]* '.' [0-9]+ / '-'? [0-9]+
|
98
|
+
end
|
99
|
+
|
100
|
+
rule unit
|
101
|
+
('px'/'em'/'pc'/'%'/'pt'/'cm'/'mm')?
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
# Color
|
106
|
+
#
|
107
|
+
rule color
|
108
|
+
'#' rgb {
|
109
|
+
def build
|
110
|
+
Node::Color.new(*rgb.build)
|
111
|
+
end
|
112
|
+
} / fn:(('hsl'/'rgb') 'a'?) arguments {
|
113
|
+
def build
|
114
|
+
Node::Function.new(fn.text_value, arguments.build.flatten)
|
115
|
+
end
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
# 00ffdd / 0fd
|
121
|
+
#
|
122
|
+
rule rgb
|
123
|
+
r:(hex hex) g:(hex hex) b:(hex hex) {
|
124
|
+
def build
|
125
|
+
[r.text_value, g.text_value, b.text_value]
|
126
|
+
end
|
127
|
+
} / r:hex g:hex b:hex {
|
128
|
+
def build
|
129
|
+
[r.text_value, g.text_value, b.text_value].map {|c| c * 2 }
|
130
|
+
end
|
131
|
+
}
|
132
|
+
end
|
133
|
+
|
134
|
+
rule hex
|
135
|
+
[a-fA-F0-9]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|