Class: PageTemplate::Parser

Inherits:
Object
  • Object
show all
Includes:
NamespaceItem
Defined in:
lib/PageTemplate/parser.rb

Overview

The big ass parser that does all the dirty work of turning templates into compiled commands.

Parser.new() accepts a hash as an argument, and looks for these keys: (with defaults)

'namespace' => A namespace object. (A new namespace)
'glossary'  => A SyntaxGlossary class singleton. (DefaultGlossary)
'preprocessor' => The preprocessor. (DefaultPreprocessor)
'default_processor' => The processor. (:process)
'source' => The Source for templates. (FileSource)

Once the parser is created, it can compile and parse any number of templates.

It can be treated as a one-template item by using Parser#load(template), and calling Parser.output

To create separate generated templates from the same engine, use Parser#parse, or Parser#load. (It will still keep the most recent one it's #load'd, but that will not affect previously parsed or loaded)

Instance Attribute Summary collapse

Attributes included from NamespaceItem

#object, #parent

Class Method Summary collapse

Instance Method Summary collapse

Methods included from NamespaceItem

#clear, #delete, #get, #set, #true?

Constructor Details

#initialize(args = {}) ⇒ Parser

Parser.new() accepts a hash as an argument, and looks for these keys: (with defaults)

'namespace' => A namespace object. (A new namespace)
'glossary'  => A SyntaxGlossary object. (a dup of DEFAULTGLOSSARY)
'preprocessor' => The preprocessor. (DefaultPreprocessor)
'default_processor' => The processor. (:process)
'source' => The Source for templates. (FileSource)

528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
# File 'lib/PageTemplate/parser.rb', line 528

def initialize(args = {})
  @namespace    = self
  @@recent_parser = self
  @args         = args # For sub-commands
  @parent       = args['namespace'] || nil
  if @parent
    unless @parent.is_a? Namespace then
      @parent = Namespace.construct_from(args['namespace'])
    end
  end
  @glossary     = args['glossary'] || DefaultGlossary
  @preprocessor = args['preprocessor'] || DefaultPreprocessor
  @default_processor = args['default_processor'] || :unescaped
  @method_separators = args['method_separators'] || './'
  @source       = (args['source'] || FileSource).new(@args)
  @commands     = nil
end

Instance Attribute Details

#argsObject (readonly)

Returns the value of attribute args


513
514
515
# File 'lib/PageTemplate/parser.rb', line 513

def args
  @args
end

#commandsObject (readonly)

Returns the value of attribute commands


513
514
515
# File 'lib/PageTemplate/parser.rb', line 513

def commands
  @commands
end

#default_processorObject (readonly)

Returns the value of attribute default_processor


511
512
513
# File 'lib/PageTemplate/parser.rb', line 511

def default_processor
  @default_processor
end

#glossaryObject (readonly)

Returns the value of attribute glossary


512
513
514
# File 'lib/PageTemplate/parser.rb', line 512

def glossary
  @glossary
end

#method_separatorsObject (readonly)

Returns the value of attribute method_separators


513
514
515
# File 'lib/PageTemplate/parser.rb', line 513

def method_separators
  @method_separators
end

#namespaceObject (readonly)

Returns the value of attribute namespace


512
513
514
# File 'lib/PageTemplate/parser.rb', line 512

def namespace
  @namespace
end

#preprocessorObject (readonly)

Returns the value of attribute preprocessor


511
512
513
# File 'lib/PageTemplate/parser.rb', line 511

def preprocessor
  @preprocessor
end

#sourceObject (readonly)

Returns the value of attribute source


512
513
514
# File 'lib/PageTemplate/parser.rb', line 512

def source
  @source
end

Class Method Details

.recent_parserObject

This is corny, but recent_parser returns the most recently created Parser.


517
518
519
# File 'lib/PageTemplate/parser.rb', line 517

def Parser.recent_parser
  @@recent_parser
end

Instance Method Details

#clearCommandsObject

Not really of any point, but clears the saved commands.


628
629
630
# File 'lib/PageTemplate/parser.rb', line 628

def clearCommands
  @commands = nil
end

#compile(name) ⇒ Object

Load name from a template, but do not save it.


551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
# File 'lib/PageTemplate/parser.rb', line 551

def compile(name)
  body = @source.get(name)
  case
  when body.is_a?(Command)
    body
  when body
    cmds = parse(body)
    @source.cache(name,cmds) if @source.respond_to?(:cache)
    cmds
  else
    cmds = Template.new(self)
    cmds.add TextCommand.new("[ Template '#{name}' not found ]")
    cmds
  end
end

#load(name) ⇒ Object

Load name from a template, and save it to allow this parser to use it for output.


547
548
549
# File 'lib/PageTemplate/parser.rb', line 547

def load(name)
  @commands = compile(name)
end

#output(*args) ⇒ Object

If any commands are loaded and saved, return a string of it.


632
633
634
635
# File 'lib/PageTemplate/parser.rb', line 632

def output(*args)
  return '' unless @commands
  @commands.output(*args)
end

#parse(body) ⇒ Object

Compile a Template (BlockCommand) from a string. Does not save the commands.


568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
# File 'lib/PageTemplate/parser.rb', line 568

def parse(body)
  rx = @glossary.directive
  stack = [Template.new(self)]
  stack[0].parent = self
  last = stack.last
  modifier = nil
  closer = nil
  while (m = rx.match(body))
    pre = m.pre_match
    command = m[1..-1].compact.first.strip.gsub(/\s+/,' ')
    body = m.post_match
    
    # Convert all pre-text to a TextCommand
    if (pre && pre.length > 0)
      stack.last.add TextCommand.new(pre)
    end

    # If the command at the top of the stack is a 'Stacker',
    # Does this command modify it? If so, just skip back.
    next if modifier && @glossary.modifies?(modifier,last,command)

    # If it closes, we're done changing this. Pop it off the
    # Stack and add it to the one above it.
    if closer and @glossary.modifies?(closer,last,command)
      cmd = stack.pop
      last = stack.last
      last.add(cmd)
      modifier = last.class.modifier
      closer = last.class.closer
      next
    end

    # Create the command
    cmd = @glossary.lookup(command)
    
    # If it's a stacking command, push it on the stack
    if cmd.is_a?(StackableCommand)
      modifier = cmd.class.modifier
      closer   = cmd.class.closer
      stack.push cmd
      last = cmd
    else
      last.add cmd
    end
  end
  stack.last.add TextCommand.new(body) if body && body.length > 0
  if (stack.length > 1)
    raise ArgumentError, 'Mismatched command closures in template'
  end
  stack[0]
end

#parserObject

But redefine parser


623
624
625
# File 'lib/PageTemplate/parser.rb', line 623

def parser
  self
end