sass 3.2.5 → 3.2.6

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 (56) hide show
  1. data/VERSION +1 -1
  2. data/VERSION_DATE +1 -1
  3. data/bin/sass +2 -1
  4. data/bin/sass-convert +2 -1
  5. data/bin/scss +2 -1
  6. data/lib/sass/cache_stores/chain.rb +1 -1
  7. data/lib/sass/cache_stores/filesystem.rb +0 -1
  8. data/lib/sass/engine.rb +7 -1
  9. data/lib/sass/importers/filesystem.rb +1 -1
  10. data/lib/sass/media.rb +1 -4
  11. data/lib/sass/script/funcall.rb +43 -8
  12. data/lib/sass/script/lexer.rb +0 -2
  13. data/lib/sass/script/parser.rb +0 -2
  14. data/lib/sass/scss/parser.rb +13 -1
  15. data/lib/sass/selector/simple_sequence.rb +1 -1
  16. data/lib/sass/tree/comment_node.rb +2 -2
  17. data/lib/sass/tree/visitors/cssize.rb +10 -1
  18. data/lib/sass/tree/visitors/perform.rb +4 -2
  19. data/lib/sass/util.rb +54 -1
  20. data/lib/sass/util/multibyte_string_scanner.rb +29 -8
  21. data/test/sass/engine_test.rb +16 -0
  22. data/test/sass/extend_test.rb +15 -0
  23. data/test/sass/script_test.rb +3 -1
  24. data/vendor/listen/CHANGELOG.md +76 -2
  25. data/vendor/listen/CONTRIBUTING.md +38 -0
  26. data/vendor/listen/Gemfile +8 -1
  27. data/vendor/listen/Guardfile +1 -1
  28. data/vendor/listen/LICENSE +1 -1
  29. data/vendor/listen/README.md +8 -5
  30. data/vendor/listen/lib/listen.rb +7 -5
  31. data/vendor/listen/lib/listen/adapter.rb +76 -29
  32. data/vendor/listen/lib/listen/adapters/bsd.rb +112 -0
  33. data/vendor/listen/lib/listen/adapters/darwin.rb +11 -10
  34. data/vendor/listen/lib/listen/adapters/linux.rb +33 -30
  35. data/vendor/listen/lib/listen/adapters/polling.rb +2 -1
  36. data/vendor/listen/lib/listen/adapters/windows.rb +27 -21
  37. data/vendor/listen/lib/listen/dependency_manager.rb +126 -0
  38. data/vendor/listen/lib/listen/directory_record.rb +63 -10
  39. data/vendor/listen/lib/listen/listener.rb +22 -0
  40. data/vendor/listen/lib/listen/multi_listener.rb +22 -0
  41. data/vendor/listen/lib/listen/version.rb +1 -1
  42. data/vendor/listen/listen.gemspec +0 -4
  43. data/vendor/listen/spec/listen/adapter_spec.rb +45 -4
  44. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
  45. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +6 -0
  46. data/vendor/listen/spec/listen/adapters/linux_spec.rb +6 -0
  47. data/vendor/listen/spec/listen/adapters/windows_spec.rb +7 -1
  48. data/vendor/listen/spec/listen/dependency_manager_spec.rb +107 -0
  49. data/vendor/listen/spec/listen/directory_record_spec.rb +91 -4
  50. data/vendor/listen/spec/listen/listener_spec.rb +14 -0
  51. data/vendor/listen/spec/listen/multi_listener_spec.rb +19 -1
  52. data/vendor/listen/spec/spec_helper.rb +6 -3
  53. data/vendor/listen/spec/support/adapter_helper.rb +125 -212
  54. data/vendor/listen/spec/support/listeners_helper.rb +13 -1
  55. data/vendor/listen/spec/support/platform_helper.rb +4 -0
  56. metadata +9 -3
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.5
1
+ 3.2.6
@@ -1 +1 @@
1
- 05 January 2013 02:49:12 UTC
1
+ 23 February 2013 01:41:39 UTC
data/bin/sass CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # The command line Sass parser.
3
3
 
4
- require File.dirname(__FILE__) + '/../lib/sass'
4
+ THIS_FILE = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
5
+ require File.dirname(THIS_FILE) + '/../lib/sass'
5
6
  require 'sass/exec'
6
7
 
7
8
  opts = Sass::Exec::Sass.new(ARGV)
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require File.dirname(__FILE__) + '/../lib/sass'
3
+ THIS_FILE = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
4
+ require File.dirname(THIS_FILE) + '/../lib/sass'
4
5
  require 'sass/exec'
5
6
 
6
7
  opts = Sass::Exec::SassConvert.new(ARGV)
data/bin/scss CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # The command line Sass parser.
3
3
 
4
- require File.dirname(__FILE__) + '/../lib/sass'
4
+ THIS_FILE = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
5
+ require File.dirname(THIS_FILE) + '/../lib/sass'
5
6
  require 'sass/exec'
6
7
 
7
8
  opts = Sass::Exec::Scss.new(ARGV)
@@ -23,7 +23,7 @@ module Sass
23
23
  def retrieve(key, sha)
24
24
  @caches.each_with_index do |c, i|
25
25
  next unless obj = c.retrieve(key, sha)
26
- @caches[0...i].each {|c| c.store(key, sha, obj)}
26
+ @caches[0...i].each {|prev| prev.store(key, sha, obj)}
27
27
  return obj
28
28
  end
29
29
  nil
@@ -17,7 +17,6 @@ module Sass
17
17
  # @see Base#\_retrieve
18
18
  def _retrieve(key, version, sha)
19
19
  return unless File.readable?(path_to(key))
20
- contents = nil
21
20
  File.open(path_to(key), "rb") do |f|
22
21
  if f.readline("\n").strip == version && f.readline("\n").strip == sha
23
22
  return f.read
@@ -293,7 +293,7 @@ module Sass
293
293
  # @return [[Sass::Engine]] The dependency documents.
294
294
  def dependencies
295
295
  _dependencies(Set.new, engines = Set.new)
296
- engines - [self]
296
+ Sass::Util.array_minus(engines, [self])
297
297
  end
298
298
 
299
299
  # Helper for \{#dependencies}.
@@ -714,6 +714,12 @@ WARNING
714
714
  parser = Sass::SCSS::Parser.new(value, @options[:filename], @line)
715
715
  Tree::MediaNode.new(parser.parse_media_query_list.to_a)
716
716
  else
717
+ unprefixed_directive = directive.gsub(/^-[a-z0-9]+-/i, '')
718
+ if unprefixed_directive == 'supports'
719
+ parser = Sass::SCSS::Parser.new(value, @options[:filename], @line)
720
+ return Tree::SupportsNode.new(directive, parser.parse_supports_condition)
721
+ end
722
+
717
723
  Tree::DirectiveNode.new(
718
724
  value.nil? ? ["@#{directive}"] : ["@#{directive} "] + parse_interp(value, offset))
719
725
  end
@@ -30,7 +30,7 @@ module Sass
30
30
 
31
31
  # @see Base#mtime
32
32
  def mtime(name, options)
33
- file, s = Sass::Util.destructure(find_real_file(@root, name, options))
33
+ file, _ = Sass::Util.destructure(find_real_file(@root, name, options))
34
34
  File.mtime(file) if file
35
35
  rescue Errno::ENOENT
36
36
  nil
@@ -140,10 +140,7 @@ module Sass::Media
140
140
  type = t1
141
141
  mod = m1.empty? ? m2 : m1
142
142
  end
143
- q = Query.new([], [], other.expressions + expressions)
144
- q.type = [type]
145
- q.modifier = [mod]
146
- return q
143
+ return Query.new([mod], [type], other.expressions + expressions)
147
144
  end
148
145
 
149
146
  # Returns the CSS for the media query.
@@ -106,18 +106,53 @@ module Sass
106
106
  opts(Functions::EvaluationContext.new(environment.options).send(ruby_name, *args))
107
107
  end
108
108
  rescue ArgumentError => e
109
+ message = e.message
110
+
109
111
  # If this is a legitimate Ruby-raised argument error, re-raise it.
110
112
  # Otherwise, it's an error in the user's stylesheet, so wrap it.
111
- if e.message =~ /^wrong number of arguments \(\d+ for \d+\)/ &&
112
- e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/ &&
113
- # JRuby (as of 1.6.7.2) doesn't put the actual method for
114
- # which the argument error was thrown in the backtrace, so
115
- # we detect whether our send threw an argument error.
116
- (RUBY_PLATFORM !~ /java/ || e.backtrace[0] !~ /:in `send'$/ ||
117
- e.backtrace[1] !~ /:in `_perform'$/)
113
+ if Sass::Util.rbx?
114
+ # Rubinius has a different error report string than vanilla Ruby. It
115
+ # also doesn't put the actual method for which the argument error was
116
+ # thrown in the backtrace, nor does it include `send`, so we look for
117
+ # `_perform`.
118
+ if e.message =~ /^method '([^']+)': given (\d+), expected (\d+)/
119
+ error_name, given, expected = $1, $2, $3
120
+ raise e if error_name != ruby_name || e.backtrace[0] !~ /:in `_perform'$/
121
+ message = "wrong number of arguments (#{given} for #{expected})"
122
+ end
123
+ elsif Sass::Util.jruby?
124
+ if Sass::Util.jruby1_6?
125
+ should_maybe_raise = e.message =~ /^wrong number of arguments \((\d+) for (\d+)\)/ &&
126
+ # The one case where JRuby does include the Ruby name of the function
127
+ # is manually-thrown ArgumentErrors, which are indistinguishable from
128
+ # legitimate ArgumentErrors. We treat both of these as
129
+ # Sass::SyntaxErrors even though it can hide Ruby errors.
130
+ e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
131
+ else
132
+ should_maybe_raise = e.message =~ /^wrong number of arguments calling `[^`]+` \((\d+) for (\d+)\)/
133
+ given, expected = $1, $2
134
+ end
135
+
136
+ if should_maybe_raise
137
+ # JRuby 1.7 includes __send__ before send and _perform.
138
+ trace = e.backtrace.dup
139
+ raise e if !Sass::Util.jruby1_6? && trace.shift !~ /:in `__send__'$/
140
+
141
+ # JRuby (as of 1.7.2) doesn't put the actual method
142
+ # for which the argument error was thrown in the backtrace, so we
143
+ # detect whether our send threw an argument error.
144
+ if !(trace[0] =~ /:in `send'$/ && trace[1] =~ /:in `_perform'$/)
145
+ raise e
146
+ elsif !Sass::Util.jruby1_6?
147
+ # JRuby 1.7 doesn't use standard formatting for its ArgumentErrors.
148
+ message = "wrong number of arguments (#{given} for #{expected})"
149
+ end
150
+ end
151
+ elsif e.message =~ /^wrong number of arguments \(\d+ for \d+\)/ &&
152
+ e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
118
153
  raise e
119
154
  end
120
- raise Sass::SyntaxError.new("#{e.message} for `#{name}'")
155
+ raise Sass::SyntaxError.new("#{message} for `#{name}'")
121
156
  end
122
157
 
123
158
  # This method is factored out from `_perform` so that compass can override
@@ -245,8 +245,6 @@ module Sass
245
245
  end
246
246
 
247
247
  def _variable(rx)
248
- line = @line
249
- offset = @offset
250
248
  return unless scan(rx)
251
249
 
252
250
  [:const, @scanner[2]]
@@ -346,8 +346,6 @@ RUBY
346
346
  splat = nil
347
347
  must_have_default = false
348
348
  loop do
349
- line = @lexer.line
350
- offset = @lexer.offset + 1
351
349
  c = assert_tok(:const)
352
350
  var = Script::Variable.new(c.value)
353
351
  if try_tok(:colon)
@@ -52,6 +52,18 @@ module Sass
52
52
  ql
53
53
  end
54
54
 
55
+ # Parses a supports query condition.
56
+ #
57
+ # @return [Sass::Supports::Condition] The parsed condition
58
+ # @raise [Sass::SyntaxError] if there's a syntax error in the condition,
59
+ # or if it doesn't take up the entire input string.
60
+ def parse_supports_condition
61
+ init_scanner!
62
+ condition = supports_condition
63
+ expected("supports condition") unless @scanner.eos?
64
+ condition
65
+ end
66
+
55
67
  private
56
68
 
57
69
  include Sass::SCSS::RX
@@ -986,7 +998,7 @@ MESSAGE
986
998
  line = @line
987
999
  @strs.push ""
988
1000
  throw_error {yield} && @strs.last
989
- rescue Sass::SyntaxError => e
1001
+ rescue Sass::SyntaxError
990
1002
  @scanner.pos = pos
991
1003
  @line = line
992
1004
  nil
@@ -101,7 +101,7 @@ module Sass
101
101
  # If A {@extend B} and C {...},
102
102
  # seq is A, sels is B, and self is C
103
103
 
104
- self_without_sel = self.members - sels
104
+ self_without_sel = Sass::Util.array_minus(self.members, sels)
105
105
  group.each {|e, _| e.result = :failed_to_unify unless e.result == :succeeded}
106
106
  next unless unified = seq.members.last.unify(self_without_sel, subject?)
107
107
  group.each {|e, _| e.result = :succeeded}
@@ -70,13 +70,13 @@ module Sass::Tree
70
70
  private
71
71
 
72
72
  def normalize_indentation(str)
73
- pre = str.split("\n").inject(str[/^[ \t]*/].split("")) do |pre, line|
73
+ ind = str.split("\n").inject(str[/^[ \t]*/].split("")) do |pre, line|
74
74
  line[/^[ \t]*/].split("").zip(pre).inject([]) do |arr, (a, b)|
75
75
  break arr if a != b
76
76
  arr << a
77
77
  end
78
78
  end.join
79
- str.gsub(/^#{pre}/, '')
79
+ str.gsub(/^#{ind}/, '')
80
80
  end
81
81
  end
82
82
  end
@@ -32,6 +32,8 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
32
32
  end
33
33
  end
34
34
 
35
+ MERGEABLE_DIRECTIVES = [Sass::Tree::MediaNode]
36
+
35
37
  # Runs a block of code with the current parent node
36
38
  # replaced with the given node.
37
39
  #
@@ -39,11 +41,18 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
39
41
  # @yield A block in which the parent is set to `parent`.
40
42
  # @return [Object] The return value of the block.
41
43
  def with_parent(parent)
42
- @parent_directives.push parent if parent.is_a?(Sass::Tree::DirectiveNode)
44
+ if parent.is_a?(Sass::Tree::DirectiveNode)
45
+ if MERGEABLE_DIRECTIVES.any? {|klass| parent.is_a?(klass)}
46
+ old_parent_directive = @parent_directives.pop
47
+ end
48
+ @parent_directives.push parent
49
+ end
50
+
43
51
  old_parent, @parent = @parent, parent
44
52
  yield
45
53
  ensure
46
54
  @parent_directives.pop if parent.is_a?(Sass::Tree::DirectiveNode)
55
+ @parent_directives.push old_parent_directive if old_parent_directive
47
56
  @parent = old_parent
48
57
  end
49
58
 
@@ -14,11 +14,13 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
14
14
 
15
15
  begin
16
16
  unless keywords.empty?
17
- unknown_args = keywords.keys - callable.args.map {|var| var.first.underscored_name}
17
+ unknown_args = Sass::Util.array_minus(keywords.keys,
18
+ callable.args.map {|var| var.first.underscored_name})
18
19
  if callable.splat && unknown_args.include?(callable.splat.underscored_name)
19
20
  raise Sass::SyntaxError.new("Argument $#{callable.splat.name} of #{downcase_desc} cannot be used as a named argument.")
20
21
  elsif unknown_args.any?
21
- raise Sass::SyntaxError.new("#{desc} doesn't have #{unknown_args.length > 1 ? 'the following arguments:' : 'an argument named'} #{unknown_args.map{|name| "$#{name}"}.join ', '}.")
22
+ description = unknown_args.length > 1 ? 'the following arguments:' : 'an argument named'
23
+ raise Sass::SyntaxError.new("#{desc} doesn't have #{description} #{unknown_args.map {|name| "$#{name}"}.join ', '}.")
22
24
  end
23
25
  end
24
26
  rescue Sass::SyntaxError => keyword_exception
@@ -256,6 +256,33 @@ module Sass
256
256
  arr
257
257
  end
258
258
 
259
+ # Returns a sub-array of `minuend` containing only elements that are also in
260
+ # `subtrahend`. Ensures that the return value has the same order as
261
+ # `minuend`, even on Rubinius where that's not guaranteed by {Array#-}.
262
+ #
263
+ # @param minuend [Array]
264
+ # @param subtrahend [Array]
265
+ # @return [Array]
266
+ def array_minus(minuend, subtrahend)
267
+ return minuend - subtrahend unless rbx?
268
+ set = Set.new(minuend) - subtrahend
269
+ minuend.select {|e| set.include?(e)}
270
+ end
271
+
272
+ # Returns a string description of the character that caused an
273
+ # `Encoding::UndefinedConversionError`.
274
+ #
275
+ # @param [Encoding::UndefinedConversionError]
276
+ # @return [String]
277
+ def undefined_conversion_error_char(e)
278
+ # Rubinius (as of 2.0.0.rc1) pre-quotes the error character.
279
+ return e.error_char if rbx?
280
+ # JRuby (as of 1.7.2) doesn't have an error_char field on
281
+ # Encoding::UndefinedConversionError.
282
+ return e.error_char.dump unless jruby?
283
+ e.message[/^"[^"]+"/] #"
284
+ end
285
+
259
286
  # Asserts that `value` falls within `range` (inclusive), leaving
260
287
  # room for slight floating-point errors.
261
288
  #
@@ -462,6 +489,27 @@ module Sass
462
489
  RUBY_ENGINE == "ironruby"
463
490
  end
464
491
 
492
+ # Whether or not this is running on Rubinius.
493
+ #
494
+ # @return [Boolean]
495
+ def rbx?
496
+ RUBY_ENGINE == "rbx"
497
+ end
498
+
499
+ # Whether or not this is running on JRuby.
500
+ #
501
+ # @return [Boolean]
502
+ def jruby?
503
+ RUBY_PLATFORM =~ /java/
504
+ end
505
+
506
+ # Returns an array of ints representing the JRuby version number.
507
+ #
508
+ # @return [Array<Fixnum>]
509
+ def jruby_version
510
+ $jruby_version ||= ::JRUBY_VERSION.split(".").map {|s| s.to_i}
511
+ end
512
+
465
513
  # Like `Dir.glob`, but works with backslash-separated paths on Windows.
466
514
  #
467
515
  # @param path [String]
@@ -512,6 +560,11 @@ module Sass
512
560
  ruby1_8? && Sass::Util::RUBY_VERSION[2] < 7
513
561
  end
514
562
 
563
+ # Wehter or not this is running under JRuby 1.6 or lower.
564
+ def jruby1_6?
565
+ jruby? && jruby_version[0] == 1 && jruby_version[1] < 7
566
+ end
567
+
515
568
  # Whether or not this is running under MacRuby.
516
569
  #
517
570
  # @return [Boolean]
@@ -548,7 +601,7 @@ module Sass
548
601
  line.encode(encoding)
549
602
  rescue Encoding::UndefinedConversionError => e
550
603
  yield <<MSG.rstrip, i + 1
551
- Invalid #{encoding.name} character #{e.error_char.dump}
604
+ Invalid #{encoding.name} character #{undefined_conversion_error_char(e)}
552
605
  MSG
553
606
  end
554
607
  end
@@ -3,23 +3,44 @@ require 'strscan'
3
3
  if Sass::Util.ruby1_8?
4
4
  Sass::Util::MultibyteStringScanner = StringScanner
5
5
  else
6
+ if Sass::Util.rbx?
7
+ # Rubinius's StringScanner class implements some of its methods in terms of
8
+ # others, which causes us to double-count bytes in some cases if we do
9
+ # straightforward inheritance. To work around this, we use a delegate class.
10
+ require 'delegate'
11
+ class Sass::Util::MultibyteStringScanner < DelegateClass(StringScanner)
12
+ def initialize(str)
13
+ super(StringScanner.new(str))
14
+ @mb_pos = 0
15
+ @mb_matched_size = nil
16
+ @mb_last_pos = nil
17
+ end
18
+
19
+ def is_a?(klass)
20
+ __getobj__.is_a?(klass) || super
21
+ end
22
+ end
23
+ else
24
+ class Sass::Util::MultibyteStringScanner < StringScanner
25
+ def initialize(str)
26
+ super
27
+ @mb_pos = 0
28
+ @mb_matched_size = nil
29
+ @mb_last_pos = nil
30
+ end
31
+ end
32
+ end
33
+
6
34
  # A wrapper of the native StringScanner class that works correctly with
7
35
  # multibyte character encodings. The native class deals only in bytes, not
8
36
  # characters, for methods like [#pos] and [#matched_size]. This class deals
9
37
  # only in characters, instead.
10
- class Sass::Util::MultibyteStringScanner < StringScanner
38
+ class Sass::Util::MultibyteStringScanner
11
39
  def self.new(str)
12
40
  return StringScanner.new(str) if str.ascii_only?
13
41
  super
14
42
  end
15
43
 
16
- def initialize(str)
17
- super
18
- @mb_pos = 0
19
- @mb_matched_size = nil
20
- @mb_last_pos = nil
21
- end
22
-
23
44
  alias_method :byte_pos, :pos
24
45
  alias_method :byte_matched_size, :matched_size
25
46
 
@@ -2381,6 +2381,22 @@ SASS
2381
2381
 
2382
2382
  # Regression tests
2383
2383
 
2384
+ def test_supports_bubbles
2385
+ assert_equal <<CSS, render(<<SASS)
2386
+ parent {
2387
+ background: orange; }
2388
+ @supports (perspective: 10px) or (-moz-perspective: 10px) {
2389
+ parent child {
2390
+ background: blue; } }
2391
+ CSS
2392
+ parent
2393
+ background: orange
2394
+ @supports (perspective: 10px) or (-moz-perspective: 10px)
2395
+ child
2396
+ background: blue
2397
+ SASS
2398
+ end
2399
+
2384
2400
  def test_line_numbers_with_dos_line_endings
2385
2401
  assert_equal <<CSS, render(<<SASS, :line_comments => true)
2386
2402
  /* line 5, test_line_numbers_with_dos_line_endings_inline.sass */
@@ -1186,6 +1186,21 @@ SCSS
1186
1186
 
1187
1187
  # Regression Tests
1188
1188
 
1189
+ def test_extend_in_double_nested_media_query
1190
+ assert_equal <<CSS, render(<<SCSS)
1191
+ @media all and (orientation: landscape) {
1192
+ .bar {
1193
+ color: blue; } }
1194
+ CSS
1195
+ @media all {
1196
+ @media (orientation: landscape) {
1197
+ %foo {color: blue}
1198
+ .bar {@extend %foo}
1199
+ }
1200
+ }
1201
+ SCSS
1202
+ end
1203
+
1189
1204
  def test_partially_failed_extend
1190
1205
  assert_no_warning {assert_equal(<<CSS, render(<<SCSS))}
1191
1206
  .rc, test {