haml-edge 2.1.21 → 2.1.22
Sign up to get free protection for your applications and to get access to all the features.
- 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
|