unboxed-less 1.2.12 → 1.2.19

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 CHANGED
@@ -36,7 +36,7 @@ LESS allows you to write CSS the way (I think) it was meant to, that is: with *v
36
36
  If you have CSS nightmares, just
37
37
  $ lessc style.less
38
38
 
39
- For more information, see you at [http://lesscss.org]
39
+ For more information, see you at <http://lesscss.org>
40
40
 
41
41
  People without whom this wouldn't have happened a.k.a *Credits*
42
42
  ---------------------------------------------------------------
data/Rakefile CHANGED
@@ -11,7 +11,6 @@ begin
11
11
  s.add_dependency('treetop', '>= 1.4.2')
12
12
  end
13
13
  Jeweler::GemcutterTasks.new
14
- Jeweler::RubyforgeTasks.new
15
14
  rescue LoadError
16
15
  puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
17
16
  end
@@ -31,29 +30,21 @@ end
31
30
  begin
32
31
  require 'lib/less'
33
32
  require 'benchmark'
34
-
33
+
35
34
  task :compile do
36
35
  abort "compiling isn't necessary anymore."
37
36
  puts "compiling #{LESS_GRAMMAR.split('/').last}..."
38
37
  File.open(LESS_PARSER, 'w') {|f| f.write Treetop::Compiler::GrammarCompiler.new.ruby_source(LESS_GRAMMAR) }
39
38
  end
40
-
39
+
41
40
  task :benchmark do
42
- #require 'profile'
43
- puts "benchmarking... "
44
- less, tree = File.read("spec/less/big.less"), nil
45
-
46
- parse = Benchmark.measure do
47
- tree = Less::Engine.new(less).parse(false)
48
- end.total.round(2)
49
-
50
- build = Benchmark.measure do
51
- tree.build(Less::Node::Element.new)
52
- end.total.round(2)
53
-
54
- puts "parse: #{parse}s\nbuild: #{build}s"
55
- puts "------------"
56
- puts "total: #{parse + build}s"
41
+ less = File.read("spec/less/big.less")
42
+ result = nil
43
+ Benchmark.bmbm do |b|
44
+ b.report("parse: ") { result = Less::Engine.new(less).parse(false) }
45
+ b.report("build: ") { result = result.build(Less::Node::Element.new) }
46
+ b.report("compile:") { result.to_css }
47
+ end
57
48
  end
58
49
  end
59
50
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.12
1
+ 1.2.19
data/bin/lessc CHANGED
@@ -20,19 +20,20 @@ options = {
20
20
  :compress => false,
21
21
  :debug => false,
22
22
  :growl => false,
23
- :color => true
23
+ :timestamps => false,
24
+ :color => $stdout.tty?
24
25
  }
25
26
 
26
27
  # Get arguments
27
28
  opts = OptionParser.new do |o|
28
29
  o.banner = "usage: lessc source [destination] [--watch]"
29
30
  o.separator ""
30
-
31
+
31
32
  # Watch mode
32
33
  o.on("-w", "--watch", "watch for changes") do
33
34
  options[:watch] = true
34
35
  end
35
-
36
+
36
37
  # Growl
37
38
  o.on("-g", "--growl", "growl notifications") do
38
39
  if Less::GROWL && (Growl.installed? rescue false)
@@ -44,18 +45,27 @@ opts = OptionParser.new do |o|
44
45
  "`sudo gem install visionmedia-growl -s http://gems.github.com`"
45
46
  end
46
47
  end
47
-
48
+
49
+ # Timestamps
50
+ o.on("-t", "--timestamps", "show timestamps in watch mode") do
51
+ options[:timestamps] = true
52
+ end
53
+
48
54
  # No color in output
49
55
  o.on("--no-color", "suppress color in output") do
50
56
  options[:color] = false
51
57
  end
52
-
58
+
59
+ o.on('--verbose', 'show success messages when using growl') do
60
+ options[:verbose] = true
61
+ end
62
+
53
63
  # Compression needs a proper algorithm
54
64
  #
55
65
  # o.on("-x", "--compress", "compress css file") do
56
66
  # options[:compress] = true
57
67
  # end
58
-
68
+
59
69
  o.separator ""
60
70
 
61
71
  # Help
@@ -63,7 +73,7 @@ opts = OptionParser.new do |o|
63
73
  puts opts
64
74
  exit
65
75
  end
66
-
76
+
67
77
  o.on_tail("-d", "--debug", "show full error messages") do
68
78
  options[:debug] = true
69
79
  end
@@ -1,5 +1,3 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
1
  require 'cgi'
4
2
  require 'treetop'
5
3
  require 'delegate'
@@ -8,24 +6,27 @@ LESS_ROOT = File.expand_path(File.dirname(__FILE__))
8
6
  LESS_PARSER = File.join(LESS_ROOT, 'less', 'engine', 'parser.rb')
9
7
  LESS_GRAMMAR = File.join(LESS_ROOT, 'less', 'engine', 'grammar')
10
8
 
11
- require 'ext'
9
+ $:.unshift File.dirname(__FILE__)
10
+
11
+ require 'less/ext'
12
12
  require 'less/command'
13
13
  require 'less/engine'
14
14
 
15
- module Less
15
+ module Less
16
16
  MixedUnitsError = Class.new(RuntimeError)
17
17
  PathError = Class.new(RuntimeError)
18
18
  VariableNameError = Class.new(NameError)
19
19
  MixinNameError = Class.new(NameError)
20
20
  SyntaxError = Class.new(RuntimeError)
21
21
  ImportError = Class.new(RuntimeError)
22
-
22
+ CompileError = Class.new(RuntimeError)
23
+
23
24
  $verbose = false
24
25
 
25
26
  def self.version
26
27
  File.read( File.join( File.dirname(__FILE__), '..', 'VERSION') ).strip
27
28
  end
28
-
29
+
29
30
  def self.parse less
30
31
  Engine.new(less).to_css
31
32
  end
@@ -36,6 +36,7 @@ module Less
36
36
 
37
37
  # File has changed
38
38
  if File.stat( @source ).mtime > File.stat( @destination ).mtime
39
+ print Time.now.strftime("%H:%M:%S -- ") if @options[:timestamps]
39
40
  print "Change detected... "
40
41
 
41
42
  # Loop until error is fixed
@@ -59,12 +60,16 @@ module Less
59
60
  File.open( @destination, "w" ) do |file|
60
61
  file.write css
61
62
  end
62
- print "* #{is_new ? 'Created' : 'Updated'} " +
63
- "#{@destination.split('/').last}\n: " if watch?
63
+
64
+ act, file = (is_new ? 'Created' : 'Updated'), @destination.split('/').last
65
+ print "* #{act} #{file}\n: " if watch?
66
+ Growl.notify "#{act} #{file}", :title => 'LESS' if @options[:growl] && @options[:verbose]
64
67
  rescue Errno::ENOENT => e
65
68
  abort "#{e}"
66
69
  rescue SyntaxError => e
67
70
  err "#{e}\n", "Syntax"
71
+ rescue CompileError => e
72
+ err "#{e}\n", "Compile"
68
73
  rescue MixedUnitsError => e
69
74
  err "`#{e}` you're mixing units together! What do you expect?\n", "Mixed Units"
70
75
  rescue PathError => e
@@ -5,15 +5,13 @@ require 'engine/nodes'
5
5
  begin
6
6
  require 'engine/parser'
7
7
  rescue LoadError
8
- Treetop.load File.join(LESS_GRAMMAR, 'common.tt')
9
- Treetop.load File.join(LESS_GRAMMAR, 'entity.tt')
10
8
  Treetop.load File.join(LESS_GRAMMAR, 'less.tt')
11
9
  end
12
10
 
13
11
  module Less
14
12
  class Engine
15
13
  attr_reader :css, :less
16
-
14
+
17
15
  def initialize obj, options = {}
18
16
  @less = if obj.is_a? File
19
17
  @path = File.dirname File.expand_path(obj.path)
@@ -23,16 +21,16 @@ module Less
23
21
  else
24
22
  raise ArgumentError, "argument must be an instance of File or String!"
25
23
  end
26
-
24
+
27
25
  @options = options
28
26
  @parser = StyleSheetParser.new
29
27
  end
30
-
28
+
31
29
  def parse build = true, env = Node::Element.new
32
30
  root = @parser.parse(self.prepare)
33
-
31
+
34
32
  return root unless build
35
-
33
+
36
34
  if root
37
35
  env.file = @path
38
36
  @tree = root.build env
@@ -43,13 +41,13 @@ module Less
43
41
  @tree
44
42
  end
45
43
  alias :to_tree :parse
46
-
44
+
47
45
  def to_css
48
46
  @css || @css = self.parse.group.to_css
49
47
  end
50
-
48
+
51
49
  def prepare
52
50
  @less.gsub(/\r\n/, "\n").gsub(/\t/, ' ')
53
51
  end
54
52
  end
55
- end
53
+ end
@@ -1,3 +1,5 @@
1
+ require 'grammar/common'
2
+
1
3
  module Less
2
4
  module StyleSheet
3
5
  grammar Entity
@@ -5,7 +7,7 @@ module Less
5
7
  # Entity: Any whitespace delimited token
6
8
  #
7
9
  rule entity
8
- url / function / accessor / keyword / variable / literal / font
10
+ url / alpha / function / accessor / keyword / variable / literal / font
9
11
  end
10
12
 
11
13
  rule fonts
@@ -125,6 +127,18 @@ module Less
125
127
  rule hex
126
128
  [a-fA-F0-9]
127
129
  end
130
+
131
+ #
132
+ # Special case for IE alpha filter
133
+ #
134
+ rule alpha
135
+ "alpha" '(' "opacity=" variable ')' {
136
+ def build env
137
+ var = variable.text_value
138
+ Node::Quoted.new(text_value.sub(var, env.nearest(var).evaluate.to_i.to_s))
139
+ end
140
+ }
141
+ end
128
142
  end
129
143
  end
130
- end
144
+ end
@@ -1,10 +1,13 @@
1
+ require 'grammar/common'
2
+ require 'grammar/entity'
3
+
1
4
  module Less
2
5
  grammar StyleSheet
3
6
  include Common
4
7
  include Entity
5
-
8
+
6
9
  rule primary
7
- (import / declaration / mixin / ruleset / comment)* {
10
+ (import / declaration / ruleset / mixin / comment)* {
8
11
  def build env = Less::Element.new
9
12
  elements.map do |e|
10
13
  e.build env if e.respond_to? :build
@@ -30,43 +33,41 @@ module Less
30
33
  end
31
34
  end
32
35
  # Mixin Declaration
33
- } / '.' name:[-a-zA-Z0-9_]+ ws parameters ws "{" ws primary ws "}" ws {
36
+ } / ws '.' name:[-a-zA-Z0-9_]+ ws parameters ws "{" ws primary ws "}" ws {
34
37
  def build env
35
38
  env << Node::Mixin::Def.new(name.text_value, parameters.build(env))
36
39
  primary.build env.last
37
- #env.last
38
40
  end
39
41
  }
40
42
  end
41
-
43
+
42
44
  rule mixin
43
45
  name:('.' [-a-zA-Z0-9_]+) args:(arguments) s ';' ws {
44
46
  def build env
45
- definition = env.nearest(name.text_value, :mixin) or raise MixinNameError, name.text_value
47
+ definition = env.nearest(name.text_value, :mixin) or raise MixinNameError, "#{name.text_value}() in #{env}"
46
48
  params = args.build.map {|i| Node::Expression.new i } unless args.empty?
47
49
  env << Node::Mixin::Call.new(definition, params || [], env)
48
50
  end
49
51
  } / ws selectors ';' ws {
50
- def build env
52
+ def build env
51
53
  selectors.build(env, :mixin).each do |path|
52
54
  rules = path.inject(env.root) do |current, node|
53
- current.descend(node.selector, node) or raise MixinNameError, selectors.text_value
55
+ current.descend(node.selector, node) or raise MixinNameError, "#{selectors.text_value} in #{env}"
54
56
  end.rules
55
57
  env.rules += rules
56
- #env.mix(rules)
57
58
  end
58
59
  end
59
- }
60
+ }
60
61
  end
61
-
62
+
62
63
  rule selectors
63
64
  ws selector tail:(s ',' ws selector)* ws {
64
- def build env, method
65
+ def build env, method
65
66
  all.map do |e|
66
67
  e.send(method, env) if e.respond_to? method
67
68
  end.compact
68
69
  end
69
-
70
+
70
71
  def all
71
72
  [selector] + tail.elements.map {|e| e.selector }
72
73
  end
@@ -84,7 +85,7 @@ module Less
84
85
  node.last
85
86
  end
86
87
  end
87
-
88
+
88
89
  def mixin env
89
90
  sel.elements.map do |e|
90
91
  Node::Element.new(e.element.text_value, e.select.text_value)
@@ -92,7 +93,7 @@ module Less
92
93
  end
93
94
  }
94
95
  end
95
-
96
+
96
97
  rule parameters
97
98
  '(' s ')' {
98
99
  def build env
@@ -104,7 +105,7 @@ module Less
104
105
  e.build(env)
105
106
  end
106
107
  end
107
-
108
+
108
109
  def all
109
110
  [parameter] + tail.elements.map {|e| e.parameter }
110
111
  end
@@ -118,7 +119,7 @@ module Less
118
119
  end
119
120
  }
120
121
  end
121
-
122
+
122
123
  rule import
123
124
  ws "@import" S url:(string / url) medias? s ';' ws {
124
125
  def build env
@@ -141,7 +142,7 @@ module Less
141
142
  def build env = nil
142
143
  Node::Function.new('url', value)
143
144
  end
144
-
145
+
145
146
  def value
146
147
  Node::Quoted.new CGI.unescape(path.text_value)
147
148
  end
@@ -157,10 +158,10 @@ module Less
157
158
  # height: 100%;
158
159
  #
159
160
  rule declaration
160
- ws name:(ident / variable) s ':' s expressions tail:(ws ',' ws expressions)* s (';'/ ws &'}') ws {
161
+ ws name:(ident / variable) s ':' ws expressions tail:(ws ',' ws expressions)* s (';'/ ws &'}') ws {
161
162
  def build env
162
163
  result = all.map {|e| e.build(env) if e.respond_to? :build }.compact
163
- env << (name.text_value =~ /^@/ ?
164
+ env << (name.text_value =~ /^@/ ?
164
165
  Node::Variable : Node::Property).new(name.text_value, result, env)
165
166
  end
166
167
 
@@ -190,12 +191,12 @@ module Less
190
191
  def build env = nil
191
192
  all.map {|e| e.build(env) if e.respond_to? :build }.compact
192
193
  end
193
-
194
+
194
195
  def all
195
196
  [expression] + tail.elements.map {|f| f.expression } + [i]
196
197
  end
197
198
  # Catch-all rule
198
- } / [-a-zA-Z0-9_%*/.&=:,#+? \[\]()]+ {
199
+ } / [-a-zA-Z0-9_.&*/=:,+? \[\]()#%]+ {
199
200
  def build env
200
201
  [Node::Anonymous.new(text_value)]
201
202
  end
@@ -218,7 +219,7 @@ module Less
218
219
  end
219
220
  }
220
221
  end
221
-
222
+
222
223
  # !important
223
224
  rule important
224
225
  s '!' s 'important' {
@@ -247,7 +248,15 @@ module Less
247
248
  # div / .class / #id / input[type="text"] / lang(fr)
248
249
  #
249
250
  rule element
250
- ((class / id / tag / ident) attribute* ('(' (selector / number) ')')?)+ / attribute+ / '@media' / '@font-face'
251
+ ((class / id / tag / ident) attribute* ('(' ([a-zA-Z]+ / pseudo_exp / selector / [0-9]+) ')')?)+
252
+ / attribute+ / '@media' / '@font-face'
253
+ end
254
+
255
+ #
256
+ # 4n+1
257
+ #
258
+ rule pseudo_exp
259
+ '-'? ([0-9]+)? 'n' ([-+] [0-9]+)?
251
260
  end
252
261
 
253
262
  #
@@ -293,7 +302,7 @@ module Less
293
302
  end
294
303
  }
295
304
  end
296
-
305
+
297
306
  #
298
307
  # Functions and arguments
299
308
  #
@@ -312,7 +321,7 @@ module Less
312
321
  e.build if e.respond_to? :build
313
322
  end.compact
314
323
  end
315
-
324
+
316
325
  def all
317
326
  [expressions] + tail.elements.map {|e| e.expressions }
318
327
  end
@@ -323,4 +332,4 @@ module Less
323
332
  }
324
333
  end
325
334
  end
326
- end
335
+ end