sass 3.2.0.alpha.275 → 3.2.0.alpha.277

Sign up to get free protection for your applications and to get access to all the features.
data/REVISION CHANGED
@@ -1 +1 @@
1
- 1edbe5841971a4cdab0ac63de360973289e700ec
1
+ 4b0ad099f2e46bb7a014a8b841a0ed089d1b4416
data/Rakefile CHANGED
@@ -194,7 +194,6 @@ OPTS
194
194
  t.files = FileList.new(scope('lib/**/*.rb')) do |list|
195
195
  list.exclude('lib/sass/plugin/merb.rb')
196
196
  list.exclude('lib/sass/plugin/rails.rb')
197
- list.exclude('lib/sass/less.rb')
198
197
  end.to_a
199
198
  t.options << '--incremental' if Rake.application.top_level_tasks.include?('redoc')
200
199
  t.options += FileList.new(scope('yard/*.rb')).to_a.map {|f| ['-e', f]}.flatten
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.0.alpha.275
1
+ 3.2.0.alpha.277
@@ -18,13 +18,16 @@ module Sass
18
18
  #
19
19
  # @return [Environment]
20
20
  attr_reader :parent
21
- attr_writer :options
21
+ attr_reader :options
22
22
  attr_writer :caller
23
23
  attr_writer :content
24
24
 
25
+ # @param options [{Symbol => Object}] The options hash. See
26
+ # {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
25
27
  # @param parent [Environment] See \{#parent}
26
- def initialize(parent = nil)
28
+ def initialize(parent = nil, options = nil)
27
29
  @parent = parent
30
+ @options = options || (parent && parent.options) || {}
28
31
  end
29
32
 
30
33
  # The environment of the caller of this environment's mixin or function.
@@ -40,20 +43,8 @@ module Sass
40
43
  @content || (@parent && @parent.content)
41
44
  end
42
45
 
43
- # The options hash.
44
- # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
45
- #
46
- # @return [{Symbol => Object}]
47
- def options
48
- @options || parent_options || {}
49
- end
50
-
51
46
  private
52
47
 
53
- def parent_options
54
- @parent_options ||= @parent && @parent.options
55
- end
56
-
57
48
  class << self
58
49
  private
59
50
  UNDERSCORE, DASH = '_', '-'
data/lib/sass/exec.rb CHANGED
@@ -490,14 +490,14 @@ Options:
490
490
  END
491
491
 
492
492
  opts.on('-F', '--from FORMAT',
493
- 'The format to convert from. Can be css, scss, sass, less.',
493
+ 'The format to convert from. Can be css, scss, sass.',
494
494
  'By default, this is inferred from the input filename.',
495
495
  'If there is none, defaults to css.') do |name|
496
496
  @options[:from] = name.downcase.to_sym
497
- unless [:css, :scss, :sass, :less].include?(@options[:from])
497
+ raise "sass-convert no longer supports LessCSS." if @options[:from] == :less
498
+ unless [:css, :scss, :sass].include?(@options[:from])
498
499
  raise "Unknown format for sass-convert --from: #{name}"
499
500
  end
500
- try_less_note if @options[:from] == :less
501
501
  end
502
502
 
503
503
  opts.on('-T', '--to FORMAT',
@@ -630,7 +630,7 @@ END
630
630
  case input.path
631
631
  when /\.scss$/; :scss
632
632
  when /\.sass$/; :sass
633
- when /\.less$/; :less
633
+ when /\.less$/; raise "sass-convert no longer supports LessCSS."
634
634
  when /\.css$/; :css
635
635
  end
636
636
  elsif @options[:in_place]
@@ -654,11 +654,6 @@ END
654
654
  if @options[:from] == :css
655
655
  require 'sass/css'
656
656
  ::Sass::CSS.new(input.read, @options[:for_tree]).render(@options[:to])
657
- elsif @options[:from] == :less
658
- require 'sass/less'
659
- try_less_note
660
- input = input.read if input.is_a?(IO) && !input.is_a?(File) # Less is dumb
661
- Less::Engine.new(input).to_tree.to_sass_tree.send("to_#{@options[:to]}", @options[:for_tree])
662
657
  else
663
658
  if input.is_a?(File)
664
659
  ::Sass::Engine.for_file(input.path, @options[:for_engine])
@@ -677,17 +672,6 @@ END
677
672
  rescue LoadError => err
678
673
  handle_load_error(err)
679
674
  end
680
-
681
- @@less_note_printed = false
682
- def try_less_note
683
- return if @@less_note_printed
684
- @@less_note_printed = true
685
- warn <<NOTE
686
- * NOTE: Sass and Less are different languages, and they work differently.
687
- * I'll do my best to translate, but some features -- especially mixins --
688
- * should be checked by hand.
689
- NOTE
690
- end
691
675
  end
692
676
  end
693
677
  end
@@ -73,20 +73,6 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
73
73
  end
74
74
  end
75
75
 
76
- def invalid_function_parent?(parent, child)
77
- "Functions may only be defined at the root of a document." unless parent.is_a?(Sass::Tree::RootNode)
78
- end
79
-
80
- VALID_FUNCTION_CHILDREN = [
81
- Sass::Tree::CommentNode, Sass::Tree::DebugNode, Sass::Tree::ReturnNode,
82
- Sass::Tree::VariableNode, Sass::Tree::WarnNode
83
- ] + CONTROL_NODES
84
- def invalid_function_child?(parent, child)
85
- unless is_any_of?(child, VALID_FUNCTION_CHILDREN)
86
- "Functions can only contain variable declarations and control directives."
87
- end
88
- end
89
-
90
76
  INVALID_IMPORT_PARENTS = CONTROL_NODES +
91
77
  [Sass::Tree::MixinDefNode, Sass::Tree::MixinNode]
92
78
  def invalid_import_parent?(parent, child)
@@ -95,10 +81,6 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
95
81
  end
96
82
  return if parent.is_a?(Sass::Tree::RootNode)
97
83
  return "CSS import directives may only be used at the root of a document." if child.css_import?
98
- # If this is a nested @import, we need to make sure it doesn't have anything
99
- # that's legal at top-level but not in the current context (e.g. mixin defs).
100
- child.imported_file.to_tree.children.each {|c| visit(c)}
101
- nil
102
84
  rescue Sass::SyntaxError => e
103
85
  e.modify_backtrace(:filename => child.imported_file.options[:filename])
104
86
  e.add_backtrace(:filename => child.filename, :line => child.line)
@@ -106,7 +88,25 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
106
88
  end
107
89
 
108
90
  def invalid_mixindef_parent?(parent, child)
109
- "Mixins may only be defined at the root of a document." unless parent.is_a?(Sass::Tree::RootNode)
91
+ unless (@parents.map {|p| p.class} & INVALID_IMPORT_PARENTS).empty?
92
+ return "Mixins may not be defined within control directives or other mixins."
93
+ end
94
+ end
95
+
96
+ def invalid_function_parent?(parent, child)
97
+ unless (@parents.map {|p| p.class} & INVALID_IMPORT_PARENTS).empty?
98
+ return "Functions may not be defined within control directives or other mixins."
99
+ end
100
+ end
101
+
102
+ VALID_FUNCTION_CHILDREN = [
103
+ Sass::Tree::CommentNode, Sass::Tree::DebugNode, Sass::Tree::ReturnNode,
104
+ Sass::Tree::VariableNode, Sass::Tree::WarnNode
105
+ ] + CONTROL_NODES
106
+ def invalid_function_child?(parent, child)
107
+ unless is_any_of?(child, VALID_FUNCTION_CHILDREN)
108
+ "Functions can only contain variable declarations and control directives."
109
+ end
110
110
  end
111
111
 
112
112
  VALID_PROP_CHILDREN = [Sass::Tree::CommentNode, Sass::Tree::PropNode, Sass::Tree::MixinNode] + CONTROL_NODES
@@ -148,7 +148,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
148
148
  end
149
149
 
150
150
  def visit_media(node)
151
- "#{tab_str}@media #{interp_to_src(node.query)}#{yield}"
151
+ "#{tab_str}@media #{media_interp_to_src(node.query)}#{yield}"
152
152
  end
153
153
 
154
154
  def visit_supports(node)
@@ -243,6 +243,22 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
243
243
  end.join
244
244
  end
245
245
 
246
+ # Like interp_to_src, but removes the unnecessary `#{}` around the keys and
247
+ # values in media expressions.
248
+ def media_interp_to_src(interp)
249
+ Sass::Util.enum_with_index(interp).map do |r, i|
250
+ next r if r.is_a?(String)
251
+ before, after = interp[i-1], interp[i+1]
252
+ if before.is_a?(String) && after.is_a?(String) &&
253
+ ((before[-1] == ?( && after[0] == ?:) ||
254
+ (before =~ /:\s*/ && after[0] == ?)))
255
+ r.to_sass(@options)
256
+ else
257
+ "\#{#{r.to_sass(@options)}}"
258
+ end
259
+ end.join
260
+ end
261
+
246
262
  def selector_to_src(sel)
247
263
  @format == :sass ? selector_to_sass(sel) : selector_to_scss(sel)
248
264
  end
@@ -61,6 +61,7 @@ class Sass::Tree::Visitors::Extend < Sass::Tree::Visitors::Base
61
61
  WARNING on line #{ex.node.line}#{" of #{ex.node.filename}" if ex.node.filename}: #{warn}
62
62
  #{reason}
63
63
  This will be an error in future releases of Sass.
64
+ Use "@extend #{ex.target.join} !optional" if the extend should be able to fail.
64
65
  WARN
65
66
  end
66
67
  end
@@ -25,7 +25,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
25
25
 
26
26
  # Keeps track of the current environment.
27
27
  def visit_children(parent)
28
- with_environment Sass::Environment.new(@environment) do
28
+ with_environment Sass::Environment.new(@environment, parent.options) do
29
29
  parent.children = super.flatten
30
30
  parent
31
31
  end
@@ -45,7 +45,6 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
45
45
 
46
46
  # Sets the options on the environment if this is the top-level root.
47
47
  def visit_root(node)
48
- @environment.options = node.options if @environment.options.nil? || @environment.options.empty?
49
48
  yield
50
49
  rescue Sass::SyntaxError => e
51
50
  e.sass_template ||= node.template
@@ -113,8 +112,9 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
113
112
 
114
113
  # Loads the function into the environment.
115
114
  def visit_function(node)
116
- @environment.set_function(node.name,
117
- Sass::Callable.new(node.name, node.args, @environment, node.children, !:has_content))
115
+ env = Sass::Environment.new(@environment, node.options)
116
+ @environment.set_local_function(node.name,
117
+ Sass::Callable.new(node.name, node.args, env, node.children, !:has_content))
118
118
  []
119
119
  end
120
120
 
@@ -155,8 +155,9 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
155
155
 
156
156
  # Loads a mixin into the environment.
157
157
  def visit_mixindef(node)
158
- @environment.set_mixin(node.name,
159
- Sass::Callable.new(node.name, node.args, @environment, node.children, node.has_content))
158
+ env = Sass::Environment.new(@environment, node.options)
159
+ @environment.set_local_mixin(node.name,
160
+ Sass::Callable.new(node.name, node.args, env, node.children, node.has_content))
160
161
  []
161
162
  end
162
163
 
data/test/Gemfile CHANGED
@@ -1,4 +1,3 @@
1
1
  source :gemcutter
2
2
 
3
3
  gem 'rake'
4
- gem 'less', '< 2.0.0'
data/test/Gemfile.lock CHANGED
@@ -1,19 +1,10 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- less (1.2.21)
5
- mutter (>= 0.4.2)
6
- treetop (>= 1.4.2)
7
- mutter (0.5.3)
8
- polyglot (0.3.2)
9
4
  rake (0.9.2)
10
- treetop (1.4.10)
11
- polyglot
12
- polyglot (>= 0.3.1)
13
5
 
14
6
  PLATFORMS
15
7
  ruby
16
8
 
17
9
  DEPENDENCIES
18
- less (< 2.0.0)
19
10
  rake
@@ -1160,14 +1160,13 @@ SCSS
1160
1160
  end
1161
1161
 
1162
1162
  def test_media_with_expressions
1163
- # TODO: get rid of the #{} in the expression output
1164
1163
  assert_sass_to_scss <<SCSS, <<SASS
1165
1164
  $media1: screen;
1166
1165
  $media2: print;
1167
1166
  $var: -webkit-min-device-pixel-ratio;
1168
1167
  $val: 20;
1169
1168
 
1170
- @media \#{$media1} and (\#{$var + "-foo"}: \#{$val + 5}), only \#{$media2} {
1169
+ @media \#{$media1} and ($var + "-foo": $val + 5), only \#{$media2} {
1171
1170
  a: b;
1172
1171
  }
1173
1172
  SCSS
@@ -1186,7 +1185,7 @@ $media2: print
1186
1185
  $var: -webkit-min-device-pixel-ratio
1187
1186
  $val: 20
1188
1187
 
1189
- @media \#{$media1} and (\#{$var + "-foo"}: \#{$val + 5}), only \#{$media2}
1188
+ @media \#{$media1} and ($var + "-foo": $val + 5), only \#{$media2}
1190
1189
  a: b
1191
1190
  SASS
1192
1191
  $media1: screen;
@@ -1565,6 +1564,16 @@ SCSS
1565
1564
 
1566
1565
  ## Regression Tests
1567
1566
 
1567
+ def test_media_query_with_expr
1568
+ assert_scss_to_sass <<SASS, <<SCSS
1569
+ @media foo and (bar: baz)
1570
+ a: b
1571
+ SASS
1572
+ @media foo and (bar: baz) {
1573
+ a: b; }
1574
+ SCSS
1575
+ end
1576
+
1568
1577
  def test_empty_lists
1569
1578
  assert_renders(<<SASS, <<SCSS)
1570
1579
  $foo: ()
@@ -73,7 +73,7 @@ MSG
73
73
  "=foo\n :color red\n.bar\n +bang" => "Undefined mixin 'bang'.",
74
74
  "=foo\n :color red\n.bar\n +bang_bop" => "Undefined mixin 'bang_bop'.",
75
75
  "=foo\n :color red\n.bar\n +bang-bop" => "Undefined mixin 'bang-bop'.",
76
- ".bar\n =foo\n :color red\n" => ["Mixins may only be defined at the root of a document.", 2],
76
+ ".foo\n =foo\n :color red\n.bar\n +foo" => "Undefined mixin 'foo'.",
77
77
  " a\n b: c" => ["Indenting at the beginning of the document is illegal.", 1],
78
78
  " \n \n\t\n a\n b: c" => ["Indenting at the beginning of the document is illegal.", 4],
79
79
  "a\n b: c\n b: c" => ["Inconsistent indentation: 1 space was used for indentation, but the rest of the document was indented using 2 spaces.", 3],
@@ -105,7 +105,6 @@ MSG
105
105
  "@function foo($)\n @return 1" => ['Invalid CSS after "(": expected variable (e.g. $foo), was "$)"', 1],
106
106
  "@function foo()\n @return" => 'Invalid @return: expected expression.',
107
107
  "@function foo()\n @return 1\n $var: val" => 'Illegal nesting: Nothing may be nested beneath return directives.',
108
- "foo\n @function bar()\n @return 1" => ['Functions may only be defined at the root of a document.', 2],
109
108
  "@function foo($a)\n @return 1\na\n b: foo()" => 'Function foo is missing argument $a',
110
109
  "@function foo()\n @return 1\na\n b: foo(2)" => 'Wrong number of arguments (1 for 0) for `foo\'',
111
110
  "@function foo()\n @return 1\na\n b: foo($a: 1)" => "Function foo doesn't have an argument named $a",
@@ -274,7 +273,7 @@ SASS
274
273
  end
275
274
 
276
275
  def test_imported_exception
277
- [1, 2, 3, 4, 5].each do |i|
276
+ [1, 2, 3, 4].each do |i|
278
277
  begin
279
278
  Sass::Engine.new("@import bork#{i}", :load_paths => [File.dirname(__FILE__) + '/templates/']).render
280
279
  rescue Sass::SyntaxError => err
@@ -296,7 +295,7 @@ SASS
296
295
  end
297
296
 
298
297
  def test_double_imported_exception
299
- [1, 2, 3, 4, 5].each do |i|
298
+ [1, 2, 3, 4].each do |i|
300
299
  begin
301
300
  Sass::Engine.new("@import nested_bork#{i}", :load_paths => [File.dirname(__FILE__) + '/templates/']).render
302
301
  rescue Sass::SyntaxError => err
@@ -723,24 +722,6 @@ CSS
723
722
  SASS
724
723
  end
725
724
 
726
- def test_nested_import_with_toplevel_constructs
727
- Sass::Engine.new(".foo\n @import importee", :load_paths => [File.dirname(__FILE__) + '/templates/']).render
728
- rescue Sass::SyntaxError => err
729
- assert_equal(3, err.sass_line)
730
- assert_match(/(\/|^)importee\.sass$/, err.sass_filename)
731
-
732
- assert_hash_has(err.sass_backtrace.first,
733
- :filename => err.sass_filename, :line => err.sass_line)
734
-
735
- assert_nil(err.sass_backtrace[1][:filename])
736
- assert_equal(2, err.sass_backtrace[1][:line])
737
-
738
- assert_match(/(\/|^)importee\.sass:3$/, err.backtrace.first)
739
- assert_equal("(sass):2", err.backtrace[1])
740
- else
741
- assert(false, "Exception not raised for importing mixins nested")
742
- end
743
-
744
725
  def test_units
745
726
  renders_correctly "units"
746
727
  end
@@ -1119,6 +1119,7 @@ end
1119
1119
  WARNING on line 1 of test_extend_warns_when_extendee_doesnt_exist_inline.scss: ".foo" failed to @extend ".bar".
1120
1120
  The selector ".bar" was not found.
1121
1121
  This will be an error in future releases of Sass.
1122
+ Use "@extend .bar !optional" if the extend should be able to fail.
1122
1123
  WARN
1123
1124
  .foo {@extend .bar}
1124
1125
  SCSS
@@ -1129,6 +1130,7 @@ SCSS
1129
1130
  WARNING on line 2 of test_extend_warns_when_extension_fails_inline.scss: "b.foo" failed to @extend ".bar".
1130
1131
  No selectors matching ".bar" could be unified with "b.foo".
1131
1132
  This will be an error in future releases of Sass.
1133
+ Use "@extend .bar !optional" if the extend should be able to fail.
1132
1134
  WARN
1133
1135
  a.bar {
1134
1136
  a: b; }
@@ -1305,6 +1307,7 @@ SCSS
1305
1307
  WARNING on line #{line} of #{filename_for_test syntax}: #{warn}
1306
1308
  #{reason}
1307
1309
  This will be an error in future releases of Sass.
1310
+ Use "@extend #{target} !optional" if the extend should be able to fail.
1308
1311
  WARNING
1309
1312
  end
1310
1313
 
@@ -4,11 +4,18 @@ require File.dirname(__FILE__) + '/test_helper'
4
4
  require 'sass/plugin'
5
5
  require 'fileutils'
6
6
 
7
+ module Sass::Script::Functions
8
+ def filename
9
+ filename = options[:filename].gsub(%r{.*((/[^/]+){4})}, '\1')
10
+ Sass::Script::String.new(filename)
11
+ end
12
+ end
13
+
7
14
  class SassPluginTest < Test::Unit::TestCase
8
15
  @@templates = %w{
9
16
  complex script parent_ref import scss_import alt
10
17
  subdir/subdir subdir/nested_subdir/nested_subdir
11
- options import_content
18
+ options import_content filename_fn
12
19
  }
13
20
  @@templates += %w[import_charset import_charset_ibm866] unless Sass::Util.ruby1_8?
14
21
  @@templates << 'import_charset_1_8' if Sass::Util.ruby1_8?
@@ -0,0 +1,3 @@
1
+ filename { imported: /test/sass/templates/_filename_fn_import.scss; }
2
+
3
+ filename { local: /test/sass/templates/filename_fn.scss; local-mixin: /test/sass/templates/filename_fn.scss; local-function: /test/sass/templates/filename_fn.scss; imported-mixin: /test/sass/templates/_filename_fn_import.scss; imported-function: /test/sass/templates/_filename_fn_import.scss; }
@@ -554,9 +554,9 @@ SASS
554
554
 
555
555
  def eval(str, opts = {}, environment = env)
556
556
  munge_filename opts
557
- environment.options = opts
558
557
  Sass::Script.parse(str, opts.delete(:line) || 1,
559
- opts.delete(:offset) || 0, opts).perform(environment)
558
+ opts.delete(:offset) || 0, opts).
559
+ perform(Sass::Environment.new(environment, opts))
560
560
  end
561
561
 
562
562
  def render(sass, options = {})