Class Sass::Engine
In: lib/sass/engine.rb
Parent: Object
Haml::Util Engine Color SyntaxError UnitConversionError StandardError AbstractSequence CommaSequence Sequence SimpleSequence Simple Parent Universal Class SelectorPseudoClass Id Pseudo Attribute Interpolation Element Node Operation Literal UnaryOperation StringInterpolation Funcall Interpolation Variable Lexer CssLexer Number Bool String Parser Parser CssParser EvaluationContext StaticParser SassParser CssParser Node DebugNode IfNode CommentNode ForNode PropNode MixinNode CharsetNode DirectiveNode VariableNode WarnNode ExtendNode RootNode WhileNode MixinDefNode RuleNode Enumerable ImportNode Merb::BootLoader MerbBootLoader Repl CSS Environment Rack StalenessChecker lib/sass/repl.rb lib/sass/css.rb lib/sass/environment.rb lib/sass/error.rb lib/sass/engine.rb lib/sass/selector/simple_sequence.rb lib/sass/selector/abstract_sequence.rb lib/sass/selector/sequence.rb lib/sass/selector/comma_sequence.rb lib/sass/selector/simple.rb lib/sass/selector.rb Selector lib/sass/script/css_parser.rb lib/sass/script/lexer.rb lib/sass/script/color.rb lib/sass/script/string.rb lib/sass/script/unary_operation.rb lib/sass/script/variable.rb lib/sass/script/funcall.rb lib/sass/script/string_interpolation.rb lib/sass/script/operation.rb lib/sass/script/bool.rb lib/sass/script/parser.rb lib/sass/script/node.rb lib/sass/script/literal.rb lib/sass/script/interpolation.rb lib/sass/script/css_lexer.rb lib/sass/script/number.rb lib/sass/script/functions.rb Functions Script lib/sass/scss/sass_parser.rb lib/sass/scss/static_parser.rb lib/sass/scss/parser.rb lib/sass/scss/css_parser.rb ScriptLexer ScriptParser RX SCSS Callbacks Files lib/sass/tree/while_node.rb lib/sass/tree/if_node.rb lib/sass/tree/mixin_def_node.rb lib/sass/tree/debug_node.rb lib/sass/tree/root_node.rb lib/sass/tree/for_node.rb lib/sass/tree/import_node.rb lib/sass/tree/prop_node.rb lib/sass/tree/node.rb lib/sass/tree/comment_node.rb lib/sass/tree/extend_node.rb lib/sass/tree/charset_node.rb lib/sass/tree/mixin_node.rb lib/sass/tree/warn_node.rb lib/sass/tree/directive_node.rb lib/sass/tree/rule_node.rb lib/sass/tree/variable_node.rb Tree lib/sass/plugin/rack.rb lib/sass/plugin/staleness_checker.rb lib/sass/plugin/merb.rb Plugin Sass dot/m_86_0.png

This class handles the parsing and compilation of the Sass template. Example usage:

    template = File.load('stylesheets/sassy.sass')
    sass_engine = Sass::Engine.new(template)
    output = sass_engine.render
    puts output

Methods

Included Modules

Haml::Util

Classes and Modules

Class Sass::Engine::Line

Constants

PROPERTY_CHAR = ?:   The character that begins a CSS property.
SCRIPT_CHAR = ?=   The character that designates that a property should be assigned to a SassScript expression.
COMMENT_CHAR = ?/   The character that designates the beginning of a comment, either Sass or CSS.
SASS_COMMENT_CHAR = ?/   The character that follows the general COMMENT_CHAR and designates a Sass comment, which is not output as a CSS comment.
CSS_COMMENT_CHAR = ?*   The character that follows the general COMMENT_CHAR and designates a CSS comment, which is embedded in the CSS document.
DIRECTIVE_CHAR = ?@   The character used to denote a compiler directive.
ESCAPE_CHAR = ?\\   Designates a non-parsed rule.
MIXIN_DEFINITION_CHAR = ?=   Designates block as mixin definition rather than CSS rules to output
MIXIN_INCLUDE_CHAR = ?+   Includes named mixin declared using MIXIN_DEFINITION_CHAR
PROPERTY_NEW_MATCHER = /^[^\s:"\[]+\s*[=:](\s|$)/   The regex that matches properties of the form `name: prop`.
PROPERTY_NEW = /^([^\s=:"]+)\s*(=|:)(?:\s+|$)(.*)/   The regex that matches and extracts data from properties of the form `name: prop`.
PROPERTY_OLD = /^:([^\s=:"]+)\s*(=?)(?:\s+|$)(.*)/   The regex that matches and extracts data from properties of the form `:name prop`.
DEFAULT_OPTIONS = { :style => :nested, :load_paths => ['.'], :cache => true, :cache_location => './.sass-cache', :syntax => :sass, }.freeze   The default options for Sass::Engine. @api public
MIXIN_DEF_RE = /^(?:=|@mixin)\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
MIXIN_INCLUDE_RE = /^(?:\+|@include)\s*(#{Sass::SCSS::RX::IDENT})(.*)$/

Public Class methods

@param template [String] The Sass template.

  This template can be encoded using any encoding
  that can be converted to Unicode.
  If the template contains an `@charset` declaration,
  that overrides the Ruby encoding
  (see {file:SASS_REFERENCE.md#encodings the encoding documentation})

@param options [{Symbol => Object}] An options hash;

  see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}

[Source]

     # File lib/sass/engine.rb, line 144
144:     def initialize(template, options={})
145:       @options = DEFAULT_OPTIONS.merge(options.reject {|k, v| v.nil?})
146:       @template = template
147: 
148:       # Support both, because the docs said one and the other actually worked
149:       # for quite a long time.
150:       @options[:line_comments] ||= @options[:line_numbers]
151: 
152:       # Backwards compatibility
153:       @options[:property_syntax] ||= @options[:attribute_syntax]
154:       case @options[:property_syntax]
155:       when :alternate; @options[:property_syntax] = :new
156:       when :normal; @options[:property_syntax] = :old
157:       end
158:     end

Private Class methods

It‘s important that this have strings (at least) at the beginning, the end, and between each Script::Node.

@private

[Source]

     # File lib/sass/engine.rb, line 706
706:     def self.parse_interp(text, line, offset, options)
707:       res = []
708:       rest = Haml::Shared.handle_interpolation text do |scan|
709:         escapes = scan[2].size
710:         res << scan.matched[0...-2 - escapes]
711:         if escapes % 2 == 1
712:           res << "\\" * (escapes - 1) << '#{'
713:         else
714:           res << "\\" * [0, escapes - 1].max
715:           res << Script::Parser.new(
716:             scan, line, offset + scan.pos - scan.matched_size, options).
717:             parse_interpolated
718:         end
719:       end
720:       res << rest
721:     end

Public Instance methods

Render the template to CSS.

@return [String] The CSS @raise [Sass::SyntaxError] if there‘s an error in the document @raise [Encoding::UndefinedConversionError] if the source encoding

  cannot be converted to UTF-8

@raise [ArgumentError] if the document uses an unknown encoding with `@charset`

[Source]

     # File lib/sass/engine.rb, line 167
167:     def render
168:       return _render unless @options[:quiet]
169:       Haml::Util.silence_haml_warnings {_render}
170:     end

Returns the original encoding of the document, or `nil` under Ruby 1.8.

@return [Encoding, nil] @raise [Encoding::UndefinedConversionError] if the source encoding

  cannot be converted to UTF-8

@raise [ArgumentError] if the document uses an unknown encoding with `@charset`

[Source]

     # File lib/sass/engine.rb, line 189
189:     def source_encoding
190:       check_encoding!
191:       @original_encoding
192:     end
to_css()

Alias for render

Parses the document into its parse tree.

@return [Sass::Tree::Node] The root of the parse tree. @raise [Sass::SyntaxError] if there‘s an error in the document

[Source]

     # File lib/sass/engine.rb, line 177
177:     def to_tree
178:       return _to_tree unless @options[:quiet]
179:       Haml::Util.silence_haml_warnings {_to_tree}
180:     end

Private Instance methods

[Source]

     # File lib/sass/engine.rb, line 196
196:     def _render
197:       rendered = _to_tree.render
198:       return rendered if ruby1_8?
199:       begin
200:         # Try to convert the result to the original encoding,
201:         # but if that doesn't work fall back on UTF-8
202:         rendered = rendered.encode(source_encoding)
203:       rescue EncodingError
204:       end
205:       rendered.gsub(Regexp.new('\A@charset "(.*?)"'.encode(source_encoding)),
206:         "@charset \"#{source_encoding.name}\"".encode(source_encoding))
207:     end

[Source]

     # File lib/sass/engine.rb, line 209
209:     def _to_tree
210:       check_encoding!
211: 
212:       if @options[:syntax] == :scss
213:         root = Sass::SCSS::Parser.new(@template).parse
214:       else
215:         root = Tree::RootNode.new(@template)
216:         append_children(root, tree(tabulate(@template)).first, true)
217:       end
218: 
219:       root.options = @options
220:       root
221:     rescue SyntaxError => e
222:       e.modify_backtrace(:filename => @options[:filename], :line => @line)
223:       e.sass_template = @template
224:       raise e
225:     end

[Source]

     # File lib/sass/engine.rb, line 345
345:     def append_children(parent, children, root)
346:       continued_rule = nil
347:       continued_comment = nil
348:       children.each do |line|
349:         child = build_tree(parent, line, root)
350: 
351:         if child.is_a?(Tree::RuleNode) && child.continued?
352:           raise SyntaxError.new("Rules can't end in commas.",
353:             :line => child.line) unless child.children.empty?
354:           if continued_rule
355:             continued_rule.add_rules child
356:           else
357:             continued_rule = child
358:           end
359:           next
360:         end
361: 
362:         if continued_rule
363:           raise SyntaxError.new("Rules can't end in commas.",
364:             :line => continued_rule.line) unless child.is_a?(Tree::RuleNode)
365:           continued_rule.add_rules child
366:           continued_rule.children = child.children
367:           continued_rule, child = nil, continued_rule
368:         end
369: 
370:         if child.is_a?(Tree::CommentNode) && child.silent
371:           if continued_comment &&
372:               child.line == continued_comment.line +
373:               continued_comment.value.count("\n") + 1
374:             continued_comment.value << "\n" << child.value
375:             next
376:           end
377: 
378:           continued_comment = child
379:         end
380: 
381:         check_for_no_children(child)
382:         validate_and_append_child(parent, child, line, root)
383:       end
384: 
385:       raise SyntaxError.new("Rules can't end in commas.",
386:         :line => continued_rule.line) if continued_rule
387: 
388:       parent
389:     end

[Source]

     # File lib/sass/engine.rb, line 328
328:     def build_tree(parent, line, root = false)
329:       @line = line.index
330:       node_or_nodes = parse_line(parent, line, root)
331: 
332:       Array(node_or_nodes).each do |node|
333:         # Node is a symbol if it's non-outputting, like a variable assignment
334:         next unless node.is_a? Tree::Node
335: 
336:         node.line = line.index
337:         node.filename = line.filename
338: 
339:         append_children(node, line.children, false)
340:       end
341: 
342:       node_or_nodes
343:     end

[Source]

     # File lib/sass/engine.rb, line 227
227:     def check_encoding!
228:       return if @checked_encoding
229:       @checked_encoding = true
230:       @template, @original_encoding = check_sass_encoding(@template) do |msg, line|
231:         raise Sass::SyntaxError.new(msg, :line => line)
232:       end
233:     end

[Source]

     # File lib/sass/engine.rb, line 400
400:     def check_for_no_children(node)
401:       return unless node.is_a?(Tree::RuleNode) && node.children.empty?
402:       Haml::Util.haml_warn("WARNING on line \#{node.line}\#{\" of \#{node.filename}\" if node.filename}:\nThis selector doesn't have any properties and will not be rendered.\n".strip)
403:     end

[Source]

     # File lib/sass/engine.rb, line 678
678:     def format_comment_text(text, silent)
679:       content = text.split("\n")
680: 
681:       if content.first && content.first.strip.empty?
682:         removed_first = true
683:         content.shift
684:       end
685: 
686:       return silent ? "//" : "/* */" if content.empty?
687:       content.last.gsub!(%r{ ?\*/ *$}, '')
688:       content.map! {|l| l.gsub!(/^\*( ?)/, '\1') || (l.empty? ? "" : " ") + l}
689:       content.first.gsub!(/^ /, '') unless removed_first
690:       if silent
691:         "//" + content.join("\n//")
692:       else
693:         # The #gsub fixes the case of a trailing */
694:         "/*" + content.join("\n *").gsub(/ \*\Z/, '') + " */"
695:       end
696:     end

[Source]

     # File lib/sass/engine.rb, line 505
505:     def parse_comment(line)
506:       if line[1] == CSS_COMMENT_CHAR || line[1] == SASS_COMMENT_CHAR
507:         silent = line[1] == SASS_COMMENT_CHAR
508:         Tree::CommentNode.new(
509:           format_comment_text(line[2..-1], silent),
510:           silent)
511:       else
512:         Tree::RuleNode.new(parse_interp(line))
513:       end
514:     end

[Source]

     # File lib/sass/engine.rb, line 516
516:     def parse_directive(parent, line, root)
517:       directive, whitespace, value = line.text[1..-1].split(/(\s+)/, 2)
518:       offset = directive.size + whitespace.size + 1 if whitespace
519: 
520:       # If value begins with url( or ",
521:       # it's a CSS @import rule and we don't want to touch it.
522:       if directive == "import"
523:         parse_import(line, value)
524:       elsif directive == "mixin"
525:         parse_mixin_definition(line)
526:       elsif directive == "include"
527:         parse_mixin_include(line, root)
528:       elsif directive == "for"
529:         parse_for(line, root, value)
530:       elsif directive == "else"
531:         parse_else(parent, line, value)
532:       elsif directive == "while"
533:         raise SyntaxError.new("Invalid while directive '@while': expected expression.") unless value
534:         Tree::WhileNode.new(parse_script(value, :offset => offset))
535:       elsif directive == "if"
536:         raise SyntaxError.new("Invalid if directive '@if': expected expression.") unless value
537:         Tree::IfNode.new(parse_script(value, :offset => offset))
538:       elsif directive == "debug"
539:         raise SyntaxError.new("Invalid debug directive '@debug': expected expression.") unless value
540:         raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath debug directives.",
541:           :line => @line + 1) unless line.children.empty?
542:         offset = line.offset + line.text.index(value).to_i
543:         Tree::DebugNode.new(parse_script(value, :offset => offset))
544:       elsif directive == "extend"
545:         raise SyntaxError.new("Invalid extend directive '@extend': expected expression.") unless value
546:         raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath extend directives.",
547:           :line => @line + 1) unless line.children.empty?
548:         offset = line.offset + line.text.index(value).to_i
549:         Tree::ExtendNode.new(parse_interp(value, offset))
550:       elsif directive == "warn"
551:         raise SyntaxError.new("Invalid warn directive '@warn': expected expression.") unless value
552:         raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath warn directives.",
553:           :line => @line + 1) unless line.children.empty?
554:         offset = line.offset + line.text.index(value).to_i
555:         Tree::WarnNode.new(parse_script(value, :offset => offset))
556:       elsif directive == "charset"
557:         name = value && value[/\A(["'])(.*)\1\Z/, 2] #"
558:         raise SyntaxError.new("Invalid charset directive '@charset': expected string.") unless name
559:         raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath charset directives.",
560:           :line => @line + 1) unless line.children.empty?
561:         Tree::CharsetNode.new(name)
562:       else
563:         Tree::DirectiveNode.new(line.text)
564:       end
565:     end

[Source]

     # File lib/sass/engine.rb, line 591
591:     def parse_else(parent, line, text)
592:       previous = parent.children.last
593:       raise SyntaxError.new("@else must come after @if.") unless previous.is_a?(Tree::IfNode)
594: 
595:       if text
596:         if text !~ /^if\s+(.+)/
597:           raise SyntaxError.new("Invalid else directive '@else #{text}': expected 'if <expr>'.")
598:         end
599:         expr = parse_script($1, :offset => line.offset + line.text.index($1))
600:       end
601: 
602:       node = Tree::IfNode.new(expr)
603:       append_children(node, line.children, false)
604:       previous.add_else node
605:       nil
606:     end

[Source]

     # File lib/sass/engine.rb, line 567
567:     def parse_for(line, root, text)
568:       var, from_expr, to_name, to_expr = text.scan(/^([^\s]+)\s+from\s+(.+)\s+(to|through)\s+(.+)$/).first
569: 
570:       if var.nil? # scan failed, try to figure out why for error message
571:         if text !~ /^[^\s]+/
572:           expected = "variable name"
573:         elsif text !~ /^[^\s]+\s+from\s+.+/
574:           expected = "'from <expr>'"
575:         else
576:           expected = "'to <expr>' or 'through <expr>'"
577:         end
578:         raise SyntaxError.new("Invalid for directive '@for #{text}': expected #{expected}.")
579:       end
580:       raise SyntaxError.new("Invalid variable \"#{var}\".") unless var =~ Script::VALIDATE
581:       if var.slice!(0) == ?!
582:         offset = line.offset + line.text.index("!" + var) + 1
583:         Script.var_warning(var, @line, offset, @options[:filename])
584:       end
585: 
586:       parsed_from = parse_script(from_expr, :offset => line.offset + line.text.index(from_expr))
587:       parsed_to = parse_script(to_expr, :offset => line.offset + line.text.index(to_expr))
588:       Tree::ForNode.new(var, parsed_from, parsed_to, to_name == 'to')
589:     end

[Source]

     # File lib/sass/engine.rb, line 608
608:     def parse_import(line, value)
609:       raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath import directives.",
610:         :line => @line + 1) unless line.children.empty?
611: 
612:       scanner = StringScanner.new(value)
613:       values = []
614: 
615:       loop do
616:         unless node = parse_import_arg(scanner)
617:           raise SyntaxError.new("Invalid @import: expected file to import, was #{scanner.rest.inspect}",
618:             :line => @line)
619:         end
620:         values << node
621:         break unless scanner.scan(/,\s*/)
622:       end
623: 
624:       return values
625:     end

[Source]

     # File lib/sass/engine.rb, line 627
627:     def parse_import_arg(scanner)
628:       return if scanner.eos?
629:       unless (str = scanner.scan(Sass::SCSS::RX::STRING)) ||
630:           (uri = scanner.scan(Sass::SCSS::RX::URI))
631:         return Tree::ImportNode.new(scanner.scan(/[^,]+/))
632:       end
633: 
634:       val = scanner[1] || scanner[2]
635:       scanner.scan(/\s*/)
636:       if media = scanner.scan(/[^,].*/)
637:         Tree::DirectiveNode.new("@import #{str || uri} #{media}")
638:       elsif uri
639:         Tree::DirectiveNode.new("@import #{uri}")
640:       elsif val =~ /^http:\/\//
641:         Tree::DirectiveNode.new("@import url(#{val})")
642:       else
643:         Tree::ImportNode.new(val)
644:       end
645:     end

[Source]

     # File lib/sass/engine.rb, line 698
698:     def parse_interp(text, offset = 0)
699:       self.class.parse_interp(text, @line, offset, :filename => @filename)
700:     end

[Source]

     # File lib/sass/engine.rb, line 409
409:     def parse_line(parent, line, root)
410:       case line.text[0]
411:       when PROPERTY_CHAR
412:         if line.text[1] == PROPERTY_CHAR ||
413:             (@options[:property_syntax] == :new &&
414:              line.text =~ PROPERTY_OLD && $3.empty?)
415:           # Support CSS3-style pseudo-elements,
416:           # which begin with ::,
417:           # as well as pseudo-classes
418:           # if we're using the new property syntax
419:           Tree::RuleNode.new(parse_interp(line.text))
420:         else
421:           name, eq, value = line.text.scan(PROPERTY_OLD)[0]
422:           raise SyntaxError.new("Invalid property: \"#{line.text}\".",
423:             :line => @line) if name.nil? || value.nil?
424:           parse_property(name, parse_interp(name), eq, value, :old, line)
425:         end
426:       when ?!, ?$
427:         parse_variable(line)
428:       when COMMENT_CHAR
429:         parse_comment(line.text)
430:       when DIRECTIVE_CHAR
431:         parse_directive(parent, line, root)
432:       when ESCAPE_CHAR
433:         Tree::RuleNode.new(parse_interp(line.text[1..-1]))
434:       when MIXIN_DEFINITION_CHAR
435:         parse_mixin_definition(line)
436:       when MIXIN_INCLUDE_CHAR
437:         if line.text[1].nil? || line.text[1] == ?\s
438:           Tree::RuleNode.new(parse_interp(line.text))
439:         else
440:           parse_mixin_include(line, root)
441:         end
442:       else
443:         parse_property_or_rule(line)
444:       end
445:     end

[Source]

     # File lib/sass/engine.rb, line 648
648:     def parse_mixin_definition(line)
649:       name, arg_string = line.text.scan(MIXIN_DEF_RE).first
650:       raise SyntaxError.new("Invalid mixin \"#{line.text[1..-1]}\".") if name.nil?
651: 
652:       offset = line.offset + line.text.size - arg_string.size
653:       args = Script::Parser.new(arg_string.strip, @line, offset, @options).
654:         parse_mixin_definition_arglist
655:       default_arg_found = false
656:       Tree::MixinDefNode.new(name, args)
657:     end

[Source]

     # File lib/sass/engine.rb, line 660
660:     def parse_mixin_include(line, root)
661:       name, arg_string = line.text.scan(MIXIN_INCLUDE_RE).first
662:       raise SyntaxError.new("Invalid mixin include \"#{line.text}\".") if name.nil?
663: 
664:       offset = line.offset + line.text.size - arg_string.size
665:       args = Script::Parser.new(arg_string.strip, @line, offset, @options).
666:         parse_mixin_include_arglist
667:       raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath mixin directives.",
668:         :line => @line + 1) unless line.children.empty?
669:       Tree::MixinNode.new(name, args)
670:     end

[Source]

     # File lib/sass/engine.rb, line 469
469:     def parse_property(name, parsed_name, eq, value, prop, line)
470:       if value.strip.empty?
471:         expr = Sass::Script::String.new("")
472:       else
473:         expr = parse_script(value, :offset => line.offset + line.text.index(value))
474: 
475:         if eq.strip[0] == SCRIPT_CHAR
476:           expr.context = :equals
477:           Script.equals_warning("properties", name,
478:             Sass::Tree::PropNode.val_to_sass(expr, @options), false,
479:             @line, line.offset + 1, @options[:filename])
480:         end
481:       end
482:       Tree::PropNode.new(parse_interp(name), expr, prop)
483:     end

[Source]

     # File lib/sass/engine.rb, line 447
447:     def parse_property_or_rule(line)
448:       scanner = StringScanner.new(line.text)
449:       hack_char = scanner.scan(/[:\*\.]|\#(?!\{)/)
450:       parser = Sass::SCSS::SassParser.new(scanner, @line)
451: 
452:       unless res = parser.parse_interp_ident
453:         return Tree::RuleNode.new(parse_interp(line.text))
454:       end
455:       res.unshift(hack_char) if hack_char
456:       if comment = scanner.scan(Sass::SCSS::RX::COMMENT)
457:         res << comment
458:       end
459: 
460:       name = line.text[0...scanner.pos]
461:       if scanner.scan(/\s*([:=])(?:\s|$)/)
462:         parse_property(name, res, scanner[1], scanner.rest, :new, line)
463:       else
464:         res.pop if comment
465:         Tree::RuleNode.new(res + parse_interp(scanner.rest))
466:       end
467:     end

[Source]

     # File lib/sass/engine.rb, line 672
672:     def parse_script(script, options = {})
673:       line = options[:line] || @line
674:       offset = options[:offset] || 0
675:       Script.parse(script, line, offset, @options)
676:     end

[Source]

     # File lib/sass/engine.rb, line 485
485:     def parse_variable(line)
486:       name, op, value, default = line.text.scan(Script::MATCH)[0]
487:       guarded = op =~ /^\|\|/
488:       raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath variable declarations.",
489:         :line => @line + 1) unless line.children.empty?
490:       raise SyntaxError.new("Invalid variable: \"#{line.text}\".",
491:         :line => @line) unless name && value
492:       Script.var_warning(name, @line, line.offset + 1, @options[:filename]) if line.text[0] == ?!
493: 
494:       expr = parse_script(value, :offset => line.offset + line.text.index(value))
495:       if op =~ /=$/
496:         expr.context = :equals
497:         type = guarded ? "variable defaults" : "variables"
498:         Script.equals_warning(type, "$#{name}", expr.to_sass,
499:           guarded, @line, line.offset + 1, @options[:filename])
500:       end
501: 
502:       Tree::VariableNode.new(name, expr, default || guarded)
503:     end

[Source]

     # File lib/sass/engine.rb, line 235
235:     def tabulate(string)
236:       tab_str = nil
237:       comment_tab_str = nil
238:       first = true
239:       lines = []
240:       string.gsub(/\r|\n|\r\n|\r\n/, "\n").scan(/^[^\n]*?$/).each_with_index do |line, index|
241:         index += (@options[:line] || 1)
242:         if line.strip.empty?
243:           lines.last.text << "\n" if lines.last && lines.last.comment?
244:           next
245:         end
246: 
247:         line_tab_str = line[/^\s*/]
248:         unless line_tab_str.empty?
249:           if tab_str.nil?
250:             comment_tab_str ||= line_tab_str
251:             next if try_comment(line, lines.last, "", comment_tab_str, index)
252:             comment_tab_str = nil
253:           end
254: 
255:           tab_str ||= line_tab_str
256: 
257:           raise SyntaxError.new("Indenting at the beginning of the document is illegal.",
258:             :line => index) if first
259: 
260:           raise SyntaxError.new("Indentation can't use both tabs and spaces.",
261:             :line => index) if tab_str.include?(?\s) && tab_str.include?(?\t)
262:         end
263:         first &&= !tab_str.nil?
264:         if tab_str.nil?
265:           lines << Line.new(line.strip, 0, index, 0, @options[:filename], [])
266:           next
267:         end
268: 
269:         comment_tab_str ||= line_tab_str
270:         if try_comment(line, lines.last, tab_str * lines.last.tabs, comment_tab_str, index)
271:           next
272:         else
273:           comment_tab_str = nil
274:         end
275: 
276:         line_tabs = line_tab_str.scan(tab_str).size
277:         if tab_str * line_tabs != line_tab_str
278:           message = "Inconsistent indentation: \#{Haml::Shared.human_indentation line_tab_str, true} used for indentation,\nbut the rest of the document was indented using \#{Haml::Shared.human_indentation tab_str}.\n".strip.gsub("\n", ' ')
279:           raise SyntaxError.new(message, :line => index)
280:         end
281: 
282:         lines << Line.new(line.strip, line_tabs, index, tab_str.size, @options[:filename], [])
283:       end
284:       lines
285:     end

[Source]

     # File lib/sass/engine.rb, line 309
309:     def tree(arr, i = 0)
310:       return [], i if arr[i].nil?
311: 
312:       base = arr[i].tabs
313:       nodes = []
314:       while (line = arr[i]) && line.tabs >= base
315:         if line.tabs > base
316:           raise SyntaxError.new("The line was indented #{line.tabs - base} levels deeper than the previous line.",
317:             :line => line.index) if line.tabs > base + 1
318: 
319:           nodes.last.children, i = tree(arr, i)
320:         else
321:           nodes << line
322:           i += 1
323:         end
324:       end
325:       return nodes, i
326:     end

[Source]

     # File lib/sass/engine.rb, line 291
291:     def try_comment(line, last, tab_str, comment_tab_str, index)
292:       return unless last && last.comment?
293:       # Nested comment stuff must be at least one whitespace char deeper
294:       # than the normal indentation
295:       return unless line =~ /^#{tab_str}\s/
296:       unless line =~ /^(?:#{comment_tab_str})(.*)$/
297:         raise SyntaxError.new("Inconsistent indentation:\nprevious line was indented by \#{Haml::Shared.human_indentation comment_tab_str},\nbut this line was indented by \#{Haml::Shared.human_indentation line[/^\\s*/]}.\n".strip.gsub("\n", " "), :line => index)
298:       end
299: 
300:       last.text << "\n" << $1
301:       true
302:     end

[Source]

     # File lib/sass/engine.rb, line 391
391:     def validate_and_append_child(parent, child, line, root)
392:       case child
393:       when Array
394:         child.each {|c| validate_and_append_child(parent, c, line, root)}
395:       when Tree::Node
396:         parent << child
397:       end
398:     end

[Validate]