Class: Flott::Parser

Inherits:
Object
  • Object
show all
Includes:
FilenameMixin
Defined in:
lib/flott.rb

Overview

The Flott::Parser class creates parser objects, that can be used to compile Flott template documents or files to Flott::Template instances.

Defined Under Namespace

Classes: Mode, RubyMode, State, TextMode

Constant Summary collapse

ESCOPEN =

Regexp matching an escaped open square bracket like ‘[’.

/\\\[/
INCOPEN =
^filename
/\[\^\s*([^\]]+?)\s*(-)?\]/
PRIOPEN =
=“foo<bar”

“foo&lt;bar”

/\[=\s*/
RAWOPEN =
!“foo<bar”

“foo<bar”

/\[!\s*/
COMOPEN =
#comment
/\[#\s*/
MINPRIOPEN =

Open succeded by minus deletes previous whitespaces until start of line.

/\[-=/
MINRAWOPEN =

Open succeded by minus deletes previous whitespaces until start of line.

/\[-!/
MINCOMOPEN =

Open succeded by minus deletes previous whitespaces until start of line.

/\[-#/
MINOPEN =

Open succeded by minus deletes previous whitespaces until start of line.

/\[-/
OPEN =

Regexp matching an open square bracket like ‘[’.

/\[/
MINCLOSE =

Close preceded by minus deletes next CRLF.

/-\]/
CLOSE =

Regexp matching an open square bracket like ‘]’.

/\]/
ESCCLOSE =

Regexp matching an escaped closed square bracket like ‘]’.

/\\\]/
TEXT =

Regexp matching general text, that doesn’t need special handling.

/([^-\\\]\[\{\}]+|-(?!\]))/
ESC =

Regexp matching the escape character ‘'.

/\\/
ESC_CLOSURE =

Regexp matching the escape character at least once.

/\\(\\*)/
CURLY =

Regexp matching curly brackets ‘or ‘’.

/[{}]/
CURLYOPEN =

Regexp matching open curly bracket like ‘{’.

/\{/
CURLYCLOSE =

Regexp matching open curly bracket like ‘}’.

/\}/
ESCAPE_MAP =

:stopdoc:

Hash.new { |h, c| raise "unknown character '#{c}'" }
HTML_ESCAPE =

This Proc object escapes string, by substituting &<>“‘ with their respective html entities, and returns the result.

lambda do |string|
  if string.respond_to?(:to_str)
    string.to_str.gsub(/[&<>"']/) { |c| ESCAPE_MAP[c[0]] }
  else
    string = string.to_s
    string.gsub!(/[&<>"']/) { |c| ESCAPE_MAP[c[0]] }
    string
  end
end

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from FilenameMixin

#interpret_filename_as_page

Constructor Details

#initialize(source, workdir = nil, rootdir = nil, filename = nil) ⇒ Parser

Creates a Parser object. workdir is the directory, on which relative template inclusions are based. rootdir is the directory. On which absolute template inclusions (starting with ‘/’) are based. filename is the filename of this template (if any), which is important to track changes in the template file to trigger a reloading.



679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
# File 'lib/flott.rb', line 679

def initialize(source, workdir = nil, rootdir = nil, filename = nil)
  if workdir
    check_secure_path(workdir)
    @workdir = File.expand_path(workdir)
  else
    @workdir = Dir.pwd
  end
  if rootdir
    check_secure_path(rootdir)
    @rootdir = File.expand_path(rootdir)
  else
    @rootdir = @workdir
  end
  sub_path?(@workdir, @rootdir) or
    raise SecurityViolation, "#{@workdir} isn't a sub path of '#{@rootdir}'"
  if filename
    check_secure_path(filename)
    @filename  = File.expand_path(filename)
    sub_path?(@filename, @workdir) or
      raise SecurityViolation, "#{@filename} isn't a sub path of '#{@workdir}"
  end
  @ruby = RubyMode.new(self)
  @text = TextMode.new(self)
  @current_mode = @text
  @scanner = StringScanner.new(source)
end

Instance Attribute Details

#parentObject

Returns nil if this is the root parser, or a reference to the parent parser of this parser.



726
727
728
# File 'lib/flott.rb', line 726

def parent
  @parent
end

#rootdirObject (readonly)

Compute the rootdir of this parser (these parsers). Cache the result and return it.



730
731
732
# File 'lib/flott.rb', line 730

def rootdir
  @rootdir
end

#scannerObject (readonly)

The StringScanner instance of this Parser object.



716
717
718
# File 'lib/flott.rb', line 716

def scanner
  @scanner
end

#workdirObject

Returns the current work directory of this parser.



733
734
735
# File 'lib/flott.rb', line 733

def workdir
  @workdir
end

Class Method Details

.from_filename(filename) ⇒ Object

Creates a Parser object from filename, the workdir and _rootdir attributes are set to the directory the file is located in.



708
709
710
711
712
713
# File 'lib/flott.rb', line 708

def self.from_filename(filename)
  filename  = File.expand_path(filename)
  workdir   = File.dirname(filename)
  source    = File.read(filename)
  new(source, workdir, workdir, filename)
end

Instance Method Details

#compileObject

Compiles the template source and returns a Proc object to be executed later. This method raises a ParserError exception if source is not _Parser#wellformed?_.



748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
# File 'lib/flott.rb', line 748

def compile
  @state = State.new
  state.compiled << [
    "::Flott::Template.new \{ |__env__| __env__.instance_eval %q{\n",
    "@__rootdir__ = '#{rootdir}'\n",
  ]
  state.pathes << @filename if defined?(@filename)
  compile_inner
  state.compiled << "\n}\n}"
  source = state.compiled_string
  template = eval(source, nil, '(flott)')
  template.pathes = state.pathes
  template.source = source
  template
rescue SyntaxError => e
  raise EvalError.wrap(e)
end

#evaluate(env = Environment.new, &block) ⇒ Object

First compiles the source template and evaluates it in the environment env. If no environment is given, a newly created environment is used.



977
978
979
980
981
# File 'lib/flott.rb', line 977

def evaluate(env = Environment.new, &block)
  env.instance_eval(&block) if block
  compile.evaluate(env)
  self
end

#fork(source, workdir, rootdir, filename) ⇒ Object

Fork another Parser to handle an included template.



781
782
783
784
785
# File 'lib/flott.rb', line 781

def fork(source, workdir, rootdir, filename)
  parser        = self.class.new(source, workdir, rootdir, filename)
  parser.parent = self
  parser.compile_inner(@workdir != workdir)
end

#goto_ruby_modeObject

Change parsing mode to RubyMode.



741
742
743
# File 'lib/flott.rb', line 741

def goto_ruby_mode
  @current_mode = @ruby
end

#goto_text_modeObject

Change parsing mode to TextMode.



736
737
738
# File 'lib/flott.rb', line 736

def goto_text_mode
  @current_mode = @text
end

#include_template(filename) ⇒ Object

Include the template file with filename at the current place.



767
768
769
770
771
772
773
774
775
776
777
778
# File 'lib/flott.rb', line 767

def include_template(filename)
  filename = interpret_filename(filename)
  if File.readable?(filename)
    state.text2compiled
    state.pathes << filename
    source  = File.read(filename)
    workdir = File.dirname(filename)
    fork(source, workdir, rootdir, filename)
  else
    raise CompileError, "Cannot open #{filename} for inclusion!"
  end
end

#stateObject

Returns the shared state between all parsers that are parsing the current template and the included templates.



720
721
722
# File 'lib/flott.rb', line 720

def state
  @state ||= parent.state
end