Rename Sass::Constant to Sass::Script, and refer to constants as variables.

This commit is contained in:
Nathan Weizenbaum 2008-10-12 19:03:06 -07:00
parent b59dffc442
commit 03d2ab6f3b
24 changed files with 236 additions and 241 deletions

View File

@ -175,14 +175,14 @@ becomes:
:text-decoration underline
Pretty nice, no? Well, it gets better.
One of the main complaints against CSS is that it doesn't allow constants.
One of the main complaints against CSS is that it doesn't allow variables.
What if have a color or a width you re-use all the time?
In CSS, you just have to re-type it each time,
which is a nightmare when you decide to change it later.
Not so for Sass!
You can use the "!" character to set constants.
You can use the "!" character to set variables.
Then, if you put "=" after your attribute name,
you can set it to a constant.
you can set it to a variable.
For example:
!note_bg= #55aaff
@ -205,7 +205,7 @@ becomes:
width: 5em;
background-color: #55aaff; }
You can even do simple arithmetic operations with constants,
You can even do simple arithmetic operations with variables,
adding numbers and even colors together:
!main_bg= #46ar12
@ -227,7 +227,7 @@ becomes:
background-color: #79d645;
width: 15em; }
Taking the idea of constants a bit further are mixins.
Taking the idea of variables a bit further are mixins.
These let you group whole swathes of CSS attributes into a single
directive and then include those anywhere you want:

2
TODO
View File

@ -2,7 +2,7 @@ Testing:
Test html2haml and css2sass
Features:
Sass should throw generic errors for undefined constants, not syntax errors
Sass should throw generic errors for undefined variables, not syntax errors
Sass::Plugin should log errors
There should be a way to make Haml tags not insert whitespace
"%li, %a"?

View File

@ -481,7 +481,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
#
# === Functions
#
# SassScript defines some useful functions (see Sass::Constant::Functions)
# SassScript defines some useful functions (see Sass::Script::Functions)
# that are called using the normal CSS function syntax:
#
# p

View File

@ -1,37 +0,0 @@
require 'strscan'
require 'sass/constant/funcall'
require 'sass/constant/operation'
require 'sass/constant/literal'
require 'sass/constant/parser'
module Sass
# This module contains various constant-script related functionality.
module Constant
# :stopdoc:
# The character that begins a constant.
CONSTANT_CHAR = ?!
# The regular expression used to parse constants
MATCH = /^!(\w+)\s*((?:\|\|)?=)\s*(.+)/
# The regular expression used to validate constants without matching
VALIDATE = /^!\w+$/
def self.resolve(*args)
parse(*args).to_s
end
def self.parse(value, constants, line)
Parser.parse(value, constants).perform
rescue Sass::SyntaxError => e
if e.message == "Constant arithmetic error"
e.instance_eval do
@message += ": #{value.dump}."
end
end
e.sass_line = line
raise e
end
# :startdoc:
end
end

View File

@ -1,61 +0,0 @@
# :stopdoc:
# Let the subclasses see the superclass
module Sass::Constant; class Literal; end; end;
# :startdoc:
require 'sass/constant/string'
require 'sass/constant/number'
require 'sass/constant/color'
require 'sass/constant/bool'
class Sass::Constant::Literal # :nodoc:
attr_reader :value
def initialize(value = nil)
@value = value
end
def perform
self
end
def and(other)
to_bool ? other : self
end
def or(other)
to_bool ? self : other
end
def eq(other)
Sass::Constant::Bool.new(self.class == other.class && self.value == other.value)
end
def neq(other)
Sass::Constant::Bool.new(!eq(other).to_bool)
end
def unary_not
Sass::Constant::Bool.new(!to_bool)
end
def concat(other)
Sass::Constant::String.new("#{self.to_s} #{other.to_s}")
end
def comma(other)
Sass::Constant::String.new("#{self.to_s}, #{other.to_s}")
end
def inspect
value.inspect
end
def to_bool
true
end
def to_i
raise SyntaxError.new("#{value.dump} is not an integer.")
end
end

View File

@ -1,33 +0,0 @@
require 'sass/constant/literal'
module Sass::Constant
class String < Literal # :nodoc:
def plus(other)
Sass::Constant::String.new(self.to_s + other.to_s)
end
def minus(other)
Sass::Constant::String.new("#{self.to_s}-#{other.to_s}")
end
def unary_minus
Sass::Constant::String.new("-#{self.to_s}")
end
def div(other)
Sass::Constant::String.new("#{self.to_s}/#{other.to_s}")
end
def unary_div
Sass::Constant::String.new("/#{self.to_s}")
end
def funcall(other)
Sass::Constant::String.new("#{self.to_s}(#{other.to_s})")
end
def to_s
@value
end
end
end

View File

@ -6,7 +6,7 @@ require 'sass/tree/rule_node'
require 'sass/tree/comment_node'
require 'sass/tree/attr_node'
require 'sass/tree/directive_node'
require 'sass/constant'
require 'sass/script'
require 'sass/error'
require 'haml/shared'
@ -27,7 +27,7 @@ module Sass
ATTRIBUTE_CHAR = ?:
# The character that designates that
# an attribute should be assigned to the result of constant arithmetic.
# an attribute should be assigned to a SassScript expression.
SCRIPT_CHAR = ?=
# The character that designates the beginning of a comment,
@ -83,7 +83,7 @@ module Sass
:load_paths => ['.']
}.merge! options
@template = template
@constants = {"important" => Constant::String.new("!important")}
@environment = {"important" => Script::String.new("!important")}
@mixins = {}
end
@ -104,8 +104,8 @@ module Sass
protected
def constants
@constants
def environment
@environment
end
def mixins
@ -171,7 +171,7 @@ END
@line = line.index
node = parse_line(line, root)
# Node is a symbol if it's non-outputting, like a constant assignment,
# Node is a symbol if it's non-outputting, like a variable assignment,
# or an array if it's a group of nodes to add
return node unless node.is_a? Tree::Node
@ -219,8 +219,8 @@ END
def validate_and_append_child(parent, child, line, root)
unless root
case child
when :constant
raise SyntaxError.new("Constants may only be declared at the root of a document.", line.index)
when :variable
raise SyntaxError.new("Variables may only be declared at the root of a document.", line.index)
when :mixin
raise SyntaxError.new("Mixins may only be defined at the root of a document.", line.index)
when Tree::DirectiveNode
@ -240,8 +240,8 @@ END
case line.text[0]
when ATTRIBUTE_CHAR
parse_attribute(line.text, ATTRIBUTE)
when Constant::CONSTANT_CHAR
parse_constant(line)
when Script::VARIABLE_CHAR
parse_variable(line)
when COMMENT_CHAR
parse_comment(line.text)
when DIRECTIVE_CHAR
@ -281,25 +281,25 @@ END
end
if eq.strip[0] == SCRIPT_CHAR
value = Sass::Constant.resolve(value, @constants, @line)
value = Script.resolve(value, @environment, @line)
end
Tree::AttrNode.new(interpolate(name), interpolate(value), @options)
end
def parse_constant(line)
name, op, value = line.text.scan(Sass::Constant::MATCH)[0]
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath constants.", @line + 1) unless line.children.empty?
raise SyntaxError.new("Invalid constant: \"#{line.text}\".", @line) unless name && value
def parse_variable(line)
name, op, value = line.text.scan(Script::MATCH)[0]
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath variable declarations.", @line + 1) unless line.children.empty?
raise SyntaxError.new("Invalid variable: \"#{line.text}\".", @line) unless name && value
constant = Sass::Constant.parse(value, @constants, @line)
var = Script.parse(value, @environment, @line)
if op == '||='
@constants[name] ||= constant
@environment[name] ||= var
else
@constants[name] = constant
@environment[name] = var
end
:constant
:variable
end
def parse_comment(line)
@ -332,7 +332,7 @@ END
end
def parse_if(line, root, text)
if Sass::Constant.parse(text, @constants, line.index).to_bool
if Script.parse(text, @environment, line.index).to_bool
append_children([], line.children, root)
else
[]
@ -344,7 +344,7 @@ END
if var.nil? # scan failed, try to figure out why for error message
if text !~ /^[^\s]+/
expected = "constant name"
expected = "variable name"
elsif text !~ /^[^\s]+\s+from\s+.+/
expected = "'from <expr>'"
else
@ -352,25 +352,25 @@ END
end
raise SyntaxError.new("Invalid for directive '@for #{text}': expected #{expected}.", @line)
end
raise SyntaxError.new("Invalid constant \"#{var}\".", @line) unless var =~ Constant::VALIDATE
raise SyntaxError.new("Invalid variable \"#{var}\".", @line) unless var =~ Script::VALIDATE
from = Sass::Constant.parse(from_expr, @constants, @line).to_i
to = Sass::Constant.parse(to_expr, @constants, @line).to_i
from = Script.parse(from_expr, @environment, @line).to_i
to = Script.parse(to_expr, @environment, @line).to_i
range = Range.new(from, to, to_name == 'to')
tree = []
old_constants = @constants.dup
old_env = @environment.dup
for i in range
@constants[var[1..-1]] = Constant::Number.new(i)
@environment[var[1..-1]] = Script::Number.new(i)
append_children(tree, line.children, root)
end
@constants = old_constants
@environment = old_env
tree
end
def parse_while(line, root, text)
tree = []
while Sass::Constant.parse(text, @constants, line.index).to_bool
while Script.parse(text, @environment, line.index).to_bool
append_children(tree, line.children, root)
end
tree
@ -394,15 +394,15 @@ END
required_arg_count = 0
args.map! do |arg|
raise SyntaxError.new("Mixin arguments can't be empty.", @line) if arg.empty? || arg == "!"
unless arg[0] == Constant::CONSTANT_CHAR
unless arg[0] == Script::VARIABLE_CHAR
raise SyntaxError.new("Mixin argument \"#{arg}\" must begin with an exclamation point (!).", @line)
end
arg, default = arg.split(/\s*=\s*/, 2)
required_arg_count += 1 unless default
default_arg_found ||= default
raise SyntaxError.new("Invalid constant \"#{arg}\".", @line) unless arg =~ Constant::VALIDATE
raise SyntaxError.new("Invalid variable \"#{arg}\".", @line) unless arg =~ Script::VALIDATE
raise SyntaxError.new("Required arguments must not follow optional arguments \"#{arg}\".", @line) if default_arg_found && !default
default = Sass::Constant.parse(default, @constants, @line) if default
default = Script.parse(default, @environment, @line) if default
{ :name => arg[1..-1], :default_value => default }
end
mixin = @mixins[name] = Mixin.new(args, line.children)
@ -422,19 +422,19 @@ Mixin #{name} takes #{mixin.args.size} argument#{'s' if mixin.args.size != 1}
but #{args.size} #{args.size == 1 ? 'was' : 'were'} passed.
END
old_constants = @constants.dup
mixin.args.zip(args).inject(@constants) do |constants, (arg, value)|
constants[arg[:name]] = if value
Sass::Constant.parse(value, old_constants, @line)
else
arg[:default_value]
end
raise SyntaxError.new("Mixin #{name} is missing parameter ##{mixin.args.index(arg)+1} (#{arg[:name]}).") unless constants[arg[:name]]
constants
old_env = @environment.dup
mixin.args.zip(args).inject(@environment) do |env, (arg, value)|
env[arg[:name]] = if value
Script.parse(value, old_env, @line)
else
arg[:default_value]
end
raise SyntaxError.new("Mixin #{name} is missing parameter ##{mixin.args.index(arg)+1} (#{arg[:name]}).") unless env[arg[:name]]
env
end
tree = append_children([], mixin.tree, root)
@constants = old_constants
@environment = old_env
tree
end
@ -448,7 +448,7 @@ END
if escapes % 2 == 1
str << '#{'
else
str << Sass::Constant.resolve(balance(scan, ?{, ?}, 1)[0][0...-1], @constants, @line)
str << Script.resolve(balance(scan, ?{, ?}, 1)[0][0...-1], @environment, @line)
end
end
@ -495,7 +495,7 @@ END
engine = Sass::Engine.new(file.read, new_options)
end
engine.constants.merge! @constants
engine.environment.merge! @environment
engine.mixins.merge! @mixins
begin
@ -505,7 +505,7 @@ END
raise err
end
nodes += root.children
@constants = engine.constants
@environment = engine.environment
@mixins = engine.mixins
end
end

37
lib/sass/script.rb Normal file
View File

@ -0,0 +1,37 @@
require 'strscan'
require 'sass/script/funcall'
require 'sass/script/operation'
require 'sass/script/literal'
require 'sass/script/parser'
module Sass
# This module contains various SassScript-related functionality.
module Script
# :stopdoc:
# The character that begins a variable.
VARIABLE_CHAR = ?!
# The regular expression used to parse variables
MATCH = /^!(\w+)\s*((?:\|\|)?=)\s*(.+)/
# The regular expression used to validate variables without matching
VALIDATE = /^!\w+$/
def self.resolve(*args)
parse(*args).to_s
end
def self.parse(value, environment, line)
Parser.parse(value, environment).perform
rescue Sass::SyntaxError => e
if e.message == "SassScript error"
e.instance_eval do
@message += ": #{value.dump}."
end
end
e.sass_line = line
raise e
end
# :startdoc:
end
end

View File

@ -1,6 +1,6 @@
require 'sass/constant/literal'
require 'sass/script/literal'
module Sass::Constant
module Sass::Script
class Bool < Literal # :nodoc:
def to_s
@value.to_s

View File

@ -1,6 +1,6 @@
require 'sass/constant/literal'
require 'sass/script/literal'
module Sass::Constant
module Sass::Script
class Color < Literal # :nodoc:
HTML4_COLORS = {
@ -27,15 +27,15 @@ module Sass::Constant
end
def plus(other)
if other.is_a? Sass::Constant::String
Sass::Constant::String.new(self.to_s + other.to_s)
if other.is_a? Sass::Script::String
Sass::Script::String.new(self.to_s + other.to_s)
else
piecewise(other, :+)
end
end
def minus(other)
if other.is_a? Sass::Constant::String
if other.is_a? Sass::Script::String
raise NoMethodError.new(nil, :minus)
else
piecewise(other, :-)
@ -43,7 +43,7 @@ module Sass::Constant
end
def times(other)
if other.is_a? Sass::Constant::String
if other.is_a? Sass::Script::String
raise NoMethodError.new(nil, :times)
else
piecewise(other, :*)
@ -51,7 +51,7 @@ module Sass::Constant
end
def div(other)
if other.is_a? Sass::Constant::String
if other.is_a? Sass::Script::String
raise NoMethodError.new(nil, :div)
else
piecewise(other, :/)
@ -59,7 +59,7 @@ module Sass::Constant
end
def mod(other)
if other.is_a? Sass::Constant::String
if other.is_a? Sass::Script::String
raise NoMethodError.new(nil, :mod)
else
piecewise(other, :%)

View File

@ -1,5 +1,5 @@
module Sass
module Constant
module Script
class Funcall
attr_reader :name, :args
@ -18,7 +18,7 @@ module Sass
def perform
unless Functions.public_instance_methods.include?(name) && name !~ /^__/
return Constant::String.new("#{name}(#{args.join(', ')})")
return Script::String.new("#{name}(#{args.join(', ')})")
end
return Functions.send(name, *args)

View File

@ -1,14 +1,14 @@
module Sass::Constant
# Methods in this module are accessible from the Sass constant context.
module Sass::Script
# Methods in this module are accessible from the Sass script context.
# For example, you can write
#
# color = hsl(120, 100%, 50%)
#
# and it will call Sass::Constant::Functions#hsl.
# and it will call Sass::Script::Functions#hsl.
#
# You can add your own functions to this module,
# but there are a few things to keep in mind.
# First of all, the arguments passed are (currently undocumented) Sass::Constant::Literal objects,
# First of all, the arguments passed are (currently undocumented) Sass::Script::Literal objects,
# Literal objects are also the expected return values.
#
# Second, making Ruby functions accessible from Sass introduces the temptation
@ -22,7 +22,7 @@ module Sass::Constant
instance_methods.each { |m| undef_method m unless m =~ /^__/ }
extend self
# Creates a Sass::Constant::Color object from hue, saturation, and lightness.
# Creates a Sass::Script::Color object from hue, saturation, and lightness.
# As per the CSS3 spec (http://www.w3.org/TR/css3-color/#hsl-color),
# hue is in degrees,
# and saturation and lightness are percentages.
@ -41,11 +41,11 @@ module Sass::Constant
end
def percentage(value)
value = value.perform if value.is_a?(Sass::Constant::Operation)
unless value.is_a?(Sass::Constant::Number) && value.unitless?
value = value.perform if value.is_a?(Sass::Script::Operation)
unless value.is_a?(Sass::Script::Number) && value.unitless?
raise ArgumentError.new("Value is not a unitless number")
end
Sass::Constant::Number.new(value.value * 100, '%')
Sass::Script::Number.new(value.value * 100, '%')
end
private

View File

@ -1,7 +1,7 @@
require 'strscan'
module Sass
module Constant
module Script
class Lexer
OPERATORS = {
'+' => :plus,
@ -39,7 +39,7 @@ module Sass
end
whitespace
constant || string || number || color || bool || op || ident ||
variable || string || number || color || bool || op || ident ||
(raise SyntaxError.new("Syntax error in '#{@scanner.string}' at '#{@scanner.rest}'."))
end
@ -62,7 +62,7 @@ module Sass
@scanner.scan(/\s*/)
end
def constant
def variable
return unless @scanner.scan(/!(\w+)/)
[:const, @scanner[1]]
end
@ -74,14 +74,14 @@ module Sass
def string
return unless @scanner.scan(/"((?:\\.|[^"\\])*)"/)
[:string, Constant::String.new(@scanner[1].gsub(/\\(.)/, '\1'))]
[:string, Script::String.new(@scanner[1].gsub(/\\(.)/, '\1'))]
end
def number
return unless @scanner.scan(/(-)?(?:(\d*\.\d+)|(\d+))([a-zA-Z%]+)?/)
value = @scanner[2] ? @scanner[2].to_f : @scanner[3].to_i
value = -value if @scanner[1]
[:number, Constant::Number.new(value, Array(@scanner[4]))]
[:number, Script::Number.new(value, Array(@scanner[4]))]
end
COLOR = /\##{"([0-9a-fA-F]{1,2})" * 3}|(#{Color::HTML4_COLORS.keys.join("|")})/
@ -93,12 +93,12 @@ module Sass
else
(1..3).map {|i| @scanner[i]}.map {|num| num.ljust(2, num).to_i(16)}
end
[:color, Constant::Color.new(value)]
[:color, Script::Color.new(value)]
end
def bool
return unless s = @scanner.scan(/(true|false)\b/)
[:bool, Constant::Bool.new(s == 'true')]
[:bool, Script::Bool.new(s == 'true')]
end
def op

View File

@ -0,0 +1,56 @@
class Sass::Script::Literal # :nodoc:
require 'sass/script/string'
require 'sass/script/number'
require 'sass/script/color'
require 'sass/script/bool'
attr_reader :value
def initialize(value = nil)
@value = value
end
def perform
self
end
def and(other)
to_bool ? other : self
end
def or(other)
to_bool ? self : other
end
def eq(other)
Sass::Script::Bool.new(self.class == other.class && self.value == other.value)
end
def neq(other)
Sass::Script::Bool.new(!eq(other).to_bool)
end
def unary_not
Sass::Script::Bool.new(!to_bool)
end
def concat(other)
Sass::Script::String.new("#{self.to_s} #{other.to_s}")
end
def comma(other)
Sass::Script::String.new("#{self.to_s}, #{other.to_s}")
end
def inspect
value.inspect
end
def to_bool
true
end
def to_i
raise SyntaxError.new("#{value.dump} is not an integer.")
end
end

View File

@ -1,6 +1,6 @@
require 'sass/constant/literal'
require 'sass/script/literal'
module Sass::Constant
module Sass::Script
class Number < Literal # :nodoc:
attr_reader :numerator_units, :denominator_units
@ -20,7 +20,7 @@ module Sass::Constant
elsif other.is_a?(Color)
other.plus(self)
else
Sass::Constant::String.new(self.to_s + other.to_s)
Sass::Script::String.new(self.to_s + other.to_s)
end
end
@ -66,7 +66,7 @@ module Sass::Constant
end
def eq(other)
Sass::Constant::Bool.new(super.to_bool &&
Sass::Script::Bool.new(super.to_bool &&
self.numerator_units.sort == other.numerator_units.sort &&
self.denominator_units.sort == other.denominator_units.sort)
end

View File

@ -1,10 +1,10 @@
require 'sass/constant/string'
require 'sass/constant/number'
require 'sass/constant/color'
require 'sass/constant/functions'
require 'sass/constant/unary_operation'
require 'sass/script/string'
require 'sass/script/number'
require 'sass/script/color'
require 'sass/script/functions'
require 'sass/script/unary_operation'
module Sass::Constant
module Sass::Script
class Operation # :nodoc:
def initialize(operand1, operand2, operator)
@operand1 = operand1

View File

@ -1,11 +1,11 @@
require 'sass/constant/lexer'
require 'sass/script/lexer'
module Sass
module Constant
module Script
class Parser
def initialize(str, constants = {})
def initialize(str, environment = {})
@lexer = Lexer.new(str)
@constants = constants
@environment = environment
end
def parse
@ -67,10 +67,10 @@ RUBY
def funcall
return paren unless name = try_tok(:ident)
# An identifier without arguments is just a string
return Constant::String.new(name.last) unless try_tok(:lparen)
return Script::String.new(name.last) unless try_tok(:lparen)
args = arglist || []
assert_tok(:rparen)
Constant::Funcall.new(name.last, args)
Script::Funcall.new(name.last, args)
end
def arglist
@ -80,17 +80,17 @@ RUBY
end
def paren
return constant unless try_tok(:lparen)
return variable unless try_tok(:lparen)
e = assert_expr(:expr)
assert_tok(:rparen)
return e
end
def constant
def variable
return literal unless c = try_tok(:const)
(val = @constants[c.last]) && (return val)
(val = @environment[c.last]) && (return val)
raise SyntaxError.new("Undefined constant: \"!#{c.last}\".")
raise SyntaxError.new("Undefined variable: \"!#{c.last}\".")
end
def literal

33
lib/sass/script/string.rb Normal file
View File

@ -0,0 +1,33 @@
require 'sass/script/literal'
module Sass::Script
class String < Literal # :nodoc:
def plus(other)
Sass::Script::String.new(self.to_s + other.to_s)
end
def minus(other)
Sass::Script::String.new("#{self.to_s}-#{other.to_s}")
end
def unary_minus
Sass::Script::String.new("-#{self.to_s}")
end
def div(other)
Sass::Script::String.new("#{self.to_s}/#{other.to_s}")
end
def unary_div
Sass::Script::String.new("/#{self.to_s}")
end
def funcall(other)
Sass::Script::String.new("#{self.to_s}(#{other.to_s})")
end
def to_s
@value
end
end
end

View File

@ -1,4 +1,4 @@
module Sass::Constant
module Sass::Script
class UnaryOperation # :nodoc:
def initialize(operand, operator)
@operand = operand

View File

@ -31,11 +31,11 @@ class SassEngineTest < Test::Unit::TestCase
"a\n b : c" => 'Invalid attribute: "b : c".',
"a\n b=c: d" => 'Invalid attribute: "b=c: d".',
":a" => 'Attributes aren\'t allowed at the root of a document.',
"!" => 'Invalid constant: "!".',
"!a" => 'Invalid constant: "!a".',
"! a" => 'Invalid constant: "! a".',
"!a b" => 'Invalid constant: "!a b".',
"a\n :b c\n !d = 3" => "Constants may only be declared at the root of a document.",
"!" => 'Invalid variable: "!".',
"!a" => 'Invalid variable: "!a".',
"! a" => 'Invalid variable: "! a".',
"!a b" => 'Invalid variable: "!a b".',
"a\n :b c\n !d = 3" => "Variables may only be declared at the root of a document.",
"!a = 1b + 2c" => "Incompatible units: 'c' and 'b'.",
"a\n :b= 1b * 2c" => "2b*c isn't a valid CSS value.",
"a\n :b= 1b % 2c" => "Cannot modulo by a number with units: 2c.",
@ -46,7 +46,7 @@ class SassEngineTest < Test::Unit::TestCase
"a,\n :b c" => ["Rules can\'t end in commas.", 1],
"a," => "Rules can\'t end in commas.",
"a,\n!b = c" => ["Rules can\'t end in commas.", 1],
"!a = b\n :c d\n" => "Illegal nesting: Nothing may be nested beneath constants.",
"!a = b\n :c d\n" => "Illegal nesting: Nothing may be nested beneath variable declarations.",
"@import foo.sass" => "File to import not found or unreadable: foo.sass.",
"@import templates/basic\n foo" => "Illegal nesting: Nothing may be nested beneath import directives.",
"foo\n @import templates/basic" => "Import directives may only be used at the root of a document.",
@ -68,7 +68,7 @@ class SassEngineTest < Test::Unit::TestCase
"=a(b)" => 'Mixin argument "b" must begin with an exclamation point (!).',
"=a(,)" => "Mixin arguments can't be empty.",
"=a(!)" => "Mixin arguments can't be empty.",
"=a(!foo bar)" => "Invalid constant \"!foo bar\".",
"=a(!foo bar)" => "Invalid variable \"!foo bar\".",
"=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 = 1, !c)" => "Required arguments must not follow optional arguments \"!c\".",

View File

@ -1,6 +1,6 @@
require 'test/unit'
require File.dirname(__FILE__) + '/../../lib/sass'
require 'sass/constant'
require 'sass/script'
class SassFunctionTest < Test::Unit::TestCase
def test_hsl
@ -46,6 +46,6 @@ class SassFunctionTest < Test::Unit::TestCase
private
def assert_rgb_hsl(rgb, hsl)
assert_equal(rgb, Sass::Constant::Functions.hsl(*hsl.map(&Sass::Constant::Parser.method(:parse))).value)
assert_equal(rgb, Sass::Script::Functions.hsl(*hsl.map(&Sass::Script::Parser.method(:parse))).value)
end
end

View File

@ -5,7 +5,7 @@ require 'fileutils'
class SassPluginTest < Test::Unit::TestCase
@@templates = %w{
complex constants parent_ref import alt
complex script parent_ref import alt
subdir/subdir subdir/nested_subdir/nested_subdir
}
@ -52,7 +52,7 @@ class SassPluginTest < Test::Unit::TestCase
File.delete(tempfile_loc('bork'))
Sass::Plugin.update_stylesheets
File.open(tempfile_loc('bork')) do |file|
assert_equal("/*\nSass::SyntaxError: Undefined constant: \"!bork\".\non line 2 of #{template_loc('bork')}\n\n1: bork\n2: :bork= !bork", file.read.split("\n")[0...6].join("\n"))
assert_equal("/*\nSass::SyntaxError: Undefined variable: \"!bork\".\non line 2 of #{template_loc('bork')}\n\n1: bork\n2: :bork= !bork", file.read.split("\n")[0...6].join("\n"))
end
File.delete(tempfile_loc('bork'))
end