haml 3.1.0.alpha.33 → 3.1.0.alpha.36

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.
Files changed (61) hide show
  1. data/EDGE_GEM_VERSION +1 -1
  2. data/VERSION +1 -1
  3. data/vendor/sass/doc-src/SASS_CHANGELOG.md +177 -2
  4. data/vendor/sass/doc-src/SASS_REFERENCE.md +140 -3
  5. data/vendor/sass/lib/sass/cache_stores.rb +14 -0
  6. data/vendor/sass/lib/sass/cache_stores/active_support.rb +28 -0
  7. data/vendor/sass/lib/sass/cache_stores/base.rb +84 -0
  8. data/vendor/sass/lib/sass/cache_stores/filesystem.rb +56 -0
  9. data/vendor/sass/lib/sass/cache_stores/memory.rb +51 -0
  10. data/vendor/sass/lib/sass/cache_stores/null.rb +25 -0
  11. data/vendor/sass/lib/sass/engine.rb +86 -25
  12. data/vendor/sass/lib/sass/exec.rb +10 -1
  13. data/vendor/sass/lib/sass/importers/rails.rb +75 -0
  14. data/vendor/sass/lib/sass/less.rb +1 -1
  15. data/vendor/sass/lib/sass/plugin/compiler.rb +4 -1
  16. data/vendor/sass/lib/sass/plugin/configuration.rb +4 -2
  17. data/vendor/sass/lib/sass/plugin/rack.rb +15 -2
  18. data/vendor/sass/lib/sass/plugin/rails.rb +89 -9
  19. data/vendor/sass/lib/sass/plugin/staleness_checker.rb +30 -2
  20. data/vendor/sass/lib/sass/script/css_parser.rb +1 -1
  21. data/vendor/sass/lib/sass/script/functions.rb +126 -5
  22. data/vendor/sass/lib/sass/script/lexer.rb +1 -1
  23. data/vendor/sass/lib/sass/script/list.rb +76 -0
  24. data/vendor/sass/lib/sass/script/literal.rb +10 -1
  25. data/vendor/sass/lib/sass/script/number.rb +1 -1
  26. data/vendor/sass/lib/sass/script/operation.rb +3 -2
  27. data/vendor/sass/lib/sass/script/parser.rb +25 -12
  28. data/vendor/sass/lib/sass/scss/css_parser.rb +0 -5
  29. data/vendor/sass/lib/sass/scss/parser.rb +46 -7
  30. data/vendor/sass/lib/sass/scss/static_parser.rb +1 -1
  31. data/vendor/sass/lib/sass/tree/charset_node.rb +37 -0
  32. data/vendor/sass/lib/sass/tree/directive_node.rb +2 -2
  33. data/vendor/sass/lib/sass/tree/each_node.rb +54 -0
  34. data/vendor/sass/lib/sass/tree/if_node.rb +19 -0
  35. data/vendor/sass/lib/sass/tree/media_node.rb +75 -0
  36. data/vendor/sass/lib/sass/tree/prop_node.rb +1 -1
  37. data/vendor/sass/lib/sass/tree/root_node.rb +37 -5
  38. data/vendor/sass/lib/sass/tree/rule_node.rb +4 -6
  39. data/vendor/sass/lib/sass/util.rb +18 -1
  40. data/vendor/sass/test/sass/cache_test.rb +7 -7
  41. data/vendor/sass/test/sass/conversion_test.rb +28 -0
  42. data/vendor/sass/test/sass/engine_test.rb +214 -11
  43. data/vendor/sass/test/sass/functions_test.rb +69 -0
  44. data/vendor/sass/test/sass/plugin_test.rb +13 -4
  45. data/vendor/sass/test/sass/results/import_charset.css +4 -0
  46. data/vendor/sass/test/sass/results/import_charset_1_8.css +4 -0
  47. data/vendor/sass/test/sass/results/import_charset_ibm866.css +4 -0
  48. data/vendor/sass/test/sass/script_conversion_test.rb +27 -25
  49. data/vendor/sass/test/sass/script_test.rb +12 -1
  50. data/vendor/sass/test/sass/scss/css_test.rb +27 -8
  51. data/vendor/sass/test/sass/scss/scss_test.rb +77 -0
  52. data/vendor/sass/test/sass/templates/_imported_charset_ibm866.sass +4 -0
  53. data/vendor/sass/test/sass/templates/_imported_charset_utf8.sass +4 -0
  54. data/vendor/sass/test/sass/templates/import_charset.sass +7 -0
  55. data/vendor/sass/test/sass/templates/import_charset_1_8.sass +4 -0
  56. data/vendor/sass/test/sass/templates/import_charset_ibm866.sass +9 -0
  57. data/vendor/sass/test/sass/templates/script.sass +2 -2
  58. data/vendor/sass/test/test_helper.rb +8 -0
  59. metadata +27 -10
  60. data/REVISION +0 -1
  61. data/vendor/sass/lib/sass/cache_store.rb +0 -208
@@ -0,0 +1,84 @@
1
+ module Sass
2
+ module CacheStores
3
+ # An abstract base class for backends for the Sass cache.
4
+ # Any key-value store can act as such a backend;
5
+ # it just needs to implement the
6
+ # \{#_store} and \{#_retrieve} methods.
7
+ #
8
+ # To use a cache store with Sass,
9
+ # use the {file:SASS_REFERENCE.md#cache_store-option `:cache_store` option}.
10
+ #
11
+ # @abstract
12
+ class Base
13
+ # Store cached contents for later retrieval
14
+ # Must be implemented by all CacheStore subclasses
15
+ #
16
+ # Note: cache contents contain binary data.
17
+ #
18
+ # @param key [String] The key to store the contents under
19
+ # @param version [String] The current sass version.
20
+ # Cached contents must not be retrieved across different versions of sass.
21
+ # @param sha [String] The sha of the sass source.
22
+ # Cached contents must not be retrieved if the sha has changed.
23
+ # @param contents [String] The contents to store.
24
+ def _store(key, version, sha, contents)
25
+ raise "#{self.class} must implement #_store."
26
+ end
27
+
28
+ # Retrieved cached contents.
29
+ # Must be implemented by all subclasses.
30
+ #
31
+ # Note: if the key exists but the sha or version have changed,
32
+ # then the key may be deleted by the cache store, if it wants to do so.
33
+ #
34
+ # @param key [String] The key to retrieve
35
+ # @param version [String] The current sass version.
36
+ # Cached contents must not be retrieved across different versions of sass.
37
+ # @param sha [String] The sha of the sass source.
38
+ # Cached contents must not be retrieved if the sha has changed.
39
+ # @return [String] The contents that were previously stored.
40
+ # @return [NilClass] when the cache key is not found or the version or sha have changed.
41
+ def _retrieve(key, version, sha)
42
+ raise "#{self.class} must implement #_retrieve."
43
+ end
44
+
45
+ # Store a {Sass::Tree::RootNode}.
46
+ #
47
+ # @param key [String] The key to store it under.
48
+ # @param sha [String] The checksum for the contents that are being stored.
49
+ # @param obj [Object] The object to cache.
50
+ def store(key, sha, root)
51
+ _store(key, Sass::VERSION, sha, Sass::Util.dump(root))
52
+ end
53
+
54
+ # Retrieve a {Sass::Tree::RootNode}.
55
+ #
56
+ # @param key [String] The key the root element was stored under.
57
+ # @param sha [String] The checksum of the root element's content.
58
+ # @return [Object] The cached object.
59
+ def retrieve(key, sha)
60
+ contents = _retrieve(key, Sass::VERSION, sha)
61
+ Sass::Util.load(contents) if contents
62
+ rescue EOFError, TypeError, ArgumentError => e
63
+ Sass::Util.sass_warn "Warning. Error encountered while reading cache #{path_to(key)}: #{e}"
64
+ end
65
+
66
+ # Return the key for the sass file.
67
+ #
68
+ # The `(sass_dirname, sass_basename)` pair
69
+ # should uniquely identify the Sass document,
70
+ # but otherwise there are no restrictions on their content.
71
+ #
72
+ # @param sass_dirname [String]
73
+ # The fully-expanded location of the Sass file.
74
+ # This corresponds to the directory name on a filesystem.
75
+ # @param sass_basename [String] The name of the Sass file that is being referenced.
76
+ # This corresponds to the basename on a filesystem.
77
+ def key(sass_dirname, sass_basename)
78
+ dir = Digest::SHA1.hexdigest(sass_dirname)
79
+ filename = "#{sass_basename}c"
80
+ "#{dir}/#{filename}"
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,56 @@
1
+ module Sass
2
+ module CacheStores
3
+ # A backend for the Sass cache using the filesystem.
4
+ class Filesystem < Base
5
+ # The directory where the cached files will be stored.
6
+ #
7
+ # @return [String]
8
+ attr_accessor :cache_location
9
+
10
+ # @param cache_location [String] see \{#cache\_location}
11
+ def initialize(cache_location)
12
+ @cache_location = cache_location
13
+ end
14
+
15
+ # @see Base#\_retrieve
16
+ def _retrieve(key, version, sha)
17
+ return unless File.readable?(path_to(key))
18
+ contents = nil
19
+ File.open(path_to(key), "rb") do |f|
20
+ if f.readline("\n").strip == version && f.readline("\n").strip == sha
21
+ return f.read
22
+ end
23
+ end
24
+ File.unlink path_to(key)
25
+ nil
26
+ rescue EOFError, TypeError, ArgumentError => e
27
+ Sass::Util.sass_warn "Warning. Error encountered while reading cache #{path_to(key)}: #{e}"
28
+ end
29
+
30
+ # @see Base#\_store
31
+ def _store(key, version, sha, contents)
32
+ return unless File.writable?(File.dirname(@cache_location))
33
+ return if File.exists?(@cache_location) && !File.writable?(@cache_location)
34
+ compiled_filename = path_to(key)
35
+ return if File.exists?(File.dirname(compiled_filename)) && !File.writable?(File.dirname(compiled_filename))
36
+ return if File.exists?(compiled_filename) && !File.writable?(compiled_filename)
37
+ FileUtils.mkdir_p(File.dirname(compiled_filename))
38
+ File.open(compiled_filename, "wb") do |f|
39
+ f.puts(version)
40
+ f.puts(sha)
41
+ f.write(contents)
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ # Returns the path to a file for the given key.
48
+ #
49
+ # @param key [String]
50
+ # @return [String] The path to the cache file.
51
+ def path_to(key)
52
+ File.join(cache_location, key)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,51 @@
1
+ module Sass
2
+ module CacheStores
3
+ # A backend for the Sass cache using in-process memory.
4
+ class Memory < Base
5
+ # Since the {Memory} store is stored in the Sass tree's options hash,
6
+ # when the options get serialized as part of serializing the tree,
7
+ # you get crazy exponential growth in the size of the cached objects
8
+ # unless you don't dump the cache.
9
+ #
10
+ # @private
11
+ def _dump(depth)
12
+ ""
13
+ end
14
+
15
+ # If we deserialize this class, just make a new empty one.
16
+ #
17
+ # @private
18
+ def self._load(repr)
19
+ Memory.new
20
+ end
21
+
22
+ # Create a new, empty cache store.
23
+ def initialize
24
+ @contents = {}
25
+ end
26
+
27
+ # @see Base#_retrieve
28
+ def _retrieve(key, version, sha)
29
+ if @contents.has_key?(key)
30
+ return unless @contents[key][:version] == version
31
+ return unless @contents[key][:sha] == sha
32
+ return @contents[key][:contents]
33
+ end
34
+ end
35
+
36
+ # @see Base#_store
37
+ def _store(key, version, sha, contents)
38
+ @contents[key] = {
39
+ :version => version,
40
+ :sha => sha,
41
+ :contents => contents
42
+ }
43
+ end
44
+
45
+ # Destructively clear the cache.
46
+ def reset!
47
+ @contents = {}
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,25 @@
1
+ module Sass
2
+ module CacheStores
3
+ # Doesn't store anything, but records what things it should have stored.
4
+ # This doesn't currently have any use except for testing and debugging.
5
+ #
6
+ # @private
7
+ class Null < Base
8
+ def initialize
9
+ @keys = {}
10
+ end
11
+
12
+ def _retrieve(key, version, sha)
13
+ nil
14
+ end
15
+
16
+ def _store(key, version, sha, contents)
17
+ @keys[key] = true
18
+ end
19
+
20
+ def was_set?(key)
21
+ @keys[key]
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,12 +1,14 @@
1
1
  require 'strscan'
2
+ require 'set'
2
3
  require 'digest/sha1'
3
- require 'sass/cache_store'
4
+ require 'sass/cache_stores'
4
5
  require 'sass/tree/node'
5
6
  require 'sass/tree/root_node'
6
7
  require 'sass/tree/rule_node'
7
8
  require 'sass/tree/comment_node'
8
9
  require 'sass/tree/prop_node'
9
10
  require 'sass/tree/directive_node'
11
+ require 'sass/tree/media_node'
10
12
  require 'sass/tree/variable_node'
11
13
  require 'sass/tree/mixin_def_node'
12
14
  require 'sass/tree/mixin_node'
@@ -14,9 +16,11 @@ require 'sass/tree/extend_node'
14
16
  require 'sass/tree/if_node'
15
17
  require 'sass/tree/while_node'
16
18
  require 'sass/tree/for_node'
19
+ require 'sass/tree/each_node'
17
20
  require 'sass/tree/debug_node'
18
21
  require 'sass/tree/warn_node'
19
22
  require 'sass/tree/import_node'
23
+ require 'sass/tree/charset_node'
20
24
  require 'sass/selector'
21
25
  require 'sass/environment'
22
26
  require 'sass/script'
@@ -152,7 +156,7 @@ module Sass
152
156
  # Tracks the original filename of the top-level Sass file
153
157
  options[:original_filename] = options[:original_filename] || options[:filename]
154
158
 
155
- options[:cache_store] ||= Sass::FileCacheStore.new(options[:cache_location])
159
+ options[:cache_store] ||= Sass::CacheStores::Filesystem.new(options[:cache_location])
156
160
  # Support both, because the docs said one and the other actually worked
157
161
  # for quite a long time.
158
162
  options[:line_comments] ||= options[:line_numbers]
@@ -238,13 +242,14 @@ module Sass
238
242
  end
239
243
  alias_method :to_css, :render
240
244
 
241
- # Parses the document into its parse tree.
245
+ # Parses the document into its parse tree. Memoized.
242
246
  #
243
247
  # @return [Sass::Tree::Node] The root of the parse tree.
244
248
  # @raise [Sass::SyntaxError] if there's an error in the document
245
249
  def to_tree
246
- return _to_tree unless @options[:quiet]
247
- Sass::Util.silence_sass_warnings {_to_tree}
250
+ @tree ||= @options[:quiet] ?
251
+ Sass::Util.silence_sass_warnings {_to_tree} :
252
+ _to_tree
248
253
  end
249
254
 
250
255
  # Returns the original encoding of the document,
@@ -259,12 +264,42 @@ module Sass
259
264
  @original_encoding
260
265
  end
261
266
 
267
+ # Gets a set of all the documents
268
+ # that are (transitive) dependencies of this document,
269
+ # not including the document itself.
270
+ #
271
+ # @return [[Sass::Engine]] The dependency documents.
272
+ def dependencies
273
+ _dependencies(Set.new, engines = Set.new)
274
+ engines - [self]
275
+ end
276
+
277
+ # Helper for \{#dependencies}.
278
+ #
279
+ # @private
280
+ def _dependencies(seen, engines)
281
+ return if seen.include?(key = [@options[:filename], @options[:importer]])
282
+ seen << key
283
+ engines << self
284
+ to_tree.grep(Tree::ImportNode) do |n|
285
+ next if n.css_import?
286
+ n.imported_file._dependencies(seen, engines)
287
+ end
288
+ end
289
+
262
290
  private
263
291
 
264
292
  def _render
265
293
  rendered = _to_tree.render
266
294
  return rendered if ruby1_8?
267
- return rendered.encode(source_encoding)
295
+ begin
296
+ # Try to convert the result to the original encoding,
297
+ # but if that doesn't work fall back on UTF-8
298
+ rendered = rendered.encode(source_encoding)
299
+ rescue EncodingError
300
+ end
301
+ rendered.gsub(Regexp.new('\A@charset "(.*?)"'.encode(source_encoding)),
302
+ "@charset \"#{source_encoding.name}\"".encode(source_encoding))
268
303
  end
269
304
 
270
305
  def _to_tree
@@ -315,7 +350,7 @@ module Sass
315
350
  comment_tab_str = nil
316
351
  first = true
317
352
  lines = []
318
- string.gsub(/\r|\n|\r\n|\r\n/, "\n").scan(/^.*?$/).each_with_index do |line, index|
353
+ string.gsub(/\r|\n|\r\n|\r\n/, "\n").scan(/^[^\n]*?$/).each_with_index do |line, index|
319
354
  index += (@options[:line] || 1)
320
355
  if line.strip.empty?
321
356
  lines.last.text << "\n" if lines.last && lines.last.comment?
@@ -424,23 +459,21 @@ MSG
424
459
  children.each do |line|
425
460
  child = build_tree(parent, line, root)
426
461
 
427
- if child.is_a?(Tree::RuleNode) && child.continued?
428
- raise SyntaxError.new("Rules can't end in commas.",
429
- :line => child.line) unless child.children.empty?
430
- if continued_rule
462
+ if child.is_a?(Tree::RuleNode)
463
+ if child.continued? && child.children.empty?
464
+ if continued_rule
465
+ continued_rule.add_rules child
466
+ else
467
+ continued_rule = child
468
+ end
469
+ next
470
+ elsif continued_rule
431
471
  continued_rule.add_rules child
432
- else
433
- continued_rule = child
472
+ continued_rule.children = child.children
473
+ continued_rule, child = nil, continued_rule
434
474
  end
435
- next
436
- end
437
-
438
- if continued_rule
439
- raise SyntaxError.new("Rules can't end in commas.",
440
- :line => continued_rule.line) unless child.is_a?(Tree::RuleNode)
441
- continued_rule.add_rules child
442
- continued_rule.children = child.children
443
- continued_rule, child = nil, continued_rule
475
+ elsif continued_rule
476
+ continued_rule = nil
444
477
  end
445
478
 
446
479
  if child.is_a?(Tree::CommentNode) && child.silent
@@ -458,9 +491,6 @@ MSG
458
491
  validate_and_append_child(parent, child, line, root)
459
492
  end
460
493
 
461
- raise SyntaxError.new("Rules can't end in commas.",
462
- :line => continued_rule.line) if continued_rule
463
-
464
494
  parent
465
495
  end
466
496
 
@@ -602,6 +632,8 @@ WARNING
602
632
  parse_mixin_include(line, root)
603
633
  elsif directive == "for"
604
634
  parse_for(line, root, value)
635
+ elsif directive == "each"
636
+ parse_each(line, root, value)
605
637
  elsif directive == "else"
606
638
  parse_else(parent, line, value)
607
639
  elsif directive == "while"
@@ -628,6 +660,14 @@ WARNING
628
660
  :line => @line + 1) unless line.children.empty?
629
661
  offset = line.offset + line.text.index(value).to_i
630
662
  Tree::WarnNode.new(parse_script(value, :offset => offset))
663
+ elsif directive == "charset"
664
+ name = value && value[/\A(["'])(.*)\1\Z/, 2] #"
665
+ raise SyntaxError.new("Invalid charset directive '@charset': expected string.") unless name
666
+ raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath charset directives.",
667
+ :line => @line + 1) unless line.children.empty?
668
+ Tree::CharsetNode.new(name)
669
+ elsif directive == "media"
670
+ Tree::MediaNode.new(value)
631
671
  else
632
672
  Tree::DirectiveNode.new(line.text)
633
673
  end
@@ -657,6 +697,27 @@ WARNING
657
697
  Tree::ForNode.new(var, parsed_from, parsed_to, to_name == 'to')
658
698
  end
659
699
 
700
+ def parse_each(line, root, text)
701
+ var, list_expr = text.scan(/^([^\s]+)\s+in\s+(.+)$/).first
702
+
703
+ if var.nil? # scan failed, try to figure out why for error message
704
+ if text !~ /^[^\s]+/
705
+ expected = "variable name"
706
+ elsif text !~ /^[^\s]+\s+from\s+.+/
707
+ expected = "'in <expr>'"
708
+ end
709
+ raise SyntaxError.new("Invalid for directive '@each #{text}': expected #{expected}.")
710
+ end
711
+ raise SyntaxError.new("Invalid variable \"#{var}\".") unless var =~ Script::VALIDATE
712
+ if var.slice!(0) == ?!
713
+ offset = line.offset + line.text.index("!" + var) + 1
714
+ Script.var_warning(var, @line, offset, @options[:filename])
715
+ end
716
+
717
+ parsed_list = parse_script(list_expr, :offset => line.offset + line.text.index(list_expr))
718
+ Tree::EachNode.new(var, parsed_list)
719
+ end
720
+
660
721
  def parse_else(parent, line, text)
661
722
  previous = parent.children.last
662
723
  raise SyntaxError.new("@else must come after @if.") unless previous.is_a?(Tree::IfNode)
@@ -123,9 +123,18 @@ module Sass
123
123
  # @param color [Symbol] The name of the color to use for this action.
124
124
  # Can be `:red`, `:green`, or `:yellow`.
125
125
  def puts_action(name, color, arg)
126
+ return if @options[:for_engine][:quiet]
126
127
  printf color(color, "%11s %s\n"), name, arg
127
128
  end
128
129
 
130
+ # Same as \{Kernel.puts}, but doesn't print anything if the `--quiet` option is set.
131
+ #
132
+ # @param args [Array] Passed on to \{Kernel.puts}
133
+ def puts(*args)
134
+ return if @options[:for_engine][:quiet]
135
+ Kernel.puts(*args)
136
+ end
137
+
129
138
  # Wraps the given string in terminal escapes
130
139
  # causing it to have the given color.
131
140
  # If terminal esapes aren't supported on this platform,
@@ -219,7 +228,7 @@ END
219
228
  'Output style. Can be nested (default), compact, compressed, or expanded.') do |name|
220
229
  @options[:for_engine][:style] = name.to_sym
221
230
  end
222
- opts.on('-q', '--quiet', 'Silence warnings during compilation.') do
231
+ opts.on('-q', '--quiet', 'Silence warnings and status messages during compilation.') do
223
232
  @options[:for_engine][:quiet] = true
224
233
  end
225
234
  opts.on('-g', '--debug-info',