Add a boolean datatype to SassScript.
This commit is contained in:
parent
d394f8165f
commit
901e1f378d
|
@ -1,3 +1,4 @@
|
||||||
|
require 'strscan'
|
||||||
require 'sass/constant/operation'
|
require 'sass/constant/operation'
|
||||||
require 'sass/constant/literal'
|
require 'sass/constant/literal'
|
||||||
|
|
||||||
|
@ -29,16 +30,20 @@ module Sass
|
||||||
?* => :times,
|
?* => :times,
|
||||||
?/ => :div,
|
?/ => :div,
|
||||||
?% => :mod,
|
?% => :mod,
|
||||||
|
?& => :single_and,
|
||||||
|
?| => :single_or,
|
||||||
CONSTANT_CHAR => :const,
|
CONSTANT_CHAR => :const,
|
||||||
STRING_CHAR => :str,
|
STRING_CHAR => :str,
|
||||||
ESCAPE_CHAR => :esc
|
ESCAPE_CHAR => :esc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CONSTANT_CHARS = (SYMBOLS.keys + [ ?= ]).map {|c| Regexp.escape(c.chr) }.join
|
||||||
|
|
||||||
# The regular expression used to parse constants
|
# The regular expression used to parse constants
|
||||||
MATCH = /^#{Regexp.escape(CONSTANT_CHAR.chr)}([^\s#{(SYMBOLS.keys + [ ?= ]).map {|c| Regexp.escape("#{c.chr}") }.join}]+)\s*((?:\|\|)?=)\s*(.+)/
|
MATCH = /^#{Regexp.escape(CONSTANT_CHAR.chr)}([^\s#{CONSTANT_CHARS}]+)\s*((?:\|\|)?=)\s*(.+)/
|
||||||
|
|
||||||
# The regular expression used to validate constants without matching
|
# The regular expression used to validate constants without matching
|
||||||
VALIDATE = /^#{Regexp.escape(CONSTANT_CHAR.chr)}[^\s#{(SYMBOLS.keys + [ ?= ]).map {|c| Regexp.escape("#{c.chr}") }.join}]+$/
|
VALIDATE = /^#{Regexp.escape(CONSTANT_CHAR.chr)}[^\s#{CONSTANT_CHARS}]+$/
|
||||||
|
|
||||||
# Order of operations hash
|
# Order of operations hash
|
||||||
ORDER = {
|
ORDER = {
|
||||||
|
@ -129,12 +134,17 @@ module Sass
|
||||||
end
|
end
|
||||||
|
|
||||||
# Time for a unary op!
|
# Time for a unary op!
|
||||||
if ![nil, :open, :close, :const].include?(symbol) && beginning_of_token
|
if ![nil, :open, :close, :const, :single_and, :single_or].include?(symbol) && beginning_of_token
|
||||||
beginning_of_token = true
|
beginning_of_token = true
|
||||||
to_return << :unary << symbol
|
to_return << :unary << symbol
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if (symbol == :single_and || symbol == :single_or) && last == symbol
|
||||||
|
to_return[-1] = symbol.to_s.gsub(/^single_/, '').to_sym
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
# Are we looking at an operator?
|
# Are we looking at an operator?
|
||||||
if symbol && (symbol != :mod || str.empty?)
|
if symbol && (symbol != :mod || str.empty?)
|
||||||
str = reset_str.call
|
str = reset_str.call
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
require 'sass/constant/literal'
|
||||||
|
|
||||||
|
module Sass::Constant
|
||||||
|
class Bool < Literal # :nodoc:
|
||||||
|
|
||||||
|
def parse(value)
|
||||||
|
first, second, unit = value.scan(Literal::NUMBER)[0]
|
||||||
|
@value = value == 'true' ? true : false
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
@value.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_bool
|
||||||
|
@value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,6 +6,7 @@ module Sass::Constant; class Literal; end; end;
|
||||||
require 'sass/constant/string'
|
require 'sass/constant/string'
|
||||||
require 'sass/constant/number'
|
require 'sass/constant/number'
|
||||||
require 'sass/constant/color'
|
require 'sass/constant/color'
|
||||||
|
require 'sass/constant/bool'
|
||||||
require 'sass/constant/nil'
|
require 'sass/constant/nil'
|
||||||
|
|
||||||
class Sass::Constant::Literal # :nodoc:
|
class Sass::Constant::Literal # :nodoc:
|
||||||
|
@ -23,6 +24,8 @@ class Sass::Constant::Literal # :nodoc:
|
||||||
Sass::Constant::Number.new(value)
|
Sass::Constant::Number.new(value)
|
||||||
when COLOR
|
when COLOR
|
||||||
Sass::Constant::Color.new(value)
|
Sass::Constant::Color.new(value)
|
||||||
|
when "true", "false"
|
||||||
|
Sass::Constant::Bool.new(value)
|
||||||
when ::Symbol
|
when ::Symbol
|
||||||
value
|
value
|
||||||
else
|
else
|
||||||
|
@ -42,6 +45,14 @@ class Sass::Constant::Literal # :nodoc:
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def and(other)
|
||||||
|
to_bool ? other : self
|
||||||
|
end
|
||||||
|
|
||||||
|
def or(other)
|
||||||
|
to_bool ? self : other
|
||||||
|
end
|
||||||
|
|
||||||
def concat(other)
|
def concat(other)
|
||||||
Sass::Constant::String.from_value("#{self.to_s} #{other.to_s}")
|
Sass::Constant::String.from_value("#{self.to_s} #{other.to_s}")
|
||||||
end
|
end
|
||||||
|
@ -58,6 +69,10 @@ class Sass::Constant::Literal # :nodoc:
|
||||||
[self]
|
[self]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_bool
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
attr_reader :value
|
attr_reader :value
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
|
@ -9,5 +9,9 @@ module Sass::Constant
|
||||||
def to_arglist
|
def to_arglist
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_bool
|
||||||
|
false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,9 @@ require 'sass/constant/unary_operation'
|
||||||
module Sass::Constant
|
module Sass::Constant
|
||||||
class Operation # :nodoc:
|
class Operation # :nodoc:
|
||||||
def initialize(operand1, operand2, operator)
|
def initialize(operand1, operand2, operator)
|
||||||
|
raise Sass::SyntaxError.new("SassScript doesn't support a single-& operator.") if operator == :single_and
|
||||||
|
raise Sass::SyntaxError.new("SassScript doesn't support a single-| operator.") if operator == :single_or
|
||||||
|
|
||||||
@operand1 = operand1
|
@operand1 = operand1
|
||||||
@operand2 = operand2
|
@operand2 = operand2
|
||||||
@operator = operator
|
@operator = operator
|
||||||
|
|
|
@ -67,6 +67,8 @@ class SassEngineTest < Test::Unit::TestCase
|
||||||
"=a(!foo bar)" => "Invalid constant \"!foo bar\".",
|
"=a(!foo bar)" => "Invalid constant \"!foo bar\".",
|
||||||
"=foo\n bar: baz\n+foo" => ["Attributes aren't allowed at the root of a document.", 2],
|
"=foo\n bar: baz\n+foo" => ["Attributes aren't allowed at the root of a document.", 2],
|
||||||
"a-\#{!b\n c: d" => ["Unbalanced brackets.", 1],
|
"a-\#{!b\n c: d" => ["Unbalanced brackets.", 1],
|
||||||
|
"!a = 1 & 2" => "SassScript doesn't support a single-& operator.",
|
||||||
|
"!a = 1 | 2" => "SassScript doesn't support a single-| operator.",
|
||||||
|
|
||||||
# Regression tests
|
# Regression tests
|
||||||
"a\n b:\n c\n d" => ["Illegal nesting: Only attributes may be nested beneath attributes.", 3],
|
"a\n b:\n c\n d" => ["Illegal nesting: Only attributes may be nested beneath attributes.", 3],
|
||||||
|
@ -369,6 +371,43 @@ a-\#{!a}
|
||||||
SASS
|
SASS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_booleans
|
||||||
|
assert_equal(<<CSS, render(<<SASS))
|
||||||
|
a {
|
||||||
|
b: true;
|
||||||
|
c: false;
|
||||||
|
t1: true;
|
||||||
|
t2: true;
|
||||||
|
t3: true;
|
||||||
|
t4: true;
|
||||||
|
f1: false;
|
||||||
|
f2: false;
|
||||||
|
f3: false;
|
||||||
|
f4: false; }
|
||||||
|
CSS
|
||||||
|
a
|
||||||
|
b = true
|
||||||
|
c = false
|
||||||
|
t1 = true && true
|
||||||
|
t2 = false || true
|
||||||
|
t3 = true || false
|
||||||
|
t4 = true || true
|
||||||
|
f1 = false || false
|
||||||
|
f2 = false && true
|
||||||
|
f3 = true && false
|
||||||
|
f4 = false && false
|
||||||
|
SASS
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_boolean_ops
|
||||||
|
assert_equal("a {\n b: 1;\n c: 2;\n d: 3; }\n", render(<<SASS))
|
||||||
|
a
|
||||||
|
b = false || 1
|
||||||
|
c = 2 || 3
|
||||||
|
d = 2 && 3
|
||||||
|
SASS
|
||||||
|
end
|
||||||
|
|
||||||
def test_functions
|
def test_functions
|
||||||
assert_equal("a {\n b: #80ff80; }\n", render("a\n b = hsl(120, 100%, 75%)"))
|
assert_equal("a {\n b: #80ff80; }\n", render("a\n b = hsl(120, 100%, 75%)"))
|
||||||
assert_equal("a {\n b: #81ff81; }\n", render("a\n b = hsl(120, 100%, 75%) + #010001"))
|
assert_equal("a {\n b: #81ff81; }\n", render("a\n b = hsl(120, 100%, 75%) + #010001"))
|
||||||
|
|
Loading…
Reference in New Issue