Skip to content

Commit

Permalink
Merge branch 'stable'
Browse files Browse the repository at this point in the history
Conflicts:
	VERSION
	doc-src/SASS_CHANGELOG.md
	lib/sass/util.rb
  • Loading branch information
nex3 committed May 5, 2012
2 parents fc5b92a + 62e38c1 commit 8f937fc
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 65 deletions.
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ task :permissions do
end

task :revision_file do
require 'lib/sass'
require scope('lib/sass')

release = Rake.application.top_level_tasks.include?('release') || File.exist?(scope('EDGE_GEM_VERSION'))
if Sass.version[:rev] && !release
Expand Down
4 changes: 3 additions & 1 deletion doc-src/SASS_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ that make use of `@media` and other directives dynamically.
* `#{}` interpolation is now disallowed in all `@import` statements
except for those using `url()`.

## 3.1.17 (Unreleased)
## 3.1.17

* Don't crash when calling `#inspect` on an internal Sass tree object in Ruby
1.9.
Expand All @@ -151,6 +151,8 @@ that make use of `@media` and other directives dynamically.
selectors (e.g. `[name=#{$value}]`).
* Support keyword arguments for the `invert()` function.
* Handle backslash-separated paths better on Windows.
* Fix `rake install` on Ruby 1.9.
* Properly convert nested `@if` statements with `sass-convert`.

## 3.1.16

Expand Down
4 changes: 4 additions & 0 deletions lib/sass/plugin/compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,10 @@ def watch(individual_files = [])
update_stylesheets(individual_files)
end

# The native windows listener is much slower than the polling
# option, according to https://github.com/nex3/sass/commit/a3031856b22bc834a5417dedecb038b7be9b9e3e#commitcomment-1295118
listener.force_polling(true) if Sass::Util.windows?

begin
listener.start
rescue Exception => e
Expand Down
13 changes: 4 additions & 9 deletions lib/sass/script/color.rb
Original file line number Diff line number Diff line change
Expand Up @@ -232,21 +232,16 @@ def initialize(attrs, allow_both_rgb_and_hsl = false)
[:red, :green, :blue].each do |k|
next if @attrs[k].nil?
@attrs[k] = @attrs[k].to_i
next if (0..255).include?(@attrs[k])
raise ArgumentError.new("#{k.to_s.capitalize} value must be between 0 and 255")
Sass::Util.check_range("#{k.to_s.capitalize} value", 0..255, @attrs[k])
end

[:saturation, :lightness].each do |k|
next if @attrs[k].nil?
@attrs[k] = 0 if @attrs[k] < 0.00001 && @attrs[k] > -0.00001
@attrs[k] = 100 if @attrs[k] - 100 < 0.00001 && @attrs[k] - 100 > -0.00001
next if (0..100).include?(@attrs[k])
raise ArgumentError.new("#{k.to_s.capitalize} must be between 0 and 100")
value = Number.new(@attrs[k], ['%']) # Get correct unit for error messages
@attrs[k] = Sass::Util.check_range("#{k.to_s.capitalize}", 0..100, value, '%')
end

unless (0..1).include?(@attrs[:alpha])
raise ArgumentError.new("Alpha channel must be between 0 and 1")
end
@attrs[:alpha] = Sass::Util.check_range("Alpha channel", 0..1, @attrs[:alpha])
end

# The red component of the color.
Expand Down
41 changes: 13 additions & 28 deletions lib/sass/script/functions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -375,11 +375,10 @@ def rgb(red, green, blue)
Color.new([red, green, blue].map do |c|
v = c.value
if c.numerator_units == ["%"] && c.denominator_units.empty?
next v * 255 / 100.0 if (0..100).include?(v)
raise ArgumentError.new("Color value #{c} must be between 0% and 100% inclusive")
v = Sass::Util.check_range("Color value", 0..100, c, '%')
v * 255 / 100.0
else
next v if (0..255).include?(v)
raise ArgumentError.new("Color value #{v} must be between 0 and 255 inclusive")
Sass::Util.check_range("Color value", 0..255, c)
end
end)
end
Expand Down Expand Up @@ -419,10 +418,7 @@ def rgba(*args)
assert_type color, :Color
assert_type alpha, :Number

unless (0..1).include?(alpha.value)
raise ArgumentError.new("Alpha channel #{alpha.value} must be between 0 and 1 inclusive")
end

Sass::Util.check_range('Alpha channel', 0..1, alpha)
color.with(:alpha => alpha.value)
when 4
red, green, blue, alpha = args
Expand Down Expand Up @@ -472,16 +468,11 @@ def hsla(hue, saturation, lightness, alpha)
assert_type lightness, :Number
assert_type alpha, :Number

unless (0..1).include?(alpha.value)
raise ArgumentError.new("Alpha channel #{alpha.value} must be between 0 and 1")
end
Sass::Util.check_range('Alpha channel', 0..1, alpha)

original_s = saturation
original_l = lightness
# This algorithm is from http://www.w3.org/TR/css3-color#hsl-color
h, s, l = [hue, saturation, lightness].map { |a| a.value }
raise ArgumentError.new("Saturation #{s} must be between 0% and 100%") unless (0..100).include?(s)
raise ArgumentError.new("Lightness #{l} must be between 0% and 100%") unless (0..100).include?(l)
h = hue.value
s = Sass::Util.check_range('Saturation', 0..100, saturation, '%')
l = Sass::Util.check_range('Lightness', 0..100, lightness, '%')

Color.new(:hue => h, :saturation => s, :lightness => l, :alpha => alpha.value)
end
Expand Down Expand Up @@ -804,9 +795,7 @@ def adjust_color(color, kwargs)

next unless val = kwargs.delete(name)
assert_type val, :Number, name
if range && !range.include?(val.value)
raise ArgumentError.new("$#{name}: Amount #{val} must be between #{range.first}#{units} and #{range.last}#{units}")
end
Sass::Util.check_range("$#{name}: Amount", range, val, units) if range
adjusted = color.send(name) + val.value
adjusted = [0, Sass::Util.restrict(adjusted, range)].max if range
[name.to_sym, adjusted]
Expand Down Expand Up @@ -875,8 +864,8 @@ def scale_color(color, kwargs)
assert_type val, :Number, name
if !(val.numerator_units == ['%'] && val.denominator_units.empty?)
raise ArgumentError.new("$#{name}: Amount #{val} must be a % (e.g. #{val.value}%)")
elsif !(-100..100).include?(val.value)
raise ArgumentError.new("$#{name}: Amount #{val} must be between -100% and 100%")
else
Sass::Util.check_range("$#{name}: Amount", -100..100, val, '%')
end

current = color.send(name)
Expand Down Expand Up @@ -970,9 +959,7 @@ def mix(color1, color2, weight = Number.new(50))
assert_type color2, :Color
assert_type weight, :Number

unless (0..100).include?(weight.value)
raise ArgumentError.new("Weight #{weight} must be between 0% and 100%")
end
Sass::Util.check_range("Weight", 0..100, weight, '%')

# This algorithm factors in both the user-provided weight
# and the difference between the alpha values of the two colors
Expand Down Expand Up @@ -1439,9 +1426,7 @@ def numeric_transformation(value)
def _adjust(color, amount, attr, range, op, units = "")
assert_type color, :Color
assert_type amount, :Number
unless range.include?(amount.value)
raise ArgumentError.new("Amount #{amount} must be between #{range.first}#{units} and #{range.last}#{units}")
end
Sass::Util.check_range('Amount', range, amount, units)

# TODO: is it worth restricting here,
# or should we do so in the Color constructor itself,
Expand Down
1 change: 1 addition & 0 deletions lib/sass/tree/visitors/convert.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ def visit_if(node)
elsif node.expr; "else if"
else; "else"
end
@is_else = false
str = "#{tab_str}@#{name}"
str << " #{node.expr.to_sass(@options)}" if node.expr
str << yield
Expand Down
20 changes: 20 additions & 0 deletions lib/sass/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,26 @@ def group_by_to_a(enum, &block)
arr
end

# Asserts that `value` falls within `range` (inclusive), leaving
# room for slight floating-point errors.
#
# @param name [String] The name of the value. Used in the error message.
# @param range [Range] The allowed range of values.
# @param value [Numeric, Sass::Script::Number] The value to check.
# @param unit [String] The unit of the value. Used in error reporting.
# @return [Numeric] `value` adjusted to fall within range, if it
# was outside by a floating-point margin.
def check_range(name, range, value, unit='')
grace = (-0.00001..0.00001)
str = value.to_s
value = value.value if value.is_a?(Sass::Script::Number)
return value if range.include?(value)
return range.first if grace.include?(value - range.first)
return range.last if grace.include?(value - range.last)
raise ArgumentError.new(
"#{name} #{str} must be between #{range.first}#{unit} and #{range.last}#{unit}")
end

# Returns information about the caller of the previous method.
#
# @param entry [String] An entry in the `#caller` list, or a similarly formatted string
Expand Down
26 changes: 26 additions & 0 deletions test/sass/conversion_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1525,6 +1525,32 @@ def test_empty_lists
SCSS
end

def test_nested_if_statements
assert_renders(<<SASS, <<SCSS)
@if $foo
one
a: b
@else
@if $bar
two
a: b
@else
three
a: b
SASS
@if $foo {
one {
a: b; } }
@else {
@if $bar {
two {
a: b; } }
@else {
three {
a: b; } } }
SCSS
end

private

def assert_sass_to_sass(sass, options = {})
Expand Down
50 changes: 28 additions & 22 deletions test/sass/functions_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def test_hsl_kwargs

def test_hsl_checks_bounds
assert_error_message("Saturation -114 must be between 0% and 100% for `hsl'", "hsl(10, -114, 12)");
assert_error_message("Lightness 256 must be between 0% and 100% for `hsl'", "hsl(10, 10, 256%)");
assert_error_message("Lightness 256% must be between 0% and 100% for `hsl'", "hsl(10, 10, 256%)");
end

def test_hsl_checks_types
Expand All @@ -94,7 +94,7 @@ def test_hsla

def test_hsla_checks_bounds
assert_error_message("Saturation -114 must be between 0% and 100% for `hsla'", "hsla(10, -114, 12, 1)");
assert_error_message("Lightness 256 must be between 0% and 100% for `hsla'", "hsla(10, 10, 256%, 0)");
assert_error_message("Lightness 256% must be between 0% and 100% for `hsla'", "hsla(10, 10, 256%, 0)");
assert_error_message("Alpha channel -0.1 must be between 0 and 1 for `hsla'", "hsla(10, 10, 10, -0.1)");
assert_error_message("Alpha channel 1.1 must be between 0 and 1 for `hsla'", "hsla(10, 10, 10, 1.1)");
end
Expand Down Expand Up @@ -189,24 +189,24 @@ def test_rgb_percent
end

def test_rgb_tests_bounds
assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgb'",
assert_error_message("Color value 256 must be between 0 and 255 for `rgb'",
"rgb(256, 1, 1)")
assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgb'",
assert_error_message("Color value 256 must be between 0 and 255 for `rgb'",
"rgb(1, 256, 1)")
assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgb'",
assert_error_message("Color value 256 must be between 0 and 255 for `rgb'",
"rgb(1, 1, 256)")
assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgb'",
assert_error_message("Color value 256 must be between 0 and 255 for `rgb'",
"rgb(1, 256, 257)")
assert_error_message("Color value -1 must be between 0 and 255 inclusive for `rgb'",
assert_error_message("Color value -1 must be between 0 and 255 for `rgb'",
"rgb(-1, 1, 1)")
end

def test_rgb_test_percent_bounds
assert_error_message("Color value 100.1% must be between 0% and 100% inclusive for `rgb'",
assert_error_message("Color value 100.1% must be between 0% and 100% for `rgb'",
"rgb(100.1%, 0, 0)")
assert_error_message("Color value -0.1% must be between 0% and 100% inclusive for `rgb'",
assert_error_message("Color value -0.1% must be between 0% and 100% for `rgb'",
"rgb(0, -0.1%, 0)")
assert_error_message("Color value 101% must be between 0% and 100% inclusive for `rgb'",
assert_error_message("Color value 101% must be between 0% and 100% for `rgb'",
"rgb(0, 0, 101%)")
end

Expand All @@ -224,19 +224,19 @@ def test_rgba
end

def test_rgb_tests_bounds
assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgba'",
assert_error_message("Color value 256 must be between 0 and 255 for `rgba'",
"rgba(256, 1, 1, 0.3)")
assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgba'",
assert_error_message("Color value 256 must be between 0 and 255 for `rgba'",
"rgba(1, 256, 1, 0.3)")
assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgba'",
assert_error_message("Color value 256 must be between 0 and 255 for `rgba'",
"rgba(1, 1, 256, 0.3)")
assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgba'",
assert_error_message("Color value 256 must be between 0 and 255 for `rgba'",
"rgba(1, 256, 257, 0.3)")
assert_error_message("Color value -1 must be between 0 and 255 inclusive for `rgba'",
assert_error_message("Color value -1 must be between 0 and 255 for `rgba'",
"rgba(-1, 1, 1, 0.3)")
assert_error_message("Alpha channel -0.2 must be between 0 and 1 inclusive for `rgba'",
assert_error_message("Alpha channel -0.2 must be between 0 and 1 for `rgba'",
"rgba(1, 1, 1, -0.2)")
assert_error_message("Alpha channel 1.2 must be between 0 and 1 inclusive for `rgba'",
assert_error_message("Alpha channel 1.2 must be between 0 and 1 for `rgba'",
"rgba(1, 1, 1, 1.2)")
end

Expand Down Expand Up @@ -733,15 +733,15 @@ def test_change_color_tests_types

def test_change_color_argument_errors
# Range
assert_error_message("Saturation must be between 0 and 100 for `change-color'",
assert_error_message("Saturation 101% must be between 0% and 100% for `change-color'",
"change-color(blue, $saturation: 101%)")
assert_error_message("Lightness must be between 0 and 100 for `change-color'",
assert_error_message("Lightness 101% must be between 0% and 100% for `change-color'",
"change-color(blue, $lightness: 101%)")
assert_error_message("Red value must be between 0 and 255 for `change-color'",
assert_error_message("Red value -1 must be between 0 and 255 for `change-color'",
"change-color(blue, $red: -1)")
assert_error_message("Green value must be between 0 and 255 for `change-color'",
assert_error_message("Green value 256 must be between 0 and 255 for `change-color'",
"change-color(blue, $green: 256)")
assert_error_message("Blue value must be between 0 and 255 for `change-color'",
assert_error_message("Blue value 500 must be between 0 and 255 for `change-color'",
"change-color(blue, $blue: 500)")

# Unknown argument
Expand Down Expand Up @@ -1072,6 +1072,12 @@ def test_only_kw_args
assert_equal "only-kw-args(a, b, c)", evaluate("only-kw-args($a: 1, $b: 2, $c: 3)")
end

## Regression Tests

def test_saturation_bounds
assert_equal "#fbfdff", evaluate("hsl(hue(#fbfdff), saturation(#fbfdff), lightness(#fbfdff))")
end

private

def evaluate(value)
Expand Down
8 changes: 4 additions & 4 deletions test/sass/script_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ class SassScriptTest < Test::Unit::TestCase
include Sass::Script

def test_color_checks_input
assert_raise_message(ArgumentError, "Blue value must be between 0 and 255") {Color.new([1, 2, -1])}
assert_raise_message(ArgumentError, "Red value must be between 0 and 255") {Color.new([256, 2, 3])}
assert_raise_message(ArgumentError, "Blue value -1 must be between 0 and 255") {Color.new([1, 2, -1])}
assert_raise_message(ArgumentError, "Red value 256 must be between 0 and 255") {Color.new([256, 2, 3])}
end

def test_color_checks_rgba_input
assert_raise_message(ArgumentError, "Alpha channel must be between 0 and 1") {Color.new([1, 2, 3, 1.1])}
assert_raise_message(ArgumentError, "Alpha channel must be between 0 and 1") {Color.new([1, 2, 3, -0.1])}
assert_raise_message(ArgumentError, "Alpha channel 1.1 must be between 0 and 1") {Color.new([1, 2, 3, 1.1])}
assert_raise_message(ArgumentError, "Alpha channel -0.1 must be between 0 and 1") {Color.new([1, 2, 3, -0.1])}
end

def test_string_escapes
Expand Down

0 comments on commit 8f937fc

Please sign in to comment.