oreorenasass 3.4.4 → 3.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +50 -70
- data/Rakefile +5 -26
- data/VERSION +1 -1
- data/VERSION_NAME +1 -1
- data/bin/sass +1 -1
- data/bin/scss +1 -1
- data/lib/sass.rb +12 -19
- data/lib/sass/cache_stores/base.rb +2 -2
- data/lib/sass/cache_stores/chain.rb +1 -2
- data/lib/sass/cache_stores/filesystem.rb +5 -1
- data/lib/sass/cache_stores/memory.rb +1 -1
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +0 -1
- data/lib/sass/css.rb +13 -11
- data/lib/sass/engine.rb +173 -424
- data/lib/sass/environment.rb +58 -148
- data/lib/sass/error.rb +14 -11
- data/lib/sass/exec.rb +703 -5
- data/lib/sass/importers/base.rb +6 -49
- data/lib/sass/importers/filesystem.rb +19 -44
- data/lib/sass/logger.rb +4 -1
- data/lib/sass/logger/base.rb +4 -2
- data/lib/sass/logger/log_level.rb +7 -3
- data/lib/sass/media.rb +23 -20
- data/lib/sass/plugin.rb +7 -7
- data/lib/sass/plugin/compiler.rb +145 -304
- data/lib/sass/plugin/configuration.rb +23 -18
- data/lib/sass/plugin/merb.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +3 -3
- data/lib/sass/repl.rb +3 -3
- data/lib/sass/script.rb +8 -35
- data/lib/sass/script/{value/arg_list.rb → arg_list.rb} +25 -9
- data/lib/sass/script/bool.rb +18 -0
- data/lib/sass/script/color.rb +606 -0
- data/lib/sass/script/css_lexer.rb +4 -8
- data/lib/sass/script/css_parser.rb +2 -5
- data/lib/sass/script/funcall.rb +245 -0
- data/lib/sass/script/functions.rb +408 -1491
- data/lib/sass/script/interpolation.rb +79 -0
- data/lib/sass/script/lexer.rb +68 -172
- data/lib/sass/script/list.rb +85 -0
- data/lib/sass/script/literal.rb +221 -0
- data/lib/sass/script/{tree/node.rb → node.rb} +12 -22
- data/lib/sass/script/{value/null.rb → null.rb} +7 -14
- data/lib/sass/script/{value/number.rb → number.rb} +75 -152
- data/lib/sass/script/{tree/operation.rb → operation.rb} +24 -17
- data/lib/sass/script/parser.rb +110 -245
- data/lib/sass/script/string.rb +51 -0
- data/lib/sass/script/{tree/string_interpolation.rb → string_interpolation.rb} +4 -5
- data/lib/sass/script/{tree/unary_operation.rb → unary_operation.rb} +6 -6
- data/lib/sass/script/variable.rb +58 -0
- data/lib/sass/scss/css_parser.rb +3 -9
- data/lib/sass/scss/parser.rb +421 -450
- data/lib/sass/scss/rx.rb +11 -19
- data/lib/sass/scss/static_parser.rb +7 -321
- data/lib/sass/selector.rb +194 -68
- data/lib/sass/selector/abstract_sequence.rb +14 -29
- data/lib/sass/selector/comma_sequence.rb +25 -108
- data/lib/sass/selector/sequence.rb +66 -159
- data/lib/sass/selector/simple.rb +25 -23
- data/lib/sass/selector/simple_sequence.rb +63 -173
- data/lib/sass/shared.rb +1 -1
- data/lib/sass/supports.rb +15 -13
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/comment_node.rb +3 -3
- data/lib/sass/tree/css_import_node.rb +11 -11
- data/lib/sass/tree/debug_node.rb +2 -2
- data/lib/sass/tree/directive_node.rb +4 -21
- data/lib/sass/tree/each_node.rb +8 -8
- data/lib/sass/tree/extend_node.rb +7 -14
- data/lib/sass/tree/for_node.rb +4 -4
- data/lib/sass/tree/function_node.rb +4 -9
- data/lib/sass/tree/if_node.rb +1 -1
- data/lib/sass/tree/import_node.rb +5 -4
- data/lib/sass/tree/media_node.rb +14 -4
- data/lib/sass/tree/mixin_def_node.rb +4 -4
- data/lib/sass/tree/mixin_node.rb +8 -21
- data/lib/sass/tree/node.rb +12 -54
- data/lib/sass/tree/prop_node.rb +20 -39
- data/lib/sass/tree/return_node.rb +2 -3
- data/lib/sass/tree/root_node.rb +3 -19
- data/lib/sass/tree/rule_node.rb +22 -35
- data/lib/sass/tree/supports_node.rb +13 -0
- data/lib/sass/tree/trace_node.rb +1 -2
- data/lib/sass/tree/variable_node.rb +3 -9
- data/lib/sass/tree/visitors/base.rb +8 -5
- data/lib/sass/tree/visitors/check_nesting.rb +19 -49
- data/lib/sass/tree/visitors/convert.rb +56 -74
- data/lib/sass/tree/visitors/cssize.rb +74 -202
- data/lib/sass/tree/visitors/deep_copy.rb +5 -10
- data/lib/sass/tree/visitors/extend.rb +7 -7
- data/lib/sass/tree/visitors/perform.rb +185 -278
- data/lib/sass/tree/visitors/set_options.rb +6 -20
- data/lib/sass/tree/visitors/to_css.rb +81 -234
- data/lib/sass/tree/warn_node.rb +2 -2
- data/lib/sass/tree/while_node.rb +2 -2
- data/lib/sass/util.rb +152 -522
- data/lib/sass/util/multibyte_string_scanner.rb +0 -2
- data/lib/sass/util/subset_map.rb +3 -4
- data/lib/sass/util/test.rb +1 -0
- data/lib/sass/version.rb +22 -20
- data/test/Gemfile +3 -0
- data/test/Gemfile.lock +10 -0
- data/test/sass/cache_test.rb +20 -62
- data/test/sass/callbacks_test.rb +1 -1
- data/test/sass/conversion_test.rb +2 -296
- data/test/sass/css2sass_test.rb +4 -23
- data/test/sass/engine_test.rb +354 -411
- data/test/sass/exec_test.rb +2 -2
- data/test/sass/extend_test.rb +145 -324
- data/test/sass/functions_test.rb +86 -873
- data/test/sass/importer_test.rb +21 -241
- data/test/sass/logger_test.rb +1 -1
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/plugin_test.rb +26 -16
- data/test/sass/results/compact.css +1 -1
- data/test/sass/results/complex.css +4 -4
- data/test/sass/results/expanded.css +1 -1
- data/test/sass/results/import.css +1 -1
- data/test/sass/results/import_charset_ibm866.css +2 -2
- data/test/sass/results/mixins.css +17 -17
- data/test/sass/results/nested.css +1 -1
- data/test/sass/results/parent_ref.css +2 -2
- data/test/sass/results/script.css +3 -3
- data/test/sass/results/scss_import.css +1 -1
- data/test/sass/script_conversion_test.rb +7 -36
- data/test/sass/script_test.rb +53 -485
- data/test/sass/scss/css_test.rb +28 -143
- data/test/sass/scss/rx_test.rb +4 -4
- data/test/sass/scss/scss_test.rb +325 -2119
- data/test/sass/templates/scss_import.scss +1 -2
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
- data/test/sass/util/subset_map_test.rb +2 -2
- data/test/sass/util_test.rb +1 -86
- data/test/test_helper.rb +8 -37
- metadata +19 -66
- data/lib/sass/exec/base.rb +0 -187
- data/lib/sass/exec/sass_convert.rb +0 -264
- data/lib/sass/exec/sass_scss.rb +0 -424
- data/lib/sass/features.rb +0 -47
- data/lib/sass/script/tree.rb +0 -16
- data/lib/sass/script/tree/funcall.rb +0 -306
- data/lib/sass/script/tree/interpolation.rb +0 -118
- data/lib/sass/script/tree/list_literal.rb +0 -77
- data/lib/sass/script/tree/literal.rb +0 -45
- data/lib/sass/script/tree/map_literal.rb +0 -64
- data/lib/sass/script/tree/selector.rb +0 -26
- data/lib/sass/script/tree/variable.rb +0 -57
- data/lib/sass/script/value.rb +0 -11
- data/lib/sass/script/value/base.rb +0 -240
- data/lib/sass/script/value/bool.rb +0 -35
- data/lib/sass/script/value/color.rb +0 -680
- data/lib/sass/script/value/helpers.rb +0 -262
- data/lib/sass/script/value/list.rb +0 -113
- data/lib/sass/script/value/map.rb +0 -70
- data/lib/sass/script/value/string.rb +0 -97
- data/lib/sass/selector/pseudo.rb +0 -256
- data/lib/sass/source/map.rb +0 -210
- data/lib/sass/source/position.rb +0 -39
- data/lib/sass/source/range.rb +0 -41
- data/lib/sass/stack.rb +0 -120
- data/lib/sass/tree/at_root_node.rb +0 -83
- data/lib/sass/tree/error_node.rb +0 -18
- data/lib/sass/tree/keyframe_rule_node.rb +0 -15
- data/lib/sass/util/cross_platform_random.rb +0 -19
- data/lib/sass/util/normalized_map.rb +0 -130
- data/lib/sass/util/ordered_hash.rb +0 -192
- data/test/sass/compiler_test.rb +0 -232
- data/test/sass/encoding_test.rb +0 -219
- data/test/sass/source_map_test.rb +0 -977
- data/test/sass/superselector_test.rb +0 -191
- data/test/sass/util/normalized_map_test.rb +0 -51
- 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
|
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
|
-
|
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
|
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 {
|
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 {
|
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($
|
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 {
|
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 {
|
48
|
-
#
|
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($
|
113
|
+
# \{#percentage percentage($value)}
|
140
114
|
# : Converts a unitless number to a percentage.
|
141
115
|
#
|
142
|
-
# \{#round round($
|
116
|
+
# \{#round round($value)}
|
143
117
|
# : Rounds a number to the nearest whole number.
|
144
118
|
#
|
145
|
-
# \{#ceil ceil($
|
119
|
+
# \{#ceil ceil($value)}
|
146
120
|
# : Rounds a number up to the next whole number.
|
147
121
|
#
|
148
|
-
# \{#floor floor($
|
122
|
+
# \{#floor floor($value)}
|
149
123
|
# : Rounds a number down to the previous whole number.
|
150
124
|
#
|
151
|
-
# \{#abs abs($
|
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($
|
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::
|
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 {
|
316
|
-
#
|
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
|
320
|
-
# their Ruby values.
|
321
|
-
#
|
322
|
-
# {Sass::Script::
|
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 {
|
344
|
-
# safe to call {
|
345
|
-
#
|
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<
|
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, :
|
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 {
|
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 [
|
425
|
-
# @param kwarg_arity [
|
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
|
-
|
434
|
-
|
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
|
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 -= (
|
445
|
-
t_arg_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
|
449
|
-
(t_kwarg_arity == 0
|
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
|
500
|
-
def initialize(
|
501
|
-
@
|
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::
|
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
|
-
|
521
|
-
|
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 {
|
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
|
-
#
|
614
|
-
#
|
615
|
-
#
|
616
|
-
#
|
617
|
-
#
|
618
|
-
#
|
619
|
-
#
|
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
|
-
|
630
|
-
|
631
|
-
c.
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
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 {
|
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 [
|
652
|
-
#
|
653
|
-
# @param $green [
|
654
|
-
#
|
655
|
-
# @param $blue [
|
656
|
-
#
|
657
|
-
# @param $alpha [
|
658
|
-
#
|
659
|
-
# @return [
|
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 [
|
671
|
-
#
|
672
|
-
#
|
673
|
-
#
|
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 {
|
697
|
-
#
|
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
|
-
#
|
704
|
-
#
|
705
|
-
#
|
706
|
-
#
|
707
|
-
#
|
708
|
-
#
|
709
|
-
# @return [
|
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,
|
460
|
+
hsla(hue, saturation, lightness, Number.new(1))
|
714
461
|
end
|
715
462
|
declare :hsl, [:hue, :saturation, :lightness]
|
716
463
|
|
717
|
-
# Creates a {
|
718
|
-
#
|
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
|
-
#
|
726
|
-
#
|
727
|
-
#
|
728
|
-
#
|
729
|
-
#
|
730
|
-
#
|
731
|
-
#
|
732
|
-
#
|
733
|
-
# @return [
|
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
|
744
|
-
l = lightness
|
745
|
-
|
746
|
-
|
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
|
-
#
|
761
|
-
# @return [
|
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
|
-
|
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
|
-
#
|
777
|
-
# @return [
|
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
|
-
|
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
|
-
#
|
793
|
-
# @return [
|
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
|
-
|
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
|
-
#
|
811
|
-
# @return [
|
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
|
-
|
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
|
-
#
|
829
|
-
# @return [
|
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
|
-
|
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
|
-
#
|
847
|
-
# @return [
|
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
|
-
|
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
|
-
#
|
864
|
-
# @return [
|
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
|
-
|
869
|
-
|
870
|
-
|
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
|
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
|
-
|
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
|
-
#
|
887
|
-
# @return [
|
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::
|
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
|
-
|
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
|
-
#
|
907
|
-
#
|
908
|
-
#
|
909
|
-
# @return [
|
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
|
-
#
|
929
|
-
#
|
930
|
-
#
|
931
|
-
# @return [
|
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
|
-
#
|
951
|
-
#
|
952
|
-
#
|
953
|
-
# @return [
|
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
|
-
#
|
970
|
-
#
|
971
|
-
#
|
972
|
-
# @return [
|
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
|
-
#
|
989
|
-
#
|
990
|
-
#
|
991
|
-
# @return [
|
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
|
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
|
-
#
|
1012
|
-
#
|
1013
|
-
#
|
1014
|
-
# @return [
|
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%),
|
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
|
-
#
|
1032
|
-
#
|
1033
|
-
#
|
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
|
-
#
|
1051
|
-
# @return [
|
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
|
-
|
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
|
-
#
|
1078
|
-
#
|
1079
|
-
#
|
1080
|
-
#
|
1081
|
-
#
|
1082
|
-
#
|
1083
|
-
#
|
1084
|
-
#
|
1085
|
-
#
|
1086
|
-
#
|
1087
|
-
#
|
1088
|
-
#
|
1089
|
-
#
|
1090
|
-
#
|
1091
|
-
#
|
1092
|
-
#
|
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
|
-
#
|
1159
|
-
#
|
1160
|
-
#
|
1161
|
-
#
|
1162
|
-
#
|
1163
|
-
#
|
1164
|
-
#
|
1165
|
-
#
|
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
|
-
|
1186
|
-
|
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
|
916
|
+
scale = val.value/100.0
|
1190
917
|
diff = scale > 0 ? max - current : current
|
1191
|
-
[name.to_sym, current + diff
|
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
|
-
#
|
1220
|
-
#
|
1221
|
-
#
|
1222
|
-
#
|
1223
|
-
#
|
1224
|
-
#
|
1225
|
-
#
|
1226
|
-
#
|
1227
|
-
#
|
1228
|
-
#
|
1229
|
-
#
|
1230
|
-
#
|
1231
|
-
#
|
1232
|
-
#
|
1233
|
-
#
|
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
|
-
|
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($
|
1287
|
-
#
|
1288
|
-
#
|
1289
|
-
#
|
1290
|
-
#
|
1291
|
-
#
|
1292
|
-
# @return [
|
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(
|
1296
|
-
assert_type
|
1297
|
-
assert_type
|
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
|
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
|
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
|
1320
|
-
# and the weight of
|
1321
|
-
p = (weight.value
|
1322
|
-
w = p
|
1323
|
-
a =
|
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)
|
1031
|
+
w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0
|
1326
1032
|
w2 = 1 - w1
|
1327
1033
|
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
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, [:
|
1333
|
-
declare :mix, [:
|
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
|
-
#
|
1341
|
-
# @return [
|
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::
|
1345
|
-
|
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
|
-
#
|
1357
|
-
# @return [
|
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,
|
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
|
-
#
|
1369
|
-
# @return [
|
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::
|
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
|
-
#
|
1393
|
-
# @return [
|
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::
|
1397
|
-
|
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
|
-
#
|
1413
|
-
# @return [
|
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
|
-
|
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
|
-
#
|
1582
|
-
# @return [
|
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
|
-
|
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
|
-
#
|
1631
|
-
# @return [
|
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
|
-
|
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
|
-
#
|
1647
|
-
# @return [
|
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
|
-
|
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($
|
1662
|
-
#
|
1663
|
-
#
|
1664
|
-
# @return [
|
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(
|
1667
|
-
assert_type
|
1668
|
-
assert_type
|
1669
|
-
|
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, [:
|
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($
|
1679
|
-
#
|
1680
|
-
# @return [
|
1681
|
-
# @raise [ArgumentError] if `$
|
1682
|
-
def percentage(
|
1683
|
-
unless
|
1684
|
-
raise ArgumentError.new("$
|
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
|
-
|
1205
|
+
Sass::Script::Number.new(value.value * 100, ['%'])
|
1687
1206
|
end
|
1688
|
-
declare :percentage, [:
|
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($
|
1696
|
-
#
|
1697
|
-
# @return [
|
1698
|
-
# @raise [ArgumentError] if `$
|
1699
|
-
def round(
|
1700
|
-
numeric_transformation(
|
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, [:
|
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($
|
1710
|
-
#
|
1711
|
-
# @return [
|
1712
|
-
# @raise [ArgumentError] if `$
|
1713
|
-
def ceil(
|
1714
|
-
numeric_transformation(
|
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, [:
|
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($
|
1724
|
-
#
|
1725
|
-
# @return [
|
1726
|
-
# @raise [ArgumentError] if `$
|
1727
|
-
def floor(
|
1728
|
-
numeric_transformation(
|
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, [:
|
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($
|
1738
|
-
#
|
1739
|
-
# @return [
|
1740
|
-
# @raise [ArgumentError] if `$
|
1741
|
-
def abs(
|
1742
|
-
numeric_transformation(
|
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, [:
|
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
|
-
#
|
1754
|
-
# @return [
|
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
|
-
#
|
1771
|
-
# @return [
|
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
|
-
#
|
1790
|
-
# @return [
|
1305
|
+
# @param $list [Literal]
|
1306
|
+
# @return [Number]
|
1791
1307
|
def length(list)
|
1792
|
-
|
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
|
-
#
|
1842
|
-
#
|
1843
|
-
#
|
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
|
-
|
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
|
-
|
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
|
-
#
|
1871
|
-
#
|
1872
|
-
#
|
1873
|
-
#
|
1874
|
-
#
|
1875
|
-
# @return [
|
1876
|
-
def join(list1, list2, separator =
|
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
|
-
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
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
|
-
#
|
1904
|
-
#
|
1905
|
-
#
|
1906
|
-
#
|
1907
|
-
#
|
1908
|
-
# @return [
|
1909
|
-
def append(list, val, separator =
|
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
|
1915
|
-
|
1916
|
-
|
1917
|
-
|
1918
|
-
|
1919
|
-
|
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
|
-
#
|
1936
|
-
# @return [
|
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
|
-
|
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
|
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) =>
|
1964
|
-
# index((width: 10px, height: 20px), (height 20px)) => 2
|
1453
|
+
# index(1px solid red, dashed) => false
|
1965
1454
|
# @overload index($list, $value)
|
1966
|
-
#
|
1967
|
-
#
|
1968
|
-
# @return [
|
1969
|
-
#
|
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
|
-
|
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
|
-
#
|
2128
|
-
#
|
2129
|
-
#
|
2130
|
-
#
|
2131
|
-
# @return [
|
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
|
-
|
1484
|
+
if_true
|
2135
1485
|
else
|
2136
|
-
|
1486
|
+
if_false
|
2137
1487
|
end
|
2138
1488
|
end
|
2139
|
-
declare :if, [:condition, :
|
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
|
-
#
|
2158
|
-
#
|
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 [
|
1500
|
+
# @return [String]
|
2194
1501
|
def counter(*args)
|
2195
|
-
|
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
|
-
#
|
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 [
|
1515
|
+
# @return [String]
|
2208
1516
|
def counters(*args)
|
2209
|
-
|
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::
|
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
|
-
|
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
|