Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 373
- Log:
Initial import of Radiant 0.9.1, which is now packaged as a gem. This is an
import of the tagged 0.9.1 source checked out from GitHub, which isn't quite
the same as the gem distribution - but it doesn't seem to be available in an
archived form and the installed gem already has modifications, so this is
the closest I can get.
- Author:
- rool
- Date:
- Mon Mar 21 13:40:05 +0000 2011
- Size:
- 8543 Bytes
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**. |
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. |
20 | class Node |
21 | # The child nodes of this node. |
22 | # |
23 | # @return [Array<Tree::Node>] |
24 | attr_accessor :children |
25 | |
26 | # The line of the document on which this node appeared. |
27 | # |
28 | # @return [Fixnum] |
29 | attr_accessor :line |
30 | |
31 | # The name of the document on which this node appeared. |
32 | # |
33 | # @return [String] |
34 | attr_writer :filename |
35 | |
36 | # The options hash for the node. |
37 | # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}. |
38 | # |
39 | # @return [{Symbol => Object}] |
40 | attr_reader :options |
41 | |
42 | def initialize |
43 | @children = [] |
44 | end |
45 | |
46 | # Sets the options hash for the node and all its children. |
47 | # |
48 | # @param options [{Symbol => Object}] The options |
49 | # @see #options |
50 | def options=(options) |
51 | children.each {|c| c.options = options} |
52 | @options = options |
53 | end |
54 | |
55 | # The name of the document on which this node appeared. |
56 | # |
57 | # @return [String] |
58 | def filename |
59 | @filename || (@options && @options[:filename]) |
60 | end |
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? |
67 | def <<(child) |
68 | if msg = invalid_child?(child) |
69 | raise Sass::SyntaxError.new(msg, child.line) |
70 | end |
71 | @children << child |
72 | end |
73 | |
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 |
79 | def last |
80 | children.last |
81 | end |
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 |
94 | def ==(other) |
95 | self.class == other.class && other.children == children |
96 | end |
97 | |
98 | # Runs the dynamic Sass code *and* computes the CSS for the tree. |
99 | # |
100 | # @see #perform |
101 | # @see #to_s |
102 | def render |
103 | perform(Environment.new).to_s |
104 | end |
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] |
111 | def invisible?; false; end |
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 |
122 | def to_s |
123 | result = String.new |
124 | children.each do |child| |
125 | if child.is_a? PropNode |
126 | message = "Properties aren't allowed at the root of a document." + |
127 | child.pseudo_class_selector_message |
128 | raise Sass::SyntaxError.new(message, child.line) |
129 | else |
130 | next if child.invisible? |
131 | child_str = child.to_s(1) |
132 | result << child_str + (style == :compressed ? '' : "\n") |
133 | end |
134 | end |
135 | result.rstrip! |
136 | return "" if result.empty? |
137 | return result + "\n" |
138 | rescue Sass::SyntaxError => e; e.add_metadata(filename, line) |
139 | end |
140 | |
141 | # Runs the dynamic Sass code: |
142 | # mixins, variables, control directives, and so forth. |
143 | # This doesn't modify this node or any of its children. |
144 | # |
145 | # \{#perform} shouldn't be overridden directly; |
146 | # if you want to return a new node (or list of nodes), |
147 | # override \{#\_perform}; |
148 | # if you want to destructively modify this node, |
149 | # override \{#perform!}. |
150 | # |
151 | # @param environment [Sass::Environment] The lexical environment containing |
152 | # variable and mixin values |
153 | # @return [Tree::Node] The resulting tree of static nodes |
154 | # @raise [Sass::SyntaxError] if some element of the tree is invalid |
155 | # @see Sass::Tree |
156 | def perform(environment) |
157 | environment.options = @options if self.class == Tree::Node |
158 | _perform(environment) |
159 | rescue Sass::SyntaxError => e; e.add_metadata(filename, line) |
160 | end |
161 | |
162 | # The output style. See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}. |
163 | # |
164 | # @return [Symbol] |
165 | def style |
166 | @options[:style] |
167 | end |
168 | |
169 | protected |
170 | |
171 | # Runs any dynamic Sass code in this particular node. |
172 | # This doesn't modify this node or any of its children. |
173 | # |
174 | # @param environment [Sass::Environment] The lexical environment containing |
175 | # variable and mixin values |
176 | # @return [Tree::Node, Array<Tree::Node>] The resulting static nodes |
177 | # @see #perform |
178 | # @see Sass::Tree |
179 | def _perform(environment) |
180 | node = dup |
181 | node.perform!(environment) |
182 | node |
183 | end |
184 | |
185 | # Destructively runs dynamic Sass code in this particular node. |
186 | # This *does* modify this node, |
187 | # but will be run non-destructively by \{#\_perform\}. |
188 | # |
189 | # @param environment [Sass::Environment] The lexical environment containing |
190 | # variable and mixin values |
191 | # @see #perform |
192 | def perform!(environment) |
193 | self.children = perform_children(Environment.new(environment)) |
194 | end |
195 | |
196 | # Non-destructively runs \{#perform} on all children of the current node. |
197 | # |
198 | # @param environment [Sass::Environment] The lexical environment containing |
199 | # variable and mixin values |
200 | # @return [Array<Tree::Node>] The resulting static nodes |
201 | def perform_children(environment) |
202 | children.map {|c| c.perform(environment)}.flatten |
203 | end |
204 | |
205 | # Replaces SassScript in a chunk of text (via `#{}`) |
206 | # with the resulting value. |
207 | # |
208 | # @param text [String] The text to interpolate |
209 | # @param environment [Sass::Environment] The lexical environment containing |
210 | # variable and mixin values |
211 | # @return [String] The interpolated text |
212 | def interpolate(text, environment) |
213 | res = '' |
214 | rest = Haml::Shared.handle_interpolation text do |scan| |
215 | escapes = scan[2].size |
216 | res << scan.matched[0...-2 - escapes] |
217 | if escapes % 2 == 1 |
218 | res << "\\" * (escapes - 1) << '#{' |
219 | else |
220 | res << "\\" * [0, escapes - 1].max |
221 | res << Script::Parser.new(scan, line, scan.pos - scan.matched_size, filename). |
222 | parse_interpolated.perform(environment).to_s |
223 | end |
224 | end |
225 | res + rest |
226 | end |
227 | |
228 | # @see Haml::Shared.balance |
229 | # @raise [Sass::SyntaxError] if the brackets aren't balanced |
230 | def balance(*args) |
231 | res = Haml::Shared.balance(*args) |
232 | return res if res |
233 | raise Sass::SyntaxError.new("Unbalanced brackets.", line) |
234 | end |
235 | |
236 | # Returns an error message if the given child node is invalid, |
237 | # and false otherwise. |
238 | # |
239 | # By default, all child nodes are valid. |
240 | # This is expected to be overriden by subclasses |
241 | # for which some children are invalid. |
242 | # |
243 | # @param child [Tree::Node] A potential child node |
244 | # @return [Boolean, String] Whether or not the child node is valid, |
245 | # as well as the error message to display if it is invalid |
246 | def invalid_child?(child) |
247 | false |
248 | end |
249 | end |
250 | end |
251 | end |