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

Sign up to get free protection for your applications and to get access to all the features.
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