[Sass] Refer to properties as properties, not attributes.

This commit is contained in:
Nathan Weizenbaum 2009-06-19 03:33:03 -07:00
parent 36b316a60c
commit 81900a6db5
9 changed files with 122 additions and 124 deletions

View File

@ -113,9 +113,9 @@ At its most basic,
Sass is just another way of writing CSS. Sass is just another way of writing CSS.
Although it's very much like normal CSS, Although it's very much like normal CSS,
the basic syntax offers a few helpful features: the basic syntax offers a few helpful features:
tabulation indicates the attributes in a rule, indentation indicates the properties in a rule,
rather than non-DRY brackets; rather than non-DRY brackets;
and newlines indicate the end of an attribute, and newlines indicate the end of a properties,
rather than a semicolon. rather than a semicolon.
For example: For example:
@ -181,7 +181,7 @@ In CSS, you just have to re-type it each time,
which is a nightmare when you decide to change it later. which is a nightmare when you decide to change it later.
Not so for Sass! Not so for Sass!
You can use the `!` character to set variables. You can use the `!` character to set variables.
Then, if you put `=` after your attribute name, Then, if you put `=` after your property name,
you can set it to a variable. you can set it to a variable.
For example: For example:
@ -228,7 +228,7 @@ becomes:
width: 15em; } width: 15em; }
Taking the idea of variables 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 These let you group whole bunches of CSS properties into a single
directive and then include those anywhere you want: directive and then include those anywhere you want:
=blue-border =blue-border

View File

@ -101,15 +101,15 @@ Available options are:
: Sets the style of the CSS output. : Sets the style of the CSS output.
See the section on Output Style, above. See the section on Output Style, above.
{#attribute_syntax-option} `:attribute_syntax` {#property_syntax-option} `:property_syntax`
: Forces the document to use one syntax for attributes. : Forces the document to use one syntax for properties.
If the correct syntax isn't used, an error is thrown. If the correct syntax isn't used, an error is thrown.
`:new` forces the use of a colon or equals sign `:new` forces the use of a colon or equals sign
after the attribute name. after the property name.
For example: `color: #0f3` For example: `color: #0f3`
or `width = !main_width`. or `width = !main_width`.
`:old` forces the use of a colon `:old` forces the use of a colon
before the attribute name. before the property name.
For example: `:color #0f3` For example: `:color #0f3`
or `:width = !main_width`. or `:width = !main_width`.
By default, either syntax is valid. By default, either syntax is valid.
@ -194,11 +194,8 @@ Available options are:
## CSS Rules ## CSS Rules
Rules in flat CSS have two elements: Rules in flat CSS have two elements:
the selector the selector (e.g. `#main`, `div p`, `li a:hover`)
(e.g. `#main`, `div p`, `li a:hover`) and the properties (e.g. `color: #00ff00;`, `width: 5em;`).
and the attributes
(e.g. `color: #00ff00;`, `width: 5em;`).
Sass has both of these, Sass has both of these,
as well as one additional element: nested rules. as well as one additional element: nested rules.
@ -206,13 +203,13 @@ as well as one additional element: nested rules.
However, some of the syntax is a little different. However, some of the syntax is a little different.
The syntax for selectors is the same, The syntax for selectors is the same,
but instead of using brackets to delineate the attributes that belong to a particular rule, but instead of using brackets to delineate the properties that belong to a particular rule,
Sass uses indentation. Sass uses indentation.
For example: For example:
#main p #main p
<attribute> <property>
<attribute> <property>
... ...
Like CSS, you can stretch rules over multiple lines. Like CSS, you can stretch rules over multiple lines.
@ -222,15 +219,15 @@ For example:
.users #userTab, .users #userTab,
.posts #postsTab .posts #postsTab
<attributes> <property>
### Attributes ### Properties
There are two different ways to write CSS attributes. There are two different ways to write CSS properties.
The first is very similar to the how you're used to writing them: The first is very similar to the how you're used to writing them:
with a colon between the name and the value. with a colon between the name and the value.
However, Sass attributes don't have semicolons at the end; However, Sass properties don't have semicolons at the end;
each attribute is on its own line, so they aren't necessary. each property is on its own line, so they aren't necessary.
For example: For example:
#main p #main p
@ -243,10 +240,10 @@ is compiled to:
color: #00ff00; color: #00ff00;
width: 97% } width: 97% }
The second syntax for attributes is slightly different. The second syntax for properties is slightly different.
The colon is at the beginning of the attribute, The colon is at the beginning of the property,
rather than between the name and the value, rather than between the name and the value,
so it's easier to tell what elements are attributes just by glancing at them. so it's easier to tell what elements are properties just by glancing at them.
For example: For example:
#main p #main p
@ -259,9 +256,9 @@ is compiled to:
color: #00ff00; color: #00ff00;
width: 97% } width: 97% }
By default, either attribute syntax may be used. By default, either property syntax may be used.
If you want to force one or the other, If you want to force one or the other,
see the [`:attribute_syntax`](#attribute_syntax-option) option. see the [`:property_syntax`](#property_syntax-option) option.
### Nested Rules ### Nested Rules
@ -320,7 +317,7 @@ by using the ampersand character `&` in your selectors.
The ampersand is automatically replaced by the parent selector, The ampersand is automatically replaced by the parent selector,
instead of having it prepended. instead of having it prepended.
This allows you to cleanly create pseudo-attributes: This allows you to cleanly create pseudo-classes:
a a
font-weight: bold font-weight: bold
@ -361,16 +358,16 @@ Which would become:
.ie6 #main #sidebar { .ie6 #main #sidebar {
margin-left: 40%; } margin-left: 40%; }
### Attribute Namespaces ### Property Namespaces
CSS has quite a few attributes that are in "namespaces;" CSS has quite a few properties that are in "namespaces;"
for instance, `font-family`, `font-size`, and `font-weight` for instance, `font-family`, `font-size`, and `font-weight`
are all in the `font` namespace. are all in the `font` namespace.
In CSS, if you want to set a bunch of attributes in the same namespace, In CSS, if you want to set a bunch of properties in the same namespace,
you have to type it out each time. you have to type it out each time.
Sass offers a shortcut for this: Sass offers a shortcut for this:
just write the namespace one, just write the namespace one,
then indent each of the sub-attributes within it. then indent each of the sub-properties within it.
For example: For example:
.funky .funky
@ -635,7 +632,7 @@ is compiled to:
color: #357; color: #357;
For old-style attributes, the `=` is added but the `:` is retained. For old-style properties, the `=` is added but the `:` is retained.
For example: For example:
:color = #123 + #234 :color = #123 + #234
@ -671,7 +668,7 @@ and are set like so:
!width = 5em !width = 5em
You can then refer to them by putting an equals sign You can then refer to them by putting an equals sign
after your attributes: after your properties:
#main #main
width = !width width = !width
@ -799,7 +796,7 @@ See {Sass::Script::Functions} for more information.
### Interpolation: `#{}` ### Interpolation: `#{}`
You can also use SassScript variables in selectors You can also use SassScript variables in selectors
and attribute names using #{} interpolation syntax: and property names using #{} interpolation syntax:
!name = foo !name = foo
!attr = border !attr = border
@ -836,7 +833,7 @@ is compiled to:
## Mixins ## Mixins
Mixins enable you to define groups of CSS attributes and Mixins enable you to define groups of CSS properties and
then include them inline in any number of selectors then include them inline in any number of selectors
throughout the document. This allows you to keep your throughout the document. This allows you to keep your
stylesheets DRY and also avoid placing presentation stylesheets DRY and also avoid placing presentation
@ -965,14 +962,14 @@ For example:
/* A very awesome rule. /* A very awesome rule.
#awesome.rule #awesome.rule
/* An equally awesome attribute. /* An equally awesome property.
awesomeness: very awesomeness: very
becomes becomes
/* A very awesome rule. */ /* A very awesome rule. */
#awesome.rule { #awesome.rule {
/* An equally awesome attribute. */ /* An equally awesome property. */
awesomeness: very; } awesomeness: very; }
You can also nest content beneath loud comments. For example: You can also nest content beneath loud comments. For example:
@ -1006,7 +1003,7 @@ For example:
// A very awesome rule. // A very awesome rule.
#awesome.rule #awesome.rule
// An equally awesome attribute. // An equally awesome property.
awesomeness: very awesomeness: very
becomes becomes
@ -1019,7 +1016,7 @@ For example:
// A very awesome rule // A very awesome rule
#awesome.rule #awesome.rule
// Don't use these attributes // Don't use these properties
color: green color: green
font-size: 10em font-size: 10em
color: red color: red
@ -1045,7 +1042,7 @@ outside Rails, it's done by passing an options hash with `:style` set.
Nested style is the default Sass style, Nested style is the default Sass style,
because it reflects the structure of the document because it reflects the structure of the document
in much the same way Sass does. in much the same way Sass does.
Each attribute has its own line, Each property has its own line,
but the indentation isn't constant. but the indentation isn't constant.
Each rule is indented based on how deeply it's nested. Each rule is indented based on how deeply it's nested.
For example: For example:
@ -1069,8 +1066,8 @@ without actually reading anything.
### `:expanded` ### `:expanded`
Expanded is the typical human-made CSS style, Expanded is the typical human-made CSS style,
with each attribute and rule taking up one line. with each property and rule taking up one line.
Attributes are indented within the rules, Properties are indented within the rules,
but the rules aren't indented in any special way. but the rules aren't indented in any special way.
For example: For example:
@ -1094,7 +1091,7 @@ Compact style, as the name would imply,
takes up less space than Nested or Expanded. takes up less space than Nested or Expanded.
However, it's also harder to read. However, it's also harder to read.
Each CSS rule takes up only one line, Each CSS rule takes up only one line,
with every attribute defined on that line. with every property defined on that line.
Nested rules are placed next to each other with no newline, Nested rules are placed next to each other with no newline,
while groups of rules have newlines between them. while groups of rules have newlines between them.
For example: For example:

View File

@ -60,7 +60,7 @@ module Sass
class CSS class CSS
# @param template [String] The CSS code # @param template [String] The CSS code
# @option options :old [Boolean] (false) # @option options :old [Boolean] (false)
# Whether or not to output old attribute syntax # Whether or not to output old property syntax
# (`:color blue` as opposed to `color: blue`). # (`:color blue` as opposed to `color: blue`).
def initialize(template, options = {}) def initialize(template, options = {})
if template.is_a? IO if template.is_a? IO
@ -135,14 +135,14 @@ module Sass
assert_match /\{/ assert_match /\{/
node = Tree::RuleNode.new(rule) node = Tree::RuleNode.new(rule)
attributes(node) properties(node)
return node return node
end end
# Parses a set of CSS attributes within a rule. # Parses a set of CSS properties within a rule.
# #
# @param rule [Tree::RuleNode] The parent node of the attributes # @param rule [Tree::RuleNode] The parent node of the properties
def attributes(rule) def properties(rule)
while @template.scan(/[^:\}\s]+/) while @template.scan(/[^:\}\s]+/)
name = @template[0] name = @template[0]
whitespace whitespace

View File

@ -75,11 +75,11 @@ module Sass
end end
end end
# The character that begins a CSS attribute. # The character that begins a CSS property.
ATTRIBUTE_CHAR = ?: PROPERTY_CHAR = ?:
# The character that designates that # The character that designates that
# an attribute should be assigned to a SassScript expression. # a property should be assigned to a SassScript expression.
SCRIPT_CHAR = ?= SCRIPT_CHAR = ?=
# The character that designates the beginning of a comment, # The character that designates the beginning of a comment,
@ -106,16 +106,16 @@ module Sass
# Includes named mixin declared using MIXIN_DEFINITION_CHAR # Includes named mixin declared using MIXIN_DEFINITION_CHAR
MIXIN_INCLUDE_CHAR = ?+ MIXIN_INCLUDE_CHAR = ?+
# The regex that matches attributes of the form <tt>name: attr</tt>. # The regex that matches properties of the form <tt>name: prop</tt>.
ATTRIBUTE_NEW_MATCHER = /^[^\s:"]+\s*[=:](\s|$)/ PROPERTY_NEW_MATCHER = /^[^\s:"]+\s*[=:](\s|$)/
# The regex that matches and extracts data from # The regex that matches and extracts data from
# attributes of the form <tt>name: attr</tt>. # properties of the form <tt>name: prop</tt>.
ATTRIBUTE_NEW = /^([^\s=:"]+)(\s*=|:)(?:\s+|$)(.*)/ PROPERTY_NEW = /^([^\s=:"]+)(\s*=|:)(?:\s+|$)(.*)/
# The regex that matches and extracts data from # The regex that matches and extracts data from
# attributes of the form <tt>:name attr</tt>. # properties of the form <tt>:name prop</tt>.
ATTRIBUTE_OLD = /^:([^\s=:"]+)\s*(=?)(?:\s+|$)(.*)/ PROPERTY_OLD = /^:([^\s=:"]+)\s*(=?)(?:\s+|$)(.*)/
# The default options for Sass::Engine. # The default options for Sass::Engine.
DEFAULT_OPTIONS = { DEFAULT_OPTIONS = {
@ -133,9 +133,10 @@ module Sass
@template = template @template = template
# Backwards compatibility # Backwards compatibility
case @options[:attribute_syntax] @options[:property_syntax] ||= @options[:attribute_syntax]
when :alternate; @options[:attribute_syntax] = :new case @options[:property_syntax]
when :normal; @options[:attribute_syntax] = :old when :alternate; @options[:property_syntax] = :new
when :normal; @options[:property_syntax] = :old
end end
end end
@ -290,9 +291,9 @@ END
def parse_line(parent, line, root) def parse_line(parent, line, root)
case line.text[0] case line.text[0]
when ATTRIBUTE_CHAR when PROPERTY_CHAR
if line.text[1] != ATTRIBUTE_CHAR if line.text[1] != PROPERTY_CHAR
parse_attribute(line, ATTRIBUTE_OLD) parse_property(line, PROPERTY_OLD)
else else
# Support CSS3-style pseudo-elements, # Support CSS3-style pseudo-elements,
# which begin with :: # which begin with ::
@ -315,26 +316,26 @@ END
parse_mixin_include(line, root) parse_mixin_include(line, root)
end end
else else
if line.text =~ ATTRIBUTE_NEW_MATCHER if line.text =~ PROPERTY_NEW_MATCHER
parse_attribute(line, ATTRIBUTE_NEW) parse_property(line, PROPERTY_NEW)
else else
Tree::RuleNode.new(line.text) Tree::RuleNode.new(line.text)
end end
end end
end end
def parse_attribute(line, attribute_regx) def parse_property(line, property_regx)
name, eq, value = line.text.scan(attribute_regx)[0] name, eq, value = line.text.scan(property_regx)[0]
if name.nil? || value.nil? if name.nil? || value.nil?
raise SyntaxError.new("Invalid attribute: \"#{line.text}\".", @line) raise SyntaxError.new("Invalid property: \"#{line.text}\".", @line)
end end
expr = if (eq.strip[0] == SCRIPT_CHAR) expr = if (eq.strip[0] == SCRIPT_CHAR)
parse_script(value, :offset => line.offset + line.text.index(value)) parse_script(value, :offset => line.offset + line.text.index(value))
else else
value value
end end
Tree::AttrNode.new(name, expr, attribute_regx == ATTRIBUTE_OLD ? :old : :new) Tree::AttrNode.new(name, expr, property_regx == PROPERTY_OLD ? :old : :new)
end end
def parse_variable(line) def parse_variable(line)

View File

@ -16,12 +16,12 @@ module Sass::Tree
# @param name [String] See \{#name} # @param name [String] See \{#name}
# @param value [String] See \{#value} # @param value [String] See \{#value}
# @param attr_syntax [Symbol] `:new` if this property uses `a: b`-style syntax, # @param prop_syntax [Symbol] `:new` if this property uses `a: b`-style syntax,
# `:old` if it uses `:a b`-style syntax # `:old` if it uses `:a b`-style syntax
def initialize(name, value, attr_syntax) def initialize(name, value, prop_syntax)
@name = name @name = name
@value = value @value = value
@attr_syntax = attr_syntax @prop_syntax = prop_syntax
super() super()
end end
@ -39,22 +39,22 @@ module Sass::Tree
# @param tabs [Fixnum] The level of indentation for the CSS # @param tabs [Fixnum] The level of indentation for the CSS
# @param parent_name [String] The name of the parent property (e.g. `text`) or nil # @param parent_name [String] The name of the parent property (e.g. `text`) or nil
# @return [String] The resulting CSS # @return [String] The resulting CSS
# @raise [Sass::SyntaxError] if the attribute uses invalid syntax # @raise [Sass::SyntaxError] if the property uses invalid syntax
def to_s(tabs, parent_name = nil) def to_s(tabs, parent_name = nil)
if @options[:attribute_syntax] == :old && @attr_syntax == :new if @options[:property_syntax] == :old && @prop_syntax == :new
raise Sass::SyntaxError.new("Illegal attribute syntax: can't use new syntax when :attribute_syntax => :old is set.") raise Sass::SyntaxError.new("Illegal property syntax: can't use new syntax when :property_syntax => :old is set.")
elsif @options[:attribute_syntax] == :new && @attr_syntax == :old elsif @options[:property_syntax] == :new && @prop_syntax == :old
raise Sass::SyntaxError.new("Illegal attribute syntax: can't use old syntax when :attribute_syntax => :new is set.") raise Sass::SyntaxError.new("Illegal property syntax: can't use old syntax when :property_syntax => :new is set.")
end end
if value[-1] == ?; if value[-1] == ?;
raise Sass::SyntaxError.new("Invalid attribute: #{declaration.dump} (no \";\" required at end-of-line).", @line) raise Sass::SyntaxError.new("Invalid property: #{declaration.dump} (no \";\" required at end-of-line).", @line)
end end
real_name = name real_name = name
real_name = "#{parent_name}-#{real_name}" if parent_name real_name = "#{parent_name}-#{real_name}" if parent_name
if value.empty? && children.empty? if value.empty? && children.empty?
raise Sass::SyntaxError.new("Invalid attribute: #{declaration.dump} (no value).", @line) raise Sass::SyntaxError.new("Invalid property: #{declaration.dump} (no value).", @line)
end end
join_string = case style join_string = case style
@ -96,14 +96,14 @@ module Sass::Tree
# @return [String] An error message if the child is invalid, or nil otherwise # @return [String] An error message if the child is invalid, or nil otherwise
def invalid_child?(child) def invalid_child?(child)
if !child.is_a?(AttrNode) && !child.is_a?(CommentNode) if !child.is_a?(AttrNode) && !child.is_a?(CommentNode)
"Illegal nesting: Only attributes may be nested beneath attributes." "Illegal nesting: Only properties may be nested beneath properties."
end end
end end
private private
def declaration def declaration
@attr_syntax == :new ? "#{name}: #{value}" : ":#{name} #{value}" @prop_syntax == :new ? "#{name}: #{value}" : ":#{name} #{value}"
end end
end end
end end

View File

@ -36,26 +36,26 @@ module Sass::Tree
else else
"#{' ' * (tabs - 1)}#{value} {" + (style == :compact ? ' ' : "\n") "#{' ' * (tabs - 1)}#{value} {" + (style == :compact ? ' ' : "\n")
end end
was_attr = false was_prop = false
first = true first = true
children.each do |child| children.each do |child|
next if child.invisible? next if child.invisible?
if style == :compact if style == :compact
if child.is_a?(AttrNode) if child.is_a?(AttrNode)
result << "#{child.to_s(first || was_attr ? 1 : tabs + 1)} " result << "#{child.to_s(first || was_prop ? 1 : tabs + 1)} "
else else
if was_attr if was_prop
result[-1] = "\n" result[-1] = "\n"
end end
rendered = child.to_s(tabs + 1) rendered = child.to_s(tabs + 1)
rendered.lstrip! if first rendered.lstrip! if first
result << rendered result << rendered
end end
was_attr = child.is_a?(AttrNode) was_prop = child.is_a?(AttrNode)
first = false first = false
elsif style == :compressed elsif style == :compressed
result << (was_attr ? ";#{child.to_s(1)}" : child.to_s(1)) result << (was_prop ? ";#{child.to_s(1)}" : child.to_s(1))
was_attr = child.is_a?(AttrNode) was_prop = child.is_a?(AttrNode)
else else
result << child.to_s(tabs + 1) + "\n" result << child.to_s(tabs + 1) + "\n"
end end

View File

@ -123,7 +123,7 @@ module Sass
result = String.new result = String.new
children.each do |child| children.each do |child|
if child.is_a? AttrNode if child.is_a? AttrNode
raise Sass::SyntaxError.new('Attributes aren\'t allowed at the root of a document.', child.line) raise Sass::SyntaxError.new('Properties aren\'t allowed at the root of a document.', child.line)
else else
next if child.invisible? next if child.invisible?
child_str = child.to_s(1) child_str = child.to_s(1)

View File

@ -79,7 +79,7 @@ module Sass::Tree
def to_s(tabs, super_rules = nil) def to_s(tabs, super_rules = nil)
resolved_rules = resolve_parent_refs(super_rules) resolved_rules = resolve_parent_refs(super_rules)
attributes = [] properties = []
sub_rules = [] sub_rules = []
rule_separator = style == :compressed ? ',' : ', ' rule_separator = style == :compressed ? ',' : ', '
@ -96,12 +96,12 @@ module Sass::Tree
if child.is_a? RuleNode if child.is_a? RuleNode
sub_rules << child sub_rules << child
else else
attributes << child properties << child
end end
end end
to_return = '' to_return = ''
if !attributes.empty? if !properties.empty?
old_spaces = ' ' * (tabs - 1) old_spaces = ' ' * (tabs - 1)
spaces = ' ' * tabs spaces = ' ' * tabs
if @options[:line_comments] && style != :compressed if @options[:line_comments] && style != :compressed
@ -124,19 +124,19 @@ module Sass::Tree
end end
if style == :compact if style == :compact
attributes = attributes.map { |a| a.to_s(1) }.select{|a| a && a.length > 0}.join(' ') properties = properties.map { |a| a.to_s(1) }.select{|a| a && a.length > 0}.join(' ')
to_return << "#{total_rule} { #{attributes} }\n" to_return << "#{total_rule} { #{properties} }\n"
elsif style == :compressed elsif style == :compressed
attributes = attributes.map { |a| a.to_s(1) }.select{|a| a && a.length > 0}.join(';') properties = properties.map { |a| a.to_s(1) }.select{|a| a && a.length > 0}.join(';')
to_return << "#{total_rule}{#{attributes}}" to_return << "#{total_rule}{#{properties}}"
else else
attributes = attributes.map { |a| a.to_s(tabs + 1) }.select{|a| a && a.length > 0}.join("\n") properties = properties.map { |a| a.to_s(tabs + 1) }.select{|a| a && a.length > 0}.join("\n")
end_attrs = (style == :expanded ? "\n" + old_spaces : ' ') end_props = (style == :expanded ? "\n" + old_spaces : ' ')
to_return << "#{total_rule} {\n#{attributes}#{end_attrs}}\n" to_return << "#{total_rule} {\n#{properties}#{end_props}}\n"
end end
end end
tabs += 1 unless attributes.empty? || style != :nested tabs += 1 unless properties.empty? || style != :nested
sub_rules.each do |sub| sub_rules.each do |sub|
to_return << sub.to_s(tabs, resolved_rules) to_return << sub.to_s(tabs, resolved_rules)
end end

View File

@ -15,19 +15,19 @@ class SassEngineTest < Test::Unit::TestCase
"!a = foo(\"bar\"" => 'Expected rparen token, was end of text.', "!a = foo(\"bar\"" => 'Expected rparen token, was end of text.',
"!a = 1 }" => 'Unexpected end_interpolation token.', "!a = 1 }" => 'Unexpected end_interpolation token.',
"!a = 1 }foo\"" => 'Unexpected end_interpolation token.', "!a = 1 }foo\"" => 'Unexpected end_interpolation token.',
":" => 'Invalid attribute: ":".', ":" => 'Invalid property: ":".',
": a" => 'Invalid attribute: ": a".', ": a" => 'Invalid property: ": a".',
":= a" => 'Invalid attribute: ":= a".', ":= a" => 'Invalid property: ":= a".',
"a\n :b" => 'Invalid attribute: ":b " (no value).', "a\n :b" => 'Invalid property: ":b " (no value).',
"a\n b:" => 'Invalid attribute: "b: " (no value).', "a\n b:" => 'Invalid property: "b: " (no value).',
"a\n :b: c" => 'Invalid attribute: ":b: c".', "a\n :b: c" => 'Invalid property: ":b: c".',
"a\n :b:c d" => 'Invalid attribute: ":b:c d".', "a\n :b:c d" => 'Invalid property: ":b:c d".',
"a\n :b=c d" => 'Invalid attribute: ":b=c d".', "a\n :b=c d" => 'Invalid property: ":b=c d".',
"a\n :b c;" => 'Invalid attribute: ":b c;" (no ";" required at end-of-line).', "a\n :b c;" => 'Invalid property: ":b c;" (no ";" required at end-of-line).',
"a\n b: c;" => 'Invalid attribute: "b: c;" (no ";" required at end-of-line).', "a\n b: c;" => 'Invalid property: "b: c;" (no ";" required at end-of-line).',
"a\n b : c" => 'Invalid attribute: "b : c".', "a\n b : c" => 'Invalid property: "b : c".',
"a\n b=c: d" => 'Invalid attribute: "b=c: d".', "a\n b=c: d" => 'Invalid property: "b=c: d".',
":a" => 'Attributes aren\'t allowed at the root of a document.', ":a" => 'Properties aren\'t allowed at the root of a document.',
"!" => 'Invalid variable: "!".', "!" => 'Invalid variable: "!".',
"!a" => 'Invalid variable: "!a".', "!a" => 'Invalid variable: "!a".',
"! a" => 'Invalid variable: "! a".', "! a" => 'Invalid variable: "! a".',
@ -38,7 +38,7 @@ class SassEngineTest < Test::Unit::TestCase
"!a = 2px + #ccc" => "Cannot add a number with units (2px) to a color (#cccccc).", "!a = 2px + #ccc" => "Cannot add a number with units (2px) to a color (#cccccc).",
"!a = #ccc + 2px" => "Cannot add a number with units (2px) to a color (#cccccc).", "!a = #ccc + 2px" => "Cannot add a number with units (2px) to a color (#cccccc).",
"& a\n :b c" => ["Base-level rules cannot contain the parent-selector-referencing character '&'.", 1], "& a\n :b c" => ["Base-level rules cannot contain the parent-selector-referencing character '&'.", 1],
"a\n :b\n c" => "Illegal nesting: Only attributes may be nested beneath attributes.", "a\n :b\n c" => "Illegal nesting: Only properties may be nested beneath properties.",
"a,\n :b c" => ["Rules can\'t end in commas.", 1], "a,\n :b c" => ["Rules can\'t end in commas.", 1],
"a," => "Rules can\'t end in commas.", "a," => "Rules can\'t end in commas.",
"a,\n!b = 1" => ["Rules can\'t end in commas.", 1], "a,\n!b = 1" => ["Rules can\'t end in commas.", 1],
@ -66,7 +66,7 @@ class SassEngineTest < Test::Unit::TestCase
"=a(,)" => "Mixin arguments can't be empty.", "=a(,)" => "Mixin arguments can't be empty.",
"=a(!)" => "Mixin arguments can't be empty.", "=a(!)" => "Mixin arguments can't be empty.",
"=a(!foo bar)" => "Invalid variable \"!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], "=foo\n bar: baz\n+foo" => ["Properties aren't allowed at the root of a document.", 2],
"a-\#{!b\n c: d" => ["Expected end_interpolation token, was end of text.", 1], "a-\#{!b\n c: d" => ["Expected end_interpolation token, was end of text.", 1],
"=a(!b = 1, !c)" => "Required arguments must not follow optional arguments \"!c\".", "=a(!b = 1, !c)" => "Required arguments must not follow optional arguments \"!c\".",
"=a(!b = 1)\n :a= !b\ndiv\n +a(1,2)" => "Mixin a takes 1 argument but 2 were passed.", "=a(!b = 1)\n :a= !b\ndiv\n +a(1,2)" => "Mixin a takes 1 argument but 2 were passed.",
@ -83,7 +83,7 @@ class SassEngineTest < Test::Unit::TestCase
'@debug' => "Invalid debug directive '@debug': expected expression.", '@debug' => "Invalid debug directive '@debug': expected expression.",
# 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 properties may be nested beneath properties.", 3],
"& foo\n bar: baz\n blat: bang" => ["Base-level rules cannot contain the parent-selector-referencing character '&'.", 1], "& foo\n bar: baz\n blat: bang" => ["Base-level rules cannot contain the parent-selector-referencing character '&'.", 1],
"a\n b: c\n& foo\n bar: baz\n blat: bang" => ["Base-level rules cannot contain the parent-selector-referencing character '&'.", 3], "a\n b: c\n& foo\n bar: baz\n blat: bang" => ["Base-level rules cannot contain the parent-selector-referencing character '&'.", 3],
} }
@ -140,7 +140,7 @@ class SassEngineTest < Test::Unit::TestCase
def test_exception_line def test_exception_line
to_render = <<SASS to_render = <<SASS
rule rule
:attr val :prop val
// comment! // comment!
:broken :broken
@ -157,7 +157,7 @@ SASS
def test_exception_location def test_exception_location
to_render = <<SASS to_render = <<SASS
rule rule
:attr val :prop val
// comment! // comment!
:broken :broken
@ -244,21 +244,21 @@ SASS
def test_colon_only def test_colon_only
begin begin
render("a\n b: c", :attribute_syntax => :old) render("a\n b: c", :property_syntax => :old)
rescue Sass::SyntaxError => e rescue Sass::SyntaxError => e
assert_equal("Illegal attribute syntax: can't use new syntax when :attribute_syntax => :old is set.", assert_equal("Illegal property syntax: can't use new syntax when :property_syntax => :old is set.",
e.message) e.message)
else else
assert(false, "SyntaxError not raised for :attribute_syntax => :old") assert(false, "SyntaxError not raised for :property_syntax => :old")
end end
begin begin
render("a\n :b c", :attribute_syntax => :new) render("a\n :b c", :property_syntax => :new)
rescue Sass::SyntaxError => e rescue Sass::SyntaxError => e
assert_equal("Illegal attribute syntax: can't use old syntax when :attribute_syntax => :new is set.", assert_equal("Illegal property syntax: can't use old syntax when :property_syntax => :new is set.",
e.message) e.message)
else else
assert(false, "SyntaxError not raised for :attribute_syntax => :new") assert(false, "SyntaxError not raised for :property_syntax => :new")
end end
end end
@ -699,7 +699,7 @@ SASS
# Regression tests # Regression tests
def test_comment_beneath_attr def test_comment_beneath_prop
assert_equal(<<RESULT, render(<<SOURCE)) assert_equal(<<RESULT, render(<<SOURCE))
.box { .box {
border-style: solid; } border-style: solid; }