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.



28
29
30
31
32
# File 'lib/walrus/compiler.rb', line 28

def initialize(options)        
  @class_name     = (options[:class_name] || DEFAULT_CLASS).to_s
  @template_body  = []  # will accumulate items for body, and joins them at the end of processing
  @outside_body   = []  # will accumulate items for outside of body, and joins them at the end of processing
end

Instance Method Details

#compile(tree) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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
# File 'lib/walrus/compiler.rb', line 65

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 WalrusGrammar

    class #{@class_name} < #{superclass_name}

def template_body

#{@template_body.join}
end

#{@outside_body.join}    
if __FILE__ == $0   # when run from the command line the default action is to call 'run'
  new.run
end

    end \# #{@class_name}

  end \# WalrusGrammar

end \# Walrus

  RETURN
  
end

#compile_subtree(subtree) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/walrus/compiler.rb', line 34

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|          
    # def/block and include directives may return two items
    if element.kind_of? WalrusGrammar::DefDirective or element.kind_of? WalrusGrammar::IncludeDirective
      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? WalrusGrammar::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') unless @extends_directive.nil?
      raise CompileError.new('illegal #extends (#import already used in this template)') unless @import_directive.nil?
      @extends_directive = element.compile(options)
    elsif element.instance_of? WalrusGrammar::ImportDirective   # defines superclass with no automatic invocation of #super on the template_body
      raise CompileError.new('#import may be used only once per template') unless @import_directive.nil?
      raise CompileError.new('illegal #import (#extends already used in this template)') unless @extends_directive.nil?
      @import_directive = element.compile(options)
    elsif element.kind_of? WalrusGrammar::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 { |line| template_body << BODY_INDENT + line } # indent by 6 spaces
    end
    options = { :compiler_instance => self } # reset
  end
  [template_body, outside_body]
end