haml-edge 2.1.21 → 2.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/EDGE_GEM_VERSION +1 -1
- data/FAQ.md +142 -0
- data/{README.rdoc → README.md} +141 -141
- data/Rakefile +29 -17
- data/VERSION +1 -1
- data/lib/haml/buffer.rb +63 -27
- data/lib/haml/engine.rb +103 -80
- data/lib/haml/error.rb +7 -7
- data/lib/haml/exec.rb +80 -26
- data/lib/haml/filters.rb +106 -40
- data/lib/haml/helpers/action_view_extensions.rb +34 -39
- data/lib/haml/helpers/action_view_mods.rb +132 -139
- data/lib/haml/helpers.rb +207 -153
- data/lib/haml/html.rb +40 -21
- data/lib/haml/precompiler.rb +2 -0
- data/lib/haml/shared.rb +34 -3
- data/lib/haml/template/patch.rb +1 -1
- data/lib/haml/template/plugin.rb +0 -2
- data/lib/haml/template.rb +5 -0
- data/lib/haml/util.rb +136 -1
- data/lib/haml/version.rb +16 -4
- data/lib/haml.rb +502 -481
- data/lib/sass/css.rb +106 -68
- data/lib/sass/engine.rb +55 -22
- data/lib/sass/environment.rb +52 -21
- data/lib/sass/error.rb +23 -12
- data/lib/sass/files.rb +27 -0
- data/lib/sass/plugin/merb.rb +2 -2
- data/lib/sass/plugin/rails.rb +0 -2
- data/lib/sass/plugin.rb +32 -23
- data/lib/sass/repl.rb +7 -0
- data/lib/sass/script/bool.rb +9 -5
- data/lib/sass/script/color.rb +87 -1
- data/lib/sass/script/funcall.rb +23 -2
- data/lib/sass/script/functions.rb +93 -44
- data/lib/sass/script/lexer.rb +33 -3
- data/lib/sass/script/literal.rb +93 -1
- data/lib/sass/script/node.rb +14 -0
- data/lib/sass/script/number.rb +128 -4
- data/lib/sass/script/operation.rb +16 -1
- data/lib/sass/script/parser.rb +51 -21
- data/lib/sass/script/string.rb +7 -4
- data/lib/sass/script/unary_operation.rb +14 -1
- data/lib/sass/script/variable.rb +12 -1
- data/lib/sass/script.rb +26 -5
- data/lib/sass/tree/attr_node.rb +46 -9
- data/lib/sass/tree/comment_node.rb +41 -1
- data/lib/sass/tree/debug_node.rb +8 -0
- data/lib/sass/tree/directive_node.rb +20 -0
- data/lib/sass/tree/file_node.rb +12 -0
- data/lib/sass/tree/for_node.rb +15 -0
- data/lib/sass/tree/if_node.rb +22 -0
- data/lib/sass/tree/mixin_def_node.rb +12 -1
- data/lib/sass/tree/mixin_node.rb +13 -0
- data/lib/sass/tree/node.rb +136 -6
- data/lib/sass/tree/rule_node.rb +66 -7
- data/lib/sass/tree/variable_node.rb +10 -0
- data/lib/sass/tree/while_node.rb +11 -1
- data/lib/sass.rb +544 -534
- metadata +7 -6
- data/FAQ +0 -138
data/lib/sass/script.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'strscan'
|
2
|
+
require 'sass/script/node'
|
2
3
|
require 'sass/script/variable'
|
3
4
|
require 'sass/script/funcall'
|
4
5
|
require 'sass/script/operation'
|
@@ -6,22 +7,43 @@ require 'sass/script/literal'
|
|
6
7
|
require 'sass/script/parser'
|
7
8
|
|
8
9
|
module Sass
|
9
|
-
#
|
10
|
+
# SassScript is code that's embedded in Sass documents
|
11
|
+
# to allow for property values to be computed from variables.
|
12
|
+
#
|
13
|
+
# This module contains code that handles the parsing and evaluation of SassScript.
|
10
14
|
module Script
|
11
|
-
# :stopdoc:
|
12
15
|
# The character that begins a variable.
|
13
16
|
VARIABLE_CHAR = ?!
|
14
17
|
|
15
|
-
# The regular expression used to parse variables
|
18
|
+
# The regular expression used to parse variables.
|
16
19
|
MATCH = /^!([a-zA-Z_]\w*)\s*((?:\|\|)?=)\s*(.+)/
|
17
20
|
|
18
|
-
# The regular expression used to validate variables without matching
|
21
|
+
# The regular expression used to validate variables without matching.
|
19
22
|
VALIDATE = /^![a-zA-Z_]\w*$/
|
20
23
|
|
24
|
+
# Parses and evaluates a string of SassScript.
|
25
|
+
#
|
26
|
+
# @param value [String] The SassScript
|
27
|
+
# @param line [Fixnum] The number of the line on which the SassScript appeared.
|
28
|
+
# Used for error reporting
|
29
|
+
# @param offset [Fixnum] The number of characters in on `line` that the SassScript started.
|
30
|
+
# Used for error reporting
|
31
|
+
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
32
|
+
# @return [String] The string result of evaluating the SassScript
|
21
33
|
def self.resolve(value, line, offset, environment)
|
22
34
|
parse(value, line, offset).perform(environment).to_s
|
23
35
|
end
|
24
36
|
|
37
|
+
# Parses a string of SassScript
|
38
|
+
#
|
39
|
+
# @param value [String] The SassScript
|
40
|
+
# @param line [Fixnum] The number of the line on which the SassScript appeared.
|
41
|
+
# Used for error reporting
|
42
|
+
# @param offset [Fixnum] The number of characters in on `line` that the SassScript started.
|
43
|
+
# Used for error reporting
|
44
|
+
# @param filename [String] The path to the file in which the SassScript appeared.
|
45
|
+
# Used for error reporting
|
46
|
+
# @return [Script::Node] The root node of the parse tree
|
25
47
|
def self.parse(value, line, offset, filename = nil)
|
26
48
|
Parser.parse(value, line, offset, filename)
|
27
49
|
rescue Sass::SyntaxError => e
|
@@ -33,6 +55,5 @@ module Sass
|
|
33
55
|
e.sass_line = line
|
34
56
|
raise e
|
35
57
|
end
|
36
|
-
# :startdoc:
|
37
58
|
end
|
38
59
|
end
|
data/lib/sass/tree/attr_node.rb
CHANGED
@@ -1,7 +1,23 @@
|
|
1
1
|
module Sass::Tree
|
2
|
+
# A static node reprenting a CSS property.
|
3
|
+
#
|
4
|
+
# @see Sass::Tree
|
2
5
|
class AttrNode < Node
|
3
|
-
|
4
|
-
|
6
|
+
# The name of the property.
|
7
|
+
#
|
8
|
+
# @return [String]
|
9
|
+
attr_accessor :name
|
10
|
+
|
11
|
+
# The value of the property,
|
12
|
+
# either a plain string or a SassScript parse tree.
|
13
|
+
#
|
14
|
+
# @return [String, Script::Node]
|
15
|
+
attr_accessor :value
|
16
|
+
|
17
|
+
# @param name [String] See \{#name}
|
18
|
+
# @param value [String] See \{#value}
|
19
|
+
# @param attr_syntax [Symbol] `:new` if this property uses `a: b`-style syntax,
|
20
|
+
# `:old` if it uses `:a b`-style syntax
|
5
21
|
def initialize(name, value, attr_syntax)
|
6
22
|
@name = name
|
7
23
|
@value = value
|
@@ -9,10 +25,21 @@ module Sass::Tree
|
|
9
25
|
super()
|
10
26
|
end
|
11
27
|
|
28
|
+
# Compares the names and values of two properties.
|
29
|
+
#
|
30
|
+
# @param other [Object] The object to compare with
|
31
|
+
# @return [Boolean] Whether or not this node and the other object
|
32
|
+
# are the same
|
12
33
|
def ==(other)
|
13
34
|
self.class == other.class && name == other.name && value == other.value && super
|
14
35
|
end
|
15
36
|
|
37
|
+
# Computes the CSS for the property.
|
38
|
+
#
|
39
|
+
# @param tabs [Fixnum] The level of indentation for the CSS
|
40
|
+
# @param parent_name [String] The name of the parent property (e.g. `text`) or nil
|
41
|
+
# @return [String] The resulting CSS
|
42
|
+
# @raise [Sass::SyntaxError] if the attribute uses invalid syntax
|
16
43
|
def to_s(tabs, parent_name = nil)
|
17
44
|
if @options[:attribute_syntax] == :normal && @attr_syntax == :new
|
18
45
|
raise Sass::SyntaxError.new("Illegal attribute syntax: can't use alternate syntax when :attribute_syntax => :normal is set.")
|
@@ -50,23 +77,33 @@ module Sass::Tree
|
|
50
77
|
end
|
51
78
|
|
52
79
|
protected
|
53
|
-
|
80
|
+
|
81
|
+
# Runs any SassScript that may be embedded in the property.
|
82
|
+
#
|
83
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
84
|
+
# variable and mixin values
|
54
85
|
def perform!(environment)
|
55
86
|
@name = interpolate(@name, environment)
|
56
87
|
@value = @value.is_a?(String) ? interpolate(@value, environment) : @value.perform(environment).to_s
|
57
88
|
super
|
58
89
|
end
|
59
90
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
91
|
+
# Returns an error message if the given child node is invalid,
|
92
|
+
# and false otherwise.
|
93
|
+
#
|
94
|
+
# {AttrNode} only allows other {AttrNode}s and {CommentNode}s as children.
|
95
|
+
# @param child [Tree::Node] A potential child node
|
96
|
+
# @return [String] An error message if the child is invalid, or nil otherwise
|
66
97
|
def invalid_child?(child)
|
67
98
|
if !child.is_a?(AttrNode) && !child.is_a?(CommentNode)
|
68
99
|
"Illegal nesting: Only attributes may be nested beneath attributes."
|
69
100
|
end
|
70
101
|
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def declaration
|
106
|
+
@attr_syntax == :new ? "#{name}: #{value}" : ":#{name} #{value}"
|
107
|
+
end
|
71
108
|
end
|
72
109
|
end
|
@@ -1,11 +1,27 @@
|
|
1
1
|
require 'sass/tree/node'
|
2
2
|
|
3
3
|
module Sass::Tree
|
4
|
+
# A static node representing a Sass comment (silent or loud).
|
5
|
+
#
|
6
|
+
# @see Sass::Tree
|
4
7
|
class CommentNode < Node
|
8
|
+
# The lines of text nested beneath the comment.
|
9
|
+
#
|
10
|
+
# @return [Array<Sass::Engine::Line>]
|
5
11
|
attr_accessor :lines
|
12
|
+
|
13
|
+
# The text on the same line as the comment starter.
|
14
|
+
#
|
15
|
+
# @return [String]
|
6
16
|
attr_accessor :value
|
17
|
+
|
18
|
+
# Whether or not the comment is silent (that is, doesn't output to CSS).
|
19
|
+
#
|
20
|
+
# @return [Boolean]
|
7
21
|
attr_accessor :silent
|
8
22
|
|
23
|
+
# @param value [String] See \{#value}
|
24
|
+
# @param silent [Boolean] See \{#silent}
|
9
25
|
def initialize(value, silent)
|
10
26
|
@lines = []
|
11
27
|
@value = value[2..-1].strip
|
@@ -13,11 +29,25 @@ module Sass::Tree
|
|
13
29
|
super()
|
14
30
|
end
|
15
31
|
|
32
|
+
# Compares the contents of two comments.
|
33
|
+
#
|
34
|
+
# @param other [Object] The object to compare with
|
35
|
+
# @return [Boolean] Whether or not this node and the other object
|
36
|
+
# are the same
|
16
37
|
def ==(other)
|
17
38
|
self.class == other.class && value == other.value && silent == other.silent && lines == other.lines
|
18
39
|
end
|
19
40
|
|
20
|
-
|
41
|
+
# Computes the CSS for the comment.
|
42
|
+
#
|
43
|
+
# Returns `nil` if this is a silent comment
|
44
|
+
# or the current style doesn't render comments.
|
45
|
+
#
|
46
|
+
# @overload to_s(tabs = 0)
|
47
|
+
# @param tabs [Fixnum] The level of indentation for the CSS
|
48
|
+
# @return [String, nil] The resulting CSS
|
49
|
+
# @see #invisible?
|
50
|
+
def to_s(tabs = 0, _ = nil)
|
21
51
|
return if invisible?
|
22
52
|
|
23
53
|
spaces = ' ' * (tabs - 1)
|
@@ -25,12 +55,22 @@ module Sass::Tree
|
|
25
55
|
map{|l| l.sub(%r{ ?\*/ *$},'')}.join(style == :compact ? ' ' : "\n#{spaces} * ") + " */"
|
26
56
|
end
|
27
57
|
|
58
|
+
# Returns `true` if this is a silent comment
|
59
|
+
# or the current style doesn't render comments.
|
60
|
+
#
|
61
|
+
# @return [Boolean]
|
28
62
|
def invisible?
|
29
63
|
style == :compressed || @silent
|
30
64
|
end
|
31
65
|
|
32
66
|
protected
|
33
67
|
|
68
|
+
# Removes this node from the tree if it's a silent comment.
|
69
|
+
#
|
70
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
71
|
+
# variable and mixin values
|
72
|
+
# @return [Tree::Node, Array<Tree::Node>] The resulting static nodes
|
73
|
+
# @see Sass::Tree
|
34
74
|
def _perform(environment)
|
35
75
|
return [] if @silent
|
36
76
|
self
|
data/lib/sass/tree/debug_node.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
module Sass
|
2
2
|
module Tree
|
3
|
+
# A dynamic node representing a Sass `@debug` statement.
|
4
|
+
#
|
5
|
+
# @see Sass::Tree
|
3
6
|
class DebugNode < Node
|
7
|
+
# @param expr [Script::Node] The expression to print
|
4
8
|
def initialize(expr)
|
5
9
|
@expr = expr
|
6
10
|
super()
|
@@ -8,6 +12,10 @@ module Sass
|
|
8
12
|
|
9
13
|
protected
|
10
14
|
|
15
|
+
# Prints the expression to STDERR.
|
16
|
+
#
|
17
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
18
|
+
# variable and mixin values
|
11
19
|
def _perform(environment)
|
12
20
|
res = @expr.perform(environment)
|
13
21
|
if filename
|
@@ -1,12 +1,32 @@
|
|
1
1
|
module Sass::Tree
|
2
|
+
# A static node representing an unproccessed Sass `@`-directive.
|
3
|
+
# Directives known to Sass, like `@for` and `@debug`,
|
4
|
+
# are handled by their own nodes;
|
5
|
+
# only CSS directives like `@media` and `@font-face` become {DirectiveNode}s.
|
6
|
+
#
|
7
|
+
# `@import` is a bit of a weird case;
|
8
|
+
# if it's importing a Sass file,
|
9
|
+
# it becomes a {FileNode},
|
10
|
+
# but if it's importing a plain CSS file,
|
11
|
+
# it becomes a {DirectiveNode}.
|
12
|
+
#
|
13
|
+
# @see Sass::Tree
|
2
14
|
class DirectiveNode < Node
|
15
|
+
# The text of the directive, `@` and all.
|
16
|
+
#
|
17
|
+
# @return [String]
|
3
18
|
attr_accessor :value
|
4
19
|
|
20
|
+
# @param value [String] See \{#value}
|
5
21
|
def initialize(value)
|
6
22
|
@value = value
|
7
23
|
super()
|
8
24
|
end
|
9
25
|
|
26
|
+
# Computes the CSS for the directive.
|
27
|
+
#
|
28
|
+
# @param tabs [Fixnum] The level of indentation for the CSS
|
29
|
+
# @return [String] The resulting CSS
|
10
30
|
def to_s(tabs)
|
11
31
|
if children.empty?
|
12
32
|
value + ";"
|
data/lib/sass/tree/file_node.rb
CHANGED
@@ -1,11 +1,18 @@
|
|
1
1
|
module Sass
|
2
2
|
module Tree
|
3
|
+
# A static node that wraps the {Sass::Tree} for an `@import`ed file.
|
4
|
+
# It doesn't have a functional purpose other than to add the `@import`ed file
|
5
|
+
# to the backtrace if an error occurs.
|
3
6
|
class FileNode < Node
|
7
|
+
# @param filename [String] The name of the imported file
|
4
8
|
def initialize(filename)
|
5
9
|
@filename = filename
|
6
10
|
super()
|
7
11
|
end
|
8
12
|
|
13
|
+
# Computes the CSS for the imported file.
|
14
|
+
#
|
15
|
+
# @param args [Array] Ignored
|
9
16
|
def to_s(*args)
|
10
17
|
@to_s ||= (style == :compressed ? super().strip : super())
|
11
18
|
rescue Sass::SyntaxError => e
|
@@ -17,6 +24,11 @@ module Sass
|
|
17
24
|
|
18
25
|
protected
|
19
26
|
|
27
|
+
# Parses the imported file
|
28
|
+
# and runs the dynamic Sass for it.
|
29
|
+
#
|
30
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
31
|
+
# variable and mixin values
|
20
32
|
def perform!(environment)
|
21
33
|
self.children = Sass::Files.tree_for(filename, @options).children
|
22
34
|
self.children = perform_children(environment)
|
data/lib/sass/tree/for_node.rb
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
require 'sass/tree/node'
|
2
2
|
|
3
3
|
module Sass::Tree
|
4
|
+
# A dynamic node representing a Sass `@for` loop.
|
5
|
+
#
|
6
|
+
# @see Sass::Tree
|
4
7
|
class ForNode < Node
|
8
|
+
# @param var [String] The name of the loop variable
|
9
|
+
# @param from [Script::Node] The parse tree for the initial expression
|
10
|
+
# @param to [Script::Node] The parse tree for the final expression
|
11
|
+
# @param exclusive [Boolean] Whether to include `to` in the loop
|
12
|
+
# or stop just before
|
5
13
|
def initialize(var, from, to, exclusive)
|
6
14
|
@var = var
|
7
15
|
@from = from
|
@@ -12,6 +20,13 @@ module Sass::Tree
|
|
12
20
|
|
13
21
|
protected
|
14
22
|
|
23
|
+
# Runs the child nodes once for each time through the loop,
|
24
|
+
# varying the variable each time.
|
25
|
+
#
|
26
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
27
|
+
# variable and mixin values
|
28
|
+
# @return [Array<Tree::Node>] The resulting static nodes
|
29
|
+
# @see Sass::Tree
|
15
30
|
def _perform(environment)
|
16
31
|
from = @from.perform(environment).to_i
|
17
32
|
to = @to.perform(environment).to_i
|
data/lib/sass/tree/if_node.rb
CHANGED
@@ -1,15 +1,30 @@
|
|
1
1
|
require 'sass/tree/node'
|
2
2
|
|
3
3
|
module Sass::Tree
|
4
|
+
# A dynamic node representing a Sass `@if` statement.
|
5
|
+
#
|
6
|
+
# {IfNode}s are a little odd, in that they also represent `@else` and `@else if`s.
|
7
|
+
# This is done as a linked list:
|
8
|
+
# each {IfNode} has a link (\{#else}) to the next {IfNode}.
|
9
|
+
#
|
10
|
+
# @see Sass::Tree
|
4
11
|
class IfNode < Node
|
12
|
+
# The next {IfNode} in the if-else list, or `nil`.
|
13
|
+
#
|
14
|
+
# @return [IfNode]
|
5
15
|
attr_accessor :else
|
6
16
|
|
17
|
+
# @param expr [Script::Expr] The conditional expression.
|
18
|
+
# If this is nil, this is an `@else` node, not an `@else if`
|
7
19
|
def initialize(expr)
|
8
20
|
@expr = expr
|
9
21
|
@last_else = self
|
10
22
|
super()
|
11
23
|
end
|
12
24
|
|
25
|
+
# Append an `@else` node to the end of the list.
|
26
|
+
#
|
27
|
+
# @param node [IfNode] The `@else` node to append
|
13
28
|
def add_else(node)
|
14
29
|
@last_else.else = node
|
15
30
|
@last_else = node
|
@@ -22,6 +37,13 @@ module Sass::Tree
|
|
22
37
|
|
23
38
|
protected
|
24
39
|
|
40
|
+
# Runs the child nodes if the conditional expression is true;
|
41
|
+
# otherwise, tries the \{#else} nodes.
|
42
|
+
#
|
43
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
44
|
+
# variable and mixin values
|
45
|
+
# @return [Array<Tree::Node>] The resulting static nodes
|
46
|
+
# @see Sass::Tree
|
25
47
|
def _perform(environment)
|
26
48
|
environment = Sass::Environment.new(environment)
|
27
49
|
return perform_children(environment) if @expr.nil? || @expr.perform(environment).to_bool
|
@@ -1,14 +1,25 @@
|
|
1
1
|
module Sass
|
2
2
|
module Tree
|
3
|
+
# A dynamic node representing a mixin definition.
|
4
|
+
#
|
5
|
+
# @see Sass::Tree
|
3
6
|
class MixinDefNode < Node
|
7
|
+
# @param name [String] The mixin name
|
8
|
+
# @param args [Array<(String, Script::Node)>] The arguments for the mixin.
|
9
|
+
# Each element is a tuple containing the name of the argument
|
10
|
+
# and the parse tree for the default value of the argument
|
4
11
|
def initialize(name, args)
|
5
12
|
@name = name
|
6
13
|
@args = args
|
7
14
|
super()
|
8
15
|
end
|
9
16
|
|
10
|
-
|
17
|
+
protected
|
11
18
|
|
19
|
+
# Loads the mixin into the environment.
|
20
|
+
#
|
21
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
22
|
+
# variable and mixin values
|
12
23
|
def _perform(environment)
|
13
24
|
environment.set_mixin(@name, Sass::Mixin.new(@name, @args, environment, children))
|
14
25
|
[]
|
data/lib/sass/tree/mixin_node.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
require 'sass/tree/node'
|
2
2
|
|
3
3
|
module Sass::Tree
|
4
|
+
# A dynamic node representing a mixin include.
|
5
|
+
#
|
6
|
+
# @see Sass::Tree
|
4
7
|
class MixinNode < Node
|
8
|
+
# @param name [String] The name of the mixin
|
9
|
+
# @param args [Array<Script::Node>] The arguments to the mixin
|
5
10
|
def initialize(name, args)
|
6
11
|
@name = name
|
7
12
|
@args = args
|
@@ -10,6 +15,14 @@ module Sass::Tree
|
|
10
15
|
|
11
16
|
protected
|
12
17
|
|
18
|
+
# Runs the mixin.
|
19
|
+
#
|
20
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
21
|
+
# variable and mixin values
|
22
|
+
# @return [Array<Tree::Node>] The resulting static nodes
|
23
|
+
# @raise [Sass::SyntaxError] if there is no mixin with the given name
|
24
|
+
# @raise [Sass::SyntaxError] if an incorrect number of arguments was passed
|
25
|
+
# @see Sass::Tree
|
13
26
|
def _perform(environment)
|
14
27
|
raise Sass::SyntaxError.new("Undefined mixin '#{@name}'.", @line) unless mixin = environment.mixin(@name)
|
15
28
|
|
data/lib/sass/tree/node.rb
CHANGED
@@ -1,24 +1,69 @@
|
|
1
1
|
module Sass
|
2
|
+
# A namespace for nodes in the Sass parse tree.
|
3
|
+
#
|
4
|
+
# The Sass parse tree has two states.
|
5
|
+
# When it's first parsed, it has nodes for mixin definitions
|
6
|
+
# and for loops and so forth,
|
7
|
+
# in addition to nodes for CSS rules and properties.
|
8
|
+
#
|
9
|
+
# However, {Tree::Node#perform} returns a different sort of tree.
|
10
|
+
# This tree maps more closely to the resulting CSS document
|
11
|
+
# than it does to the original Sass document.
|
12
|
+
# It still has nodes for CSS rules and properties,
|
13
|
+
# but it doesn't have any dynamic-generation-related nodes.
|
14
|
+
#
|
15
|
+
# Nodes that only appear in the pre-perform state are called **dynamic nodes**;
|
16
|
+
# those that appear in both states are called **static nodes**.
|
2
17
|
module Tree
|
18
|
+
# This class doubles as the root node of the parse tree
|
19
|
+
# and the superclass of all other parse-tree nodes.
|
3
20
|
class Node
|
21
|
+
# The child nodes of this node.
|
22
|
+
#
|
23
|
+
# @return [Array<Tree::Node>]
|
4
24
|
attr_accessor :children
|
25
|
+
|
26
|
+
# The line of the document on which this node appeared.
|
27
|
+
#
|
28
|
+
# @return [Fixnum]
|
5
29
|
attr_accessor :line
|
30
|
+
|
31
|
+
# The name of the document on which this node appeared.
|
32
|
+
#
|
33
|
+
# @return [String]
|
6
34
|
attr_writer :filename
|
35
|
+
|
36
|
+
# The options hash for the node.
|
37
|
+
# See [the Sass options documentation](../../Sass.html#sass_options).
|
38
|
+
#
|
39
|
+
# @return [Hash<Symbol, Object>]
|
7
40
|
attr_reader :options
|
8
41
|
|
9
42
|
def initialize
|
10
43
|
@children = []
|
11
44
|
end
|
12
45
|
|
46
|
+
# Sets the options hash for the node and all its children.
|
47
|
+
#
|
48
|
+
# @param options [Hash<Symbol, Object>] The options
|
49
|
+
# @see #options
|
13
50
|
def options=(options)
|
14
51
|
children.each {|c| c.options = options}
|
15
52
|
@options = options
|
16
53
|
end
|
17
54
|
|
55
|
+
# The name of the document on which this node appeared.
|
56
|
+
#
|
57
|
+
# @return [String]
|
18
58
|
def filename
|
19
59
|
@filename || @options[:filename]
|
20
60
|
end
|
21
61
|
|
62
|
+
# Appends a child to the node.
|
63
|
+
#
|
64
|
+
# @param child [Tree::Node] The child node
|
65
|
+
# @raise [Sass::SyntaxError] if `child` is invalid
|
66
|
+
# @see #invalid_child?
|
22
67
|
def <<(child)
|
23
68
|
if msg = invalid_child?(child)
|
24
69
|
raise Sass::SyntaxError.new(msg, child.line)
|
@@ -26,21 +71,54 @@ module Sass
|
|
26
71
|
@children << child
|
27
72
|
end
|
28
73
|
|
29
|
-
#
|
74
|
+
# Return the last child node.
|
75
|
+
#
|
76
|
+
# We need this because {Tree::Node} duck types as an Array for {Sass::Engine}.
|
77
|
+
#
|
78
|
+
# @return [Tree::Node] The last child node
|
30
79
|
def last
|
31
80
|
children.last
|
32
81
|
end
|
33
82
|
|
83
|
+
# Compares this node and another object (only other {Tree::Node}s will be equal).
|
84
|
+
# This does a structural comparison;
|
85
|
+
# if the contents of the nodes and all the child nodes are equivalent,
|
86
|
+
# then the nodes are as well.
|
87
|
+
#
|
88
|
+
# Only static nodes need to override this.
|
89
|
+
#
|
90
|
+
# @param other [Object] The object to compare with
|
91
|
+
# @return [Boolean] Whether or not this node and the other object
|
92
|
+
# are the same
|
93
|
+
# @see Sass::Tree
|
34
94
|
def ==(other)
|
35
95
|
self.class == other.class && other.children == children
|
36
96
|
end
|
37
97
|
|
98
|
+
# Runs the dynamic Sass code *and* computes the CSS for the tree.
|
99
|
+
#
|
100
|
+
# @see #perform
|
101
|
+
# @see #to_s
|
38
102
|
def render
|
39
103
|
perform(Environment.new).to_s
|
40
104
|
end
|
41
105
|
|
106
|
+
# True if \{#to\_s} will return `nil`;
|
107
|
+
# that is, if the node shouldn't be rendered.
|
108
|
+
# Should only be called in a static tree.
|
109
|
+
#
|
110
|
+
# @return [Boolean]
|
42
111
|
def invisible?; false; end
|
43
112
|
|
113
|
+
# Computes the CSS corresponding to this Sass tree.
|
114
|
+
#
|
115
|
+
# Only static-node subclasses need to implement \{#to\_s}.
|
116
|
+
#
|
117
|
+
# This may return `nil`, but it will only do so if \{#invisible?} is true.
|
118
|
+
#
|
119
|
+
# @return [String, nil] The resulting CSS
|
120
|
+
# @raise [Sass::SyntaxError] if some element of the tree is invalid
|
121
|
+
# @see Sass::Tree
|
44
122
|
def to_s
|
45
123
|
result = String.new
|
46
124
|
children.each do |child|
|
@@ -56,32 +134,77 @@ module Sass
|
|
56
134
|
rescue Sass::SyntaxError => e; e.add_metadata(filename, line)
|
57
135
|
end
|
58
136
|
|
137
|
+
# Runs the dynamic Sass code:
|
138
|
+
# mixins, variables, control structures, and so forth.
|
139
|
+
# This doesn't modify this node or any of its children.
|
140
|
+
#
|
141
|
+
# \{#perform} shouldn't be overridden directly;
|
142
|
+
# if you want to return a new node (or list of nodes),
|
143
|
+
# override \{#\_perform};
|
144
|
+
# if you want to destructively modify this node,
|
145
|
+
# override \{#perform!}.
|
146
|
+
#
|
147
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
148
|
+
# variable and mixin values
|
149
|
+
# @return [Tree::Node] The resulting tree of static nodes
|
150
|
+
# @raise [Sass::SyntaxError] if some element of the tree is invalid
|
151
|
+
# @see Sass::Tree
|
59
152
|
def perform(environment)
|
60
153
|
environment.options = @options if self.class == Tree::Node
|
61
154
|
_perform(environment)
|
62
155
|
rescue Sass::SyntaxError => e; e.add_metadata(filename, line)
|
63
156
|
end
|
64
157
|
|
158
|
+
# The output style. See [the Sass options documentation](../../Sass.html#output_style).
|
159
|
+
#
|
160
|
+
# @return [Symbol]
|
65
161
|
def style
|
66
162
|
@options[:style]
|
67
163
|
end
|
68
164
|
|
69
165
|
protected
|
70
166
|
|
167
|
+
# Runs any dynamic Sass code in this particular node.
|
168
|
+
# This doesn't modify this node or any of its children.
|
169
|
+
#
|
170
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
171
|
+
# variable and mixin values
|
172
|
+
# @return [Tree::Node, Array<Tree::Node>] The resulting static nodes
|
173
|
+
# @see #perform
|
174
|
+
# @see Sass::Tree
|
71
175
|
def _perform(environment)
|
72
176
|
node = dup
|
73
177
|
node.perform!(environment)
|
74
178
|
node
|
75
179
|
end
|
76
180
|
|
181
|
+
# Destructively runs dynamic Sass code in this particular node.
|
182
|
+
# This *does* modify this node,
|
183
|
+
# but will be run non-destructively by \{#\_perform\}.
|
184
|
+
#
|
185
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
186
|
+
# variable and mixin values
|
187
|
+
# @see #perform
|
77
188
|
def perform!(environment)
|
78
189
|
self.children = perform_children(Environment.new(environment))
|
79
190
|
end
|
80
191
|
|
192
|
+
# Non-destructively runs \{#perform} on all children of the current node.
|
193
|
+
#
|
194
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
195
|
+
# variable and mixin values
|
196
|
+
# @return [Array<Tree::Node>] The resulting static nodes
|
81
197
|
def perform_children(environment)
|
82
198
|
children.map {|c| c.perform(environment)}.flatten
|
83
199
|
end
|
84
200
|
|
201
|
+
# Replaces SassScript in a chunk of text (via `#{}`)
|
202
|
+
# with the resulting value.
|
203
|
+
#
|
204
|
+
# @param text [String] The text to interpolate
|
205
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
206
|
+
# variable and mixin values
|
207
|
+
# @return [String] The interpolated text
|
85
208
|
def interpolate(text, environment)
|
86
209
|
res = ''
|
87
210
|
rest = Haml::Shared.handle_interpolation text do |scan|
|
@@ -98,17 +221,24 @@ module Sass
|
|
98
221
|
res + rest
|
99
222
|
end
|
100
223
|
|
224
|
+
# @see Haml::Shared.balance
|
225
|
+
# @raise [Sass::SyntaxError] if the brackets aren't balanced
|
101
226
|
def balance(*args)
|
102
227
|
res = Haml::Shared.balance(*args)
|
103
228
|
return res if res
|
104
229
|
raise Sass::SyntaxError.new("Unbalanced brackets.", line)
|
105
230
|
end
|
106
231
|
|
107
|
-
|
108
|
-
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
232
|
+
# Returns an error message if the given child node is invalid,
|
233
|
+
# and false otherwise.
|
234
|
+
#
|
235
|
+
# By default, all child nodes are valid.
|
236
|
+
# This is expected to be overriden by subclasses
|
237
|
+
# for which some children are invalid.
|
238
|
+
#
|
239
|
+
# @param child [Tree::Node] A potential child node
|
240
|
+
# @return [Boolean, String] Whether or not the child node is valid,
|
241
|
+
# as well as the error message to display if it is invalid
|
112
242
|
def invalid_child?(child)
|
113
243
|
false
|
114
244
|
end
|