Skip to content

Instantly share code, notes, and snippets.

@takuma-saito
Created May 2, 2020 09:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save takuma-saito/00b857c47fed16b278d7be1aae814c97 to your computer and use it in GitHub Desktop.
Save takuma-saito/00b857c47fed16b278d7be1aae814c97 to your computer and use it in GitHub Desktop.
mini_erb.rb
require 'strscan'
BEGIN_TAGS = %w(<%= <%# <%)
END_TAGS = %w(%>)
class MiniErb
def scan(content)
scanner = ::StringScanner.new(content)
state = :text
until scanner.eos?
case state
when :text
scanner.scan(/(.*?)?(#{BEGIN_TAGS.join("|")}|\z)/m)
if scanner[2].nil?
yield(scanner[1], state)
else
yield(scanner[1], state)
state = :begin
yield(scanner[2], state)
state = :code
end
when :code
scanner.scan(/(.*?)(#{END_TAGS.join("|")}|\z)/m)
if scanner[2].nil?
yield(scanner[1], state)
else
yield(scanner[1], state)
state = :end
yield(scanner[2], state)
state = :text
end
end
end
end
def compile(content, bind = binding)
src =
self
.enum_for(:scan, content)
.each_with_object({curr: '', text: '', tag: nil}) do |values, memo|
token, state = values
case state
when :text
memo[:text] += %Q(print "#{token.gsub('"', '\\"')}";)
when :begin
memo[:curr] = ''
memo[:tag] = token
when :end
add_code(token, memo)
when :code
memo[:curr] += token
end
end
# puts src[:text]
eval(src[:text], bind, __FILE__, __LINE__)
end
def add_code(token, memo)
case memo[:tag]
when '<%'
memo[:text] += %Q( #{memo[:curr]}; )
when '<%='
memo[:text] += %Q( print #{memo[:curr]}; )
when '<%#'
# skip
else
fail
end
memo[:curr] = ''
end
end
puts MiniErb.new.compile("#{<<-BEGIN}")
<html>
<body>
<p><%= 'hoge' %></p>
<div class="main">
<% ['a', 'b', 'c'].each do |val| %>
<div class="sub"><%= val %></div>
<% end %>
</div>
</body>
</html>
BEGIN
hoge = 'fuga'
puts MiniErb.new.compile("#{<<-BEGIN}", binding)
<%= 'ok' %>
<%= hoge %>
<body><% (0..10).each do |i| %><p><%= i %></p><% end %></body>
<%# comment_out %>
BEGIN
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment