haml 2.0.10 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of haml might be problematic. Click here for more details.
- data/.yardopts +5 -0
- data/MIT-LICENSE +1 -1
- data/README.md +347 -0
- data/Rakefile +124 -19
- data/VERSION +1 -1
- data/VERSION_NAME +1 -0
- data/extra/haml-mode.el +397 -78
- data/extra/sass-mode.el +148 -36
- data/extra/update_watch.rb +13 -0
- data/lib/haml.rb +15 -993
- data/lib/haml/buffer.rb +131 -84
- data/lib/haml/engine.rb +129 -97
- data/lib/haml/error.rb +7 -7
- data/lib/haml/exec.rb +127 -42
- data/lib/haml/filters.rb +107 -42
- data/lib/haml/helpers.rb +210 -156
- data/lib/haml/helpers/action_view_extensions.rb +34 -39
- data/lib/haml/helpers/action_view_mods.rb +132 -139
- data/lib/haml/html.rb +77 -65
- data/lib/haml/precompiler.rb +404 -213
- data/lib/haml/shared.rb +78 -0
- data/lib/haml/template.rb +14 -14
- data/lib/haml/template/patch.rb +2 -2
- data/lib/haml/template/plugin.rb +2 -3
- data/lib/haml/util.rb +211 -6
- data/lib/haml/version.rb +30 -13
- data/lib/sass.rb +7 -856
- data/lib/sass/css.rb +169 -161
- data/lib/sass/engine.rb +344 -328
- data/lib/sass/environment.rb +79 -0
- data/lib/sass/error.rb +33 -11
- data/lib/sass/files.rb +139 -0
- data/lib/sass/plugin.rb +160 -117
- data/lib/sass/plugin/merb.rb +7 -6
- data/lib/sass/plugin/rails.rb +5 -6
- data/lib/sass/repl.rb +58 -0
- data/lib/sass/script.rb +59 -0
- data/lib/sass/script/bool.rb +17 -0
- data/lib/sass/script/color.rb +183 -0
- data/lib/sass/script/funcall.rb +50 -0
- data/lib/sass/script/functions.rb +198 -0
- data/lib/sass/script/lexer.rb +178 -0
- data/lib/sass/script/literal.rb +177 -0
- data/lib/sass/script/node.rb +14 -0
- data/lib/sass/script/number.rb +381 -0
- data/lib/sass/script/operation.rb +45 -0
- data/lib/sass/script/parser.rb +172 -0
- data/lib/sass/script/string.rb +12 -0
- data/lib/sass/script/unary_operation.rb +34 -0
- data/lib/sass/script/variable.rb +31 -0
- data/lib/sass/tree/comment_node.rb +73 -10
- data/lib/sass/tree/debug_node.rb +30 -0
- data/lib/sass/tree/directive_node.rb +42 -17
- data/lib/sass/tree/file_node.rb +41 -0
- data/lib/sass/tree/for_node.rb +48 -0
- data/lib/sass/tree/if_node.rb +54 -0
- data/lib/sass/tree/mixin_def_node.rb +29 -0
- data/lib/sass/tree/mixin_node.rb +48 -0
- data/lib/sass/tree/node.rb +214 -11
- data/lib/sass/tree/prop_node.rb +109 -0
- data/lib/sass/tree/rule_node.rb +178 -51
- data/lib/sass/tree/variable_node.rb +34 -0
- data/lib/sass/tree/while_node.rb +31 -0
- data/test/haml/engine_test.rb +331 -36
- data/test/haml/helper_test.rb +12 -1
- data/test/haml/results/content_for_layout.xhtml +0 -3
- data/test/haml/results/filters.xhtml +2 -0
- data/test/haml/results/list.xhtml +1 -1
- data/test/haml/template_test.rb +7 -2
- data/test/haml/templates/content_for_layout.haml +0 -2
- data/test/haml/templates/list.haml +1 -1
- data/test/haml/util_test.rb +92 -0
- data/test/sass/css2sass_test.rb +69 -24
- data/test/sass/engine_test.rb +586 -64
- data/test/sass/functions_test.rb +125 -0
- data/test/sass/more_results/more1.css +9 -0
- data/test/sass/more_results/more1_with_line_comments.css +26 -0
- data/test/sass/more_results/more_import.css +29 -0
- data/test/sass/more_templates/_more_partial.sass +2 -0
- data/test/sass/more_templates/more1.sass +23 -0
- data/test/sass/more_templates/more_import.sass +11 -0
- data/test/sass/plugin_test.rb +81 -28
- data/test/sass/results/line_numbers.css +49 -0
- data/test/sass/results/{constants.css → script.css} +4 -4
- data/test/sass/results/subdir/subdir.css +2 -0
- data/test/sass/results/units.css +11 -0
- data/test/sass/script_test.rb +258 -0
- data/test/sass/templates/import.sass +1 -1
- data/test/sass/templates/importee.sass +7 -2
- data/test/sass/templates/line_numbers.sass +13 -0
- data/test/sass/templates/{constants.sass → script.sass} +11 -10
- data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
- data/test/sass/templates/subdir/subdir.sass +2 -2
- data/test/sass/templates/units.sass +11 -0
- data/test/test_helper.rb +14 -0
- metadata +77 -19
- data/FAQ +0 -138
- data/README.rdoc +0 -319
- data/lib/sass/constant.rb +0 -216
- data/lib/sass/constant/color.rb +0 -101
- data/lib/sass/constant/literal.rb +0 -54
- data/lib/sass/constant/nil.rb +0 -9
- data/lib/sass/constant/number.rb +0 -87
- data/lib/sass/constant/operation.rb +0 -30
- data/lib/sass/constant/string.rb +0 -22
- data/lib/sass/tree/attr_node.rb +0 -57
- data/lib/sass/tree/value_node.rb +0 -20
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'sass/script/string'
|
3
|
+
require 'sass/script/number'
|
4
|
+
require 'sass/script/color'
|
5
|
+
require 'sass/script/functions'
|
6
|
+
require 'sass/script/unary_operation'
|
7
|
+
|
8
|
+
module Sass::Script
|
9
|
+
# A SassScript parse node representing a binary operation,
|
10
|
+
# such as `!a + !b` or `"foo" + 1`.
|
11
|
+
class Operation < Node
|
12
|
+
# @param operand1 [Script::Node] The parse-tree node
|
13
|
+
# for the right-hand side of the operator
|
14
|
+
# @param operand2 [Script::Node] The parse-tree node
|
15
|
+
# for the left-hand side of the operator
|
16
|
+
# @param operator [Symbol] The operator to perform.
|
17
|
+
# This should be one of the binary operator names in {Lexer::OPERATORS}
|
18
|
+
def initialize(operand1, operand2, operator)
|
19
|
+
@operand1 = operand1
|
20
|
+
@operand2 = operand2
|
21
|
+
@operator = operator
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [String] A human-readable s-expression representation of the operation
|
25
|
+
def inspect
|
26
|
+
"(#{@operator.inspect} #{@operand1.inspect} #{@operand2.inspect})"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Evaluates the operation.
|
30
|
+
#
|
31
|
+
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
32
|
+
# @return [Literal] The SassScript object that is the value of the operation
|
33
|
+
# @raise [Sass::SyntaxError] if the operation is undefined for the operands
|
34
|
+
def perform(environment)
|
35
|
+
literal1 = @operand1.perform(environment)
|
36
|
+
literal2 = @operand2.perform(environment)
|
37
|
+
begin
|
38
|
+
literal1.send(@operator, literal2)
|
39
|
+
rescue NoMethodError => e
|
40
|
+
raise e unless e.name.to_s == @operator.to_s
|
41
|
+
raise Sass::SyntaxError.new("Undefined operation: \"#{literal1} #{@operator} #{literal2}\".")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'sass/script/lexer'
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
module Script
|
5
|
+
# The parser for SassScript.
|
6
|
+
# It parses a string of code into a tree of {Script::Node}s.
|
7
|
+
class Parser
|
8
|
+
# @param str [String, StringScanner] The source text to parse
|
9
|
+
# @param line [Fixnum] The line on which the SassScript appears.
|
10
|
+
# Used for error reporting
|
11
|
+
# @param offset [Fixnum] The number of characters in on which the SassScript appears.
|
12
|
+
# Used for error reporting
|
13
|
+
# @param filename [String] The name of the file in which the SassScript appears.
|
14
|
+
# Used for error reporting
|
15
|
+
def initialize(str, line, offset, filename = nil)
|
16
|
+
@filename = filename
|
17
|
+
@lexer = Lexer.new(str, line, offset)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Parses a SassScript expression within an interpolated segment (`#{}`).
|
21
|
+
# This means that it stops when it comes across an unmatched `}`,
|
22
|
+
# which signals the end of an interpolated segment,
|
23
|
+
# it returns rather than throwing an error.
|
24
|
+
#
|
25
|
+
# @return [Script::Node] The root node of the parse tree
|
26
|
+
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
27
|
+
def parse_interpolated
|
28
|
+
expr = assert_expr :expr
|
29
|
+
assert_tok :end_interpolation
|
30
|
+
expr
|
31
|
+
end
|
32
|
+
|
33
|
+
# Parses a SassScript expression.
|
34
|
+
#
|
35
|
+
# @return [Script::Node] The root node of the parse tree
|
36
|
+
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
37
|
+
def parse
|
38
|
+
expr = assert_expr :expr
|
39
|
+
raise Sass::SyntaxError.new("Unexpected #{@lexer.peek.type} token.") unless @lexer.done?
|
40
|
+
expr
|
41
|
+
end
|
42
|
+
|
43
|
+
# Parses a SassScript expression.
|
44
|
+
#
|
45
|
+
# @overload parse(str, line, offset, filename = nil)
|
46
|
+
# @return [Script::Node] The root node of the parse tree
|
47
|
+
# @see Parser#initialize
|
48
|
+
# @see Parser#parse
|
49
|
+
def self.parse(*args)
|
50
|
+
new(*args).parse
|
51
|
+
end
|
52
|
+
|
53
|
+
class << self
|
54
|
+
private
|
55
|
+
|
56
|
+
# Defines a simple left-associative production.
|
57
|
+
# name is the name of the production,
|
58
|
+
# sub is the name of the production beneath it,
|
59
|
+
# and ops is a list of operators for this precedence level
|
60
|
+
def production(name, sub, *ops)
|
61
|
+
class_eval <<RUBY
|
62
|
+
def #{name}
|
63
|
+
return unless e = #{sub}
|
64
|
+
while tok = try_tok(#{ops.map {|o| o.inspect}.join(', ')})
|
65
|
+
e = Operation.new(e, assert_expr(#{sub.inspect}), tok.type)
|
66
|
+
end
|
67
|
+
e
|
68
|
+
end
|
69
|
+
RUBY
|
70
|
+
end
|
71
|
+
|
72
|
+
def unary(op, sub)
|
73
|
+
class_eval <<RUBY
|
74
|
+
def unary_#{op}
|
75
|
+
return #{sub} unless try_tok(:#{op})
|
76
|
+
UnaryOperation.new(assert_expr(:unary_#{op}), :#{op})
|
77
|
+
end
|
78
|
+
RUBY
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
production :expr, :concat, :comma
|
85
|
+
|
86
|
+
def concat
|
87
|
+
return unless e = or_expr
|
88
|
+
while sub = or_expr
|
89
|
+
e = Operation.new(e, sub, :concat)
|
90
|
+
end
|
91
|
+
e
|
92
|
+
end
|
93
|
+
|
94
|
+
production :or_expr, :and_expr, :or
|
95
|
+
production :and_expr, :eq_or_neq, :and
|
96
|
+
production :eq_or_neq, :relational, :eq, :neq
|
97
|
+
production :relational, :plus_or_minus, :gt, :gte, :lt, :lte
|
98
|
+
production :plus_or_minus, :times_div_or_mod, :plus, :minus
|
99
|
+
production :times_div_or_mod, :unary_minus, :times, :div, :mod
|
100
|
+
|
101
|
+
unary :minus, :unary_div
|
102
|
+
unary :div, :unary_not # For strings, so /foo/bar works
|
103
|
+
unary :not, :funcall
|
104
|
+
|
105
|
+
def funcall
|
106
|
+
return paren unless name = try_tok(:ident)
|
107
|
+
# An identifier without arguments is just a string
|
108
|
+
unless try_tok(:lparen)
|
109
|
+
warn(<<END)
|
110
|
+
DEPRECATION WARNING:
|
111
|
+
On line #{name.line}, character #{name.offset}#{" of '#{@filename}'" if @filename}
|
112
|
+
Implicit strings have been deprecated and will be removed in version 2.4.
|
113
|
+
'#{name.value}' was not quoted. Please add double quotes (e.g. "#{name.value}").
|
114
|
+
END
|
115
|
+
Script::String.new(name.value)
|
116
|
+
else
|
117
|
+
args = arglist || []
|
118
|
+
assert_tok(:rparen)
|
119
|
+
Script::Funcall.new(name.value, args)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def arglist
|
124
|
+
return unless e = concat
|
125
|
+
return [e] unless try_tok(:comma)
|
126
|
+
[e, *arglist]
|
127
|
+
end
|
128
|
+
|
129
|
+
def paren
|
130
|
+
return variable unless try_tok(:lparen)
|
131
|
+
e = assert_expr(:expr)
|
132
|
+
assert_tok(:rparen)
|
133
|
+
return e
|
134
|
+
end
|
135
|
+
|
136
|
+
def variable
|
137
|
+
return string unless c = try_tok(:const)
|
138
|
+
Variable.new(c.value)
|
139
|
+
end
|
140
|
+
|
141
|
+
def string
|
142
|
+
return literal unless first = try_tok(:string)
|
143
|
+
return first.value unless try_tok(:begin_interpolation)
|
144
|
+
mid = parse_interpolated
|
145
|
+
last = assert_expr(:string)
|
146
|
+
Operation.new(first.value, Operation.new(mid, last, :plus), :plus)
|
147
|
+
end
|
148
|
+
|
149
|
+
def literal
|
150
|
+
(t = try_tok(:number, :color, :bool)) && (return t.value)
|
151
|
+
end
|
152
|
+
|
153
|
+
# It would be possible to have unified #assert and #try methods,
|
154
|
+
# but detecting the method/token difference turns out to be quite expensive.
|
155
|
+
|
156
|
+
def assert_expr(name)
|
157
|
+
(e = send(name)) && (return e)
|
158
|
+
raise Sass::SyntaxError.new("Expected expression, was #{@lexer.done? ? 'end of text' : "#{@lexer.peek.type} token"}.")
|
159
|
+
end
|
160
|
+
|
161
|
+
def assert_tok(*names)
|
162
|
+
(t = try_tok(*names)) && (return t)
|
163
|
+
raise Sass::SyntaxError.new("Expected #{names.join(' or ')} token, was #{@lexer.done? ? 'end of text' : "#{@lexer.peek.type} token"}.")
|
164
|
+
end
|
165
|
+
|
166
|
+
def try_tok(*names)
|
167
|
+
peeked = @lexer.peek
|
168
|
+
peeked && names.include?(peeked.type) && @lexer.next
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'sass/script/literal'
|
2
|
+
|
3
|
+
module Sass::Script
|
4
|
+
# A SassScript object representing a string of text.
|
5
|
+
class String < Literal
|
6
|
+
# The Ruby value of the string.
|
7
|
+
#
|
8
|
+
# @return [String]
|
9
|
+
attr_reader :value
|
10
|
+
alias_method :to_s, :value
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Sass::Script
|
2
|
+
# A SassScript parse node representing a unary operation,
|
3
|
+
# such as `-!b` or `not true`.
|
4
|
+
#
|
5
|
+
# Currently only `-`, `/`, and `not` are unary operators.
|
6
|
+
class UnaryOperation < Node
|
7
|
+
# @param operand [Script::Node] The parse-tree node
|
8
|
+
# for the object of the operator
|
9
|
+
# @param operator [Symbol] The operator to perform
|
10
|
+
def initialize(operand, operator)
|
11
|
+
@operand = operand
|
12
|
+
@operator = operator
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [String] A human-readable s-expression representation of the operation
|
16
|
+
def inspect
|
17
|
+
"(#{@operator.inspect} #{@operand.inspect})"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Evaluates the operation.
|
21
|
+
#
|
22
|
+
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
23
|
+
# @return [Literal] The SassScript object that is the value of the operation
|
24
|
+
# @raise [Sass::SyntaxError] if the operation is undefined for the operand
|
25
|
+
def perform(environment)
|
26
|
+
operator = "unary_#{@operator}"
|
27
|
+
literal = @operand.perform(environment)
|
28
|
+
literal.send(operator)
|
29
|
+
rescue NoMethodError => e
|
30
|
+
raise e unless e.name.to_s == operator.to_s
|
31
|
+
raise Sass::SyntaxError.new("Undefined unary operation: \"#{@operator} #{literal}\".")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Sass
|
2
|
+
module Script
|
3
|
+
# A SassScript parse node representing a variable.
|
4
|
+
class Variable < Node
|
5
|
+
# The name of the variable.
|
6
|
+
#
|
7
|
+
# @return [String]
|
8
|
+
attr_reader :name
|
9
|
+
|
10
|
+
# @param name [String] See \{#name}
|
11
|
+
def initialize(name)
|
12
|
+
@name = name
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [String] A string representation of the variable
|
16
|
+
def inspect
|
17
|
+
"!#{name}"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Evaluates the variable.
|
21
|
+
#
|
22
|
+
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
23
|
+
# @return [Literal] The SassScript object that is the value of the variable
|
24
|
+
# @raise [Sass::SyntaxError] if the variable is undefined
|
25
|
+
def perform(environment)
|
26
|
+
(val = environment.var(name)) && (return val)
|
27
|
+
raise SyntaxError.new("Undefined variable: \"!#{name}\".")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,20 +1,83 @@
|
|
1
1
|
require 'sass/tree/node'
|
2
2
|
|
3
3
|
module Sass::Tree
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
# A static node representing a Sass comment (silent or loud).
|
5
|
+
#
|
6
|
+
# @see Sass::Tree
|
7
|
+
class CommentNode < Node
|
8
|
+
# The lines of text nested beneath the comment.
|
9
|
+
#
|
10
|
+
# @return [Array<Sass::Engine::Line>]
|
11
|
+
attr_accessor :lines
|
12
|
+
|
13
|
+
# The text on the same line as the comment starter.
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
attr_accessor :value
|
17
|
+
|
18
|
+
# Whether or not the comment is silent (that is, doesn't output to CSS).
|
19
|
+
#
|
20
|
+
# @return [Boolean]
|
21
|
+
attr_accessor :silent
|
22
|
+
|
23
|
+
# @param value [String] See \{#value}
|
24
|
+
# @param silent [Boolean] See \{#silent}
|
25
|
+
def initialize(value, silent)
|
26
|
+
@lines = []
|
27
|
+
@value = value[2..-1].strip
|
28
|
+
@silent = silent
|
29
|
+
super()
|
7
30
|
end
|
8
31
|
|
9
|
-
|
10
|
-
|
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
|
37
|
+
def ==(other)
|
38
|
+
self.class == other.class && value == other.value && silent == other.silent && lines == other.lines
|
39
|
+
end
|
40
|
+
|
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)
|
51
|
+
return if invisible?
|
52
|
+
|
53
|
+
content = (value.split("\n") + lines.map {|l| l.text})
|
54
|
+
content.map! {|l| (l.empty? ? "" : " ") + l}
|
55
|
+
content.first.gsub!(/^ /, '')
|
56
|
+
content.last.gsub!(%r{ ?\*/ *$}, '')
|
11
57
|
|
12
58
|
spaces = ' ' * (tabs - 1)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
59
|
+
spaces + "/* " + content.join(style == :compact ? '' : "\n#{spaces} *") + " */"
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns `true` if this is a silent comment
|
63
|
+
# or the current style doesn't render comments.
|
64
|
+
#
|
65
|
+
# @return [Boolean]
|
66
|
+
def invisible?
|
67
|
+
style == :compressed || @silent
|
68
|
+
end
|
69
|
+
|
70
|
+
protected
|
71
|
+
|
72
|
+
# Removes this node from the tree if it's a silent comment.
|
73
|
+
#
|
74
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
75
|
+
# variable and mixin values
|
76
|
+
# @return [Tree::Node, Array<Tree::Node>] The resulting static nodes
|
77
|
+
# @see Sass::Tree
|
78
|
+
def _perform(environment)
|
79
|
+
return [] if @silent
|
80
|
+
self
|
18
81
|
end
|
19
82
|
end
|
20
83
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Sass
|
2
|
+
module Tree
|
3
|
+
# A dynamic node representing a Sass `@debug` statement.
|
4
|
+
#
|
5
|
+
# @see Sass::Tree
|
6
|
+
class DebugNode < Node
|
7
|
+
# @param expr [Script::Node] The expression to print
|
8
|
+
def initialize(expr)
|
9
|
+
@expr = expr
|
10
|
+
super()
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
# Prints the expression to STDERR.
|
16
|
+
#
|
17
|
+
# @param environment [Sass::Environment] The lexical environment containing
|
18
|
+
# variable and mixin values
|
19
|
+
def _perform(environment)
|
20
|
+
res = @expr.perform(environment)
|
21
|
+
if filename
|
22
|
+
STDERR.puts "#{filename}:#{line} DEBUG: #{res}"
|
23
|
+
else
|
24
|
+
STDERR.puts "Line #{line} DEBUG: #{res}"
|
25
|
+
end
|
26
|
+
[]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,44 +1,69 @@
|
|
1
|
-
require 'sass/tree/node'
|
2
|
-
require 'sass/tree/value_node'
|
3
|
-
|
4
1
|
module Sass::Tree
|
5
|
-
|
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
|
14
|
+
class DirectiveNode < Node
|
15
|
+
# The text of the directive, `@` and all.
|
16
|
+
#
|
17
|
+
# @return [String]
|
18
|
+
attr_accessor :value
|
19
|
+
|
20
|
+
# @param value [String] See \{#value}
|
21
|
+
def initialize(value)
|
22
|
+
@value = value
|
23
|
+
super()
|
24
|
+
end
|
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
|
6
30
|
def to_s(tabs)
|
7
31
|
if children.empty?
|
8
32
|
value + ";"
|
9
33
|
else
|
10
|
-
result = if
|
34
|
+
result = if style == :compressed
|
11
35
|
"#{value}{"
|
12
36
|
else
|
13
|
-
"#{' ' * (tabs - 1)}#{value} {" + (
|
37
|
+
"#{' ' * (tabs - 1)}#{value} {" + (style == :compact ? ' ' : "\n")
|
14
38
|
end
|
15
|
-
|
39
|
+
was_prop = false
|
16
40
|
first = true
|
17
41
|
children.each do |child|
|
18
|
-
if
|
19
|
-
|
20
|
-
|
42
|
+
next if child.invisible?
|
43
|
+
if style == :compact
|
44
|
+
if child.is_a?(PropNode)
|
45
|
+
result << "#{child.to_s(first || was_prop ? 1 : tabs + 1)} "
|
21
46
|
else
|
22
|
-
if
|
47
|
+
if was_prop
|
23
48
|
result[-1] = "\n"
|
24
49
|
end
|
25
50
|
rendered = child.to_s(tabs + 1)
|
26
51
|
rendered.lstrip! if first
|
27
52
|
result << rendered
|
28
53
|
end
|
29
|
-
|
54
|
+
was_prop = child.is_a?(PropNode)
|
30
55
|
first = false
|
31
|
-
elsif
|
32
|
-
result << (
|
33
|
-
|
56
|
+
elsif style == :compressed
|
57
|
+
result << (was_prop ? ";#{child.to_s(1)}" : child.to_s(1))
|
58
|
+
was_prop = child.is_a?(PropNode)
|
34
59
|
else
|
35
60
|
result << child.to_s(tabs + 1) + "\n"
|
36
61
|
end
|
37
62
|
end
|
38
|
-
result.rstrip + if
|
63
|
+
result.rstrip + if style == :compressed
|
39
64
|
"}"
|
40
65
|
else
|
41
|
-
(
|
66
|
+
(style == :expanded ? "\n" : " ") + "}\n"
|
42
67
|
end
|
43
68
|
end
|
44
69
|
end
|