Class: Walrus::Compiler::Instance

Inherits:
Object
  • Object
show all
Defined in:
lib/walrus/compiler.rb

Overview

The public compiler class serves as the interface with the outside world. For thread-safety and concurrency, an inner, private Instance class is spawned in order to perform the actual compilation.

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Instance

Returns a new instance of Instance.



36
37
38
39
40
# File 'lib/walrus/compiler.rb', line 36

def initialize options
  @class_name     = (options[:class_name] || DEFAULT_CLASS).to_s
  @template_body  = []  # accumulate body items, joined at end of process
  @outside_body   = []  # accumulate outside-of-body items, joined at end
end

Instance Method Details

#compile(tree) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/walrus/compiler.rb', line 82

def compile(tree)
  inner, outer = compile_subtree(tree)
  @template_body.concat inner if inner
  @outside_body.concat outer if outer
  if @import_directive
    superclass_name = @import_directive.class_name
    require_line    = "require 'walrus/document'\n" +
                      @import_directive.require_line
  elsif @extends_directive
    superclass_name = @extends_directive.class_name
    require_line    = "require 'walrus/document'\n" +
                      @extends_directive.require_line
    @template_body.unshift BODY_INDENT +
      "super # (invoked automatically due to Extends directive)\n"
  else
    superclass_name = 'Document'
    require_line    = "require 'walrus/document'"
  end

  <<-RETURN
\#!/usr/bin/env ruby
\# Generated by Walrus <http://walrus.wincent.com/>

begin
  require 'rubygems'
rescue LoadError
  # installing Walrus via RubyGems is recommended
  # otherwise Walrus must be installed in the RUBYLIB load path
end

#{require_line}

module Walrus
  class Grammar
    class #{@class_name} < #{superclass_name}
def template_body
#{@template_body.join}
end

#{@outside_body.join}
if __FILE__ == $0   # if run from the command line
  new.run           # same as "walrus run __FILE__"
end
    end \# #{@class_name}
  end \# Grammar
end \# Walrus
  RETURN
end

#compile_subtree(subtree) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/walrus/compiler.rb', line 42

def compile_subtree(subtree)
  template_body   = [] # local variable
  outside_body    = [] # local variable
  subtree = [subtree] unless subtree.respond_to? :each
  options = { :compiler_instance => self } # reset
  subtree.each do |element|
    if element.kind_of? Walrus::Grammar::DefDirective or
       element.kind_of? Walrus::Grammar::IncludeDirective
      # def/block and include directives may return two items
      inner, outer = element.compile(options)
      outer.each { |line| outside_body << OUTSIDE_INDENT + line } if outer
      inner.each { |line| template_body << BODY_INDENT + line } if inner
    elsif element.instance_of? Walrus::Grammar::ExtendsDirective
      # defines superclass and automatically invoke #super (super) at the
      # head of the template_body
      raise CompileError.new('#extends may be used only once per template') if @extends_directive
      raise CompileError.new('illegal #extends (#import already used in this template)') if @import_directive
      @extends_directive = element.compile(options)
    elsif element.instance_of? Walrus::Grammar::ImportDirective
      # defines superclass with no automatic invocation of #super on the
      # template_body
      raise CompileError.new('#import may be used only once per template') if @import_directive
      raise CompileError.new('illegal #import (#extends already used in this template)') if @extends_directive
      @import_directive = element.compile(options)
    elsif element.kind_of? Walrus::Grammar::Comment and
          element.column_start == 0
      # special case if comment is only thing on input line
      template_body << BODY_INDENT + element.compile(options)
      options[:slurping] = true
      next
    else  # everything else gets added to the template_body
      element.compile(options).each do |line|
        template_body << BODY_INDENT + line # indent by 6 spaces
      end
    end
    options = { :compiler_instance => self } # reset
  end
  [template_body, outside_body]
end