Skip to content

Commit

Permalink
clean up, start structuring with temple assets.
Browse files Browse the repository at this point in the history
  • Loading branch information
apotonick committed Jul 31, 2016
1 parent 76e1bff commit 75abb1d
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 317 deletions.
2 changes: 2 additions & 0 deletions erbse.gemspec
Expand Up @@ -19,6 +19,8 @@ Gem::Specification.new do |spec|
spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
spec.require_paths = ["lib"]

spec.add_dependency "temple"

spec.add_development_dependency "rake"
spec.add_development_dependency "minitest"
end
79 changes: 34 additions & 45 deletions lib/erbse.rb
@@ -1,49 +1,38 @@
##
## an implementation of eRuby
##
## ex.
## input = <<'END'
## <ul>
## <% for item in @list %>
## <li><%= item %>
## <%== item %></li>
## <% end %>
## </ul>
## END
## list = ['<aaa>', 'b&b', '"ccc"']
## eruby = Erubis::Eruby.new(input)
## puts "--- code ---"
## puts eruby.src
## puts "--- result ---"
## context = Erubis::Context.new() # or new(:list=>list)
## context[:list] = list
## puts eruby.evaluate(context)
##
## result:
## --- source ---
## _buf = ''; _buf << '<ul>
## '; for item in @list
## _buf << ' <li>'; _buf << ( item ).to_s; _buf << '
## '; _buf << ' '; _buf << Erubis::XmlHelper.escape_xml( item ); _buf << '</li>
## '; end
## _buf << '</ul>
## ';
## _buf.to_s
## --- result ---
## <ul>
## <li><aaa>
## &lt;aaa&gt;</li>
## <li>b&b
## b&amp;b</li>
## <li>"ccc"
## &quot;ccc&quot;</li>
## </ul>
##

require "temple"
require "erbse/parser"
require "erbse/template"
# require "erbse/eruby"

module Erbse
class BlockFilter < Temple::Filter
# Highly inspired by https://github.com/slim-template/slim/blob/master/lib/slim/controls.rb#on_slim_output
def on_erb_block(outter_i, inner_i, code, content_ast)
# this is for <%= do %>
outter_i = unique_name
inner_i = unique_name

# this still needs the Temple::Filters::ControlFlow run-through.
[:multi,
[:block, "#{outter_i} = #{code}",
[:capture, inner_i, compile(content_ast)] # compile() is recursion on nested block content.
],
[:dynamic, outter_i] # return the outter buffer. # DISCUSS: why do we need that, again?
]
end
end

class Engine < Temple::Engine
use Parser
use BlockFilter

# filter :MultiFlattener
# filter :StaticMerger
# filter :DynamicInliner
filter :ControlFlow

# Finally the generator
generator :ArrayBuffer
end

end

require "erbse/parser"
require "erbse/template"
require "erbse/eruby"
173 changes: 57 additions & 116 deletions lib/erbse/parser.rb
@@ -1,33 +1,70 @@
module Erbse
# Convert input ERB string into Ruby.
class Parser
def initialize(properties={}, generator)
init_converter!(properties)
@generator = generator
def self.pattern_regexp(pattern)
@prefix, @postfix = pattern.split() # '<% %>' => '<%', '%>'
return /#{@prefix}(=+|-|\#|%)?(.*?)([-=])?#{@postfix}([ \t]*\r?\n)?/m
end

def call(input)
codebuf = "" # or []
@preamble.nil? ? generator.add_preamble(codebuf, "ob_0") : (@preamble && (codebuf << @preamble))
convert_input(codebuf, input)
@postamble.nil? ? generator.add_postamble(codebuf, "ob_0") : (@postamble && (codebuf << @postamble))
return codebuf # or codebuf.join()
DEFAULT_REGEXP = pattern_regexp('<% %>')
BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/

def initialize(*)
end

private
attr_accessor :preamble, :postamble, :escape
def call(str)
pos = 0
is_bol = true # is beginning of line

attr_reader :generator
buffers = []
result = [:multi]
buffers << result

def init_converter!(properties)
@preamble = properties[:preamble]
@postamble = properties[:postamble]
@escape = properties[:escape]
index = 0

str.scan(DEFAULT_REGEXP) do |indicator, code, tailch, rspace|
match = Regexp.last_match()
len = match.begin(0) - pos
text = str[pos, len]
pos = match.end(0)
ch = indicator ? indicator[0] : nil
lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
is_bol = rspace ? true : false

result = buffers.last
# puts "parsing #{code} to #{result.inspect}"

if ch == ?= # <%= %>
if code =~ BLOCK_EXPR
buffers.last << [:erb, :block, index += 1, index += 1, code, block = [:multi]]
buffers << block
else
buffers.last << [:code, code]
end
end

if code =~ / end /
block = buffers.pop
end


# generator.add_expr_literal(src, code, indicator, "ob_#{top_buffer}", buffers)

# elsif ch == ?\# # <%# %>
# n = code.count("\n") + (rspace ? 1 : 0)
# if @trim && lspace && rspace
# generator.add_stmt(src, "\n" * n, "ob_#{buffers.size}")
# else
# generator.add_stmt(src, "\n" * n, "ob_#{buffers.size}")
# end
# else

# # <% %>

end

buffers.last
end

##
## detect spaces at beginning of line
##
def detect_spaces_at_bol(text, is_bol)
lspace = nil
if text.empty?
Expand Down Expand Up @@ -55,100 +92,4 @@ def detect_spaces_at_bol(text, is_bol)
return lspace
end
end


module Basic
end


##
## basic converter which supports '<% ... %>' notation.
##
class Basic::Parser < Parser
private

attr_accessor :pattern, :trim

def init_converter!(properties={})
super(properties)
@pattern = properties[:pattern]
@trim = properties[:trim] != false
end



## return regexp of pattern to parse eRuby script
def self.pattern_regexp(pattern)
@prefix, @postfix = pattern.split() # '<% %>' => '<%', '%>'
return /#{@prefix}(=+|-|\#|%)?(.*?)([-=])?#{@postfix}([ \t]*\r?\n)?/m
end

DEFAULT_REGEXP = pattern_regexp('<% %>')

def convert_input(src, input)
pat = @pattern
regexp = pat.nil? || pat == '<% %>' ? DEFAULT_REGEXP : pattern_regexp(pat)
pos = 0
is_bol = true # is beginning of line

buffers = []

input.scan(regexp) do |indicator, code, tailch, rspace|
match = Regexp.last_match()
len = match.begin(0) - pos
text = input[pos, len]
pos = match.end(0)
ch = indicator ? indicator[0] : nil
lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
is_bol = rspace ? true : false
generator.add_text(src, text, "ob_#{buffers.size}") if text && !text.empty?
## * when '<%= %>', do nothing
## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
if ch == ?= # <%= %>

puts "block begin #{buffers.size}"

rspace = nil if tailch && !tailch.empty?
generator.add_text(src, lspace, "ob_#{buffers.size}") if lspace

top_buffer = buffers.size
generator.add_expr_literal(src, code, indicator, "ob_#{top_buffer}", buffers)

generator.add_text(src, rspace, "ob_#{buffers.size}") if rspace
elsif ch == ?\# # <%# %>
n = code.count("\n") + (rspace ? 1 : 0)
if @trim && lspace && rspace
generator.add_stmt(src, "\n" * n, "ob_#{buffers.size}")
else
generator.add_text(src, lspace, "ob_#{buffers.size}") if lspace
generator.add_stmt(src, "\n" * n, "ob_#{buffers.size}")
generator.add_text(src, rspace, "ob_#{buffers.size}") if rspace
end
else # <% %>
if @trim && lspace && rspace

generator.add_stmt(src, "#{lspace}#{code}#{rspace}", "ob_#{buffers.size}")
else
generator.add_text(src, lspace, "ob_#{buffers.size}") if lspace
if code == " end "
# src << "ob_#{buffers.size - 2} << ob_#{buffers.size-1};"
src << "ob_#{buffers.size };"
buffers.pop

end
generator.add_stmt(src, code, "ob_#{buffers.size}")
generator.add_text(src, rspace, "ob_#{buffers.size}") if rspace
end

puts "@@@@@ #{code.inspect}"


puts "block begin #{code} #{buffers.size}"
end
end
#rest = $' || input # ruby1.8
rest = pos == 0 ? input : input[pos..-1] # ruby1.9
generator.add_text(src, rest, "ob_#{buffers.size}")
end
end
end

0 comments on commit 75abb1d

Please sign in to comment.