oreorenasass 3.4.4 → 3.4.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,221 @@
|
|
1
|
+
module Sass::Script
|
2
|
+
# The abstract superclass for SassScript objects.
|
3
|
+
#
|
4
|
+
# Many of these methods, especially the ones that correspond to SassScript operations,
|
5
|
+
# are designed to be overridden by subclasses which may change the semantics somewhat.
|
6
|
+
# The operations listed here are just the defaults.
|
7
|
+
class Literal < Node
|
8
|
+
require 'sass/script/string'
|
9
|
+
require 'sass/script/number'
|
10
|
+
require 'sass/script/color'
|
11
|
+
require 'sass/script/bool'
|
12
|
+
require 'sass/script/null'
|
13
|
+
require 'sass/script/list'
|
14
|
+
require 'sass/script/arg_list'
|
15
|
+
|
16
|
+
# Returns the Ruby value of the literal.
|
17
|
+
# The type of this value varies based on the subclass.
|
18
|
+
#
|
19
|
+
# @return [Object]
|
20
|
+
attr_reader :value
|
21
|
+
|
22
|
+
# Creates a new literal.
|
23
|
+
#
|
24
|
+
# @param value [Object] The object for \{#value}
|
25
|
+
def initialize(value = nil)
|
26
|
+
@value = value
|
27
|
+
super()
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns an empty array.
|
31
|
+
#
|
32
|
+
# @return [Array<Node>] empty
|
33
|
+
# @see Node#children
|
34
|
+
def children
|
35
|
+
[]
|
36
|
+
end
|
37
|
+
|
38
|
+
# @see Node#deep_copy
|
39
|
+
def deep_copy
|
40
|
+
dup
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the options hash for this node.
|
44
|
+
#
|
45
|
+
# @return [{Symbol => Object}]
|
46
|
+
# @raise [Sass::SyntaxError] if the options hash hasn't been set.
|
47
|
+
# This should only happen when the literal was created
|
48
|
+
# outside of the parser and \{#to\_s} was called on it
|
49
|
+
def options
|
50
|
+
opts = super
|
51
|
+
return opts if opts
|
52
|
+
raise Sass::SyntaxError.new(<<MSG)
|
53
|
+
The #options attribute is not set on this #{self.class}.
|
54
|
+
This error is probably occurring because #to_s was called
|
55
|
+
on this literal within a custom Sass function without first
|
56
|
+
setting the #option attribute.
|
57
|
+
MSG
|
58
|
+
end
|
59
|
+
|
60
|
+
# The SassScript `==` operation.
|
61
|
+
# **Note that this returns a {Sass::Script::Bool} object,
|
62
|
+
# not a Ruby boolean**.
|
63
|
+
#
|
64
|
+
# @param other [Literal] The right-hand side of the operator
|
65
|
+
# @return [Bool] True if this literal is the same as the other,
|
66
|
+
# false otherwise
|
67
|
+
def eq(other)
|
68
|
+
Sass::Script::Bool.new(self.class == other.class && self.value == other.value)
|
69
|
+
end
|
70
|
+
|
71
|
+
# The SassScript `!=` operation.
|
72
|
+
# **Note that this returns a {Sass::Script::Bool} object,
|
73
|
+
# not a Ruby boolean**.
|
74
|
+
#
|
75
|
+
# @param other [Literal] The right-hand side of the operator
|
76
|
+
# @return [Bool] False if this literal is the same as the other,
|
77
|
+
# true otherwise
|
78
|
+
def neq(other)
|
79
|
+
Sass::Script::Bool.new(!eq(other).to_bool)
|
80
|
+
end
|
81
|
+
|
82
|
+
# The SassScript `==` operation.
|
83
|
+
# **Note that this returns a {Sass::Script::Bool} object,
|
84
|
+
# not a Ruby boolean**.
|
85
|
+
#
|
86
|
+
# @param other [Literal] The right-hand side of the operator
|
87
|
+
# @return [Bool] True if this literal is the same as the other,
|
88
|
+
# false otherwise
|
89
|
+
def unary_not
|
90
|
+
Sass::Script::Bool.new(!to_bool)
|
91
|
+
end
|
92
|
+
|
93
|
+
# The SassScript `=` operation
|
94
|
+
# (used for proprietary MS syntax like `alpha(opacity=20)`).
|
95
|
+
#
|
96
|
+
# @param other [Literal] The right-hand side of the operator
|
97
|
+
# @return [Script::String] A string containing both literals
|
98
|
+
# separated by `"="`
|
99
|
+
def single_eq(other)
|
100
|
+
Sass::Script::String.new("#{self.to_s}=#{other.to_s}")
|
101
|
+
end
|
102
|
+
|
103
|
+
# The SassScript `+` operation.
|
104
|
+
#
|
105
|
+
# @param other [Literal] The right-hand side of the operator
|
106
|
+
# @return [Script::String] A string containing both literals
|
107
|
+
# without any separation
|
108
|
+
def plus(other)
|
109
|
+
if other.is_a?(Sass::Script::String)
|
110
|
+
return Sass::Script::String.new(self.to_s + other.value, other.type)
|
111
|
+
end
|
112
|
+
Sass::Script::String.new(self.to_s + other.to_s)
|
113
|
+
end
|
114
|
+
|
115
|
+
# The SassScript `-` operation.
|
116
|
+
#
|
117
|
+
# @param other [Literal] The right-hand side of the operator
|
118
|
+
# @return [Script::String] A string containing both literals
|
119
|
+
# separated by `"-"`
|
120
|
+
def minus(other)
|
121
|
+
Sass::Script::String.new("#{self.to_s}-#{other.to_s}")
|
122
|
+
end
|
123
|
+
|
124
|
+
# The SassScript `/` operation.
|
125
|
+
#
|
126
|
+
# @param other [Literal] The right-hand side of the operator
|
127
|
+
# @return [Script::String] A string containing both literals
|
128
|
+
# separated by `"/"`
|
129
|
+
def div(other)
|
130
|
+
Sass::Script::String.new("#{self.to_s}/#{other.to_s}")
|
131
|
+
end
|
132
|
+
|
133
|
+
# The SassScript unary `+` operation (e.g. `+$a`).
|
134
|
+
#
|
135
|
+
# @param other [Literal] The right-hand side of the operator
|
136
|
+
# @return [Script::String] A string containing the literal
|
137
|
+
# preceded by `"+"`
|
138
|
+
def unary_plus
|
139
|
+
Sass::Script::String.new("+#{self.to_s}")
|
140
|
+
end
|
141
|
+
|
142
|
+
# The SassScript unary `-` operation (e.g. `-$a`).
|
143
|
+
#
|
144
|
+
# @param other [Literal] The right-hand side of the operator
|
145
|
+
# @return [Script::String] A string containing the literal
|
146
|
+
# preceded by `"-"`
|
147
|
+
def unary_minus
|
148
|
+
Sass::Script::String.new("-#{self.to_s}")
|
149
|
+
end
|
150
|
+
|
151
|
+
# The SassScript unary `/` operation (e.g. `/$a`).
|
152
|
+
#
|
153
|
+
# @param other [Literal] The right-hand side of the operator
|
154
|
+
# @return [Script::String] A string containing the literal
|
155
|
+
# preceded by `"/"`
|
156
|
+
def unary_div
|
157
|
+
Sass::Script::String.new("/#{self.to_s}")
|
158
|
+
end
|
159
|
+
|
160
|
+
# @return [String] A readable representation of the literal
|
161
|
+
def inspect
|
162
|
+
value.inspect
|
163
|
+
end
|
164
|
+
|
165
|
+
# @return [Boolean] `true` (the Ruby boolean value)
|
166
|
+
def to_bool
|
167
|
+
true
|
168
|
+
end
|
169
|
+
|
170
|
+
# Compares this object with another.
|
171
|
+
#
|
172
|
+
# @param other [Object] The object to compare with
|
173
|
+
# @return [Boolean] Whether or not this literal is equivalent to `other`
|
174
|
+
def ==(other)
|
175
|
+
eq(other).to_bool
|
176
|
+
end
|
177
|
+
|
178
|
+
# @return [Fixnum] The integer value of this literal
|
179
|
+
# @raise [Sass::SyntaxError] if this literal isn't an integer
|
180
|
+
def to_i
|
181
|
+
raise Sass::SyntaxError.new("#{self.inspect} is not an integer.")
|
182
|
+
end
|
183
|
+
|
184
|
+
# @raise [Sass::SyntaxError] if this literal isn't an integer
|
185
|
+
def assert_int!; to_i; end
|
186
|
+
|
187
|
+
# Returns the value of this literal as a list.
|
188
|
+
# Single literals are considered the same as single-element lists.
|
189
|
+
#
|
190
|
+
# @return [Array<Literal>] The of this literal as a list
|
191
|
+
def to_a
|
192
|
+
[self]
|
193
|
+
end
|
194
|
+
|
195
|
+
# Returns the string representation of this literal
|
196
|
+
# as it would be output to the CSS document.
|
197
|
+
#
|
198
|
+
# @return [String]
|
199
|
+
def to_s(opts = {})
|
200
|
+
raise Sass::SyntaxError.new("[BUG] All subclasses of Sass::Literal must implement #to_s.")
|
201
|
+
end
|
202
|
+
alias_method :to_sass, :to_s
|
203
|
+
|
204
|
+
# Returns whether or not this object is null.
|
205
|
+
#
|
206
|
+
# @return [Boolean] `false`
|
207
|
+
def null?
|
208
|
+
false
|
209
|
+
end
|
210
|
+
|
211
|
+
protected
|
212
|
+
|
213
|
+
# Evaluates the literal.
|
214
|
+
#
|
215
|
+
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
216
|
+
# @return [Literal] This literal
|
217
|
+
def _perform(environment)
|
218
|
+
self
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Sass::Script
|
1
|
+
module Sass::Script
|
2
2
|
# The abstract superclass for SassScript parse tree nodes.
|
3
3
|
#
|
4
4
|
# Use \{#perform} to evaluate a parse tree.
|
@@ -13,16 +13,6 @@ module Sass::Script::Tree
|
|
13
13
|
# @return [Fixnum]
|
14
14
|
attr_accessor :line
|
15
15
|
|
16
|
-
# The source range in the document on which this node appeared.
|
17
|
-
#
|
18
|
-
# @return [Sass::Source::Range]
|
19
|
-
attr_accessor :source_range
|
20
|
-
|
21
|
-
# The file name of the document on which this node appeared.
|
22
|
-
#
|
23
|
-
# @return [String]
|
24
|
-
attr_accessor :filename
|
25
|
-
|
26
16
|
# Sets the options hash for this node,
|
27
17
|
# as well as for all child nodes.
|
28
18
|
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
@@ -32,7 +22,7 @@ module Sass::Script::Tree
|
|
32
22
|
@options = options
|
33
23
|
children.each do |c|
|
34
24
|
if c.is_a? Hash
|
35
|
-
c.values.each {|v| v.options = options}
|
25
|
+
c.values.each {|v| v.options = options }
|
36
26
|
else
|
37
27
|
c.options = options
|
38
28
|
end
|
@@ -45,7 +35,7 @@ module Sass::Script::Tree
|
|
45
35
|
# instead, override \{#\_perform}.
|
46
36
|
#
|
47
37
|
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
48
|
-
# @return [
|
38
|
+
# @return [Literal] The SassScript object that is the value of the SassScript
|
49
39
|
def perform(environment)
|
50
40
|
_perform(environment)
|
51
41
|
rescue Sass::SyntaxError => e
|
@@ -80,30 +70,30 @@ module Sass::Script::Tree
|
|
80
70
|
# Converts underscores to dashes if the :dasherize option is set.
|
81
71
|
def dasherize(s, opts)
|
82
72
|
if opts[:dasherize]
|
83
|
-
s.gsub(/_/,
|
73
|
+
s.gsub(/_/,'-')
|
84
74
|
else
|
85
75
|
s
|
86
76
|
end
|
87
77
|
end
|
88
78
|
|
89
79
|
# Evaluates this node.
|
90
|
-
# Note that all {
|
80
|
+
# Note that all {Literal} objects created within this method
|
91
81
|
# should have their \{#options} attribute set, probably via \{#opts}.
|
92
82
|
#
|
93
83
|
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
94
|
-
# @return [
|
84
|
+
# @return [Literal] The SassScript object that is the value of the SassScript
|
95
85
|
# @see #perform
|
96
86
|
def _perform(environment)
|
97
87
|
Sass::Util.abstract(self)
|
98
88
|
end
|
99
89
|
|
100
|
-
# Sets the \{#options} field on the given
|
90
|
+
# Sets the \{#options} field on the given literal and returns it
|
101
91
|
#
|
102
|
-
# @param
|
103
|
-
# @return [
|
104
|
-
def opts(
|
105
|
-
|
106
|
-
|
92
|
+
# @param literal [Literal]
|
93
|
+
# @return [Literal]
|
94
|
+
def opts(literal)
|
95
|
+
literal.options = options
|
96
|
+
literal
|
107
97
|
end
|
108
98
|
end
|
109
99
|
end
|
@@ -1,18 +1,11 @@
|
|
1
|
-
|
2
|
-
# A SassScript object representing a null value.
|
3
|
-
class Null < Base
|
4
|
-
# The null value in SassScript.
|
5
|
-
#
|
6
|
-
# This is assigned before new is overridden below so that we use the default implementation.
|
7
|
-
NULL = new(nil)
|
1
|
+
require 'sass/script/literal'
|
8
2
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
NULL
|
3
|
+
module Sass::Script
|
4
|
+
# A SassScript object representing a null value.
|
5
|
+
class Null < Literal
|
6
|
+
# Creates a new null literal.
|
7
|
+
def initialize
|
8
|
+
super nil
|
16
9
|
end
|
17
10
|
|
18
11
|
# @return [Boolean] `false` (the Ruby boolean value)
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
require 'sass/script/literal'
|
2
|
+
|
3
|
+
module Sass::Script
|
2
4
|
# A SassScript object representing a number.
|
3
5
|
# SassScript numbers can have decimal values,
|
4
6
|
# and can also have units.
|
@@ -7,7 +9,7 @@ module Sass::Script::Value
|
|
7
9
|
#
|
8
10
|
# Numbers can also have more complex units, such as `1px*em/in`.
|
9
11
|
# These cannot be inputted directly in Sass code at the moment.
|
10
|
-
class Number <
|
12
|
+
class Number < Literal
|
11
13
|
# The Ruby value of the number.
|
12
14
|
#
|
13
15
|
# @return [Numeric]
|
@@ -15,7 +17,7 @@ module Sass::Script::Value
|
|
15
17
|
|
16
18
|
# A list of units in the numerator of the number.
|
17
19
|
# For example, `1px*em/in*cm` would return `["px", "em"]`
|
18
|
-
# @return [Array<String>]
|
20
|
+
# @return [Array<String>]
|
19
21
|
attr_reader :numerator_units
|
20
22
|
|
21
23
|
# A list of units in the denominator of the number.
|
@@ -51,15 +53,24 @@ module Sass::Script::Value
|
|
51
53
|
@precision_factor ||= 10.0**precision
|
52
54
|
end
|
53
55
|
|
56
|
+
# Handles the deprecation warning for the PRECISION constant
|
57
|
+
# This can be removed in 3.2.
|
58
|
+
def self.const_missing(const)
|
59
|
+
if const == :PRECISION
|
60
|
+
Sass::Util.sass_warn("Sass::Script::Number::PRECISION is deprecated and will be removed in a future release. Use Sass::Script::Number.precision_factor instead.")
|
61
|
+
const_set(:PRECISION, self.precision_factor)
|
62
|
+
else
|
63
|
+
super
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
54
67
|
# Used so we don't allocate two new arrays for each new number.
|
55
68
|
NO_UNITS = []
|
56
69
|
|
57
70
|
# @param value [Numeric] The value of the number
|
58
|
-
# @param numerator_units [
|
59
|
-
# @param denominator_units [
|
71
|
+
# @param numerator_units [Array<String>] See \{#numerator\_units}
|
72
|
+
# @param denominator_units [Array<String>] See \{#denominator\_units}
|
60
73
|
def initialize(value, numerator_units = NO_UNITS, denominator_units = NO_UNITS)
|
61
|
-
numerator_units = [numerator_units] if numerator_units.is_a?(::String)
|
62
|
-
denominator_units = [denominator_units] if denominator_units.is_a?(::String)
|
63
74
|
super(value)
|
64
75
|
@numerator_units = numerator_units
|
65
76
|
@denominator_units = denominator_units
|
@@ -75,11 +86,11 @@ module Sass::Script::Value
|
|
75
86
|
# {Color}
|
76
87
|
# : Adds this number to each of the RGB color channels.
|
77
88
|
#
|
78
|
-
# {
|
79
|
-
# : See {
|
89
|
+
# {Literal}
|
90
|
+
# : See {Literal#plus}.
|
80
91
|
#
|
81
|
-
# @param other [
|
82
|
-
# @return [
|
92
|
+
# @param other [Literal] The right-hand side of the operator
|
93
|
+
# @return [Literal] The result of the operation
|
83
94
|
# @raise [Sass::UnitConversionError] if `other` is a number with incompatible units
|
84
95
|
def plus(other)
|
85
96
|
if other.is_a? Number
|
@@ -97,11 +108,11 @@ module Sass::Script::Value
|
|
97
108
|
# {Number}
|
98
109
|
# : Subtracts this number from the other, converting units if possible.
|
99
110
|
#
|
100
|
-
# {
|
101
|
-
# : See {
|
111
|
+
# {Literal}
|
112
|
+
# : See {Literal#minus}.
|
102
113
|
#
|
103
|
-
# @param other [
|
104
|
-
# @return [
|
114
|
+
# @param other [Literal] The right-hand side of the operator
|
115
|
+
# @return [Literal] The result of the operation
|
105
116
|
# @raise [Sass::UnitConversionError] if `other` is a number with incompatible units
|
106
117
|
def minus(other)
|
107
118
|
if other.is_a? Number
|
@@ -153,16 +164,16 @@ module Sass::Script::Value
|
|
153
164
|
# {Number}
|
154
165
|
# : Divides this number by the other, converting units appropriately.
|
155
166
|
#
|
156
|
-
# {
|
157
|
-
# : See {
|
167
|
+
# {Literal}
|
168
|
+
# : See {Literal#div}.
|
158
169
|
#
|
159
|
-
# @param other [
|
160
|
-
# @return [
|
170
|
+
# @param other [Literal] The right-hand side of the operator
|
171
|
+
# @return [Literal] The result of the operation
|
161
172
|
def div(other)
|
162
173
|
if other.is_a? Number
|
163
174
|
res = operate(other, :/)
|
164
|
-
if original && other.original
|
165
|
-
res.original = "#{original}/#{other.original}"
|
175
|
+
if self.original && other.original
|
176
|
+
res.original = "#{self.original}/#{other.original}"
|
166
177
|
end
|
167
178
|
res
|
168
179
|
else
|
@@ -175,9 +186,12 @@ module Sass::Script::Value
|
|
175
186
|
# @param other [Number] The right-hand side of the operator
|
176
187
|
# @return [Number] This number modulo the other
|
177
188
|
# @raise [NoMethodError] if `other` is an invalid type
|
178
|
-
# @raise [Sass::UnitConversionError] if `other` has
|
189
|
+
# @raise [Sass::UnitConversionError] if `other` has any units
|
179
190
|
def mod(other)
|
180
191
|
if other.is_a?(Number)
|
192
|
+
unless other.unitless?
|
193
|
+
raise Sass::UnitConversionError.new("Cannot modulo by a number with units: #{other.inspect}.")
|
194
|
+
end
|
181
195
|
operate(other, :%)
|
182
196
|
else
|
183
197
|
raise NoMethodError.new(nil, :mod)
|
@@ -186,10 +200,10 @@ module Sass::Script::Value
|
|
186
200
|
|
187
201
|
# The SassScript `==` operation.
|
188
202
|
#
|
189
|
-
# @param other [
|
203
|
+
# @param other [Literal] The right-hand side of the operator
|
190
204
|
# @return [Boolean] Whether this number is equal to the other object
|
191
205
|
def eq(other)
|
192
|
-
return Bool
|
206
|
+
return Sass::Script::Bool.new(false) unless other.is_a?(Sass::Script::Number)
|
193
207
|
this = self
|
194
208
|
begin
|
195
209
|
if unitless?
|
@@ -198,21 +212,10 @@ module Sass::Script::Value
|
|
198
212
|
other = other.coerce(@numerator_units, @denominator_units)
|
199
213
|
end
|
200
214
|
rescue Sass::UnitConversionError
|
201
|
-
return Bool
|
215
|
+
return Sass::Script::Bool.new(false)
|
202
216
|
end
|
203
|
-
Bool.new(this.value == other.value)
|
204
|
-
end
|
205
|
-
|
206
|
-
def hash
|
207
|
-
[value, numerator_units, denominator_units].hash
|
208
|
-
end
|
209
217
|
|
210
|
-
|
211
|
-
# Hash-equality must be transitive, so it just compares the exact value,
|
212
|
-
# numerator units, and denominator units.
|
213
|
-
def eql?(other)
|
214
|
-
value == other.value && numerator_units == other.numerator_units &&
|
215
|
-
denominator_units == other.denominator_units
|
218
|
+
Sass::Script::Bool.new(this.value == other.value)
|
216
219
|
end
|
217
220
|
|
218
221
|
# The SassScript `>` operation.
|
@@ -271,17 +274,8 @@ module Sass::Script::Value
|
|
271
274
|
#
|
272
275
|
# @return [String] The representation
|
273
276
|
def inspect(opts = {})
|
274
|
-
return original if original
|
275
|
-
|
276
277
|
value = self.class.round(self.value)
|
277
|
-
|
278
|
-
|
279
|
-
# Ruby will occasionally print in scientific notation if the number is
|
280
|
-
# small enough. That's technically valid CSS, but it's not well-supported
|
281
|
-
# and confusing.
|
282
|
-
str = ("%0.#{self.class.precision}f" % value).gsub(/0*$/, '') if str.include?('e')
|
283
|
-
|
284
|
-
unitless? ? str : "#{str}#{unit_str}"
|
278
|
+
unitless? ? value.to_s : "#{value}#{unit_str}"
|
285
279
|
end
|
286
280
|
alias_method :to_sass, :inspect
|
287
281
|
|
@@ -289,7 +283,7 @@ module Sass::Script::Value
|
|
289
283
|
# @raise [Sass::SyntaxError] if the number isn't an integer
|
290
284
|
def to_i
|
291
285
|
super unless int?
|
292
|
-
value
|
286
|
+
return value
|
293
287
|
end
|
294
288
|
|
295
289
|
# @return [Boolean] Whether or not this number is an integer.
|
@@ -302,24 +296,6 @@ module Sass::Script::Value
|
|
302
296
|
@numerator_units.empty? && @denominator_units.empty?
|
303
297
|
end
|
304
298
|
|
305
|
-
# Checks whether the number has the numerator unit specified.
|
306
|
-
#
|
307
|
-
# @example
|
308
|
-
# number = Sass::Script::Value::Number.new(10, "px")
|
309
|
-
# number.is_unit?("px") => true
|
310
|
-
# number.is_unit?(nil) => false
|
311
|
-
#
|
312
|
-
# @param unit [::String, nil] The unit the number should have or nil if the number
|
313
|
-
# should be unitless.
|
314
|
-
# @see Number#unitless? The unitless? method may be more readable.
|
315
|
-
def is_unit?(unit)
|
316
|
-
if unit
|
317
|
-
denominator_units.size == 0 && numerator_units.size == 1 && numerator_units.first == unit
|
318
|
-
else
|
319
|
-
unitless?
|
320
|
-
end
|
321
|
-
end
|
322
|
-
|
323
299
|
# @return [Boolean] Whether or not this number has units that can be represented in CSS
|
324
300
|
# (that is, zero or one \{#numerator\_units}).
|
325
301
|
def legal_units?
|
@@ -344,9 +320,9 @@ module Sass::Script::Value
|
|
344
320
|
# current units
|
345
321
|
def coerce(num_units, den_units)
|
346
322
|
Number.new(if unitless?
|
347
|
-
value
|
323
|
+
self.value
|
348
324
|
else
|
349
|
-
value * coercion_factor(@numerator_units, num_units) /
|
325
|
+
self.value * coercion_factor(@numerator_units, num_units) /
|
350
326
|
coercion_factor(@denominator_units, den_units)
|
351
327
|
end, num_units, den_units)
|
352
328
|
end
|
@@ -354,10 +330,12 @@ module Sass::Script::Value
|
|
354
330
|
# @param other [Number] A number to decide if it can be compared with this number.
|
355
331
|
# @return [Boolean] Whether or not this number can be compared with the other.
|
356
332
|
def comparable_to?(other)
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
333
|
+
begin
|
334
|
+
operate(other, :+)
|
335
|
+
true
|
336
|
+
rescue Sass::UnitConversionError
|
337
|
+
false
|
338
|
+
end
|
361
339
|
end
|
362
340
|
|
363
341
|
# Returns a human readable representation of the units in this number.
|
@@ -382,11 +360,11 @@ module Sass::Script::Value
|
|
382
360
|
elsif num % 1 == 0.0
|
383
361
|
num.to_i
|
384
362
|
else
|
385
|
-
((num * precision_factor).round / precision_factor).to_f
|
363
|
+
((num * self.precision_factor).round / self.precision_factor).to_f
|
386
364
|
end
|
387
365
|
end
|
388
366
|
|
389
|
-
OPERATIONS = [:+, :-, :<=, :<, :>,
|
367
|
+
OPERATIONS = [:+, :-, :<=, :<, :>, :>=]
|
390
368
|
|
391
369
|
def operate(other, operation)
|
392
370
|
this = self
|
@@ -398,7 +376,7 @@ module Sass::Script::Value
|
|
398
376
|
end
|
399
377
|
end
|
400
378
|
# avoid integer division
|
401
|
-
value = :/ == operation ? this.value.to_f : this.value
|
379
|
+
value = (:/ == operation) ? this.value.to_f : this.value
|
402
380
|
result = value.send(operation, other.value)
|
403
381
|
|
404
382
|
if result.is_a?(Numeric)
|
@@ -413,33 +391,29 @@ module Sass::Script::Value
|
|
413
391
|
from_units, to_units = sans_common_units(from_units, to_units)
|
414
392
|
|
415
393
|
if from_units.size != to_units.size || !convertable?(from_units | to_units)
|
416
|
-
raise Sass::UnitConversionError.new(
|
417
|
-
"Incompatible units: '#{from_units.join('*')}' and '#{to_units.join('*')}'.")
|
394
|
+
raise Sass::UnitConversionError.new("Incompatible units: '#{from_units.join('*')}' and '#{to_units.join('*')}'.")
|
418
395
|
end
|
419
396
|
|
420
|
-
from_units.zip(to_units).inject(1) {|m,
|
397
|
+
from_units.zip(to_units).inject(1) {|m,p| m * conversion_factor(p[0], p[1]) }
|
421
398
|
end
|
422
399
|
|
423
400
|
def compute_units(this, other, operation)
|
424
401
|
case operation
|
425
402
|
when :*
|
426
|
-
[this.numerator_units + other.numerator_units,
|
427
|
-
this.denominator_units + other.denominator_units]
|
403
|
+
[this.numerator_units + other.numerator_units, this.denominator_units + other.denominator_units]
|
428
404
|
when :/
|
429
|
-
[this.numerator_units + other.denominator_units,
|
430
|
-
|
431
|
-
else
|
405
|
+
[this.numerator_units + other.denominator_units, this.denominator_units + other.numerator_units]
|
406
|
+
else
|
432
407
|
[this.numerator_units, this.denominator_units]
|
433
408
|
end
|
434
409
|
end
|
435
410
|
|
436
411
|
def normalize!
|
437
412
|
return if unitless?
|
438
|
-
@numerator_units, @denominator_units =
|
439
|
-
sans_common_units(@numerator_units, @denominator_units)
|
413
|
+
@numerator_units, @denominator_units = sans_common_units(@numerator_units, @denominator_units)
|
440
414
|
|
441
415
|
@denominator_units.each_with_index do |d, i|
|
442
|
-
if convertable?(d) && (u = @numerator_units.
|
416
|
+
if convertable?(d) && (u = @numerator_units.detect(&method(:convertable?)))
|
443
417
|
@value /= conversion_factor(d, u)
|
444
418
|
@denominator_units.delete_at(i)
|
445
419
|
@numerator_units.delete_at(@numerator_units.index(u))
|
@@ -447,84 +421,33 @@ module Sass::Script::Value
|
|
447
421
|
end
|
448
422
|
end
|
449
423
|
|
450
|
-
#
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
'cm' => Rational(1, 2.54),
|
459
|
-
'pc' => Rational(1, 6),
|
460
|
-
'mm' => Rational(1, 25.4),
|
461
|
-
'pt' => Rational(1, 72),
|
462
|
-
'px' => Rational(1, 96)
|
463
|
-
},
|
464
|
-
{
|
465
|
-
'deg' => Rational(1, 360),
|
466
|
-
'grad' => Rational(1, 400),
|
467
|
-
'rad' => Rational(1, 2 * Math::PI),
|
468
|
-
'turn' => Rational(1)
|
469
|
-
},
|
470
|
-
{
|
471
|
-
's' => Rational(1),
|
472
|
-
'ms' => Rational(1, 1000)
|
473
|
-
},
|
474
|
-
{
|
475
|
-
'Hz' => Rational(1),
|
476
|
-
'kHz' => Rational(1000)
|
477
|
-
},
|
478
|
-
{
|
479
|
-
'dpi' => Rational(1),
|
480
|
-
'dpcm' => Rational(1, 2.54),
|
481
|
-
'dppx' => Rational(1, 96)
|
482
|
-
}
|
483
|
-
]
|
484
|
-
|
485
|
-
# A hash from each known unit to the set of units that it's mutually
|
486
|
-
# convertible with.
|
487
|
-
MUTUALLY_CONVERTIBLE = {}
|
488
|
-
relative_sizes.map do |values|
|
489
|
-
set = values.keys.to_set
|
490
|
-
values.keys.each {|name| MUTUALLY_CONVERTIBLE[name] = set}
|
491
|
-
end
|
492
|
-
|
493
|
-
# A two-dimensional hash from two units to the conversion ratio between
|
494
|
-
# them. Multiply `X` by `CONVERSION_TABLE[X][Y]` to convert it to `Y`.
|
495
|
-
CONVERSION_TABLE = {}
|
496
|
-
relative_sizes.each do |values|
|
497
|
-
values.each do |(name1, value1)|
|
498
|
-
CONVERSION_TABLE[name1] ||= {}
|
499
|
-
values.each do |(name2, value2)|
|
500
|
-
value = value1 / value2
|
501
|
-
CONVERSION_TABLE[name1][name2] = value.denominator == 1 ? value.to_i : value.to_f
|
502
|
-
end
|
503
|
-
end
|
504
|
-
end
|
424
|
+
# A hash of unit names to their index in the conversion table
|
425
|
+
CONVERTABLE_UNITS = {"in" => 0, "cm" => 1, "pc" => 2, "mm" => 3, "pt" => 4, "px" => 5 }
|
426
|
+
CONVERSION_TABLE = [[ 1, 2.54, 6, 25.4, 72 , 96 ], # in
|
427
|
+
[ nil, 1, 2.36220473, 10, 28.3464567, 37.795275591], # cm
|
428
|
+
[ nil, nil, 1, 4.23333333, 12 , 16 ], # pc
|
429
|
+
[ nil, nil, nil, 1, 2.83464567, 3.7795275591], # mm
|
430
|
+
[ nil, nil, nil, nil, 1 , 1.3333333333], # pt
|
431
|
+
[ nil, nil, nil, nil, nil , 1 ]] # px
|
505
432
|
|
506
433
|
def conversion_factor(from_unit, to_unit)
|
507
|
-
CONVERSION_TABLE[from_unit][to_unit]
|
434
|
+
res = CONVERSION_TABLE[CONVERTABLE_UNITS[from_unit]][CONVERTABLE_UNITS[to_unit]]
|
435
|
+
return 1.0 / conversion_factor(to_unit, from_unit) if res.nil?
|
436
|
+
res
|
508
437
|
end
|
509
438
|
|
510
439
|
def convertable?(units)
|
511
|
-
units
|
512
|
-
return true if units.empty?
|
513
|
-
return false unless (mutually_convertible = MUTUALLY_CONVERTIBLE[units.first])
|
514
|
-
units.subset?(mutually_convertible)
|
440
|
+
Array(units).all? {|u| CONVERTABLE_UNITS.include?(u)}
|
515
441
|
end
|
516
442
|
|
517
443
|
def sans_common_units(units1, units2)
|
518
444
|
units2 = units2.dup
|
519
445
|
# Can't just use -, because we want px*px to coerce properly to px*mm
|
520
|
-
|
521
|
-
j = units2.index(u)
|
522
|
-
next u unless j
|
446
|
+
return units1.map do |u|
|
447
|
+
next u unless j = units2.index(u)
|
523
448
|
units2.delete_at(j)
|
524
449
|
nil
|
525
|
-
end
|
526
|
-
units1.compact!
|
527
|
-
return units1, units2
|
450
|
+
end.compact, units2
|
528
451
|
end
|
529
452
|
end
|
530
453
|
end
|