| Class | Sass::CSS |
| In: |
lib/sass/css.rb
|
| Parent: | Object |
Creates a new instance of Sass::CSS that will compile the given document to a Sass string when render is called.
# File lib/sass/css.rb, line 114
114: def initialize(template, options = {})
115: if template.is_a? IO
116: template = template.read
117: end
118:
119: @options = options
120: @template = StringScanner.new(template)
121: end
Processes the document and returns the result as a string containing the CSS template.
# File lib/sass/css.rb, line 125
125: def render
126: begin
127: build_tree.to_sass(@options).strip + "\n"
128: rescue Exception => err
129: line = @template.string[0...@template.pos].split("\n").size
130:
131: err.backtrace.unshift "(css):#{line}"
132: raise err
133: end
134: end
# File lib/sass/css.rb, line 210
210: def assert_match(re)
211: if !@template.scan(re)
212: line = @template.string[0..@template.pos].count "\n"
213: # Display basic regexps as plain old strings
214: expected = re.source == Regexp.escape(re.source) ? "\"#{re.source}\"" : re.inspect
215: raise Exception.new("Invalid CSS on line #{line}: expected #{expected}")
216: end
217: whitespace
218: end
# File lib/sass/css.rb, line 179
179: def attributes(rule)
180: while @template.scan(/[^:\}\s]+/)
181: name = @template[0]
182: whitespace
183:
184: assert_match /:/
185:
186: value = ''
187: while @template.scan(/[^;\s\}]+/)
188: value << @template[0] << whitespace
189: end
190:
191: assert_match /(;|(?=\}))/
192: rule << Tree::AttrNode.new(name, value, nil)
193: end
194:
195: assert_match /\}/
196: end
# File lib/sass/css.rb, line 138
138: def build_tree
139: root = Tree::Node.new(nil)
140: whitespace
141: rules root
142: expand_commas root
143: parent_ref_rules root
144: remove_parent_refs root
145: flatten_rules root
146: fold_commas root
147: root
148: end
Transform
foo, bar, baz
color: blue
into
foo
color: blue
bar
color: blue
baz
color: blue
Yes, this expands the amount of code, but it‘s necessary to get nesting to work properly.
# File lib/sass/css.rb, line 236
236: def expand_commas(root)
237: root.children.map! do |child|
238: next child unless Tree::RuleNode === child && child.rule.include?(',')
239: child.rule.split(',').map do |rule|
240: node = Tree::RuleNode.new(rule.strip, {})
241: node.children = child.children
242: node
243: end
244: end
245: root.children.flatten!
246: end
# File lib/sass/css.rb, line 347
347: def flatten_rule(rule)
348: while rule.children.size == 1 && rule.children.first.is_a?(Tree::RuleNode)
349: child = rule.children.first
350:
351: if child.rule[0] == ?&
352: rule.rule = child.rule.gsub /^&/, rule.rule
353: else
354: rule.rule = "#{rule.rule} #{child.rule}"
355: end
356:
357: rule.children = child.children
358: end
359:
360: flatten_rules(rule)
361: end
Transform
foo
bar
color: blue
baz
color: blue
into
foo
bar, baz
color: blue
# File lib/sass/css.rb, line 377
377: def fold_commas(root)
378: prev_rule = nil
379: root.children.map! do |child|
380: next child unless child.is_a?(Tree::RuleNode)
381:
382: if prev_rule && prev_rule.children == child.children
383: prev_rule.rule << ", #{child.rule}"
384: next nil
385: end
386:
387: fold_commas(child)
388: prev_rule = child
389: child
390: end
391: root.children.compact!
392: end
Make rules use parent refs so that
foo
color: green
foo.bar
color: blue
becomes
foo
color: green
&.bar
color: blue
This has the side effect of nesting rules, so that
foo
color: green
foo bar
color: red
foo baz
color: blue
becomes
foo
color: green
& bar
color: red
& baz
color: blue
# File lib/sass/css.rb, line 281
281: def parent_ref_rules(root)
282: rules = OrderedHash.new
283: root.children.select { |c| Tree::RuleNode === c }.each do |child|
284: root.children.delete child
285: first, rest = child.rule.scan(/^(&?(?: .|[^ ])[^.#: \[]*)([.#: \[].*)?$/).first
286: rules[first] ||= Tree::RuleNode.new(first, nil)
287: if rest
288: child.rule = "&" + rest
289: rules[first] << child
290: else
291: rules[first].children += child.children
292: end
293: end
294:
295: rules.values.each { |v| parent_ref_rules(v) }
296: root.children += rules.values
297: end
Remove useless parent refs so that
foo
& bar
color: blue
becomes
foo
bar
color: blue
# File lib/sass/css.rb, line 311
311: def remove_parent_refs(root)
312: root.children.each do |child|
313: if child.is_a?(Tree::RuleNode)
314: child.rule.gsub! /^& +/, ''
315: remove_parent_refs child
316: end
317: end
318: end
# File lib/sass/css.rb, line 157
157: def rule
158: return unless rule = @template.scan(/[^\{\};]+/)
159: rule.strip!
160: directive = rule[0] == ?@
161:
162: if directive
163: node = Tree::DirectiveNode.new(rule, nil)
164: return node if @template.scan(/;/)
165:
166: assert_match /\{/
167: whitespace
168:
169: rules(node)
170: return node
171: end
172:
173: assert_match /\{/
174: node = Tree::RuleNode.new(rule, nil)
175: attributes(node)
176: return node
177: end
# File lib/sass/css.rb, line 150
150: def rules(root)
151: while r = rule
152: root << r
153: whitespace
154: end
155: end
# File lib/sass/css.rb, line 198
198: def whitespace
199: space = @template.scan(/\s*/) || ''
200:
201: # If we've hit a comment,
202: # go past it and look for more whitespace
203: if @template.scan(/\/\*/)
204: @template.scan_until(/\*\//)
205: return space + whitespace
206: end
207: return space
208: end