sass 3.3.0 → 3.4.25

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 (208) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +3 -1
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/CONTRIBUTING.md +148 -0
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +76 -62
  7. data/Rakefile +104 -24
  8. data/VERSION +1 -1
  9. data/VERSION_DATE +1 -1
  10. data/VERSION_NAME +1 -1
  11. data/bin/sass +1 -1
  12. data/bin/scss +1 -1
  13. data/extra/sass-spec-ref.sh +32 -0
  14. data/extra/update_watch.rb +1 -1
  15. data/lib/sass/cache_stores/filesystem.rb +9 -5
  16. data/lib/sass/cache_stores/memory.rb +4 -5
  17. data/lib/sass/callbacks.rb +2 -2
  18. data/lib/sass/css.rb +12 -13
  19. data/lib/sass/deprecation.rb +55 -0
  20. data/lib/sass/engine.rb +106 -70
  21. data/lib/sass/environment.rb +39 -19
  22. data/lib/sass/error.rb +17 -20
  23. data/lib/sass/exec/base.rb +199 -0
  24. data/lib/sass/exec/sass_convert.rb +283 -0
  25. data/lib/sass/exec/sass_scss.rb +440 -0
  26. data/lib/sass/exec.rb +5 -771
  27. data/lib/sass/features.rb +9 -2
  28. data/lib/sass/importers/base.rb +8 -3
  29. data/lib/sass/importers/filesystem.rb +30 -38
  30. data/lib/sass/logger/base.rb +8 -2
  31. data/lib/sass/logger/delayed.rb +50 -0
  32. data/lib/sass/logger.rb +8 -3
  33. data/lib/sass/media.rb +1 -4
  34. data/lib/sass/plugin/compiler.rb +224 -90
  35. data/lib/sass/plugin/configuration.rb +38 -22
  36. data/lib/sass/plugin/merb.rb +2 -2
  37. data/lib/sass/plugin/rack.rb +3 -3
  38. data/lib/sass/plugin/rails.rb +1 -1
  39. data/lib/sass/plugin/staleness_checker.rb +4 -4
  40. data/lib/sass/plugin.rb +6 -5
  41. data/lib/sass/script/css_lexer.rb +1 -1
  42. data/lib/sass/script/css_parser.rb +2 -3
  43. data/lib/sass/script/css_variable_warning.rb +52 -0
  44. data/lib/sass/script/functions.rb +739 -318
  45. data/lib/sass/script/lexer.rb +134 -54
  46. data/lib/sass/script/parser.rb +252 -56
  47. data/lib/sass/script/tree/funcall.rb +13 -6
  48. data/lib/sass/script/tree/interpolation.rb +127 -4
  49. data/lib/sass/script/tree/list_literal.rb +31 -4
  50. data/lib/sass/script/tree/literal.rb +4 -0
  51. data/lib/sass/script/tree/node.rb +21 -3
  52. data/lib/sass/script/tree/operation.rb +54 -1
  53. data/lib/sass/script/tree/selector.rb +26 -0
  54. data/lib/sass/script/tree/string_interpolation.rb +59 -38
  55. data/lib/sass/script/tree/variable.rb +1 -1
  56. data/lib/sass/script/tree.rb +1 -0
  57. data/lib/sass/script/value/base.rb +17 -14
  58. data/lib/sass/script/value/bool.rb +0 -5
  59. data/lib/sass/script/value/color.rb +78 -42
  60. data/lib/sass/script/value/helpers.rb +119 -2
  61. data/lib/sass/script/value/list.rb +0 -15
  62. data/lib/sass/script/value/map.rb +1 -1
  63. data/lib/sass/script/value/null.rb +0 -5
  64. data/lib/sass/script/value/number.rb +112 -31
  65. data/lib/sass/script/value/string.rb +102 -13
  66. data/lib/sass/script/value.rb +0 -1
  67. data/lib/sass/script.rb +3 -3
  68. data/lib/sass/scss/css_parser.rb +24 -4
  69. data/lib/sass/scss/parser.rb +290 -383
  70. data/lib/sass/scss/rx.rb +17 -9
  71. data/lib/sass/scss/static_parser.rb +306 -4
  72. data/lib/sass/scss.rb +0 -2
  73. data/lib/sass/selector/abstract_sequence.rb +35 -18
  74. data/lib/sass/selector/comma_sequence.rb +114 -19
  75. data/lib/sass/selector/pseudo.rb +266 -0
  76. data/lib/sass/selector/sequence.rb +146 -40
  77. data/lib/sass/selector/simple.rb +22 -33
  78. data/lib/sass/selector/simple_sequence.rb +122 -39
  79. data/lib/sass/selector.rb +57 -197
  80. data/lib/sass/shared.rb +2 -2
  81. data/lib/sass/source/map.rb +31 -14
  82. data/lib/sass/source/position.rb +4 -4
  83. data/lib/sass/stack.rb +2 -8
  84. data/lib/sass/supports.rb +10 -13
  85. data/lib/sass/tree/at_root_node.rb +1 -0
  86. data/lib/sass/tree/charset_node.rb +1 -1
  87. data/lib/sass/tree/comment_node.rb +1 -1
  88. data/lib/sass/tree/css_import_node.rb +9 -1
  89. data/lib/sass/tree/directive_node.rb +8 -2
  90. data/lib/sass/tree/error_node.rb +18 -0
  91. data/lib/sass/tree/extend_node.rb +1 -1
  92. data/lib/sass/tree/function_node.rb +9 -0
  93. data/lib/sass/tree/import_node.rb +6 -5
  94. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  95. data/lib/sass/tree/node.rb +5 -3
  96. data/lib/sass/tree/prop_node.rb +6 -7
  97. data/lib/sass/tree/rule_node.rb +26 -11
  98. data/lib/sass/tree/visitors/check_nesting.rb +56 -32
  99. data/lib/sass/tree/visitors/convert.rb +59 -44
  100. data/lib/sass/tree/visitors/cssize.rb +34 -30
  101. data/lib/sass/tree/visitors/deep_copy.rb +6 -1
  102. data/lib/sass/tree/visitors/extend.rb +15 -13
  103. data/lib/sass/tree/visitors/perform.rb +87 -50
  104. data/lib/sass/tree/visitors/set_options.rb +15 -1
  105. data/lib/sass/tree/visitors/to_css.rb +72 -43
  106. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  107. data/lib/sass/util/normalized_map.rb +0 -1
  108. data/lib/sass/util/subset_map.rb +2 -3
  109. data/lib/sass/util.rb +334 -154
  110. data/lib/sass/version.rb +7 -7
  111. data/lib/sass.rb +10 -8
  112. data/test/sass/cache_test.rb +62 -20
  113. data/test/sass/callbacks_test.rb +1 -1
  114. data/test/sass/compiler_test.rb +24 -11
  115. data/test/sass/conversion_test.rb +241 -50
  116. data/test/sass/css2sass_test.rb +73 -5
  117. data/test/sass/css_variable_test.rb +132 -0
  118. data/test/sass/encoding_test.rb +219 -0
  119. data/test/sass/engine_test.rb +343 -260
  120. data/test/sass/exec_test.rb +12 -2
  121. data/test/sass/extend_test.rb +333 -44
  122. data/test/sass/functions_test.rb +353 -260
  123. data/test/sass/importer_test.rb +40 -21
  124. data/test/sass/logger_test.rb +1 -1
  125. data/test/sass/more_results/more_import.css +1 -1
  126. data/test/sass/more_templates/more1.sass +10 -10
  127. data/test/sass/more_templates/more_import.sass +2 -2
  128. data/test/sass/plugin_test.rb +24 -21
  129. data/test/sass/results/compact.css +1 -1
  130. data/test/sass/results/complex.css +4 -4
  131. data/test/sass/results/expanded.css +1 -1
  132. data/test/sass/results/import.css +1 -1
  133. data/test/sass/results/import_charset_ibm866.css +2 -2
  134. data/test/sass/results/mixins.css +17 -17
  135. data/test/sass/results/nested.css +1 -1
  136. data/test/sass/results/parent_ref.css +2 -2
  137. data/test/sass/results/script.css +5 -5
  138. data/test/sass/results/scss_import.css +1 -1
  139. data/test/sass/script_conversion_test.rb +71 -39
  140. data/test/sass/script_test.rb +714 -123
  141. data/test/sass/scss/css_test.rb +213 -30
  142. data/test/sass/scss/rx_test.rb +8 -4
  143. data/test/sass/scss/scss_test.rb +766 -22
  144. data/test/sass/source_map_test.rb +263 -95
  145. data/test/sass/superselector_test.rb +210 -0
  146. data/test/sass/templates/_partial.sass +1 -1
  147. data/test/sass/templates/basic.sass +10 -10
  148. data/test/sass/templates/bork1.sass +1 -1
  149. data/test/sass/templates/bork5.sass +1 -1
  150. data/test/sass/templates/compact.sass +10 -10
  151. data/test/sass/templates/complex.sass +187 -187
  152. data/test/sass/templates/compressed.sass +10 -10
  153. data/test/sass/templates/expanded.sass +10 -10
  154. data/test/sass/templates/import.sass +2 -2
  155. data/test/sass/templates/importee.sass +3 -3
  156. data/test/sass/templates/mixins.sass +22 -22
  157. data/test/sass/templates/multiline.sass +4 -4
  158. data/test/sass/templates/nested.sass +13 -13
  159. data/test/sass/templates/parent_ref.sass +12 -12
  160. data/test/sass/templates/script.sass +70 -70
  161. data/test/sass/templates/scss_import.scss +2 -1
  162. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
  163. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
  164. data/test/sass/templates/subdir/subdir.sass +3 -3
  165. data/test/sass/templates/units.sass +10 -10
  166. data/test/sass/test_helper.rb +1 -1
  167. data/test/sass/util/multibyte_string_scanner_test.rb +11 -3
  168. data/test/sass/util/normalized_map_test.rb +1 -1
  169. data/test/sass/util/subset_map_test.rb +2 -2
  170. data/test/sass/util_test.rb +46 -45
  171. data/test/sass/value_helpers_test.rb +5 -7
  172. data/test/sass-spec.yml +3 -0
  173. data/test/test_helper.rb +7 -6
  174. data/vendor/listen/CHANGELOG.md +1 -228
  175. data/vendor/listen/Gemfile +5 -15
  176. data/vendor/listen/README.md +111 -77
  177. data/vendor/listen/Rakefile +0 -42
  178. data/vendor/listen/lib/listen/adapter.rb +195 -82
  179. data/vendor/listen/lib/listen/adapters/bsd.rb +27 -64
  180. data/vendor/listen/lib/listen/adapters/darwin.rb +21 -58
  181. data/vendor/listen/lib/listen/adapters/linux.rb +23 -55
  182. data/vendor/listen/lib/listen/adapters/polling.rb +25 -34
  183. data/vendor/listen/lib/listen/adapters/windows.rb +50 -46
  184. data/vendor/listen/lib/listen/directory_record.rb +96 -61
  185. data/vendor/listen/lib/listen/listener.rb +135 -37
  186. data/vendor/listen/lib/listen/turnstile.rb +9 -5
  187. data/vendor/listen/lib/listen/version.rb +1 -1
  188. data/vendor/listen/lib/listen.rb +33 -19
  189. data/vendor/listen/listen.gemspec +6 -0
  190. data/vendor/listen/spec/listen/adapter_spec.rb +43 -77
  191. data/vendor/listen/spec/listen/adapters/polling_spec.rb +8 -8
  192. data/vendor/listen/spec/listen/directory_record_spec.rb +81 -56
  193. data/vendor/listen/spec/listen/listener_spec.rb +128 -39
  194. data/vendor/listen/spec/listen_spec.rb +15 -21
  195. data/vendor/listen/spec/spec_helper.rb +4 -0
  196. data/vendor/listen/spec/support/adapter_helper.rb +52 -15
  197. data/vendor/listen/spec/support/directory_record_helper.rb +7 -5
  198. data/vendor/listen/spec/support/listeners_helper.rb +30 -7
  199. metadata +310 -300
  200. data/CONTRIBUTING +0 -3
  201. data/ext/mkrf_conf.rb +0 -27
  202. data/lib/sass/script/value/deprecated_false.rb +0 -55
  203. data/lib/sass/scss/script_lexer.rb +0 -15
  204. data/lib/sass/scss/script_parser.rb +0 -25
  205. data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
  206. data/vendor/listen/lib/listen/multi_listener.rb +0 -143
  207. data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
  208. data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
@@ -34,25 +34,35 @@ module Sass::Script::Value
34
34
  attr_accessor :original
35
35
 
36
36
  def self.precision
37
- @precision ||= 5
37
+ Thread.current[:sass_numeric_precision] || Thread.main[:sass_numeric_precision] || 5
38
38
  end
39
39
 
40
40
  # Sets the number of digits of precision
41
41
  # For example, if this is `3`,
42
42
  # `3.1415926` will be printed as `3.142`.
43
+ # The numeric precision is stored as a thread local for thread safety reasons.
44
+ # To set for all threads, be sure to set the precision on the main thread.
43
45
  def self.precision=(digits)
44
- @precision = digits.round
45
- @precision_factor = 10.0**@precision
46
+ Thread.current[:sass_numeric_precision] = digits.round
47
+ Thread.current[:sass_numeric_precision_factor] = nil
48
+ Thread.current[:sass_numeric_epsilon] = nil
46
49
  end
47
50
 
48
51
  # the precision factor used in numeric output
49
52
  # it is derived from the `precision` method.
50
53
  def self.precision_factor
51
- @precision_factor ||= 10.0**precision
54
+ Thread.current[:sass_numeric_precision_factor] ||= 10.0**precision
55
+ end
56
+
57
+ # Used in checking equality of floating point numbers. Any
58
+ # numbers within an `epsilon` of each other are considered functionally equal.
59
+ # The value for epsilon is one tenth of the current numeric precision.
60
+ def self.epsilon
61
+ Thread.current[:sass_numeric_epsilon] ||= 1 / (precision_factor * 10)
52
62
  end
53
63
 
54
64
  # Used so we don't allocate two new arrays for each new number.
55
- NO_UNITS = []
65
+ NO_UNITS = []
56
66
 
57
67
  # @param value [Numeric] The value of the number
58
68
  # @param numerator_units [::String, Array<::String>] See \{#numerator\_units}
@@ -63,6 +73,7 @@ module Sass::Script::Value
63
73
  super(value)
64
74
  @numerator_units = numerator_units
65
75
  @denominator_units = denominator_units
76
+ @options = nil
66
77
  normalize!
67
78
  end
68
79
 
@@ -200,7 +211,7 @@ module Sass::Script::Value
200
211
  rescue Sass::UnitConversionError
201
212
  return Bool::FALSE
202
213
  end
203
- Bool.new(this.value == other.value)
214
+ Bool.new(basically_equal?(this.value, other.value))
204
215
  end
205
216
 
206
217
  def hash
@@ -211,7 +222,7 @@ module Sass::Script::Value
211
222
  # Hash-equality must be transitive, so it just compares the exact value,
212
223
  # numerator units, and denominator units.
213
224
  def eql?(other)
214
- value == other.value && numerator_units == other.numerator_units &&
225
+ basically_equal?(value, other.value) && numerator_units == other.numerator_units &&
215
226
  denominator_units == other.denominator_units
216
227
  end
217
228
 
@@ -271,6 +282,8 @@ module Sass::Script::Value
271
282
  #
272
283
  # @return [String] The representation
273
284
  def inspect(opts = {})
285
+ return original if original
286
+
274
287
  value = self.class.round(self.value)
275
288
  str = value.to_s
276
289
 
@@ -279,20 +292,30 @@ module Sass::Script::Value
279
292
  # and confusing.
280
293
  str = ("%0.#{self.class.precision}f" % value).gsub(/0*$/, '') if str.include?('e')
281
294
 
295
+ # Sometimes numeric formatting will result in a decimal number with a trailing zero (x.0)
296
+ if str =~ /(.*)\.0$/
297
+ str = $1
298
+ end
299
+
300
+ # We omit a leading zero before the decimal point in compressed mode.
301
+ if @options && options[:style] == :compressed
302
+ str.sub!(/^(-)?0\./, '\1.')
303
+ end
304
+
282
305
  unitless? ? str : "#{str}#{unit_str}"
283
306
  end
284
307
  alias_method :to_sass, :inspect
285
308
 
286
- # @return [Fixnum] The integer value of the number
309
+ # @return [Integer] The integer value of the number
287
310
  # @raise [Sass::SyntaxError] if the number isn't an integer
288
311
  def to_i
289
312
  super unless int?
290
- value
313
+ value.to_i
291
314
  end
292
315
 
293
316
  # @return [Boolean] Whether or not this number is an integer.
294
317
  def int?
295
- value % 1 == 0.0
318
+ basically_equal?(value % 1, 0.0)
296
319
  end
297
320
 
298
321
  # @return [Boolean] Whether or not this number has no units.
@@ -373,12 +396,24 @@ module Sass::Script::Value
373
396
 
374
397
  private
375
398
 
399
+ # @private
400
+ # @see Sass::Script::Number.basically_equal?
401
+ def basically_equal?(num1, num2)
402
+ self.class.basically_equal?(num1, num2)
403
+ end
404
+
405
+ # Checks whether two numbers are within an epsilon of each other.
406
+ # @return [Boolean]
407
+ def self.basically_equal?(num1, num2)
408
+ (num1 - num2).abs < epsilon
409
+ end
410
+
376
411
  # @private
377
412
  def self.round(num)
378
413
  if num.is_a?(Float) && (num.infinite? || num.nan?)
379
414
  num
380
- elsif num % 1 == 0.0
381
- num.to_i
415
+ elsif basically_equal?(num % 1, 0.0)
416
+ num.round
382
417
  else
383
418
  ((num * precision_factor).round / precision_factor).to_f
384
419
  end
@@ -437,33 +472,79 @@ module Sass::Script::Value
437
472
  sans_common_units(@numerator_units, @denominator_units)
438
473
 
439
474
  @denominator_units.each_with_index do |d, i|
440
- if convertable?(d) && (u = @numerator_units.find(&method(:convertable?)))
441
- @value /= conversion_factor(d, u)
442
- @denominator_units.delete_at(i)
443
- @numerator_units.delete_at(@numerator_units.index(u))
444
- end
475
+ next unless convertable?(d) && (u = @numerator_units.find(&method(:convertable?)))
476
+ @value /= conversion_factor(d, u)
477
+ @denominator_units.delete_at(i)
478
+ @numerator_units.delete_at(@numerator_units.index(u))
445
479
  end
446
480
  end
447
481
 
448
- # A hash of unit names to their index in the conversion table
449
- CONVERTABLE_UNITS = %w(in cm pc mm pt px).inject({}) {|m, v| m[v] = m.size; m}
450
-
451
- # in cm pc mm pt px
452
- CONVERSION_TABLE = [[1, 2.54, 6, 25.4, 72 , 96], # in
453
- [nil, 1, 2.36220473, 10, 28.3464567, 37.795275591], # cm
454
- [nil, nil, 1, 4.23333333, 12 , 16], # pc
455
- [nil, nil, nil, 1, 2.83464567, 3.7795275591], # mm
456
- [nil, nil, nil, nil, 1 , 1.3333333333], # pt
457
- [nil, nil, nil, nil, nil , 1]] # px
482
+ # This is the source data for all the unit logic. It's pre-processed to make
483
+ # it efficient to figure out whether a set of units is mutually compatible
484
+ # and what the conversion ratio is between two units.
485
+ #
486
+ # These come from http://www.w3.org/TR/2012/WD-css3-values-20120308/.
487
+ relative_sizes = [
488
+ {
489
+ 'in' => Rational(1),
490
+ 'cm' => Rational(1, 2.54),
491
+ 'pc' => Rational(1, 6),
492
+ 'mm' => Rational(1, 25.4),
493
+ 'q' => Rational(1, 101.6),
494
+ 'pt' => Rational(1, 72),
495
+ 'px' => Rational(1, 96)
496
+ },
497
+ {
498
+ 'deg' => Rational(1, 360),
499
+ 'grad' => Rational(1, 400),
500
+ 'rad' => Rational(1, 2 * Math::PI),
501
+ 'turn' => Rational(1)
502
+ },
503
+ {
504
+ 's' => Rational(1),
505
+ 'ms' => Rational(1, 1000)
506
+ },
507
+ {
508
+ 'Hz' => Rational(1),
509
+ 'kHz' => Rational(1000)
510
+ },
511
+ {
512
+ 'dpi' => Rational(1),
513
+ 'dpcm' => Rational(254, 100),
514
+ 'dppx' => Rational(96)
515
+ }
516
+ ]
517
+
518
+ # A hash from each known unit to the set of units that it's mutually
519
+ # convertible with.
520
+ MUTUALLY_CONVERTIBLE = {}
521
+ relative_sizes.map do |values|
522
+ set = values.keys.to_set
523
+ values.keys.each {|name| MUTUALLY_CONVERTIBLE[name] = set}
524
+ end
525
+
526
+ # A two-dimensional hash from two units to the conversion ratio between
527
+ # them. Multiply `X` by `CONVERSION_TABLE[X][Y]` to convert it to `Y`.
528
+ CONVERSION_TABLE = {}
529
+ relative_sizes.each do |values|
530
+ values.each do |(name1, value1)|
531
+ CONVERSION_TABLE[name1] ||= {}
532
+ values.each do |(name2, value2)|
533
+ value = value1 / value2
534
+ CONVERSION_TABLE[name1][name2] = value.denominator == 1 ? value.to_i : value.to_f
535
+ end
536
+ end
537
+ end
458
538
 
459
539
  def conversion_factor(from_unit, to_unit)
460
- res = CONVERSION_TABLE[CONVERTABLE_UNITS[from_unit]][CONVERTABLE_UNITS[to_unit]]
461
- return 1.0 / conversion_factor(to_unit, from_unit) if res.nil?
462
- res
540
+ CONVERSION_TABLE[from_unit][to_unit]
463
541
  end
464
542
 
465
543
  def convertable?(units)
466
- Array(units).all? {|u| CONVERTABLE_UNITS.include?(u)}
544
+ units = Array(units).to_set
545
+ return true if units.empty?
546
+ return false unless (mutually_convertible = MUTUALLY_CONVERTIBLE[units.first])
547
+ units.subset?(mutually_convertible)
467
548
  end
468
549
 
469
550
  def sans_common_units(units1, units2)
@@ -1,6 +1,9 @@
1
+ # -*- coding: utf-8 -*-
1
2
  module Sass::Script::Value
2
3
  # A SassScript object representing a CSS string *or* a CSS identifier.
3
4
  class String < Base
5
+ @@interpolation_deprecation = Sass::Deprecation.new
6
+
4
7
  # The Ruby value of the string.
5
8
  #
6
9
  # @return [String]
@@ -13,37 +16,123 @@ module Sass::Script::Value
13
16
  # @return [Symbol] `:string` or `:identifier`
14
17
  attr_reader :type
15
18
 
19
+ def self.value(contents)
20
+ contents.gsub("\\\n", "").gsub(/\\(?:([0-9a-fA-F]{1,6})\s?|(.))/) do
21
+ next $2 if $2
22
+ # Handle unicode escapes as per CSS Syntax Level 3 section 4.3.8.
23
+ code_point = $1.to_i(16)
24
+ if code_point == 0 || code_point > 0x10FFFF ||
25
+ (code_point >= 0xD800 && code_point <= 0xDFFF)
26
+ '�'
27
+ else
28
+ [code_point].pack("U")
29
+ end
30
+ end
31
+ end
32
+
33
+ # Returns the quoted string representation of `contents`.
34
+ #
35
+ # @options opts :quote [String]
36
+ # The preferred quote style for quoted strings. If `:none`, strings are
37
+ # always emitted unquoted. If `nil`, quoting is determined automatically.
38
+ # @options opts :sass [String]
39
+ # Whether to quote strings for Sass source, as opposed to CSS. Defaults to `false`.
40
+ def self.quote(contents, opts = {})
41
+ quote = opts[:quote]
42
+
43
+ # Short-circuit if there are no characters that need quoting.
44
+ unless contents =~ /[\n\\"']|\#\{/
45
+ quote ||= '"'
46
+ return "#{quote}#{contents}#{quote}"
47
+ end
48
+
49
+ if quote.nil?
50
+ if contents.include?('"')
51
+ if contents.include?("'")
52
+ quote = '"'
53
+ else
54
+ quote = "'"
55
+ end
56
+ else
57
+ quote = '"'
58
+ end
59
+ end
60
+
61
+ # Replace single backslashes with multiples.
62
+ contents = contents.gsub("\\", "\\\\\\\\")
63
+
64
+ # Escape interpolation.
65
+ contents = contents.gsub('#{', "\\\#{") if opts[:sass]
66
+
67
+ if quote == '"'
68
+ contents = contents.gsub('"', "\\\"")
69
+ else
70
+ contents = contents.gsub("'", "\\'")
71
+ end
72
+
73
+ contents = contents.gsub(/\n(?![a-fA-F0-9\s])/, "\\a").gsub("\n", "\\a ")
74
+ "#{quote}#{contents}#{quote}"
75
+ end
76
+
16
77
  # Creates a new string.
17
78
  #
18
79
  # @param value [String] See \{#value}
19
80
  # @param type [Symbol] See \{#type}
20
- def initialize(value, type = :identifier)
81
+ # @param deprecated_interp_equivalent [String?]
82
+ # If this was created via a potentially-deprecated string interpolation,
83
+ # this is the replacement expression that should be suggested to the user.
84
+ def initialize(value, type = :identifier, deprecated_interp_equivalent = nil)
21
85
  super(value)
22
86
  @type = type
87
+ @deprecated_interp_equivalent = deprecated_interp_equivalent
23
88
  end
24
89
 
25
90
  # @see Value#plus
26
91
  def plus(other)
27
- other_str = other.is_a?(Sass::Script::Value::String) ? other.value : other.to_s
28
- Sass::Script::Value::String.new(value + other_str, type)
92
+ other_value = if other.is_a?(Sass::Script::Value::String)
93
+ other.value
94
+ else
95
+ other.to_s(:quote => :none)
96
+ end
97
+ Sass::Script::Value::String.new(value + other_value, type)
29
98
  end
30
99
 
31
100
  # @see Value#to_s
32
101
  def to_s(opts = {})
33
- if @type == :identifier
34
- return @value.gsub(/\n\s*/, " ")
35
- end
36
-
37
- return "\"#{value.gsub('"', "\\\"")}\"" if opts[:quote] == %q{"}
38
- return "'#{value.gsub("'", "\\'")}'" if opts[:quote] == %q{'}
39
- return "\"#{value}\"" unless value.include?('"')
40
- return "'#{value}'" unless value.include?("'")
41
- "\"#{value.gsub('"', "\\\"")}\"" # '
102
+ return @value.gsub(/\n\s*/, ' ') if opts[:quote] == :none || @type == :identifier
103
+ String.quote(value, opts)
42
104
  end
43
105
 
44
106
  # @see Value#to_sass
45
107
  def to_sass(opts = {})
46
- to_s
108
+ to_s(opts.merge(:sass => true))
109
+ end
110
+
111
+ def separator
112
+ check_deprecated_interp
113
+ super
114
+ end
115
+
116
+ def to_a
117
+ check_deprecated_interp
118
+ super
119
+ end
120
+
121
+ # Prints a warning if this string was created using potentially-deprecated
122
+ # interpolation.
123
+ def check_deprecated_interp
124
+ return unless @deprecated_interp_equivalent
125
+
126
+ @@interpolation_deprecation.warn(source_range.file, source_range.start_pos.line, <<WARNING)
127
+ \#{} interpolation near operators will be simplified in a future version of Sass.
128
+ To preserve the current behavior, use quotes:
129
+
130
+ #{@deprecated_interp_equivalent}
131
+ WARNING
132
+ end
133
+
134
+ def inspect
135
+ String.quote(value)
47
136
  end
48
137
  end
49
138
  end
@@ -5,7 +5,6 @@ require 'sass/script/value/string'
5
5
  require 'sass/script/value/number'
6
6
  require 'sass/script/value/color'
7
7
  require 'sass/script/value/bool'
8
- require 'sass/script/value/deprecated_false'
9
8
  require 'sass/script/value/null'
10
9
  require 'sass/script/value/list'
11
10
  require 'sass/script/value/arg_list'
data/lib/sass/script.rb CHANGED
@@ -16,12 +16,12 @@ module Sass
16
16
  # Parses a string of SassScript
17
17
  #
18
18
  # @param value [String] The SassScript
19
- # @param line [Fixnum] The number of the line on which the SassScript appeared.
19
+ # @param line [Integer] The number of the line on which the SassScript appeared.
20
20
  # Used for error reporting
21
- # @param offset [Fixnum] The number of characters in on `line` that the SassScript started.
21
+ # @param offset [Integer] The number of characters in on `line` that the SassScript started.
22
22
  # Used for error reporting
23
23
  # @param options [{Symbol => Object}] An options hash;
24
- # see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
24
+ # see {file:SASS_REFERENCE.md#Options the Sass options documentation}
25
25
  # @return [Script::Tree::Node] The root node of the parse tree
26
26
  def self.parse(value, line, offset, options = {})
27
27
  Parser.parse(value, line, offset, options)
@@ -11,9 +11,16 @@ module Sass
11
11
 
12
12
  def placeholder_selector; nil; end
13
13
  def parent_selector; nil; end
14
- def interpolation; nil; end
14
+ def interpolation(warn_for_color = false); nil; end
15
15
  def use_css_import?; true; end
16
16
 
17
+ def block_contents(node, context)
18
+ if node.is_a?(Sass::Tree::DirectiveNode) && node.normalized_name == '@keyframes'
19
+ context = :keyframes
20
+ end
21
+ super(node, context)
22
+ end
23
+
17
24
  def block_child(context)
18
25
  case context
19
26
  when :ruleset
@@ -22,15 +29,28 @@ module Sass
22
29
  directive || ruleset
23
30
  when :directive
24
31
  directive || declaration_or_ruleset
32
+ when :keyframes
33
+ keyframes_ruleset
25
34
  end
26
35
  end
27
36
 
28
- def nested_properties!(node, space)
37
+ def nested_properties!(node)
29
38
  expected('expression (e.g. 1px, bold)')
30
39
  end
31
40
 
32
- @sass_script_parser = Class.new(Sass::Script::CssParser)
33
- @sass_script_parser.send(:include, ScriptParser)
41
+ def ruleset
42
+ start_pos = source_position
43
+ return unless (selector = selector_comma_sequence)
44
+ block(node(Sass::Tree::RuleNode.new(selector, range(start_pos)), start_pos), :ruleset)
45
+ end
46
+
47
+ def keyframes_ruleset
48
+ start_pos = source_position
49
+ return unless (selector = keyframes_selector)
50
+ block(node(Sass::Tree::KeyframeRuleNode.new(selector.strip), start_pos), :ruleset)
51
+ end
52
+
53
+ @sass_script_parser = Sass::Script::CssParser
34
54
  end
35
55
  end
36
56
  end