diff --git a/README.md b/README.md index c6306973..009359f2 100644 --- a/README.md +++ b/README.md @@ -113,9 +113,9 @@ At its most basic, Sass is just another way of writing CSS. Although it's very much like normal CSS, 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; -and newlines indicate the end of an attribute, +and newlines indicate the end of a properties, rather than a semicolon. 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. Not so for Sass! 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. For example: @@ -228,7 +228,7 @@ becomes: width: 15em; } 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: =blue-border diff --git a/doc-src/SASS_REFERENCE.md b/doc-src/SASS_REFERENCE.md index 0f55e3c6..c57d5901 100644 --- a/doc-src/SASS_REFERENCE.md +++ b/doc-src/SASS_REFERENCE.md @@ -101,15 +101,15 @@ Available options are: : Sets the style of the CSS output. See the section on Output Style, above. -{#attribute_syntax-option} `:attribute_syntax` -: Forces the document to use one syntax for attributes. +{#property_syntax-option} `:property_syntax` +: Forces the document to use one syntax for properties. If the correct syntax isn't used, an error is thrown. `:new` forces the use of a colon or equals sign - after the attribute name. + after the property name. For example: `color: #0f3` or `width = !main_width`. `:old` forces the use of a colon - before the attribute name. + before the property name. For example: `:color #0f3` or `:width = !main_width`. By default, either syntax is valid. @@ -194,11 +194,8 @@ Available options are: ## CSS Rules Rules in flat CSS have two elements: -the selector -(e.g. `#main`, `div p`, `li a:hover`) -and the attributes -(e.g. `color: #00ff00;`, `width: 5em;`). - +the selector (e.g. `#main`, `div p`, `li a:hover`) +and the properties (e.g. `color: #00ff00;`, `width: 5em;`). Sass has both of these, 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. 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. For example: #main p - - + + ... Like CSS, you can stretch rules over multiple lines. @@ -222,15 +219,15 @@ For example: .users #userTab, .posts #postsTab - + -### 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: with a colon between the name and the value. -However, Sass attributes don't have semicolons at the end; -each attribute is on its own line, so they aren't necessary. +However, Sass properties don't have semicolons at the end; +each property is on its own line, so they aren't necessary. For example: #main p @@ -243,10 +240,10 @@ is compiled to: color: #00ff00; width: 97% } -The second syntax for attributes is slightly different. -The colon is at the beginning of the attribute, +The second syntax for properties is slightly different. +The colon is at the beginning of the property, 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: #main p @@ -259,9 +256,9 @@ is compiled to: color: #00ff00; 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, -see the [`:attribute_syntax`](#attribute_syntax-option) option. +see the [`:property_syntax`](#property_syntax-option) option. ### Nested Rules @@ -320,7 +317,7 @@ by using the ampersand character `&` in your selectors. The ampersand is automatically replaced by the parent selector, instead of having it prepended. -This allows you to cleanly create pseudo-attributes: +This allows you to cleanly create pseudo-classes: a font-weight: bold @@ -361,16 +358,16 @@ Which would become: .ie6 #main #sidebar { 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` 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. Sass offers a shortcut for this: 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: .funky @@ -635,7 +632,7 @@ is compiled to: 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: :color = #123 + #234 @@ -671,7 +668,7 @@ and are set like so: !width = 5em You can then refer to them by putting an equals sign -after your attributes: +after your properties: #main width = !width @@ -799,7 +796,7 @@ See {Sass::Script::Functions} for more information. ### Interpolation: `#{}` You can also use SassScript variables in selectors -and attribute names using #{} interpolation syntax: +and property names using #{} interpolation syntax: !name = foo !attr = border @@ -836,7 +833,7 @@ is compiled to: ## 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 throughout the document. This allows you to keep your stylesheets DRY and also avoid placing presentation @@ -965,14 +962,14 @@ For example: /* A very awesome rule. #awesome.rule - /* An equally awesome attribute. + /* An equally awesome property. awesomeness: very becomes /* A very awesome rule. */ #awesome.rule { - /* An equally awesome attribute. */ + /* An equally awesome property. */ awesomeness: very; } You can also nest content beneath loud comments. For example: @@ -1006,7 +1003,7 @@ For example: // A very awesome rule. #awesome.rule - // An equally awesome attribute. + // An equally awesome property. awesomeness: very becomes @@ -1019,7 +1016,7 @@ For example: // A very awesome rule #awesome.rule - // Don't use these attributes + // Don't use these properties color: green font-size: 10em 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, because it reflects the structure of the document 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. Each rule is indented based on how deeply it's nested. For example: @@ -1069,8 +1066,8 @@ without actually reading anything. ### `:expanded` Expanded is the typical human-made CSS style, -with each attribute and rule taking up one line. -Attributes are indented within the rules, +with each property and rule taking up one line. +Properties are indented within the rules, but the rules aren't indented in any special way. For example: @@ -1094,7 +1091,7 @@ Compact style, as the name would imply, takes up less space than Nested or Expanded. However, it's also harder to read. 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, while groups of rules have newlines between them. For example: diff --git a/lib/sass/css.rb b/lib/sass/css.rb index a8120856..006528ae 100644 --- a/lib/sass/css.rb +++ b/lib/sass/css.rb @@ -60,7 +60,7 @@ module Sass class CSS # @param template [String] The CSS code # @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`). def initialize(template, options = {}) if template.is_a? IO @@ -135,14 +135,14 @@ module Sass assert_match /\{/ node = Tree::RuleNode.new(rule) - attributes(node) + properties(node) return node 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 - def attributes(rule) + # @param rule [Tree::RuleNode] The parent node of the properties + def properties(rule) while @template.scan(/[^:\}\s]+/) name = @template[0] whitespace diff --git a/lib/sass/engine.rb b/lib/sass/engine.rb index 34af696d..2cd4a7b3 100644 --- a/lib/sass/engine.rb +++ b/lib/sass/engine.rb @@ -75,11 +75,11 @@ module Sass end end - # The character that begins a CSS attribute. - ATTRIBUTE_CHAR = ?: + # The character that begins a CSS property. + PROPERTY_CHAR = ?: # 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 = ?= # The character that designates the beginning of a comment, @@ -106,16 +106,16 @@ module Sass # Includes named mixin declared using MIXIN_DEFINITION_CHAR MIXIN_INCLUDE_CHAR = ?+ - # The regex that matches attributes of the form name: attr. - ATTRIBUTE_NEW_MATCHER = /^[^\s:"]+\s*[=:](\s|$)/ + # The regex that matches properties of the form name: prop. + PROPERTY_NEW_MATCHER = /^[^\s:"]+\s*[=:](\s|$)/ # The regex that matches and extracts data from - # attributes of the form name: attr. - ATTRIBUTE_NEW = /^([^\s=:"]+)(\s*=|:)(?:\s+|$)(.*)/ + # properties of the form name: prop. + PROPERTY_NEW = /^([^\s=:"]+)(\s*=|:)(?:\s+|$)(.*)/ # The regex that matches and extracts data from - # attributes of the form :name attr. - ATTRIBUTE_OLD = /^:([^\s=:"]+)\s*(=?)(?:\s+|$)(.*)/ + # properties of the form :name prop. + PROPERTY_OLD = /^:([^\s=:"]+)\s*(=?)(?:\s+|$)(.*)/ # The default options for Sass::Engine. DEFAULT_OPTIONS = { @@ -133,9 +133,10 @@ module Sass @template = template # Backwards compatibility - case @options[:attribute_syntax] - when :alternate; @options[:attribute_syntax] = :new - when :normal; @options[:attribute_syntax] = :old + @options[:property_syntax] ||= @options[:attribute_syntax] + case @options[:property_syntax] + when :alternate; @options[:property_syntax] = :new + when :normal; @options[:property_syntax] = :old end end @@ -290,9 +291,9 @@ END def parse_line(parent, line, root) case line.text[0] - when ATTRIBUTE_CHAR - if line.text[1] != ATTRIBUTE_CHAR - parse_attribute(line, ATTRIBUTE_OLD) + when PROPERTY_CHAR + if line.text[1] != PROPERTY_CHAR + parse_property(line, PROPERTY_OLD) else # Support CSS3-style pseudo-elements, # which begin with :: @@ -315,26 +316,26 @@ END parse_mixin_include(line, root) end else - if line.text =~ ATTRIBUTE_NEW_MATCHER - parse_attribute(line, ATTRIBUTE_NEW) + if line.text =~ PROPERTY_NEW_MATCHER + parse_property(line, PROPERTY_NEW) else Tree::RuleNode.new(line.text) end end end - def parse_attribute(line, attribute_regx) - name, eq, value = line.text.scan(attribute_regx)[0] + def parse_property(line, property_regx) + name, eq, value = line.text.scan(property_regx)[0] if name.nil? || value.nil? - raise SyntaxError.new("Invalid attribute: \"#{line.text}\".", @line) + raise SyntaxError.new("Invalid property: \"#{line.text}\".", @line) end expr = if (eq.strip[0] == SCRIPT_CHAR) parse_script(value, :offset => line.offset + line.text.index(value)) else value end - Tree::AttrNode.new(name, expr, attribute_regx == ATTRIBUTE_OLD ? :old : :new) + Tree::AttrNode.new(name, expr, property_regx == PROPERTY_OLD ? :old : :new) end def parse_variable(line) diff --git a/lib/sass/tree/attr_node.rb b/lib/sass/tree/attr_node.rb index e18c28f5..63e2eb27 100644 --- a/lib/sass/tree/attr_node.rb +++ b/lib/sass/tree/attr_node.rb @@ -16,12 +16,12 @@ module Sass::Tree # @param name [String] See \{#name} # @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 - def initialize(name, value, attr_syntax) + def initialize(name, value, prop_syntax) @name = name @value = value - @attr_syntax = attr_syntax + @prop_syntax = prop_syntax super() end @@ -39,22 +39,22 @@ module Sass::Tree # @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 # @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) - if @options[:attribute_syntax] == :old && @attr_syntax == :new - raise Sass::SyntaxError.new("Illegal attribute syntax: can't use new syntax when :attribute_syntax => :old is set.") - elsif @options[:attribute_syntax] == :new && @attr_syntax == :old - raise Sass::SyntaxError.new("Illegal attribute syntax: can't use old syntax when :attribute_syntax => :new is set.") + if @options[:property_syntax] == :old && @prop_syntax == :new + raise Sass::SyntaxError.new("Illegal property syntax: can't use new syntax when :property_syntax => :old is set.") + elsif @options[:property_syntax] == :new && @prop_syntax == :old + raise Sass::SyntaxError.new("Illegal property syntax: can't use old syntax when :property_syntax => :new is set.") end 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 real_name = name real_name = "#{parent_name}-#{real_name}" if parent_name 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 join_string = case style @@ -96,14 +96,14 @@ module Sass::Tree # @return [String] An error message if the child is invalid, or nil otherwise def invalid_child?(child) 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 private def declaration - @attr_syntax == :new ? "#{name}: #{value}" : ":#{name} #{value}" + @prop_syntax == :new ? "#{name}: #{value}" : ":#{name} #{value}" end end end diff --git a/lib/sass/tree/directive_node.rb b/lib/sass/tree/directive_node.rb index ebb26ea8..4e24fd2a 100644 --- a/lib/sass/tree/directive_node.rb +++ b/lib/sass/tree/directive_node.rb @@ -36,26 +36,26 @@ module Sass::Tree else "#{' ' * (tabs - 1)}#{value} {" + (style == :compact ? ' ' : "\n") end - was_attr = false + was_prop = false first = true children.each do |child| next if child.invisible? if style == :compact 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 - if was_attr + if was_prop result[-1] = "\n" end rendered = child.to_s(tabs + 1) rendered.lstrip! if first result << rendered end - was_attr = child.is_a?(AttrNode) + was_prop = child.is_a?(AttrNode) first = false elsif style == :compressed - result << (was_attr ? ";#{child.to_s(1)}" : child.to_s(1)) - was_attr = child.is_a?(AttrNode) + result << (was_prop ? ";#{child.to_s(1)}" : child.to_s(1)) + was_prop = child.is_a?(AttrNode) else result << child.to_s(tabs + 1) + "\n" end diff --git a/lib/sass/tree/node.rb b/lib/sass/tree/node.rb index 45e66f4b..37268d83 100644 --- a/lib/sass/tree/node.rb +++ b/lib/sass/tree/node.rb @@ -123,7 +123,7 @@ module Sass result = String.new children.each do |child| 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 next if child.invisible? child_str = child.to_s(1) diff --git a/lib/sass/tree/rule_node.rb b/lib/sass/tree/rule_node.rb index 3eb0c8f2..0b90a353 100644 --- a/lib/sass/tree/rule_node.rb +++ b/lib/sass/tree/rule_node.rb @@ -79,7 +79,7 @@ module Sass::Tree def to_s(tabs, super_rules = nil) resolved_rules = resolve_parent_refs(super_rules) - attributes = [] + properties = [] sub_rules = [] rule_separator = style == :compressed ? ',' : ', ' @@ -96,12 +96,12 @@ module Sass::Tree if child.is_a? RuleNode sub_rules << child else - attributes << child + properties << child end end to_return = '' - if !attributes.empty? + if !properties.empty? old_spaces = ' ' * (tabs - 1) spaces = ' ' * tabs if @options[:line_comments] && style != :compressed @@ -124,19 +124,19 @@ module Sass::Tree end if style == :compact - attributes = attributes.map { |a| a.to_s(1) }.select{|a| a && a.length > 0}.join(' ') - to_return << "#{total_rule} { #{attributes} }\n" + properties = properties.map { |a| a.to_s(1) }.select{|a| a && a.length > 0}.join(' ') + to_return << "#{total_rule} { #{properties} }\n" elsif style == :compressed - attributes = attributes.map { |a| a.to_s(1) }.select{|a| a && a.length > 0}.join(';') - to_return << "#{total_rule}{#{attributes}}" + properties = properties.map { |a| a.to_s(1) }.select{|a| a && a.length > 0}.join(';') + to_return << "#{total_rule}{#{properties}}" else - attributes = attributes.map { |a| a.to_s(tabs + 1) }.select{|a| a && a.length > 0}.join("\n") - end_attrs = (style == :expanded ? "\n" + old_spaces : ' ') - to_return << "#{total_rule} {\n#{attributes}#{end_attrs}}\n" + properties = properties.map { |a| a.to_s(tabs + 1) }.select{|a| a && a.length > 0}.join("\n") + end_props = (style == :expanded ? "\n" + old_spaces : ' ') + to_return << "#{total_rule} {\n#{properties}#{end_props}}\n" end end - tabs += 1 unless attributes.empty? || style != :nested + tabs += 1 unless properties.empty? || style != :nested sub_rules.each do |sub| to_return << sub.to_s(tabs, resolved_rules) end diff --git a/test/sass/engine_test.rb b/test/sass/engine_test.rb index 7aa273b3..62a7bf00 100755 --- a/test/sass/engine_test.rb +++ b/test/sass/engine_test.rb @@ -15,19 +15,19 @@ class SassEngineTest < Test::Unit::TestCase "!a = foo(\"bar\"" => 'Expected rparen token, was end of text.', "!a = 1 }" => 'Unexpected end_interpolation token.', "!a = 1 }foo\"" => 'Unexpected end_interpolation token.', - ":" => 'Invalid attribute: ":".', - ": a" => 'Invalid attribute: ": a".', - ":= a" => 'Invalid attribute: ":= a".', - "a\n :b" => 'Invalid attribute: ":b " (no value).', - "a\n b:" => 'Invalid attribute: "b: " (no value).', - "a\n :b: c" => 'Invalid attribute: ":b: c".', - "a\n :b:c d" => 'Invalid attribute: ":b:c d".', - "a\n :b=c d" => 'Invalid attribute: ":b=c d".', - "a\n :b c;" => 'Invalid attribute: ":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 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 property: ":".', + ": a" => 'Invalid property: ": a".', + ":= a" => 'Invalid property: ":= a".', + "a\n :b" => 'Invalid property: ":b " (no value).', + "a\n b:" => 'Invalid property: "b: " (no value).', + "a\n :b: c" => 'Invalid property: ":b: c".', + "a\n :b:c d" => 'Invalid property: ":b:c d".', + "a\n :b=c d" => 'Invalid property: ":b=c d".', + "a\n :b c;" => 'Invalid property: ":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 property: "b : c".', + "a\n b=c: d" => 'Invalid property: "b=c: d".', + ":a" => 'Properties aren\'t allowed at the root of a document.', "!" => 'Invalid variable: "!".', "!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 = #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\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," => "Rules can\'t end in commas.", "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(!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 = 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.", @@ -83,7 +83,7 @@ class SassEngineTest < Test::Unit::TestCase '@debug' => "Invalid debug directive '@debug': expected expression.", # 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], "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 to_render = < :old) + render("a\n b: c", :property_syntax => :old) 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) else - assert(false, "SyntaxError not raised for :attribute_syntax => :old") + assert(false, "SyntaxError not raised for :property_syntax => :old") end begin - render("a\n :b c", :attribute_syntax => :new) + render("a\n :b c", :property_syntax => :new) 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) else - assert(false, "SyntaxError not raised for :attribute_syntax => :new") + assert(false, "SyntaxError not raised for :property_syntax => :new") end end @@ -699,7 +699,7 @@ SASS # Regression tests - def test_comment_beneath_attr + def test_comment_beneath_prop assert_equal(<