oreorenasass 3.4.4 → 3.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +50 -70
  4. data/Rakefile +5 -26
  5. data/VERSION +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/bin/sass +1 -1
  8. data/bin/scss +1 -1
  9. data/lib/sass.rb +12 -19
  10. data/lib/sass/cache_stores/base.rb +2 -2
  11. data/lib/sass/cache_stores/chain.rb +1 -2
  12. data/lib/sass/cache_stores/filesystem.rb +5 -1
  13. data/lib/sass/cache_stores/memory.rb +1 -1
  14. data/lib/sass/cache_stores/null.rb +2 -2
  15. data/lib/sass/callbacks.rb +0 -1
  16. data/lib/sass/css.rb +13 -11
  17. data/lib/sass/engine.rb +173 -424
  18. data/lib/sass/environment.rb +58 -148
  19. data/lib/sass/error.rb +14 -11
  20. data/lib/sass/exec.rb +703 -5
  21. data/lib/sass/importers/base.rb +6 -49
  22. data/lib/sass/importers/filesystem.rb +19 -44
  23. data/lib/sass/logger.rb +4 -1
  24. data/lib/sass/logger/base.rb +4 -2
  25. data/lib/sass/logger/log_level.rb +7 -3
  26. data/lib/sass/media.rb +23 -20
  27. data/lib/sass/plugin.rb +7 -7
  28. data/lib/sass/plugin/compiler.rb +145 -304
  29. data/lib/sass/plugin/configuration.rb +23 -18
  30. data/lib/sass/plugin/merb.rb +1 -1
  31. data/lib/sass/plugin/staleness_checker.rb +3 -3
  32. data/lib/sass/repl.rb +3 -3
  33. data/lib/sass/script.rb +8 -35
  34. data/lib/sass/script/{value/arg_list.rb → arg_list.rb} +25 -9
  35. data/lib/sass/script/bool.rb +18 -0
  36. data/lib/sass/script/color.rb +606 -0
  37. data/lib/sass/script/css_lexer.rb +4 -8
  38. data/lib/sass/script/css_parser.rb +2 -5
  39. data/lib/sass/script/funcall.rb +245 -0
  40. data/lib/sass/script/functions.rb +408 -1491
  41. data/lib/sass/script/interpolation.rb +79 -0
  42. data/lib/sass/script/lexer.rb +68 -172
  43. data/lib/sass/script/list.rb +85 -0
  44. data/lib/sass/script/literal.rb +221 -0
  45. data/lib/sass/script/{tree/node.rb → node.rb} +12 -22
  46. data/lib/sass/script/{value/null.rb → null.rb} +7 -14
  47. data/lib/sass/script/{value/number.rb → number.rb} +75 -152
  48. data/lib/sass/script/{tree/operation.rb → operation.rb} +24 -17
  49. data/lib/sass/script/parser.rb +110 -245
  50. data/lib/sass/script/string.rb +51 -0
  51. data/lib/sass/script/{tree/string_interpolation.rb → string_interpolation.rb} +4 -5
  52. data/lib/sass/script/{tree/unary_operation.rb → unary_operation.rb} +6 -6
  53. data/lib/sass/script/variable.rb +58 -0
  54. data/lib/sass/scss/css_parser.rb +3 -9
  55. data/lib/sass/scss/parser.rb +421 -450
  56. data/lib/sass/scss/rx.rb +11 -19
  57. data/lib/sass/scss/static_parser.rb +7 -321
  58. data/lib/sass/selector.rb +194 -68
  59. data/lib/sass/selector/abstract_sequence.rb +14 -29
  60. data/lib/sass/selector/comma_sequence.rb +25 -108
  61. data/lib/sass/selector/sequence.rb +66 -159
  62. data/lib/sass/selector/simple.rb +25 -23
  63. data/lib/sass/selector/simple_sequence.rb +63 -173
  64. data/lib/sass/shared.rb +1 -1
  65. data/lib/sass/supports.rb +15 -13
  66. data/lib/sass/tree/charset_node.rb +1 -1
  67. data/lib/sass/tree/comment_node.rb +3 -3
  68. data/lib/sass/tree/css_import_node.rb +11 -11
  69. data/lib/sass/tree/debug_node.rb +2 -2
  70. data/lib/sass/tree/directive_node.rb +4 -21
  71. data/lib/sass/tree/each_node.rb +8 -8
  72. data/lib/sass/tree/extend_node.rb +7 -14
  73. data/lib/sass/tree/for_node.rb +4 -4
  74. data/lib/sass/tree/function_node.rb +4 -9
  75. data/lib/sass/tree/if_node.rb +1 -1
  76. data/lib/sass/tree/import_node.rb +5 -4
  77. data/lib/sass/tree/media_node.rb +14 -4
  78. data/lib/sass/tree/mixin_def_node.rb +4 -4
  79. data/lib/sass/tree/mixin_node.rb +8 -21
  80. data/lib/sass/tree/node.rb +12 -54
  81. data/lib/sass/tree/prop_node.rb +20 -39
  82. data/lib/sass/tree/return_node.rb +2 -3
  83. data/lib/sass/tree/root_node.rb +3 -19
  84. data/lib/sass/tree/rule_node.rb +22 -35
  85. data/lib/sass/tree/supports_node.rb +13 -0
  86. data/lib/sass/tree/trace_node.rb +1 -2
  87. data/lib/sass/tree/variable_node.rb +3 -9
  88. data/lib/sass/tree/visitors/base.rb +8 -5
  89. data/lib/sass/tree/visitors/check_nesting.rb +19 -49
  90. data/lib/sass/tree/visitors/convert.rb +56 -74
  91. data/lib/sass/tree/visitors/cssize.rb +74 -202
  92. data/lib/sass/tree/visitors/deep_copy.rb +5 -10
  93. data/lib/sass/tree/visitors/extend.rb +7 -7
  94. data/lib/sass/tree/visitors/perform.rb +185 -278
  95. data/lib/sass/tree/visitors/set_options.rb +6 -20
  96. data/lib/sass/tree/visitors/to_css.rb +81 -234
  97. data/lib/sass/tree/warn_node.rb +2 -2
  98. data/lib/sass/tree/while_node.rb +2 -2
  99. data/lib/sass/util.rb +152 -522
  100. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  101. data/lib/sass/util/subset_map.rb +3 -4
  102. data/lib/sass/util/test.rb +1 -0
  103. data/lib/sass/version.rb +22 -20
  104. data/test/Gemfile +3 -0
  105. data/test/Gemfile.lock +10 -0
  106. data/test/sass/cache_test.rb +20 -62
  107. data/test/sass/callbacks_test.rb +1 -1
  108. data/test/sass/conversion_test.rb +2 -296
  109. data/test/sass/css2sass_test.rb +4 -23
  110. data/test/sass/engine_test.rb +354 -411
  111. data/test/sass/exec_test.rb +2 -2
  112. data/test/sass/extend_test.rb +145 -324
  113. data/test/sass/functions_test.rb +86 -873
  114. data/test/sass/importer_test.rb +21 -241
  115. data/test/sass/logger_test.rb +1 -1
  116. data/test/sass/more_results/more_import.css +1 -1
  117. data/test/sass/plugin_test.rb +26 -16
  118. data/test/sass/results/compact.css +1 -1
  119. data/test/sass/results/complex.css +4 -4
  120. data/test/sass/results/expanded.css +1 -1
  121. data/test/sass/results/import.css +1 -1
  122. data/test/sass/results/import_charset_ibm866.css +2 -2
  123. data/test/sass/results/mixins.css +17 -17
  124. data/test/sass/results/nested.css +1 -1
  125. data/test/sass/results/parent_ref.css +2 -2
  126. data/test/sass/results/script.css +3 -3
  127. data/test/sass/results/scss_import.css +1 -1
  128. data/test/sass/script_conversion_test.rb +7 -36
  129. data/test/sass/script_test.rb +53 -485
  130. data/test/sass/scss/css_test.rb +28 -143
  131. data/test/sass/scss/rx_test.rb +4 -4
  132. data/test/sass/scss/scss_test.rb +325 -2119
  133. data/test/sass/templates/scss_import.scss +1 -2
  134. data/test/sass/test_helper.rb +1 -1
  135. data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
  136. data/test/sass/util/subset_map_test.rb +2 -2
  137. data/test/sass/util_test.rb +1 -86
  138. data/test/test_helper.rb +8 -37
  139. metadata +19 -66
  140. data/lib/sass/exec/base.rb +0 -187
  141. data/lib/sass/exec/sass_convert.rb +0 -264
  142. data/lib/sass/exec/sass_scss.rb +0 -424
  143. data/lib/sass/features.rb +0 -47
  144. data/lib/sass/script/tree.rb +0 -16
  145. data/lib/sass/script/tree/funcall.rb +0 -306
  146. data/lib/sass/script/tree/interpolation.rb +0 -118
  147. data/lib/sass/script/tree/list_literal.rb +0 -77
  148. data/lib/sass/script/tree/literal.rb +0 -45
  149. data/lib/sass/script/tree/map_literal.rb +0 -64
  150. data/lib/sass/script/tree/selector.rb +0 -26
  151. data/lib/sass/script/tree/variable.rb +0 -57
  152. data/lib/sass/script/value.rb +0 -11
  153. data/lib/sass/script/value/base.rb +0 -240
  154. data/lib/sass/script/value/bool.rb +0 -35
  155. data/lib/sass/script/value/color.rb +0 -680
  156. data/lib/sass/script/value/helpers.rb +0 -262
  157. data/lib/sass/script/value/list.rb +0 -113
  158. data/lib/sass/script/value/map.rb +0 -70
  159. data/lib/sass/script/value/string.rb +0 -97
  160. data/lib/sass/selector/pseudo.rb +0 -256
  161. data/lib/sass/source/map.rb +0 -210
  162. data/lib/sass/source/position.rb +0 -39
  163. data/lib/sass/source/range.rb +0 -41
  164. data/lib/sass/stack.rb +0 -120
  165. data/lib/sass/tree/at_root_node.rb +0 -83
  166. data/lib/sass/tree/error_node.rb +0 -18
  167. data/lib/sass/tree/keyframe_rule_node.rb +0 -15
  168. data/lib/sass/util/cross_platform_random.rb +0 -19
  169. data/lib/sass/util/normalized_map.rb +0 -130
  170. data/lib/sass/util/ordered_hash.rb +0 -192
  171. data/test/sass/compiler_test.rb +0 -232
  172. data/test/sass/encoding_test.rb +0 -219
  173. data/test/sass/source_map_test.rb +0 -977
  174. data/test/sass/superselector_test.rb +0 -191
  175. data/test/sass/util/normalized_map_test.rb +0 -51
  176. data/test/sass/value_helpers_test.rb +0 -179
@@ -12,20 +12,16 @@ module Sass
12
12
 
13
13
  def string(re, *args)
14
14
  if re == :uri
15
- uri = scan(URI)
16
- return unless uri
17
- return [:string, Script::Value::String.new(uri)]
15
+ return unless uri = scan(URI)
16
+ return [:string, Script::String.new(uri)]
18
17
  end
19
18
 
20
19
  return unless scan(STRING)
21
- string_value = Sass::Script::Value::String.value(@scanner[1] || @scanner[2])
22
- value = Script::Value::String.new(string_value, :string)
23
- [:string, value]
20
+ [:string, Script::String.new((@scanner[1] || @scanner[2]).gsub(/\\(['"])/, '\1'), :string)]
24
21
  end
25
22
 
26
23
  def important
27
- s = scan(IMPORTANT)
28
- return unless s
24
+ return unless s = scan(IMPORTANT)
29
25
  [:raw, s]
30
26
  end
31
27
  end
@@ -17,11 +17,8 @@ module Sass
17
17
  production :div, :unary_plus, :div
18
18
 
19
19
  def string
20
- tok = try_tok(:string)
21
- return number unless tok
22
- unless @lexer.peek && @lexer.peek.type == :begin_interpolation
23
- return literal_node(tok.value, tok.source_range)
24
- end
20
+ return number unless tok = try_tok(:string)
21
+ return tok.value unless @lexer.peek && @lexer.peek.type == :begin_interpolation
25
22
  end
26
23
 
27
24
  # Short-circuit all the SassScript-only productions
@@ -0,0 +1,245 @@
1
+ require 'sass/script/functions'
2
+
3
+ module Sass
4
+ module Script
5
+ # A SassScript parse node representing a function call.
6
+ #
7
+ # A function call either calls one of the functions in {Script::Functions},
8
+ # or if no function with the given name exists
9
+ # it returns a string representation of the function call.
10
+ class Funcall < Node
11
+ # The name of the function.
12
+ #
13
+ # @return [String]
14
+ attr_reader :name
15
+
16
+ # The arguments to the function.
17
+ #
18
+ # @return [Array<Script::Node>]
19
+ attr_reader :args
20
+
21
+ # The keyword arguments to the function.
22
+ #
23
+ # @return [{String => Script::Node}]
24
+ attr_reader :keywords
25
+
26
+ # The splat argument for this function, if one exists.
27
+ #
28
+ # @return [Script::Node?]
29
+ attr_accessor :splat
30
+
31
+ # @param name [String] See \{#name}
32
+ # @param args [Array<Script::Node>] See \{#args}
33
+ # @param splat [Script::Node] See \{#splat}
34
+ # @param keywords [{String => Script::Node}] See \{#keywords}
35
+ def initialize(name, args, keywords, splat)
36
+ @name = name
37
+ @args = args
38
+ @keywords = keywords
39
+ @splat = splat
40
+ super()
41
+ end
42
+
43
+ # @return [String] A string representation of the function call
44
+ def inspect
45
+ args = @args.map {|a| a.inspect}.join(', ')
46
+ keywords = Sass::Util.hash_to_a(@keywords).
47
+ map {|k, v| "$#{k}: #{v.inspect}"}.join(', ')
48
+ if self.splat
49
+ splat = (args.empty? && keywords.empty?) ? "" : ", "
50
+ splat = "#{splat}#{self.splat.inspect}..."
51
+ end
52
+ "#{name}(#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords}#{splat})"
53
+ end
54
+
55
+ # @see Node#to_sass
56
+ def to_sass(opts = {})
57
+ arg_to_sass = lambda do |arg|
58
+ sass = arg.to_sass(opts)
59
+ sass = "(#{sass})" if arg.is_a?(Sass::Script::List) && arg.separator == :comma
60
+ sass
61
+ end
62
+
63
+ args = @args.map(&arg_to_sass).join(', ')
64
+ keywords = Sass::Util.hash_to_a(@keywords).
65
+ map {|k, v| "$#{dasherize(k, opts)}: #{arg_to_sass[v]}"}.join(', ')
66
+ if self.splat
67
+ splat = (args.empty? && keywords.empty?) ? "" : ", "
68
+ splat = "#{splat}#{arg_to_sass[self.splat]}..."
69
+ end
70
+ "#{dasherize(name, opts)}(#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords}#{splat})"
71
+ end
72
+
73
+ # Returns the arguments to the function.
74
+ #
75
+ # @return [Array<Node>]
76
+ # @see Node#children
77
+ def children
78
+ res = @args + @keywords.values
79
+ res << @splat if @splat
80
+ res
81
+ end
82
+
83
+ # @see Node#deep_copy
84
+ def deep_copy
85
+ node = dup
86
+ node.instance_variable_set('@args', args.map {|a| a.deep_copy})
87
+ node.instance_variable_set('@keywords', Hash[keywords.map {|k, v| [k, v.deep_copy]}])
88
+ node
89
+ end
90
+
91
+ protected
92
+
93
+ # Evaluates the function call.
94
+ #
95
+ # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
96
+ # @return [Literal] The SassScript object that is the value of the function call
97
+ # @raise [Sass::SyntaxError] if the function call raises an ArgumentError
98
+ def _perform(environment)
99
+ args = @args.map {|a| a.perform(environment)}
100
+ splat = @splat.perform(environment) if @splat
101
+ if fn = environment.function(@name)
102
+ keywords = Sass::Util.map_hash(@keywords) {|k, v| [k, v.perform(environment)]}
103
+ return without_original(perform_sass_fn(fn, args, keywords, splat))
104
+ end
105
+
106
+ ruby_name = @name.tr('-', '_')
107
+ args = construct_ruby_args(ruby_name, args, splat, environment)
108
+
109
+ unless Functions.callable?(ruby_name)
110
+ without_original(opts(to_literal(args)))
111
+ else
112
+ without_original(opts(Functions::EvaluationContext.new(environment.options).
113
+ send(ruby_name, *args)))
114
+ end
115
+ rescue ArgumentError => e
116
+ message = e.message
117
+
118
+ # If this is a legitimate Ruby-raised argument error, re-raise it.
119
+ # Otherwise, it's an error in the user's stylesheet, so wrap it.
120
+ if Sass::Util.rbx?
121
+ # Rubinius has a different error report string than vanilla Ruby. It
122
+ # also doesn't put the actual method for which the argument error was
123
+ # thrown in the backtrace, nor does it include `send`, so we look for
124
+ # `_perform`.
125
+ if e.message =~ /^method '([^']+)': given (\d+), expected (\d+)/
126
+ error_name, given, expected = $1, $2, $3
127
+ raise e if error_name != ruby_name || e.backtrace[0] !~ /:in `_perform'$/
128
+ message = "wrong number of arguments (#{given} for #{expected})"
129
+ end
130
+ elsif Sass::Util.jruby?
131
+ if Sass::Util.jruby1_6?
132
+ should_maybe_raise = e.message =~ /^wrong number of arguments \((\d+) for (\d+)\)/ &&
133
+ # The one case where JRuby does include the Ruby name of the function
134
+ # is manually-thrown ArgumentErrors, which are indistinguishable from
135
+ # legitimate ArgumentErrors. We treat both of these as
136
+ # Sass::SyntaxErrors even though it can hide Ruby errors.
137
+ e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
138
+ else
139
+ should_maybe_raise = e.message =~ /^wrong number of arguments calling `[^`]+` \((\d+) for (\d+)\)/
140
+ given, expected = $1, $2
141
+ end
142
+
143
+ if should_maybe_raise
144
+ # JRuby 1.7 includes __send__ before send and _perform.
145
+ trace = e.backtrace.dup
146
+ raise e if !Sass::Util.jruby1_6? && trace.shift !~ /:in `__send__'$/
147
+
148
+ # JRuby (as of 1.7.2) doesn't put the actual method
149
+ # for which the argument error was thrown in the backtrace, so we
150
+ # detect whether our send threw an argument error.
151
+ if !(trace[0] =~ /:in `send'$/ && trace[1] =~ /:in `_perform'$/)
152
+ raise e
153
+ elsif !Sass::Util.jruby1_6?
154
+ # JRuby 1.7 doesn't use standard formatting for its ArgumentErrors.
155
+ message = "wrong number of arguments (#{given} for #{expected})"
156
+ end
157
+ end
158
+ elsif e.message =~ /^wrong number of arguments \(\d+ for \d+\)/ &&
159
+ e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
160
+ raise e
161
+ end
162
+ raise Sass::SyntaxError.new("#{message} for `#{name}'")
163
+ end
164
+
165
+ # This method is factored out from `_perform` so that compass can override
166
+ # it with a cross-browser implementation for functions that require vendor prefixes
167
+ # in the generated css.
168
+ def to_literal(args)
169
+ Script::String.new("#{name}(#{args.join(', ')})")
170
+ end
171
+
172
+ private
173
+
174
+ def without_original(value)
175
+ return value unless value.is_a?(Number)
176
+ value = value.dup
177
+ value.original = nil
178
+ return value
179
+ end
180
+
181
+ def construct_ruby_args(name, args, splat, environment)
182
+ args += splat.to_a if splat
183
+
184
+ # If variable arguments were passed, there won't be any explicit keywords.
185
+ if splat.is_a?(Sass::Script::ArgList)
186
+ kwargs_size = splat.keywords.size
187
+ splat.keywords_accessed = false
188
+ else
189
+ kwargs_size = @keywords.size
190
+ end
191
+
192
+ unless signature = Functions.signature(name.to_sym, args.size, kwargs_size)
193
+ return args if @keywords.empty?
194
+ raise Sass::SyntaxError.new("Function #{name} doesn't support keyword arguments")
195
+ end
196
+ keywords = splat.is_a?(Sass::Script::ArgList) ? splat.keywords :
197
+ Sass::Util.map_hash(@keywords) {|k, v| [k, v.perform(environment)]}
198
+
199
+ # If the user passes more non-keyword args than the function expects,
200
+ # but it does expect keyword args, Ruby's arg handling won't raise an error.
201
+ # Since we don't want to make functions think about this,
202
+ # we'll handle it for them here.
203
+ if signature.var_kwargs && !signature.var_args && args.size > signature.args.size
204
+ raise Sass::SyntaxError.new(
205
+ "#{args[signature.args.size].inspect} is not a keyword argument for `#{name}'")
206
+ elsif keywords.empty?
207
+ return args
208
+ end
209
+
210
+ args = args + signature.args[args.size..-1].map do |argname|
211
+ if keywords.has_key?(argname)
212
+ keywords.delete(argname)
213
+ else
214
+ raise Sass::SyntaxError.new("Function #{name} requires an argument named $#{argname}")
215
+ end
216
+ end
217
+
218
+ if keywords.size > 0
219
+ if signature.var_kwargs
220
+ args << keywords
221
+ else
222
+ argname = keywords.keys.sort.first
223
+ if signature.args.include?(argname)
224
+ raise Sass::SyntaxError.new("Function #{name} was passed argument $#{argname} both by position and by name")
225
+ else
226
+ raise Sass::SyntaxError.new("Function #{name} doesn't have an argument named $#{argname}")
227
+ end
228
+ end
229
+ end
230
+
231
+ args
232
+ end
233
+
234
+ def perform_sass_fn(function, args, keywords, splat)
235
+ Sass::Tree::Visitors::Perform.perform_arguments(function, args, keywords, splat) do |env|
236
+ val = catch :_sass_return do
237
+ function.tree.each {|c| Sass::Tree::Visitors::Perform.visit(c, env)}
238
+ raise Sass::SyntaxError.new("Function #{@name} finished without @return")
239
+ end
240
+ val
241
+ end
242
+ end
243
+ end
244
+ end
245
+ end
@@ -1,15 +1,10 @@
1
- require 'sass/script/value/helpers'
2
-
3
1
  module Sass::Script
4
- # @comment
5
- # YARD can't handle some multiline tags, and we need really long tags for function declarations.
6
- # rubocop:disable LineLength
7
2
  # Methods in this module are accessible from the SassScript context.
8
3
  # For example, you can write
9
4
  #
10
5
  # $color: hsl(120deg, 100%, 50%)
11
6
  #
12
- # and it will call {Functions#hsl}.
7
+ # and it will call {Sass::Script::Functions#hsl}.
13
8
  #
14
9
  # The following functions are provided:
15
10
  #
@@ -18,12 +13,10 @@ module Sass::Script
18
13
  # ## RGB Functions
19
14
  #
20
15
  # \{#rgb rgb($red, $green, $blue)}
21
- # : Creates a {Sass::Script::Value::Color Color} from red, green, and blue
22
- # values.
16
+ # : Creates a {Color} from red, green, and blue values.
23
17
  #
24
18
  # \{#rgba rgba($red, $green, $blue, $alpha)}
25
- # : Creates a {Sass::Script::Value::Color Color} from red, green, blue, and
26
- # alpha values.
19
+ # : Creates a {Color} from red, green, blue, and alpha values.
27
20
  #
28
21
  # \{#red red($color)}
29
22
  # : Gets the red component of a color.
@@ -34,18 +27,17 @@ module Sass::Script
34
27
  # \{#blue blue($color)}
35
28
  # : Gets the blue component of a color.
36
29
  #
37
- # \{#mix mix($color1, $color2, \[$weight\])}
30
+ # \{#mix mix($color-1, $color-2, \[$weight\])}
38
31
  # : Mixes two colors together.
39
32
  #
40
33
  # ## HSL Functions
41
34
  #
42
35
  # \{#hsl hsl($hue, $saturation, $lightness)}
43
- # : Creates a {Sass::Script::Value::Color Color} from hue, saturation, and
44
- # lightness values.
36
+ # : Creates a {Color} from hue, saturation, and lightness values.
45
37
  #
46
38
  # \{#hsla hsla($hue, $saturation, $lightness, $alpha)}
47
- # : Creates a {Sass::Script::Value::Color Color} from hue, saturation,
48
- # lightness, and alpha values.
39
+ # : Creates a {Color} from hue, saturation, lightness, and alpha
40
+ # values.
49
41
  #
50
42
  # \{#hue hue($color)}
51
43
  # : Gets the hue component of a color.
@@ -116,39 +108,21 @@ module Sass::Script
116
108
  # \{#quote quote($string)}
117
109
  # : Adds quotes to a string.
118
110
  #
119
- # \{#str_length str-length($string)}
120
- # : Returns the number of characters in a string.
121
- #
122
- # \{#str_insert str-insert($string, $insert, $index)}
123
- # : Inserts `$insert` into `$string` at `$index`.
124
- #
125
- # \{#str_index str-index($string, $substring)}
126
- # : Returns the index of the first occurance of `$substring` in `$string`.
127
- #
128
- # \{#str_slice str-slice($string, $start-at, [$end-at])}
129
- # : Extracts a substring from `$string`.
130
- #
131
- # \{#to_upper_case to-upper-case($string)}
132
- # : Converts a string to upper case.
133
- #
134
- # \{#to_lower_case to-lower-case($string)}
135
- # : Converts a string to lower case.
136
- #
137
111
  # ## Number Functions
138
112
  #
139
- # \{#percentage percentage($number)}
113
+ # \{#percentage percentage($value)}
140
114
  # : Converts a unitless number to a percentage.
141
115
  #
142
- # \{#round round($number)}
116
+ # \{#round round($value)}
143
117
  # : Rounds a number to the nearest whole number.
144
118
  #
145
- # \{#ceil ceil($number)}
119
+ # \{#ceil ceil($value)}
146
120
  # : Rounds a number up to the next whole number.
147
121
  #
148
- # \{#floor floor($number)}
122
+ # \{#floor floor($value)}
149
123
  # : Rounds a number down to the previous whole number.
150
124
  #
151
- # \{#abs abs($number)}
125
+ # \{#abs abs($value)}
152
126
  # : Returns the absolute value of a number.
153
127
  #
154
128
  # \{#min min($numbers...)\}
@@ -157,13 +131,8 @@ module Sass::Script
157
131
  # \{#max max($numbers...)\}
158
132
  # : Finds the maximum of several numbers.
159
133
  #
160
- # \{#random random([$limit])\}
161
- # : Returns a random number.
162
- #
163
134
  # ## List Functions {#list-functions}
164
135
  #
165
- # All list functions work for maps as well, treating them as lists of pairs.
166
- #
167
136
  # \{#length length($list)}
168
137
  # : Returns the length of a list.
169
138
  #
@@ -182,94 +151,8 @@ module Sass::Script
182
151
  # \{#index index($list, $value)}
183
152
  # : Returns the position of a value within a list.
184
153
  #
185
- # \{#list_separator list-separator(#list)}
186
- # : Returns the separator of a list.
187
- #
188
- # ## Map Functions {#map-functions}
189
- #
190
- # \{#map_get map-get($map, $key)}
191
- # : Returns the value in a map associated with a given key.
192
- #
193
- # \{#map_merge map-merge($map1, $map2)}
194
- # : Merges two maps together into a new map.
195
- #
196
- # \{#map_remove map-remove($map, $keys...)}
197
- # : Returns a new map with keys removed.
198
- #
199
- # \{#map_keys map-keys($map)}
200
- # : Returns a list of all keys in a map.
201
- #
202
- # \{#map_values map-values($map)}
203
- # : Returns a list of all values in a map.
204
- #
205
- # \{#map_has_key map-has-key($map, $key)}
206
- # : Returns whether a map has a value associated with a given key.
207
- #
208
- # \{#keywords keywords($args)}
209
- # : Returns the keywords passed to a function that takes variable arguments.
210
- #
211
- # ## Selector Functions
212
- #
213
- # Selector functions are very liberal in the formats they support
214
- # for selector arguments. They can take a plain string, a list of
215
- # lists as returned by `&` or anything in between:
216
- #
217
- # * A plain sring, such as `".foo .bar, .baz .bang"`.
218
- # * A space-separated list of strings such as `(".foo" ".bar")`.
219
- # * A comma-separated list of strings such as `(".foo .bar", ".baz .bang")`.
220
- # * A comma-separated list of space-separated lists of strings such
221
- # as `((".foo" ".bar"), (".baz" ".bang"))`.
222
- #
223
- # In general, selector functions allow placeholder selectors
224
- # (`%foo`) but disallow parent-reference selectors (`&`).
225
- #
226
- # \{#selector_nest selector-nest($selectors...)}
227
- # : Nests selector beneath one another like they would be nested in the
228
- # stylesheet.
229
- #
230
- # \{#selector_append selector-append($selectors...)}
231
- # : Appends selectors to one another without spaces in between.
232
- #
233
- # \{#selector_extend selector-extend($selector, $extendee, $extender)}
234
- # : Extends `$extendee` with `$extender` within `$selector`.
235
- #
236
- # \{#selector_replace selector-replace($selector, $original, $replacement)}
237
- # : Replaces `$original` with `$replacement` within `$selector`.
238
- #
239
- # \{#selector_unify selector-unify($selector1, $selector2)}
240
- # : Unifies two selectors to produce a selector that matches
241
- # elements matched by both.
242
- #
243
- # \{#is_superselector is-superselector($super, $sub)}
244
- # : Returns whether `$super` matches all the elements `$sub` does, and
245
- # possibly more.
246
- #
247
- # \{#simple_selectors simple-selectors($selector)}
248
- # : Returns the simple selectors that comprise a compound selector.
249
- #
250
- # \{#selector_parse selector-parse($selector)}
251
- # : Parses a selector into the format returned by `&`.
252
- #
253
154
  # ## Introspection Functions
254
155
  #
255
- # \{#feature_exists feature-exists($feature)}
256
- # : Returns whether a feature exists in the current Sass runtime.
257
- #
258
- # \{#variable_exists variable-exists($name)}
259
- # : Returns whether a variable with the given name exists in the current scope.
260
- #
261
- # \{#global_variable_exists global-variable-exists($name)}
262
- # : Returns whether a variable with the given name exists in the global scope.
263
- #
264
- # \{#function_exists function-exists($name)}
265
- # : Returns whether a function with the given name exists.
266
- #
267
- # \{#mixin_exists mixin-exists($name)}
268
- # : Returns whether a mixin with the given name exists.
269
- #
270
- # \{#inspect inspect($value)}
271
- # : Returns the string representation of a value as it would be represented in Sass.
272
- #
273
156
  # \{#type_of type-of($value)}
274
157
  # : Returns the type of a value.
275
158
  #
@@ -279,21 +162,15 @@ module Sass::Script
279
162
  # \{#unitless unitless($number)}
280
163
  # : Returns whether a number has units.
281
164
  #
282
- # \{#comparable comparable($number1, $number2)}
165
+ # \{#comparable comparable($number-1, $number-2)}
283
166
  # : Returns whether two numbers can be added, subtracted, or compared.
284
167
  #
285
- # \{#call call($name, $args...)}
286
- # : Dynamically calls a Sass function.
287
- #
288
168
  # ## Miscellaneous Functions
289
169
  #
290
170
  # \{#if if($condition, $if-true, $if-false)}
291
171
  # : Returns one of two values, depending on whether or not `$condition` is
292
172
  # true.
293
173
  #
294
- # \{#unique_id unique-id()}
295
- # : Returns a unique CSS identifier.
296
- #
297
174
  # ## Adding Custom Functions
298
175
  #
299
176
  # New Sass functions can be added by adding Ruby methods to this module.
@@ -302,9 +179,9 @@ module Sass::Script
302
179
  # module Sass::Script::Functions
303
180
  # def reverse(string)
304
181
  # assert_type string, :String
305
- # Sass::Script::Value::String.new(string.value.reverse)
182
+ # Sass::Script::String.new(string.value.reverse)
306
183
  # end
307
- # declare :reverse, [:string]
184
+ # declare :reverse, :args => [:string]
308
185
  # end
309
186
  #
310
187
  # Calling {declare} tells Sass the argument names for your function.
@@ -312,15 +189,14 @@ module Sass::Script
312
189
  # {declare} can also allow your function to take arbitrary keyword arguments.
313
190
  #
314
191
  # There are a few things to keep in mind when modifying this module.
315
- # First of all, the arguments passed are {Value} objects.
316
- # Value objects are also expected to be returned.
192
+ # First of all, the arguments passed are {Sass::Script::Literal} objects.
193
+ # Literal objects are also expected to be returned.
317
194
  # This means that Ruby values must be unwrapped and wrapped.
318
195
  #
319
- # Most Value objects support the {Value::Base#value value} accessor for getting
320
- # their Ruby values. Color objects, though, must be accessed using
321
- # {Sass::Script::Value::Color#rgb rgb}, {Sass::Script::Value::Color#red red},
322
- # {Sass::Script::Value::Color#blue green}, or {Sass::Script::Value::Color#blue
323
- # blue}.
196
+ # Most Literal objects support the {Sass::Script::Literal#value value} accessor
197
+ # for getting their Ruby values.
198
+ # Color objects, though, must be accessed using {Sass::Script::Color#rgb rgb},
199
+ # {Sass::Script::Color#red red}, {Sass::Script::Color#blue green}, or {Sass::Script::Color#blue blue}.
324
200
  #
325
201
  # Second, making Ruby functions accessible from Sass introduces the temptation
326
202
  # to do things like database access within stylesheets.
@@ -340,24 +216,19 @@ module Sass::Script
340
216
  #
341
217
  # ### Caveats
342
218
  #
343
- # When creating new {Value} objects within functions, be aware that it's not
344
- # safe to call {Value::Base#to_s #to_s} (or other methods that use the string
345
- # representation) on those objects without first setting {Tree::Node#options=
346
- # the #options attribute}.
347
- #
348
- # @comment
349
- # rubocop:enable LineLength
219
+ # When creating new {Literal} objects within functions,
220
+ # be aware that it's not safe to call {Literal#to_s #to_s}
221
+ # (or other methods that use the string representation)
222
+ # on those objects without first setting {Node#options= the #options attribute}.
350
223
  module Functions
351
224
  @signatures = {}
352
225
 
353
226
  # A class representing a Sass function signature.
354
227
  #
355
- # @attr args [Array<String>] The names of the arguments to the function.
356
- # @attr delayed_args [Array<String>] The names of the arguments whose evaluation should be
357
- # delayed.
228
+ # @attr args [Array<Symbol>] The names of the arguments to the function.
358
229
  # @attr var_args [Boolean] Whether the function takes a variable number of arguments.
359
230
  # @attr var_kwargs [Boolean] Whether the function takes an arbitrary set of keyword arguments.
360
- Signature = Struct.new(:args, :delayed_args, :var_args, :var_kwargs, :deprecated)
231
+ Signature = Struct.new(:args, :var_args, :var_kwargs)
361
232
 
362
233
  # Declare a Sass signature for a Ruby-defined function.
363
234
  # This includes the names of the arguments,
@@ -390,30 +261,15 @@ module Sass::Script
390
261
  # Whether the function accepts other keyword arguments
391
262
  # in addition to those in `:args`.
392
263
  # If this is true, the Ruby function will be passed a hash from strings
393
- # to {Value}s as the last argument.
264
+ # to {Sass::Script::Literal}s as the last argument.
394
265
  # In addition, if this is true and `:var_args` is not,
395
266
  # Sass will ensure that the last argument passed is a hash.
396
267
  def self.declare(method_name, args, options = {})
397
- delayed_args = []
398
- args = args.map do |a|
399
- a = a.to_s
400
- if a[0] == ?&
401
- a = a[1..-1]
402
- delayed_args << a
403
- end
404
- a
405
- end
406
- # We don't expose this functionality except to certain builtin methods.
407
- if delayed_args.any? && method_name != :if
408
- raise ArgumentError.new("Delayed arguments are not allowed for method #{method_name}")
409
- end
410
268
  @signatures[method_name] ||= []
411
269
  @signatures[method_name] << Signature.new(
412
- args,
413
- delayed_args,
270
+ args.map {|s| s.to_s},
414
271
  options[:var_args],
415
- options[:var_kwargs],
416
- options[:deprecated] && options[:deprecated].map {|a| a.to_s})
272
+ options[:var_kwargs])
417
273
  end
418
274
 
419
275
  # Determine the correct signature for the number of arguments
@@ -421,8 +277,8 @@ module Sass::Script
421
277
  # If no signatures match, the first signature is returned for error messaging.
422
278
  #
423
279
  # @param method_name [Symbol] The name of the Ruby function to be called.
424
- # @param arg_arity [Fixnum] The number of unnamed arguments the function was passed.
425
- # @param kwarg_arity [Fixnum] The number of keyword arguments the function was passed.
280
+ # @param arg_arity [Number] The number of unnamed arguments the function was passed.
281
+ # @param kwarg_arity [Number] The number of keyword arguments the function was passed.
426
282
  #
427
283
  # @return [{Symbol => Object}, nil]
428
284
  # The signature options for the matching signature,
@@ -430,76 +286,42 @@ module Sass::Script
430
286
  def self.signature(method_name, arg_arity, kwarg_arity)
431
287
  return unless @signatures[method_name]
432
288
  @signatures[method_name].each do |signature|
433
- sig_arity = signature.args.size
434
- return signature if sig_arity == arg_arity + kwarg_arity
435
- next unless sig_arity < arg_arity + kwarg_arity
289
+ return signature if signature.args.size == arg_arity + kwarg_arity
290
+ next unless signature.args.size < arg_arity + kwarg_arity
436
291
 
437
292
  # We have enough args.
438
293
  # Now we need to figure out which args are varargs
439
294
  # and if the signature allows them.
440
295
  t_arg_arity, t_kwarg_arity = arg_arity, kwarg_arity
441
- if sig_arity > t_arg_arity
296
+ if signature.args.size > t_arg_arity
442
297
  # we transfer some kwargs arity to args arity
443
298
  # if it does not have enough args -- assuming the names will work out.
444
- t_kwarg_arity -= (sig_arity - t_arg_arity)
445
- t_arg_arity = sig_arity
299
+ t_kwarg_arity -= (signature.args.size - t_arg_arity)
300
+ t_arg_arity = signature.args.size
446
301
  end
447
302
 
448
- if (t_arg_arity == sig_arity || t_arg_arity > sig_arity && signature.var_args) &&
449
- (t_kwarg_arity == 0 || t_kwarg_arity > 0 && signature.var_kwargs)
303
+ if ( t_arg_arity == signature.args.size || t_arg_arity > signature.args.size && signature.var_args ) &&
304
+ (t_kwarg_arity == 0 || t_kwarg_arity > 0 && signature.var_kwargs)
450
305
  return signature
451
306
  end
452
307
  end
453
308
  @signatures[method_name].first
454
309
  end
455
310
 
456
- # Sets the random seed used by Sass's internal random number generator.
457
- #
458
- # This can be used to ensure consistent random number sequences which
459
- # allows for consistent results when testing, etc.
460
- #
461
- # @param seed [Integer]
462
- # @return [Integer] The same seed.
463
- def self.random_seed=(seed)
464
- @random_number_generator = Sass::Util::CrossPlatformRandom.new(seed)
465
- end
466
-
467
- # Get Sass's internal random number generator.
468
- #
469
- # @return [Random]
470
- def self.random_number_generator
471
- @random_number_generator ||= Sass::Util::CrossPlatformRandom.new
472
- end
473
-
474
311
  # The context in which methods in {Script::Functions} are evaluated.
475
312
  # That means that all instance methods of {EvaluationContext}
476
313
  # are available to use in functions.
477
314
  class EvaluationContext
478
315
  include Functions
479
- include Value::Helpers
480
-
481
- # The human-readable names for [Sass::Script::Value::Base]. The default is
482
- # just the downcased name of the type. The default is the downcased type
483
- # name.
484
- TYPE_NAMES = {:ArgList => 'variable argument list'}
485
-
486
- # The environment for this function. This environment's
487
- # {Environment#parent} is the global environment, and its
488
- # {Environment#caller} is a read-only view of the local environment of the
489
- # caller of this function.
490
- #
491
- # @return [Environment]
492
- attr_reader :environment
493
316
 
494
317
  # The options hash for the {Sass::Engine} that is processing the function call
495
318
  #
496
319
  # @return [{Symbol => Object}]
497
320
  attr_reader :options
498
321
 
499
- # @param environment [Environment] See \{#environment}
500
- def initialize(environment)
501
- @environment = environment
502
- @options = environment.options
322
+ # @param options [{Symbol => Object}] See \{#options}
323
+ def initialize(options)
324
+ @options = options
503
325
  end
504
326
 
505
327
  # Asserts that the type of a given SassScript value
@@ -512,79 +334,15 @@ module Sass::Script
512
334
  # @example
513
335
  # assert_type value, :String
514
336
  # assert_type value, :Number
515
- # @param value [Sass::Script::Value::Base] A SassScript value
337
+ # @param value [Sass::Script::Literal] A SassScript value
516
338
  # @param type [Symbol] The name of the type the value is expected to be
517
339
  # @param name [String, Symbol, nil] The name of the argument.
518
- # @raise [ArgumentError] if value is not of the correct type.
519
340
  def assert_type(value, type, name = nil)
520
- klass = Sass::Script::Value.const_get(type)
521
- return if value.is_a?(klass)
522
- return if value.is_a?(Sass::Script::Value::List) && type == :Map && value.value.empty?
523
- err = "#{value.inspect} is not a #{TYPE_NAMES[type] || type.to_s.downcase}"
341
+ return if value.is_a?(Sass::Script.const_get(type))
342
+ err = "#{value.inspect} is not a #{type.to_s.downcase}"
524
343
  err = "$#{name.to_s.gsub('_', '-')}: " + err if name
525
344
  raise ArgumentError.new(err)
526
345
  end
527
-
528
- # Asserts that the unit of the number is as expected.
529
- #
530
- # @example
531
- # assert_unit number, "px"
532
- # assert_unit number, nil
533
- # @param number [Sass::Script::Value::Number] The number to be validated.
534
- # @param unit [::String]
535
- # The unit that the number must have.
536
- # If nil, the number must be unitless.
537
- # @param name [::String] The name of the parameter being validated.
538
- # @raise [ArgumentError] if number is not of the correct unit or is not a number.
539
- def assert_unit(number, unit, name = nil)
540
- assert_type number, :Number, name
541
- return if number.is_unit?(unit)
542
- expectation = unit ? "have a unit of #{unit}" : "be unitless"
543
- if name
544
- raise ArgumentError.new("Expected $#{name} to #{expectation} but got #{number}")
545
- else
546
- raise ArgumentError.new("Expected #{number} to #{expectation}")
547
- end
548
- end
549
-
550
- # Asserts that the value is an integer.
551
- #
552
- # @example
553
- # assert_integer 2px
554
- # assert_integer 2.5px
555
- # => SyntaxError: "Expected 2.5px to be an integer"
556
- # assert_integer 2.5px, "width"
557
- # => SyntaxError: "Expected width to be an integer but got 2.5px"
558
- # @param number [Sass::Script::Value::Base] The value to be validated.
559
- # @param name [::String] The name of the parameter being validated.
560
- # @raise [ArgumentError] if number is not an integer or is not a number.
561
- def assert_integer(number, name = nil)
562
- assert_type number, :Number, name
563
- return if number.int?
564
- if name
565
- raise ArgumentError.new("Expected $#{name} to be an integer but got #{number}")
566
- else
567
- raise ArgumentError.new("Expected #{number} to be an integer")
568
- end
569
- end
570
-
571
- # Performs a node that has been delayed for execution.
572
- #
573
- # @private
574
- # @param node [Sass::Script::Tree::Node,
575
- # Sass::Script::Value::Base] When this is a tree node, it's
576
- # performed in the caller's environment. When it's a value
577
- # (which can happen when the value had to be performed already
578
- # -- like for a splat), it's returned as-is.
579
- # @param env [Sass::Environment] The environment within which to perform the node.
580
- # Defaults to the (read-only) environment of the caller.
581
- def perform(node, env = environment.caller)
582
- if node.is_a?(Sass::Script::Value::Base)
583
- node
584
- else
585
- node.perform(env)
586
- end
587
- end
588
346
  end
589
347
 
590
348
  class << self
@@ -595,7 +353,6 @@ module Sass::Script
595
353
  alias_method :callable?, :public_method_defined?
596
354
 
597
355
  private
598
-
599
356
  def include(*args)
600
357
  r = super
601
358
  # We have to re-include ourselves into EvaluationContext to work around
@@ -605,58 +362,48 @@ module Sass::Script
605
362
  end
606
363
  end
607
364
 
608
- # Creates a {Sass::Script::Value::Color Color} object from red, green, and
609
- # blue values.
365
+ # Creates a {Color} object from red, green, and blue values.
610
366
  #
611
367
  # @see #rgba
612
368
  # @overload rgb($red, $green, $blue)
613
- # @param $red [Sass::Script::Value::Number] The amount of red in the color.
614
- # Must be between 0 and 255 inclusive, or between `0%` and `100%`
615
- # inclusive
616
- # @param $green [Sass::Script::Value::Number] The amount of green in the
617
- # color. Must be between 0 and 255 inclusive, or between `0%` and `100%`
618
- # inclusive
619
- # @param $blue [Sass::Script::Value::Number] The amount of blue in the
620
- # color. Must be between 0 and 255 inclusive, or between `0%` and `100%`
621
- # inclusive
622
- # @return [Sass::Script::Value::Color]
369
+ # @param $red [Number] The amount of red in the color. Must be between 0 and
370
+ # 255 inclusive, or between `0%` and `100%` inclusive
371
+ # @param $green [Number] The amount of green in the color. Must be between 0
372
+ # and 255 inclusive, or between `0%` and `100%` inclusive
373
+ # @param $blue [Number] The amount of blue in the color. Must be between 0
374
+ # and 255 inclusive, or between `0%` and `100%` inclusive
375
+ # @return [Color]
623
376
  # @raise [ArgumentError] if any parameter is the wrong type or out of bounds
624
377
  def rgb(red, green, blue)
625
378
  assert_type red, :Number, :red
626
379
  assert_type green, :Number, :green
627
380
  assert_type blue, :Number, :blue
628
381
 
629
- color_attrs = [[red, :red], [green, :green], [blue, :blue]].map do |(c, name)|
630
- if c.is_unit?("%")
631
- c.value * 255 / 100.0
632
- elsif c.unitless?
633
- c.value
634
- else
635
- raise ArgumentError.new("Expected #{c} to be unitless or have a unit of % but got #{c}")
636
- end
637
- end
638
-
639
- # Don't store the string representation for function-created colors, both
640
- # because it's not very useful and because some functions aren't supported
641
- # on older browsers.
642
- Sass::Script::Value::Color.new(color_attrs)
382
+ Color.new([[red, :red], [green, :green], [blue, :blue]].map do |(c, name)|
383
+ v = c.value
384
+ if c.numerator_units == ["%"] && c.denominator_units.empty?
385
+ v = Sass::Util.check_range("$#{name}: Color value", 0..100, c, '%')
386
+ v * 255 / 100.0
387
+ else
388
+ Sass::Util.check_range("$#{name}: Color value", 0..255, c)
389
+ end
390
+ end)
643
391
  end
644
392
  declare :rgb, [:red, :green, :blue]
645
393
 
646
- # Creates a {Sass::Script::Value::Color Color} from red, green, blue, and
647
- # alpha values.
394
+ # Creates a {Color} from red, green, blue, and alpha values.
648
395
  # @see #rgb
649
396
  #
650
397
  # @overload rgba($red, $green, $blue, $alpha)
651
- # @param $red [Sass::Script::Value::Number] The amount of red in the
652
- # color. Must be between 0 and 255 inclusive
653
- # @param $green [Sass::Script::Value::Number] The amount of green in the
654
- # color. Must be between 0 and 255 inclusive
655
- # @param $blue [Sass::Script::Value::Number] The amount of blue in the
656
- # color. Must be between 0 and 255 inclusive
657
- # @param $alpha [Sass::Script::Value::Number] The opacity of the color.
658
- # Must be between 0 and 1 inclusive
659
- # @return [Sass::Script::Value::Color]
398
+ # @param $red [Number] The amount of red in the color. Must be between 0
399
+ # and 255 inclusive
400
+ # @param $green [Number] The amount of green in the color. Must be between
401
+ # 0 and 255 inclusive
402
+ # @param $blue [Number] The amount of blue in the color. Must be between 0
403
+ # and 255 inclusive
404
+ # @param $alpha [Number] The opacity of the color. Must be between 0 and 1
405
+ # inclusive
406
+ # @return [Color]
660
407
  # @raise [ArgumentError] if any parameter is the wrong type or out of
661
408
  # bounds
662
409
  #
@@ -667,11 +414,10 @@ module Sass::Script
667
414
  # rgba(#102030, 0.5) => rgba(16, 32, 48, 0.5)
668
415
  # rgba(blue, 0.2) => rgba(0, 0, 255, 0.2)
669
416
  #
670
- # @param $color [Sass::Script::Value::Color] The color whose opacity will
671
- # be changed.
672
- # @param $alpha [Sass::Script::Value::Number] The new opacity of the
673
- # color. Must be between 0 and 1 inclusive
674
- # @return [Sass::Script::Value::Color]
417
+ # @param $color [Color] The color whose opacity will be changed.
418
+ # @param $alpha [Number] The new opacity of the color. Must be between 0
419
+ # and 1 inclusive
420
+ # @return [Color]
675
421
  # @raise [ArgumentError] if `$alpha` is out of bounds or either parameter
676
422
  # is the wrong type
677
423
  def rgba(*args)
@@ -682,6 +428,7 @@ module Sass::Script
682
428
  assert_type color, :Color, :color
683
429
  assert_type alpha, :Number, :alpha
684
430
 
431
+ Sass::Util.check_range('Alpha channel', 0..1, alpha)
685
432
  color.with(:alpha => alpha.value)
686
433
  when 4
687
434
  red, green, blue, alpha = args
@@ -693,44 +440,43 @@ module Sass::Script
693
440
  declare :rgba, [:red, :green, :blue, :alpha]
694
441
  declare :rgba, [:color, :alpha]
695
442
 
696
- # Creates a {Sass::Script::Value::Color Color} from hue, saturation, and
697
- # lightness values. Uses the algorithm from the [CSS3 spec][].
443
+ # Creates a {Color} from hue, saturation, and lightness values. Uses the
444
+ # algorithm from the [CSS3 spec][].
698
445
  #
699
446
  # [CSS3 spec]: http://www.w3.org/TR/css3-color/#hsl-color
700
447
  #
701
448
  # @see #hsla
702
449
  # @overload hsl($hue, $saturation, $lightness)
703
- # @param $hue [Sass::Script::Value::Number] The hue of the color. Should be
704
- # between 0 and 360 degrees, inclusive
705
- # @param $saturation [Sass::Script::Value::Number] The saturation of the
706
- # color. Must be between `0%` and `100%`, inclusive
707
- # @param $lightness [Sass::Script::Value::Number] The lightness of the
708
- # color. Must be between `0%` and `100%`, inclusive
709
- # @return [Sass::Script::Value::Color]
450
+ # @param $hue [Number] The hue of the color. Should be between 0 and 360
451
+ # degrees, inclusive
452
+ # @param $saturation [Number] The saturation of the color. Must be between
453
+ # `0%` and `100%`, inclusive
454
+ # @param $lightness [Number] The lightness of the color. Must be between
455
+ # `0%` and `100%`, inclusive
456
+ # @return [Color]
710
457
  # @raise [ArgumentError] if `$saturation` or `$lightness` are out of bounds
711
458
  # or any parameter is the wrong type
712
459
  def hsl(hue, saturation, lightness)
713
- hsla(hue, saturation, lightness, number(1))
460
+ hsla(hue, saturation, lightness, Number.new(1))
714
461
  end
715
462
  declare :hsl, [:hue, :saturation, :lightness]
716
463
 
717
- # Creates a {Sass::Script::Value::Color Color} from hue,
718
- # saturation, lightness, and alpha values. Uses the algorithm from
719
- # the [CSS3 spec][].
464
+ # Creates a {Color} from hue, saturation, lightness, and alpha
465
+ # values. Uses the algorithm from the [CSS3 spec][].
720
466
  #
721
467
  # [CSS3 spec]: http://www.w3.org/TR/css3-color/#hsl-color
722
468
  #
723
469
  # @see #hsl
724
470
  # @overload hsla($hue, $saturation, $lightness, $alpha)
725
- # @param $hue [Sass::Script::Value::Number] The hue of the color. Should be
726
- # between 0 and 360 degrees, inclusive
727
- # @param $saturation [Sass::Script::Value::Number] The saturation of the
728
- # color. Must be between `0%` and `100%`, inclusive
729
- # @param $lightness [Sass::Script::Value::Number] The lightness of the
730
- # color. Must be between `0%` and `100%`, inclusive
731
- # @param $alpha [Sass::Script::Value::Number] The opacity of the color. Must
732
- # be between 0 and 1, inclusive
733
- # @return [Sass::Script::Value::Color]
471
+ # @param $hue [Number] The hue of the color. Should be between 0 and 360
472
+ # degrees, inclusive
473
+ # @param $saturation [Number] The saturation of the color. Must be between
474
+ # `0%` and `100%`, inclusive
475
+ # @param $lightness [Number] The lightness of the color. Must be between
476
+ # `0%` and `100%`, inclusive
477
+ # @param $alpha [Number] The opacity of the color. Must be between 0 and 1,
478
+ # inclusive
479
+ # @return [Color]
734
480
  # @raise [ArgumentError] if `$saturation`, `$lightness`, or `$alpha` are out
735
481
  # of bounds or any parameter is the wrong type
736
482
  def hsla(hue, saturation, lightness, alpha)
@@ -739,15 +485,13 @@ module Sass::Script
739
485
  assert_type lightness, :Number, :lightness
740
486
  assert_type alpha, :Number, :alpha
741
487
 
488
+ Sass::Util.check_range('Alpha channel', 0..1, alpha)
489
+
742
490
  h = hue.value
743
- s = saturation.value
744
- l = lightness.value
745
-
746
- # Don't store the string representation for function-created colors, both
747
- # because it's not very useful and because some functions aren't supported
748
- # on older browsers.
749
- Sass::Script::Value::Color.new(
750
- :hue => h, :saturation => s, :lightness => l, :alpha => alpha.value)
491
+ s = Sass::Util.check_range('Saturation', 0..100, saturation, '%')
492
+ l = Sass::Util.check_range('Lightness', 0..100, lightness, '%')
493
+
494
+ Color.new(:hue => h, :saturation => s, :lightness => l, :alpha => alpha.value)
751
495
  end
752
496
  declare :hsla, [:hue, :saturation, :lightness, :alpha]
753
497
 
@@ -757,13 +501,12 @@ module Sass::Script
757
501
  # [hsl-to-rgb]: http://www.w3.org/TR/css3-color/#hsl-color
758
502
  #
759
503
  # @overload red($color)
760
- # @param $color [Sass::Script::Value::Color]
761
- # @return [Sass::Script::Value::Number] The red component, between 0 and 255
762
- # inclusive
504
+ # @param $color [Color]
505
+ # @return [Number] The red component, between 0 and 255 inclusive
763
506
  # @raise [ArgumentError] if `$color` isn't a color
764
507
  def red(color)
765
508
  assert_type color, :Color, :color
766
- number(color.red)
509
+ Sass::Script::Number.new(color.red)
767
510
  end
768
511
  declare :red, [:color]
769
512
 
@@ -773,13 +516,12 @@ module Sass::Script
773
516
  # [hsl-to-rgb]: http://www.w3.org/TR/css3-color/#hsl-color
774
517
  #
775
518
  # @overload green($color)
776
- # @param $color [Sass::Script::Value::Color]
777
- # @return [Sass::Script::Value::Number] The green component, between 0 and
778
- # 255 inclusive
519
+ # @param $color [Color]
520
+ # @return [Number] The green component, between 0 and 255 inclusive
779
521
  # @raise [ArgumentError] if `$color` isn't a color
780
522
  def green(color)
781
523
  assert_type color, :Color, :color
782
- number(color.green)
524
+ Sass::Script::Number.new(color.green)
783
525
  end
784
526
  declare :green, [:color]
785
527
 
@@ -789,13 +531,12 @@ module Sass::Script
789
531
  # [hsl-to-rgb]: http://www.w3.org/TR/css3-color/#hsl-color
790
532
  #
791
533
  # @overload blue($color)
792
- # @param $color [Sass::Script::Value::Color]
793
- # @return [Sass::Script::Value::Number] The blue component, between 0 and
794
- # 255 inclusive
534
+ # @param $color [Color]
535
+ # @return [Number] The blue component, between 0 and 255 inclusive
795
536
  # @raise [ArgumentError] if `$color` isn't a color
796
537
  def blue(color)
797
538
  assert_type color, :Color, :color
798
- number(color.blue)
539
+ Sass::Script::Number.new(color.blue)
799
540
  end
800
541
  declare :blue, [:color]
801
542
 
@@ -807,13 +548,12 @@ module Sass::Script
807
548
  # [rgb-to-hsl]: http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
808
549
  #
809
550
  # @overload hue($color)
810
- # @param $color [Sass::Script::Value::Color]
811
- # @return [Sass::Script::Value::Number] The hue component, between 0deg and
812
- # 360deg
551
+ # @param $color [Color]
552
+ # @return [Number] The hue component, between 0deg and 360deg
813
553
  # @raise [ArgumentError] if `$color` isn't a color
814
554
  def hue(color)
815
555
  assert_type color, :Color, :color
816
- number(color.hue, "deg")
556
+ Sass::Script::Number.new(color.hue, ["deg"])
817
557
  end
818
558
  declare :hue, [:color]
819
559
 
@@ -825,13 +565,12 @@ module Sass::Script
825
565
  # [rgb-to-hsl]: http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
826
566
  #
827
567
  # @overload saturation($color)
828
- # @param $color [Sass::Script::Value::Color]
829
- # @return [Sass::Script::Value::Number] The saturation component, between 0%
830
- # and 100%
568
+ # @param $color [Color]
569
+ # @return [Number] The saturation component, between 0% and 100%
831
570
  # @raise [ArgumentError] if `$color` isn't a color
832
571
  def saturation(color)
833
572
  assert_type color, :Color, :color
834
- number(color.saturation, "%")
573
+ Sass::Script::Number.new(color.saturation, ["%"])
835
574
  end
836
575
  declare :saturation, [:color]
837
576
 
@@ -843,13 +582,12 @@ module Sass::Script
843
582
  # [rgb-to-hsl]: http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
844
583
  #
845
584
  # @overload lightness($color)
846
- # @param $color [Sass::Script::Value::Color]
847
- # @return [Sass::Script::Value::Number] The lightness component, between 0%
848
- # and 100%
585
+ # @param $color [Color]
586
+ # @return [Number] The lightness component, between 0% and 100%
849
587
  # @raise [ArgumentError] if `$color` isn't a color
850
588
  def lightness(color)
851
589
  assert_type color, :Color, :color
852
- number(color.lightness, "%")
590
+ Sass::Script::Number.new(color.lightness, ["%"])
853
591
  end
854
592
  declare :lightness, [:color]
855
593
 
@@ -860,22 +598,22 @@ module Sass::Script
860
598
  # syntax as a special case.
861
599
  #
862
600
  # @overload alpha($color)
863
- # @param $color [Sass::Script::Value::Color]
864
- # @return [Sass::Script::Value::Number] The alpha component, between 0 and 1
601
+ # @param $color [Color]
602
+ # @return [Number] The alpha component, between 0 and 1
865
603
  # @raise [ArgumentError] if `$color` isn't a color
866
604
  def alpha(*args)
867
605
  if args.all? do |a|
868
- a.is_a?(Sass::Script::Value::String) && a.type == :identifier &&
869
- a.value =~ /^[a-zA-Z]+\s*=/
870
- end
606
+ a.is_a?(Sass::Script::String) && a.type == :identifier &&
607
+ a.value =~ /^[a-zA-Z]+\s*=/
608
+ end
871
609
  # Support the proprietary MS alpha() function
872
- return identifier("alpha(#{args.map {|a| a.to_s}.join(", ")})")
610
+ return Sass::Script::String.new("alpha(#{args.map {|a| a.to_s}.join(", ")})")
873
611
  end
874
612
 
875
613
  raise ArgumentError.new("wrong number of arguments (#{args.size} for 1)") if args.size != 1
876
614
 
877
615
  assert_type args.first, :Color, :color
878
- number(args.first.alpha)
616
+ Sass::Script::Number.new(args.first.alpha)
879
617
  end
880
618
  declare :alpha, [:color]
881
619
 
@@ -883,15 +621,13 @@ module Sass::Script
883
621
  # otherwise specified.
884
622
  #
885
623
  # @overload opacity($color)
886
- # @param $color [Sass::Script::Value::Color]
887
- # @return [Sass::Script::Value::Number] The alpha component, between 0 and 1
624
+ # @param $color [Color]
625
+ # @return [Number] The alpha component, between 0 and 1
888
626
  # @raise [ArgumentError] if `$color` isn't a color
889
627
  def opacity(color)
890
- if color.is_a?(Sass::Script::Value::Number)
891
- return identifier("opacity(#{color})")
892
- end
628
+ return Sass::Script::String.new("opacity(#{color})") if color.is_a?(Sass::Script::Number)
893
629
  assert_type color, :Color, :color
894
- number(color.alpha)
630
+ Sass::Script::Number.new(color.alpha)
895
631
  end
896
632
  declare :opacity, [:color]
897
633
 
@@ -903,10 +639,10 @@ module Sass::Script
903
639
  # opacify(rgba(0, 0, 0, 0.5), 0.1) => rgba(0, 0, 0, 0.6)
904
640
  # opacify(rgba(0, 0, 17, 0.8), 0.2) => #001
905
641
  # @overload opacify($color, $amount)
906
- # @param $color [Sass::Script::Value::Color]
907
- # @param $amount [Sass::Script::Value::Number] The amount to increase the
908
- # opacity by, between 0 and 1
909
- # @return [Sass::Script::Value::Color]
642
+ # @param $color [Color]
643
+ # @param $amount [Number] The amount to increase the opacity by, between 0
644
+ # and 1
645
+ # @return [Color]
910
646
  # @raise [ArgumentError] if `$amount` is out of bounds, or either parameter
911
647
  # is the wrong type
912
648
  def opacify(color, amount)
@@ -925,10 +661,10 @@ module Sass::Script
925
661
  # transparentize(rgba(0, 0, 0, 0.5), 0.1) => rgba(0, 0, 0, 0.4)
926
662
  # transparentize(rgba(0, 0, 0, 0.8), 0.2) => rgba(0, 0, 0, 0.6)
927
663
  # @overload transparentize($color, $amount)
928
- # @param $color [Sass::Script::Value::Color]
929
- # @param $amount [Sass::Script::Value::Number] The amount to decrease the
930
- # opacity by, between 0 and 1
931
- # @return [Sass::Script::Value::Color]
664
+ # @param $color [Color]
665
+ # @param $amount [Number] The amount to decrease the opacity by, between 0
666
+ # and 1
667
+ # @return [Color]
932
668
  # @raise [ArgumentError] if `$amount` is out of bounds, or either parameter
933
669
  # is the wrong type
934
670
  def transparentize(color, amount)
@@ -947,10 +683,10 @@ module Sass::Script
947
683
  # lighten(hsl(0, 0%, 0%), 30%) => hsl(0, 0, 30)
948
684
  # lighten(#800, 20%) => #e00
949
685
  # @overload lighten($color, $amount)
950
- # @param $color [Sass::Script::Value::Color]
951
- # @param $amount [Sass::Script::Value::Number] The amount to increase the
952
- # lightness by, between `0%` and `100%`
953
- # @return [Sass::Script::Value::Color]
686
+ # @param $color [Color]
687
+ # @param $amount [Number] The amount to increase the lightness by, between
688
+ # `0%` and `100%`
689
+ # @return [Color]
954
690
  # @raise [ArgumentError] if `$amount` is out of bounds, or either parameter
955
691
  # is the wrong type
956
692
  def lighten(color, amount)
@@ -966,10 +702,10 @@ module Sass::Script
966
702
  # darken(hsl(25, 100%, 80%), 30%) => hsl(25, 100%, 50%)
967
703
  # darken(#800, 20%) => #200
968
704
  # @overload darken($color, $amount)
969
- # @param $color [Sass::Script::Value::Color]
970
- # @param $amount [Sass::Script::Value::Number] The amount to decrease the
971
- # lightness by, between `0%` and `100%`
972
- # @return [Sass::Script::Value::Color]
705
+ # @param $color [Color]
706
+ # @param $amount [Number] The amount to dencrease the lightness by, between
707
+ # `0%` and `100%`
708
+ # @return [Color]
973
709
  # @raise [ArgumentError] if `$amount` is out of bounds, or either parameter
974
710
  # is the wrong type
975
711
  def darken(color, amount)
@@ -985,16 +721,16 @@ module Sass::Script
985
721
  # saturate(hsl(120, 30%, 90%), 20%) => hsl(120, 50%, 90%)
986
722
  # saturate(#855, 20%) => #9e3f3f
987
723
  # @overload saturate($color, $amount)
988
- # @param $color [Sass::Script::Value::Color]
989
- # @param $amount [Sass::Script::Value::Number] The amount to increase the
990
- # saturation by, between `0%` and `100%`
991
- # @return [Sass::Script::Value::Color]
724
+ # @param $color [Color]
725
+ # @param $amount [Number] The amount to increase the saturation by, between
726
+ # `0%` and `100%`
727
+ # @return [Color]
992
728
  # @raise [ArgumentError] if `$amount` is out of bounds, or either parameter
993
729
  # is the wrong type
994
730
  def saturate(color, amount = nil)
995
731
  # Support the filter effects definition of saturate.
996
732
  # https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
997
- return identifier("saturate(#{color})") if amount.nil?
733
+ return Sass::Script::String.new("saturate(#{color})") if amount.nil?
998
734
  _adjust(color, amount, :saturation, 0..100, :+, "%")
999
735
  end
1000
736
  declare :saturate, [:color, :amount]
@@ -1008,10 +744,10 @@ module Sass::Script
1008
744
  # desaturate(hsl(120, 30%, 90%), 20%) => hsl(120, 10%, 90%)
1009
745
  # desaturate(#855, 20%) => #726b6b
1010
746
  # @overload desaturate($color, $amount)
1011
- # @param $color [Sass::Script::Value::Color]
1012
- # @param $amount [Sass::Script::Value::Number] The amount to decrease the
1013
- # saturation by, between `0%` and `100%`
1014
- # @return [Sass::Script::Value::Color]
747
+ # @param $color [Color]
748
+ # @param $amount [Number] The amount to decrease the saturation by, between
749
+ # `0%` and `100%`
750
+ # @return [Color]
1015
751
  # @raise [ArgumentError] if `$amount` is out of bounds, or either parameter
1016
752
  # is the wrong type
1017
753
  def desaturate(color, amount)
@@ -1025,13 +761,12 @@ module Sass::Script
1025
761
  #
1026
762
  # @example
1027
763
  # adjust-hue(hsl(120, 30%, 90%), 60deg) => hsl(180, 30%, 90%)
1028
- # adjust-hue(hsl(120, 30%, 90%), -60deg) => hsl(60, 30%, 90%)
764
+ # adjust-hue(hsl(120, 30%, 90%), 060deg) => hsl(60, 30%, 90%)
1029
765
  # adjust-hue(#811, 45deg) => #886a11
1030
766
  # @overload adjust_hue($color, $degrees)
1031
- # @param $color [Sass::Script::Value::Color]
1032
- # @param $degrees [Sass::Script::Value::Number] The number of degrees to
1033
- # rotate the hue
1034
- # @return [Sass::Script::Value::Color]
767
+ # @param $color [Color]
768
+ # @param $degrees [Number] The number of degrees to rotate the hue
769
+ # @return [Color]
1035
770
  # @raise [ArgumentError] if either parameter is the wrong type
1036
771
  def adjust_hue(color, degrees)
1037
772
  assert_type color, :Color, :color
@@ -1047,14 +782,13 @@ module Sass::Script
1047
782
  # ie-hex-str(#3322BB) => #FF3322BB
1048
783
  # ie-hex-str(rgba(0, 255, 0, 0.5)) => #8000FF00
1049
784
  # @overload ie_hex_str($color)
1050
- # @param $color [Sass::Script::Value::Color]
1051
- # @return [Sass::Script::Value::String] The IE-formatted string
1052
- # representation of the color
785
+ # @param $color [Color]
786
+ # @return [String] The IE-formatted string representation of the color
1053
787
  # @raise [ArgumentError] if `$color` isn't a color
1054
788
  def ie_hex_str(color)
1055
789
  assert_type color, :Color, :color
1056
790
  alpha = (color.alpha * 255).round.to_s(16).rjust(2, '0')
1057
- identifier("##{alpha}#{color.send(:hex_str)[1..-1]}".upcase)
791
+ Sass::Script::String.new("##{alpha}#{color.send(:hex_str)[1..-1]}".upcase)
1058
792
  end
1059
793
  declare :ie_hex_str, [:color]
1060
794
 
@@ -1071,33 +805,29 @@ module Sass::Script
1071
805
  # adjust-color(#102030, $blue: 5) => #102035
1072
806
  # adjust-color(#102030, $red: -5, $blue: 5) => #0b2035
1073
807
  # adjust-color(hsl(25, 100%, 80%), $lightness: -30%, $alpha: -0.4) => hsla(25, 100%, 50%, 0.6)
1074
- # @comment
1075
- # rubocop:disable LineLength
1076
808
  # @overload adjust_color($color, [$red], [$green], [$blue], [$hue], [$saturation], [$lightness], [$alpha])
1077
- # @comment
1078
- # rubocop:disable LineLength
1079
- # @param $color [Sass::Script::Value::Color]
1080
- # @param $red [Sass::Script::Value::Number] The adjustment to make on the
1081
- # red component, between -255 and 255 inclusive
1082
- # @param $green [Sass::Script::Value::Number] The adjustment to make on the
1083
- # green component, between -255 and 255 inclusive
1084
- # @param $blue [Sass::Script::Value::Number] The adjustment to make on the
1085
- # blue component, between -255 and 255 inclusive
1086
- # @param $hue [Sass::Script::Value::Number] The adjustment to make on the
1087
- # hue component, in degrees
1088
- # @param $saturation [Sass::Script::Value::Number] The adjustment to make on
1089
- # the saturation component, between `-100%` and `100%` inclusive
1090
- # @param $lightness [Sass::Script::Value::Number] The adjustment to make on
1091
- # the lightness component, between `-100%` and `100%` inclusive
1092
- # @param $alpha [Sass::Script::Value::Number] The adjustment to make on the
1093
- # alpha component, between -1 and 1 inclusive
1094
- # @return [Sass::Script::Value::Color]
809
+ # @param $color [Color]
810
+ # @param $red [Number] The adjustment to make on the red component, between
811
+ # -255 and 255 inclusive
812
+ # @param $green [Number] The adjustment to make on the green component,
813
+ # between -255 and 255 inclusive
814
+ # @param $blue [Number] The adjustment to make on the blue component, between
815
+ # -255 and 255 inclusive
816
+ # @param $hue [Number] The adjustment to make on the hue component, in
817
+ # degrees
818
+ # @param $saturation [Number] The adjustment to make on the saturation
819
+ # component, between `-100%` and `100%` inclusive
820
+ # @param $lightness [Number] The adjustment to make on the lightness
821
+ # component, between `-100%` and `100%` inclusive
822
+ # @param $alpha [Number] The adjustment to make on the alpha component,
823
+ # between -1 and 1 inclusive
824
+ # @return [Color]
1095
825
  # @raise [ArgumentError] if any parameter is the wrong type or out-of
1096
826
  # bounds, or if RGB properties and HSL properties are adjusted at the
1097
827
  # same time
1098
828
  def adjust_color(color, kwargs)
1099
829
  assert_type color, :Color, :color
1100
- with = Sass::Util.map_hash(
830
+ with = Sass::Util.map_hash({
1101
831
  "red" => [-255..255, ""],
1102
832
  "green" => [-255..255, ""],
1103
833
  "blue" => [-255..255, ""],
@@ -1105,10 +835,9 @@ module Sass::Script
1105
835
  "saturation" => [-100..100, "%"],
1106
836
  "lightness" => [-100..100, "%"],
1107
837
  "alpha" => [-1..1, ""]
1108
- ) do |name, (range, units)|
838
+ }) do |name, (range, units)|
1109
839
 
1110
- val = kwargs.delete(name)
1111
- next unless val
840
+ next unless val = kwargs.delete(name)
1112
841
  assert_type val, :Number, name
1113
842
  Sass::Util.check_range("$#{name}: Amount", range, val, units) if range
1114
843
  adjusted = color.send(name) + val.value
@@ -1152,43 +881,41 @@ module Sass::Script
1152
881
  # scale-color(hsl(120, 70%, 80%), $lightness: 50%) => hsl(120, 70%, 90%)
1153
882
  # scale-color(rgb(200, 150%, 170%), $green: -40%, $blue: 70%) => rgb(200, 90, 229)
1154
883
  # scale-color(hsl(200, 70%, 80%), $saturation: -90%, $alpha: -30%) => hsla(200, 7%, 80%, 0.7)
1155
- # @comment
1156
- # rubocop:disable LineLength
1157
884
  # @overload scale_color($color, [$red], [$green], [$blue], [$saturation], [$lightness], [$alpha])
1158
- # @comment
1159
- # rubocop:disable LineLength
1160
- # @param $color [Sass::Script::Value::Color]
1161
- # @param $red [Sass::Script::Value::Number]
1162
- # @param $green [Sass::Script::Value::Number]
1163
- # @param $blue [Sass::Script::Value::Number]
1164
- # @param $saturation [Sass::Script::Value::Number]
1165
- # @param $lightness [Sass::Script::Value::Number]
1166
- # @param $alpha [Sass::Script::Value::Number]
1167
- # @return [Sass::Script::Value::Color]
885
+ # @param $color [Color]
886
+ # @param $red [Number]
887
+ # @param $green [Number]
888
+ # @param $blue [Number]
889
+ # @param $saturation [Number]
890
+ # @param $lightness [Number]
891
+ # @param $alpha [Number]
892
+ # @return [Color]
1168
893
  # @raise [ArgumentError] if any parameter is the wrong type or out-of
1169
894
  # bounds, or if RGB properties and HSL properties are adjusted at the
1170
895
  # same time
1171
896
  def scale_color(color, kwargs)
1172
897
  assert_type color, :Color, :color
1173
- with = Sass::Util.map_hash(
898
+ with = Sass::Util.map_hash({
1174
899
  "red" => 255,
1175
900
  "green" => 255,
1176
901
  "blue" => 255,
1177
902
  "saturation" => 100,
1178
903
  "lightness" => 100,
1179
904
  "alpha" => 1
1180
- ) do |name, max|
905
+ }) do |name, max|
1181
906
 
1182
- val = kwargs.delete(name)
1183
- next unless val
907
+ next unless val = kwargs.delete(name)
1184
908
  assert_type val, :Number, name
1185
- assert_unit val, '%', name
1186
- Sass::Util.check_range("$#{name}: Amount", -100..100, val, '%')
909
+ if !(val.numerator_units == ['%'] && val.denominator_units.empty?)
910
+ raise ArgumentError.new("$#{name}: Amount #{val} must be a % (e.g. #{val.value}%)")
911
+ else
912
+ Sass::Util.check_range("$#{name}: Amount", -100..100, val, '%')
913
+ end
1187
914
 
1188
915
  current = color.send(name)
1189
- scale = val.value / 100.0
916
+ scale = val.value/100.0
1190
917
  diff = scale > 0 ? max - current : current
1191
- [name.to_sym, current + diff * scale]
918
+ [name.to_sym, current + diff*scale]
1192
919
  end
1193
920
 
1194
921
  unless kwargs.empty?
@@ -1213,52 +940,31 @@ module Sass::Script
1213
940
  # change-color(#102030, $blue: 5) => #102005
1214
941
  # change-color(#102030, $red: 120, $blue: 5) => #782005
1215
942
  # change-color(hsl(25, 100%, 80%), $lightness: 40%, $alpha: 0.8) => hsla(25, 100%, 40%, 0.8)
1216
- # @comment
1217
- # rubocop:disable LineLength
1218
943
  # @overload change_color($color, [$red], [$green], [$blue], [$hue], [$saturation], [$lightness], [$alpha])
1219
- # @comment
1220
- # rubocop:disable LineLength
1221
- # @param $color [Sass::Script::Value::Color]
1222
- # @param $red [Sass::Script::Value::Number] The new red component for the
1223
- # color, within 0 and 255 inclusive
1224
- # @param $green [Sass::Script::Value::Number] The new green component for
1225
- # the color, within 0 and 255 inclusive
1226
- # @param $blue [Sass::Script::Value::Number] The new blue component for the
1227
- # color, within 0 and 255 inclusive
1228
- # @param $hue [Sass::Script::Value::Number] The new hue component for the
1229
- # color, in degrees
1230
- # @param $saturation [Sass::Script::Value::Number] The new saturation
1231
- # component for the color, between `0%` and `100%` inclusive
1232
- # @param $lightness [Sass::Script::Value::Number] The new lightness
1233
- # component for the color, within `0%` and `100%` inclusive
1234
- # @param $alpha [Sass::Script::Value::Number] The new alpha component for
1235
- # the color, within 0 and 1 inclusive
1236
- # @return [Sass::Script::Value::Color]
944
+ # @param $color [Color]
945
+ # @param $red [Number] The new red component for the color, within 0 and 255
946
+ # inclusive
947
+ # @param $green [Number] The new green component for the color, within 0 and
948
+ # 255 inclusive
949
+ # @param $blue [Number] The new blue component for the color, within 0 and
950
+ # 255 inclusive
951
+ # @param $hue [Number] The new hue component for the color, in degrees
952
+ # @param $saturation [Number] The new saturation component for the color,
953
+ # between `0%` and `100%` inclusive
954
+ # @param $lightness [Number] The new lightness component for the color,
955
+ # within `0%` and `100%` inclusive
956
+ # @param $alpha [Number] The new alpha component for the color, within 0 and
957
+ # 1 inclusive
958
+ # @return [Color]
1237
959
  # @raise [ArgumentError] if any parameter is the wrong type or out-of
1238
960
  # bounds, or if RGB properties and HSL properties are adjusted at the
1239
961
  # same time
1240
962
  def change_color(color, kwargs)
1241
963
  assert_type color, :Color, :color
1242
- with = Sass::Util.map_hash(
1243
- 'red' => ['Red value', 0..255],
1244
- 'green' => ['Green value', 0..255],
1245
- 'blue' => ['Blue value', 0..255],
1246
- 'hue' => [],
1247
- 'saturation' => ['Saturation', 0..100, '%'],
1248
- 'lightness' => ['Lightness', 0..100, '%'],
1249
- 'alpha' => ['Alpha channel', 0..1]
1250
- ) do |name, (desc, range, unit)|
1251
- val = kwargs.delete(name)
1252
- next unless val
964
+ with = Sass::Util.map_hash(%w[red green blue hue saturation lightness alpha]) do |name, max|
965
+ next unless val = kwargs.delete(name)
1253
966
  assert_type val, :Number, name
1254
-
1255
- if range
1256
- val = Sass::Util.check_range(desc, range, val, unit)
1257
- else
1258
- val = val.value
1259
- end
1260
-
1261
- [name.to_sym, val]
967
+ [name.to_sym, val.value]
1262
968
  end
1263
969
 
1264
970
  unless kwargs.empty?
@@ -1283,18 +989,18 @@ module Sass::Script
1283
989
  # mix(#f00, #00f) => #7f007f
1284
990
  # mix(#f00, #00f, 25%) => #3f00bf
1285
991
  # mix(rgba(255, 0, 0, 0.5), #00f) => rgba(63, 0, 191, 0.75)
1286
- # @overload mix($color1, $color2, $weight: 50%)
1287
- # @param $color1 [Sass::Script::Value::Color]
1288
- # @param $color2 [Sass::Script::Value::Color]
1289
- # @param $weight [Sass::Script::Value::Number] The relative weight of each
1290
- # color. Closer to `0%` gives more weight to `$color`, closer to `100%`
1291
- # gives more weight to `$color2`
1292
- # @return [Sass::Script::Value::Color]
992
+ # @overload mix($color-1, $color-2, $weight: 50%)
993
+ # @param $color-1 [Color]
994
+ # @param $color-2 [Color]
995
+ # @param $weight [Number] The relative weight of each color. Closer to `0%`
996
+ # gives more weight to `$color`, closer to `100%` gives more weight to
997
+ # `$color2`
998
+ # @return [Color]
1293
999
  # @raise [ArgumentError] if `$weight` is out of bounds or any parameter is
1294
1000
  # the wrong type
1295
- def mix(color1, color2, weight = number(50))
1296
- assert_type color1, :Color, :color1
1297
- assert_type color2, :Color, :color2
1001
+ def mix(color_1, color_2, weight = Number.new(50))
1002
+ assert_type color_1, :Color, :color_1
1003
+ assert_type color_2, :Color, :color_2
1298
1004
  assert_type weight, :Number, :weight
1299
1005
 
1300
1006
  Sass::Util.check_range("Weight", 0..100, weight, '%')
@@ -1304,11 +1010,11 @@ module Sass::Script
1304
1010
  # to perform the weighted average of the two RGB values.
1305
1011
  #
1306
1012
  # It works by first normalizing both parameters to be within [-1, 1],
1307
- # where 1 indicates "only use color1", -1 indicates "only use color2", and
1013
+ # where 1 indicates "only use color_1", -1 indicates "only use color_2", and
1308
1014
  # all values in between indicated a proportionately weighted average.
1309
1015
  #
1310
1016
  # Once we have the normalized variables w and a, we apply the formula
1311
- # (w + a)/(1 + w*a) to get the combined weight (in [-1, 1]) of color1.
1017
+ # (w + a)/(1 + w*a) to get the combined weight (in [-1, 1]) of color_1.
1312
1018
  # This formula has two especially nice properties:
1313
1019
  #
1314
1020
  # * When either w or a are -1 or 1, the combined weight is also that number
@@ -1316,35 +1022,33 @@ module Sass::Script
1316
1022
  #
1317
1023
  # * When a is 0, the combined weight is w, and vice versa.
1318
1024
  #
1319
- # Finally, the weight of color1 is renormalized to be within [0, 1]
1320
- # and the weight of color2 is given by 1 minus the weight of color1.
1321
- p = (weight.value / 100.0).to_f
1322
- w = p * 2 - 1
1323
- a = color1.alpha - color2.alpha
1025
+ # Finally, the weight of color_1 is renormalized to be within [0, 1]
1026
+ # and the weight of color_2 is given by 1 minus the weight of color_1.
1027
+ p = (weight.value/100.0).to_f
1028
+ w = p*2 - 1
1029
+ a = color_1.alpha - color_2.alpha
1324
1030
 
1325
- w1 = ((w * a == -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0
1031
+ w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0
1326
1032
  w2 = 1 - w1
1327
1033
 
1328
- rgba = color1.rgb.zip(color2.rgb).map {|v1, v2| v1 * w1 + v2 * w2}
1329
- rgba << color1.alpha * p + color2.alpha * (1 - p)
1330
- rgb_color(*rgba)
1034
+ rgb = color_1.rgb.zip(color_2.rgb).map {|v1, v2| v1*w1 + v2*w2}
1035
+ alpha = color_1.alpha*p + color_2.alpha*(1-p)
1036
+ Color.new(rgb + [alpha])
1331
1037
  end
1332
- declare :mix, [:color1, :color2]
1333
- declare :mix, [:color1, :color2, :weight]
1038
+ declare :mix, [:color_1, :color_2]
1039
+ declare :mix, [:color_1, :color_2, :weight]
1334
1040
 
1335
1041
  # Converts a color to grayscale. This is identical to `desaturate(color,
1336
1042
  # 100%)`.
1337
1043
  #
1338
1044
  # @see #desaturate
1339
1045
  # @overload grayscale($color)
1340
- # @param $color [Sass::Script::Value::Color]
1341
- # @return [Sass::Script::Value::Color]
1046
+ # @param $color [Color]
1047
+ # @return [Color]
1342
1048
  # @raise [ArgumentError] if `$color` isn't a color
1343
1049
  def grayscale(color)
1344
- if color.is_a?(Sass::Script::Value::Number)
1345
- return identifier("grayscale(#{color})")
1346
- end
1347
- desaturate color, number(100)
1050
+ return Sass::Script::String.new("grayscale(#{color})") if color.is_a?(Sass::Script::Number)
1051
+ desaturate color, Number.new(100)
1348
1052
  end
1349
1053
  declare :grayscale, [:color]
1350
1054
 
@@ -1353,11 +1057,11 @@ module Sass::Script
1353
1057
  #
1354
1058
  # @see #adjust_hue #adjust-hue
1355
1059
  # @overload complement($color)
1356
- # @param $color [Sass::Script::Value::Color]
1357
- # @return [Sass::Script::Value::Color]
1060
+ # @param $color [Color]
1061
+ # @return [Color]
1358
1062
  # @raise [ArgumentError] if `$color` isn't a color
1359
1063
  def complement(color)
1360
- adjust_hue color, number(180)
1064
+ adjust_hue color, Number.new(180)
1361
1065
  end
1362
1066
  declare :complement, [:color]
1363
1067
 
@@ -1365,13 +1069,11 @@ module Sass::Script
1365
1069
  # are inverted, while the opacity is left alone.
1366
1070
  #
1367
1071
  # @overload invert($color)
1368
- # @param $color [Sass::Script::Value::Color]
1369
- # @return [Sass::Script::Value::Color]
1072
+ # @param $color [Color]
1073
+ # @return [Color]
1370
1074
  # @raise [ArgumentError] if `$color` isn't a color
1371
1075
  def invert(color)
1372
- if color.is_a?(Sass::Script::Value::Number)
1373
- return identifier("invert(#{color})")
1374
- end
1076
+ return Sass::Script::String.new("invert(#{color})") if color.is_a?(Sass::Script::Number)
1375
1077
 
1376
1078
  assert_type color, :Color, :color
1377
1079
  color.with(
@@ -1389,12 +1091,12 @@ module Sass::Script
1389
1091
  # unquote("foo") => foo
1390
1092
  # unquote(foo) => foo
1391
1093
  # @overload unquote($string)
1392
- # @param $string [Sass::Script::Value::String]
1393
- # @return [Sass::Script::Value::String]
1094
+ # @param $string [String]
1095
+ # @return [String]
1394
1096
  # @raise [ArgumentError] if `$string` isn't a string
1395
1097
  def unquote(string)
1396
- if string.is_a?(Sass::Script::Value::String) && string.type != :identifier
1397
- identifier(string.value)
1098
+ if string.is_a?(Sass::Script::String)
1099
+ Sass::Script::String.new(string.value, :identifier)
1398
1100
  else
1399
1101
  string
1400
1102
  end
@@ -1409,165 +1111,15 @@ module Sass::Script
1409
1111
  # quote("foo") => "foo"
1410
1112
  # quote(foo) => "foo"
1411
1113
  # @overload quote($string)
1412
- # @param $string [Sass::Script::Value::String]
1413
- # @return [Sass::Script::Value::String]
1114
+ # @param $string [String]
1115
+ # @return [String]
1414
1116
  # @raise [ArgumentError] if `$string` isn't a string
1415
1117
  def quote(string)
1416
1118
  assert_type string, :String, :string
1417
- if string.type != :string
1418
- quoted_string(string.value)
1419
- else
1420
- string
1421
- end
1119
+ Sass::Script::String.new(string.value, :string)
1422
1120
  end
1423
1121
  declare :quote, [:string]
1424
1122
 
1425
- # Returns the number of characters in a string.
1426
- #
1427
- # @example
1428
- # str-length("foo") => 3
1429
- # @overload str_length($string)
1430
- # @param $string [Sass::Script::Value::String]
1431
- # @return [Sass::Script::Value::Number]
1432
- # @raise [ArgumentError] if `$string` isn't a string
1433
- def str_length(string)
1434
- assert_type string, :String, :string
1435
- number(string.value.size)
1436
- end
1437
- declare :str_length, [:string]
1438
-
1439
- # Inserts `$insert` into `$string` at `$index`.
1440
- #
1441
- # Note that unlike some languages, the first character in a Sass string is
1442
- # number 1, the second number 2, and so forth.
1443
- #
1444
- # @example
1445
- # str-insert("abcd", "X", 1) => "Xabcd"
1446
- # str-insert("abcd", "X", 4) => "abcXd"
1447
- # str-insert("abcd", "X", 5) => "abcdX"
1448
- #
1449
- # @overload str_insert($string, $insert, $index)
1450
- # @param $string [Sass::Script::Value::String]
1451
- # @param $insert [Sass::Script::Value::String]
1452
- # @param $index [Sass::Script::Value::Number] The position at which
1453
- # `$insert` will be inserted. Negative indices count from the end of
1454
- # `$string`. An index that's outside the bounds of the string will insert
1455
- # `$insert` at the front or back of the string
1456
- # @return [Sass::Script::Value::String] The result string. This will be
1457
- # quoted if and only if `$string` was quoted
1458
- # @raise [ArgumentError] if any parameter is the wrong type
1459
- def str_insert(original, insert, index)
1460
- assert_type original, :String, :string
1461
- assert_type insert, :String, :insert
1462
- assert_integer index, :index
1463
- assert_unit index, nil, :index
1464
- insertion_point = if index.value > 0
1465
- [index.value - 1, original.value.size].min
1466
- else
1467
- [index.value, -original.value.size - 1].max
1468
- end
1469
- result = original.value.dup.insert(insertion_point, insert.value)
1470
- Sass::Script::Value::String.new(result, original.type)
1471
- end
1472
- declare :str_insert, [:string, :insert, :index]
1473
-
1474
- # Returns the index of the first occurrence of `$substring` in `$string`. If
1475
- # there is no such occurrence, returns `null`.
1476
- #
1477
- # Note that unlike some languages, the first character in a Sass string is
1478
- # number 1, the second number 2, and so forth.
1479
- #
1480
- # @example
1481
- # str-index(abcd, a) => 1
1482
- # str-index(abcd, ab) => 1
1483
- # str-index(abcd, X) => null
1484
- # str-index(abcd, c) => 3
1485
- #
1486
- # @overload str_index($string, $substring)
1487
- # @param $string [Sass::Script::Value::String]
1488
- # @param $substring [Sass::Script::Value::String]
1489
- # @return [Sass::Script::Value::Number, Sass::Script::Value::Null]
1490
- # @raise [ArgumentError] if any parameter is the wrong type
1491
- def str_index(string, substring)
1492
- assert_type string, :String, :string
1493
- assert_type substring, :String, :substring
1494
- index = string.value.index(substring.value)
1495
- index ? number(index + 1) : null
1496
- end
1497
- declare :str_index, [:string, :substring]
1498
-
1499
- # Extracts a substring from `$string`. The substring will begin at index
1500
- # `$start-at` and ends at index `$end-at`.
1501
- #
1502
- # Note that unlike some languages, the first character in a Sass string is
1503
- # number 1, the second number 2, and so forth.
1504
- #
1505
- # @example
1506
- # str-slice("abcd", 2, 3) => "bc"
1507
- # str-slice("abcd", 2) => "bcd"
1508
- # str-slice("abcd", -3, -2) => "bc"
1509
- # str-slice("abcd", 2, -2) => "bc"
1510
- #
1511
- # @overload str_slice($string, $start-at, $end-at: -1)
1512
- # @param $start-at [Sass::Script::Value::Number] The index of the first
1513
- # character of the substring. If this is negative, it counts from the end
1514
- # of `$string`
1515
- # @param $end-before [Sass::Script::Value::Number] The index of the last
1516
- # character of the substring. If this is negative, it counts from the end
1517
- # of `$string`. Defaults to -1
1518
- # @return [Sass::Script::Value::String] The substring. This will be quoted
1519
- # if and only if `$string` was quoted
1520
- # @raise [ArgumentError] if any parameter is the wrong type
1521
- def str_slice(string, start_at, end_at = nil)
1522
- assert_type string, :String, :string
1523
- assert_unit start_at, nil, "start-at"
1524
-
1525
- end_at = number(-1) if end_at.nil?
1526
- assert_unit end_at, nil, "end-at"
1527
-
1528
- return Sass::Script::Value::String.new("", string.type) if end_at.value == 0
1529
- s = start_at.value > 0 ? start_at.value - 1 : start_at.value
1530
- e = end_at.value > 0 ? end_at.value - 1 : end_at.value
1531
- s = string.value.length + s if s < 0
1532
- s = 0 if s < 0
1533
- e = string.value.length + e if e < 0
1534
- e = 0 if s < 0
1535
- extracted = string.value.slice(s..e)
1536
- Sass::Script::Value::String.new(extracted || "", string.type)
1537
- end
1538
- declare :str_slice, [:string, :start_at]
1539
- declare :str_slice, [:string, :start_at, :end_at]
1540
-
1541
- # Converts a string to upper case.
1542
- #
1543
- # @example
1544
- # to-upper-case(abcd) => ABCD
1545
- #
1546
- # @overload to_upper_case($string)
1547
- # @param $string [Sass::Script::Value::String]
1548
- # @return [Sass::Script::Value::String]
1549
- # @raise [ArgumentError] if `$string` isn't a string
1550
- def to_upper_case(string)
1551
- assert_type string, :String, :string
1552
- Sass::Script::Value::String.new(string.value.upcase, string.type)
1553
- end
1554
- declare :to_upper_case, [:string]
1555
-
1556
- # Convert a string to lower case,
1557
- #
1558
- # @example
1559
- # to-lower-case(ABCD) => abcd
1560
- #
1561
- # @overload to_lower_case($string)
1562
- # @param $string [Sass::Script::Value::String]
1563
- # @return [Sass::Script::Value::String]
1564
- # @raise [ArgumentError] if `$string` isn't a string
1565
- def to_lower_case(string)
1566
- assert_type string, :String, :string
1567
- Sass::Script::Value::String.new(string.value.downcase, string.type)
1568
- end
1569
- declare :to_lower_case, [:string]
1570
-
1571
1123
  # Returns the type of a value.
1572
1124
  #
1573
1125
  # @example
@@ -1578,45 +1130,13 @@ module Sass::Script
1578
1130
  # type-of(#fff) => color
1579
1131
  # type-of(blue) => color
1580
1132
  # @overload type_of($value)
1581
- # @param $value [Sass::Script::Value::Base] The value to inspect
1582
- # @return [Sass::Script::Value::String] The unquoted string name of the
1583
- # value's type
1133
+ # @param $value [Literal] The value to inspect
1134
+ # @return [String] The unquoted string name of the value's type
1584
1135
  def type_of(value)
1585
- identifier(value.class.name.gsub(/Sass::Script::Value::/, '').downcase)
1136
+ Sass::Script::String.new(value.class.name.gsub(/Sass::Script::/,'').downcase)
1586
1137
  end
1587
1138
  declare :type_of, [:value]
1588
1139
 
1589
- # Returns whether a feature exists in the current Sass runtime.
1590
- #
1591
- # The following features are supported:
1592
- #
1593
- # * `global-variable-shadowing` indicates that a local variable will shadow
1594
- # a global variable unless `!global` is used.
1595
- #
1596
- # * `extend-selector-pseudoclass` indicates that `@extend` will reach into
1597
- # selector pseudoclasses like `:not`.
1598
- #
1599
- # * `units-level-3` indicates full support for unit arithmetic using units
1600
- # defined in the [Values and Units Level 3][] spec.
1601
- #
1602
- # [Values and Units Level 3]: http://www.w3.org/TR/css3-values/
1603
- #
1604
- # * `at-error` indicates that the Sass `@error` directive is supported.
1605
- #
1606
- # @example
1607
- # feature-exists(some-feature-that-exists) => true
1608
- # feature-exists(what-is-this-i-dont-know) => false
1609
- #
1610
- # @overload feature_exists($feature)
1611
- # @param $feature [Sass::Script::Value::String] The name of the feature
1612
- # @return [Sass::Script::Value::Bool] Whether the feature is supported in this version of Sass
1613
- # @raise [ArgumentError] if `$feature` isn't a string
1614
- def feature_exists(feature)
1615
- assert_type feature, :String, :feature
1616
- bool(Sass.has_feature?(feature.value))
1617
- end
1618
- declare :feature_exists, [:feature]
1619
-
1620
1140
  # Returns the unit(s) associated with a number. Complex units are sorted in
1621
1141
  # alphabetical order by numerator and denominator.
1622
1142
  #
@@ -1627,13 +1147,12 @@ module Sass::Script
1627
1147
  # unit(10px * 5em) => "em*px"
1628
1148
  # unit(10px * 5em / 30cm / 1rem) => "em*px/cm*rem"
1629
1149
  # @overload unit($number)
1630
- # @param $number [Sass::Script::Value::Number]
1631
- # @return [Sass::Script::Value::String] The unit(s) of the number, as a
1632
- # quoted string
1150
+ # @param $number [Number]
1151
+ # @return [String] The unit(s) of the number, as a quoted string
1633
1152
  # @raise [ArgumentError] if `$number` isn't a number
1634
1153
  def unit(number)
1635
1154
  assert_type number, :Number, :number
1636
- quoted_string(number.unit_str)
1155
+ Sass::Script::String.new(number.unit_str, :string)
1637
1156
  end
1638
1157
  declare :unit, [:number]
1639
1158
 
@@ -1643,12 +1162,12 @@ module Sass::Script
1643
1162
  # unitless(100) => true
1644
1163
  # unitless(100px) => false
1645
1164
  # @overload unitless($number)
1646
- # @param $number [Sass::Script::Value::Number]
1647
- # @return [Sass::Script::Value::Bool]
1165
+ # @param $number [Number]
1166
+ # @return [Bool]
1648
1167
  # @raise [ArgumentError] if `$number` isn't a number
1649
1168
  def unitless(number)
1650
1169
  assert_type number, :Number, :number
1651
- bool(number.unitless?)
1170
+ Sass::Script::Bool.new(number.unitless?)
1652
1171
  end
1653
1172
  declare :unitless, [:number]
1654
1173
 
@@ -1658,90 +1177,90 @@ module Sass::Script
1658
1177
  # comparable(2px, 1px) => true
1659
1178
  # comparable(100px, 3em) => false
1660
1179
  # comparable(10cm, 3mm) => true
1661
- # @overload comparable($number1, $number2)
1662
- # @param $number1 [Sass::Script::Value::Number]
1663
- # @param $number2 [Sass::Script::Value::Number]
1664
- # @return [Sass::Script::Value::Bool]
1180
+ # @overload comparable($number-1, $number-2)
1181
+ # @param $number-1 [Number]
1182
+ # @param $number-2 [Number]
1183
+ # @return [Bool]
1665
1184
  # @raise [ArgumentError] if either parameter is the wrong type
1666
- def comparable(number1, number2)
1667
- assert_type number1, :Number, :number1
1668
- assert_type number2, :Number, :number2
1669
- bool(number1.comparable_to?(number2))
1185
+ def comparable(number_1, number_2)
1186
+ assert_type number_1, :Number, :number_1
1187
+ assert_type number_2, :Number, :number_2
1188
+ Sass::Script::Bool.new(number_1.comparable_to?(number_2))
1670
1189
  end
1671
- declare :comparable, [:number1, :number2]
1190
+ declare :comparable, [:number_1, :number_2]
1672
1191
 
1673
1192
  # Converts a unitless number to a percentage.
1674
1193
  #
1675
1194
  # @example
1676
1195
  # percentage(0.2) => 20%
1677
1196
  # percentage(100px / 50px) => 200%
1678
- # @overload percentage($number)
1679
- # @param $number [Sass::Script::Value::Number]
1680
- # @return [Sass::Script::Value::Number]
1681
- # @raise [ArgumentError] if `$number` isn't a unitless number
1682
- def percentage(number)
1683
- unless number.is_a?(Sass::Script::Value::Number) && number.unitless?
1684
- raise ArgumentError.new("$number: #{number.inspect} is not a unitless number")
1197
+ # @overload percentage($value)
1198
+ # @param $value [Number]
1199
+ # @return [Number]
1200
+ # @raise [ArgumentError] if `$value` isn't a unitless number
1201
+ def percentage(value)
1202
+ unless value.is_a?(Sass::Script::Number) && value.unitless?
1203
+ raise ArgumentError.new("$value: #{value.inspect} is not a unitless number")
1685
1204
  end
1686
- number(number.value * 100, '%')
1205
+ Sass::Script::Number.new(value.value * 100, ['%'])
1687
1206
  end
1688
- declare :percentage, [:number]
1207
+ declare :percentage, [:value]
1689
1208
 
1690
1209
  # Rounds a number to the nearest whole number.
1691
1210
  #
1692
1211
  # @example
1693
1212
  # round(10.4px) => 10px
1694
1213
  # round(10.6px) => 11px
1695
- # @overload round($number)
1696
- # @param $number [Sass::Script::Value::Number]
1697
- # @return [Sass::Script::Value::Number]
1698
- # @raise [ArgumentError] if `$number` isn't a number
1699
- def round(number)
1700
- numeric_transformation(number) {|n| n.round}
1214
+ # @overload round($value)
1215
+ # @param $value [Number]
1216
+ # @return [Number]
1217
+ # @raise [ArgumentError] if `$value` isn't a number
1218
+ def round(value)
1219
+ numeric_transformation(value) {|n| n.round}
1701
1220
  end
1702
- declare :round, [:number]
1221
+ declare :round, [:value]
1703
1222
 
1704
1223
  # Rounds a number up to the next whole number.
1705
1224
  #
1706
1225
  # @example
1707
1226
  # ceil(10.4px) => 11px
1708
1227
  # ceil(10.6px) => 11px
1709
- # @overload ceil($number)
1710
- # @param $number [Sass::Script::Value::Number]
1711
- # @return [Sass::Script::Value::Number]
1712
- # @raise [ArgumentError] if `$number` isn't a number
1713
- def ceil(number)
1714
- numeric_transformation(number) {|n| n.ceil}
1228
+ # @overload ceil($value)
1229
+ # @param $value [Number]
1230
+ # @return [Number]
1231
+ # @raise [ArgumentError] if `$value` isn't a number
1232
+ def ceil(value)
1233
+ numeric_transformation(value) {|n| n.ceil}
1715
1234
  end
1716
- declare :ceil, [:number]
1235
+ declare :ceil, [:value]
1717
1236
 
1718
1237
  # Rounds a number down to the previous whole number.
1719
1238
  #
1720
1239
  # @example
1721
1240
  # floor(10.4px) => 10px
1722
1241
  # floor(10.6px) => 10px
1723
- # @overload floor($number)
1724
- # @param $number [Sass::Script::Value::Number]
1725
- # @return [Sass::Script::Value::Number]
1726
- # @raise [ArgumentError] if `$number` isn't a number
1727
- def floor(number)
1728
- numeric_transformation(number) {|n| n.floor}
1242
+ # @overload floor($value)
1243
+ # @param $value [Number]
1244
+ # @return [Number]
1245
+ # @raise [ArgumentError] if `$value` isn't a number
1246
+ def floor(value)
1247
+ numeric_transformation(value) {|n| n.floor}
1729
1248
  end
1730
- declare :floor, [:number]
1249
+ declare :floor, [:value]
1731
1250
 
1732
1251
  # Returns the absolute value of a number.
1733
1252
  #
1734
1253
  # @example
1735
1254
  # abs(10px) => 10px
1736
1255
  # abs(-10px) => 10px
1737
- # @overload abs($number)
1738
- # @param $number [Sass::Script::Value::Number]
1739
- # @return [Sass::Script::Value::Number]
1740
- # @raise [ArgumentError] if `$number` isn't a number
1741
- def abs(number)
1742
- numeric_transformation(number) {|n| n.abs}
1256
+ # @overload abs($value)
1257
+ # @param $value [Number]
1258
+ # @return [Number]
1259
+ # @raise [ArgumentError] if `$value` isn't a number
1260
+ def abs(value)
1261
+ numeric_transformation(value) {|n| n.abs}
1743
1262
  end
1744
- declare :abs, [:number]
1263
+ declare :abs, [:value]
1745
1264
 
1746
1265
  # Finds the minimum of several numbers. This function takes any number of
1747
1266
  # arguments.
@@ -1750,8 +1269,8 @@ module Sass::Script
1750
1269
  # min(1px, 4px) => 1px
1751
1270
  # min(5em, 3em, 4em) => 3em
1752
1271
  # @overload min($numbers...)
1753
- # @param $numbers [[Sass::Script::Value::Number]]
1754
- # @return [Sass::Script::Value::Number]
1272
+ # @param $numbers [[Number]]
1273
+ # @return [Number]
1755
1274
  # @raise [ArgumentError] if any argument isn't a number, or if not all of
1756
1275
  # the arguments have comparable units
1757
1276
  def min(*numbers)
@@ -1767,8 +1286,8 @@ module Sass::Script
1767
1286
  # max(1px, 4px) => 4px
1768
1287
  # max(5em, 3em, 4em) => 5em
1769
1288
  # @overload max($numbers...)
1770
- # @param $numbers [[Sass::Script::Value::Number]]
1771
- # @return [Sass::Script::Value::Number]
1289
+ # @param $numbers [[Number]]
1290
+ # @return [Number]
1772
1291
  # @raise [ArgumentError] if any argument isn't a number, or if not all of
1773
1292
  # the arguments have comparable units
1774
1293
  def max(*values)
@@ -1779,77 +1298,44 @@ module Sass::Script
1779
1298
 
1780
1299
  # Return the length of a list.
1781
1300
  #
1782
- # This can return the number of pairs in a map as well.
1783
- #
1784
1301
  # @example
1785
1302
  # length(10px) => 1
1786
1303
  # length(10px 20px 30px) => 3
1787
- # length((width: 10px, height: 20px)) => 2
1788
1304
  # @overload length($list)
1789
- # @param $list [Sass::Script::Value::Base]
1790
- # @return [Sass::Script::Value::Number]
1305
+ # @param $list [Literal]
1306
+ # @return [Number]
1791
1307
  def length(list)
1792
- number(list.to_a.size)
1308
+ Sass::Script::Number.new(list.to_a.size)
1793
1309
  end
1794
1310
  declare :length, [:list]
1795
1311
 
1796
- # Return a new list, based on the list provided, but with the nth
1797
- # element changed to the value given.
1798
- #
1799
- # Note that unlike some languages, the first item in a Sass list is number
1800
- # 1, the second number 2, and so forth.
1801
- #
1802
- # Negative index values address elements in reverse order, starting with the last element
1803
- # in the list.
1804
- #
1805
- # @example
1806
- # set-nth($list: 10px 20px 30px, $n: 2, $value: -20px) => 10px -20px 30px
1807
- # @overload set-nth($list, $n, $value)
1808
- # @param $list [Sass::Script::Value::Base] The list that will be copied, having the element
1809
- # at index `$n` changed.
1810
- # @param $n [Sass::Script::Value::Number] The index of the item to set.
1811
- # Negative indices count from the end of the list.
1812
- # @param $value [Sass::Script::Value::Base] The new value at index `$n`.
1813
- # @return [Sass::Script::Value::List]
1814
- # @raise [ArgumentError] if `$n` isn't an integer between 1 and the length
1815
- # of `$list`
1816
- def set_nth(list, n, value)
1817
- assert_type n, :Number, :n
1818
- Sass::Script::Value::List.assert_valid_index(list, n)
1819
- index = n.to_i > 0 ? n.to_i - 1 : n.to_i
1820
- new_list = list.to_a.dup
1821
- new_list[index] = value
1822
- Sass::Script::Value::List.new(new_list, list.separator)
1823
- end
1824
- declare :set_nth, [:list, :n, :value]
1825
-
1826
1312
  # Gets the nth item in a list.
1827
1313
  #
1828
1314
  # Note that unlike some languages, the first item in a Sass list is number
1829
1315
  # 1, the second number 2, and so forth.
1830
1316
  #
1831
- # This can return the nth pair in a map as well.
1832
- #
1833
- # Negative index values address elements in reverse order, starting with the last element in
1834
- # the list.
1835
- #
1836
1317
  # @example
1837
1318
  # nth(10px 20px 30px, 1) => 10px
1838
1319
  # nth((Helvetica, Arial, sans-serif), 3) => sans-serif
1839
- # nth((width: 10px, length: 20px), 2) => length, 20px
1840
1320
  # @overload nth($list, $n)
1841
- # @param $list [Sass::Script::Value::Base]
1842
- # @param $n [Sass::Script::Value::Number] The index of the item to get.
1843
- # Negative indices count from the end of the list.
1844
- # @return [Sass::Script::Value::Base]
1321
+ # @param $list [Literal]
1322
+ # @param $n [Number] The index of the item to get
1323
+ # @return [Literal]
1845
1324
  # @raise [ArgumentError] if `$n` isn't an integer between 1 and the length
1846
1325
  # of `$list`
1847
1326
  def nth(list, n)
1848
1327
  assert_type n, :Number, :n
1849
- Sass::Script::Value::List.assert_valid_index(list, n)
1328
+ if !n.int?
1329
+ raise ArgumentError.new("List index #{n} must be an integer")
1330
+ elsif n.to_i < 1
1331
+ raise ArgumentError.new("List index #{n} must be greater than or equal to 1")
1332
+ elsif list.to_a.size == 0
1333
+ raise ArgumentError.new("List index is #{n} but list has no items")
1334
+ elsif n.to_i > (size = list.to_a.size)
1335
+ raise ArgumentError.new("List index is #{n} but list is only #{size} item#{'s' if size != 1} long")
1336
+ end
1850
1337
 
1851
- index = n.to_i > 0 ? n.to_i - 1 : n.to_i
1852
- list.to_a[index]
1338
+ list.to_a[n.to_i - 1]
1853
1339
  end
1854
1340
  declare :nth, [:list, :n]
1855
1341
 
@@ -1867,23 +1353,26 @@ module Sass::Script
1867
1353
  # join(10px, 20px, comma) => 10px, 20px
1868
1354
  # join((blue, red), (#abc, #def), space) => blue red #abc #def
1869
1355
  # @overload join($list1, $list2, $separator: auto)
1870
- # @param $list1 [Sass::Script::Value::Base]
1871
- # @param $list2 [Sass::Script::Value::Base]
1872
- # @param $separator [Sass::Script::Value::String] The list separator to use.
1873
- # If this is `comma` or `space`, that separator will be used. If this is
1874
- # `auto` (the default), the separator is determined as explained above.
1875
- # @return [Sass::Script::Value::List]
1876
- def join(list1, list2, separator = identifier("auto"))
1356
+ # @param $list1 [Literal]
1357
+ # @param $list2 [Literal]
1358
+ # @param $separator [String] The list separator to use. If this is `comma`
1359
+ # or `space`, that separator will be used. If this is `auto` (the
1360
+ # default), the separator is determined as explained above.
1361
+ # @return [List]
1362
+ def join(list1, list2, separator = Sass::Script::String.new("auto"))
1877
1363
  assert_type separator, :String, :separator
1878
1364
  unless %w[auto space comma].include?(separator.value)
1879
1365
  raise ArgumentError.new("Separator name must be space, comma, or auto")
1880
1366
  end
1881
- sep = if separator.value == 'auto'
1882
- list1.separator || list2.separator || :space
1883
- else
1884
- separator.value.to_sym
1885
- end
1886
- list(list1.to_a + list2.to_a, sep)
1367
+ sep1 = list1.separator if list1.is_a?(Sass::Script::List) && !list1.value.empty?
1368
+ sep2 = list2.separator if list2.is_a?(Sass::Script::List) && !list2.value.empty?
1369
+ Sass::Script::List.new(
1370
+ list1.to_a + list2.to_a,
1371
+ if separator.value == 'auto'
1372
+ sep1 || sep2 || :space
1373
+ else
1374
+ separator.value.to_sym
1375
+ end)
1887
1376
  end
1888
1377
  declare :join, [:list1, :list2]
1889
1378
  declare :join, [:list1, :list2, :separator]
@@ -1900,23 +1389,25 @@ module Sass::Script
1900
1389
  # append(10px, 20px, comma) => 10px, 20px
1901
1390
  # append((blue, red), green, space) => blue red green
1902
1391
  # @overload append($list, $val, $separator: auto)
1903
- # @param $list [Sass::Script::Value::Base]
1904
- # @param $val [Sass::Script::Value::Base]
1905
- # @param $separator [Sass::Script::Value::String] The list separator to use.
1906
- # If this is `comma` or `space`, that separator will be used. If this is
1907
- # `auto` (the default), the separator is determined as explained above.
1908
- # @return [Sass::Script::Value::List]
1909
- def append(list, val, separator = identifier("auto"))
1392
+ # @param $list [Literal]
1393
+ # @param $val [Literal]
1394
+ # @param $separator [String] The list separator to use. If this is `comma`
1395
+ # or `space`, that separator will be used. If this is `auto` (the
1396
+ # default), the separator is determined as explained above.
1397
+ # @return [List]
1398
+ def append(list, val, separator = Sass::Script::String.new("auto"))
1910
1399
  assert_type separator, :String, :separator
1911
1400
  unless %w[auto space comma].include?(separator.value)
1912
1401
  raise ArgumentError.new("Separator name must be space, comma, or auto")
1913
1402
  end
1914
- sep = if separator.value == 'auto'
1915
- list.separator || :space
1916
- else
1917
- separator.value.to_sym
1918
- end
1919
- list(list.to_a + [val], sep)
1403
+ sep = list.separator if list.is_a?(Sass::Script::List)
1404
+ Sass::Script::List.new(
1405
+ list.to_a + [val],
1406
+ if separator.value == 'auto'
1407
+ sep || :space
1408
+ else
1409
+ separator.value.to_sym
1410
+ end)
1920
1411
  end
1921
1412
  declare :append, [:list, :val]
1922
1413
  declare :append, [:list, :val, :separator]
@@ -1932,8 +1423,8 @@ module Sass::Script
1932
1423
  # zip(1px 1px 3px, solid dashed solid, red green blue)
1933
1424
  # => 1px solid red, 1px dashed green, 3px solid blue
1934
1425
  # @overload zip($lists...)
1935
- # @param $lists [[Sass::Script::Value::Base]]
1936
- # @return [Sass::Script::Value::List]
1426
+ # @param $lists [[Literal]]
1427
+ # @return [List]
1937
1428
  def zip(*lists)
1938
1429
  length = nil
1939
1430
  values = []
@@ -1946,176 +1437,35 @@ module Sass::Script
1946
1437
  value.slice!(length)
1947
1438
  end
1948
1439
  new_list_value = values.first.zip(*values[1..-1])
1949
- list(new_list_value.map {|list| list(list, :space)}, :comma)
1440
+ List.new(new_list_value.map{|list| List.new(list, :space)}, :comma)
1950
1441
  end
1951
1442
  declare :zip, [], :var_args => true
1952
1443
 
1444
+
1953
1445
  # Returns the position of a value within a list. If the value isn't found,
1954
- # returns `null` instead.
1446
+ # returns false instead.
1955
1447
  #
1956
1448
  # Note that unlike some languages, the first item in a Sass list is number
1957
1449
  # 1, the second number 2, and so forth.
1958
1450
  #
1959
- # This can return the position of a pair in a map as well.
1960
- #
1961
1451
  # @example
1962
1452
  # index(1px solid red, solid) => 2
1963
- # index(1px solid red, dashed) => null
1964
- # index((width: 10px, height: 20px), (height 20px)) => 2
1453
+ # index(1px solid red, dashed) => false
1965
1454
  # @overload index($list, $value)
1966
- # @param $list [Sass::Script::Value::Base]
1967
- # @param $value [Sass::Script::Value::Base]
1968
- # @return [Sass::Script::Value::Number, Sass::Script::Value::Null] The
1969
- # 1-based index of `$value` in `$list`, or `null`
1455
+ # @param $list [Literal]
1456
+ # @param $value [Literal]
1457
+ # @return [Number, Bool] The 1-based index of `$value` in `$list`, or
1458
+ # `false`
1970
1459
  def index(list, value)
1971
- index = list.to_a.index {|e| e.eq(value).to_bool}
1972
- index ? number(index + 1) : null
1460
+ index = list.to_a.index {|e| e.eq(value).to_bool }
1461
+ if index
1462
+ Number.new(index + 1)
1463
+ else
1464
+ Bool.new(false)
1465
+ end
1973
1466
  end
1974
1467
  declare :index, [:list, :value]
1975
1468
 
1976
- # Returns the separator of a list. If the list doesn't have a separator due
1977
- # to having fewer than two elements, returns `space`.
1978
- #
1979
- # @example
1980
- # list-separator(1px 2px 3px) => space
1981
- # list-separator(1px, 2px, 3px) => comma
1982
- # list-separator('foo') => space
1983
- # @overload list_separator($list)
1984
- # @param $list [Sass::Script::Value::Base]
1985
- # @return [Sass::Script::Value::String] `comma` or `space`
1986
- def list_separator(list)
1987
- identifier((list.separator || :space).to_s)
1988
- end
1989
- declare :separator, [:list]
1990
-
1991
- # Returns the value in a map associated with the given key. If the map
1992
- # doesn't have such a key, returns `null`.
1993
- #
1994
- # @example
1995
- # map-get(("foo": 1, "bar": 2), "foo") => 1
1996
- # map-get(("foo": 1, "bar": 2), "bar") => 2
1997
- # map-get(("foo": 1, "bar": 2), "baz") => null
1998
- # @overload map_get($map, $key)
1999
- # @param $map [Sass::Script::Value::Map]
2000
- # @param $key [Sass::Script::Value::Base]
2001
- # @return [Sass::Script::Value::Base] The value indexed by `$key`, or `null`
2002
- # if the map doesn't contain the given key
2003
- # @raise [ArgumentError] if `$map` is not a map
2004
- def map_get(map, key)
2005
- assert_type map, :Map, :map
2006
- map.to_h[key] || null
2007
- end
2008
- declare :map_get, [:map, :key]
2009
-
2010
- # Merges two maps together into a new map. Keys in `$map2` will take
2011
- # precedence over keys in `$map1`.
2012
- #
2013
- # This is the best way to add new values to a map.
2014
- #
2015
- # All keys in the returned map that also appear in `$map1` will have the
2016
- # same order as in `$map1`. New keys from `$map2` will be placed at the end
2017
- # of the map.
2018
- #
2019
- # @example
2020
- # map-merge(("foo": 1), ("bar": 2)) => ("foo": 1, "bar": 2)
2021
- # map-merge(("foo": 1, "bar": 2), ("bar": 3)) => ("foo": 1, "bar": 3)
2022
- # @overload map_merge($map1, $map2)
2023
- # @param $map1 [Sass::Script::Value::Map]
2024
- # @param $map2 [Sass::Script::Value::Map]
2025
- # @return [Sass::Script::Value::Map]
2026
- # @raise [ArgumentError] if either parameter is not a map
2027
- def map_merge(map1, map2)
2028
- assert_type map1, :Map, :map1
2029
- assert_type map2, :Map, :map2
2030
- map(map1.to_h.merge(map2.to_h))
2031
- end
2032
- declare :map_merge, [:map1, :map2]
2033
-
2034
- # Returns a new map with keys removed.
2035
- #
2036
- # @example
2037
- # map-remove(("foo": 1, "bar": 2), "bar") => ("foo": 1)
2038
- # map-remove(("foo": 1, "bar": 2, "baz": 3), "bar", "baz") => ("foo": 1)
2039
- # map-remove(("foo": 1, "bar": 2), "baz") => ("foo": 1, "bar": 2)
2040
- # @overload map_remove($map, $keys...)
2041
- # @param $map [Sass::Script::Value::Map]
2042
- # @param $keys [[Sass::Script::Value::Base]]
2043
- # @return [Sass::Script::Value::Map]
2044
- # @raise [ArgumentError] if `$map` is not a map
2045
- def map_remove(map, *keys)
2046
- assert_type map, :Map, :map
2047
- hash = map.to_h.dup
2048
- hash.delete_if {|key, _| keys.include?(key)}
2049
- map(hash)
2050
- end
2051
- declare :map_remove, [:map, :key], :var_args => true
2052
-
2053
- # Returns a list of all keys in a map.
2054
- #
2055
- # @example
2056
- # map-keys(("foo": 1, "bar": 2)) => "foo", "bar"
2057
- # @overload map_keys($map)
2058
- # @param $map [Map]
2059
- # @return [List] the list of keys, comma-separated
2060
- # @raise [ArgumentError] if `$map` is not a map
2061
- def map_keys(map)
2062
- assert_type map, :Map, :map
2063
- list(map.to_h.keys, :comma)
2064
- end
2065
- declare :map_keys, [:map]
2066
-
2067
- # Returns a list of all values in a map. This list may include duplicate
2068
- # values, if multiple keys have the same value.
2069
- #
2070
- # @example
2071
- # map-values(("foo": 1, "bar": 2)) => 1, 2
2072
- # map-values(("foo": 1, "bar": 2, "baz": 1)) => 1, 2, 1
2073
- # @overload map_values($map)
2074
- # @param $map [Map]
2075
- # @return [List] the list of values, comma-separated
2076
- # @raise [ArgumentError] if `$map` is not a map
2077
- def map_values(map)
2078
- assert_type map, :Map, :map
2079
- list(map.to_h.values, :comma)
2080
- end
2081
- declare :map_values, [:map]
2082
-
2083
- # Returns whether a map has a value associated with a given key.
2084
- #
2085
- # @example
2086
- # map-has-key(("foo": 1, "bar": 2), "foo") => true
2087
- # map-has-key(("foo": 1, "bar": 2), "baz") => false
2088
- # @overload map_has_key($map, $key)
2089
- # @param $map [Sass::Script::Value::Map]
2090
- # @param $key [Sass::Script::Value::Base]
2091
- # @return [Sass::Script::Value::Bool]
2092
- # @raise [ArgumentError] if `$map` is not a map
2093
- def map_has_key(map, key)
2094
- assert_type map, :Map, :map
2095
- bool(map.to_h.has_key?(key))
2096
- end
2097
- declare :map_has_key, [:map, :key]
2098
-
2099
- # Returns the map of named arguments passed to a function or mixin that
2100
- # takes a variable argument list. The argument names are strings, and they
2101
- # do not contain the leading `$`.
2102
- #
2103
- # @example
2104
- # @mixin foo($args...) {
2105
- # @debug keywords($args); //=> (arg1: val, arg2: val)
2106
- # }
2107
- #
2108
- # @include foo($arg1: val, $arg2: val);
2109
- # @overload keywords($args)
2110
- # @param $args [Sass::Script::Value::ArgList]
2111
- # @return [Sass::Script::Value::Map]
2112
- # @raise [ArgumentError] if `$args` isn't a variable argument list
2113
- def keywords(args)
2114
- assert_type args, :ArgList, :args
2115
- map(Sass::Util.map_keys(args.keywords.as_stored) {|k| Sass::Script::Value::String.new(k)})
2116
- end
2117
- declare :keywords, [:args]
2118
-
2119
1469
  # Returns one of two values, depending on whether or not `$condition` is
2120
1470
  # true. Just like in `@if`, all values other than `false` and `null` are
2121
1471
  # considered to be true.
@@ -2124,483 +1474,50 @@ module Sass::Script
2124
1474
  # if(true, 1px, 2px) => 1px
2125
1475
  # if(false, 1px, 2px) => 2px
2126
1476
  # @overload if($condition, $if-true, $if-false)
2127
- # @param $condition [Sass::Script::Value::Base] Whether the `$if-true` or
2128
- # `$if-false` will be returned
2129
- # @param $if-true [Sass::Script::Tree::Node]
2130
- # @param $if-false [Sass::Script::Tree::Node]
2131
- # @return [Sass::Script::Value::Base] `$if-true` or `$if-false`
1477
+ # @param $condition [Literal] Whether the `$if-true` or `$if-false` will be
1478
+ # returned
1479
+ # @param $if-true [Literal]
1480
+ # @param $if-false [Literal]
1481
+ # @return [Literal] `$if-true` or `$if-false`
2132
1482
  def if(condition, if_true, if_false)
2133
1483
  if condition.to_bool
2134
- perform(if_true)
1484
+ if_true
2135
1485
  else
2136
- perform(if_false)
1486
+ if_false
2137
1487
  end
2138
1488
  end
2139
- declare :if, [:condition, :"&if_true", :"&if_false"]
2140
-
2141
- # Returns a unique CSS identifier. The identifier is returned as an unquoted
2142
- # string. The identifier returned is only guaranteed to be unique within the
2143
- # scope of a single Sass run.
2144
- #
2145
- # @overload unique_id()
2146
- # @return [Sass::Script::Value::String]
2147
- def unique_id
2148
- generator = Sass::Script::Functions.random_number_generator
2149
- Thread.current[:sass_last_unique_id] ||= generator.rand(36**8)
2150
- # avoid the temptation of trying to guess the next unique value.
2151
- value = (Thread.current[:sass_last_unique_id] += (generator.rand(10) + 1))
2152
- # the u makes this a legal identifier if it would otherwise start with a number.
2153
- identifier("u" + value.to_s(36).rjust(8, '0'))
2154
- end
2155
- declare :unique_id, []
1489
+ declare :if, [:condition, :if_true, :if_false]
2156
1490
 
2157
- # Dynamically calls a function. This can call user-defined
2158
- # functions, built-in functions, or plain CSS functions. It will
2159
- # pass along all arguments, including keyword arguments, to the
2160
- # called function.
2161
- #
2162
- # @example
2163
- # call(rgb, 10, 100, 255) => #0a64ff
2164
- # call(scale-color, #0a64ff, $lightness: -10%) => #0058ef
2165
- #
2166
- # $fn: nth;
2167
- # call($fn, (a b c), 2) => b
2168
- #
2169
- # @overload call($name, $args...)
2170
- # @param $name [String] The name of the function to call.
2171
- def call(name, *args)
2172
- assert_type name, :String, :name
2173
- kwargs = args.last.is_a?(Hash) ? args.pop : {}
2174
- funcall = Sass::Script::Tree::Funcall.new(
2175
- name.value,
2176
- args.map {|a| Sass::Script::Tree::Literal.new(a)},
2177
- Sass::Util.map_vals(kwargs) {|v| Sass::Script::Tree::Literal.new(v)},
2178
- nil,
2179
- nil)
2180
- funcall.options = options
2181
- perform(funcall)
2182
- end
2183
- declare :call, [:name], :var_args => true, :var_kwargs => true
2184
-
2185
- # This function only exists as a workaround for IE7's [`content:
2186
- # counter` bug](http://jes.st/2013/ie7s-css-breaking-content-counter-bug/).
2187
- # It works identically to any other plain-CSS function, except it
1491
+ # This function only exists as a workaround for IE7's [`content: counter`
1492
+ # bug][bug]. It works identically to any other plain-CSS function, except it
2188
1493
  # avoids adding spaces between the argument commas.
2189
1494
  #
1495
+ # [bug]: http://jes.st/2013/ie7s-css-breaking-content-counter-bug/
1496
+ #
2190
1497
  # @example
2191
1498
  # counter(item, ".") => counter(item,".")
2192
1499
  # @overload counter($args...)
2193
- # @return [Sass::Script::Value::String]
1500
+ # @return [String]
2194
1501
  def counter(*args)
2195
- identifier("counter(#{args.map {|a| a.to_s(options)}.join(',')})")
1502
+ Sass::Script::String.new("counter(#{args.map {|a| a.to_s(options)}.join(',')})")
2196
1503
  end
2197
1504
  declare :counter, [], :var_args => true
2198
1505
 
2199
- # This function only exists as a workaround for IE7's [`content:
2200
- # counter` bug](http://jes.st/2013/ie7s-css-breaking-content-counter-bug/).
2201
- # It works identically to any other plain-CSS function, except it
1506
+ # This function only exists as a workaround for IE7's [`content: counters`
1507
+ # bug][bug]. It works identically to any other plain-CSS function, except it
2202
1508
  # avoids adding spaces between the argument commas.
2203
1509
  #
1510
+ # [bug]: http://jes.st/2013/ie7s-css-breaking-content-counter-bug/
1511
+ #
2204
1512
  # @example
2205
1513
  # counters(item, ".") => counters(item,".")
2206
1514
  # @overload counters($args...)
2207
- # @return [Sass::Script::Value::String]
1515
+ # @return [String]
2208
1516
  def counters(*args)
2209
- identifier("counters(#{args.map {|a| a.to_s(options)}.join(',')})")
1517
+ Sass::Script::String.new("counters(#{args.map {|a| a.to_s(options)}.join(',')})")
2210
1518
  end
2211
1519
  declare :counters, [], :var_args => true
2212
1520
 
2213
- # Check whether a variable with the given name exists in the current
2214
- # scope or in the global scope.
2215
- #
2216
- # @example
2217
- # $a-false-value: false;
2218
- # variable-exists(a-false-value) => true
2219
- #
2220
- # variable-exists(nonexistent) => false
2221
- #
2222
- # @overload variable_exists($name)
2223
- # @param $name [Sass::Script::Value::String] The name of the variable to
2224
- # check. The name should not include the `$`.
2225
- # @return [Sass::Script::Value::Bool] Whether the variable is defined in
2226
- # the current scope.
2227
- def variable_exists(name)
2228
- assert_type name, :String, :name
2229
- bool(environment.caller.var(name.value))
2230
- end
2231
- declare :variable_exists, [:name]
2232
-
2233
- # Check whether a variable with the given name exists in the global
2234
- # scope (at the top level of the file).
2235
- #
2236
- # @example
2237
- # $a-false-value: false;
2238
- # global-variable-exists(a-false-value) => true
2239
- #
2240
- # .foo {
2241
- # $some-var: false;
2242
- # @if global-variable-exists(some-var) { /* false, doesn't run */ }
2243
- # }
2244
- #
2245
- # @overload global_variable_exists($name)
2246
- # @param $name [Sass::Script::Value::String] The name of the variable to
2247
- # check. The name should not include the `$`.
2248
- # @return [Sass::Script::Value::Bool] Whether the variable is defined in
2249
- # the global scope.
2250
- def global_variable_exists(name)
2251
- assert_type name, :String, :name
2252
- bool(environment.global_env.var(name.value))
2253
- end
2254
- declare :global_variable_exists, [:name]
2255
-
2256
- # Check whether a function with the given name exists.
2257
- #
2258
- # @example
2259
- # function-exists(lighten) => true
2260
- #
2261
- # @function myfunc { @return "something"; }
2262
- # function-exists(myfunc) => true
2263
- #
2264
- # @overload function_exists($name)
2265
- # @param name [Sass::Script::Value::String] The name of the function to
2266
- # check.
2267
- # @return [Sass::Script::Value::Bool] Whether the function is defined.
2268
- def function_exists(name)
2269
- assert_type name, :String, :name
2270
- exists = Sass::Script::Functions.callable?(name.value.tr("-", "_"))
2271
- exists ||= environment.function(name.value)
2272
- bool(exists)
2273
- end
2274
- declare :function_exists, [:name]
2275
-
2276
- # Check whether a mixin with the given name exists.
2277
- #
2278
- # @example
2279
- # mixin-exists(nonexistent) => false
2280
- #
2281
- # @mixin red-text { color: red; }
2282
- # mixin-exists(red-text) => true
2283
- #
2284
- # @overload mixin_exists($name)
2285
- # @param name [Sass::Script::Value::String] The name of the mixin to
2286
- # check.
2287
- # @return [Sass::Script::Value::Bool] Whether the mixin is defined.
2288
- def mixin_exists(name)
2289
- assert_type name, :String, :name
2290
- bool(environment.mixin(name.value))
2291
- end
2292
- declare :mixin_exists, [:name]
2293
-
2294
- # Return a string containing the value as its Sass representation.
2295
- #
2296
- # @overload inspect($value)
2297
- # @param $value [Sass::Script::Value::Base] The value to inspect.
2298
- # @return [Sass::Script::Value::String] A representation of the value as
2299
- # it would be written in Sass.
2300
- def inspect(value)
2301
- unquoted_string(value.to_sass)
2302
- end
2303
- declare :inspect, [:value]
2304
-
2305
- # @overload random()
2306
- # Return a decimal between 0 and 1, inclusive of 0 but not 1.
2307
- # @return [Sass::Script::Value::Number] A decimal value.
2308
- # @overload random($limit)
2309
- # Return an integer between 1 and `$limit`, inclusive of 1 but not `$limit`.
2310
- # @param $limit [Sass::Script::Value::Number] The maximum of the random integer to be
2311
- # returned, a positive integer.
2312
- # @return [Sass::Script::Value::Number] An integer.
2313
- # @raise [ArgumentError] if the `$limit` is not 1 or greater
2314
- def random(limit = nil)
2315
- generator = Sass::Script::Functions.random_number_generator
2316
- if limit
2317
- assert_integer limit, "limit"
2318
- if limit.value < 1
2319
- raise ArgumentError.new("$limit #{limit} must be greater than or equal to 1")
2320
- end
2321
- number(1 + generator.rand(limit.value))
2322
- else
2323
- number(generator.rand)
2324
- end
2325
- end
2326
- declare :random, []
2327
- declare :random, [:limit]
2328
-
2329
- # Parses a user-provided selector into a list of lists of strings
2330
- # as returned by `&`.
2331
- #
2332
- # @example
2333
- # selector-parse(".foo .bar, .baz .bang") => ('.foo' '.bar', '.baz' '.bang')
2334
- #
2335
- # @overload selector_parse($selector)
2336
- # @param $selector [Sass::Script::Value::String, Sass::Script::Value::List]
2337
- # The selector to parse. This can be either a string, a list of
2338
- # strings, or a list of lists of strings as returned by `&`.
2339
- # @return [Sass::Script::Value::List]
2340
- # A list of lists of strings representing `$selector`. This is
2341
- # in the same format as a selector returned by `&`.
2342
- def selector_parse(selector)
2343
- parse_selector(selector, :selector).to_sass_script
2344
- end
2345
- declare :selector_parse, [:selector]
2346
-
2347
- # Return a new selector with all selectors in `$selectors` nested beneath
2348
- # one another as though they had been nested in the stylesheet as
2349
- # `$selector1 { $selector2 { ... } }`.
2350
- #
2351
- # Unlike most selector functions, `selector-nest` allows the
2352
- # parent selector `&` to be used in any selector but the first.
2353
- #
2354
- # @example
2355
- # selector-nest(".foo", ".bar", ".baz") => .foo .bar .baz
2356
- # selector-nest(".a .foo", ".b .bar") => .a .foo .b .bar
2357
- # selector-nest(".foo", "&.bar") => .foo.bar
2358
- #
2359
- # @overload selector_nest($selectors...)
2360
- # @param $selectors [[Sass::Script::Value::String, Sass::Script::Value::List]]
2361
- # The selectors to nest. At least one selector must be passed. Each of
2362
- # these can be either a string, a list of strings, or a list of lists of
2363
- # strings as returned by `&`.
2364
- # @return [Sass::Script::Value::List]
2365
- # A list of lists of strings representing the result of nesting
2366
- # `$selectors`. This is in the same format as a selector returned by
2367
- # `&`.
2368
- def selector_nest(*selectors)
2369
- if selectors.empty?
2370
- raise ArgumentError.new("$selectors: At least one selector must be passed")
2371
- end
2372
-
2373
- parsed = [parse_selector(selectors.first, :selectors)]
2374
- parsed += selectors[1..-1].map {|sel| parse_selector(sel, :selectors, !!:parse_parent_ref)}
2375
- parsed.inject {|result, child| child.resolve_parent_refs(result)}.to_sass_script
2376
- end
2377
- declare :selector_nest, [], :var_args => true
2378
-
2379
- # Return a new selector with all selectors in `$selectors` appended one
2380
- # another as though they had been nested in the stylesheet as `$selector1 {
2381
- # &$selector2 { ... } }`.
2382
- #
2383
- # @example
2384
- # selector-append(".foo", ".bar", ".baz") => .foo.bar.baz
2385
- # selector-append(".a .foo", ".b .bar") => "a .foo.b .bar"
2386
- # selector-append(".foo", "-suffix") => ".foo-suffix"
2387
- #
2388
- # @overload selector_append($selectors...)
2389
- # @param $selectors [[Sass::Script::Value::String, Sass::Script::Value::List]]
2390
- # The selectors to append. At least one selector must be passed. Each of
2391
- # these can be either a string, a list of strings, or a list of lists of
2392
- # strings as returned by `&`.
2393
- # @return [Sass::Script::Value::List]
2394
- # A list of lists of strings representing the result of appending
2395
- # `$selectors`. This is in the same format as a selector returned by
2396
- # `&`.
2397
- # @raise [ArgumentError] if a selector could not be appended.
2398
- def selector_append(*selectors)
2399
- if selectors.empty?
2400
- raise ArgumentError.new("$selectors: At least one selector must be passed")
2401
- end
2402
-
2403
- selectors.map {|sel| parse_selector(sel, :selectors)}.inject do |parent, child|
2404
- child.members.each do |seq|
2405
- sseq = seq.members.first
2406
- unless sseq.is_a?(Sass::Selector::SimpleSequence)
2407
- raise ArgumentError.new("Can't append \"#{seq}\" to \"#{parent}\"")
2408
- end
2409
-
2410
- base = sseq.base
2411
- case base
2412
- when Sass::Selector::Universal
2413
- raise ArgumentError.new("Can't append \"#{seq}\" to \"#{parent}\"")
2414
- when Sass::Selector::Element
2415
- unless base.namespace.nil?
2416
- raise ArgumentError.new("Can't append \"#{seq}\" to \"#{parent}\"")
2417
- end
2418
- sseq.members[0] = Sass::Selector::Parent.new(base.name)
2419
- else
2420
- sseq.members.unshift Sass::Selector::Parent.new
2421
- end
2422
- end
2423
- child.resolve_parent_refs(parent)
2424
- end.to_sass_script
2425
- end
2426
- declare :selector_append, [], :var_args => true
2427
-
2428
- # Returns a new version of `$selector` with `$extendee` extended
2429
- # with `$extender`. This works just like the result of
2430
- #
2431
- # $selector { ... }
2432
- # $extender { @extend $extendee }
2433
- #
2434
- # @example
2435
- # selector-extend(".a .b", ".b", ".foo .bar") => .a .b, .a .foo .bar, .foo .a .bar
2436
- #
2437
- # @overload selector_extend($selector, $extendee, $extender)
2438
- # @param $selector [Sass::Script::Value::String, Sass::Script::Value::List]
2439
- # The selector within which `$extendee` is extended with
2440
- # `$extender`. This can be either a string, a list of strings,
2441
- # or a list of lists of strings as returned by `&`.
2442
- # @param $extendee [Sass::Script::Value::String, Sass::Script::Value::List]
2443
- # The selector being extended. This can be either a string, a
2444
- # list of strings, or a list of lists of strings as returned
2445
- # by `&`.
2446
- # @param $extender [Sass::Script::Value::String, Sass::Script::Value::List]
2447
- # The selector being injected into `$selector`. This can be
2448
- # either a string, a list of strings, or a list of lists of
2449
- # strings as returned by `&`.
2450
- # @return [Sass::Script::Value::List]
2451
- # A list of lists of strings representing the result of the
2452
- # extension. This is in the same format as a selector returned
2453
- # by `&`.
2454
- # @raise [ArgumentError] if the extension fails
2455
- def selector_extend(selector, extendee, extender)
2456
- selector = parse_selector(selector, :selector)
2457
- extendee = parse_selector(extendee, :extendee)
2458
- extender = parse_selector(extender, :extender)
2459
-
2460
- extends = Sass::Util::SubsetMap.new
2461
- begin
2462
- extender.populate_extends(extends, extendee)
2463
- selector.do_extend(extends).to_sass_script
2464
- rescue Sass::SyntaxError => e
2465
- raise ArgumentError.new(e.to_s)
2466
- end
2467
- end
2468
- declare :selector_extend, [:selector, :extendee, :extender]
2469
-
2470
- # Replaces all instances of `$original` with `$replacement` in `$selector`
2471
- #
2472
- # This works by using `@extend` and throwing away the original
2473
- # selector. This means that it can be used to do very advanced
2474
- # replacements; see the examples below.
2475
- #
2476
- # @example
2477
- # selector-replace(".foo .bar", ".bar", ".baz") => ".foo .baz"
2478
- # selector-replace(".foo.bar.baz", ".foo.baz", ".qux") => ".bar.qux"
2479
- #
2480
- # @overload selector_replace($selector, $original, $replacement)
2481
- # @param $selector [Sass::Script::Value::String, Sass::Script::Value::List]
2482
- # The selector within which `$original` is replaced with
2483
- # `$replacement`. This can be either a string, a list of
2484
- # strings, or a list of lists of strings as returned by `&`.
2485
- # @param $original [Sass::Script::Value::String, Sass::Script::Value::List]
2486
- # The selector being replaced. This can be either a string, a
2487
- # list of strings, or a list of lists of strings as returned
2488
- # by `&`.
2489
- # @param $replacement [Sass::Script::Value::String, Sass::Script::Value::List]
2490
- # The selector that `$original` is being replaced with. This
2491
- # can be either a string, a list of strings, or a list of
2492
- # lists of strings as returned by `&`.
2493
- # @return [Sass::Script::Value::List]
2494
- # A list of lists of strings representing the result of the
2495
- # extension. This is in the same format as a selector returned
2496
- # by `&`.
2497
- # @raise [ArgumentError] if the replacement fails
2498
- def selector_replace(selector, original, replacement)
2499
- selector = parse_selector(selector, :selector)
2500
- original = parse_selector(original, :original)
2501
- replacement = parse_selector(replacement, :replacement)
2502
-
2503
- extends = Sass::Util::SubsetMap.new
2504
- begin
2505
- replacement.populate_extends(extends, original)
2506
- selector.do_extend(extends, [], !!:replace).to_sass_script
2507
- rescue Sass::SyntaxError => e
2508
- raise ArgumentError.new(e.to_s)
2509
- end
2510
- end
2511
- declare :selector_replace, [:selector, :original, :replacement]
2512
-
2513
- # Unifies two selectors into a single selector that matches only
2514
- # elements matched by both input selectors. Returns `null` if
2515
- # there is no such selector.
2516
- #
2517
- # Like the selector unification done for `@extend`, this doesn't
2518
- # guarantee that the output selector will match *all* elements
2519
- # matched by both input selectors. For example, if `.a .b` is
2520
- # unified with `.x .y`, `.a .x .b.y, .x .a .b.y` will be returned,
2521
- # but `.a.x .b.y` will not. This avoids exponential output size
2522
- # while matching all elements that are likely to exist in
2523
- # practice.
2524
- #
2525
- # @example
2526
- # selector-unify(".a", ".b") => .a.b
2527
- # selector-unify(".a .b", ".x .y") => .a .x .b.y, .x .a .b.y
2528
- # selector-unify(".a.b", ".b.c") => .a.b.c
2529
- # selector-unify("#a", "#b") => null
2530
- #
2531
- # @overload selector_unify($selector1, $selector2)
2532
- # @param $selector1 [Sass::Script::Value::String, Sass::Script::Value::List]
2533
- # The first selector to be unified. This can be either a
2534
- # string, a list of strings, or a list of lists of strings as
2535
- # returned by `&`.
2536
- # @param $selector2 [Sass::Script::Value::String, Sass::Script::Value::List]
2537
- # The second selector to be unified. This can be either a
2538
- # string, a list of strings, or a list of lists of strings as
2539
- # returned by `&`.
2540
- # @return [Sass::Script::Value::List, Sass::Script::Value::Null]
2541
- # A list of lists of strings representing the result of the
2542
- # unification, or null if no unification exists. This is in
2543
- # the same format as a selector returned by `&`.
2544
- def selector_unify(selector1, selector2)
2545
- selector1 = parse_selector(selector1, :selector1)
2546
- selector2 = parse_selector(selector2, :selector2)
2547
- return null unless (unified = selector1.unify(selector2))
2548
- unified.to_sass_script
2549
- end
2550
- declare :selector_unify, [:selector1, :selector2]
2551
-
2552
- # Returns the [simple
2553
- # selectors](http://dev.w3.org/csswg/selectors4/#simple) that
2554
- # comprise the compound selector `$selector`.
2555
- #
2556
- # Note that `$selector` **must be** a [compound
2557
- # selector](http://dev.w3.org/csswg/selectors4/#compound). That
2558
- # means it cannot contain commas or spaces. It also means that
2559
- # unlike other selector functions, this takes only strings, not
2560
- # lists.
2561
- #
2562
- # @example
2563
- # simple-selectors(".foo.bar") => ".foo", ".bar"
2564
- # simple-selectors(".foo.bar.baz") => ".foo", ".bar", ".baz"
2565
- #
2566
- # @overload simple_selectors($selector)
2567
- # @param $selector [Sass::Script::Value::String]
2568
- # The compound selector whose simple selectors will be extracted.
2569
- # @return [Sass::Script::Value::List]
2570
- # A list of simple selectors in the compound selector.
2571
- def simple_selectors(selector)
2572
- selector = parse_compound_selector(selector, :selector)
2573
- list(selector.members.map {|simple| unquoted_string(simple.to_s)}, :comma)
2574
- end
2575
- declare :simple_selectors, [:selector]
2576
-
2577
- # Returns whether `$super` is a superselector of `$sub`. This means that
2578
- # `$super` matches all the elements that `$sub` matches, as well as possibly
2579
- # additional elements. In general, simpler selectors tend to be
2580
- # superselectors of more complex oned.
2581
- #
2582
- # @example
2583
- # is-superselector(".foo", ".foo.bar") => true
2584
- # is-superselector(".foo.bar", ".foo") => false
2585
- # is-superselector(".bar", ".foo .bar") => true
2586
- # is-superselector(".foo .bar", ".bar") => false
2587
- #
2588
- # @overload is_superselector($super, $sub)
2589
- # @param $super [Sass::Script::Value::String, Sass::Script::Value::List]
2590
- # The potential superselector. This can be either a string, a list of
2591
- # strings, or a list of lists of strings as returned by `&`.
2592
- # @param $sub [Sass::Script::Value::String, Sass::Script::Value::List]
2593
- # The potential subselector. This can be either a string, a list of
2594
- # strings, or a list of lists of strings as returned by `&`.
2595
- # @return [Sass::Script::Value::Bool]
2596
- # Whether `$selector1` is a superselector of `$selector2`.
2597
- def is_superselector(sup, sub)
2598
- sup = parse_selector(sup, :super)
2599
- sub = parse_selector(sub, :sub)
2600
- bool(sup.superselector?(sub))
2601
- end
2602
- declare :is_superselector, [:super, :sub]
2603
-
2604
1521
  private
2605
1522
 
2606
1523
  # This method implements the pattern of transforming a numeric value into
@@ -2608,19 +1525,19 @@ module Sass::Script
2608
1525
  # It yields a number to a block to perform the operation and return a number
2609
1526
  def numeric_transformation(value)
2610
1527
  assert_type value, :Number, :value
2611
- Sass::Script::Value::Number.new(
2612
- yield(value.value), value.numerator_units, value.denominator_units)
1528
+ Sass::Script::Number.new(yield(value.value), value.numerator_units, value.denominator_units)
2613
1529
  end
2614
1530
 
2615
- # @comment
2616
- # rubocop:disable ParameterLists
2617
1531
  def _adjust(color, amount, attr, range, op, units = "")
2618
- # rubocop:enable ParameterLists
2619
1532
  assert_type color, :Color, :color
2620
1533
  assert_type amount, :Number, :amount
2621
1534
  Sass::Util.check_range('Amount', range, amount, units)
2622
1535
 
2623
- color.with(attr => color.send(attr).send(op, amount.value))
1536
+ # TODO: is it worth restricting here,
1537
+ # or should we do so in the Color constructor itself,
1538
+ # and allow clipping in rgb() et al?
1539
+ color.with(attr => Sass::Util.restrict(
1540
+ color.send(attr).send(op, amount.value), range))
2624
1541
  end
2625
1542
  end
2626
1543
  end