haml-edge 2.1.6 → 2.1.7

Sign up to get free protection for your applications and to get access to all the features.
data/EDGE_GEM_VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.6
1
+ 2.1.7
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.6
1
+ 2.1.7
data/lib/haml/exec.rb CHANGED
@@ -189,6 +189,12 @@ END
189
189
  opts.on('-I', '--load-path PATH', 'Add a sass import path.') do |path|
190
190
  @options[:for_engine][:load_paths] << path
191
191
  end
192
+ opts.on('--cache-location', 'The path to put cached Sass files. Defaults to .sass-cache.') do |loc|
193
+ @options[:for_engine][:cache_location] = path
194
+ end
195
+ opts.on('-C', '--no-cache', "Don't cache to sassc files.") do
196
+ @options[:for_engine][:cache] = false
197
+ end
192
198
  end
193
199
 
194
200
  def process_result
@@ -203,21 +209,23 @@ END
203
209
  input = @options[:input]
204
210
  output = @options[:output]
205
211
 
206
- template = input.read()
207
- input.close() if input.is_a? File
212
+ tree =
213
+ if input.is_a?(File) && !@options[:check_syntax]
214
+ ::Sass::Files.tree_for(input.path, @options[:for_engine])
215
+ else
216
+ # We don't need to do any special handling of @options[:check_syntax] here,
217
+ # because the Sass syntax checking happens alongside evaluation
218
+ # and evaluation doesn't actually evaluate any code anyway.
219
+ ::Sass::Engine.new(input.read(), @options[:for_engine]).to_tree
220
+ end
208
221
 
209
- begin
210
- # We don't need to do any special handling of @options[:check_syntax] here,
211
- # because the Sass syntax checking happens alongside evaluation
212
- # and evaluation doesn't actually evaluate any code anyway.
213
- result = ::Sass::Engine.new(template, @options[:for_engine]).render
214
- rescue ::Sass::SyntaxError => e
215
- raise e if @options[:trace]
216
- raise "Syntax error on line #{get_line e}: #{e.message}"
217
- end
222
+ input.close() if input.is_a?(File)
218
223
 
219
- output.write(result)
224
+ output.write(tree.render)
220
225
  output.close() if output.is_a? File
226
+ rescue ::Sass::SyntaxError => e
227
+ raise e if @options[:trace]
228
+ raise "Syntax error on line #{get_line e}: #{e.message}"
221
229
  end
222
230
  end
223
231
 
data/lib/sass.rb CHANGED
@@ -991,6 +991,9 @@ require 'haml/version'
991
991
  # or <tt>width = !main_width</tt>.
992
992
  # By default, either syntax is valid.
993
993
  #
994
+ # [<tt>:cache</tt>] Whether parsed Sass files should be cached,
995
+ # allowing greater speed. Defaults to true.
996
+ #
994
997
  # [<tt>:never_update</tt>] Whether the CSS files should never be updated,
995
998
  # even if the template file changes.
996
999
  # Setting this to true may give small performance gains.
@@ -1035,6 +1038,11 @@ require 'haml/version'
1035
1038
  # or <tt>MERB_ROOT + "/public/stylesheets"</tt>.
1036
1039
  # Only has meaning within Ruby on Rails or Merb.
1037
1040
  #
1041
+ # [<tt>:cache_location</tt>] The path where the cached <tt>sassc</tt> files should be written to.
1042
+ # Defaults to <tt>RAILS_ROOT + "/tmp/sass-cache"</tt>,
1043
+ # or <tt>MERB_ROOT + "/tmp/sass-cache"</tt>,
1044
+ # or just <tt>"./.sass-cache"</tt>.
1045
+ #
1038
1046
  # [<tt>:filename</tt>] The filename of the file being rendered.
1039
1047
  # This is used solely for reporting errors,
1040
1048
  # and is automatically set when using Rails or Merb.
data/lib/sass/css.rb CHANGED
@@ -75,7 +75,7 @@ module Sass
75
75
  private
76
76
 
77
77
  def build_tree
78
- root = Tree::Node.new({})
78
+ root = Tree::Node.new
79
79
  whitespace
80
80
  rules root
81
81
  expand_commas root
@@ -99,7 +99,7 @@ module Sass
99
99
  directive = rule[0] == ?@
100
100
 
101
101
  if directive
102
- node = Tree::DirectiveNode.new(rule, {})
102
+ node = Tree::DirectiveNode.new(rule)
103
103
  return node if @template.scan(/;/)
104
104
 
105
105
  assert_match /\{/
@@ -110,7 +110,7 @@ module Sass
110
110
  end
111
111
 
112
112
  assert_match /\{/
113
- node = Tree::RuleNode.new(rule, {})
113
+ node = Tree::RuleNode.new(rule)
114
114
  attributes(node)
115
115
  return node
116
116
  end
@@ -128,7 +128,7 @@ module Sass
128
128
  end
129
129
 
130
130
  assert_match /(;|(?=\}))/
131
- rule << Tree::AttrNode.new(name, value, {})
131
+ rule << Tree::AttrNode.new(name, value, nil)
132
132
  end
133
133
 
134
134
  assert_match /\}/
@@ -176,7 +176,7 @@ module Sass
176
176
  root.children.map! do |child|
177
177
  next child unless Tree::RuleNode === child && child.rules.first.include?(',')
178
178
  child.rules.first.split(',').map do |rule|
179
- node = Tree::RuleNode.new(rule.strip, {})
179
+ node = Tree::RuleNode.new(rule.strip)
180
180
  node.children = child.children
181
181
  node
182
182
  end
@@ -224,7 +224,7 @@ module Sass
224
224
  first, rest = child.rules.first.scan(/^(&?(?: .|[^ ])[^.#: \[]*)([.#: \[].*)?$/).first
225
225
 
226
226
  if current_rule.nil? || current_rule.rules.first != first
227
- current_rule = Tree::RuleNode.new(first, {})
227
+ current_rule = Tree::RuleNode.new(first)
228
228
  root << current_rule
229
229
  end
230
230
 
data/lib/sass/engine.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'strscan'
2
+ require 'digest/sha1'
2
3
  require 'sass/tree/node'
3
4
  require 'sass/tree/rule_node'
4
5
  require 'sass/tree/comment_node'
@@ -15,6 +16,7 @@ require 'sass/tree/file_node'
15
16
  require 'sass/environment'
16
17
  require 'sass/script'
17
18
  require 'sass/error'
19
+ require 'sass/files'
18
20
  require 'haml/shared'
19
21
 
20
22
  module Sass
@@ -76,6 +78,14 @@ module Sass
76
78
  # attributes of the form <tt>name: attr</tt>.
77
79
  ATTRIBUTE_ALTERNATE = /^([^\s=:"]+)(\s*=|:)(?:\s+|$)(.*)/
78
80
 
81
+ # The default options for Sass::Engine.
82
+ DEFAULT_OPTIONS = {
83
+ :style => :nested,
84
+ :load_paths => ['.'],
85
+ :cache => true,
86
+ :cache_location => './.sass-cache',
87
+ }.freeze
88
+
79
89
  # Creates a new instace of Sass::Engine that will compile the given
80
90
  # template string when <tt>render</tt> is called.
81
91
  # See README.rdoc for available options.
@@ -89,36 +99,23 @@ module Sass
89
99
  #++
90
100
  #
91
101
  def initialize(template, options={})
92
- @options = {
93
- :style => :nested,
94
- :load_paths => ['.']
95
- }.merge! options
102
+ @options = DEFAULT_OPTIONS.merge(options)
96
103
  @template = template
97
- @environment = Environment.new(nil, @options)
98
- @environment.set_var("important", Script::String.new("!important"))
99
104
  end
100
105
 
101
106
  # Processes the template and returns the result as a string.
102
107
  def render
103
- begin
104
- render_to_tree.perform(@environment).to_s
105
- rescue SyntaxError => err
106
- err.sass_line = @line unless err.sass_line
107
- unless err.sass_filename
108
- err.add_backtrace_entry(@options[:filename])
109
- end
110
- raise err
111
- end
108
+ to_tree.render
112
109
  end
113
110
 
114
111
  alias_method :to_css, :render
115
112
 
116
- protected
117
-
118
- def render_to_tree
119
- root = Tree::Node.new(@options)
113
+ def to_tree
114
+ root = Tree::Node.new
120
115
  append_children(root, tree(tabulate(@template)).first, true)
116
+ root.options = @options
121
117
  root
118
+ rescue SyntaxError => e; e.add_metadata(@options[:filename], @line)
122
119
  end
123
120
 
124
121
  private
@@ -246,7 +243,7 @@ END
246
243
  else
247
244
  # Support CSS3-style pseudo-elements,
248
245
  # which begin with ::
249
- Tree::RuleNode.new(line.text, @options)
246
+ Tree::RuleNode.new(line.text)
250
247
  end
251
248
  when Script::VARIABLE_CHAR
252
249
  parse_variable(line)
@@ -255,12 +252,12 @@ END
255
252
  when DIRECTIVE_CHAR
256
253
  parse_directive(parent, line, root)
257
254
  when ESCAPE_CHAR
258
- Tree::RuleNode.new(line.text[1..-1], @options)
255
+ Tree::RuleNode.new(line.text[1..-1])
259
256
  when MIXIN_DEFINITION_CHAR
260
257
  parse_mixin_definition(line)
261
258
  when MIXIN_INCLUDE_CHAR
262
259
  if line.text[1].nil?
263
- Tree::RuleNode.new(line.text, @options)
260
+ Tree::RuleNode.new(line.text)
264
261
  else
265
262
  parse_mixin_include(line, root)
266
263
  end
@@ -268,20 +265,12 @@ END
268
265
  if line.text =~ ATTRIBUTE_ALTERNATE_MATCHER
269
266
  parse_attribute(line, ATTRIBUTE_ALTERNATE)
270
267
  else
271
- Tree::RuleNode.new(line.text, @options)
268
+ Tree::RuleNode.new(line.text)
272
269
  end
273
270
  end
274
271
  end
275
272
 
276
273
  def parse_attribute(line, attribute_regx)
277
- if @options[:attribute_syntax] == :normal &&
278
- attribute_regx == ATTRIBUTE_ALTERNATE
279
- raise SyntaxError.new("Illegal attribute syntax: can't use alternate syntax when :attribute_syntax => :normal is set.")
280
- elsif @options[:attribute_syntax] == :alternate &&
281
- attribute_regx == ATTRIBUTE
282
- raise SyntaxError.new("Illegal attribute syntax: can't use normal syntax when :attribute_syntax => :alternate is set.")
283
- end
284
-
285
274
  name, eq, value = line.text.scan(attribute_regx)[0]
286
275
 
287
276
  if name.nil? || value.nil?
@@ -292,7 +281,7 @@ END
292
281
  else
293
282
  value
294
283
  end
295
- Tree::AttrNode.new(name, expr, @options)
284
+ Tree::AttrNode.new(name, expr, attribute_regx == ATTRIBUTE ? :old : :new)
296
285
  end
297
286
 
298
287
  def parse_variable(line)
@@ -300,14 +289,14 @@ END
300
289
  raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath variable declarations.", @line + 1) unless line.children.empty?
301
290
  raise SyntaxError.new("Invalid variable: \"#{line.text}\".", @line) unless name && value
302
291
 
303
- Tree::VariableNode.new(name, parse_script(value, :offset => line.offset + line.text.index(value)), op == '||=', @options)
292
+ Tree::VariableNode.new(name, parse_script(value, :offset => line.offset + line.text.index(value)), op == '||=')
304
293
  end
305
294
 
306
295
  def parse_comment(line)
307
296
  if line[1] == CSS_COMMENT_CHAR || line[1] == SASS_COMMENT_CHAR
308
- Tree::CommentNode.new(line, @options.merge(:silent => (line[1] == SASS_COMMENT_CHAR)))
297
+ Tree::CommentNode.new(line, line[1] == SASS_COMMENT_CHAR)
309
298
  else
310
- Tree::RuleNode.new(line, @options)
299
+ Tree::RuleNode.new(line)
311
300
  end
312
301
  end
313
302
 
@@ -326,17 +315,17 @@ END
326
315
  parse_else(parent, line, value)
327
316
  elsif directive == "while"
328
317
  raise SyntaxError.new("Invalid while directive '@while': expected expression.") unless value
329
- Tree::WhileNode.new(parse_script(value, :offset => offset), @options)
318
+ Tree::WhileNode.new(parse_script(value, :offset => offset))
330
319
  elsif directive == "if"
331
320
  raise SyntaxError.new("Invalid if directive '@if': expected expression.") unless value
332
- Tree::IfNode.new(parse_script(value, :offset => offset), @options)
321
+ Tree::IfNode.new(parse_script(value, :offset => offset))
333
322
  elsif directive == "debug"
334
323
  raise SyntaxError.new("Invalid debug directive '@debug': expected expression.") unless value
335
324
  raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath debug directives.", @line + 1) unless line.children.empty?
336
325
  offset = line.offset + line.text.index(value).to_i
337
- Tree::DebugNode.new(parse_script(value, :offset => offset), @options)
326
+ Tree::DebugNode.new(parse_script(value, :offset => offset))
338
327
  else
339
- Tree::DirectiveNode.new(line.text, @options)
328
+ Tree::DirectiveNode.new(line.text)
340
329
  end
341
330
  end
342
331
 
@@ -357,7 +346,7 @@ END
357
346
 
358
347
  parsed_from = parse_script(from_expr, :offset => line.offset + line.text.index(from_expr))
359
348
  parsed_to = parse_script(to_expr, :offset => line.offset + line.text.index(to_expr))
360
- Tree::ForNode.new(var[1..-1], parsed_from, parsed_to, to_name == 'to', @options)
349
+ Tree::ForNode.new(var[1..-1], parsed_from, parsed_to, to_name == 'to')
361
350
  end
362
351
 
363
352
  def parse_else(parent, line, text)
@@ -371,7 +360,7 @@ END
371
360
  expr = parse_script($1, :offset => line.offset + line.text.index($1))
372
361
  end
373
362
 
374
- node = Tree::IfNode.new(expr, @options)
363
+ node = Tree::IfNode.new(expr)
375
364
  append_children(node, line.children, false)
376
365
  previous.add_else node
377
366
  nil
@@ -406,7 +395,7 @@ END
406
395
  default = parse_script(default, :offset => line.offset + line.text.index(default)) if default
407
396
  [arg[1..-1], default]
408
397
  end
409
- Tree::MixinDefNode.new(name, args, @options)
398
+ Tree::MixinDefNode.new(name, args)
410
399
  end
411
400
 
412
401
  def parse_mixin_include(line, root)
@@ -416,7 +405,7 @@ END
416
405
  raise SyntaxError.new("Invalid mixin include \"#{line.text}\".", @line) if name.nil? || args.nil?
417
406
  args.each {|a| raise SyntaxError.new("Mixin arguments can't be empty.", @line) if a.empty?}
418
407
 
419
- Tree::MixinNode.new(name, args.map {|s| parse_script(s, :offset => line.offset + line.text.index(s))}, @options)
408
+ Tree::MixinNode.new(name, args.map {|s| parse_script(s, :offset => line.offset + line.text.index(s))})
420
409
  end
421
410
 
422
411
  def parse_script(script, options = {})
@@ -436,60 +425,15 @@ END
436
425
  engine = nil
437
426
 
438
427
  begin
439
- filename = self.class.find_file_to_import(filename, import_paths)
428
+ filename = Sass::Files.find_file_to_import(filename, import_paths)
440
429
  rescue Exception => e
441
430
  raise SyntaxError.new(e.message, @line)
442
431
  end
443
432
 
444
- next Tree::DirectiveNode.new("@import url(#{filename})", @options) if filename =~ /\.css$/
433
+ next Tree::DirectiveNode.new("@import url(#{filename})") if filename =~ /\.css$/
445
434
 
446
- File.open(filename) do |file|
447
- new_options = @options.dup
448
- new_options[:filename] = filename
449
- engine = Sass::Engine.new(file.read, new_options)
450
- end
451
-
452
- begin
453
- root = engine.render_to_tree
454
- rescue Sass::SyntaxError => err
455
- err.add_backtrace_entry(filename)
456
- raise err
457
- end
458
- Tree::FileNode.new(filename, root.children, @options)
435
+ Tree::FileNode.new(filename)
459
436
  end.flatten
460
437
  end
461
-
462
- def self.find_file_to_import(filename, load_paths)
463
- was_sass = false
464
- original_filename = filename
465
-
466
- if filename[-5..-1] == ".sass"
467
- filename = filename[0...-5]
468
- was_sass = true
469
- elsif filename[-4..-1] == ".css"
470
- return filename
471
- end
472
-
473
- new_filename = find_full_path("#{filename}.sass", load_paths)
474
-
475
- return new_filename if new_filename
476
- return filename + '.css' unless was_sass
477
- raise SyntaxError.new("File to import not found or unreadable: #{original_filename}.", @line)
478
- end
479
-
480
- def self.find_full_path(filename, load_paths)
481
- segments = filename.split(File::SEPARATOR)
482
- segments.push "_#{segments.pop}"
483
- partial_name = segments.join(File::SEPARATOR)
484
- load_paths.each do |path|
485
- [partial_name, filename].each do |name|
486
- full_path = File.join(path, name)
487
- if File.readable?(full_path)
488
- return full_path
489
- end
490
- end
491
- end
492
- nil
493
- end
494
438
  end
495
439
  end
@@ -1,12 +1,14 @@
1
1
  module Sass
2
2
  class Environment
3
3
  attr_reader :parent
4
+ attr_writer :options
4
5
 
5
- def initialize(parent = nil, options = nil)
6
+ def initialize(parent = nil)
6
7
  @vars = {}
7
8
  @mixins = {}
8
9
  @parent = parent
9
- @options = options
10
+
11
+ set_var("important", Script::String.new("!important")) unless @parent
10
12
  end
11
13
 
12
14
  def options
data/lib/sass/error.rb CHANGED
@@ -19,6 +19,13 @@ module Sass
19
19
  @sass_line = lineno
20
20
  end
21
21
 
22
+ # Add information about the filename and line on which the error was raised.
23
+ def add_metadata(filename, line)
24
+ self.sass_line ||= line
25
+ add_backtrace_entry(filename) unless sass_filename
26
+ raise self
27
+ end
28
+
22
29
  # Adds a properly formatted entry to the exception's backtrace.
23
30
  # +filename+ should be the file in which the error occurred,
24
31
  # if applicable (defaults to "(sass)").
data/lib/sass/files.rb ADDED
@@ -0,0 +1,100 @@
1
+ require 'digest/sha1'
2
+
3
+ module Sass
4
+ # This module contains various bits of functionality
5
+ # related to finding and caching Sass files.
6
+ module Files
7
+ extend self
8
+
9
+ def tree_for(filename, options)
10
+ options = Sass::Engine::DEFAULT_OPTIONS.merge(options)
11
+ text = File.read(filename)
12
+
13
+ if options[:cache]
14
+ compiled_filename = sassc_filename(filename, options)
15
+ sha = Digest::SHA1.hexdigest(text)
16
+
17
+ if dump = try_to_read_sassc(filename, compiled_filename, sha)
18
+ return Marshal.load(dump)
19
+ end
20
+ end
21
+
22
+ engine = Sass::Engine.new(text, options.merge(:filename => filename))
23
+
24
+ begin
25
+ root = engine.to_tree
26
+ rescue Sass::SyntaxError => err
27
+ err.add_backtrace_entry(filename)
28
+ raise err
29
+ end
30
+
31
+ try_to_write_sassc(root, compiled_filename, sha, options) if options[:cache]
32
+
33
+ root
34
+ end
35
+
36
+ def find_file_to_import(filename, load_paths)
37
+ was_sass = false
38
+ original_filename = filename
39
+
40
+ if filename[-5..-1] == ".sass"
41
+ filename = filename[0...-5]
42
+ was_sass = true
43
+ elsif filename[-4..-1] == ".css"
44
+ return filename
45
+ end
46
+
47
+ new_filename = find_full_path("#{filename}.sass", load_paths)
48
+
49
+ return new_filename if new_filename
50
+ return filename + '.css' unless was_sass
51
+ raise SyntaxError.new("File to import not found or unreadable: #{original_filename}.", @line)
52
+ end
53
+
54
+ private
55
+
56
+ def sassc_filename(filename, options)
57
+ File.join(options[:cache_location],
58
+ Digest::SHA1.hexdigest(File.dirname(File.expand_path(filename))),
59
+ File.basename(filename) + 'c')
60
+ end
61
+
62
+ def try_to_read_sassc(filename, compiled_filename, sha)
63
+ return unless File.readable?(compiled_filename)
64
+
65
+ File.open(compiled_filename) do |f|
66
+ return unless f.readline("\n").strip == Sass::VERSION
67
+ return unless f.readline("\n").strip == sha
68
+ return f.read
69
+ end
70
+ end
71
+
72
+ def try_to_write_sassc(root, compiled_filename, sha, options)
73
+ return unless File.writable?(File.dirname(options[:cache_location]))
74
+ return if File.exists?(options[:cache_location]) && !File.writable?(options[:cache_location])
75
+ return if File.exists?(File.dirname(compiled_filename)) && !File.writable?(File.dirname(compiled_filename))
76
+ return if File.exists?(compiled_filename) && !File.writable?(compiled_filename)
77
+ FileUtils.mkdir_p(File.dirname(compiled_filename))
78
+ File.open(compiled_filename, "w") do |f|
79
+ f.puts(Sass::VERSION)
80
+ f.puts(sha)
81
+ f.write(Marshal.dump(root))
82
+ end
83
+ end
84
+
85
+ def find_full_path(filename, load_paths)
86
+ segments = filename.split(File::SEPARATOR)
87
+ segments.push "_#{segments.pop}"
88
+ partial_name = segments.join(File::SEPARATOR)
89
+ load_paths.each do |path|
90
+ [partial_name, filename].each do |name|
91
+ full_path = File.join(path, name)
92
+ if File.readable?(full_path)
93
+ return full_path
94
+ end
95
+ end
96
+ end
97
+ nil
98
+ end
99
+ end
100
+ end
data/lib/sass/plugin.rb CHANGED
@@ -70,9 +70,8 @@ module Sass
70
70
  File.delete(css) if File.exists?(css)
71
71
 
72
72
  filename = template_filename(name, template_location)
73
- engine = Engine.new(File.read(filename), engine_options(:css_filename => css, :filename => filename))
74
73
  result = begin
75
- engine.render
74
+ Sass::Files.tree_for(filename, engine_options(:css_filename => css, :filename => filename)).render
76
75
  rescue Exception => e
77
76
  exception_string(e)
78
77
  end
@@ -193,7 +192,7 @@ END
193
192
  def dependencies(filename)
194
193
  File.readlines(filename).grep(/^@import /).map do |line|
195
194
  line[8..-1].split(',').map do |inc|
196
- Sass::Engine.find_file_to_import(inc.strip, [File.dirname(filename)] + load_paths)
195
+ Sass::Files.find_file_to_import(inc.strip, [File.dirname(filename)] + load_paths)
197
196
  end
198
197
  end.flatten.grep(/\.sass$/)
199
198
  end
@@ -10,10 +10,11 @@ unless defined?(Sass::MERB_LOADED)
10
10
  env = Merb.environment
11
11
  end
12
12
 
13
- Sass::Plugin.options.merge!(:template_location => root + '/public/stylesheets/sass',
14
- :css_location => root + '/public/stylesheets',
15
- :always_check => env != "production",
16
- :full_exception => env != "production")
13
+ Sass::Plugin.options.merge!(:template_location => root + '/public/stylesheets/sass',
14
+ :css_location => root + '/public/stylesheets',
15
+ :cache_location => root + '/tmp/sass-cache',
16
+ :always_check => env != "production",
17
+ :full_exception => env != "production")
17
18
  config = Merb::Plugins.config[:sass] || Merb::Plugins.config["sass"] || {}
18
19
 
19
20
  if defined? config.symbolize_keys!
@@ -1,10 +1,11 @@
1
1
  unless defined?(Sass::RAILS_LOADED)
2
2
  Sass::RAILS_LOADED = true
3
3
 
4
- Sass::Plugin.options.merge!(:template_location => RAILS_ROOT + '/public/stylesheets/sass',
5
- :css_location => RAILS_ROOT + '/public/stylesheets',
6
- :always_check => RAILS_ENV != "production",
7
- :full_exception => RAILS_ENV != "production")
4
+ Sass::Plugin.options.merge!(:template_location => RAILS_ROOT + '/public/stylesheets/sass',
5
+ :css_location => RAILS_ROOT + '/public/stylesheets',
6
+ :cache_location => RAILS_ROOT + '/tmp/sass-cache',
7
+ :always_check => RAILS_ENV != "production",
8
+ :full_exception => RAILS_ENV != "production")
8
9
 
9
10
  # :stopdoc:
10
11
  module ActionController
@@ -2,10 +2,11 @@ module Sass::Tree
2
2
  class AttrNode < Node
3
3
  attr_accessor :name, :value
4
4
 
5
- def initialize(name, value, options)
5
+ def initialize(name, value, attr_syntax)
6
6
  @name = name
7
7
  @value = value
8
- super(options)
8
+ @attr_syntax = attr_syntax
9
+ super()
9
10
  end
10
11
 
11
12
  def ==(other)
@@ -13,6 +14,12 @@ module Sass::Tree
13
14
  end
14
15
 
15
16
  def to_s(tabs, parent_name = nil)
17
+ if @options[:attribute_syntax] == :normal && @attr_syntax == :new
18
+ raise Sass::SyntaxError.new("Illegal attribute syntax: can't use alternate syntax when :attribute_syntax => :normal is set.")
19
+ elsif @options[:attribute_syntax] == :alternate && @attr_syntax == :old
20
+ raise Sass::SyntaxError.new("Illegal attribute syntax: can't use normal syntax when :attribute_syntax => :alternate is set.")
21
+ end
22
+
16
23
  if value[-1] == ?;
17
24
  raise Sass::SyntaxError.new("Invalid attribute: #{declaration.dump} (This isn't CSS!).", @line)
18
25
  end
@@ -23,7 +30,7 @@ module Sass::Tree
23
30
  raise Sass::SyntaxError.new("Invalid attribute: #{declaration.dump}.", @line)
24
31
  end
25
32
 
26
- join_string = case @style
33
+ join_string = case style
27
34
  when :compact; ' '
28
35
  when :compressed; ''
29
36
  else "\n"
@@ -31,7 +38,7 @@ module Sass::Tree
31
38
  spaces = ' ' * (tabs - 1)
32
39
  to_return = ''
33
40
  if !value.empty?
34
- to_return << "#{spaces}#{real_name}:#{@style == :compressed ? '' : ' '}#{value};#{join_string}"
41
+ to_return << "#{spaces}#{real_name}:#{style == :compressed ? '' : ' '}#{value};#{join_string}"
35
42
  end
36
43
 
37
44
  children.each do |kid|
@@ -39,7 +46,7 @@ module Sass::Tree
39
46
  to_return << kid.to_s(tabs, real_name) << join_string
40
47
  end
41
48
 
42
- (@style == :compressed && parent_name) ? to_return : to_return[0...-1]
49
+ (style == :compressed && parent_name) ? to_return : to_return[0...-1]
43
50
  end
44
51
 
45
52
  protected
@@ -4,19 +4,17 @@ module Sass::Tree
4
4
  class CommentNode < Node
5
5
  attr_accessor :lines
6
6
  attr_accessor :value
7
+ attr_accessor :silent
7
8
 
8
- def initialize(value, options)
9
+ def initialize(value, silent)
9
10
  @lines = []
10
11
  @value = value[2..-1].strip
11
- super(options)
12
+ @silent = silent
13
+ super()
12
14
  end
13
15
 
14
16
  def ==(other)
15
- self.class == other.class && value == other.value && lines == other.lines
16
- end
17
-
18
- def silent?
19
- !!@options[:silent]
17
+ self.class == other.class && value == other.value && silent == other.silent && lines == other.lines
20
18
  end
21
19
 
22
20
  def to_s(tabs = 0, parent_name = nil)
@@ -24,17 +22,17 @@ module Sass::Tree
24
22
 
25
23
  spaces = ' ' * (tabs - 1)
26
24
  spaces + "/* " + ([value] + lines.map {|l| l.text}).
27
- map{|l| l.sub(%r{ ?\*/ *$},'')}.join(@style == :compact ? ' ' : "\n#{spaces} * ") + " */"
25
+ map{|l| l.sub(%r{ ?\*/ *$},'')}.join(style == :compact ? ' ' : "\n#{spaces} * ") + " */"
28
26
  end
29
27
 
30
28
  def invisible?
31
- @style == :compressed || silent?
29
+ style == :compressed || @silent
32
30
  end
33
31
 
34
32
  protected
35
33
 
36
34
  def _perform(environment)
37
- return [] if silent?
35
+ return [] if @silent
38
36
  self
39
37
  end
40
38
  end
@@ -1,9 +1,9 @@
1
1
  module Sass
2
2
  module Tree
3
3
  class DebugNode < Node
4
- def initialize(expr, options)
4
+ def initialize(expr)
5
5
  @expr = expr
6
- super(options)
6
+ super()
7
7
  end
8
8
 
9
9
  protected
@@ -2,25 +2,25 @@ module Sass::Tree
2
2
  class DirectiveNode < Node
3
3
  attr_accessor :value
4
4
 
5
- def initialize(value, options)
5
+ def initialize(value)
6
6
  @value = value
7
- super(options)
7
+ super()
8
8
  end
9
9
 
10
10
  def to_s(tabs)
11
11
  if children.empty?
12
12
  value + ";"
13
13
  else
14
- result = if @style == :compressed
14
+ result = if style == :compressed
15
15
  "#{value}{"
16
16
  else
17
- "#{' ' * (tabs - 1)}#{value} {" + (@style == :compact ? ' ' : "\n")
17
+ "#{' ' * (tabs - 1)}#{value} {" + (style == :compact ? ' ' : "\n")
18
18
  end
19
19
  was_attr = false
20
20
  first = true
21
21
  children.each do |child|
22
22
  next if child.invisible?
23
- if @style == :compact
23
+ if style == :compact
24
24
  if child.is_a?(AttrNode)
25
25
  result << "#{child.to_s(first || was_attr ? 1 : tabs + 1)} "
26
26
  else
@@ -33,17 +33,17 @@ module Sass::Tree
33
33
  end
34
34
  was_attr = child.is_a?(AttrNode)
35
35
  first = false
36
- elsif @style == :compressed
36
+ elsif style == :compressed
37
37
  result << (was_attr ? ";#{child.to_s(1)}" : child.to_s(1))
38
38
  was_attr = child.is_a?(AttrNode)
39
39
  else
40
40
  result << child.to_s(tabs + 1) + "\n"
41
41
  end
42
42
  end
43
- result.rstrip + if @style == :compressed
43
+ result.rstrip + if style == :compressed
44
44
  "}"
45
45
  else
46
- (@style == :expanded ? "\n" : " ") + "}\n"
46
+ (style == :expanded ? "\n" : " ") + "}\n"
47
47
  end
48
48
  end
49
49
  end
@@ -1,10 +1,9 @@
1
1
  module Sass
2
2
  module Tree
3
3
  class FileNode < Node
4
- def initialize(filename, children, options)
4
+ def initialize(filename)
5
5
  @filename = filename
6
- super(options)
7
- self.children = children
6
+ super()
8
7
  end
9
8
 
10
9
  def to_s(*args)
@@ -17,6 +16,7 @@ module Sass
17
16
  protected
18
17
 
19
18
  def perform!(environment)
19
+ self.children = Sass::Files.tree_for(filename, @options).children
20
20
  self.children = perform_children(environment)
21
21
  rescue Sass::SyntaxError => e
22
22
  e.add_backtrace_entry(@filename)
@@ -2,12 +2,12 @@ require 'sass/tree/node'
2
2
 
3
3
  module Sass::Tree
4
4
  class ForNode < Node
5
- def initialize(var, from, to, exclusive, options)
5
+ def initialize(var, from, to, exclusive)
6
6
  @var = var
7
7
  @from = from
8
8
  @to = to
9
9
  @exclusive = exclusive
10
- super(options)
10
+ super()
11
11
  end
12
12
 
13
13
  protected
@@ -4,10 +4,10 @@ module Sass::Tree
4
4
  class IfNode < Node
5
5
  attr_accessor :else
6
6
 
7
- def initialize(expr, options)
7
+ def initialize(expr)
8
8
  @expr = expr
9
9
  @last_else = self
10
- super(options)
10
+ super()
11
11
  end
12
12
 
13
13
  def add_else(node)
@@ -15,6 +15,11 @@ module Sass::Tree
15
15
  @last_else = node
16
16
  end
17
17
 
18
+ def options=(options)
19
+ super
20
+ self.else.options = options if self.else
21
+ end
22
+
18
23
  protected
19
24
 
20
25
  def _perform(environment)
@@ -1,10 +1,10 @@
1
1
  module Sass
2
2
  module Tree
3
3
  class MixinDefNode < Node
4
- def initialize(name, args, options)
4
+ def initialize(name, args)
5
5
  @name = name
6
6
  @args = args
7
- super(options)
7
+ super()
8
8
  end
9
9
 
10
10
  private
@@ -2,10 +2,10 @@ require 'sass/tree/node'
2
2
 
3
3
  module Sass::Tree
4
4
  class MixinNode < Node
5
- def initialize(name, args, options)
5
+ def initialize(name, args)
6
6
  @name = name
7
7
  @args = args
8
- super(options)
8
+ super()
9
9
  end
10
10
 
11
11
  protected
@@ -3,14 +3,22 @@ module Sass
3
3
  class Node
4
4
  attr_accessor :children
5
5
  attr_accessor :line
6
- attr_accessor :filename
6
+ attr_writer :filename
7
+ attr_reader :options
7
8
 
8
- def initialize(options)
9
- @options = options
10
- @style = options[:style]
9
+ def initialize
11
10
  @children = []
12
11
  end
13
12
 
13
+ def options=(options)
14
+ children.each {|c| c.options = options}
15
+ @options = options
16
+ end
17
+
18
+ def filename
19
+ @filename || @options[:filename]
20
+ end
21
+
14
22
  def <<(child)
15
23
  if msg = invalid_child?(child)
16
24
  raise Sass::SyntaxError.new(msg, child.line)
@@ -27,6 +35,10 @@ module Sass
27
35
  self.class == other.class && other.children == children
28
36
  end
29
37
 
38
+ def render
39
+ perform(Environment.new).to_s
40
+ end
41
+
30
42
  def invisible?; false; end
31
43
 
32
44
  def to_s
@@ -37,17 +49,21 @@ module Sass
37
49
  else
38
50
  next if child.invisible?
39
51
  child_str = child.to_s(1)
40
- result << child_str + (@style == :compressed ? '' : "\n")
52
+ result << child_str + (style == :compressed ? '' : "\n")
41
53
  end
42
54
  end
43
- @style == :compressed ? result+"\n" : result[0...-1]
55
+ style == :compressed ? result+"\n" : result[0...-1]
56
+ rescue Sass::SyntaxError => e; e.add_metadata(filename, line)
44
57
  end
45
58
 
46
59
  def perform(environment)
60
+ environment.options = @options if self.class == Tree::Node
47
61
  _perform(environment)
48
- rescue Sass::SyntaxError => e
49
- e.sass_line ||= line
50
- raise e
62
+ rescue Sass::SyntaxError => e; e.add_metadata(filename, line)
63
+ end
64
+
65
+ def style
66
+ @options[:style]
51
67
  end
52
68
 
53
69
  protected
@@ -7,9 +7,9 @@ module Sass::Tree
7
7
 
8
8
  attr_accessor :rules, :parsed_rules
9
9
 
10
- def initialize(rule, options)
10
+ def initialize(rule)
11
11
  @rules = [rule]
12
- super(options)
12
+ super()
13
13
  end
14
14
 
15
15
  def ==(other)
@@ -30,10 +30,10 @@ module Sass::Tree
30
30
  attributes = []
31
31
  sub_rules = []
32
32
 
33
- rule_separator = @style == :compressed ? ',' : ', '
34
- line_separator = [:nested, :expanded].include?(@style) ? ",\n" : rule_separator
33
+ rule_separator = style == :compressed ? ',' : ', '
34
+ line_separator = [:nested, :expanded].include?(style) ? ",\n" : rule_separator
35
35
  rule_indent = ' ' * (tabs - 1)
36
- per_rule_indent, total_indent = [:nested, :expanded].include?(@style) ? [rule_indent, ''] : ['', rule_indent]
36
+ per_rule_indent, total_indent = [:nested, :expanded].include?(style) ? [rule_indent, ''] : ['', rule_indent]
37
37
 
38
38
  total_rule = total_indent + resolved_rules.map do |line|
39
39
  per_rule_indent + line.join(rule_separator)
@@ -52,7 +52,7 @@ module Sass::Tree
52
52
  if !attributes.empty?
53
53
  old_spaces = ' ' * (tabs - 1)
54
54
  spaces = ' ' * tabs
55
- if @options[:line_comments] && @style != :compressed
55
+ if @options[:line_comments] && style != :compressed
56
56
  to_return << "#{old_spaces}/* line #{line}"
57
57
 
58
58
  if filename
@@ -71,20 +71,20 @@ module Sass::Tree
71
71
  to_return << " */\n"
72
72
  end
73
73
 
74
- if @style == :compact
74
+ if style == :compact
75
75
  attributes = attributes.map { |a| a.to_s(1) }.select{|a| a && a.length > 0}.join(' ')
76
76
  to_return << "#{total_rule} { #{attributes} }\n"
77
- elsif @style == :compressed
77
+ elsif style == :compressed
78
78
  attributes = attributes.map { |a| a.to_s(1) }.select{|a| a && a.length > 0}.join(';')
79
79
  to_return << "#{total_rule}{#{attributes}}"
80
80
  else
81
81
  attributes = attributes.map { |a| a.to_s(tabs + 1) }.select{|a| a && a.length > 0}.join("\n")
82
- end_attrs = (@style == :expanded ? "\n" + old_spaces : ' ')
82
+ end_attrs = (style == :expanded ? "\n" + old_spaces : ' ')
83
83
  to_return << "#{total_rule} {\n#{attributes}#{end_attrs}}\n"
84
84
  end
85
85
  end
86
86
 
87
- tabs += 1 unless attributes.empty? || @style != :nested
87
+ tabs += 1 unless attributes.empty? || style != :nested
88
88
  sub_rules.each do |sub|
89
89
  to_return << sub.to_s(tabs, resolved_rules)
90
90
  end
@@ -1,11 +1,11 @@
1
1
  module Sass
2
2
  module Tree
3
3
  class VariableNode < Node
4
- def initialize(name, expr, guarded, options)
4
+ def initialize(name, expr, guarded)
5
5
  @name = name
6
6
  @expr = expr
7
7
  @guarded = guarded
8
- super(options)
8
+ super()
9
9
  end
10
10
 
11
11
  protected
@@ -2,9 +2,9 @@ require 'sass/tree/node'
2
2
 
3
3
  module Sass::Tree
4
4
  class WhileNode < Node
5
- def initialize(expr, options)
5
+ def initialize(expr)
6
6
  @expr = expr
7
- super(options)
7
+ super()
8
8
  end
9
9
 
10
10
  private
@@ -85,7 +85,11 @@ class SassEngineTest < Test::Unit::TestCase
85
85
  "& foo\n bar: baz\n blat: bang" => ["Base-level rules cannot contain the parent-selector-referencing character '&'.", 1],
86
86
  "a\n b: c\n& foo\n bar: baz\n blat: bang" => ["Base-level rules cannot contain the parent-selector-referencing character '&'.", 3],
87
87
  }
88
-
88
+
89
+ def teardown
90
+ clean_up_sassc
91
+ end
92
+
89
93
  def test_basic_render
90
94
  renders_correctly "basic", { :style => :compact }
91
95
  end
@@ -185,7 +189,18 @@ SASS
185
189
  end
186
190
 
187
191
  def test_sass_import
192
+ assert !File.exists?(sassc_path("importee"))
188
193
  renders_correctly "import", { :style => :compact, :load_paths => [File.dirname(__FILE__) + "/templates"] }
194
+ assert File.exists?(sassc_path("importee"))
195
+ end
196
+
197
+ def test_no_cache
198
+ assert !File.exists?(sassc_path("importee"))
199
+ renders_correctly("import", {
200
+ :style => :compact, :cache => false,
201
+ :load_paths => [File.dirname(__FILE__) + "/templates"],
202
+ })
203
+ assert !File.exists?(sassc_path("importee"))
189
204
  end
190
205
 
191
206
  def test_units
@@ -750,4 +765,9 @@ SOURCE
750
765
  def filename(name, type)
751
766
  File.dirname(__FILE__) + "/#{type == 'sass' ? 'templates' : 'results'}/#{name}.#{type}"
752
767
  end
768
+
769
+ def sassc_path(template)
770
+ sassc_path = File.join(File.dirname(__FILE__) + "/templates/#{template}.sass")
771
+ Sass::Files.send(:sassc_filename, sassc_path, Sass::Engine::DEFAULT_OPTIONS)
772
+ end
753
773
  end
@@ -17,6 +17,7 @@ class SassPluginTest < Test::Unit::TestCase
17
17
  end
18
18
 
19
19
  def teardown
20
+ clean_up_sassc
20
21
  FileUtils.rm_r tempfile_loc
21
22
  FileUtils.rm_r tempfile_loc(nil,"more_")
22
23
  end
data/test/test_helper.rb CHANGED
@@ -2,6 +2,7 @@ lib_dir = File.dirname(__FILE__) + '/../lib'
2
2
  require File.dirname(__FILE__) + '/linked_rails'
3
3
 
4
4
  require 'test/unit'
5
+ require 'fileutils'
5
6
  $:.unshift lib_dir unless $:.include?(lib_dir)
6
7
  require 'haml'
7
8
  require 'sass'
@@ -18,4 +19,9 @@ class Test::Unit::TestCase
18
19
  test_name = caller[1].gsub(/^.*`(?:\w+ )*(\w+)'.*$/, '\1')
19
20
  opts[:filename] = "#{test_name}_inline.sass"
20
21
  end
22
+
23
+ def clean_up_sassc
24
+ path = File.dirname(__FILE__) + "/../.sass-cache"
25
+ FileUtils.rm_r(path) if File.exist?(path)
26
+ end
21
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haml-edge
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.6
4
+ version: 2.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Weizenbaum
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-05-10 00:00:00 -04:00
13
+ date: 2009-05-11 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -91,6 +91,7 @@ files:
91
91
  - lib/sass/tree/rule_node.rb
92
92
  - lib/sass/tree/variable_node.rb
93
93
  - lib/sass/tree/while_node.rb
94
+ - lib/sass/files.rb
94
95
  - bin/css2sass
95
96
  - bin/haml
96
97
  - bin/html2haml