Skip to content

Commit d8ae9b1

Browse files
committed
Always perform division on numbers returned by functions.
Closes sass#973
1 parent 741f3ac commit d8ae9b1

File tree

4 files changed

+42
-4
lines changed

4 files changed

+42
-4
lines changed

doc-src/SASS_CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
* Table of contents
44
{:toc}
55

6+
## 3.2.13 (Unreleased)
7+
8+
* Numbers returned by user-defined functions now trigger division, just like
9+
numbers stored in variables.
10+
611
## 3.2.12
712

813
* Add a couple missing `require`s, fixing some load errors, especially when

doc-src/SASS_REFERENCE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ However, there are three situations where the `/` will be interpreted as divisio
761761
These cover the vast majority of cases where division is actually used.
762762
They are:
763763

764-
1. If the value, or any part of it, is stored in a variable.
764+
1. If the value, or any part of it, is stored in a variable or returned by a function.
765765
2. If the value is surrounded by parentheses.
766766
3. If the value is used as part of another arithmetic expression.
767767

@@ -771,6 +771,7 @@ For example:
771771
font: 10px/8px; // Plain CSS, no division
772772
$width: 1000px;
773773
width: $width/2; // Uses a variable, does division
774+
width: round(1.5)/2; // Uses a function, does division
774775
height: (500px/2); // Uses parentheses, does division
775776
margin-left: 5px + 8px/2px; // Uses +, does division
776777
}

lib/sass/script/funcall.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,17 @@ def _perform(environment)
100100
splat = @splat.perform(environment) if @splat
101101
if fn = environment.function(@name)
102102
keywords = Sass::Util.map_hash(@keywords) {|k, v| [k, v.perform(environment)]}
103-
return perform_sass_fn(fn, args, keywords, splat)
103+
return without_original(perform_sass_fn(fn, args, keywords, splat))
104104
end
105105

106106
ruby_name = @name.tr('-', '_')
107107
args = construct_ruby_args(ruby_name, args, splat, environment)
108108

109109
unless Functions.callable?(ruby_name)
110-
opts(to_literal(args))
110+
without_original(opts(to_literal(args)))
111111
else
112-
opts(Functions::EvaluationContext.new(environment.options).send(ruby_name, *args))
112+
without_original(opts(Functions::EvaluationContext.new(environment.options)
113+
.send(ruby_name, *args)))
113114
end
114115
rescue ArgumentError => e
115116
message = e.message
@@ -170,6 +171,13 @@ def to_literal(args)
170171

171172
private
172173

174+
def without_original(value)
175+
return value unless value.is_a?(Number)
176+
value = value.dup
177+
value.original = nil
178+
return value
179+
end
180+
173181
def construct_ruby_args(name, args, splat, environment)
174182
args += splat.to_a if splat
175183

test/sass/script_test.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,30 @@ def test_boolean_ops_short_circuit
510510

511511
# Regression Tests
512512

513+
def test_user_defined_function_forces_division
514+
assert_equal(<<CSS, render(<<SASS))
515+
a {
516+
b: 10px; }
517+
CSS
518+
@function foo()
519+
@return 20px
520+
521+
a
522+
b: (foo() / 2)
523+
SASS
524+
525+
assert_equal(<<CSS, render(<<SASS))
526+
a {
527+
b: 10px; }
528+
CSS
529+
@function foo()
530+
@return 20px
531+
532+
a
533+
b: foo() / 2
534+
SASS
535+
end
536+
513537
def test_funcall_has_higher_precedence_than_color_name
514538
assert_equal "teal(12)", resolve("teal(12)")
515539
assert_equal "tealbang(12)", resolve("tealbang(12)")

0 commit comments

Comments
 (0)