haml 3.0.21 → 3.0.22
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of haml might be problematic. Click here for more details.
- data/Rakefile +1 -41
- data/VERSION +1 -1
- data/lib/haml/precompiler.rb +8 -6
- data/lib/haml/template/plugin.rb +16 -6
- data/lib/sass/less.rb +31 -12
- data/lib/sass/script/funcall.rb +2 -1
- data/lib/sass/script/operation.rb +10 -5
- data/lib/sass/script/parser.rb +9 -0
- data/test/haml/engine_test.rb +25 -0
- data/test/sass/less_conversion_test.rb +24 -3
- data/test/sass/script_conversion_test.rb +60 -0
- metadata +243 -426
- data/vendor/sass/CONTRIBUTING +0 -3
- data/vendor/sass/MIT-LICENSE +0 -20
- data/vendor/sass/README.md +0 -201
- data/vendor/sass/Rakefile +0 -363
- data/vendor/sass/TODO +0 -39
- data/vendor/sass/VERSION +0 -1
- data/vendor/sass/VERSION_NAME +0 -1
- data/vendor/sass/bin/css2sass +0 -13
- data/vendor/sass/bin/sass +0 -8
- data/vendor/sass/bin/sass-convert +0 -7
- data/vendor/sass/doc-src/FAQ.md +0 -35
- data/vendor/sass/doc-src/INDENTED_SYNTAX.md +0 -210
- data/vendor/sass/doc-src/SASS_CHANGELOG.md +0 -1870
- data/vendor/sass/doc-src/SASS_REFERENCE.md +0 -1713
- data/vendor/sass/doc-src/SCSS_FOR_SASS_USERS.md +0 -155
- data/vendor/sass/ext/extconf.rb +0 -10
- data/vendor/sass/extra/update_watch.rb +0 -13
- data/vendor/sass/init.rb +0 -18
- data/vendor/sass/lib/sass.rb +0 -71
- data/vendor/sass/lib/sass/cache_store.rb +0 -208
- data/vendor/sass/lib/sass/callbacks.rb +0 -66
- data/vendor/sass/lib/sass/css.rb +0 -294
- data/vendor/sass/lib/sass/engine.rb +0 -792
- data/vendor/sass/lib/sass/environment.rb +0 -143
- data/vendor/sass/lib/sass/error.rb +0 -201
- data/vendor/sass/lib/sass/exec.rb +0 -619
- data/vendor/sass/lib/sass/importers.rb +0 -22
- data/vendor/sass/lib/sass/importers/base.rb +0 -138
- data/vendor/sass/lib/sass/importers/filesystem.rb +0 -121
- data/vendor/sass/lib/sass/less.rb +0 -363
- data/vendor/sass/lib/sass/plugin.rb +0 -126
- data/vendor/sass/lib/sass/plugin/compiler.rb +0 -346
- data/vendor/sass/lib/sass/plugin/configuration.rb +0 -123
- data/vendor/sass/lib/sass/plugin/generic.rb +0 -15
- data/vendor/sass/lib/sass/plugin/merb.rb +0 -48
- data/vendor/sass/lib/sass/plugin/rack.rb +0 -47
- data/vendor/sass/lib/sass/plugin/rails.rb +0 -41
- data/vendor/sass/lib/sass/plugin/staleness_checker.rb +0 -145
- data/vendor/sass/lib/sass/railtie.rb +0 -8
- data/vendor/sass/lib/sass/repl.rb +0 -58
- data/vendor/sass/lib/sass/root.rb +0 -7
- data/vendor/sass/lib/sass/script.rb +0 -63
- data/vendor/sass/lib/sass/script/bool.rb +0 -18
- data/vendor/sass/lib/sass/script/color.rb +0 -491
- data/vendor/sass/lib/sass/script/css_lexer.rb +0 -29
- data/vendor/sass/lib/sass/script/css_parser.rb +0 -31
- data/vendor/sass/lib/sass/script/funcall.rb +0 -79
- data/vendor/sass/lib/sass/script/functions.rb +0 -852
- data/vendor/sass/lib/sass/script/interpolation.rb +0 -70
- data/vendor/sass/lib/sass/script/lexer.rb +0 -337
- data/vendor/sass/lib/sass/script/literal.rb +0 -236
- data/vendor/sass/lib/sass/script/node.rb +0 -101
- data/vendor/sass/lib/sass/script/number.rb +0 -423
- data/vendor/sass/lib/sass/script/operation.rb +0 -92
- data/vendor/sass/lib/sass/script/parser.rb +0 -392
- data/vendor/sass/lib/sass/script/string.rb +0 -67
- data/vendor/sass/lib/sass/script/string_interpolation.rb +0 -93
- data/vendor/sass/lib/sass/script/unary_operation.rb +0 -57
- data/vendor/sass/lib/sass/script/variable.rb +0 -48
- data/vendor/sass/lib/sass/scss.rb +0 -17
- data/vendor/sass/lib/sass/scss/css_parser.rb +0 -51
- data/vendor/sass/lib/sass/scss/parser.rb +0 -838
- data/vendor/sass/lib/sass/scss/rx.rb +0 -126
- data/vendor/sass/lib/sass/scss/sass_parser.rb +0 -11
- data/vendor/sass/lib/sass/scss/script_lexer.rb +0 -15
- data/vendor/sass/lib/sass/scss/script_parser.rb +0 -25
- data/vendor/sass/lib/sass/scss/static_parser.rb +0 -40
- data/vendor/sass/lib/sass/selector.rb +0 -361
- data/vendor/sass/lib/sass/selector/abstract_sequence.rb +0 -62
- data/vendor/sass/lib/sass/selector/comma_sequence.rb +0 -82
- data/vendor/sass/lib/sass/selector/sequence.rb +0 -236
- data/vendor/sass/lib/sass/selector/simple.rb +0 -113
- data/vendor/sass/lib/sass/selector/simple_sequence.rb +0 -135
- data/vendor/sass/lib/sass/shared.rb +0 -78
- data/vendor/sass/lib/sass/tree/comment_node.rb +0 -128
- data/vendor/sass/lib/sass/tree/debug_node.rb +0 -36
- data/vendor/sass/lib/sass/tree/directive_node.rb +0 -75
- data/vendor/sass/lib/sass/tree/extend_node.rb +0 -65
- data/vendor/sass/lib/sass/tree/for_node.rb +0 -67
- data/vendor/sass/lib/sass/tree/if_node.rb +0 -81
- data/vendor/sass/lib/sass/tree/import_node.rb +0 -124
- data/vendor/sass/lib/sass/tree/mixin_def_node.rb +0 -60
- data/vendor/sass/lib/sass/tree/mixin_node.rb +0 -123
- data/vendor/sass/lib/sass/tree/node.rb +0 -490
- data/vendor/sass/lib/sass/tree/prop_node.rb +0 -220
- data/vendor/sass/lib/sass/tree/root_node.rb +0 -125
- data/vendor/sass/lib/sass/tree/rule_node.rb +0 -273
- data/vendor/sass/lib/sass/tree/variable_node.rb +0 -39
- data/vendor/sass/lib/sass/tree/warn_node.rb +0 -42
- data/vendor/sass/lib/sass/tree/while_node.rb +0 -48
- data/vendor/sass/lib/sass/util.rb +0 -700
- data/vendor/sass/lib/sass/util/subset_map.rb +0 -101
- data/vendor/sass/lib/sass/version.rb +0 -109
- data/vendor/sass/rails/init.rb +0 -1
- data/vendor/sass/sass.gemspec +0 -32
- data/vendor/sass/test/sass/cache_test.rb +0 -74
- data/vendor/sass/test/sass/callbacks_test.rb +0 -61
- data/vendor/sass/test/sass/conversion_test.rb +0 -1210
- data/vendor/sass/test/sass/css2sass_test.rb +0 -364
- data/vendor/sass/test/sass/data/hsl-rgb.txt +0 -319
- data/vendor/sass/test/sass/engine_test.rb +0 -2283
- data/vendor/sass/test/sass/extend_test.rb +0 -1348
- data/vendor/sass/test/sass/functions_test.rb +0 -565
- data/vendor/sass/test/sass/importer_test.rb +0 -104
- data/vendor/sass/test/sass/less_conversion_test.rb +0 -632
- data/vendor/sass/test/sass/mock_importer.rb +0 -49
- data/vendor/sass/test/sass/more_results/more1.css +0 -9
- data/vendor/sass/test/sass/more_results/more1_with_line_comments.css +0 -26
- data/vendor/sass/test/sass/more_results/more_import.css +0 -29
- data/vendor/sass/test/sass/more_templates/_more_partial.sass +0 -2
- data/vendor/sass/test/sass/more_templates/more1.sass +0 -23
- data/vendor/sass/test/sass/more_templates/more_import.sass +0 -11
- data/vendor/sass/test/sass/plugin_test.rb +0 -430
- data/vendor/sass/test/sass/results/alt.css +0 -4
- data/vendor/sass/test/sass/results/basic.css +0 -9
- data/vendor/sass/test/sass/results/compact.css +0 -5
- data/vendor/sass/test/sass/results/complex.css +0 -86
- data/vendor/sass/test/sass/results/compressed.css +0 -1
- data/vendor/sass/test/sass/results/expanded.css +0 -19
- data/vendor/sass/test/sass/results/import.css +0 -31
- data/vendor/sass/test/sass/results/line_numbers.css +0 -49
- data/vendor/sass/test/sass/results/mixins.css +0 -95
- data/vendor/sass/test/sass/results/multiline.css +0 -24
- data/vendor/sass/test/sass/results/nested.css +0 -22
- data/vendor/sass/test/sass/results/options.css +0 -1
- data/vendor/sass/test/sass/results/parent_ref.css +0 -13
- data/vendor/sass/test/sass/results/script.css +0 -16
- data/vendor/sass/test/sass/results/scss_import.css +0 -31
- data/vendor/sass/test/sass/results/scss_importee.css +0 -2
- data/vendor/sass/test/sass/results/subdir/nested_subdir/nested_subdir.css +0 -1
- data/vendor/sass/test/sass/results/subdir/subdir.css +0 -3
- data/vendor/sass/test/sass/results/units.css +0 -11
- data/vendor/sass/test/sass/results/warn.css +0 -0
- data/vendor/sass/test/sass/results/warn_imported.css +0 -0
- data/vendor/sass/test/sass/script_conversion_test.rb +0 -254
- data/vendor/sass/test/sass/script_test.rb +0 -470
- data/vendor/sass/test/sass/scss/css_test.rb +0 -897
- data/vendor/sass/test/sass/scss/rx_test.rb +0 -156
- data/vendor/sass/test/sass/scss/scss_test.rb +0 -1088
- data/vendor/sass/test/sass/scss/test_helper.rb +0 -37
- data/vendor/sass/test/sass/templates/_partial.sass +0 -2
- data/vendor/sass/test/sass/templates/alt.sass +0 -16
- data/vendor/sass/test/sass/templates/basic.sass +0 -23
- data/vendor/sass/test/sass/templates/bork1.sass +0 -2
- data/vendor/sass/test/sass/templates/bork2.sass +0 -2
- data/vendor/sass/test/sass/templates/bork3.sass +0 -2
- data/vendor/sass/test/sass/templates/bork4.sass +0 -2
- data/vendor/sass/test/sass/templates/compact.sass +0 -17
- data/vendor/sass/test/sass/templates/complex.sass +0 -305
- data/vendor/sass/test/sass/templates/compressed.sass +0 -15
- data/vendor/sass/test/sass/templates/expanded.sass +0 -17
- data/vendor/sass/test/sass/templates/import.sass +0 -12
- data/vendor/sass/test/sass/templates/importee.less +0 -2
- data/vendor/sass/test/sass/templates/importee.sass +0 -19
- data/vendor/sass/test/sass/templates/line_numbers.sass +0 -13
- data/vendor/sass/test/sass/templates/mixin_bork.sass +0 -5
- data/vendor/sass/test/sass/templates/mixins.sass +0 -76
- data/vendor/sass/test/sass/templates/multiline.sass +0 -20
- data/vendor/sass/test/sass/templates/nested.sass +0 -25
- data/vendor/sass/test/sass/templates/nested_bork1.sass +0 -2
- data/vendor/sass/test/sass/templates/nested_bork2.sass +0 -2
- data/vendor/sass/test/sass/templates/nested_bork3.sass +0 -2
- data/vendor/sass/test/sass/templates/nested_bork4.sass +0 -2
- data/vendor/sass/test/sass/templates/nested_mixin_bork.sass +0 -6
- data/vendor/sass/test/sass/templates/options.sass +0 -2
- data/vendor/sass/test/sass/templates/parent_ref.sass +0 -25
- data/vendor/sass/test/sass/templates/script.sass +0 -101
- data/vendor/sass/test/sass/templates/scss_import.scss +0 -11
- data/vendor/sass/test/sass/templates/scss_importee.scss +0 -1
- data/vendor/sass/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +0 -2
- data/vendor/sass/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +0 -3
- data/vendor/sass/test/sass/templates/subdir/subdir.sass +0 -6
- data/vendor/sass/test/sass/templates/units.sass +0 -11
- data/vendor/sass/test/sass/templates/warn.sass +0 -3
- data/vendor/sass/test/sass/templates/warn_imported.sass +0 -4
- data/vendor/sass/test/sass/test_helper.rb +0 -8
- data/vendor/sass/test/sass/util/subset_map_test.rb +0 -91
- data/vendor/sass/test/sass/util_test.rb +0 -275
- data/vendor/sass/test/test_helper.rb +0 -64
- data/vendor/sass/yard/callbacks.rb +0 -29
- data/vendor/sass/yard/default/fulldoc/html/css/common.sass +0 -26
- data/vendor/sass/yard/default/layout/html/footer.erb +0 -12
- data/vendor/sass/yard/inherited_hash.rb +0 -41
@@ -1,29 +0,0 @@
|
|
1
|
-
module Sass
|
2
|
-
module Script
|
3
|
-
# This is a subclass of {Lexer} for use in parsing plain CSS properties.
|
4
|
-
#
|
5
|
-
# @see Sass::SCSS::CssParser
|
6
|
-
class CssLexer < Lexer
|
7
|
-
private
|
8
|
-
|
9
|
-
def token
|
10
|
-
important || super
|
11
|
-
end
|
12
|
-
|
13
|
-
def string(re, *args)
|
14
|
-
if re == :uri
|
15
|
-
return unless uri = scan(URI)
|
16
|
-
return [:string, Script::String.new(uri)]
|
17
|
-
end
|
18
|
-
|
19
|
-
return unless scan(STRING)
|
20
|
-
[:string, Script::String.new((@scanner[1] || @scanner[2]).gsub(/\\(['"])/, '\1'), :string)]
|
21
|
-
end
|
22
|
-
|
23
|
-
def important
|
24
|
-
return unless s = scan(IMPORTANT)
|
25
|
-
[:raw, s]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'sass/script'
|
2
|
-
require 'sass/script/css_lexer'
|
3
|
-
|
4
|
-
module Sass
|
5
|
-
module Script
|
6
|
-
# This is a subclass of {Parser} for use in parsing plain CSS properties.
|
7
|
-
#
|
8
|
-
# @see Sass::SCSS::CssParser
|
9
|
-
class CssParser < Parser
|
10
|
-
private
|
11
|
-
|
12
|
-
# @private
|
13
|
-
def lexer_class; CssLexer; end
|
14
|
-
|
15
|
-
# We need a production that only does /,
|
16
|
-
# since * and % aren't allowed in plain CSS
|
17
|
-
production :div, :unary_plus, :div
|
18
|
-
|
19
|
-
def string
|
20
|
-
return number unless tok = try_tok(:string)
|
21
|
-
return tok.value unless @lexer.peek && @lexer.peek.type == :begin_interpolation
|
22
|
-
end
|
23
|
-
|
24
|
-
# Short-circuit all the SassScript-only productions
|
25
|
-
alias_method :interpolation, :concat
|
26
|
-
alias_method :or_expr, :div
|
27
|
-
alias_method :unary_div, :ident
|
28
|
-
alias_method :paren, :string
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,79 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'functions')
|
2
|
-
module Sass
|
3
|
-
module Script
|
4
|
-
# A SassScript parse node representing a function call.
|
5
|
-
#
|
6
|
-
# A function call either calls one of the functions in {Script::Functions},
|
7
|
-
# or if no function with the given name exists
|
8
|
-
# it returns a string representation of the function call.
|
9
|
-
class Funcall < Node
|
10
|
-
# The name of the function.
|
11
|
-
#
|
12
|
-
# @return [String]
|
13
|
-
attr_reader :name
|
14
|
-
|
15
|
-
# The arguments to the function.
|
16
|
-
#
|
17
|
-
# @return [Array<Script::Node>]
|
18
|
-
attr_reader :args
|
19
|
-
|
20
|
-
# Don't set the context for child nodes if this is `url()`,
|
21
|
-
# since `url()` allows quoted strings.
|
22
|
-
#
|
23
|
-
# @param context [Symbol]
|
24
|
-
# @see Node#context=
|
25
|
-
def context=(context)
|
26
|
-
super unless @name == "url"
|
27
|
-
end
|
28
|
-
|
29
|
-
# @param name [String] See \{#name}
|
30
|
-
# @param name [Array<Script::Node>] See \{#args}
|
31
|
-
def initialize(name, args)
|
32
|
-
@name = name
|
33
|
-
@args = args
|
34
|
-
super()
|
35
|
-
end
|
36
|
-
|
37
|
-
# @return [String] A string representation of the function call
|
38
|
-
def inspect
|
39
|
-
"#{name}(#{args.map {|a| a.inspect}.join(', ')})"
|
40
|
-
end
|
41
|
-
|
42
|
-
# @see Node#to_sass
|
43
|
-
def to_sass(opts = {})
|
44
|
-
"#{dasherize(name, opts)}(#{args.map {|a| a.to_sass(opts)}.join(', ')})"
|
45
|
-
end
|
46
|
-
|
47
|
-
# Returns the arguments to the function.
|
48
|
-
#
|
49
|
-
# @return [Array<Node>]
|
50
|
-
# @see Node#children
|
51
|
-
def children
|
52
|
-
@args
|
53
|
-
end
|
54
|
-
|
55
|
-
protected
|
56
|
-
|
57
|
-
# Evaluates the function call.
|
58
|
-
#
|
59
|
-
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
60
|
-
# @return [Literal] The SassScript object that is the value of the function call
|
61
|
-
# @raise [Sass::SyntaxError] if the function call raises an ArgumentError
|
62
|
-
def _perform(environment)
|
63
|
-
args = self.args.map {|a| a.perform(environment)}
|
64
|
-
ruby_name = name.gsub('-', '_')
|
65
|
-
unless Sass::Util.has?(:public_instance_method, Functions, ruby_name) && ruby_name !~ /^__/
|
66
|
-
result = Script::String.new("#{name}(#{args.map {|a| a.perform(environment)}.join(', ')})")
|
67
|
-
else
|
68
|
-
result = Functions::EvaluationContext.new(environment.options).send(ruby_name, *args)
|
69
|
-
end
|
70
|
-
|
71
|
-
result.options = environment.options
|
72
|
-
return result
|
73
|
-
rescue ArgumentError => e
|
74
|
-
raise e unless e.backtrace.any? {|t| t =~ /:in `(block in )?(#{name}|perform)'$/}
|
75
|
-
raise Sass::SyntaxError.new("#{e.message} for `#{name}'")
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
@@ -1,852 +0,0 @@
|
|
1
|
-
module Sass::Script
|
2
|
-
# Methods in this module are accessible from the SassScript context.
|
3
|
-
# For example, you can write
|
4
|
-
#
|
5
|
-
# $color = hsl(120deg, 100%, 50%)
|
6
|
-
#
|
7
|
-
# and it will call {Sass::Script::Functions#hsl}.
|
8
|
-
#
|
9
|
-
# The following functions are provided:
|
10
|
-
#
|
11
|
-
# ## RGB Functions
|
12
|
-
#
|
13
|
-
# \{#rgb}
|
14
|
-
# : Converts an `rgb(red, green, blue)` triplet into a color.
|
15
|
-
#
|
16
|
-
# \{#rgba}
|
17
|
-
# : Converts an `rgba(red, green, blue, alpha)` quadruplet into a color.
|
18
|
-
#
|
19
|
-
# \{#red}
|
20
|
-
# : Gets the red component of a color.
|
21
|
-
#
|
22
|
-
# \{#green}
|
23
|
-
# : Gets the green component of a color.
|
24
|
-
#
|
25
|
-
# \{#blue}
|
26
|
-
# : Gets the blue component of a color.
|
27
|
-
#
|
28
|
-
# \{#mix}
|
29
|
-
# : Mixes two colors together.
|
30
|
-
#
|
31
|
-
# ## HSL Functions
|
32
|
-
#
|
33
|
-
# \{#hsl}
|
34
|
-
# : Converts an `hsl(hue, saturation, lightness)` triplet into a color.
|
35
|
-
#
|
36
|
-
# \{#hsla}
|
37
|
-
# : Converts an `hsla(hue, saturation, lightness, alpha)` quadruplet into a color.
|
38
|
-
#
|
39
|
-
# \{#hue}
|
40
|
-
# : Gets the hue component of a color.
|
41
|
-
#
|
42
|
-
# \{#saturation}
|
43
|
-
# : Gets the saturation component of a color.
|
44
|
-
#
|
45
|
-
# \{#lightness}
|
46
|
-
# : Gets the lightness component of a color.
|
47
|
-
#
|
48
|
-
# \{#adjust_hue #adjust-hue}
|
49
|
-
# : Changes the hue of a color.
|
50
|
-
#
|
51
|
-
# \{#lighten}
|
52
|
-
# : Makes a color lighter.
|
53
|
-
#
|
54
|
-
# \{#darken}
|
55
|
-
# : Makes a color darker.
|
56
|
-
#
|
57
|
-
# \{#saturate}
|
58
|
-
# : Makes a color more saturated.
|
59
|
-
#
|
60
|
-
# \{#desaturate}
|
61
|
-
# : Makes a color less saturated.
|
62
|
-
#
|
63
|
-
# \{#grayscale}
|
64
|
-
# : Converts a color to grayscale.
|
65
|
-
#
|
66
|
-
# \{#complement}
|
67
|
-
# : Returns the complement of a color.
|
68
|
-
#
|
69
|
-
# \{#invert}
|
70
|
-
# : Returns the inverse of a color.
|
71
|
-
#
|
72
|
-
# ## Opacity Functions
|
73
|
-
#
|
74
|
-
# \{#alpha} / \{#opacity}
|
75
|
-
# : Gets the alpha component (opacity) of a color.
|
76
|
-
#
|
77
|
-
# \{#rgba}
|
78
|
-
# : Sets the alpha component of a color.
|
79
|
-
#
|
80
|
-
# \{#opacify} / \{#fade_in #fade-in}
|
81
|
-
# : Makes a color more opaque.
|
82
|
-
#
|
83
|
-
# \{#transparentize} / \{#fade_out #fade-out}
|
84
|
-
# : Makes a color more transparent.
|
85
|
-
#
|
86
|
-
# ## String Functions
|
87
|
-
#
|
88
|
-
# \{#unquote}
|
89
|
-
# : Removes the quotes from a string.
|
90
|
-
#
|
91
|
-
# \{#quote}
|
92
|
-
# : Adds quotes to a string.
|
93
|
-
#
|
94
|
-
# ## Number Functions
|
95
|
-
#
|
96
|
-
# \{#percentage}
|
97
|
-
# : Converts a unitless number to a percentage.
|
98
|
-
#
|
99
|
-
# \{#round}
|
100
|
-
# : Rounds a number to the nearest whole number.
|
101
|
-
#
|
102
|
-
# \{#ceil}
|
103
|
-
# : Rounds a number up to the nearest whole number.
|
104
|
-
#
|
105
|
-
# \{#floor}
|
106
|
-
# : Rounds a number down to the nearest whole number.
|
107
|
-
#
|
108
|
-
# \{#abs}
|
109
|
-
# : Returns the absolute value of a number.
|
110
|
-
#
|
111
|
-
# ## Introspection Functions
|
112
|
-
#
|
113
|
-
# \{#type_of}
|
114
|
-
# : Returns the type of a value.
|
115
|
-
#
|
116
|
-
# \{#unit}
|
117
|
-
# : Returns the units associated with a number.
|
118
|
-
#
|
119
|
-
# \{#unitless}
|
120
|
-
# : Returns whether a number has units or not.
|
121
|
-
#
|
122
|
-
# \{#comparable}
|
123
|
-
# : Returns whether two numbers can be added or compared.
|
124
|
-
#
|
125
|
-
# These functions are described in more detail below.
|
126
|
-
#
|
127
|
-
# ## Adding Custom Functions
|
128
|
-
#
|
129
|
-
# New Sass functions can be added by adding Ruby methods to this module.
|
130
|
-
# For example:
|
131
|
-
#
|
132
|
-
# module Sass::Script::Functions
|
133
|
-
# def reverse(string)
|
134
|
-
# assert_type string, :String
|
135
|
-
# Sass::Script::String.new(string.value.reverse)
|
136
|
-
# end
|
137
|
-
# end
|
138
|
-
#
|
139
|
-
# There are a few things to keep in mind when modifying this module.
|
140
|
-
# First of all, the arguments passed are {Sass::Script::Literal} objects.
|
141
|
-
# Literal objects are also expected to be returned.
|
142
|
-
# This means that Ruby values must be unwrapped and wrapped.
|
143
|
-
#
|
144
|
-
# Most Literal objects support the {Sass::Script::Literal#value value} accessor
|
145
|
-
# for getting their Ruby values.
|
146
|
-
# Color objects, though, must be accessed using {Sass::Script::Color#rgb rgb},
|
147
|
-
# {Sass::Script::Color#red red}, {Sass::Script::Color#blue green}, or {Sass::Script::Color#blue blue}.
|
148
|
-
#
|
149
|
-
# Second, making Ruby functions accessible from Sass introduces the temptation
|
150
|
-
# to do things like database access within stylesheets.
|
151
|
-
# This is generally a bad idea;
|
152
|
-
# since Sass files are by default only compiled once,
|
153
|
-
# dynamic code is not a great fit.
|
154
|
-
#
|
155
|
-
# If you really, really need to compile Sass on each request,
|
156
|
-
# first make sure you have adequate caching set up.
|
157
|
-
# Then you can use {Sass::Engine} to render the code,
|
158
|
-
# using the {file:SASS_REFERENCE.md#custom-option `options` parameter}
|
159
|
-
# to pass in data that {EvaluationContext#options can be accessed}
|
160
|
-
# from your Sass functions.
|
161
|
-
#
|
162
|
-
# Within one of the functions in this module,
|
163
|
-
# methods of {EvaluationContext} can be used.
|
164
|
-
#
|
165
|
-
# ### Caveats
|
166
|
-
#
|
167
|
-
# When creating new {Literal} objects within functions,
|
168
|
-
# be aware that it's not safe to call {Literal#to_s #to_s}
|
169
|
-
# (or other methods that use the string representation)
|
170
|
-
# on those objects without first setting {Node#options= the #options attribute}.
|
171
|
-
module Functions
|
172
|
-
# The context in which methods in {Script::Functions} are evaluated.
|
173
|
-
# That means that all instance methods of {EvaluationContext}
|
174
|
-
# are available to use in functions.
|
175
|
-
class EvaluationContext
|
176
|
-
# The options hash for the {Sass::Engine} that is processing the function call
|
177
|
-
#
|
178
|
-
# @return [{Symbol => Object}]
|
179
|
-
attr_reader :options
|
180
|
-
|
181
|
-
# @param options [{Symbol => Object}] See \{#options}
|
182
|
-
def initialize(options)
|
183
|
-
@options = options
|
184
|
-
|
185
|
-
# We need to include this individually in each instance
|
186
|
-
# because of an icky Ruby restriction
|
187
|
-
class << self; include Sass::Script::Functions; end
|
188
|
-
end
|
189
|
-
|
190
|
-
# Asserts that the type of a given SassScript value
|
191
|
-
# is the expected type (designated by a symbol).
|
192
|
-
#
|
193
|
-
# Valid types are `:Bool`, `:Color`, `:Number`, and `:String`.
|
194
|
-
# Note that `:String` will match both double-quoted strings
|
195
|
-
# and unquoted identifiers.
|
196
|
-
#
|
197
|
-
# @example
|
198
|
-
# assert_type value, :String
|
199
|
-
# assert_type value, :Number
|
200
|
-
# @param value [Sass::Script::Literal] A SassScript value
|
201
|
-
# @param type [Symbol] The name of the type the value is expected to be
|
202
|
-
def assert_type(value, type)
|
203
|
-
return if value.is_a?(Sass::Script.const_get(type))
|
204
|
-
raise ArgumentError.new("#{value.inspect} is not a #{type.to_s.downcase}")
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
instance_methods.each { |m| undef_method m unless m.to_s =~ /^__/ }
|
209
|
-
|
210
|
-
|
211
|
-
# Creates a {Color} object from red, green, and blue values.
|
212
|
-
#
|
213
|
-
# @param red [Number]
|
214
|
-
# A number between 0 and 255 inclusive,
|
215
|
-
# or between 0% and 100% inclusive
|
216
|
-
# @param green [Number]
|
217
|
-
# A number between 0 and 255 inclusive,
|
218
|
-
# or between 0% and 100% inclusive
|
219
|
-
# @param blue [Number]
|
220
|
-
# A number between 0 and 255 inclusive,
|
221
|
-
# or between 0% and 100% inclusive
|
222
|
-
# @see #rgba
|
223
|
-
# @return [Color]
|
224
|
-
def rgb(red, green, blue)
|
225
|
-
assert_type red, :Number
|
226
|
-
assert_type green, :Number
|
227
|
-
assert_type blue, :Number
|
228
|
-
|
229
|
-
Color.new([red, green, blue].map do |c|
|
230
|
-
v = c.value
|
231
|
-
if c.numerator_units == ["%"] && c.denominator_units.empty?
|
232
|
-
next v * 255 / 100.0 if (0..100).include?(v)
|
233
|
-
raise ArgumentError.new("Color value #{c} must be between 0% and 100% inclusive")
|
234
|
-
else
|
235
|
-
next v if (0..255).include?(v)
|
236
|
-
raise ArgumentError.new("Color value #{v} must be between 0 and 255 inclusive")
|
237
|
-
end
|
238
|
-
end)
|
239
|
-
end
|
240
|
-
|
241
|
-
# @see #rgb
|
242
|
-
# @overload rgba(red, green, blue, alpha)
|
243
|
-
# Creates a {Color} object from red, green, and blue values,
|
244
|
-
# as well as an alpha channel indicating opacity.
|
245
|
-
#
|
246
|
-
# @param red [Number]
|
247
|
-
# A number between 0 and 255 inclusive
|
248
|
-
# @param green [Number]
|
249
|
-
# A number between 0 and 255 inclusive
|
250
|
-
# @param blue [Number]
|
251
|
-
# A number between 0 and 255 inclusive
|
252
|
-
# @param alpha [Number]
|
253
|
-
# A number between 0 and 1
|
254
|
-
# @return [Color]
|
255
|
-
#
|
256
|
-
# @overload rgba(color, alpha)
|
257
|
-
# Sets the opacity of a color.
|
258
|
-
#
|
259
|
-
# @example
|
260
|
-
# rgba(#102030, 0.5) => rgba(16, 32, 48, 0.5)
|
261
|
-
# rgba(blue, 0.2) => rgba(0, 0, 255, 0.2)
|
262
|
-
#
|
263
|
-
# @param color [Color]
|
264
|
-
# @param alpha [Number]
|
265
|
-
# A number between 0 and 1
|
266
|
-
# @return [Color]
|
267
|
-
def rgba(*args)
|
268
|
-
case args.size
|
269
|
-
when 2
|
270
|
-
color, alpha = args
|
271
|
-
|
272
|
-
assert_type color, :Color
|
273
|
-
assert_type alpha, :Number
|
274
|
-
|
275
|
-
unless (0..1).include?(alpha.value)
|
276
|
-
raise ArgumentError.new("Alpha channel #{alpha.value} must be between 0 and 1 inclusive")
|
277
|
-
end
|
278
|
-
|
279
|
-
color.with(:alpha => alpha.value)
|
280
|
-
when 4
|
281
|
-
red, green, blue, alpha = args
|
282
|
-
rgba(rgb(red, green, blue), alpha)
|
283
|
-
else
|
284
|
-
raise ArgumentError.new("wrong number of arguments (#{args.size} for 4)")
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
288
|
-
# Creates a {Color} object from hue, saturation, and lightness.
|
289
|
-
# Uses the algorithm from the [CSS3 spec](http://www.w3.org/TR/css3-color/#hsl-color).
|
290
|
-
#
|
291
|
-
# @param hue [Number] The hue of the color.
|
292
|
-
# Should be between 0 and 360 degrees, inclusive
|
293
|
-
# @param saturation [Number] The saturation of the color.
|
294
|
-
# Must be between `0%` and `100%`, inclusive
|
295
|
-
# @param lightness [Number] The lightness of the color.
|
296
|
-
# Must be between `0%` and `100%`, inclusive
|
297
|
-
# @return [Color] The resulting color
|
298
|
-
# @see #hsla
|
299
|
-
# @raise [ArgumentError] if `saturation` or `lightness` are out of bounds
|
300
|
-
def hsl(hue, saturation, lightness)
|
301
|
-
hsla(hue, saturation, lightness, Number.new(1))
|
302
|
-
end
|
303
|
-
|
304
|
-
# Creates a {Color} object from hue, saturation, and lightness,
|
305
|
-
# as well as an alpha channel indicating opacity.
|
306
|
-
# Uses the algorithm from the [CSS3 spec](http://www.w3.org/TR/css3-color/#hsl-color).
|
307
|
-
#
|
308
|
-
# @param hue [Number] The hue of the color.
|
309
|
-
# Should be between 0 and 360 degrees, inclusive
|
310
|
-
# @param saturation [Number] The saturation of the color.
|
311
|
-
# Must be between `0%` and `100%`, inclusive
|
312
|
-
# @param lightness [Number] The lightness of the color.
|
313
|
-
# Must be between `0%` and `100%`, inclusive
|
314
|
-
# @param alpha [Number] The opacity of the color.
|
315
|
-
# Must be between 0 and 1, inclusive
|
316
|
-
# @return [Color] The resulting color
|
317
|
-
# @see #hsl
|
318
|
-
# @raise [ArgumentError] if `saturation`, `lightness`, or `alpha` are out of bounds
|
319
|
-
def hsla(hue, saturation, lightness, alpha)
|
320
|
-
assert_type hue, :Number
|
321
|
-
assert_type saturation, :Number
|
322
|
-
assert_type lightness, :Number
|
323
|
-
assert_type alpha, :Number
|
324
|
-
|
325
|
-
unless (0..1).include?(alpha.value)
|
326
|
-
raise ArgumentError.new("Alpha channel #{alpha.value} must be between 0 and 1")
|
327
|
-
end
|
328
|
-
|
329
|
-
original_s = saturation
|
330
|
-
original_l = lightness
|
331
|
-
# This algorithm is from http://www.w3.org/TR/css3-color#hsl-color
|
332
|
-
h, s, l = [hue, saturation, lightness].map { |a| a.value }
|
333
|
-
raise ArgumentError.new("Saturation #{s} must be between 0% and 100%") unless (0..100).include?(s)
|
334
|
-
raise ArgumentError.new("Lightness #{l} must be between 0% and 100%") unless (0..100).include?(l)
|
335
|
-
|
336
|
-
Color.new(:hue => h, :saturation => s, :lightness => l, :alpha => alpha.value)
|
337
|
-
end
|
338
|
-
|
339
|
-
# Returns the red component of a color.
|
340
|
-
#
|
341
|
-
# @param color [Color]
|
342
|
-
# @return [Number]
|
343
|
-
# @raise [ArgumentError] If `color` isn't a color
|
344
|
-
def red(color)
|
345
|
-
assert_type color, :Color
|
346
|
-
Sass::Script::Number.new(color.red)
|
347
|
-
end
|
348
|
-
|
349
|
-
# Returns the green component of a color.
|
350
|
-
#
|
351
|
-
# @param color [Color]
|
352
|
-
# @return [Number]
|
353
|
-
# @raise [ArgumentError] If `color` isn't a color
|
354
|
-
def green(color)
|
355
|
-
assert_type color, :Color
|
356
|
-
Sass::Script::Number.new(color.green)
|
357
|
-
end
|
358
|
-
|
359
|
-
# Returns the blue component of a color.
|
360
|
-
#
|
361
|
-
# @param color [Color]
|
362
|
-
# @return [Number]
|
363
|
-
# @raise [ArgumentError] If `color` isn't a color
|
364
|
-
def blue(color)
|
365
|
-
assert_type color, :Color
|
366
|
-
Sass::Script::Number.new(color.blue)
|
367
|
-
end
|
368
|
-
|
369
|
-
# Returns the hue component of a color.
|
370
|
-
#
|
371
|
-
# See [the CSS3 HSL specification](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
|
372
|
-
#
|
373
|
-
# Calculated from RGB where necessary via [this algorithm](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
|
374
|
-
#
|
375
|
-
# @param color [Color]
|
376
|
-
# @return [Number] between 0deg and 360deg
|
377
|
-
# @see #adjust_hue
|
378
|
-
# @raise [ArgumentError] if `color` isn't a color
|
379
|
-
def hue(color)
|
380
|
-
assert_type color, :Color
|
381
|
-
Sass::Script::Number.new(color.hue, ["deg"])
|
382
|
-
end
|
383
|
-
|
384
|
-
# Returns the saturation component of a color.
|
385
|
-
#
|
386
|
-
# See [the CSS3 HSL specification](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
|
387
|
-
#
|
388
|
-
# Calculated from RGB where necessary via [this algorithm](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
|
389
|
-
#
|
390
|
-
# @param color [Color]
|
391
|
-
# @return [Number] between 0% and 100%
|
392
|
-
# @see #saturate
|
393
|
-
# @see #desaturate
|
394
|
-
# @raise [ArgumentError] if `color` isn't a color
|
395
|
-
def saturation(color)
|
396
|
-
assert_type color, :Color
|
397
|
-
Sass::Script::Number.new(color.saturation, ["%"])
|
398
|
-
end
|
399
|
-
|
400
|
-
# Returns the hue component of a color.
|
401
|
-
#
|
402
|
-
# See [the CSS3 HSL specification](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
|
403
|
-
#
|
404
|
-
# Calculated from RGB where necessary via [this algorithm](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
|
405
|
-
#
|
406
|
-
# @param color [Color]
|
407
|
-
# @return [Number] between 0% and 100%
|
408
|
-
# @see #lighten
|
409
|
-
# @see #darken
|
410
|
-
# @raise [ArgumentError] if `color` isn't a color
|
411
|
-
def lightness(color)
|
412
|
-
assert_type color, :Color
|
413
|
-
Sass::Script::Number.new(color.lightness, ["%"])
|
414
|
-
end
|
415
|
-
|
416
|
-
# Returns the alpha component (opacity) of a color.
|
417
|
-
# This is 1 unless otherwise specified.
|
418
|
-
#
|
419
|
-
# This function also supports the proprietary Microsoft
|
420
|
-
# `alpha(opacity=20)` syntax.
|
421
|
-
#
|
422
|
-
# @overload def alpha(color)
|
423
|
-
# @param color [Color]
|
424
|
-
# @return [Number]
|
425
|
-
# @see #opacify
|
426
|
-
# @see #transparentize
|
427
|
-
# @raise [ArgumentError] If `color` isn't a color
|
428
|
-
def alpha(*args)
|
429
|
-
if args.all? do |a|
|
430
|
-
a.is_a?(Sass::Script::String) && a.type == :identifier &&
|
431
|
-
a.value =~ /^[a-zA-Z]+\s*=/
|
432
|
-
end
|
433
|
-
# Support the proprietary MS alpha() function
|
434
|
-
return Sass::Script::String.new("alpha(#{args.map {|a| a.to_s}.join(", ")})")
|
435
|
-
end
|
436
|
-
|
437
|
-
opacity(*args)
|
438
|
-
end
|
439
|
-
|
440
|
-
# Returns the alpha component (opacity) of a color.
|
441
|
-
# This is 1 unless otherwise specified.
|
442
|
-
#
|
443
|
-
# @param color [Color]
|
444
|
-
# @return [Number]
|
445
|
-
# @see #opacify
|
446
|
-
# @see #transparentize
|
447
|
-
# @raise [ArgumentError] If `color` isn't a color
|
448
|
-
def opacity(color)
|
449
|
-
assert_type color, :Color
|
450
|
-
Sass::Script::Number.new(color.alpha)
|
451
|
-
end
|
452
|
-
|
453
|
-
# Makes a color more opaque.
|
454
|
-
# Takes a color and an amount between 0 and 1,
|
455
|
-
# and returns a color with the opacity increased by that value.
|
456
|
-
#
|
457
|
-
# @example
|
458
|
-
# opacify(rgba(0, 0, 0, 0.5), 0.1) => rgba(0, 0, 0, 0.6)
|
459
|
-
# opacify(rgba(0, 0, 17, 0.8), 0.2) => #001
|
460
|
-
# @param color [Color]
|
461
|
-
# @param amount [Number]
|
462
|
-
# @return [Color]
|
463
|
-
# @see #transparentize
|
464
|
-
# @raise [ArgumentError] If `color` isn't a color,
|
465
|
-
# or `number` isn't a number between 0 and 1
|
466
|
-
def opacify(color, amount)
|
467
|
-
adjust(color, amount, :alpha, 0..1, :+)
|
468
|
-
end
|
469
|
-
alias_method :fade_in, :opacify
|
470
|
-
|
471
|
-
# Makes a color more transparent.
|
472
|
-
# Takes a color and an amount between 0 and 1,
|
473
|
-
# and returns a color with the opacity decreased by that value.
|
474
|
-
#
|
475
|
-
# @example
|
476
|
-
# transparentize(rgba(0, 0, 0, 0.5), 0.1) => rgba(0, 0, 0, 0.4)
|
477
|
-
# transparentize(rgba(0, 0, 0, 0.8), 0.2) => rgba(0, 0, 0, 0.6)
|
478
|
-
# @param color [Color]
|
479
|
-
# @param amount [Number]
|
480
|
-
# @return [Color]
|
481
|
-
# @see #opacify
|
482
|
-
# @raise [ArgumentError] If `color` isn't a color,
|
483
|
-
# or `number` isn't a number between 0 and 1
|
484
|
-
def transparentize(color, amount)
|
485
|
-
adjust(color, amount, :alpha, 0..1, :-)
|
486
|
-
end
|
487
|
-
alias_method :fade_out, :transparentize
|
488
|
-
|
489
|
-
# Makes a color lighter.
|
490
|
-
# Takes a color and an amount between 0% and 100%,
|
491
|
-
# and returns a color with the lightness increased by that value.
|
492
|
-
#
|
493
|
-
# @example
|
494
|
-
# lighten(hsl(0, 0%, 0%), 30%) => hsl(0, 0, 30)
|
495
|
-
# lighten(#800, 20%) => #e00
|
496
|
-
# @param color [Color]
|
497
|
-
# @param amount [Number]
|
498
|
-
# @return [Color]
|
499
|
-
# @see #darken
|
500
|
-
# @raise [ArgumentError] If `color` isn't a color,
|
501
|
-
# or `number` isn't a number between 0% and 100%
|
502
|
-
def lighten(color, amount)
|
503
|
-
adjust(color, amount, :lightness, 0..100, :+, "%")
|
504
|
-
end
|
505
|
-
|
506
|
-
# Makes a color darker.
|
507
|
-
# Takes a color and an amount between 0% and 100%,
|
508
|
-
# and returns a color with the lightness decreased by that value.
|
509
|
-
#
|
510
|
-
# @example
|
511
|
-
# darken(hsl(25, 100%, 80%), 30%) => hsl(25, 100%, 50%)
|
512
|
-
# darken(#800, 20%) => #200
|
513
|
-
# @param color [Color]
|
514
|
-
# @param amount [Number]
|
515
|
-
# @return [Color]
|
516
|
-
# @see #lighten
|
517
|
-
# @raise [ArgumentError] If `color` isn't a color,
|
518
|
-
# or `number` isn't a number between 0% and 100%
|
519
|
-
def darken(color, amount)
|
520
|
-
adjust(color, amount, :lightness, 0..100, :-, "%")
|
521
|
-
end
|
522
|
-
|
523
|
-
# Makes a color more saturated.
|
524
|
-
# Takes a color and an amount between 0% and 100%,
|
525
|
-
# and returns a color with the saturation increased by that value.
|
526
|
-
#
|
527
|
-
# @example
|
528
|
-
# saturate(hsl(120, 30%, 90%), 20%) => hsl(120, 50%, 90%)
|
529
|
-
# saturate(#855, 20%) => #9e3f3f
|
530
|
-
# @param color [Color]
|
531
|
-
# @param amount [Number]
|
532
|
-
# @return [Color]
|
533
|
-
# @see #desaturate
|
534
|
-
# @raise [ArgumentError] If `color` isn't a color,
|
535
|
-
# or `number` isn't a number between 0% and 100%
|
536
|
-
def saturate(color, amount)
|
537
|
-
adjust(color, amount, :saturation, 0..100, :+, "%")
|
538
|
-
end
|
539
|
-
|
540
|
-
# Makes a color less saturated.
|
541
|
-
# Takes a color and an amount between 0% and 100%,
|
542
|
-
# and returns a color with the saturation decreased by that value.
|
543
|
-
#
|
544
|
-
# @example
|
545
|
-
# desaturate(hsl(120, 30%, 90%), 20%) => hsl(120, 10%, 90%)
|
546
|
-
# desaturate(#855, 20%) => #726b6b
|
547
|
-
# @param color [Color]
|
548
|
-
# @param amount [Number]
|
549
|
-
# @return [Color]
|
550
|
-
# @see #saturate
|
551
|
-
# @raise [ArgumentError] If `color` isn't a color,
|
552
|
-
# or `number` isn't a number between 0% and 100%
|
553
|
-
def desaturate(color, amount)
|
554
|
-
adjust(color, amount, :saturation, 0..100, :-, "%")
|
555
|
-
end
|
556
|
-
|
557
|
-
# Changes the hue of a color while retaining the lightness and saturation.
|
558
|
-
# Takes a color and a number of degrees (usually between -360deg and 360deg),
|
559
|
-
# and returns a color with the hue rotated by that value.
|
560
|
-
#
|
561
|
-
# @example
|
562
|
-
# adjust-hue(hsl(120, 30%, 90%), 60deg) => hsl(180, 30%, 90%)
|
563
|
-
# adjust-hue(hsl(120, 30%, 90%), 060deg) => hsl(60, 30%, 90%)
|
564
|
-
# adjust-hue(#811, 45deg) => #886a11
|
565
|
-
# @param color [Color]
|
566
|
-
# @param amount [Number]
|
567
|
-
# @return [Color]
|
568
|
-
# @raise [ArgumentError] If `color` isn't a color, or `number` isn't a number
|
569
|
-
def adjust_hue(color, degrees)
|
570
|
-
assert_type color, :Color
|
571
|
-
assert_type degrees, :Number
|
572
|
-
color.with(:hue => color.hue + degrees.value)
|
573
|
-
end
|
574
|
-
|
575
|
-
# Mixes together two colors.
|
576
|
-
# Specifically, takes the average of each of the RGB components,
|
577
|
-
# optionally weighted by the given percentage.
|
578
|
-
# The opacity of the colors is also considered when weighting the components.
|
579
|
-
#
|
580
|
-
# The weight specifies the amount of the first color that should be included
|
581
|
-
# in the returned color.
|
582
|
-
# The default, 50%, means that half the first color
|
583
|
-
# and half the second color should be used.
|
584
|
-
# 25% means that a quarter of the first color
|
585
|
-
# and three quarters of the second color should be used.
|
586
|
-
#
|
587
|
-
# @example
|
588
|
-
# mix(#f00, #00f) => #7f007f
|
589
|
-
# mix(#f00, #00f, 25%) => #3f00bf
|
590
|
-
# mix(rgba(255, 0, 0, 0.5), #00f) => rgba(63, 0, 191, 0.75)
|
591
|
-
# @overload mix(color1, color2, weight = 50%)
|
592
|
-
# @param color1 [Color]
|
593
|
-
# @param color2 [Color]
|
594
|
-
# @param weight [Number] between 0% and 100%
|
595
|
-
# @return [Color]
|
596
|
-
# @raise [ArgumentError] if `color1` or `color2` aren't colors,
|
597
|
-
# or `weight` isn't a number between 0% and 100%
|
598
|
-
def mix(color1, color2, weight = Number.new(50))
|
599
|
-
assert_type color1, :Color
|
600
|
-
assert_type color2, :Color
|
601
|
-
assert_type weight, :Number
|
602
|
-
|
603
|
-
unless (0..100).include?(weight.value)
|
604
|
-
raise ArgumentError.new("Weight #{weight} must be between 0% and 100%")
|
605
|
-
end
|
606
|
-
|
607
|
-
# This algorithm factors in both the user-provided weight
|
608
|
-
# and the difference between the alpha values of the two colors
|
609
|
-
# to decide how to perform the weighted average of the two RGB values.
|
610
|
-
#
|
611
|
-
# It works by first normalizing both parameters to be within [-1, 1],
|
612
|
-
# where 1 indicates "only use color1", -1 indicates "only use color 0",
|
613
|
-
# and all values in between indicated a proportionately weighted average.
|
614
|
-
#
|
615
|
-
# Once we have the normalized variables w and a,
|
616
|
-
# we apply the formula (w + a)/(1 + w*a)
|
617
|
-
# to get the combined weight (in [-1, 1]) of color1.
|
618
|
-
# This formula has two especially nice properties:
|
619
|
-
#
|
620
|
-
# * When either w or a are -1 or 1, the combined weight is also that number
|
621
|
-
# (cases where w * a == -1 are undefined, and handled as a special case).
|
622
|
-
#
|
623
|
-
# * When a is 0, the combined weight is w, and vice versa
|
624
|
-
#
|
625
|
-
# Finally, the weight of color1 is renormalized to be within [0, 1]
|
626
|
-
# and the weight of color2 is given by 1 minus the weight of color1.
|
627
|
-
p = weight.value/100.0
|
628
|
-
w = p*2 - 1
|
629
|
-
a = color1.alpha - color2.alpha
|
630
|
-
|
631
|
-
w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0
|
632
|
-
w2 = 1 - w1
|
633
|
-
|
634
|
-
rgb = color1.rgb.zip(color2.rgb).map {|v1, v2| v1*w1 + v2*w2}
|
635
|
-
alpha = color1.alpha*p + color2.alpha*(1-p)
|
636
|
-
Color.new(rgb + [alpha])
|
637
|
-
end
|
638
|
-
|
639
|
-
# Converts a color to grayscale.
|
640
|
-
# This is identical to `desaturate(color, 100%)`.
|
641
|
-
#
|
642
|
-
# @param color [Color]
|
643
|
-
# @return [Color]
|
644
|
-
# @raise [ArgumentError] if `color` isn't a color
|
645
|
-
# @see #desaturate
|
646
|
-
def grayscale(color)
|
647
|
-
desaturate color, Number.new(100)
|
648
|
-
end
|
649
|
-
|
650
|
-
# Returns the complement of a color.
|
651
|
-
# This is identical to `adjust-hue(color, 180deg)`.
|
652
|
-
#
|
653
|
-
# @param color [Color]
|
654
|
-
# @return [Color]
|
655
|
-
# @raise [ArgumentError] if `color` isn't a color
|
656
|
-
# @see #adjust_hue #adjust-hue
|
657
|
-
def complement(color)
|
658
|
-
adjust_hue color, Number.new(180)
|
659
|
-
end
|
660
|
-
|
661
|
-
# Returns the inverse (negative) of a color.
|
662
|
-
# The red, green, and blue values are inverted, while the opacity is left alone.
|
663
|
-
#
|
664
|
-
# @param color [Color]
|
665
|
-
# @return [Color]
|
666
|
-
# @raise [ArgumentError] if `color` isn't a color
|
667
|
-
def invert(color)
|
668
|
-
assert_type color, :Color
|
669
|
-
color.with(
|
670
|
-
:red => (255 - color.red),
|
671
|
-
:green => (255 - color.green),
|
672
|
-
:blue => (255 - color.blue))
|
673
|
-
end
|
674
|
-
|
675
|
-
# Removes quotes from a string if the string is quoted,
|
676
|
-
# or returns the same string if it's not.
|
677
|
-
#
|
678
|
-
# @param str [String]
|
679
|
-
# @return [String]
|
680
|
-
# @raise [ArgumentError] if `str` isn't a string
|
681
|
-
# @see #quote
|
682
|
-
# @example
|
683
|
-
# unquote("foo") => foo
|
684
|
-
# unquote(foo) => foo
|
685
|
-
def unquote(str)
|
686
|
-
assert_type str, :String
|
687
|
-
Sass::Script::String.new(str.value, :identifier)
|
688
|
-
end
|
689
|
-
|
690
|
-
# Add quotes to a string if the string isn't quoted,
|
691
|
-
# or returns the same string if it is.
|
692
|
-
#
|
693
|
-
# @param str [String]
|
694
|
-
# @return [String]
|
695
|
-
# @raise [ArgumentError] if `str` isn't a string
|
696
|
-
# @see #unquote
|
697
|
-
# @example
|
698
|
-
# quote("foo") => "foo"
|
699
|
-
# quote(foo) => "foo"
|
700
|
-
def quote(str)
|
701
|
-
assert_type str, :String
|
702
|
-
Sass::Script::String.new(str.value, :string)
|
703
|
-
end
|
704
|
-
|
705
|
-
# Inspects the type of the argument, returning it as an unquoted string.
|
706
|
-
#
|
707
|
-
# @example
|
708
|
-
# type-of(100px) => number
|
709
|
-
# type-of(asdf) => string
|
710
|
-
# type-of("asdf") => string
|
711
|
-
# type-of(true) => bool
|
712
|
-
# type-of(#fff) => color
|
713
|
-
# type-of(blue) => color
|
714
|
-
# @param obj [Literal] The object to inspect
|
715
|
-
# @return [String] The unquoted string name of the literal's type
|
716
|
-
def type_of(obj)
|
717
|
-
Sass::Script::String.new(obj.class.name.gsub(/Sass::Script::/,'').downcase)
|
718
|
-
end
|
719
|
-
|
720
|
-
# Inspects the unit of the number, returning it as a quoted string.
|
721
|
-
# Complex units are sorted in alphabetical order by numerator and denominator.
|
722
|
-
#
|
723
|
-
# @example
|
724
|
-
# unit(100) => ""
|
725
|
-
# unit(100px) => "px"
|
726
|
-
# unit(3em) => "em"
|
727
|
-
# unit(10px * 5em) => "em*px"
|
728
|
-
# unit(10px * 5em / 30cm / 1rem) => "em*px/cm*rem"
|
729
|
-
# @param number [Literal] The number to inspect
|
730
|
-
# @return [String] The unit(s) of the number
|
731
|
-
# @raise [ArgumentError] if `number` isn't a number
|
732
|
-
def unit(number)
|
733
|
-
assert_type number, :Number
|
734
|
-
Sass::Script::String.new(number.unit_str, :string)
|
735
|
-
end
|
736
|
-
|
737
|
-
# Inspects the unit of the number, returning a boolean indicating if it is unitless.
|
738
|
-
#
|
739
|
-
# @example
|
740
|
-
# unitless(100) => true
|
741
|
-
# unitless(100px) => false
|
742
|
-
# @param number [Literal] The number to inspect
|
743
|
-
# @return [Bool] Whether or not the number is unitless
|
744
|
-
# @raise [ArgumentError] if `number` isn't a number
|
745
|
-
def unitless(number)
|
746
|
-
assert_type number, :Number
|
747
|
-
Sass::Script::Bool.new(number.unitless?)
|
748
|
-
end
|
749
|
-
|
750
|
-
# Returns true if two numbers are similar enough to be added, subtracted, or compared.
|
751
|
-
#
|
752
|
-
# @example
|
753
|
-
# comparable(2px, 1px) => true
|
754
|
-
# comparable(100px, 3em) => false
|
755
|
-
# comparable(10cm, 3mm) => true
|
756
|
-
# @param number1 [Number]
|
757
|
-
# @param number2 [Number]
|
758
|
-
# @return [Bool] indicating if the numbers can be compared.
|
759
|
-
# @raise [ArgumentError] if `number1` or `number2` aren't numbers
|
760
|
-
def comparable(number1, number2)
|
761
|
-
assert_type number1, :Number
|
762
|
-
assert_type number2, :Number
|
763
|
-
Sass::Script::Bool.new(number1.comparable_to?(number2))
|
764
|
-
end
|
765
|
-
|
766
|
-
# Converts a decimal number to a percentage.
|
767
|
-
#
|
768
|
-
# @example
|
769
|
-
# percentage(100px / 50px) => 200%
|
770
|
-
# @param value [Number] The decimal number to convert to a percentage
|
771
|
-
# @return [Number] The percentage
|
772
|
-
# @raise [ArgumentError] If `value` isn't a unitless number
|
773
|
-
def percentage(value)
|
774
|
-
unless value.is_a?(Sass::Script::Number) && value.unitless?
|
775
|
-
raise ArgumentError.new("#{value.inspect} is not a unitless number")
|
776
|
-
end
|
777
|
-
Sass::Script::Number.new(value.value * 100, ['%'])
|
778
|
-
end
|
779
|
-
|
780
|
-
# Rounds a number to the nearest whole number.
|
781
|
-
#
|
782
|
-
# @example
|
783
|
-
# round(10.4px) => 10px
|
784
|
-
# round(10.6px) => 11px
|
785
|
-
# @param value [Number] The number
|
786
|
-
# @return [Number] The rounded number
|
787
|
-
# @raise [Sass::SyntaxError] if `value` isn't a number
|
788
|
-
def round(value)
|
789
|
-
numeric_transformation(value) {|n| n.round}
|
790
|
-
end
|
791
|
-
|
792
|
-
# Rounds a number up to the nearest whole number.
|
793
|
-
#
|
794
|
-
# @example
|
795
|
-
# ciel(10.4px) => 11px
|
796
|
-
# ciel(10.6px) => 11px
|
797
|
-
# @param value [Number] The number
|
798
|
-
# @return [Number] The rounded number
|
799
|
-
# @raise [Sass::SyntaxError] if `value` isn't a number
|
800
|
-
def ceil(value)
|
801
|
-
numeric_transformation(value) {|n| n.ceil}
|
802
|
-
end
|
803
|
-
|
804
|
-
# Rounds down to the nearest whole number.
|
805
|
-
#
|
806
|
-
# @example
|
807
|
-
# floor(10.4px) => 10px
|
808
|
-
# floor(10.6px) => 10px
|
809
|
-
# @param value [Number] The number
|
810
|
-
# @return [Number] The rounded number
|
811
|
-
# @raise [Sass::SyntaxError] if `value` isn't a number
|
812
|
-
def floor(value)
|
813
|
-
numeric_transformation(value) {|n| n.floor}
|
814
|
-
end
|
815
|
-
|
816
|
-
# Finds the absolute value of a number.
|
817
|
-
#
|
818
|
-
# @example
|
819
|
-
# abs(10px) => 10px
|
820
|
-
# abs(-10px) => 10px
|
821
|
-
# @param value [Number] The number
|
822
|
-
# @return [Number] The absolute value
|
823
|
-
# @raise [Sass::SyntaxError] if `value` isn't a number
|
824
|
-
def abs(value)
|
825
|
-
numeric_transformation(value) {|n| n.abs}
|
826
|
-
end
|
827
|
-
|
828
|
-
private
|
829
|
-
|
830
|
-
# This method implements the pattern of transforming a numeric value into
|
831
|
-
# another numeric value with the same units.
|
832
|
-
# It yields a number to a block to perform the operation and return a number
|
833
|
-
def numeric_transformation(value)
|
834
|
-
assert_type value, :Number
|
835
|
-
Sass::Script::Number.new(yield(value.value), value.numerator_units, value.denominator_units)
|
836
|
-
end
|
837
|
-
|
838
|
-
def adjust(color, amount, attr, range, op, units = "")
|
839
|
-
assert_type color, :Color
|
840
|
-
assert_type amount, :Number
|
841
|
-
unless range.include?(amount.value)
|
842
|
-
raise ArgumentError.new("Amount #{amount} must be between #{range.first}#{units} and #{range.last}#{units}")
|
843
|
-
end
|
844
|
-
|
845
|
-
# TODO: is it worth restricting here,
|
846
|
-
# or should we do so in the Color constructor itself,
|
847
|
-
# and allow clipping in rgb() et al?
|
848
|
-
color.with(attr => Sass::Util.restrict(
|
849
|
-
color.send(attr).send(op, amount.value), range))
|
850
|
-
end
|
851
|
-
end
|
852
|
-
end
|