sass 3.3.0.rc.2 → 3.3.0.rc.3

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 (76) hide show
  1. checksums.yaml +15 -0
  2. data/CONTRIBUTING +1 -1
  3. data/README.md +7 -7
  4. data/Rakefile +4 -2
  5. data/VERSION +1 -1
  6. data/VERSION_DATE +1 -1
  7. data/bin/sass +5 -1
  8. data/bin/sass-convert +5 -1
  9. data/bin/scss +5 -1
  10. data/ext/mkrf_conf.rb +23 -0
  11. data/lib/sass/css.rb +1 -1
  12. data/lib/sass/engine.rb +19 -9
  13. data/lib/sass/environment.rb +8 -0
  14. data/lib/sass/exec.rb +4 -4
  15. data/lib/sass/features.rb +0 -1
  16. data/lib/sass/importers/base.rb +13 -6
  17. data/lib/sass/importers/deprecated_path.rb +8 -2
  18. data/lib/sass/importers/filesystem.rb +33 -7
  19. data/lib/sass/logger.rb +1 -4
  20. data/lib/sass/logger/base.rb +0 -2
  21. data/lib/sass/logger/log_level.rb +0 -2
  22. data/lib/sass/plugin.rb +2 -2
  23. data/lib/sass/plugin/compiler.rb +23 -11
  24. data/lib/sass/plugin/configuration.rb +0 -1
  25. data/lib/sass/railtie.rb +1 -0
  26. data/lib/sass/script/css_lexer.rb +0 -1
  27. data/lib/sass/script/css_parser.rb +0 -1
  28. data/lib/sass/script/functions.rb +158 -96
  29. data/lib/sass/script/lexer.rb +29 -35
  30. data/lib/sass/script/parser.rb +10 -3
  31. data/lib/sass/script/tree.rb +0 -1
  32. data/lib/sass/script/tree/funcall.rb +21 -5
  33. data/lib/sass/script/tree/list_literal.rb +0 -1
  34. data/lib/sass/script/value/arg_list.rb +7 -3
  35. data/lib/sass/script/value/bool.rb +0 -1
  36. data/lib/sass/script/value/null.rb +0 -1
  37. data/lib/sass/script/value/number.rb +2 -6
  38. data/lib/sass/scss/css_parser.rb +0 -1
  39. data/lib/sass/scss/parser.rb +5 -5
  40. data/lib/sass/scss/script_lexer.rb +0 -1
  41. data/lib/sass/scss/script_parser.rb +0 -1
  42. data/lib/sass/selector.rb +11 -1
  43. data/lib/sass/selector/comma_sequence.rb +3 -4
  44. data/lib/sass/selector/sequence.rb +11 -7
  45. data/lib/sass/selector/simple_sequence.rb +42 -11
  46. data/lib/sass/source/map.rb +6 -19
  47. data/lib/sass/tree/at_root_node.rb +1 -1
  48. data/lib/sass/tree/mixin_node.rb +2 -2
  49. data/lib/sass/tree/prop_node.rb +0 -1
  50. data/lib/sass/tree/variable_node.rb +0 -5
  51. data/lib/sass/tree/visitors/check_nesting.rb +0 -1
  52. data/lib/sass/tree/visitors/convert.rb +2 -2
  53. data/lib/sass/tree/visitors/cssize.rb +184 -84
  54. data/lib/sass/tree/visitors/deep_copy.rb +0 -1
  55. data/lib/sass/tree/visitors/perform.rb +14 -44
  56. data/lib/sass/util.rb +59 -12
  57. data/lib/sass/util/cross_platform_random.rb +19 -0
  58. data/lib/sass/util/normalized_map.rb +17 -1
  59. data/test/sass/compiler_test.rb +10 -0
  60. data/test/sass/conversion_test.rb +36 -0
  61. data/test/sass/css2sass_test.rb +19 -0
  62. data/test/sass/engine_test.rb +54 -105
  63. data/test/sass/functions_test.rb +233 -26
  64. data/test/sass/importer_test.rb +72 -10
  65. data/test/sass/plugin_test.rb +14 -0
  66. data/test/sass/script_conversion_test.rb +4 -4
  67. data/test/sass/script_test.rb +58 -21
  68. data/test/sass/scss/css_test.rb +8 -1
  69. data/test/sass/scss/scss_test.rb +376 -179
  70. data/test/sass/source_map_test.rb +8 -0
  71. data/test/sass/templates/subdir/import_up1.scss +1 -0
  72. data/test/sass/templates/subdir/import_up2.scss +1 -0
  73. data/test/sass/util_test.rb +16 -0
  74. data/test/test_helper.rb +12 -4
  75. metadata +269 -287
  76. data/lib/sass/script/tree/selector.rb +0 -30
@@ -1,12 +1,9 @@
1
- module Sass::Logger
2
-
3
- end
1
+ module Sass::Logger; end
4
2
 
5
3
  require "sass/logger/log_level"
6
4
  require "sass/logger/base"
7
5
 
8
6
  module Sass
9
-
10
7
  class << self
11
8
  attr_accessor :logger
12
9
  end
@@ -1,7 +1,6 @@
1
1
  require 'sass/logger/log_level'
2
2
 
3
3
  class Sass::Logger::Base
4
-
5
4
  include Sass::Logger::LogLevel
6
5
 
7
6
  attr_accessor :log_level
@@ -28,5 +27,4 @@ class Sass::Logger::Base
28
27
  def _log(level, message)
29
28
  Kernel.warn(message)
30
29
  end
31
-
32
30
  end
@@ -1,7 +1,6 @@
1
1
  module Sass
2
2
  module Logger
3
3
  module LogLevel
4
-
5
4
  def self.included(base)
6
5
  base.extend(ClassMethods)
7
6
  end
@@ -41,7 +40,6 @@ module Sass
41
40
  RUBY
42
41
  end
43
42
  end
44
-
45
43
  end
46
44
  end
47
45
  end
@@ -120,11 +120,11 @@ module Sass
120
120
  def options
121
121
  compiler.options
122
122
  end
123
-
124
123
  end
125
124
  end
126
125
 
127
- if defined?(ActionController)
126
+ # On Rails 3+ the rails plugin is loaded at the right time in railtie.rb
127
+ if defined?(ActionController) && !Sass::Util.ap_geq_3?
128
128
  require 'sass/plugin/rails'
129
129
  elsif defined?(Merb::Plugins)
130
130
  require 'sass/plugin/merb'
@@ -8,7 +8,6 @@ require 'sass/plugin/configuration'
8
8
  require 'sass/plugin/staleness_checker'
9
9
 
10
10
  module Sass::Plugin
11
-
12
11
  # The Compiler class handles compilation of multiple files and/or directories,
13
12
  # including checking which CSS files are out-of-date and need to be updated
14
13
  # and calling Sass to perform the compilation on those files.
@@ -281,13 +280,7 @@ module Sass::Plugin
281
280
  # https://github.com/nex3/sass/commit/a3031856b22bc834a5417dedecb038b7be9b9e3e
282
281
  listener.force_polling(true) if @options[:poll] || Sass::Util.windows?
283
282
 
284
- # rubocop:disable RescueException
285
- begin
286
- listener.start!
287
- rescue Exception => e
288
- raise e unless e.is_a?(Interrupt)
289
- end
290
- # rubocop:enable RescueException
283
+ listen_to(listener)
291
284
  end
292
285
 
293
286
  # Non-destructively modifies \{#options} so that default values are properly set,
@@ -309,8 +302,25 @@ module Sass::Plugin
309
302
  private
310
303
 
311
304
  def create_listener(*args, &block)
312
- require 'listen'
313
- Listen::Listener.new(*args, &block)
305
+ if Sass::Util.listen_geq_2?
306
+ Listen.to(*args, &block)
307
+ else
308
+ Listen::Listener.new(*args, &block)
309
+ end
310
+ end
311
+
312
+ def listen_to(listener)
313
+ if Sass::Util.listen_geq_2?
314
+ listener.start
315
+ listener.thread.join
316
+ listener.stop # Partially work around guard/listen#146
317
+ else
318
+ begin
319
+ listener.start!
320
+ rescue Interrupt
321
+ # Squelch Interrupt for clean exit from Listen::Listener
322
+ end
323
+ end
314
324
  end
315
325
 
316
326
  def remove_redundant_directories(directories)
@@ -338,7 +348,9 @@ module Sass::Plugin
338
348
 
339
349
  begin
340
350
  File.read(filename) unless File.readable?(filename) # triggers an error for handling
341
- engine_opts = engine_options(:css_filename => css, :filename => filename)
351
+ engine_opts = engine_options(:css_filename => css,
352
+ :filename => filename,
353
+ :sourcemap_filename => sourcemap)
342
354
  mapping = nil
343
355
  engine = Sass::Engine.for_file(filename, engine_opts)
344
356
  if sourcemap
@@ -4,7 +4,6 @@ module Sass
4
4
  # so that we can load it independently in Rails 3,
5
5
  # where the full plugin stuff is lazy-loaded.
6
6
  module Configuration
7
-
8
7
  # Returns the default options for a {Sass::Plugin::Compiler}.
9
8
  #
10
9
  # @return [{Symbol => Object}]
@@ -5,5 +5,6 @@ if defined?(ActiveSupport) && Sass::Util.has?(:public_method, ActiveSupport, :on
5
5
  ActiveSupport.on_load(:before_configuration) do
6
6
  require 'sass'
7
7
  require 'sass/plugin'
8
+ require 'sass/plugin/rails'
8
9
  end
9
10
  end
@@ -4,7 +4,6 @@ module Sass
4
4
  #
5
5
  # @see Sass::SCSS::CssParser
6
6
  class CssLexer < Lexer
7
-
8
7
  private
9
8
 
10
9
  def token
@@ -7,7 +7,6 @@ module Sass
7
7
  #
8
8
  # @see Sass::SCSS::CssParser
9
9
  class CssParser < Parser
10
-
11
10
  private
12
11
 
13
12
  # @private
@@ -31,7 +31,7 @@ module Sass::Script
31
31
  # \{#blue blue($color)}
32
32
  # : Gets the blue component of a color.
33
33
  #
34
- # \{#mix mix($color-1, $color-2, \[$weight\])}
34
+ # \{#mix mix($color1, $color2, \[$weight\])}
35
35
  # : Mixes two colors together.
36
36
  #
37
37
  # ## HSL Functions
@@ -136,19 +136,19 @@ module Sass::Script
136
136
  #
137
137
  # ## Number Functions
138
138
  #
139
- # \{#percentage percentage($value)}
139
+ # \{#percentage percentage($number)}
140
140
  # : Converts a unitless number to a percentage.
141
141
  #
142
- # \{#round round($value)}
142
+ # \{#round round($number)}
143
143
  # : Rounds a number to the nearest whole number.
144
144
  #
145
- # \{#ceil ceil($value)}
145
+ # \{#ceil ceil($number)}
146
146
  # : Rounds a number up to the next whole number.
147
147
  #
148
- # \{#floor floor($value)}
148
+ # \{#floor floor($number)}
149
149
  # : Rounds a number down to the previous whole number.
150
150
  #
151
- # \{#abs abs($value)}
151
+ # \{#abs abs($number)}
152
152
  # : Returns the absolute value of a number.
153
153
  #
154
154
  # \{#min min($numbers...)\}
@@ -157,6 +157,9 @@ module Sass::Script
157
157
  # \{#max max($numbers...)\}
158
158
  # : Finds the maximum of several numbers.
159
159
  #
160
+ # \{#random random([$limit])\}
161
+ # : Returns a random number.
162
+ #
160
163
  # ## List Functions {#list-functions}
161
164
  #
162
165
  # All list functions work for maps as well, treating them as lists of pairs.
@@ -190,6 +193,9 @@ module Sass::Script
190
193
  # \{#map_merge map-merge($map1, $map2)}
191
194
  # : Merges two maps together into a new map.
192
195
  #
196
+ # \{#map_remove map-remove($map, $key)}
197
+ # : Returns a new map with a key removed.
198
+ #
193
199
  # \{#map_keys map-keys($map)}
194
200
  # : Returns a list of all keys in a map.
195
201
  #
@@ -231,7 +237,7 @@ module Sass::Script
231
237
  # \{#unitless unitless($number)}
232
238
  # : Returns whether a number has units.
233
239
  #
234
- # \{#comparable comparable($number-1, $number-2)}
240
+ # \{#comparable comparable($number1, $number2)}
235
241
  # : Returns whether two numbers can be added, subtracted, or compared.
236
242
  #
237
243
  # \{#call call($name, $args...)}
@@ -306,7 +312,7 @@ module Sass::Script
306
312
  # delayed.
307
313
  # @attr var_args [Boolean] Whether the function takes a variable number of arguments.
308
314
  # @attr var_kwargs [Boolean] Whether the function takes an arbitrary set of keyword arguments.
309
- Signature = Struct.new(:args, :delayed_args, :var_args, :var_kwargs)
315
+ Signature = Struct.new(:args, :delayed_args, :var_args, :var_kwargs, :deprecated)
310
316
 
311
317
  # Declare a Sass signature for a Ruby-defined function.
312
318
  # This includes the names of the arguments,
@@ -361,7 +367,8 @@ module Sass::Script
361
367
  args,
362
368
  delayed_args,
363
369
  options[:var_args],
364
- options[:var_kwargs])
370
+ options[:var_kwargs],
371
+ options[:deprecated] && options[:deprecated].map {|a| a.to_s})
365
372
  end
366
373
 
367
374
  # Determine the correct signature for the number of arguments
@@ -401,6 +408,24 @@ module Sass::Script
401
408
  @signatures[method_name].first
402
409
  end
403
410
 
411
+ # Sets the random seed used by Sass's internal random number generator.
412
+ #
413
+ # This can be used to ensure consistent random number sequences which
414
+ # allows for consistent results when testing, etc.
415
+ #
416
+ # @param seed [Integer]
417
+ # @return [Integer] The same seed.
418
+ def self.random_seed=(seed)
419
+ @random_number_generator = Sass::Util::CrossPlatformRandom.new(seed)
420
+ end
421
+
422
+ # Get Sass's internal random number generator.
423
+ #
424
+ # @return [Random]
425
+ def self.random_number_generator
426
+ @random_number_generator ||= Sass::Util::CrossPlatformRandom.new
427
+ end
428
+
404
429
  # The context in which methods in {Script::Functions} are evaluated.
405
430
  # That means that all instance methods of {EvaluationContext}
406
431
  # are available to use in functions.
@@ -740,7 +765,6 @@ module Sass::Script
740
765
  # @raise [ArgumentError] if `$color` isn't a color
741
766
  def hue(color)
742
767
  assert_type color, :Color, :color
743
- assert_type color, :Color
744
768
  number(color.hue, "deg")
745
769
  end
746
770
  declare :hue, [:color]
@@ -1187,18 +1211,18 @@ module Sass::Script
1187
1211
  # mix(#f00, #00f) => #7f007f
1188
1212
  # mix(#f00, #00f, 25%) => #3f00bf
1189
1213
  # mix(rgba(255, 0, 0, 0.5), #00f) => rgba(63, 0, 191, 0.75)
1190
- # @overload mix($color-1, $color-2, $weight: 50%)
1191
- # @param $color-1 [Sass::Script::Value::Color]
1192
- # @param $color-2 [Sass::Script::Value::Color]
1214
+ # @overload mix($color1, $color2, $weight: 50%)
1215
+ # @param $color1 [Sass::Script::Value::Color]
1216
+ # @param $color2 [Sass::Script::Value::Color]
1193
1217
  # @param $weight [Sass::Script::Value::Number] The relative weight of each
1194
1218
  # color. Closer to `0%` gives more weight to `$color`, closer to `100%`
1195
1219
  # gives more weight to `$color2`
1196
1220
  # @return [Sass::Script::Value::Color]
1197
1221
  # @raise [ArgumentError] if `$weight` is out of bounds or any parameter is
1198
1222
  # the wrong type
1199
- def mix(color_1, color_2, weight = number(50))
1200
- assert_type color_1, :Color, :color_1
1201
- assert_type color_2, :Color, :color_2
1223
+ def mix(color1, color2, weight = number(50))
1224
+ assert_type color1, :Color, :color1
1225
+ assert_type color2, :Color, :color2
1202
1226
  assert_type weight, :Number, :weight
1203
1227
 
1204
1228
  Sass::Util.check_range("Weight", 0..100, weight, '%')
@@ -1208,11 +1232,11 @@ module Sass::Script
1208
1232
  # to perform the weighted average of the two RGB values.
1209
1233
  #
1210
1234
  # It works by first normalizing both parameters to be within [-1, 1],
1211
- # where 1 indicates "only use color_1", -1 indicates "only use color_2", and
1235
+ # where 1 indicates "only use color1", -1 indicates "only use color2", and
1212
1236
  # all values in between indicated a proportionately weighted average.
1213
1237
  #
1214
1238
  # Once we have the normalized variables w and a, we apply the formula
1215
- # (w + a)/(1 + w*a) to get the combined weight (in [-1, 1]) of color_1.
1239
+ # (w + a)/(1 + w*a) to get the combined weight (in [-1, 1]) of color1.
1216
1240
  # This formula has two especially nice properties:
1217
1241
  #
1218
1242
  # * When either w or a are -1 or 1, the combined weight is also that number
@@ -1220,21 +1244,21 @@ module Sass::Script
1220
1244
  #
1221
1245
  # * When a is 0, the combined weight is w, and vice versa.
1222
1246
  #
1223
- # Finally, the weight of color_1 is renormalized to be within [0, 1]
1224
- # and the weight of color_2 is given by 1 minus the weight of color_1.
1247
+ # Finally, the weight of color1 is renormalized to be within [0, 1]
1248
+ # and the weight of color2 is given by 1 minus the weight of color1.
1225
1249
  p = (weight.value / 100.0).to_f
1226
1250
  w = p * 2 - 1
1227
- a = color_1.alpha - color_2.alpha
1251
+ a = color1.alpha - color2.alpha
1228
1252
 
1229
1253
  w1 = ((w * a == -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0
1230
1254
  w2 = 1 - w1
1231
1255
 
1232
- rgba = color_1.rgb.zip(color_2.rgb).map {|v1, v2| v1 * w1 + v2 * w2}
1233
- rgba << color_1.alpha * p + color_2.alpha * (1 - p)
1256
+ rgba = color1.rgb.zip(color2.rgb).map {|v1, v2| v1 * w1 + v2 * w2}
1257
+ rgba << color1.alpha * p + color2.alpha * (1 - p)
1234
1258
  rgb_color(*rgba)
1235
1259
  end
1236
- declare :mix, [:color_1, :color_2]
1237
- declare :mix, [:color_1, :color_2, :weight]
1260
+ declare :mix, [:color1, :color2], :deprecated => [:color_1, :color_2]
1261
+ declare :mix, [:color1, :color2, :weight], :deprecated => [:color_1, :color_2, :weight]
1238
1262
 
1239
1263
  # Converts a color to grayscale. This is identical to `desaturate(color,
1240
1264
  # 100%)`.
@@ -1376,7 +1400,7 @@ module Sass::Script
1376
1400
  declare :str_insert, [:string, :insert, :index]
1377
1401
 
1378
1402
  # Returns the index of the first occurance of `$substring` in `$string`. If
1379
- # there is no such occurance, returns 0.
1403
+ # there is no such occurance, returns `null`.
1380
1404
  #
1381
1405
  # Note that unlike some languages, the first character in a Sass string is
1382
1406
  # number 1, the second number 2, and so forth.
@@ -1384,19 +1408,19 @@ module Sass::Script
1384
1408
  # @example
1385
1409
  # str-index(abcd, a) => 1
1386
1410
  # str-index(abcd, ab) => 1
1387
- # str-index(abcd, X) => 0
1411
+ # str-index(abcd, X) => null
1388
1412
  # str-index(abcd, c) => 3
1389
1413
  #
1390
1414
  # @overload str_index($string, $substring)
1391
1415
  # @param $string [Sass::Script::Value::String]
1392
1416
  # @param $substring [Sass::Script::Value::String]
1393
- # @return [Sass::Script::Value::Number]
1417
+ # @return [Sass::Script::Value::Number, Sass::Script::Value::Null]
1394
1418
  # @raise [ArgumentError] if any parameter is the wrong type
1395
1419
  def str_index(string, substring)
1396
1420
  assert_type string, :String, :string
1397
1421
  assert_type substring, :String, :substring
1398
- index = string.value.index(substring.value) || -1
1399
- number(index + 1)
1422
+ index = string.value.index(substring.value)
1423
+ index ? number(index + 1) : null
1400
1424
  end
1401
1425
  declare :str_index, [:string, :substring]
1402
1426
 
@@ -1546,90 +1570,90 @@ module Sass::Script
1546
1570
  # comparable(2px, 1px) => true
1547
1571
  # comparable(100px, 3em) => false
1548
1572
  # comparable(10cm, 3mm) => true
1549
- # @overload comparable($number-1, $number-2)
1550
- # @param $number-1 [Sass::Script::Value::Number]
1551
- # @param $number-2 [Sass::Script::Value::Number]
1573
+ # @overload comparable($number1, $number2)
1574
+ # @param $number1 [Sass::Script::Value::Number]
1575
+ # @param $number2 [Sass::Script::Value::Number]
1552
1576
  # @return [Sass::Script::Value::Bool]
1553
1577
  # @raise [ArgumentError] if either parameter is the wrong type
1554
- def comparable(number_1, number_2)
1555
- assert_type number_1, :Number, :number_1
1556
- assert_type number_2, :Number, :number_2
1557
- bool(number_1.comparable_to?(number_2))
1578
+ def comparable(number1, number2)
1579
+ assert_type number1, :Number, :number1
1580
+ assert_type number2, :Number, :number2
1581
+ bool(number1.comparable_to?(number2))
1558
1582
  end
1559
- declare :comparable, [:number_1, :number_2]
1583
+ declare :comparable, [:number1, :number2], :deprecated => [:number_1, :number_2]
1560
1584
 
1561
1585
  # Converts a unitless number to a percentage.
1562
1586
  #
1563
1587
  # @example
1564
1588
  # percentage(0.2) => 20%
1565
1589
  # percentage(100px / 50px) => 200%
1566
- # @overload percentage($value)
1567
- # @param $value [Sass::Script::Value::Number]
1590
+ # @overload percentage($number)
1591
+ # @param $number [Sass::Script::Value::Number]
1568
1592
  # @return [Sass::Script::Value::Number]
1569
- # @raise [ArgumentError] if `$value` isn't a unitless number
1570
- def percentage(value)
1571
- unless value.is_a?(Sass::Script::Value::Number) && value.unitless?
1572
- raise ArgumentError.new("$value: #{value.inspect} is not a unitless number")
1593
+ # @raise [ArgumentError] if `$number` isn't a unitless number
1594
+ def percentage(number)
1595
+ unless number.is_a?(Sass::Script::Value::Number) && number.unitless?
1596
+ raise ArgumentError.new("$number: #{number.inspect} is not a unitless number")
1573
1597
  end
1574
- number(value.value * 100, '%')
1598
+ number(number.value * 100, '%')
1575
1599
  end
1576
- declare :percentage, [:value]
1600
+ declare :percentage, [:number], :deprecated => [:value]
1577
1601
 
1578
1602
  # Rounds a number to the nearest whole number.
1579
1603
  #
1580
1604
  # @example
1581
1605
  # round(10.4px) => 10px
1582
1606
  # round(10.6px) => 11px
1583
- # @overload round($value)
1584
- # @param $value [Sass::Script::Value::Number]
1607
+ # @overload round($number)
1608
+ # @param $number [Sass::Script::Value::Number]
1585
1609
  # @return [Sass::Script::Value::Number]
1586
- # @raise [ArgumentError] if `$value` isn't a number
1587
- def round(value)
1588
- numeric_transformation(value) {|n| n.round}
1610
+ # @raise [ArgumentError] if `$number` isn't a number
1611
+ def round(number)
1612
+ numeric_transformation(number) {|n| n.round}
1589
1613
  end
1590
- declare :round, [:value]
1614
+ declare :round, [:number], :deprecated => [:value]
1591
1615
 
1592
1616
  # Rounds a number up to the next whole number.
1593
1617
  #
1594
1618
  # @example
1595
1619
  # ceil(10.4px) => 11px
1596
1620
  # ceil(10.6px) => 11px
1597
- # @overload ceil($value)
1598
- # @param $value [Sass::Script::Value::Number]
1621
+ # @overload ceil($number)
1622
+ # @param $number [Sass::Script::Value::Number]
1599
1623
  # @return [Sass::Script::Value::Number]
1600
- # @raise [ArgumentError] if `$value` isn't a number
1601
- def ceil(value)
1602
- numeric_transformation(value) {|n| n.ceil}
1624
+ # @raise [ArgumentError] if `$number` isn't a number
1625
+ def ceil(number)
1626
+ numeric_transformation(number) {|n| n.ceil}
1603
1627
  end
1604
- declare :ceil, [:value]
1628
+ declare :ceil, [:number], :deprecated => [:value]
1605
1629
 
1606
1630
  # Rounds a number down to the previous whole number.
1607
1631
  #
1608
1632
  # @example
1609
1633
  # floor(10.4px) => 10px
1610
1634
  # floor(10.6px) => 10px
1611
- # @overload floor($value)
1612
- # @param $value [Sass::Script::Value::Number]
1635
+ # @overload floor($number)
1636
+ # @param $number [Sass::Script::Value::Number]
1613
1637
  # @return [Sass::Script::Value::Number]
1614
- # @raise [ArgumentError] if `$value` isn't a number
1615
- def floor(value)
1616
- numeric_transformation(value) {|n| n.floor}
1638
+ # @raise [ArgumentError] if `$number` isn't a number
1639
+ def floor(number)
1640
+ numeric_transformation(number) {|n| n.floor}
1617
1641
  end
1618
- declare :floor, [:value]
1642
+ declare :floor, [:number], :deprecated => [:value]
1619
1643
 
1620
1644
  # Returns the absolute value of a number.
1621
1645
  #
1622
1646
  # @example
1623
1647
  # abs(10px) => 10px
1624
1648
  # abs(-10px) => 10px
1625
- # @overload abs($value)
1626
- # @param $value [Sass::Script::Value::Number]
1649
+ # @overload abs($number)
1650
+ # @param $number [Sass::Script::Value::Number]
1627
1651
  # @return [Sass::Script::Value::Number]
1628
- # @raise [ArgumentError] if `$value` isn't a number
1629
- def abs(value)
1630
- numeric_transformation(value) {|n| n.abs}
1652
+ # @raise [ArgumentError] if `$number` isn't a number
1653
+ def abs(number)
1654
+ numeric_transformation(number) {|n| n.abs}
1631
1655
  end
1632
- declare :abs, [:value]
1656
+ declare :abs, [:number], :deprecated => [:value]
1633
1657
 
1634
1658
  # Finds the minimum of several numbers. This function takes any number of
1635
1659
  # arguments.
@@ -1839,7 +1863,7 @@ module Sass::Script
1839
1863
  declare :zip, [], :var_args => true
1840
1864
 
1841
1865
  # Returns the position of a value within a list. If the value isn't found,
1842
- # returns false instead.
1866
+ # returns `null` instead.
1843
1867
  #
1844
1868
  # Note that unlike some languages, the first item in a Sass list is number
1845
1869
  # 1, the second number 2, and so forth.
@@ -1848,20 +1872,16 @@ module Sass::Script
1848
1872
  #
1849
1873
  # @example
1850
1874
  # index(1px solid red, solid) => 2
1851
- # index(1px solid red, dashed) => false
1875
+ # index(1px solid red, dashed) => null
1852
1876
  # index((width: 10px, height: 20px), (height, 20px)) => 2
1853
1877
  # @overload index($list, $value)
1854
1878
  # @param $list [Sass::Script::Value::Base]
1855
1879
  # @param $value [Sass::Script::Value::Base]
1856
- # @return [Sass::Script::Value::Number, Sass::Script::Value::Bool] The
1857
- # 1-based index of `$value` in `$list`, or `false`
1880
+ # @return [Sass::Script::Value::Number, Sass::Script::Value::Null] The
1881
+ # 1-based index of `$value` in `$list`, or `null`
1858
1882
  def index(list, value)
1859
1883
  index = list.to_a.index {|e| e.eq(value).to_bool}
1860
- if index
1861
- number(index + 1)
1862
- else
1863
- bool(false)
1864
- end
1884
+ index ? number(index + 1) : null
1865
1885
  end
1866
1886
  declare :index, [:list, :value]
1867
1887
 
@@ -1894,7 +1914,7 @@ module Sass::Script
1894
1914
  # if the map doesn't contain the given key
1895
1915
  # @raise [ArgumentError] if `$map` is not a map
1896
1916
  def map_get(map, key)
1897
- assert_type map, :Map
1917
+ assert_type map, :Map, :map
1898
1918
  to_h(map)[key] || null
1899
1919
  end
1900
1920
  declare :map_get, [:map, :key]
@@ -1917,11 +1937,29 @@ module Sass::Script
1917
1937
  # @return [Sass::Script::Value::Map]
1918
1938
  # @raise [ArgumentError] if either parameter is not a map
1919
1939
  def map_merge(map1, map2)
1920
- assert_type map1, :Map
1921
- assert_type map2, :Map
1940
+ assert_type map1, :Map, :map1
1941
+ assert_type map2, :Map, :map2
1922
1942
  map(to_h(map1).merge(to_h(map2)))
1923
1943
  end
1924
- declare :map_get, [:map1, :map2]
1944
+ declare :map_merge, [:map1, :map2]
1945
+
1946
+ # Returns a new map with a key removed.
1947
+ #
1948
+ # @example
1949
+ # map-remove(("foo": 1, "bar": 2), "bar") => ("foo": 1)
1950
+ # map-remove(("foo": 1, "bar": 2), "baz") => ("foo": 1, "bar": 2)
1951
+ # @overload map_remove($map, $key)
1952
+ # @param $map [Sass::Script::Value::Map]
1953
+ # @param $key [Sass::Script::Value::Base]
1954
+ # @return [Sass::Script::Value::Map]
1955
+ # @raise [ArgumentError] if `$map` is not a map
1956
+ def map_remove(map, key)
1957
+ assert_type map, :Map, :map
1958
+ hash = to_h(map).dup
1959
+ hash.delete key
1960
+ map(hash)
1961
+ end
1962
+ declare :map_remove, [:map, :key]
1925
1963
 
1926
1964
  # Returns a list of all keys in a map.
1927
1965
  #
@@ -1932,7 +1970,7 @@ module Sass::Script
1932
1970
  # @return [List] the list of keys, comma-separated
1933
1971
  # @raise [ArgumentError] if `$map` is not a map
1934
1972
  def map_keys(map)
1935
- assert_type map, :Map
1973
+ assert_type map, :Map, :map
1936
1974
  list(to_h(map).keys, :comma)
1937
1975
  end
1938
1976
  declare :map_keys, [:map]
@@ -1948,7 +1986,7 @@ module Sass::Script
1948
1986
  # @return [List] the list of values, comma-separated
1949
1987
  # @raise [ArgumentError] if `$map` is not a map
1950
1988
  def map_values(map)
1951
- assert_type map, :Map
1989
+ assert_type map, :Map, :map
1952
1990
  list(to_h(map).values, :comma)
1953
1991
  end
1954
1992
  declare :map_values, [:map]
@@ -1964,7 +2002,7 @@ module Sass::Script
1964
2002
  # @return [Sass::Script::Value::Bool]
1965
2003
  # @raise [ArgumentError] if `$map` is not a map
1966
2004
  def map_has_key(map, key)
1967
- assert_type map, :Map
2005
+ assert_type map, :Map, :map
1968
2006
  bool(to_h(map).has_key?(key))
1969
2007
  end
1970
2008
  declare :map_has_key, [:map, :key]
@@ -1984,8 +2022,8 @@ module Sass::Script
1984
2022
  # @return [Sass::Script::Value::Map]
1985
2023
  # @raise [ArgumentError] if `$args` isn't a variable argument list
1986
2024
  def keywords(args)
1987
- assert_type args, :ArgList
1988
- map(Sass::Util.map_keys(args.keywords) {|k| Sass::Script::String.new(k)})
2025
+ assert_type args, :ArgList, :args
2026
+ map(Sass::Util.map_keys(args.keywords.as_stored) {|k| Sass::Script::String.new(k)})
1989
2027
  end
1990
2028
  declare :keywords, [:args]
1991
2029
 
@@ -2018,9 +2056,10 @@ module Sass::Script
2018
2056
  # @overload unique_id()
2019
2057
  # @return [Sass::Script::Value::String]
2020
2058
  def unique_id
2021
- Thread.current[:sass_last_unique_id] ||= rand(36**8)
2059
+ generator = Sass::Script::Functions.random_number_generator
2060
+ Thread.current[:sass_last_unique_id] ||= generator.rand(36**8)
2022
2061
  # avoid the temptation of trying to guess the next unique value.
2023
- value = (Thread.current[:sass_last_unique_id] += (rand(10) + 1))
2062
+ value = (Thread.current[:sass_last_unique_id] += (generator.rand(10) + 1))
2024
2063
  # the u makes this a legal identifier if it would otherwise start with a number.
2025
2064
  identifier("u" + value.to_s(36).rjust(8, '0'))
2026
2065
  end
@@ -2050,7 +2089,7 @@ module Sass::Script
2050
2089
  nil,
2051
2090
  nil)
2052
2091
  funcall.options = options
2053
- funcall.perform(environment)
2092
+ perform(funcall)
2054
2093
  end
2055
2094
  declare :call, [:name], :var_args => true, :var_kwargs => true
2056
2095
 
@@ -2097,7 +2136,7 @@ module Sass::Script
2097
2136
  # @return [Sass::Script::Bool] Whether the variable is defined in
2098
2137
  # the current scope.
2099
2138
  def variable_exists(name)
2100
- assert_type name, :String
2139
+ assert_type name, :String, :name
2101
2140
  bool(environment.caller.var(name.value))
2102
2141
  end
2103
2142
  declare :variable_exists, [:name]
@@ -2118,7 +2157,7 @@ module Sass::Script
2118
2157
  # @return [Sass::Script::Bool] Whether the variable is defined in
2119
2158
  # the global scope.
2120
2159
  def global_variable_exists(name)
2121
- assert_type name, :String
2160
+ assert_type name, :String, :name
2122
2161
  bool(environment.global_env.var(name.value))
2123
2162
  end
2124
2163
  declare :global_variable_exists, [:name]
@@ -2134,7 +2173,7 @@ module Sass::Script
2134
2173
  # check.
2135
2174
  # @return [Sass::Script::Bool] Whether the function is defined.
2136
2175
  def function_exists(name)
2137
- assert_type name, :String
2176
+ assert_type name, :String, :name
2138
2177
  exists = Sass::Script::Functions.callable?(name.value.tr("-", "_"))
2139
2178
  exists ||= environment.function(name.value)
2140
2179
  bool(exists)
@@ -2152,12 +2191,11 @@ module Sass::Script
2152
2191
  # check.
2153
2192
  # @return [Sass::Script::Bool] Whether the mixin is defined.
2154
2193
  def mixin_exists(name)
2155
- assert_type name, :String
2194
+ assert_type name, :String, :name
2156
2195
  bool(environment.mixin(name.value))
2157
2196
  end
2158
2197
  declare :mixin_exists, [:name]
2159
2198
 
2160
-
2161
2199
  # Return a string containing the value as its Sass representation.
2162
2200
  #
2163
2201
  # @param value [Sass::Script::Value::Base] The value to inspect.
@@ -2168,6 +2206,30 @@ module Sass::Script
2168
2206
  end
2169
2207
  declare :inspect, [:value]
2170
2208
 
2209
+ # @overload random()
2210
+ # Return a decimal between 0 and 1, inclusive of 0 but not 1.
2211
+ # @return [Sass::Script::Number] A decimal value.
2212
+ # @overload random($limit)
2213
+ # Return an integer between 1 and `$limit`, inclusive of 1 but not `$limit`.
2214
+ # @param $limit [Sass::Script::Value::Number] The maximum of the random integer to be
2215
+ # returned, a positive integer.
2216
+ # @return [Sass::Script::Number] An integer.
2217
+ # @raise [ArgumentError] if the `$limit` is not 1 or greater
2218
+ def random(limit = nil)
2219
+ generator = Sass::Script::Functions.random_number_generator
2220
+ if limit
2221
+ assert_integer limit, "limit"
2222
+ if limit.value < 1
2223
+ raise ArgumentError.new("$limit #{limit} must be greater than or equal to 1")
2224
+ end
2225
+ number(1 + generator.rand(limit.value))
2226
+ else
2227
+ number(generator.rand)
2228
+ end
2229
+ end
2230
+ declare :random, []
2231
+ declare :random, [:limit]
2232
+
2171
2233
  private
2172
2234
 
2173
2235
  # This method implements the pattern of transforming a numeric value into