haml 3.1.0 → 3.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of haml might be problematic. Click here for more details.

Files changed (87) hide show
  1. data/VERSION +1 -1
  2. data/vendor/sass/Rakefile +22 -46
  3. data/vendor/sass/VERSION +1 -1
  4. data/vendor/sass/VERSION_NAME +1 -1
  5. data/vendor/sass/bin/scss +8 -0
  6. data/vendor/sass/doc-src/SASS_CHANGELOG.md +125 -9
  7. data/vendor/sass/doc-src/SASS_REFERENCE.md +84 -8
  8. data/vendor/sass/lib/sass.rb +0 -3
  9. data/vendor/sass/lib/sass/cache_stores.rb +1 -0
  10. data/vendor/sass/lib/sass/cache_stores/base.rb +2 -2
  11. data/vendor/sass/lib/sass/cache_stores/chain.rb +33 -0
  12. data/vendor/sass/lib/sass/cache_stores/filesystem.rb +6 -4
  13. data/vendor/sass/lib/sass/cache_stores/memory.rb +8 -12
  14. data/vendor/sass/lib/sass/engine.rb +65 -56
  15. data/vendor/sass/lib/sass/environment.rb +5 -2
  16. data/vendor/sass/lib/sass/exec.rb +52 -21
  17. data/vendor/sass/lib/sass/importers/filesystem.rb +32 -9
  18. data/vendor/sass/lib/sass/less.rb +1 -1
  19. data/vendor/sass/lib/sass/plugin.rb +11 -1
  20. data/vendor/sass/lib/sass/plugin/compiler.rb +21 -12
  21. data/vendor/sass/lib/sass/plugin/rails.rb +8 -82
  22. data/vendor/sass/lib/sass/plugin/staleness_checker.rb +10 -10
  23. data/vendor/sass/lib/sass/railtie.rb +3 -2
  24. data/vendor/sass/lib/sass/script.rb +2 -25
  25. data/vendor/sass/lib/sass/script/color.rb +4 -15
  26. data/vendor/sass/lib/sass/script/funcall.rb +63 -19
  27. data/vendor/sass/lib/sass/script/functions.rb +257 -19
  28. data/vendor/sass/lib/sass/script/lexer.rb +1 -4
  29. data/vendor/sass/lib/sass/script/list.rb +2 -2
  30. data/vendor/sass/lib/sass/script/node.rb +0 -27
  31. data/vendor/sass/lib/sass/script/number.rb +1 -1
  32. data/vendor/sass/lib/sass/script/operation.rb +0 -5
  33. data/vendor/sass/lib/sass/script/parser.rb +30 -12
  34. data/vendor/sass/lib/sass/script/string.rb +2 -17
  35. data/vendor/sass/lib/sass/script/string_interpolation.rb +1 -0
  36. data/vendor/sass/lib/sass/scss/parser.rb +58 -18
  37. data/vendor/sass/lib/sass/scss/rx.rb +2 -1
  38. data/vendor/sass/lib/sass/scss/script_lexer.rb +1 -1
  39. data/vendor/sass/lib/sass/selector/comma_sequence.rb +2 -3
  40. data/vendor/sass/lib/sass/selector/sequence.rb +3 -6
  41. data/vendor/sass/lib/sass/selector/simple_sequence.rb +2 -3
  42. data/vendor/sass/lib/sass/tree/charset_node.rb +0 -15
  43. data/vendor/sass/lib/sass/tree/comment_node.rb +20 -71
  44. data/vendor/sass/lib/sass/tree/debug_node.rb +4 -22
  45. data/vendor/sass/lib/sass/tree/directive_node.rb +0 -52
  46. data/vendor/sass/lib/sass/tree/each_node.rb +8 -38
  47. data/vendor/sass/lib/sass/tree/extend_node.rb +12 -48
  48. data/vendor/sass/lib/sass/tree/for_node.rb +20 -51
  49. data/vendor/sass/lib/sass/tree/function_node.rb +27 -0
  50. data/vendor/sass/lib/sass/tree/if_node.rb +22 -57
  51. data/vendor/sass/lib/sass/tree/import_node.rb +0 -56
  52. data/vendor/sass/lib/sass/tree/media_node.rb +0 -43
  53. data/vendor/sass/lib/sass/tree/mixin_def_node.rb +12 -45
  54. data/vendor/sass/lib/sass/tree/mixin_node.rb +13 -124
  55. data/vendor/sass/lib/sass/tree/node.rb +18 -304
  56. data/vendor/sass/lib/sass/tree/prop_node.rb +24 -92
  57. data/vendor/sass/lib/sass/tree/return_node.rb +18 -0
  58. data/vendor/sass/lib/sass/tree/root_node.rb +4 -133
  59. data/vendor/sass/lib/sass/tree/rule_node.rb +21 -164
  60. data/vendor/sass/lib/sass/tree/variable_node.rb +14 -23
  61. data/vendor/sass/lib/sass/tree/visitors/base.rb +75 -0
  62. data/vendor/sass/lib/sass/tree/visitors/check_nesting.rb +134 -0
  63. data/vendor/sass/lib/sass/tree/visitors/convert.rb +255 -0
  64. data/vendor/sass/lib/sass/tree/visitors/cssize.rb +175 -0
  65. data/vendor/sass/lib/sass/tree/visitors/perform.rb +301 -0
  66. data/vendor/sass/lib/sass/tree/visitors/to_css.rb +216 -0
  67. data/vendor/sass/lib/sass/tree/warn_node.rb +4 -28
  68. data/vendor/sass/lib/sass/tree/while_node.rb +5 -35
  69. data/vendor/sass/lib/sass/util.rb +0 -50
  70. data/vendor/sass/sass.gemspec +1 -1
  71. data/vendor/sass/test/sass/conversion_test.rb +53 -102
  72. data/vendor/sass/test/sass/engine_test.rb +416 -540
  73. data/vendor/sass/test/sass/functions_test.rb +306 -4
  74. data/vendor/sass/test/sass/importer_test.rb +0 -22
  75. data/vendor/sass/test/sass/plugin_test.rb +51 -21
  76. data/vendor/sass/test/sass/results/if.css +3 -0
  77. data/vendor/sass/test/sass/script_conversion_test.rb +0 -38
  78. data/vendor/sass/test/sass/script_test.rb +19 -4
  79. data/vendor/sass/test/sass/scss/scss_test.rb +32 -11
  80. data/vendor/sass/test/sass/templates/if.sass +11 -0
  81. data/vendor/sass/test/sass/templates/nested_import.sass +2 -0
  82. data/vendor/sass/test/sass/util_test.rb +0 -21
  83. data/vendor/sass/test/test_helper.rb +0 -3
  84. metadata +268 -258
  85. data/vendor/sass/bin/css2sass +0 -13
  86. data/vendor/sass/lib/sass/cache_stores/active_support.rb +0 -28
  87. data/vendor/sass/lib/sass/importers/rails.rb +0 -75
@@ -67,9 +67,6 @@ end
67
67
 
68
68
  require 'sass/util'
69
69
 
70
- dir = Sass::Util.scope("vendor/fssm/lib")
71
- $LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir)
72
-
73
70
  require 'sass/engine'
74
71
  require 'sass/plugin' if defined?(Merb::Plugins)
75
72
  require 'sass/railtie'
@@ -12,3 +12,4 @@ end
12
12
  require 'sass/cache_stores/base'
13
13
  require 'sass/cache_stores/filesystem'
14
14
  require 'sass/cache_stores/memory'
15
+ require 'sass/cache_stores/chain'
@@ -48,7 +48,7 @@ module Sass
48
48
  # @param sha [String] The checksum for the contents that are being stored.
49
49
  # @param obj [Object] The object to cache.
50
50
  def store(key, sha, root)
51
- _store(key, Sass::VERSION, sha, Sass::Util.dump(root))
51
+ _store(key, Sass::VERSION, sha, Marshal.dump(root))
52
52
  end
53
53
 
54
54
  # Retrieve a {Sass::Tree::RootNode}.
@@ -58,7 +58,7 @@ module Sass
58
58
  # @return [Object] The cached object.
59
59
  def retrieve(key, sha)
60
60
  contents = _retrieve(key, Sass::VERSION, sha)
61
- Sass::Util.load(contents) if contents
61
+ Marshal.load(contents) if contents
62
62
  rescue EOFError, TypeError, ArgumentError => e
63
63
  Sass::Util.sass_warn "Warning. Error encountered while reading cache #{path_to(key)}: #{e}"
64
64
  end
@@ -0,0 +1,33 @@
1
+ module Sass
2
+ module CacheStores
3
+ # A meta-cache that chains multiple caches together.
4
+ # Specifically:
5
+ #
6
+ # * All `#store`s are passed to all caches.
7
+ # * `#retrieve`s are passed to each cache until one has a hit.
8
+ # * When one cache has a hit, the value is `#store`d in all earlier caches.
9
+ class Chain < Base
10
+ # Create a new cache chaining the given caches.
11
+ #
12
+ # @param caches [Array<Sass::CacheStores::Base>] The caches to chain.
13
+ def initialize(*caches)
14
+ @caches = caches
15
+ end
16
+
17
+ # @see Base#store
18
+ def store(key, sha, obj)
19
+ @caches.each {|c| c.store(key, sha, obj)}
20
+ end
21
+
22
+ # @see Base#retrieve
23
+ def retrieve(key, sha)
24
+ @caches.each_with_index do |c, i|
25
+ next unless obj = c.retrieve(key, sha)
26
+ @caches[0...i].each {|c| c.store(key, sha, obj)}
27
+ return obj
28
+ end
29
+ nil
30
+ end
31
+ end
32
+ end
33
+ end
@@ -29,17 +29,19 @@ module Sass
29
29
 
30
30
  # @see Base#\_store
31
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)
32
+ # return unless File.writable?(File.dirname(@cache_location))
33
+ # return if File.exists?(@cache_location) && !File.writable?(@cache_location)
34
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)
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
37
  FileUtils.mkdir_p(File.dirname(compiled_filename))
38
38
  File.open(compiled_filename, "wb") do |f|
39
39
  f.puts(version)
40
40
  f.puts(sha)
41
41
  f.write(contents)
42
42
  end
43
+ rescue Errno::EACCES
44
+ #pass
43
45
  end
44
46
 
45
47
  private
@@ -24,22 +24,18 @@ module Sass
24
24
  @contents = {}
25
25
  end
26
26
 
27
- # @see Base#_retrieve
28
- def _retrieve(key, version, sha)
27
+ # @see Base#retrieve
28
+ def retrieve(key, sha)
29
29
  if @contents.has_key?(key)
30
- return unless @contents[key][:version] == version
31
30
  return unless @contents[key][:sha] == sha
32
- return @contents[key][:contents]
31
+ obj = @contents[key][:obj]
32
+ obj.respond_to?(:deep_copy) ? obj.deep_copy : obj.dup
33
33
  end
34
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
- }
35
+
36
+ # @see Base#store
37
+ def store(key, sha, obj)
38
+ @contents[key] = {:sha => sha, :obj => obj}
43
39
  end
44
40
 
45
41
  # Destructively clear the cache.
@@ -12,6 +12,8 @@ require 'sass/tree/media_node'
12
12
  require 'sass/tree/variable_node'
13
13
  require 'sass/tree/mixin_def_node'
14
14
  require 'sass/tree/mixin_node'
15
+ require 'sass/tree/function_node'
16
+ require 'sass/tree/return_node'
15
17
  require 'sass/tree/extend_node'
16
18
  require 'sass/tree/if_node'
17
19
  require 'sass/tree/while_node'
@@ -21,6 +23,12 @@ require 'sass/tree/debug_node'
21
23
  require 'sass/tree/warn_node'
22
24
  require 'sass/tree/import_node'
23
25
  require 'sass/tree/charset_node'
26
+ require 'sass/tree/visitors/base'
27
+ require 'sass/tree/visitors/perform'
28
+ require 'sass/tree/visitors/cssize'
29
+ require 'sass/tree/visitors/convert'
30
+ require 'sass/tree/visitors/to_css'
31
+ require 'sass/tree/visitors/check_nesting'
24
32
  require 'sass/selector'
25
33
  require 'sass/environment'
26
34
  require 'sass/script'
@@ -31,24 +39,24 @@ require 'sass/shared'
31
39
 
32
40
  module Sass
33
41
 
34
- # A Sass mixin.
42
+ # A Sass mixin or function.
35
43
  #
36
44
  # `name`: `String`
37
- # : The name of the mixin.
45
+ # : The name of the mixin/function.
38
46
  #
39
47
  # `args`: `Array<(String, Script::Node)>`
40
- # : The arguments for the mixin.
48
+ # : The arguments for the mixin/function.
41
49
  # Each element is a tuple containing the name of the argument
42
50
  # and the parse tree for the default value of the argument.
43
51
  #
44
52
  # `environment`: {Sass::Environment}
45
- # : The environment in which the mixin was defined.
46
- # This is captured so that the mixin can have access
53
+ # : The environment in which the mixin/function was defined.
54
+ # This is captured so that the mixin/function can have access
47
55
  # to local variables defined in its scope.
48
56
  #
49
- # `tree`: {Sass::Tree::Node}
50
- # : The parse tree for the mixin.
51
- Mixin = Struct.new(:name, :args, :environment, :tree)
57
+ # `tree`: `Array<Tree::Node>`
58
+ # : The parse tree for the mixin/function.
59
+ Callable = Struct.new(:name, :args, :environment, :tree)
52
60
 
53
61
  # This class handles the parsing and compilation of the Sass template.
54
62
  # Example usage:
@@ -89,10 +97,6 @@ module Sass
89
97
  # The character that begins a CSS property.
90
98
  PROPERTY_CHAR = ?:
91
99
 
92
- # The character that designates that
93
- # a property should be assigned to a SassScript expression.
94
- SCRIPT_CHAR = ?=
95
-
96
100
  # The character that designates the beginning of a comment,
97
101
  # either Sass or CSS.
98
102
  COMMENT_CHAR = ?/
@@ -117,16 +121,9 @@ module Sass
117
121
  # Includes named mixin declared using MIXIN_DEFINITION_CHAR
118
122
  MIXIN_INCLUDE_CHAR = ?+
119
123
 
120
- # The regex that matches properties of the form `name: prop`.
121
- PROPERTY_NEW_MATCHER = /^[^\s:"\[]+\s*[=:](\s|$)/
122
-
123
- # The regex that matches and extracts data from
124
- # properties of the form `name: prop`.
125
- PROPERTY_NEW = /^([^\s=:"]+)\s*(=|:)(?:\s+|$)(.*)/
126
-
127
124
  # The regex that matches and extracts data from
128
125
  # properties of the form `:name prop`.
129
- PROPERTY_OLD = /^:([^\s=:"]+)\s*(=?)(?:\s+|$)(.*)/
126
+ PROPERTY_OLD = /^:([^\s=:"]+)\s*(?:\s+|$)(.*)/
130
127
 
131
128
  # The default options for Sass::Engine.
132
129
  # @api public
@@ -154,9 +151,10 @@ module Sass
154
151
  options[:importer] ||= options[:filesystem_importer].new(".") if options[:filename]
155
152
 
156
153
  # Tracks the original filename of the top-level Sass file
157
- options[:original_filename] = options[:original_filename] || options[:filename]
154
+ options[:original_filename] ||= options[:filename]
158
155
 
159
- options[:cache_store] ||= Sass::CacheStores::Filesystem.new(options[:cache_location])
156
+ options[:cache_store] ||= Sass::CacheStores::Chain.new(
157
+ Sass::CacheStores::Memory.new, Sass::CacheStores::Filesystem.new(options[:cache_location]))
160
158
  # Support both, because the docs said one and the other actually worked
161
159
  # for quite a long time.
162
160
  options[:line_comments] ||= options[:line_numbers]
@@ -325,7 +323,15 @@ module Sass
325
323
  end
326
324
 
327
325
  root.options = @options
328
- @options[:cache_store].store(key, sha, root) if @options[:cache] && key && sha
326
+ if @options[:cache] && key && sha
327
+ begin
328
+ old_options = root.options
329
+ root.options = {:importer => root.options[:importer]}
330
+ @options[:cache_store].store(key, sha, root)
331
+ ensure
332
+ root.options = old_options
333
+ end
334
+ end
329
335
  root
330
336
  rescue SyntaxError => e
331
337
  e.modify_backtrace(:filename => @options[:filename], :line => @line)
@@ -516,19 +522,19 @@ WARNING
516
522
  when PROPERTY_CHAR
517
523
  if line.text[1] == PROPERTY_CHAR ||
518
524
  (@options[:property_syntax] == :new &&
519
- line.text =~ PROPERTY_OLD && $3.empty?)
525
+ line.text =~ PROPERTY_OLD && $2.empty?)
520
526
  # Support CSS3-style pseudo-elements,
521
527
  # which begin with ::,
522
528
  # as well as pseudo-classes
523
529
  # if we're using the new property syntax
524
530
  Tree::RuleNode.new(parse_interp(line.text))
525
531
  else
526
- name, eq, value = line.text.scan(PROPERTY_OLD)[0]
532
+ name, value = line.text.scan(PROPERTY_OLD)[0]
527
533
  raise SyntaxError.new("Invalid property: \"#{line.text}\".",
528
534
  :line => @line) if name.nil? || value.nil?
529
- parse_property(name, parse_interp(name), eq, value, :old, line)
535
+ parse_property(name, parse_interp(name), value, :old, line)
530
536
  end
531
- when ?!, ?$
537
+ when ?$
532
538
  parse_variable(line)
533
539
  when COMMENT_CHAR
534
540
  parse_comment(line.text)
@@ -563,48 +569,39 @@ WARNING
563
569
  end
564
570
 
565
571
  name = line.text[0...scanner.pos]
566
- if scanner.scan(/\s*([:=])(?:\s|$)/)
567
- parse_property(name, res, scanner[1], scanner.rest, :new, line)
572
+ if scanner.scan(/\s*:(?:\s|$)/)
573
+ parse_property(name, res, scanner.rest, :new, line)
568
574
  else
569
575
  res.pop if comment
570
576
  Tree::RuleNode.new(res + parse_interp(scanner.rest))
571
577
  end
572
578
  end
573
579
 
574
- def parse_property(name, parsed_name, eq, value, prop, line)
580
+ def parse_property(name, parsed_name, value, prop, line)
575
581
  if value.strip.empty?
576
582
  expr = Sass::Script::String.new("")
577
583
  else
584
+ important = false
585
+ if value =~ Sass::SCSS::RX::IMPORTANT
586
+ important = true
587
+ value = value.gsub(Sass::SCSS::RX::IMPORTANT,"")
588
+ end
578
589
  expr = parse_script(value, :offset => line.offset + line.text.index(value))
579
590
 
580
- if eq.strip[0] == SCRIPT_CHAR
581
- expr.context = :equals
582
- Script.equals_warning("properties", name,
583
- Sass::Tree::PropNode.val_to_sass(expr, @options), false,
584
- @line, line.offset + 1, @options[:filename])
585
- end
586
591
  end
587
- Tree::PropNode.new(parse_interp(name), expr, prop)
592
+ Tree::PropNode.new(parse_interp(name), expr, important, prop)
588
593
  end
589
594
 
590
595
  def parse_variable(line)
591
- name, op, value, default = line.text.scan(Script::MATCH)[0]
592
- guarded = op =~ /^\|\|/
596
+ name, value, default = line.text.scan(Script::MATCH)[0]
593
597
  raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath variable declarations.",
594
598
  :line => @line + 1) unless line.children.empty?
595
599
  raise SyntaxError.new("Invalid variable: \"#{line.text}\".",
596
600
  :line => @line) unless name && value
597
- Script.var_warning(name, @line, line.offset + 1, @options[:filename]) if line.text[0] == ?!
598
601
 
599
602
  expr = parse_script(value, :offset => line.offset + line.text.index(value))
600
- if op =~ /=$/
601
- expr.context = :equals
602
- type = guarded ? "variable defaults" : "variables"
603
- Script.equals_warning(type, "$#{name}", expr.to_sass,
604
- guarded, @line, line.offset + 1, @options[:filename])
605
- end
606
603
 
607
- Tree::VariableNode.new(name, expr, default || guarded)
604
+ Tree::VariableNode.new(name, expr, default)
608
605
  end
609
606
 
610
607
  def parse_comment(line)
@@ -630,6 +627,8 @@ WARNING
630
627
  parse_mixin_definition(line)
631
628
  elsif directive == "include"
632
629
  parse_mixin_include(line, root)
630
+ elsif directive == "function"
631
+ parse_function(line, root)
633
632
  elsif directive == "for"
634
633
  parse_for(line, root, value)
635
634
  elsif directive == "each"
@@ -660,6 +659,12 @@ WARNING
660
659
  :line => @line + 1) unless line.children.empty?
661
660
  offset = line.offset + line.text.index(value).to_i
662
661
  Tree::WarnNode.new(parse_script(value, :offset => offset))
662
+ elsif directive == "return"
663
+ raise SyntaxError.new("Invalid @return: expected expression.") unless value
664
+ raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath return directives.",
665
+ :line => @line + 1) unless line.children.empty?
666
+ offset = line.offset + line.text.index(value).to_i
667
+ Tree::ReturnNode.new(parse_script(value, :offset => offset))
663
668
  elsif directive == "charset"
664
669
  name = value && value[/\A(["'])(.*)\1\Z/, 2] #"
665
670
  raise SyntaxError.new("Invalid charset directive '@charset': expected string.") unless name
@@ -687,11 +692,8 @@ WARNING
687
692
  raise SyntaxError.new("Invalid for directive '@for #{text}': expected #{expected}.")
688
693
  end
689
694
  raise SyntaxError.new("Invalid variable \"#{var}\".") unless var =~ Script::VALIDATE
690
- if var.slice!(0) == ?!
691
- offset = line.offset + line.text.index("!" + var) + 1
692
- Script.var_warning(var, @line, offset, @options[:filename])
693
- end
694
695
 
696
+ var = var[1..-1]
695
697
  parsed_from = parse_script(from_expr, :offset => line.offset + line.text.index(from_expr))
696
698
  parsed_to = parse_script(to_expr, :offset => line.offset + line.text.index(to_expr))
697
699
  Tree::ForNode.new(var, parsed_from, parsed_to, to_name == 'to')
@@ -709,11 +711,8 @@ WARNING
709
711
  raise SyntaxError.new("Invalid for directive '@each #{text}': expected #{expected}.")
710
712
  end
711
713
  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
714
 
715
+ var = var[1..-1]
717
716
  parsed_list = parse_script(list_expr, :offset => line.offset + line.text.index(list_expr))
718
717
  Tree::EachNode.new(var, parsed_list)
719
718
  end
@@ -782,7 +781,6 @@ WARNING
782
781
  offset = line.offset + line.text.size - arg_string.size
783
782
  args = Script::Parser.new(arg_string.strip, @line, offset, @options).
784
783
  parse_mixin_definition_arglist
785
- default_arg_found = false
786
784
  Tree::MixinDefNode.new(name, args)
787
785
  end
788
786
 
@@ -799,6 +797,17 @@ WARNING
799
797
  Tree::MixinNode.new(name, args, keywords)
800
798
  end
801
799
 
800
+ FUNCTION_RE = /^@function\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
801
+ def parse_function(line, root)
802
+ name, arg_string = line.text.scan(FUNCTION_RE).first
803
+ raise SyntaxError.new("Invalid function definition \"#{line.text}\".") if name.nil?
804
+
805
+ offset = line.offset + line.text.size - arg_string.size
806
+ args = Script::Parser.new(arg_string.strip, @line, offset, @options).
807
+ parse_function_definition_arglist
808
+ Tree::FunctionNode.new(name, args)
809
+ end
810
+
802
811
  def parse_script(script, options = {})
803
812
  line = options[:line] || @line
804
813
  offset = options[:offset] || 0
@@ -2,7 +2,7 @@ require 'set'
2
2
 
3
3
  module Sass
4
4
  # The lexical environment for SassScript.
5
- # This keeps track of variable and mixin definitions.
5
+ # This keeps track of variable, mixin, and function definitions.
6
6
  #
7
7
  # A new environment is created for each level of Sass nesting.
8
8
  # This allows variables to be lexically scoped.
@@ -146,7 +146,10 @@ RUBY
146
146
  # Script::Literal
147
147
  inherited_hash :var
148
148
  # mixin
149
- # Engine::Mixin
149
+ # Sass::Callable
150
150
  inherited_hash :mixin
151
+ # function
152
+ # Sass::Callable
153
+ inherited_hash :function
151
154
  end
152
155
  end
@@ -176,12 +176,15 @@ MESSAGE
176
176
 
177
177
  # The `sass` executable.
178
178
  class Sass < Generic
179
+ attr_reader :default_syntax
180
+
179
181
  # @param args [Array<String>] The command-line arguments
180
182
  def initialize(args)
181
183
  super
182
184
  @options[:for_engine] = {
183
185
  :load_paths => ['.'] + (ENV['SASSPATH'] || '').split(File::PATH_SEPARATOR)
184
186
  }
187
+ @default_syntax = :sass
185
188
  end
186
189
 
187
190
  protected
@@ -193,7 +196,7 @@ MESSAGE
193
196
  super
194
197
 
195
198
  opts.banner = <<END
196
- Usage: sass [options] [INPUT] [OUTPUT]
199
+ Usage: #{default_syntax} [options] [INPUT] [OUTPUT]
197
200
 
198
201
  Description:
199
202
  Converts SCSS or Sass files to CSS.
@@ -201,14 +204,21 @@ Description:
201
204
  Options:
202
205
  END
203
206
 
204
- opts.on('--scss',
205
- 'Use the CSS-superset SCSS syntax.') do
206
- @options[:for_engine][:syntax] = :scss
207
+ if @default_syntax == :sass
208
+ opts.on('--scss',
209
+ 'Use the CSS-superset SCSS syntax.') do
210
+ @options[:for_engine][:syntax] = :scss
211
+ end
212
+ else
213
+ opts.on('--sass',
214
+ 'Use the Indented syntax.') do
215
+ @options[:for_engine][:syntax] = :sass
216
+ end
207
217
  end
208
218
  opts.on('--watch', 'Watch files or directories for changes.',
209
219
  'The location of the generated CSS can be set using a colon:',
210
- ' sass --watch input.sass:output.css',
211
- ' sass --watch input-dir:output-dir') do
220
+ " #{@default_syntax} --watch input.#{@default_syntax}:output.css",
221
+ " #{@default_syntax} --watch input-dir:output-dir") do
212
222
  @options[:watch] = true
213
223
  end
214
224
  opts.on('--update', 'Compile files or directories to CSS.',
@@ -231,12 +241,15 @@ END
231
241
  opts.on('-q', '--quiet', 'Silence warnings and status messages during compilation.') do
232
242
  @options[:for_engine][:quiet] = true
233
243
  end
244
+ opts.on('--compass', 'Make Compass imports available and load project configuration.') do
245
+ @options[:compass] = true
246
+ end
234
247
  opts.on('-g', '--debug-info',
235
248
  'Emit extra information in the generated CSS that can be used by the FireSass Firebug plugin.') do
236
249
  @options[:for_engine][:debug_info] = true
237
250
  end
238
251
  opts.on('-l', '--line-numbers', '--line-comments',
239
- 'Emit comments in the generated CSS indicating the corresponding sass line.') do
252
+ 'Emit comments in the generated CSS indicating the corresponding source line.') do
240
253
  @options[:for_engine][:line_numbers] = true
241
254
  end
242
255
  opts.on('-i', '--interactive',
@@ -276,7 +289,7 @@ END
276
289
  @options[:update] = true
277
290
  end
278
291
  end
279
-
292
+ load_compass if @options[:compass]
280
293
  return interactive if @options[:interactive]
281
294
  return watch_or_update if @options[:watch] || @options[:update]
282
295
  super
@@ -287,6 +300,7 @@ END
287
300
  output = @options[:output]
288
301
 
289
302
  @options[:for_engine][:syntax] ||= :scss if input.is_a?(File) && input.path =~ /\.scss$/
303
+ @options[:for_engine][:syntax] ||= @default_syntax
290
304
  engine =
291
305
  if input.is_a?(File) && !@options[:check_syntax]
292
306
  ::Sass::Engine.for_file(input.path, @options[:for_engine])
@@ -309,6 +323,23 @@ END
309
323
 
310
324
  private
311
325
 
326
+ def load_compass
327
+ begin
328
+ require 'compass'
329
+ rescue LoadError
330
+ require 'rubygems'
331
+ begin
332
+ require 'compass'
333
+ rescue LoadError
334
+ puts "ERROR: Cannot load compass."
335
+ exit 1
336
+ end
337
+ end
338
+ Compass.add_project_configuration
339
+ Compass.configuration.project_path ||= Dir.pwd
340
+ @options[:for_engine][:load_paths] += Compass.configuration.sass_load_paths
341
+ end
342
+
312
343
  def interactive
313
344
  require 'sass/repl'
314
345
  ::Sass::Repl.new(@options).run
@@ -321,8 +352,8 @@ END
321
352
 
322
353
  raise <<MSG if @args.empty?
323
354
  What files should I watch? Did you mean something like:
324
- sass --watch input.sass:output.css
325
- sass --watch input-dir:output-dir
355
+ #{@default_syntax} --watch input.#{@default_syntax}:output.css
356
+ #{@default_syntax} --watch input-dir:output-dir
326
357
  MSG
327
358
 
328
359
  if !colon_path?(@args[0]) && probably_dest_dir?(@args[1])
@@ -335,7 +366,7 @@ MSG
335
366
  end
336
367
  raise <<MSG if err
337
368
  File #{@args[1]} #{err}.
338
- Did you mean: sass #{flag} #{@args[0]}:#{@args[1]}
369
+ Did you mean: #{@default_syntax} #{flag} #{@args[0]}:#{@args[1]}
339
370
  MSG
340
371
  end
341
372
 
@@ -402,6 +433,14 @@ MSG
402
433
  end
403
434
  end
404
435
 
436
+ class Scss < Sass
437
+ # @param args [Array<String>] The command-line arguments
438
+ def initialize(args)
439
+ super
440
+ @default_syntax = :scss
441
+ end
442
+ end
443
+
405
444
  # The `sass-convert` executable.
406
445
  class SassConvert < Generic
407
446
  # @param args [Array<String>] The command-line arguments
@@ -428,12 +467,11 @@ Options:
428
467
  END
429
468
 
430
469
  opts.on('-F', '--from FORMAT',
431
- 'The format to convert from. Can be css, scss, sass, less, or sass2.',
432
- 'sass2 is the same as sass, but updates more old syntax to new.',
470
+ 'The format to convert from. Can be css, scss, sass, less.',
433
471
  'By default, this is inferred from the input filename.',
434
472
  'If there is none, defaults to css.') do |name|
435
473
  @options[:from] = name.downcase.to_sym
436
- unless [:css, :scss, :sass, :less, :sass2].include?(@options[:from])
474
+ unless [:css, :scss, :sass, :less].include?(@options[:from])
437
475
  raise "Unknown format for sass-convert --from: #{name}"
438
476
  end
439
477
  try_less_note if @options[:from] == :less
@@ -517,14 +555,12 @@ END
517
555
  @options[:output] ||= @options[:input]
518
556
 
519
557
  from = @options[:from]
520
- from = :sass if from == :sass2
521
558
  if @options[:to] == @options[:from] && !@options[:in_place]
522
559
  fmt = @options[:from]
523
560
  raise "Error: converting from #{fmt} to #{fmt} without --in-place"
524
561
  end
525
562
 
526
563
  ext = @options[:from]
527
- ext = :sass if ext == :sass2
528
564
  Dir.glob("#{@options[:input]}/**/*.#{ext}") do |f|
529
565
  output =
530
566
  if @options[:in_place]
@@ -575,11 +611,6 @@ END
575
611
  end
576
612
  end
577
613
 
578
- if @options[:from] == :sass2
579
- @options[:from] = :sass
580
- @options[:for_engine][:sass2] = true
581
- end
582
-
583
614
  @options[:from] ||= :css
584
615
  @options[:to] ||= :sass
585
616
  @options[:for_engine][:syntax] = @options[:from]