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.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +50 -70
  4. data/Rakefile +5 -26
  5. data/VERSION +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/bin/sass +1 -1
  8. data/bin/scss +1 -1
  9. data/lib/sass.rb +12 -19
  10. data/lib/sass/cache_stores/base.rb +2 -2
  11. data/lib/sass/cache_stores/chain.rb +1 -2
  12. data/lib/sass/cache_stores/filesystem.rb +5 -1
  13. data/lib/sass/cache_stores/memory.rb +1 -1
  14. data/lib/sass/cache_stores/null.rb +2 -2
  15. data/lib/sass/callbacks.rb +0 -1
  16. data/lib/sass/css.rb +13 -11
  17. data/lib/sass/engine.rb +173 -424
  18. data/lib/sass/environment.rb +58 -148
  19. data/lib/sass/error.rb +14 -11
  20. data/lib/sass/exec.rb +703 -5
  21. data/lib/sass/importers/base.rb +6 -49
  22. data/lib/sass/importers/filesystem.rb +19 -44
  23. data/lib/sass/logger.rb +4 -1
  24. data/lib/sass/logger/base.rb +4 -2
  25. data/lib/sass/logger/log_level.rb +7 -3
  26. data/lib/sass/media.rb +23 -20
  27. data/lib/sass/plugin.rb +7 -7
  28. data/lib/sass/plugin/compiler.rb +145 -304
  29. data/lib/sass/plugin/configuration.rb +23 -18
  30. data/lib/sass/plugin/merb.rb +1 -1
  31. data/lib/sass/plugin/staleness_checker.rb +3 -3
  32. data/lib/sass/repl.rb +3 -3
  33. data/lib/sass/script.rb +8 -35
  34. data/lib/sass/script/{value/arg_list.rb → arg_list.rb} +25 -9
  35. data/lib/sass/script/bool.rb +18 -0
  36. data/lib/sass/script/color.rb +606 -0
  37. data/lib/sass/script/css_lexer.rb +4 -8
  38. data/lib/sass/script/css_parser.rb +2 -5
  39. data/lib/sass/script/funcall.rb +245 -0
  40. data/lib/sass/script/functions.rb +408 -1491
  41. data/lib/sass/script/interpolation.rb +79 -0
  42. data/lib/sass/script/lexer.rb +68 -172
  43. data/lib/sass/script/list.rb +85 -0
  44. data/lib/sass/script/literal.rb +221 -0
  45. data/lib/sass/script/{tree/node.rb → node.rb} +12 -22
  46. data/lib/sass/script/{value/null.rb → null.rb} +7 -14
  47. data/lib/sass/script/{value/number.rb → number.rb} +75 -152
  48. data/lib/sass/script/{tree/operation.rb → operation.rb} +24 -17
  49. data/lib/sass/script/parser.rb +110 -245
  50. data/lib/sass/script/string.rb +51 -0
  51. data/lib/sass/script/{tree/string_interpolation.rb → string_interpolation.rb} +4 -5
  52. data/lib/sass/script/{tree/unary_operation.rb → unary_operation.rb} +6 -6
  53. data/lib/sass/script/variable.rb +58 -0
  54. data/lib/sass/scss/css_parser.rb +3 -9
  55. data/lib/sass/scss/parser.rb +421 -450
  56. data/lib/sass/scss/rx.rb +11 -19
  57. data/lib/sass/scss/static_parser.rb +7 -321
  58. data/lib/sass/selector.rb +194 -68
  59. data/lib/sass/selector/abstract_sequence.rb +14 -29
  60. data/lib/sass/selector/comma_sequence.rb +25 -108
  61. data/lib/sass/selector/sequence.rb +66 -159
  62. data/lib/sass/selector/simple.rb +25 -23
  63. data/lib/sass/selector/simple_sequence.rb +63 -173
  64. data/lib/sass/shared.rb +1 -1
  65. data/lib/sass/supports.rb +15 -13
  66. data/lib/sass/tree/charset_node.rb +1 -1
  67. data/lib/sass/tree/comment_node.rb +3 -3
  68. data/lib/sass/tree/css_import_node.rb +11 -11
  69. data/lib/sass/tree/debug_node.rb +2 -2
  70. data/lib/sass/tree/directive_node.rb +4 -21
  71. data/lib/sass/tree/each_node.rb +8 -8
  72. data/lib/sass/tree/extend_node.rb +7 -14
  73. data/lib/sass/tree/for_node.rb +4 -4
  74. data/lib/sass/tree/function_node.rb +4 -9
  75. data/lib/sass/tree/if_node.rb +1 -1
  76. data/lib/sass/tree/import_node.rb +5 -4
  77. data/lib/sass/tree/media_node.rb +14 -4
  78. data/lib/sass/tree/mixin_def_node.rb +4 -4
  79. data/lib/sass/tree/mixin_node.rb +8 -21
  80. data/lib/sass/tree/node.rb +12 -54
  81. data/lib/sass/tree/prop_node.rb +20 -39
  82. data/lib/sass/tree/return_node.rb +2 -3
  83. data/lib/sass/tree/root_node.rb +3 -19
  84. data/lib/sass/tree/rule_node.rb +22 -35
  85. data/lib/sass/tree/supports_node.rb +13 -0
  86. data/lib/sass/tree/trace_node.rb +1 -2
  87. data/lib/sass/tree/variable_node.rb +3 -9
  88. data/lib/sass/tree/visitors/base.rb +8 -5
  89. data/lib/sass/tree/visitors/check_nesting.rb +19 -49
  90. data/lib/sass/tree/visitors/convert.rb +56 -74
  91. data/lib/sass/tree/visitors/cssize.rb +74 -202
  92. data/lib/sass/tree/visitors/deep_copy.rb +5 -10
  93. data/lib/sass/tree/visitors/extend.rb +7 -7
  94. data/lib/sass/tree/visitors/perform.rb +185 -278
  95. data/lib/sass/tree/visitors/set_options.rb +6 -20
  96. data/lib/sass/tree/visitors/to_css.rb +81 -234
  97. data/lib/sass/tree/warn_node.rb +2 -2
  98. data/lib/sass/tree/while_node.rb +2 -2
  99. data/lib/sass/util.rb +152 -522
  100. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  101. data/lib/sass/util/subset_map.rb +3 -4
  102. data/lib/sass/util/test.rb +1 -0
  103. data/lib/sass/version.rb +22 -20
  104. data/test/Gemfile +3 -0
  105. data/test/Gemfile.lock +10 -0
  106. data/test/sass/cache_test.rb +20 -62
  107. data/test/sass/callbacks_test.rb +1 -1
  108. data/test/sass/conversion_test.rb +2 -296
  109. data/test/sass/css2sass_test.rb +4 -23
  110. data/test/sass/engine_test.rb +354 -411
  111. data/test/sass/exec_test.rb +2 -2
  112. data/test/sass/extend_test.rb +145 -324
  113. data/test/sass/functions_test.rb +86 -873
  114. data/test/sass/importer_test.rb +21 -241
  115. data/test/sass/logger_test.rb +1 -1
  116. data/test/sass/more_results/more_import.css +1 -1
  117. data/test/sass/plugin_test.rb +26 -16
  118. data/test/sass/results/compact.css +1 -1
  119. data/test/sass/results/complex.css +4 -4
  120. data/test/sass/results/expanded.css +1 -1
  121. data/test/sass/results/import.css +1 -1
  122. data/test/sass/results/import_charset_ibm866.css +2 -2
  123. data/test/sass/results/mixins.css +17 -17
  124. data/test/sass/results/nested.css +1 -1
  125. data/test/sass/results/parent_ref.css +2 -2
  126. data/test/sass/results/script.css +3 -3
  127. data/test/sass/results/scss_import.css +1 -1
  128. data/test/sass/script_conversion_test.rb +7 -36
  129. data/test/sass/script_test.rb +53 -485
  130. data/test/sass/scss/css_test.rb +28 -143
  131. data/test/sass/scss/rx_test.rb +4 -4
  132. data/test/sass/scss/scss_test.rb +325 -2119
  133. data/test/sass/templates/scss_import.scss +1 -2
  134. data/test/sass/test_helper.rb +1 -1
  135. data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
  136. data/test/sass/util/subset_map_test.rb +2 -2
  137. data/test/sass/util_test.rb +1 -86
  138. data/test/test_helper.rb +8 -37
  139. metadata +19 -66
  140. data/lib/sass/exec/base.rb +0 -187
  141. data/lib/sass/exec/sass_convert.rb +0 -264
  142. data/lib/sass/exec/sass_scss.rb +0 -424
  143. data/lib/sass/features.rb +0 -47
  144. data/lib/sass/script/tree.rb +0 -16
  145. data/lib/sass/script/tree/funcall.rb +0 -306
  146. data/lib/sass/script/tree/interpolation.rb +0 -118
  147. data/lib/sass/script/tree/list_literal.rb +0 -77
  148. data/lib/sass/script/tree/literal.rb +0 -45
  149. data/lib/sass/script/tree/map_literal.rb +0 -64
  150. data/lib/sass/script/tree/selector.rb +0 -26
  151. data/lib/sass/script/tree/variable.rb +0 -57
  152. data/lib/sass/script/value.rb +0 -11
  153. data/lib/sass/script/value/base.rb +0 -240
  154. data/lib/sass/script/value/bool.rb +0 -35
  155. data/lib/sass/script/value/color.rb +0 -680
  156. data/lib/sass/script/value/helpers.rb +0 -262
  157. data/lib/sass/script/value/list.rb +0 -113
  158. data/lib/sass/script/value/map.rb +0 -70
  159. data/lib/sass/script/value/string.rb +0 -97
  160. data/lib/sass/selector/pseudo.rb +0 -256
  161. data/lib/sass/source/map.rb +0 -210
  162. data/lib/sass/source/position.rb +0 -39
  163. data/lib/sass/source/range.rb +0 -41
  164. data/lib/sass/stack.rb +0 -120
  165. data/lib/sass/tree/at_root_node.rb +0 -83
  166. data/lib/sass/tree/error_node.rb +0 -18
  167. data/lib/sass/tree/keyframe_rule_node.rb +0 -15
  168. data/lib/sass/util/cross_platform_random.rb +0 -19
  169. data/lib/sass/util/normalized_map.rb +0 -130
  170. data/lib/sass/util/ordered_hash.rb +0 -192
  171. data/test/sass/compiler_test.rb +0 -232
  172. data/test/sass/encoding_test.rb +0 -219
  173. data/test/sass/source_map_test.rb +0 -977
  174. data/test/sass/superselector_test.rb +0 -191
  175. data/test/sass/util/normalized_map_test.rb +0 -51
  176. data/test/sass/value_helpers_test.rb +0 -179
@@ -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::Tree
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 [Sass::Script::Value] The SassScript object that is the value of the SassScript
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 {Sass::Script::Value} objects created within this method
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 [Sass::Script::Value] The SassScript object that is the value of the SassScript
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 value and returns it.
90
+ # Sets the \{#options} field on the given literal and returns it
101
91
  #
102
- # @param value [Sass::Script::Value]
103
- # @return [Sass::Script::Value]
104
- def opts(value)
105
- value.options = options
106
- value
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
- module Sass::Script::Value
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
- # We override object creation so that users of the core API
10
- # will not need to know that null is a specific constant.
11
- #
12
- # @private
13
- # @return [Null] the {NULL} constant.
14
- def self.new
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
- module Sass::Script::Value
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 < Base
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 [::String, Array<::String>] See \{#numerator\_units}
59
- # @param denominator_units [::String, Array<::String>] See \{#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
- # {Value}
79
- # : See {Value::Base#plus}.
89
+ # {Literal}
90
+ # : See {Literal#plus}.
80
91
  #
81
- # @param other [Value] The right-hand side of the operator
82
- # @return [Value] The result of the operation
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
- # {Value}
101
- # : See {Value::Base#minus}.
111
+ # {Literal}
112
+ # : See {Literal#minus}.
102
113
  #
103
- # @param other [Value] The right-hand side of the operator
104
- # @return [Value] The result of the operation
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
- # {Value}
157
- # : See {Value::Base#div}.
167
+ # {Literal}
168
+ # : See {Literal#div}.
158
169
  #
159
- # @param other [Value] The right-hand side of the operator
160
- # @return [Value] The result of the operation
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 incompatible units
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 [Value] The right-hand side of the operator
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::FALSE unless other.is_a?(Sass::Script::Value::Number)
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::FALSE
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
- # Hash-equality works differently than `==` equality for numbers.
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
- str = value.to_s
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
- operate(other, :+)
358
- true
359
- rescue Sass::UnitConversionError
360
- false
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, p| m * conversion_factor(p[0], p[1])}
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
- this.denominator_units + other.numerator_units]
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.find(&method(:convertable?)))
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
- # This is the source data for all the unit logic. It's pre-processed to make
451
- # it efficient to figure out whether a set of units is mutually compatible
452
- # and what the conversion ratio is between two units.
453
- #
454
- # These come from http://www.w3.org/TR/2012/WD-css3-values-20120308/.
455
- relative_sizes = [
456
- {
457
- 'in' => Rational(1),
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 = Array(units).to_set
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
- units1 = units1.map do |u|
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