judofyr/temple

Interfacing with parser generators

Closed this issue · 7 comments

There are parser generators (Parslet, Citrus, Treetop) which could be used to create template language parsers. Parslet generates a AST consisting of hashes. It would be nice to have an AST consisting of S-Expressions which could be processed by Temple then.

Parslet/ERB-Example:

require 'parslet'
require 'temple'

# Temple/Parslet-Interfacing
module Temple
  module Parslet
    class Parser < ::Parslet::Parser
      alias call parse
      def initialize(options); super(); end
    end

    class Transform < ::Parslet::Transform
      alias call apply
      def initialize(options); super(); end
    end
  end
end

class ErbParser < Temple::Parslet::Parser
  rule(:ruby) { (str('%>').absent? >> any).repeat.as(:ruby) }

  rule(:expression) { (str('=') >> ruby).as(:expression) }
  rule(:comment) { (str('#') >> ruby).as(:comment) }
  rule(:code) { ruby.as(:code) }
  rule(:erb) { expression | comment | code }

  rule(:erb_with_tags) { str('<%') >> erb >> str('%>') }
  rule(:text) { (str('<%').absent? >> any).repeat(1) }

  rule(:text_with_ruby) { (text.as(:text) | erb_with_tags).repeat.as(:text) }
  root(:text_with_ruby)
end

class ErbTransform < Temple::Parslet::Transform
  rule(:code => { :ruby => simple(:ruby) }) { [:code, ruby.str] }
  rule(:expression => { :ruby => simple(:ruby) }) { [:dynamic, ruby.str] }
  rule(:comment => { :ruby => simple(:ruby) }) { [:multi] }

  rule(:text => simple(:text)) { [:static, text.str] }
  rule(:text => subtree(:texts)) { [:multi, *texts] }
end

class ErbEngine < Temple::Engine
  use ErbParser
  use ErbTransform
  filter :MultiFlattener
  filter :DynamicInliner
  generator :ArrayBuffer
end

ErbTemplate = Temple::Templates::Tilt(ErbEngine)

puts ErbTemplate.new {
%{The <% a = 2 %>not printed result of "a = 2".
The <%# a = 1 %>not printed non-evaluated comment "a = 1", see the value of a below.
The <%= 'nicely' %> printed result.
The <% b = 3 %>value of a is <%= a %>, and b is <%= b %>.
}}.render

+1
I guess the most interseting part here is the Transformer.

What is wrong with writing exactly that code?

@kschiess: What do you mean? Essentially there is nothing wrong! I just wanted to show in this example that it is very easy to combine your Parslet with Temple to get a fully-featured optimized template engine. This is a very good thing for prototyping. The parser is also very extensible and readable through its descriptive nature.

To be correct, there is a problem with the line numbers. Parslet uses those Slices where as in Temple we use the S-Expression [:newline] which is not generated in this example.

I was trying to understand the feature request. If the example works, what is the request?

This is not a feature request. I am collecting ideas in which direction temple should be developed as a template engine framework. Temple already contains an example erb parser (https://raw.github.com/judofyr/temple/master/lib/temple/erb/parser.rb) derived from erubis.

Ah, I see.