diff options
author | makoto kuwata <kwa@kuwata-lab.com> | 2006-04-29 13:43:58 +0000 |
---|---|---|
committer | makoto kuwata <kwa@kuwata-lab.com> | 2006-04-29 13:43:58 +0000 |
commit | 23c96d3dcd301159dca6e60e561ab4b27e19bd58 (patch) | |
tree | d88c50b309387f52ab9afd6fc9038f53bcdb08ec | |
parent | 1a3ae7bbb18495c0d58d4c5a79de88976e086ea7 (diff) | |
download | erubis-23c96d3dcd301159dca6e60e561ab4b27e19bd58.tar.gz |
- [change] Eruby adopt ArrayBufferEnhancer as default
- [enhance] new module BiPatternEnhancer [experimental]
- [enhance] new module SimplifiedEnhancer
- [enhance] new module StringBufferEnhancer
- [enhance] new module PrintStatementEnhancer
- [enhance] new module PercentLineEnhancer
- [enhance] new module HeaderFooterEnhancer [experimental]
- [enhance] new class OutputSimplifiedEruby
- [enhance] Engine.supported_properties() added
- [enhance] print show_properties() when '-h' is specified
- [enhance] add Eperl class (engine/perl.rb)
- [enhance] add examples
- [change] class Eruby includes ArrayBufferEnhancer
- [change] EscapeEnhancer now overrides add_expr()
- [change] module PrintEnhancer is renamed to PrintAvailableEnhancer
- [change] Ejava doesn't out 'StringBuffer _buf' nor 'return _buf.toString();'
- [change] subclasses of Eruby are moved to new file 'enhanced.rb'
30 files changed, 2496 insertions, 916 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt index c11eb02..cacaa9b 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -2,6 +2,25 @@ .?lastupdate: $Date$ .?version: $Rev$ +.: Rev.13 (2006-04-29) + .- [change] Eruby adopt ArrayBufferEnhancer as default + .- [enhance] new module BiPatternEnhancer [experimental] + .- [enhance] new module SimplifiedEnhancer + .- [enhance] new module StringBufferEnhancer + .- [enhance] new module PrintStatementEnhancer + .- [enhance] new module PercentLineEnhancer + .- [enhance] new module HeaderFooterEnhancer [experimental] + .- [enhance] new class OutputSimplifiedEruby + .- [enhance] Engine.supported_properties() added + .- [enhance] print show_properties() when '-h' is specified + .- [enhance] add Eperl class (engine/perl.rb) + .- [enhance] add examples + .- [change] class Eruby includes ArrayBufferEnhancer + .- [change] EscapeEnhancer now overrides add_expr() + .- [change] module PrintEnhancer is renamed to PrintAvailableEnhancer + .- [change] Ejava doesn't out 'StringBuffer _buf' nor 'return _buf.toString();' + .- [change] subclasses of Eruby are moved to new file 'enhanced.rb' + .: Rev.12 (2006-04-26) .- [enhance] PHP, C, Java, and Scheme support .- [enhance] new class Engine is splitted from Eruby diff --git a/Rookbook.yaml b/Rookbook.yaml index 4567480..011ecf1 100644 --- a/Rookbook.yaml +++ b/Rookbook.yaml @@ -101,8 +101,8 @@ recipes: mkdir_p dir # store 'lib/**/*', 'bin/*', 'test/**/*', $text_files, dir - #chdir 'examples' do cmd 'rook :clean' end - #store 'examples/**/*', dir + chdir 'examples' do sys 'make clean' end + store 'examples/**/*', dir store '$(apidocdir)/**/*', dir mkdir_p "#{dir}/doc" cp_r $doc_files, "#{dir}/doc" @@ -116,3 +116,17 @@ recipes: # chmod 0644, "#{dir}/**/*", :filetype=>'file' chmod 0755, "#{dir}/{bin,contrib}/*", :filetype=>'file' + + - product: :duplicate + method: | + files = [] + files += Dir.glob('lib/**/*.rb') + files += Dir.glob('benchmark/erubybench.{rb,rhtml,yaml}') + archive = "#{@product}.tar.gz" + tar_czf archive, files + dir = '/Volumes/WORKGROUP;DENEB/src/erubis/trunk' + cp archive, dir + chdir dir do + tar_xzf archive + end + diff --git a/benchmark/erubybench.rb b/benchmark/erubybench.rb index e835132..bb6ec7c 100644 --- a/benchmark/erubybench.rb +++ b/benchmark/erubybench.rb @@ -7,13 +7,13 @@ require 'eruby' require 'erb' require 'erubis' +require 'erubis/engine/enhanced' require 'erubis/engine/optimized' ## default values -base = __FILE__.sub(/\.rb$/, '') -filename = base + '.rhtml' -datafile = base + '.yaml' +filename = 'erubybench.rhtml' +datafile = 'erubybench.yaml' n = 1000 @@ -21,7 +21,7 @@ n = 1000 def usage(n, filename, datafile) s = "Usage: ruby #{$0} [-h] [-n N] [-f file] [-d file] [testname ...]\n" s << " -h : help\n" - s << " -n N : number of repeat (default #{n})\n" + s << " -n N : number of times to loop (default #{n})\n" s << " -f file : eruby filename (default '#{filename}')\n" s << " -d file : data filename (default '#{datafile}')\n" return s @@ -40,7 +40,7 @@ while !ARGV.empty? && ARGV[0][0] == ?- when '-f' ; filename = ARGV.shift when '-d' ; datafile = ARGV.shift when '-h', '--help' ; flag_help = true - when '-A' ; flag_all = true + when '-A' ; test_all = true when '-C' ; compiler_name = ARGV.shift else ; raise "#{opt}: invalid option." end @@ -75,7 +75,8 @@ $devnull = File.open("/dev/null", 'w') module Erubis class Eruby2 < Eruby def finalize_src(src) - src << "\nprint _out\n" + #src << "\nprint _out.join; nil\n" + src << "\n_out.join; ''\n" end end end @@ -99,7 +100,7 @@ testdefs_str = <<END # print eruby.result(binding()) compile: | ERB.new(str).src - return: str + return: str - name: ErubisEruby class: Erubis::Eruby @@ -131,6 +132,33 @@ testdefs_str = <<END return: str skip: yes +#- name: ErubisArrayBuffer +# class: Erubis::ArrayBufferEruby +# code: | +# Erubis::ArrayBufferEruby.new(File.read(filename)).result(binding()) +# compile: | +# Erubis::ArrayBufferEruby.new(str).src +# return: str +# skip: no + +- name: ErubisStringBuffer + class: Erubis::StringBufferEruby + code: | + Erubis::StringBufferEruby.new(File.read(filename)).result(binding()) + compile: | + Erubis::StringBufferEruby.new(str).src + return: str + skip: no + +- name: ErubisSimplified + class: Erubis::SimplifiedEruby + code: | + Erubis::SimplifiedEruby.new(File.read(filename)).result(binding()) + compile: | + Erubis::SimplifiedEruby.new(str).src + return: str + skip: no + - name: ErubisStdout class: Erubis::StdoutEruby code: | @@ -138,47 +166,47 @@ testdefs_str = <<END compile: | Erubis::StdoutEruby.new(str).src return: null - skip: yes + skip: no -- name: ErubisArrayBuffer - class: Erubis::ArrayBufferEruby +- name: ErubisStdoutSimplified + class: Erubis::StdoutSimplifiedEruby code: | - Erubis::ArrayBufferEruby.new(File.read(filename)).result(binding()) + Erubis::StdoutSimplifiedEruby.new(File.read(filename)).result(binding()) compile: | - Erubis::ArrayBufferEruby.new(str).src + Erubis::StdoutSimplifiedEruby.new(str).src return: str - skip: yes + skip: no -- name: load - class: load - code: | - load($load_filename) - compile: null - return: null - skip: yes +#- name: load +# class: load +# code: | +# load($load_filename) +# compile: null +# return: null +# skip: yes END testdefs = YAML.load(testdefs_str) -## create file for load -if testdefs.find { |h| h['name'] == 'load' } - $load_filename = filename + ".tmp" # for load - $data = data - str = File.read(filename) - str.gsub!(/\bdata\b/, '$data') - hash = testdefs.find { |h| h['name'] == compiler_name } - code = eval hash['compile'] - code.sub!(/_out\s*\z/, 'print \&') - File.open($load_filename, 'w') { |f| f.write(code) } - at_exit do - File.unlink $load_filename if test(?f, $load_filename) - end -end +### create file for load +#if testdefs.find { |h| h['name'] == 'load' } +# $load_filename = filename + ".tmp" # for load +# $data = data +# str = File.read(filename) +# str.gsub!(/\bdata\b/, '$data') +# hash = testdefs.find { |h| h['name'] == compiler_name } +# code = eval hash['compile'] +# code.sub!(/_out\s*\z/, 'print \&') +# File.open($load_filename, 'w') { |f| f.write(code) } +# at_exit do +# File.unlink $load_filename if test(?f, $load_filename) +# end +#end ## select test target -if flag_all +if test_all #testdefs.each { |h| h['skip'] = false } elsif !ARGV.empty? #testdefs.each { |h| h['skip'] = ARGV.include?(h['name']) } @@ -284,6 +312,7 @@ begin testdefs.each do |h| title = h['class'] func = 'test_' + h['name'] + GC.start job.report(title) do __send__(func, filename, data) end @@ -294,6 +323,7 @@ begin next unless h['compile'] title = 'eval_' + h['name'] func = 'test_eval_' + h['name'] + GC.start job.report(title) do __send__(func, filename, data) end @@ -304,6 +334,7 @@ begin next unless h['compile'] title = 'func_' + h['name'] func = 'test_view_' + h['name'] + GC.start job.report(title) do __send__(func, data) end diff --git a/erubis.gemspec b/erubis.gemspec index 726cc20..6d327ab 100644 --- a/erubis.gemspec +++ b/erubis.gemspec @@ -15,21 +15,23 @@ spec = Gem::Specification.new do |s| s.version = ("$Release$" =~ /[\.\d]+/) && $& s.platform = Gem::Platform::RUBY s.homepage = "http://rubyforge.org/projects/erubis" - s.summary = "an implementation of eRuby" + s.summary = "a fast and extensible eRuby implementation which supports multi-language" s.description = <<-'END' Erubis is an implementation of eRuby and has the following features: + * Very fast (about three times faster than ERB) * Auto trimming spaces around '<% %>' * Auto sanitizing * Change embedded pattern (default '<% %>') * Context object available * Easy to expand in subclass + * Able to output multi-language (Ruby/PHP/C/Java/Scheme/Perl) END ## files files = [] files += Dir.glob('lib/**/*') files += Dir.glob('bin/*') - #files += Dir.glob('examples/**/*') + files += Dir.glob('examples/**/*') files += Dir.glob('test/test-*.rb') #files += Dir.glob('man/**/*') files += [ "doc/users-guide.html", "doc/docstyle.css", ] @@ -38,7 +40,7 @@ spec = Gem::Specification.new do |s| s.files = files s.executables = ["erubis"] s.bindir = "bin" - s.test_file = 'test/test-erubis.rb' + s.test_file = 'test/test.rb' end # Quick fix for Ruby 1.8.3 / YAML bug (thanks to Ross Bamford) diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 0000000..1261f9d --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,50 @@ +all = example.rb example.php example.c example.java example.scm example.pl + +all: $(all) + +example.rb: example.eruby + erubis -l ruby example.eruby > example.rb + + +example.php: example.ephp + erubis -l php example.ephp > example.php + +example.c: example.ec + erubis -l c example.ec > example.c + +example.java: example.ejava + erubis -l java example.ejava > example.java + +example.scm: example.escheme + erubis -l scheme --func=display example.escheme > example.scm +# erubis -l scheme example.escheme > example.scm + +example.pl: example.eperl + erubis -l perl example.eperl > example.pl + + +###---------- + +src = example.eruby example.ephp example.ec example.ejava example.escheme example.eperl Makefile + +clean: + rm -f `ruby -e 'puts(Dir.glob("*.*") - %w[$(src)])'` +# rm -f $(all) + +compile: a.out example.class + +a.out: example.c + cc example.c + +example.class: example.java + jikes example.java + +output: $(all) a.out example.class + erubis example.eruby > example.ruby.out + php example.php > example.php.out + ./a.out foo bar baz > example.c.out + java example > example.java.out + gosh example.scm > example.scm.out +# guile example.scm > example.scm.out + perl example.pl > example.pl.out + diff --git a/examples/example.ec b/examples/example.ec new file mode 100644 index 0000000..06e7961 --- /dev/null +++ b/examples/example.ec @@ -0,0 +1,24 @@ +<% +#include <stdio.h> + +int main(int argc, char *argv[]) +{ + int i; + +%> +<p>Hello <%= "%s", argv[0] %>!</p> +<table> + <tbody> + <% for (i = 1; i < argc; i++) { %> + <tr bgcolor="<%= i % 2 == 0 ? "#FFCCCC" : "#CCCCFF" %>"> + <td><%= "%d", i %></td> + <td><%= "%s", argv[i] %></td> + </tr> + <% } %> + </tbody> +</table> +<% + + return 0; +} +%> diff --git a/examples/example.ejava b/examples/example.ejava new file mode 100644 index 0000000..21dd155 --- /dev/null +++ b/examples/example.ejava @@ -0,0 +1,41 @@ +<% +import java.util.*; + +public class example { + + public static void main(String[] args) { + String user = "Erubis"; + String[] list = { "<aaa>", "b&b", "\"ccc\"" }; + StringBuffer _out = new StringBuffer(); +%> +<p>Hello <%= user %>!</p> +<table> + <tbody> + <% for (int i = 0; i < list.length; i++) { %> + <tr bgcolor="<%= i % 2 == 0 ? "#FFCCCC" : "#CCCCFF" %>"> + <td><%= i + 1 %></td> + <td><%== list[i] %></td> + </tr> + <% } %> + </tbody> +</table> +<% + System.out.print(_out.toString()); + } + + public static String escape(String s) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + switch (ch) { + case '<': sb.append("<"); break; + case '>': sb.append(">"); break; + case '&': sb.append("&"); break; + case '"': sb.append("""); break; + default: sb.append(ch); + } + } + return sb.toString(); + } +} +%> diff --git a/examples/example.eperl b/examples/example.eperl new file mode 100644 index 0000000..678aa21 --- /dev/null +++ b/examples/example.eperl @@ -0,0 +1,16 @@ +<% + my $user = 'Erubis'; + my @list = ('<aaa>', 'b&b', '"ccc"'); +%> +<p>Hello <%= $user %>!</p> +<table> + <tbody> + <% $i = 0; %> + <% for $item (@list) { %> + <tr bgcolor=<%= ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF' %>"> + <td><%= $i %></td> + <td><%= $item %></td> + </tr> + <% } %> + </tbody> +</table> diff --git a/examples/example.ephp b/examples/example.ephp new file mode 100644 index 0000000..b45d62d --- /dev/null +++ b/examples/example.ephp @@ -0,0 +1,17 @@ +<% + $user = "World"; + $list = array('<aaa>', 'b&b', '"ccc"'); +%> +<p>Hello <%= $user %>!</p> +<table> + <tbody> + <% $i = 0 %> + <% foreach ($list as $item) { %> + <% $i++; %> + <tr bgcolor="<%= $i % 2 == 0 ? '#FFCCCC' : '#CCCCFF' %>"> + <td><%= $i %></td> + <td><%== $item %></td> + </tr> + <% } %> + </tbody> +</table> diff --git a/examples/example.eruby b/examples/example.eruby new file mode 100644 index 0000000..ee1ed13 --- /dev/null +++ b/examples/example.eruby @@ -0,0 +1,15 @@ +<% + user = 'Erubis' + list = ['<aaa>', 'b&b', '"ccc"'] + %> +<p>Hello <%= user %>!</p> +<table> + <tbody> + <% list.each_with_index do |item, i| %> + <tr bgcolor="<%= i % 2 == 0 ? '#FFCCCC' : '#CCCCFF' %>"> + <td><%= i + 1 %></td> + <td><%== item %></td> + </tr> + <% end %> + </tbody> +</table> diff --git a/examples/example.escheme b/examples/example.escheme new file mode 100644 index 0000000..419ef77 --- /dev/null +++ b/examples/example.escheme @@ -0,0 +1,26 @@ +<% +(let ((user "Erubis") + (items '("<aaa>" "b&b" "\"ccc\"")) + (i 0)) + %> +<p>Hello <%= user %>!</p> +<table> + <tbody> +<% + (for-each + (lambda (item) + (set! i (+ i 1)) + %> + <tr bgcolor="<%= (if (= (modulo i 2) 0) "#FFCCCC" "#CCCCFF") %>"> + <td><%= i %></td> + <td><%= item %></td> + </tr> +<% + ) ; lambda end + items) ; for-each end + %> + </tbody> +</table> +<% +) ; let end +%> diff --git a/lib/erubis.rb b/lib/erubis.rb index e1ec3ab..70c660c 100644 --- a/lib/erubis.rb +++ b/lib/erubis.rb @@ -56,8 +56,11 @@ require 'erubis/engine' require 'erubis/helper' require 'erubis/enhancer' require 'erubis/engine/ruby' -require 'erubis/engine/optimized' +#require 'erubis/engine/enhanced' # enhanced eruby engines +#require 'erubis/engine/optimized' # generates optimized ruby code #require 'erubis/engine/php' #require 'erubis/engine/c' #require 'erubis/engine/java' #require 'erubis/engine/scheme' + +require 'erubis/local-setting' diff --git a/lib/erubis/engine.rb b/lib/erubis/engine.rb index 7ed9d29..1482986 100644 --- a/lib/erubis/engine.rb +++ b/lib/erubis/engine.rb @@ -20,6 +20,14 @@ module Erubis ## class Engine + def self.supported_properties # :nodoc: + return [ + [:pattern, '<% %>', "embed pattern"], + [:filename, nil, "filename"], + [:trim, true, "trim spaces around <% ... %>"], + ] + end + def initialize(input, options={}) #@input = input @pattern = options[:pattern] || '<% %>' @@ -38,17 +46,13 @@ module Erubis return eruby end - def result(binding=TOPLEVEL_BINDING) - filename = @filename || '(erubis)' - eval @src, binding, filename + def result(_binding=TOPLEVEL_BINDING) + _filename = @filename || '(erubis)' + eval @src, _binding, _filename end def evaluate(_context={}) - _evalstr = '' - _context.keys.each do |key| - _evalstr << "#{key.to_s} = _context[#{key.inspect}]\n" - end - eval _evalstr + eval _context.keys.inject("") { |s, k| s << "#{k.to_s} = _context[#{k.inspect}];" } return result(binding()) end diff --git a/lib/erubis/engine/c.rb b/lib/erubis/engine/c.rb index 146137b..486c8c0 100644 --- a/lib/erubis/engine/c.rb +++ b/lib/erubis/engine/c.rb @@ -16,6 +16,13 @@ module Erubis ## class Ec < Engine + def self.supported_properties() # :nodoc: + list = super + list << [:indent, '', "indent spaces (ex. ' ')"] + list << [:out, 'stdout', "output stream name"] + return list + end + def initialize(input, properties={}) @indent = properties[:indent] || '' @out = properties[:out] || 'stdout' @@ -23,7 +30,7 @@ module Erubis end def init_src(src) - src << "# 1 \"#{self.filename}\"\n" if self.filename + src << "#line 1 \"#{self.filename}\"\n" if self.filename end def escape_text(text) @@ -32,6 +39,15 @@ module Erubis return text end + def escaped_expr(code) + code.strip! + if code =~ /\A(\".*?\")\s*,\s*(.*)/ + return "#{$1}, escape(#{$2})" + else + return "escape(#{code})" + end + end + def add_text(src, text) return if text.empty? src << (src.empty? || src[-1] == ?\n ? @indent : ' ') @@ -60,10 +76,6 @@ module Erubis src << " fprintf(#{@out}, " << escaped_expr(code) << ');' end - def escaped_expr(code) - return code.strip - end - def add_expr_debug(src, code) code.strip! s = nil @@ -80,11 +92,9 @@ module Erubis end - #-- - #class XmlEc < Ec - # include EscapeEnhancer - #end - #++ + class XmlEc < Ec + include EscapeEnhancer + end end diff --git a/lib/erubis/engine/enhanced.rb b/lib/erubis/engine/enhanced.rb new file mode 100644 index 0000000..b82789e --- /dev/null +++ b/lib/erubis/engine/enhanced.rb @@ -0,0 +1,154 @@ +## +## $Rev$ +## $Release$ +## $Copyright$ +## + +require 'erubis/enhancer' +require 'erubis/engine/ruby' + + +module Erubis + + + ## (obsolete) + class FastEruby < Eruby + include FastEnhancer + end + + + class StdoutEruby < Eruby + include StdoutEnhancer + end + + + class PrintStatementEruby < Eruby + include PrintStatementEnhancer + end + + + class PrintEnabledEruby < Eruby + include PrintEnabledEnhancer + end + + + class ArrayEruby < Eruby + include ArrayEnhancer + end + + + #-- + #class ArrayBufferEruby < Eruby + # include ArrayBufferEnhancer + #end + #++ + + + class StringBufferEruby < Eruby + include StringBufferEnhancer + end + + + class SimplifiedEruby < Eruby + include SimplifiedEnhancer + end + + + class StdoutSimplifiedEruby < Eruby + include StdoutEnhancer + include SimplifiedEnhancer + end + + + class BiPatternEruby < Eruby + include BiPatternEnhancer + end + + + class PercentLineEruby < Eruby + include PercentLineEnhancer + end + + + class HeaderFooterEruby < Eruby + include HeaderFooterEnhancer + end + + + ## (obsolete) + class FastXmlEruby < Eruby + include FastEnhancer + include EscapeEnhancer + end + + + class StdoutXmlEruby < Eruby + include StdoutEnhancer + include EscapeEnhancer + end + + + class PrintStatementXmlEruby < Eruby + include PrintStatementEnhancer + include EscapeEnhancer + end + + + class PrintEnabledXmlEruby < Eruby + include PrintEnabledEnhancer + include EscapeEnhancer + end + + + class ArrayXmlEruby < Eruby + include ArrayEnhancer + include EscapeEnhancer + end + + + #-- + #class ArrayBufferXmlEruby < Eruby + # include ArrayBufferEnhancer + # include EscapeEnhancer + #end + #++ + + + class StrinBufferXmlEruby < Eruby + include StringBufferEnhancer + include EscapeEnhancer + end + + + class SimplifiedXmlEruby < Eruby + include SimplifiedEnhancer + include EscapeEnhancer + end + + + class StdoutSimplifiedXmlEruby < Eruby + include StdoutEnhancer + include SimplifiedEnhancer + include EscapeEnhancer + end + + + class BiPatternXmlEruby < Eruby + include BiPatternEnhancer + include EscapeEnhancer + end + + + class PercentLineXmlEruby < Eruby + include PercentLineEnhancer + include EscapeEnhancer + end + + + class HeaderFooterXmlEruby < Eruby + include HeaderFooterEnhancer + include EscapeEnhancer + end + + +end diff --git a/lib/erubis/engine/java.rb b/lib/erubis/engine/java.rb index 6017387..7a604f5 100644 --- a/lib/erubis/engine/java.rb +++ b/lib/erubis/engine/java.rb @@ -16,30 +16,38 @@ module Erubis ## class Ejava < Engine + def self.supported_properties() # :nodoc: + list = super + list << [:indent, '', "indent spaces (ex. ' ')"] + list << [:out, '_out', "output buffer name"] + #list << [:outclass, 'StringBuffer', "output buffer class (ex. 'StringBuilder')"] + return list + end + def initialize(input, properties={}) @indent = properties[:indent] || '' - @out = properties[:out] || '_out' - @outclass = properties[:outclass] || 'StringBuffer' + @out = properties[:out] || '_out' + #@outclass = properties[:outclass] || 'StringBuffer' super end def init_src(src) - src << "#{@indent}#{@outclass} _out = new #{@outclass}();\n" + #src << "#{@indent}#{@out} _out = new #{@outclass}();\n" end def escape_text(text) @@table_ ||= { "\r"=>"\\r", "\n"=>"\\n", "\t"=>"\\t", '"'=>'\\"', "\\"=>"\\\\" } - text.gsub(/[\r\n\t"\\]/) { |m| @@table_[m] } + return text.gsub!(/[\r\n\t"\\]/) { |m| @@table_[m] } || text end def escaped_expr(code) - return code.strip + return "escape(#{code.strip})" end def add_text(src, text) return if text.empty? src << (src.empty? || src[-1] == ?\n ? @indent : ' ') - src << "_out.append(" + src << @out << ".append(" i = 0 text.each_line do |line| src << "\n" << @indent << ' + ' if i > 0 @@ -55,12 +63,12 @@ module Erubis def add_expr_literal(src, code) src << @indent if src.empty? || src[-1] == ?\n - src << ' _out.append(' << code.strip << ');' + src << ' ' << @out << '.append(' << code.strip << ');' end def add_expr_escaped(src, code) src << @indent if src.empty? || src[-1] == ?\n - src << ' _out.append(' << escaped_expr(code) << ');' + src << ' ' << @out << '.append(' << escaped_expr(code) << ');' end def add_expr_debug(src, code) @@ -69,18 +77,17 @@ module Erubis src << " System.err.println(\"*** debug: #{code}=\"+(#{code}));" end - def finalize_src(src) + def finish_src(src) src << "\n" if src[-1] == ?; - src << @indent << "return _out.toString();\n" + #src << @indent << "return " << @out << ".toString();\n" end end - #-- - #class XmlEjava < Compiler - # include EscapeEnhancer - #end - #++ + class XmlEjava < Ejava + include EscapeEnhancer + end + end diff --git a/lib/erubis/engine/optimized.rb b/lib/erubis/engine/optimized.rb index 7330188..27bed18 100644 --- a/lib/erubis/engine/optimized.rb +++ b/lib/erubis/engine/optimized.rb @@ -12,12 +12,24 @@ module Erubis ## - ## Eruby class which generates optimized code + ## Eruby class which generates optimized ruby code ## - class OptimizedEruby < Eruby + class OptimizedEruby < Engine # Eruby + + def self.supported_properties() # :nodoc: + return super + end protected + def escape_text(text) + text.gsub(/['\\]/, '\\\\\&') # "'" => "\\'", '\\' => '\\\\' + end + + def escaped_expr(code) + return "Erubis::XmlHelper.escape_xml(#{code})" + end + def switch_to_expr(src) return if @prev_is_expr @prev_is_expr = true @@ -46,6 +58,12 @@ module Erubis end end + def add_stmt(src, code) + switch_to_stmt(src) if @initialized + #super + src << code << ';' + end + def add_expr_literal(src, code) unless @initialized; src << "_out = ''"; @initialized = true; end switch_to_expr(src) @@ -58,20 +76,22 @@ module Erubis src << " << " << escaped_expr(code) end - def add_stmt(src, code) - switch_to_stmt(src) if @initialized - super + def add_expr_debug(src, code) + code.strip! + s = (code.dump =~ /\A"(.*)"\z/) && $1 + src << ' $stderr.puts("*** debug: ' << s << '=#{(' << code << ').inspect}");' end def finish_src(src) - super if @initialized + #super if @initialized + src << "\n_out\n" if @initialized end end # end of class OptimizedEruby ## - ## XmlEruby class which generates optimized code + ## XmlEruby class which generates optimized ruby code ## class OptimizedXmlEruby < OptimizedEruby include EscapeEnhancer @@ -84,4 +104,84 @@ module Erubis end # end of class OptimizedXmlEruby + ## for test + class Optimized2Eruby < Eruby # :nodoc: + + def self.supported_properties() # :nodoc: + return super + end + + protected + + def escape_text(text) + text.gsub(/['\\]/, '\\\\\&') # "'" => "\\'", '\\' => '\\\\' + end + + def escaped_expr(code) + return "Erubis::XmlHelper.escape_xml(#{code})" + end + + #def switch_to_expr(src) + # return if @prev_is_expr + # @prev_is_expr = true + # src << ' _out' + #end + + #def switch_to_stmt(src) + # return unless @prev_is_expr + # @prev_is_expr = false + # src << ';' + #end + + def init_src(src) + @initialized = false + #@prev_is_expr = false + end + + def add_text(src, text) + return if text.empty? + if @initialized + #switch_to_expr(src) + #src << " << '" << escape_text(text) << "'" + src << "_out << '" << escape_text(text) << "';" + else + src << "_out = '" << escape_text(text) << "';" + @initialized = true + end + end + + def add_stmt(src, code) + #switch_to_stmt(src) if @initialized + #super + src << code << ';' + end + + def add_expr_literal(src, code) + unless @initialized; src << "_out = ''"; @initialized = true; end + #switch_to_expr(src) + #src << " << (" << code << ").to_s" + src << " _out << (" << code << ").to_s;" + end + + def add_expr_escaped(src, code) + unless @initialized; src << "_out = ''"; @initialized = true; end + #switch_to_expr(src) + #src << " << " << escaped_expr(code) + src << " _out << " << escaped_expr(code) << ';' + end + + def add_expr_debug(src, code) + code.strip! + s = (code.dump =~ /\A"(.*)"\z/) && $1 + src << ' $stderr.puts("*** debug: ' << s << '=#{(' << code << ').inspect}");' + end + + def finish_src(src) + #super if @initialized + src << "\n_out\n" if @initialized + end + + end + + end diff --git a/lib/erubis/engine/perl.rb b/lib/erubis/engine/perl.rb new file mode 100644 index 0000000..60b8bbf --- /dev/null +++ b/lib/erubis/engine/perl.rb @@ -0,0 +1,77 @@ +## +## $Rev$ +## $Release$ +## $Copyright$ +## + +require 'erubis/engine' +require 'erubis/enhancer' + + +module Erubis + + + ## + ## engine for Perl + ## + class Eperl < Engine + + def self.supported_properties() # :nodoc: + list = super + list << [:func, 'print', "function name"] + return list + end + + def initialize(input, options={}) + @func = options[:func] || 'print' + super + end + + #-- + #def init_src(src) + #end + #++ + + def escape_text(text) + return text.gsub!(/['\\]/, '\\\\\&') || text + end + + def add_text(src, text) + src << @func << "('" << escape_text(text) << "'); " unless text.empty? + end + + def escaped_expr(code) + return "escape(#{code.strip})" + end + + def add_expr_literal(src, code) + src << @func << "(" << code.strip << "); " + end + + def add_expr_escaped(src, code) + src << @func << "(" << escaped_expr(code) << "); " + end + + def add_expr_debug(src, code) + code.strip! + s = code.gsub(/\'/, "\\'") + src << @func << "('*** debug: #{code}=', #{code}, \"\\n\");" + end + + def add_stmt(src, code) + src << code + end + + def finish_src(src) + src << "\n" unless src[-1] == ?\n + end + + end + + + class XmlEperl < Eperl + include EscapeEnhancer + end + + +end diff --git a/lib/erubis/engine/php.rb b/lib/erubis/engine/php.rb index f1b7ba2..5de3e65 100644 --- a/lib/erubis/engine/php.rb +++ b/lib/erubis/engine/php.rb @@ -16,8 +16,8 @@ module Erubis ## class Ephp < Engine - def initialize(input, properties={}) - super + def self.supported_properties() # :nodoc: + return super end #-- diff --git a/lib/erubis/engine/ruby.rb b/lib/erubis/engine/ruby.rb index 3dee302..9e424f7 100644 --- a/lib/erubis/engine/ruby.rb +++ b/lib/erubis/engine/ruby.rb @@ -15,9 +15,11 @@ module Erubis ## engine for Ruby ## class Eruby < Engine + #include StringBufferEnhancer + include ArrayBufferEnhancer - def init_src(src) - src << "_out = '';" + def self.supported_properties() # :nodoc: + return super end def escape_text(text) @@ -28,6 +30,12 @@ module Erubis return "Erubis::XmlHelper.escape_xml(#{code})" end + #-- + #def init_src(src) + # src << "_out = [];" + #end + #++ + def add_text(src, text) src << " _out << '" << escape_text(text) << "';" unless text.empty? end @@ -50,9 +58,11 @@ module Erubis src << ' $stderr.puts("*** debug: ' << s << '=#{(' << code << ').inspect}");' end - def finish_src(src) - src << "\n_out\n" - end + #-- + #def finish_src(src) + # src << "\n_out.join\n" + #end + #++ end @@ -65,50 +75,4 @@ module Erubis end - ## (obsolete) - class FastEruby < Eruby - include FastEnhancer - end - - - class StdoutEruby < Eruby - include StdoutEnhancer - end - - - class PrintEruby < Eruby - include PrintEnhancer - end - - - class ArrayBufferEruby < Eruby - include ArrayBufferEnhancer - end - - - ## (obsolete) - class FastXmlEruby < Eruby - include FastEnhancer - include EscapeEnhancer - end - - - class StdoutXmlEruby < Eruby - include StdoutEnhancer - include EscapeEnhancer - end - - - class PrintXmlEruby < Eruby - include PrintEnhancer - include EscapeEnhancer - end - - - class ArrayBufferXmlEruby < Eruby - include ArrayBufferEnhancer - include EscapeEnhancer - end - - end diff --git a/lib/erubis/engine/scheme.rb b/lib/erubis/engine/scheme.rb index 7989133..4b8e0de 100644 --- a/lib/erubis/engine/scheme.rb +++ b/lib/erubis/engine/scheme.rb @@ -16,6 +16,12 @@ module Erubis ## class Escheme < Engine + def self.supported_properties() # :nodoc: + list = super + list << [:func, '_add', "function name (ex. 'display')"] + return list + end + def initialize(input, properties={}) @func = properties[:func] || '_add' # or 'display' super @@ -36,7 +42,7 @@ module Erubis end def escaped_expr(code) - return code.strip! || code + return "(escape #{code.strip})" end def add_text(src, text) @@ -69,11 +75,9 @@ module Erubis end - #-- - #class XmlEscheme < Escheme - # include EscapeEnhancer - #end - #++ + class XmlEscheme < Escheme + include EscapeEnhancer + end end diff --git a/lib/erubis/enhancer.rb b/lib/erubis/enhancer.rb index e94733e..347a242 100644 --- a/lib/erubis/enhancer.rb +++ b/lib/erubis/enhancer.rb @@ -12,7 +12,7 @@ module Erubis ## - ## switch '<%= ... %>' to escaped and '<%== ... %>' to non-escaped + ## switch '<%= ... %>' to escaped and '<%== ... %>' to unescaped ## ## ex. ## class XmlEruby < Eruby @@ -21,13 +21,28 @@ module Erubis ## module EscapeEnhancer - def self.included(klass) - klass.class_eval <<-END - alias _add_expr_literal add_expr_literal - alias _add_expr_escaped add_expr_escaped - alias add_expr_literal _add_expr_escaped - alias add_expr_escaped _add_expr_literal - END + #-- + #def self.included(klass) + # klass.class_eval <<-END + # alias _add_expr_literal add_expr_literal + # alias _add_expr_escaped add_expr_escaped + # alias add_expr_literal _add_expr_escaped + # alias add_expr_escaped _add_expr_literal + # END + #end + #++ + + def add_expr(src, code, indicator) + case indicator + when '=' + add_expr_escaped(src, code) + #add_expr_literal(src, code) + when '==' + add_expr_literal(src, code) + #add_expr_escaped(src, code) + when '===' + add_expr_debug(src, code) + end end end @@ -48,22 +63,54 @@ module Erubis end def finish_src(src) - src << "\nnil\n" + src << "\n''\n" end end ## - ## print function is available. + ## use print statement instead of '_out << ...' style + ## + module PrintStatementEnhancer + + def init_src(src) + end + + def add_text(src, text) + src << " print '" << escape_text(text) << "';" unless text.empty? + end + + def add_stmt(src, code) + src << code << ';' + end + + def add_expr_literal(src, code) + src << ' print((' << code << ').to_s);' + end + + def add_expr_escaped(src, code) + src << ' print ' << escaped_expr(code) << ';' + end + + def finish_src(src) + src << "\n" unless src[-1] == ?\n + end + + end + + + ## + ## enable print function ## ## Notice: use Eruby#evaluate() and don't use Eruby#result() ## to be enable print function. ## - module PrintEnhancer + module PrintEnabledEnhancer def init_src(src) - src << "@_out = _out = '';" + src << "@_out = " + super end def print(*args) @@ -76,7 +123,7 @@ module Erubis ## - ## return Array instead of String + ## return array instead of string ## module ArrayEnhancer @@ -93,7 +140,7 @@ module Erubis ## - ## use Array instead of String as buffer + ## use array buffer instead of string buffer ## module ArrayBufferEnhancer @@ -103,7 +150,207 @@ module Erubis def finish_src(src) src << "\n" unless src[-1] == ?\n - src << "_out.join()\n" + src << "_out.join\n" + end + + end + + + ## + ## use string buffer instead of array buffer + ## + module StringBufferEnhancer + + def init_src(src) + src << "_out = '';" + end + + def finish_src(src) + src << "\n" unless src[-1] == ?\n + src << "_out\n" + end + + end + + + ## + ## simple and minimum compiler engine + ## + ## this makes compile faster, but spaces around '<%...%>' are not trimmed. + ## + module SimplifiedEnhancer + + #DEFAULT_REGEXP = /(.*?)(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m + SIMPLE_REGEXP = /(.*?)<%(=+|\#)?(.*?)-?%>/m + + def compile(input) + src = "" + init_src(src) + regexp = pattern_regexp(@pattern) + input.scan(SIMPLE_REGEXP) do |text, indicator, code| + add_text(src, text) + if !indicator # <% %> + add_stmt(src, code) + elsif indicator[0] == ?= # <%= %> + add_expr(src, code, indicator) + else # <%# %> + n = code.count("\n") + add_stmt(src, "\n" * n) + end + end + rest = $' || input + add_text(src, rest) + finish_src(src) + return src + end + + end + + + ## + ## enable to use other embedded expression pattern (default is '\[= =\]'). + ## + ## notice! this is an experimental. spec may change in the future. + ## + ## ex. + ## input = <<END + ## <% for item in list %> + ## <%= item %> : <%== item %> + ## [= item =] : [== item =] + ## <% end %> + ## END + ## + ## class BiPatternEruby + ## include BiPatternEnhancer + ## end + ## eruby = BiPatternEruby.new(input, :bipattern=>'\[= =\]') + ## list = ['<a>', 'b&b', '"c"'] + ## print eruby.result(binding()) + ## + ## ## output + ## <a> : <a> + ## <a> : <a> + ## b&b : b&b + ## b&b : b&b + ## "c" : "c" + ## "c" : "c" + ## + module BiPatternEnhancer + + def initialize(input, properties={}) + @bipattern = properties[:bipattern] || '\[= =\]' # or '\$\{ \}' + pre, post = @bipattern.split() + @bipattern_regexp = /(.*?)#{pre}(=*)(.*?)#{post}/m + super + end + + def add_text(src, text) + text.scan(@bipattern_regexp) do |txt, indicator, code| + super(src, txt) + add_expr(src, code, '=' + indicator) + end + rest = $' || text + super(src, rest) + end + + end + + + ## + ## enable to use ruby statement line starts with '%' + ## + ## this is for compatibility to eruby and ERB. + ## + module PercentLineEnhancer + + PERCENT_LINE_PATTERN = /(.*?)^\%(.*?\r?\n)/m + + def add_text(src, text) + text.scan(PERCENT_LINE_PATTERN) do |txt, line| + super(src, txt) + if line[0] == ?% + super(src, line) + else + add_stmt(src, line) + end + end + rest = $' || text + super(src, rest) + end + + end + + + ## + ## [experimental] allow header and footer in eRuby script + ## + ## ex. + ## ==================== + ## ## without header and footer + ## $ cat ex1.eruby + ## <% def list_items(list) %> + ## <% for item in list %> + ## <li><%= item %></li> + ## <% end %> + ## <% end %> + ## + ## $ erubis -s ex1.eruby + ## _out = []; def list_items(list) + ## ; for item in list + ## ; _out << '<li>'; _out << ( item ).to_s; _out << '</li> + ## '; end + ## ; end + ## ; + ## _out.join + ## + ## ## with header and footer + ## $ cat ex2.eruby + ## <!--#header: + ## def list_items(list) + ## #--> + ## <% for item in list %> + ## <li><%= item %></li> + ## <% end %> + ## <!--#footer: + ## end + ## #--> + ## + ## $ erubis -s -c HeaderFooterEruby ex4.eruby + ## + ## def list_items(list) + ## _out = []; _out << ' + ## '; for item in list + ## ; _out << '<li>'; _out << ( item ).to_s; _out << '</li> + ## '; end + ## ; _out << ' + ## '; + ## _out.join + ## end + ## + ## ==================== + ## + module HeaderFooterEnhancer + + HEADER_FOOTER_PATTERN = /(.*?)(^[ \t]*)?<!--\#(\w+):(.*?)\#-->([ \t]*\r?\n)?/m + + def add_text(src, text) + text.scan(HEADER_FOOTER_PATTERN) do |txt, lspace, word, content, rspace| + flag_trim = @trim && lspace && rspace + super(src, txt) + content = "#{lspace}#{content}#{rspace}" if flag_trim + super(src, lspace) if !flag_trim && lspace + instance_variable_set("@#{word}", content) + super(src, rspace) if !flag_trim && rspace + end + rest = $' || text + super(src, rest) + end + + attr_accessor :header, :footer + + def compile(input) + source = super + return "#{@header}#{source}#{@footer}" end end diff --git a/lib/erubis/local-setting.rb b/lib/erubis/local-setting.rb new file mode 100644 index 0000000..747b313 --- /dev/null +++ b/lib/erubis/local-setting.rb @@ -0,0 +1,10 @@ +## +## $Rev$ +## $Release$ +## $Copyright$ +## + +## +## you can add site-local settings here. +## this files is 'require'd by erubis.rb +## diff --git a/lib/erubis/main.rb b/lib/erubis/main.rb index 3664938..c865867 100644 --- a/lib/erubis/main.rb +++ b/lib/erubis/main.rb @@ -6,11 +6,14 @@ require 'yaml' require 'erubis' +require 'erubis/engine/enhanced' +require 'erubis/engine/optimized' require 'erubis/engine/ruby' require 'erubis/engine/php' require 'erubis/engine/c' require 'erubis/engine/java' require 'erubis/engine/scheme' +require 'erubis/engine/perl' module Erubis @@ -49,6 +52,7 @@ module Erubis if options[?h] || options[?v] puts version() if options[?v] puts usage() if options[?h] + puts show_properties() if options[?h] return end @@ -148,27 +152,43 @@ module Erubis def usage command = File.basename($0) s = <<END +erubis - embedded program compiler for multi-language Usage: #{command} [..options..] [file ...] -h, --help : help -v : version -s : script source -x : script source (removed the last '_out' line) - -T : no trimming spaces around '<% %>' + -T : don't trim spaces around '<% %>' -p pattern : embedded pattern (default '<% %>') - -l lang : compile but no execute (ruby/php/c/java/scheme) - -c class : class name (Eruby, XmlEruby, FastEruby, ...) (default Eruby) + -l lang : compile but no execute (ruby/php/c/java/scheme/perl) + if lang is 'xmlxxx' then 'XmlExxx' class is used + -c class : class name (XmlEruby/PrintStatementEruby/...) (default Eruby) -I path : library include path - -K kanji : kanji code (euc, sjis, utf8, none) (default none) + -K kanji : kanji code (euc/sjis/utf8) (default none) -f file.yaml : YAML file for context values (read stdin if filename is '-') -t : expand tab character in YAML file - -S : convert mapping key from string to symbol - --name=value : context name and value + -S : convert mapping key from string to symbol in YAML file + END # -r library : require library # -a : action (compile/execute) return s end + def show_properties + s = "supported properties:\n" + %w[ruby php c java scheme perl].each do |lang| + klass = Erubis.const_get("E#{lang}") + s << " * #{lang}\n" + list = klass.supported_properties - Erubis::Engine.supported_properties + list.each do |name, default_val, desc| + s << (" --%-25s : %s\n" % ["#{name}=#{default_val.inspect}", desc]) + end + end + s << "\n" + return s + end + def version release = ('$Release: 0.0.0 $' =~ /([.\d]+)/) && $1 return release diff --git a/misc/memo.txt b/misc/memo.txt new file mode 100644 index 0000000..e68427c --- /dev/null +++ b/misc/memo.txt @@ -0,0 +1,373 @@ + +¡üeRuby¹â®²½·×²è + +¹â®¤ÊeRuby¤Î½èÍý·Ï¤ò¼ÂÁõ¤¹¤ë¥×¥í¥¸¥§¥¯¥È¡£ÌÜɸ¤ÏPure Ruby¤ÇERuby¤è¤ê¹â®¤Ë¤¹¤ë¤³¤È¡£ + + +¡ý¬Äê + +benchmark.rb¤ò»È¤¦¡£ + + +¡ý¹â®²½¤½¤Î1: Àµµ¬É½¸½¤Ç²òÀϤ¹¤ë + +¹½Ê¸²òÀϤò¤ä¤á¤Æ¡¢Àµµ¬É½¸½¤Ë¤è¤ë¥Ñ¥¿¡¼¥ó¥Þ¥Ã¥Á¤ò»È¤¦¡£ + +.-------------------- +def MyEruby + + def initialize(input) + @source = compile(input) + end + + attr_reader :source + + def compile(input) + ## ¥Ð¥Ã¥Õ¥¡¤ò½é´ü²½¤¹¤ë¥³¡¼¥É + src = "_buf = '';" + + ## ¥Ñ¥¿¡¼¥ó¥Þ¥Ã¥Á¤ò·«¤êÊÖ¤·¹Ô¤¦ + pattern = /(.*)<%(=?)(.*?)%>/m + input.scan(pattern) do |text, equal, code| + + ## '<% ... %>' ¤è¤êÁ°¤ÎÉôʬ¤òÄɲ乤륳¡¼¥É + text.each_line { |line| src << " _buf << #{line.dump}\n" } + src[-1] = ?; if rest[-1] != ?\n + + ## '<% ... %>' ¤Î½èÍý + if equal # '<%= ¼° %>' ¤Î¤È¤ + src << " _buf << (#{code}).to_s;" + else # '<% ʸ %>' ¤Î¤È¤ + src << code + src << ";" if code[-1] != ?\n + end + + end + + ## '<% %>' ¤è¤ê¸å¤í¤ÎÉôʬ¡Ê°ìÅÙ¤â¥Þ¥Ã¥Á¤·¤Ê¤¤¤È¤¤Ïinput¤ò»È¤¦¡Ë + rest = $' || input + rest.each_line { |line| src << " _buf << #{line.dump}\n" } + src[-1] = ?; if rest[-1] != ?\n + + ## ·ë²Ì¤Îʸ»úÎó¤òÊÖ¤¹¥³¡¼¥É + src << " _buf\n" + return src + end + + def result(binding=TOPLEVEL_BINDING) + eval @source, binding + end + +end +.-------------------- + +.#.-------------------- +.#def MyEruby +.# +.# def initialize(input) +.# @source = compile(input) +.# end +.# +.# attr_reader :source +.# +.# def compile(input) +.# src = "_buf = '';" ## ¥Ð¥Ã¥Õ¥¡¤ò½é´ü²½¤¹¤ë¥³¡¼¥É +.# pattern = /(.*)<%(=?)(.*?)%>/m +.# input.scan(pattern) do |text, equal, code| ## ¥Ñ¥¿¡¼¥ó¥Þ¥Ã¥Á +.# ## ¥Þ¥Ã¥Á¤·¤¿²Õ½ê¤ÎÁ°¤Î¥Æ¥¥¹¥È +.# text.each_line { |line| src << " _buf << #{line.dump}\n" } +.# src[-1] = ?; if rest[-1] != ?\n +.# if equal ## '<%= ¼° %>' ¤Î¤È¤ +.# src << " _buf << (#{code}).to_s;" +.# else ## '<% ʸ %>' ¤Î¤È¤ +.# src << code +.# src << ";" if code[-1] != ?\n +.# end +.# end +.# rest = $' || input ## ¥Þ¥Ã¥Á¤·¤¿²Õ½ê¤Î»Ä¤ê¤Î¥Æ¥¥¹¥È +.# rest.each_line { |line| src << " _buf << #{line.dump}\n" } +.# src[-1] = ?; if rest[-1] != ?\n +.# src << " _buf\n" ## ·ë²Ì¤Îʸ»úÎó¤òÊÖ¤¹¥³¡¼¥É +.# return src +.# end +.# +.# def result(binding=TOPLEVEL_BINDING) +.# eval @source, binding +.# end +.# +.#end +.#.-------------------- + + +¡ý¹â®²½¤½¤Î2: ʸ»úÎó¤ò·ë¹ç¤¹¤ë + +.-------------------- +def MyEruby + + def initialize(input) + @input = input + @source = compile(input) + end + + attr_reader :source + + def escape_text(text) + ## ¡Ö'¡×¤È¡Ö\¡×¤ò¥¨¥¹¥±¡¼¥×¤¹¤ë + text.gsub!(/['\\]/, '\\\\\1') + text + end + + def compile(input) + ## ¥Ð¥Ã¥Õ¥¡¤ò½é´ü²½¤¹¤ë¥³¡¼¥É + src = "_buf = '';" + + ## ¥Ñ¥¿¡¼¥ó¥Þ¥Ã¥Á¤ò·«¤êÊÖ¤·¹Ô¤¦ + pattern = /(.*)<%(=?)(.*?)%>/m + input.scan(pattern) do |text, equal, code| + + ## '<% ... %>' ¤è¤êÁ°¤ÎÉôʬ¤òÄɲ乤륳¡¼¥É + src << " _buf << '" << escape_text(text) << "'" unless text.empty? + + ## '<% ... %>' ¤Î½èÍý + if equal # '<%= ¼° %>' ¤Î¤È¤ + src << " _buf << (#{code}).to_s;" + else # '<% ʸ %>' ¤Î¤È¤ + src << code + src << ";" if code[-1] != ?\n + end + + end + + ## '<% %>' ¤è¤ê¸å¤í¤ÎÉôʬ¡Ê°ìÅÙ¤â¥Þ¥Ã¥Á¤·¤Ê¤¤¤È¤¤Ïinput¤ò»È¤¦¡Ë + rest = $' || input + src << " _buf << '" << escape_text(rest) << "'" unless rest.empty? + + ## ·ë²Ì¤Îʸ»úÎó¤òÊÖ¤¹¥³¡¼¥É + src << "\n_buf\n" + return src + end + + def result(binding=TOPLEVEL_BINDING) + eval @source, binding + end + +end +.-------------------- + + +¡ý¹â®²½¤½¤Î3: $stdout¤Ë½ÐÎϤ¹¤ë + +.-------------------- +def MyEruby + + def initialize(input) + @source = compile(input) + end + + attr_reader :source + + def escape_text(text) + ## ¡Ö'¡×¤È¡Ö\¡×¤ò¥¨¥¹¥±¡¼¥×¤¹¤ë + text.gsub!(/['\\]/, '\\\\\1') # "'" => "\\'", "\\" => "\\\\" + text + end + + def compile(input) + ## ¥Ð¥Ã¥Õ¥¡¤È¤·¤Æ$stdout¤ò»È¤¦ + src = "_buf = $stout;" + + ## ¥Ñ¥¿¡¼¥ó¥Þ¥Ã¥Á¤ò·«¤êÊÖ¤·¹Ô¤¦ + pattern = /(.*)<%(=?)(.*?)%>/m + input.scan(pattern) do |text, equal, code| + + ## '<% ... %>' ¤è¤êÁ°¤ÎÉôʬ¤òÄɲ乤륳¡¼¥É + src << " _buf << '" << escape_text(text) << "'" unless text.empty? + + ## '<% ... %>' ¤Î½èÍý + if equal # '<%= ¼° %>' ¤Î¤È¤ + src << " _buf << (#{code}).to_s;" + else # '<% ʸ %>' ¤Î¤È¤ + src << code + src << ";" if code[-1] != ?\n + end + + end + + ## '<% %>' ¤è¤ê¸å¤í¤ÎÉôʬ¡Ê°ìÅÙ¤â¥Þ¥Ã¥Á¤·¤Ê¤¤¤È¤¤Ïinput¤ò»È¤¦¡Ë + rest = $' || input + src << " _buf << '" << escape_text(rest) << "'" unless rest.empty? + + ## nil ¤òÊÖ¤¹¥³¡¼¥É + src << "\nnil\n" + return _buf + end + + def result(binding=TOPLEVEL_BINDING) + eval @source, binding + end + +end +.-------------------- + +¤¢¤ë¤¤¤Ï°ú¿ô¤Ç¥Ð¥Ã¥Õ¥¡¥ª¥Ö¥¸¥§¥¯¥È¤ò»ØÄꤹ¤ë¤è¤¦¤Ë¤·¤Æ¤â¤è¤¤¡£ + +.-------------------- +class MyEruby + + def initialize(input, buffer='') + @buffer = buffer + @source = compile(input) + end + + attr_reader :source + + def compile(input) + ## @buffer¤Ç½é´ü²½¤¹¤ë + src = "_buf = @buffer;" + + ... + + ## Ìá¤êÃÍ + src << "\n_buf\n" + return src + end + +end +.-------------------- + + +¡ý¹â®²½¤½¤Î4: ÇÛÎó¥Ð¥Ã¥Õ¥¡¤ò»È¤¦ + +$stdout¤ò»È¤¦¤Î¤Ï³Î¤«¤Ë¹â®¤Ê¤Î¤À¤¬¡¢Ê¸»úÎó¤òÊÖ¤·¤Æ¤¯¤ì¤¿¤Û¤¦¤¬½ÀÆðÀ¤¬¤¢¤ë¡£ +ʸ»úÎó¤òÊÖ¤¹¤è¤¦¤Ë¤·¤¿¤Þ¤Þ¤Ç¹â®²½¤¹¤ë¤³¤È¤Ï¤Ç¤¤Ê¤¤¤«¡£ + +¤½¤³¤Ç¡¢¥Ð¥Ã¥Õ¥¡¤È¤·¤Æʸ»úÎó¤Ç¤Ï¤Ê¤¯ÇÛÎó¤ò»È¤¦¡£ + +.-------------------- +def MyEruby + + def initialize(input) + @source = compile(input) + end + + attr_reader :source + + def escape_text(text) + text.gsub!(/['\\]/, '\\\\\1') ## ¡Ö'¡×¤È¡Ö\¡×¤ò¥¨¥¹¥±¡¼¥×¤¹¤ë + text + end + + def compile(input) + src = "_buf = [];" ## ¥Ð¥Ã¥Õ¥¡¤È¤·¤ÆÇÛÎó¤ò»È¤¦ + pattern = /(.*)<%(=?)(.*?)%>/m + input.scan(pattern) do |text, equal, code| + src << " _buf << '" << escape_text(text) << "'" unless text.empty? + if equal ## '<%= ¼° %>' ¤Î¤È¤ + src << " _buf << (#{code}).to_s;" + else ## '<% ʸ %>' ¤Î¤È¤ + src << code << ";" + end + end + rest = $' || input ## ¥Þ¥Ã¥Á¤·¤¿²Õ½ê¤Î»Ä¤ê¤Î¥Æ¥¥¹¥È + src << " _buf << '" << escape_text(rest) << "'" unless rest.empty? + src << "\n_buf.join\n" ## ÇÛÎó¤ÎÍ×ÁǤò·ë¹ç¤·¤ÆÊÖ¤¹¥³¡¼¥É + return src + end + + def result(binding=TOPLEVEL_BINDING) + eval @source, binding + end + +end +.-------------------- + + +¡ý¹â®²½¤½¤Î5: ¥ª¥Ö¥¸¥§¥¯¥È¤ÎÀ¸À®¤ò¸º¤é¤¹ + +ÉÔÊѤʥª¥Ö¥¸¥§¥¯¥È¤Ï°ì²ó¤À¤±À¸À®¤·¤Æ¤½¤ì¤ò»È¤¤²ó¤¹¤è¤¦¤Ë¤¹¤ë¡£ +º£²ó¤ÏÀµµ¬É½¸½¥ª¥Ö¥¸¥§¥¯¥È¤òÄê¿ô¤Ë¤¹¤ë¤³¤È¤Ç¡¢Ëè²óÀ¸À®¤µ¤ì¤ë¤Î¤òÈò¤±¤ë¡£ +¤¢¤Þ¤ê¹â®²½¤·¤Ê¤¤¤±¤É¡£ + +.-------------------- +def MyEruby + + def initialize(input) + @source = compile(input) + end + + attr_reader :source + + def escape_text(text) + text.gsub!(/['\\]/, '\\\\\1') ## ¡Ö'¡×¤È¡Ö\¡×¤ò¥¨¥¹¥±¡¼¥×¤¹¤ë + text + end + + PATTERN = /(.*)<%(=?)(.*?)%>/m + + def compile(input) + src = "_buf = [];" ## ¥Ð¥Ã¥Õ¥¡¤È¤·¤ÆÇÛÎó¤ò»È¤¦ + input.scan(PATTERN) do |text, equal, code| + src << " _buf << '" << escape_text(text) << "'" unless text.empty? + if equal ## '<%= ¼° %>' ¤Î¤È¤ + src << " _buf << (#{code}).to_s;" + else ## '<% ʸ %>' ¤Î¤È¤ + src << code << ";" + end + end + rest = $' || input ## ¥Þ¥Ã¥Á¤·¤¿²Õ½ê¤Î»Ä¤ê¤Î¥Æ¥¥¹¥È + src << " _buf << '" << escape_text(rest) << "'" unless rest.empty? + src << "\n_buf.join\n" ## ÇÛÎó¤ÎÍ×ÁǤò·ë¹ç¤·¤ÆÊÖ¤¹¥³¡¼¥É + return src + end + + def result(binding=TOPLEVEL_BINDING) + eval @source, binding + end + +end +.-------------------- + + +¡ý¹â®²½¤½¤Î6: ¥³¥ó¥Ñ¥¤¥ë·ë²Ì¤ò¥¥ã¥Ã¥·¥å¤¹¤ë + +Ëè²ó¥³¥ó¥Ñ¥¤¥ë¤¹¤ë¤Î¤Ç¤Ï¤Ê¤¯¡¢°ìÅÙ¥³¥ó¥Ñ¥¤¥ë¤·¤¿·ë²Ì¤ò¥Õ¥¡¥¤¥ë¤Ë¥¥ã¥Ã¥·¥å¤·¤Æ¤ª¤¯¡£ +¤Ä¤Þ¤ê +.* eRuby¥Õ¥¡¥¤¥ë¤òRuby¥¹¥¯¥ê¥×¥È¤Ë¥³¥ó¥Ñ¥¤¥ë +.* Ruby¥¹¥¯¥ê¥×¥È¤òeval¤Ç¼Â¹Ô +¤¬ +.* ¡Ê¥¥ã¥Ã¥·¥å¤µ¤ì¤¿¡ËRuby¥¹¥¯¥ê¥×¥È¤òeval¤Ç¼Â¹Ô +¤Ë¤Ê¤ê¡¢eRuby¥Õ¥¡¥¤¥ë¤ò¥³¥ó¥Ñ¥¤¥ë¤¹¤ë½èÍý¤¬¾Ê¤±¤ë¡£ + + +¡ý¹â®²½¤½¤Î7: ¥á¥½¥Ã¥É¤Ë¤·¤Æ¤·¤Þ¤¦ + + + + +¡ý¤Þ¤È¤á + +.* ¡Ö¹½Ê¸²òÀϡפè¤ê¡Ö¥Ñ¥¿¡¼¥ó¥Þ¥Ã¥Á¡× +.* ¡Ö¹Ô¤´¤È¤Îʬ³ä¡×¤è¤ê¡ÖÊ£¿ô¹Ô¤ÎÏ¢·ë¡× +.* ¡Öʸ»úÎó¤Ë¤·¤Æ½ÐÎϡפè¤ê¡ÖľÀܽÐÎÏ¡× +.* ¡Öʸ»úÎó¥Ð¥Ã¥Õ¥¡¡×¤è¤ê¡ÖÇÛÎó¥Ð¥Ã¥Õ¥¡¡× +.* ¡Ö¥ê¥Æ¥é¥ë¡×¤è¤ê¡ÖÄê¿ô¡× +.* ¡ÖC¤Ç³ÈÄ¥¥é¥¤¥Ö¥é¥ê¡×¤è¤ê¡Ö¥×¥í¥°¥é¥à¤Î¸«Ä¾¤·¡× + +¡ÖŬÅö¤Ëºî¤Ã¤¿C¥×¥í¥°¥é¥à¡×¤è¤ê¡Ö¤è¤¯¹Í¤¨¤é¤ì¤¿Ruby¥¹¥¯¥ê¥×¥È¡×¤Î¤Û¤¦¤¬¹â®¤Ê¾ì¹ç¤¬¤¢¤ë¤³¤È¤ò¼Â¾Ú¤·¤¿¡£ +¤·¤«¤·µÕ¤Ë¸À¤¨¤Ð¡¢C¤Ç½ñ¤±¤Ð¤è¤¯¹Í¤¨¤Ê¤¯¤Æ¤â¹â®¤Ë¤Ê¤ë¤ï¤±¤À¡£ + +¤â¤Ã¤È¤¤¤¨¤Ð¡Ö¤è¤¯¹Í¤¨¤é¤ì¤¿Ruby¥¹¥¯¥ê¥×¥È¡×¤Ï¡ÖŬÅö¤Ëºî¤Ã¤¿C¥×¥í¥°¥é¥à¡×¤è¤ê¹â®¤Ë¤Ê¤ë¤³¤È¤Ï¤¢¤Ã¤Æ¤â¡¢¡Ö¤è¤¯¹Í¤¨¤é¤ì¤¿C¥×¥í¥°¥é¥à¡×¤Ë¤Ï´Ö°ã¤¤¤Ê¤¯É餱¤ë¡£ +·è¤·¤Æ¡¢C¤Ë¤è¤ë³ÈÄ¥¥×¥í¥°¥é¥à¤¬ÉÔÍפˤʤ뤳¤È¤Ï¤Ê¤¤¡£ + +ŬÅö¤Ëºî¤Ã¤¿C¥×¥í¥°¥é¥à ¢â ¤è¤¯¹Í¤¨¤é¤ì¤¿Ruby¥¹¥¯¥ê¥×¥È ¢ã ¤è¤¯¹Í¤¨¤é¤ì¤¿C¥×¥í¥°¥é¥à + + +.* httpd, ruby, mod_ruby.so¤Ïstrip¤µ¤ì¤Æ¤¤¤ë¤«¡© + .- MacOS X¤Ç¤Ïstrip¤¹¤ë¤ÈÆ°¤«¤Ê¤¤¤Î¤ÇÃí°Õ +.* apache¤ÎÀßÄê¤ÏŬÀÚ¤«¡© + .- +.* ƱÅù¤Î³ÈÄ¥¥×¥í¥°¥é¥à¤Ï¤Ê¤¤¤«¡© + .- Ruby/MySQL¤è¤êMySQL/Ruby +.* ¤½¤Î¥×¥í¥°¥é¥à¤Ï¤Û¤ó¤È¤¦¤Ë¥Ü¥È¥ë¥Í¥Ã¥¯¤Ê¤Î¤«¡© + + diff --git a/test/test-bin.rb b/test/test-bin.rb index 35b048d..3a7c773 100644 --- a/test/test-bin.rb +++ b/test/test-bin.rb @@ -4,12 +4,9 @@ ## $Date$ ## -testdir = File.dirname(File.expand_path(__FILE__)) -libdir = File.dirname(testdir) + '/lib' -$: << testdir -$: << libdir +require "#{File.dirname(__FILE__)}/test.rb" -bindir = File.dirname(testdir) + '/bin' +bindir = File.dirname(TESTDIR) + '/bin' $script = bindir + '/erubis' if test(?f, 'bin/erubis') $script = 'bin/erubis' @@ -48,14 +45,14 @@ END #_out #END SRC = <<'END' -_out = ''; _out << 'list: +_out = []; _out << 'list: '; list = ['<aaa>', 'b&b', '"ccc"'] for item in list ; _out << ' - '; _out << ( item ).to_s; _out << ' '; end ; _out << 'user: '; _out << ( defined?(user) ? user : "(none)" ).to_s; _out << ' '; -_out +_out.join END OUTPUT = <<'END' @@ -109,7 +106,7 @@ END def test_source2 @input = INPUT - @expected = SRC.sub(/^_out\s*\z/, '') + @expected = SRC.sub(/^_out(\.join)?\s*\z/, '') @options = '-x' _test() end @@ -161,14 +158,14 @@ END #_out #END @expected = <<'END' -_out = ''; _out << 'list: +_out = []; _out << 'list: '; list = ['<aaa>', 'b&b', '"ccc"'] for item in list ; _out << ' '; _out << ' - '; _out << ( item ).to_s; _out << ' '; end ; _out << ' '; _out << 'user: '; _out << ( defined?(user) ? user : "(none)" ).to_s; _out << ' '; -_out +_out.join END @options = "-sT" _test() diff --git a/test/test-engines.rb b/test/test-engines.rb index e08095f..8dfa56e 100644 --- a/test/test-engines.rb +++ b/test/test-engines.rb @@ -4,237 +4,295 @@ ## $Copyright$ ## -testdir = File.dirname(__FILE__) -libdir = testdir == '.' ? '../lib' : File.dirname(testdir) + '/lib' -$: << testdir -$: << libdir - -require 'test/unit' -#require 'test/unit/ui/console/testrunner' -require 'assert-text-equal' -require 'yaml' -require 'stringio' -require 'testutil' +require "#{File.dirname(__FILE__)}/test.rb" require 'erubis' -require 'erubis/lang/ruby' -require 'erubis/lang/php' -require 'erubis/lang/c' -require 'erubis/lang/java' -require 'erubis/lang/scheme' +require 'erubis/engine/ruby' +require 'erubis/engine/php' +require 'erubis/engine/c' +require 'erubis/engine/java' +require 'erubis/engine/scheme' +require 'erubis/engine/perl' -class ErubisTest < Test::Unit::TestCase +class EnginesTest < Test::Unit::TestCase + extend TestEnhancer #load_yaml_documents(__FILE__) - load_yaml_testdata(__FILE__) - + testdata_list = load_yaml_document(__FILE__) + define_testmethods(testdata_list) def _test() klass = Erubis.const_get(@class) - eruby = klass.new(@input, @options || {}) - actual = eruby.src + engine = klass.new(@input, @options || {}) + actual = engine.src assert_text_equal(@expected, actual) end end __END__ ---- -name: ruby1 -lang: ruby -class: Eruby -options: -input: | - <table> - <tbody> - <% i = 0 - list.each_with_index do |item, i| %> - <tr> - <td><%= i+1 %></td> - <td><%== list %></td> - </tr> - <% end %> - </tbody> - </table> - <%=== i+1 %> -expected: | - _out = ''; _out << '<table> - <tbody> - '; i = 0 - list.each_with_index do |item, i| - ; _out << ' <tr> - <td>'; _out << ( i+1 ).to_s; _out << '</td> - <td>'; _out << Erubis::XmlHelper.escape_xml( list ); _out << '</td> - </tr> - '; end - ; _out << ' </tbody> - </table> - '; $stderr.puts("*** debug: i+1=#{(i+1).inspect}"); _out << ' - '; - _out +- name: ruby1 + lang: ruby + class: Eruby + options: + input: | + <table> + <tbody> + <% i = 0 + list.each_with_index do |item, i| %> + <tr> + <td><%= i+1 %></td> + <td><%== list %></td> + </tr> + <% end %> + </tbody> + </table> + <%=== i+1 %> + expected: | + _out = []; _out << '<table> + <tbody> + '; i = 0 + list.each_with_index do |item, i| + ; _out << ' <tr> + <td>'; _out << ( i+1 ).to_s; _out << '</td> + <td>'; _out << Erubis::XmlHelper.escape_xml( list ); _out << '</td> + </tr> + '; end + ; _out << ' </tbody> + </table> + '; $stderr.puts("*** debug: i+1=#{(i+1).inspect}"); _out << ' + '; + _out.join ## ---- -name: php1 -lang: php -class: Ephp -options: -input: | - <table> - <tbody> - <% - $i = 0; - foreach ($list as $item) { - $i++; - %> - <tr> - <td><%= $i %></td> - <td><%== $item %></td> - </tr> - <% - } - %> - </tbody> - </table> - <%=== $i %> -expected: | - <table> - <tbody> - <?php - $i = 0; - foreach ($list as $item) { +- name: php1 + lang: php + class: Ephp + options: + input: | + <table> + <tbody> + <% + $i = 0; + foreach ($list as $item) { + $i++; + %> + <tr> + <td><%= $i %></td> + <td><%== $item %></td> + </tr> + <% + } + %> + </tbody> + </table> + <%=== $i %> + expected: | + <table> + <tbody> + <?php + $i = 0; + foreach ($list as $item) { $i++; - ?> - <tr> - <td><?php echo $i; ?></td> - <td><?php echo htmlspecialchars($item); ?></td> - </tr> - <?php - } - ?> - </tbody> - </table> - <?php error_log('*** debug: $i='.($i), 0); ?> + ?> + <tr> + <td><?php echo $i; ?></td> + <td><?php echo htmlspecialchars($item); ?></td> + </tr> + <?php + } + ?> + </tbody> + </table> + <?php error_log('*** debug: $i='.($i), 0); ?> ## ---- -name: c1 -lang: c -class: Ec -options: { :filename: foo.html, :indent: ' ' } -input: |4 - <table> - <tbody> - <% for (i = 0; i < list; i++) { %> - <tr> - <td><%= "%d", i %></td> - <td><%== "%s", list[i] %></td> - </tr> - <% } %> - </tbody> - </table> - <%=== "%d", i %> -expected: | - # 1 "foo.html" - fputs("<table>\n" - " <tbody>\n", stdout); - for (i = 0; i < list; i++) { - fputs(" <tr>\n" - " <td>", stdout); fprintf(stdout, "%d", i); fputs("</td>\n" - " <td>", stdout); fprintf(stdout, "%s", list[i]); fputs("</td>\n" - " </tr>\n", stdout); - } - fputs(" </tbody>\n" - "</table>\n", stdout); - fprintf(stderr, "*** debug: i=" "%d", i); fputs("\n", stdout); +- name: c1 + lang: c + class: Ec + options: { :filename: foo.html, :indent: ' ' } + input: |4 + <table> + <tbody> + <% for (i = 0; i < list; i++) { %> + <tr> + <td><%= "%d", i %></td> + <td><%== "%s", list[i] %></td> + </tr> + <% } %> + </tbody> + </table> + <%=== "%d", i %> + expected: | + #line 1 "foo.html" + fputs("<table>\n" + " <tbody>\n", stdout); + for (i = 0; i < list; i++) { + fputs(" <tr>\n" + " <td>", stdout); fprintf(stdout, "%d", i); fputs("</td>\n" + " <td>", stdout); fprintf(stdout, "%s", escape(list[i])); fputs("</td>\n" + " </tr>\n", stdout); + } + fputs(" </tbody>\n" + "</table>\n", stdout); + fprintf(stderr, "*** debug: i=" "%d", i); fputs("\n", stdout); ## ---- -name: java1 -lang: java -class: Ejava -options: { :outclass: StringBuilder, :indent: ' ' } -input: | - <table> - <tbody> - <% - int i = 0; - for (Iterator it = list.iterator(); it.hasNext(); ) { - String s = (String)it.next(); - i++; - %> - <tr class="<%= i%2==0 ? "even" : "odd" %>"> - <td><%= i %></td> - <td><%== s %></td> - </tr> - <% - } - %> - <tbody> - </table> - <%=== i %> -expected: |4 - StringBuilder _out = new StringBuilder(); - _out.append("<table>\n" - + " <tbody>\n"); - - int i = 0; - for (Iterator it = list.iterator(); it.hasNext(); ) { - String s = (String)it.next(); - i++; +- name: java1 + lang: java + class: Ejava + options: { :out: _buf, :indent: ' ' } + input: | + <table> + <tbody> + <% + int i = 0; + for (Iterator it = list.iterator(); it.hasNext(); ) { + String s = (String)it.next(); + i++; + %> + <tr class="<%= i%2==0 ? "even" : "odd" %>"> + <td><%= i %></td> + <td><%== s %></td> + </tr> + <% + } + %> + <tbody> + </table> + <%=== i %> + expected: |4 + _buf.append("<table>\n" + + " <tbody>\n"); + + int i = 0; + for (Iterator it = list.iterator(); it.hasNext(); ) { + String s = (String)it.next(); + i++; + + _buf.append(" <tr class=\""); _buf.append(i%2==0 ? "even" : "odd"); _buf.append("\">\n" + + " <td>"); _buf.append(i); _buf.append("</td>\n" + + " <td>"); _buf.append(escape(s)); _buf.append("</td>\n" + + " </tr>\n"); - _out.append(" <tr class=\""); _out.append(i%2==0 ? "even" : "odd"); _out.append("\">\n" - + " <td>"); _out.append(i); _out.append("</td>\n" - + " <td>"); _out.append(s); _out.append("</td>\n" - + " </tr>\n"); - - } - - _out.append(" <tbody>\n" - + "</table>\n"); - System.err.println("*** debug: i="+(i)); _out.append("\n"); ---- -name: scheme1 -lang: scheme -class: Escheme -options: { :func: 'display' } -input: | - <% (let ((i 0)) %> - <table> - <tbody> - <% - (for-each - (lambda (item) - (set! i (+ i 1)) - %> - <tr> - <td><%= i %></td> - <td><%= item %></td> - </tr> - <% - ); lambda end - list); for-each end - %> - </tbody> - </table> - <%=== i %> - <% ); let end %> -expected: |4 - (let ((i 0)) - (display "<table> - <tbody> - ") - (for-each - (lambda (item) - (set! i (+ i 1)) - - (display " <tr> - <td>")(display i)(display "</td> - <td>")(display item)(display "</td> - </tr> - ") - ); lambda end - list); for-each end - - (display " </tbody> - </table> - ")(display "*** debug: i=")(display i)(display " - ") ); let end + } + + _buf.append(" <tbody>\n" + + "</table>\n"); + System.err.println("*** debug: i="+(i)); _buf.append("\n"); +## +- name: scheme1 + lang: scheme + class: Escheme + options: + input: &scheme1_input| + <% (let ((i 0)) %> + <table> + <tbody> + <% + (for-each + (lambda (item) + (set! i (+ i 1)) + %> + <tr> + <td><%= i %></td> + <td><%== item %></td> + </tr> + <% + ); lambda end + list); for-each end + %> + </tbody> + </table> + <%=== i %> + <% ); let end %> + expected: |4 + (let ((_out '())) (define (_add x) (set! _out (cons x _out))) (let ((i 0)) + (_add "<table> + <tbody> + ") + (for-each + (lambda (item) + (set! i (+ i 1)) + + (_add " <tr> + <td>")(_add i)(_add "</td> + <td>")(_add (escape item))(_add "</td> + </tr> + ") + ); lambda end + list); for-each end + + (_add " </tbody> + </table> + ")(display "*** debug: i=")(display i)(display "\n")(_add " + ") ); let end + (reverse _out)) + +## +- name: scheme2 + lang: scheme + class: Escheme + options: { :func: 'display' } + input: *scheme1_input + expected: |4 + (let ((i 0)) + (display "<table> + <tbody> + ") + (for-each + (lambda (item) + (set! i (+ i 1)) + + (display " <tr> + <td>")(display i)(display "</td> + <td>")(display (escape item))(display "</td> + </tr> + ") + ); lambda end + list); for-each end + + (display " </tbody> + </table> + ")(display "*** debug: i=")(display i)(display "\n")(display " + ") ); let end +## +- name: perl1 + lang: perl + class: Eperl + options: + input: | + <% + my $user = 'Erubis'; + my @list = ('<aaa>', 'b&b', '"ccc"'); + %> + <p>Hello <%= $user %>!</p> + <table> + <tbody> + <% $i = 0; %> + <% for $item (@list) { %> + <tr bgcolor=<%= ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF' %>"> + <td><%= $i %></td> + <td><%== $item %></td> + </tr> + <% } %> + </tbody> + </table> + <%=== $i %> + expected: |4 + + my $user = 'Erubis'; + my @list = ('<aaa>', 'b&b', '"ccc"'); + + print('<p>Hello '); print($user); print('!</p> + <table> + <tbody> + '); $i = 0; + for $item (@list) { + print(' <tr bgcolor='); print(++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF'); print('"> + <td>'); print($i); print('</td> + <td>'); print(escape($item)); print('</td> + </tr> + '); } + print(' </tbody> + </table> + '); print('*** debug: $i=', $i, "\n");print(' + '); diff --git a/test/test-erubis.rb b/test/test-erubis.rb index 8e3aa79..3de70f7 100644 --- a/test/test-erubis.rb +++ b/test/test-erubis.rb @@ -4,589 +4,773 @@ ## $Copyright$ ## -testdir = File.dirname(__FILE__) -libdir = testdir == '.' ? '../lib' : File.dirname(testdir) + '/lib' -$: << testdir -$: << libdir +require "#{File.dirname(__FILE__)}/test.rb" -require 'test/unit' -#require 'test/unit/ui/console/testrunner' -require 'assert-text-equal' -require 'yaml' require 'stringio' require 'erubis' +require 'erubis/engine/enhanced' require 'erubis/engine/optimized' class ErubisTest < Test::Unit::TestCase + extend TestEnhancer - #str = DATA.read() - str = File.read(__FILE__) - str.gsub!(/.*^__END__$/m, '') + testdata_list = load_yaml_document(__FILE__) + define_testmethods(testdata_list) - @@ydocs = {} - YAML.load_documents(str) do |ydoc| - name = ydoc['name'] - raise "*** test name '#{name}' is duplicated." if @@ydocs[name] - ydoc.each do |key, val| - if key[-1] == ?* - key = key.sub(/\*\z/, '') - val = val[$target] - ydoc[key] = val - end - end - @@ydocs[name] = ydoc - s = <<-END - def test_#{name} - @name = #{name.dump} - _test() - end - END - eval s - end def _test() - ydoc = @@ydocs[@name] - input = ydoc['input'] - src = ydoc['src'].gsub(/\^/, ' ') - output = ydoc['output'].gsub(/\^/, ' ') - klass = ydoc['class'] ? (eval "Erubis::#{ydoc['class']}") : Erubis::Eruby - options = ydoc['options'] || {} - testopt = ydoc['testopt'] + @src.gsub!(/\^/, ' ') + @output.gsub!(/\^/, ' ') if @output.is_a?(String) + @klass = @class ? Erubis.const_get(@class) : Erubis::Eruby + @options ||= {} - if testopt != 'load_file' - eruby = klass.new(input, options) + if @testopt != 'load_file' + eruby = @klass.new(@input, @options) else - filename = "tmp.#{name}.eruby" + filename = "tmp.#{@name}.eruby" begin - File.open(filename, 'w') { |f| f.write(input) } - eruby = klass.load_file(filename, options) + File.open(filename, 'w') { |f| f.write(@input) } + eruby = @klass.load_file(filename, @options) ensure File.unlink(filename) if test(?f, filename) end end - assert_text_equal(src, eruby.src) + assert_text_equal(@src, eruby.src) - return if testopt == 'skip_output' + return if @testopt == 'skip_output' context = {} - context[:list] = ['<aaa>', 'b&b', '"ccc"'] + context[:list] = list = ['<aaa>', 'b&b', '"ccc"'] - if testopt != 'stdout' - actual = eruby.evaluate(context) - assert_text_equal(output, actual) - else + case @testopt + when/\Aeval\(/ + eval eruby.src + actual = eval @testopt + assert_text_equal(@output, actual) + when 'stdout', 'print' begin orig = $stdout $stdout = stringio = StringIO.new actual = eruby.evaluate(context) ensure - $stdout = orig if orig + $stdout = orig end - assert_nil(actual) - assert_text_equal(output, stringio.string) + if @testopt == 'stdout' + assert_equal("", actual) + else + assert_nil(actual) + end + assert_text_equal(@output, stringio.string) + else + actual = eruby.evaluate(context) + assert_text_equal(@output, actual) end end end __END__ ---- -name: basic1 -input: | - <ul> - <% for item in list %> - <li><%= item %></li> - <% end %> - </ul> -src: | - _out = ''; _out << '<ul> - '; for item in list - ; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> - '; end - ; _out << '</ul> - '; - _out -output: | - <ul> - <li><aaa></li> - <li>b&b</li> - <li>"ccc"</li> - </ul> +- name: basic1 + input: &basic1_input| + <ul> + <% for item in list %> + <li><%= item %></li> + <% end %> + </ul> + src: | + _out = []; _out << '<ul> + '; for item in list + ; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> + '; end + ; _out << '</ul> + '; + _out.join + output: &basic1_output| + <ul> + <li><aaa></li> + <li>b&b</li> + <li>"ccc"</li> + </ul> ## ---- -name: basic2 -input: | - <ul> - <% i = 0 - for item in list - i += 1 - %> - <li><%= item %></li> - <% end %> - </ul> -src: | - _out = ''; _out << '<ul> - '; i = 0 - for item in list +- name: basic2 + input: | + <ul> + <% i = 0 + for item in list + i += 1 + %> + <li><%= item %></li> + <% end %> + </ul> + src: | + _out = []; _out << '<ul> + '; i = 0 + for item in list + i += 1 + ^^^ + ; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> + '; end + ; _out << '</ul> + '; + _out.join + output: *basic1_output +# <ul> +# <li><aaa></li> +# <li>b&b</li> +# <li>"ccc"</li> +# </ul> +## +- name: basic3 + input: | + <ul><% i = 0 + for item in list + i += 1 %><li><%= item %></li><% end %> + </ul> + src: | + _out = []; _out << '<ul>'; i = 0 + for item in list + i += 1 ; _out << '<li>'; _out << ( item ).to_s; _out << '</li>'; end ; _out << ' + '; _out << '</ul> + '; + _out.join + output: | + <ul><li><aaa></li><li>b&b</li><li>"ccc"</li> + </ul> +## +- name: quotation1 + desc: single quotation and backslash + class: Eruby + input: "ation1_input| + a = "'" + b = "\"" + c = '\'' + src: | + _out = []; _out << 'a = "\'" + b = "\\"" + c = \'\\\'\' + '; + _out.join + output: *quotation1_input +## +- name: pattern1 + options: + :pattern : '\[@ @\]' + input: | + <ul> + [@ for item in list @] + <li>[@= item @]</li> + [@ end @] + </ul> + src: | + _out = []; _out << '<ul> + '; for item in list + ; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> + '; end + ; _out << '</ul> + '; + _out.join + output: *basic1_output +# <ul> +# <li><aaa></li> +# <li>b&b</li> +# <li>"ccc"</li> +# </ul> +## +- name: pattern2 + options: + :pattern : '<(?:!--)?% %(?:--)?>' + input: | + <ul> + <!--% for item in list %--> + <li><%= item %></li> + <!--% end %--> + </ul> + src: | + _out = []; _out << '<ul> + '; for item in list + ; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> + '; end + ; _out << '</ul> + '; + _out.join + output: *basic1_output +# <ul> +# <li><aaa></li> +# <li>b&b</li> +# <li>"ccc"</li> +# </ul> +## +- name: trim1 + options: + :trim : false + input: *basic1_input +# <ul> +# <% for item in list %> +# <li><%= item %></li> +# <% end %> +# </ul> + src: | + _out = []; _out << '<ul> + '; _out << ' '; for item in list ; _out << ' + '; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> + '; _out << ' '; end ; _out << ' + '; _out << '</ul> + '; + _out.join + output: | + <ul> + ^ + <li><aaa></li> + ^ + <li>b&b</li> + ^ + <li>"ccc"</li> + ^ + </ul> +## +- name: ignore1 + input: | + <ul> + <%# i = 0 %> + <% for item in list %> + <%# i += 1 - ^^^ - ; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> - '; end - ; _out << '</ul> - '; - _out -output: | - <ul> - <li><aaa></li> - <li>b&b</li> - <li>"ccc"</li> - </ul> + color = i % 2 == 0 ? '#FFCCCC' : '#CCCCFF' + %> + <li> <%#= i %> : <%= item %> </li> + <% end %> + </ul> + src: | + _out = []; _out << '<ul> + '; + ; for item in list + ; + + + + ; _out << ' <li> ';; _out << ' : '; _out << ( item ).to_s; _out << ' </li> + '; end + ; _out << '</ul> + '; + _out.join + output: | + <ul> + <li> : <aaa> </li> + <li> : b&b </li> + <li> : "ccc" </li> + </ul> ## ---- -name: basic3 -input: | - <ul><% i = 0 - for item in list - i += 1 %><li><%= item %></li><% end %> - </ul> -src: | - _out = ''; _out << '<ul>'; i = 0 - for item in list - i += 1 ; _out << '<li>'; _out << ( item ).to_s; _out << '</li>'; end ; _out << ' - '; _out << '</ul> - '; - _out -output: | - <ul><li><aaa></li><li>b&b</li><li>"ccc"</li> - </ul> +- name: loadfile1 + testopt: load_file + #input: | + # <ul> + # <% for item in list %> + # <li><%= item %></li> + # <% end %> + # </ul> + input: + "<ul>\r\n <% for item in list %>\r\n <li><%= item %></li>\r\n <% end %>\r\n</ul>\r\n" + #src: | + # _out = ''; _out << "<ul>\n" + # for item in list + # _out << " <li>"; _out << ( item ).to_s; _out << "</li>\n" + # end + # _out << "</ul>\n" + # _out + src: + "_out = []; _out << '<ul>\r\n'; for item in list \r\n; _out << ' <li>'; _out << ( item ).to_s; _out << '</li>\r\n'; end \r\n; _out << '</ul>\r\n';\n_out.join\n" + #output: | + # <ul> + # <li><aaa></li> + # <li>b&b</li> + # <li>"ccc"</li> + # </ul> + output: + "<ul>\n <li><aaa></li>\n <li>b&b</li>\n <li>\"ccc\"</li>\n</ul>\n" + # "<ul>\r\n <li><aaa></li>\r\n <li>b&b</li>\r\n <li>\"ccc\"</li>\r\n</ul>\r\n" ## ---- -name: quotation1 -desc: single quotation and backslash -class: Eruby -input: | - a = "'" - b = "\"" - c = '\'' -src: | - _out = ''; _out << 'a = "\'" - b = "\\"" - c = \'\\\'\' - '; - _out -output: | - a = "'" - b = "\"" - c = '\'' +- name: nomatch1 + desc: bug + input: &nomatch1| + <ul> + <li>foo</li> + </ul> + src: | + _out = []; _out << '<ul> + <li>foo</li> + </ul> + '; + _out.join + output: *nomatch1 ## ---- -name: pattern1 -options: - :pattern : '\[@ @\]' -input: | - <ul> - [@ for item in list @] - <li>[@= item @]</li> - [@ end @] - </ul> -src: | - _out = ''; _out << '<ul> - '; for item in list - ; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> - '; end - ; _out << '</ul> - '; - _out -output: | - <ul> - <li><aaa></li> - <li>b&b</li> - <li>"ccc"</li> - </ul> +- name: xml1 + class: XmlEruby + input: | + <pre> + <% for item in list %> + <%= item %> + <%== item %> + <% end %> + </pre> + src: | + _out = []; _out << '<pre> + '; for item in list + ; _out << ' '; _out << Erubis::XmlHelper.escape_xml( item ); _out << ' + '; _out << ' '; _out << ( item ).to_s; _out << ' + '; end + ; _out << '</pre> + '; + _out.join + output: | + <pre> + <aaa> + <aaa> + b&b + b&b + "ccc" + "ccc" + </pre> ## ---- -name: pattern2 -options: - :pattern : '<(?:!--)?% %(?:--)?>' -input: | - <ul> - <!--% for item in list %--> - <li><%= item %></li> - <!--% end %--> - </ul> -src: | - _out = ''; _out << '<ul> - '; for item in list - ; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> - '; end - ; _out << '</ul> - '; - _out -output: | - <ul> - <li><aaa></li> - <li>b&b</li> - <li>"ccc"</li> - </ul> +- name: xml2 + class: XmlEruby + testopt: skip_output + input: | + <% for item in list %> + <%= item["var#{n}"] %> + <%== item["var#{n}"] %> + <%=== item["var#{n}"] %> + <%==== item["var#{n}"] %> + <% end %> + src: | + _out = []; for item in list + ; _out << ' '; _out << Erubis::XmlHelper.escape_xml( item["var#{n}"] ); _out << ' + '; _out << ' '; _out << ( item["var#{n}"] ).to_s; _out << ' + '; _out << ' '; $stderr.puts("*** debug: item[\"var\#{n}\"]=#{(item["var#{n}"]).inspect}"); _out << ' + '; _out << ' '; _out << ' + '; end + ; + _out.join + output: | ## ---- -name: trim1 -options: - :trim : false -input: | - <ul> - <% for item in list %> - <li><%= item %></li> - <% end %> - </ul> -src: | - _out = ''; _out << '<ul> - '; _out << ' '; for item in list ; _out << ' - '; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> - '; _out << ' '; end ; _out << ' - '; _out << '</ul> - '; - _out -output: | - <ul> - ^ - <li><aaa></li> - ^ - <li>b&b</li> - ^ - <li>"ccc"</li> - ^ - </ul> +- name: printstatement1 + class: PrintStatementEruby + testopt: print + input: *basic1_input + src: |4 + print '<ul> + '; for item in list + ; print ' <li>'; print(( item ).to_s); print '</li> + '; end + ; print '</ul> + '; + output: *basic1_output ## ---- -name: ignore1 -input: | - <ul> - <%# i = 0 %> - <% for item in list %> - <%# - i += 1 - color = i % 2 == 0 ? '#FFCCCC' : '#CCCCFF' - %> - <li> <%#= i %> : <%= item %> </li> - <% end %> - </ul> -src: | - _out = ''; _out << '<ul> - '; - ; for item in list - ; - - - - ; _out << ' <li> ';; _out << ' : '; _out << ( item ).to_s; _out << ' </li> - '; end - ; _out << '</ul> - '; - _out -output: | - <ul> - <li> : <aaa> </li> - <li> : b&b </li> - <li> : "ccc" </li> - </ul> +- name: printenabled1 + class: PrintEnabledEruby + input: &printenabled1_input| + <ul> + <% for item in list %> + <li><% print item %></li> + <% end %> + </ul> + src: | + @_out = _out = []; _out << '<ul> + '; for item in list + ; _out << ' <li>'; print item ; _out << '</li> + '; end + ; _out << '</ul> + '; + _out.join + output: *basic1_output +# <ul> +# <li><aaa></li> +# <li>b&b</li> +# <li>"ccc"</li> +# </ul> ## ---- -name: xml1 -class: XmlEruby -input: | - <pre> - <% for item in list %> - <%= item %> - <%== item %> - <% end %> - </pre> -src: | - _out = ''; _out << '<pre> - '; for item in list - ; _out << ' '; _out << Erubis::XmlHelper.escape_xml( item ); _out << ' - '; _out << ' '; _out << ( item ).to_s; _out << ' - '; end - ; _out << '</pre> - '; - _out -output: | - <pre> - <aaa> - <aaa> - b&b - b&b - "ccc" - "ccc" - </pre> +- name: printenabled2 + class: PrintEnabledXmlEruby + input: *printenabled1_input +# <ul> +# <% for item in list %> +# <li><% print item %></li> +# <% end %> +# </ul> + src: | + @_out = _out = []; _out << '<ul> + '; for item in list + ; _out << ' <li>'; print item ; _out << '</li> + '; end + ; _out << '</ul> + '; + _out.join + output: *basic1_output +# <ul> +# <li><aaa></li> +# <li>b&b</li> +# <li>"ccc"</li> +# </ul> ## ---- -name: xml2 -class: XmlEruby -testopt: skip_output -input: | - <% for item in list %> - <%= item["var#{n}"] %> - <%== item["var#{n}"] %> - <%=== item["var#{n}"] %> - <%==== item["var#{n}"] %> - <% end %> -src: | - _out = ''; for item in list - ; _out << ' '; _out << Erubis::XmlHelper.escape_xml( item["var#{n}"] ); _out << ' - '; _out << ' '; _out << ( item["var#{n}"] ).to_s; _out << ' - '; _out << ' '; $stderr.puts("*** debug: item[\"var\#{n}\"]=#{(item["var#{n}"]).inspect}"); _out << ' - '; _out << ' '; _out << ' - '; end - ; - _out -output: | +- name: stdout1 + class: StdoutEruby + testopt: stdout + input: *basic1_input +# <ul> +# <% for item in list %> +# <li><%= item %></li> +# <% end %> +# </ul> + src: | + _out = $stdout; _out << '<ul> + '; for item in list + ; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> + '; end + ; _out << '</ul> + '; + '' + output: *basic1_output +# <ul> +# <li><aaa></li> +# <li>b&b</li> +# <li>"ccc"</li> +# </ul> ## ---- -name: print1 -class: PrintEruby -input: | - <ul> - <% for item in list %> - <li><% print item %></li> - <% end %> - </ul> -src: | - @_out = _out = ''; _out << '<ul> - '; for item in list - ; _out << ' <li>'; print item ; _out << '</li> - '; end - ; _out << '</ul> - '; - _out -output: | - <ul> - <li><aaa></li> - <li>b&b</li> - <li>"ccc"</li> - </ul> +- name: array1 + class: ArrayEruby + input: | + <ul> + <% for item in list %> + <li><%= item %></li> + <% end %> + </ul> + src: | + _out = []; _out << '<ul> + '; for item in list + ; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> + '; end + ; _out << '</ul> + '; + _out + output: + - "<ul>\n" + - " <li>" + - "<aaa>" + - "</li>\n" + - " <li>" + - "b&b" + - "</li>\n" + - " <li>" + - "\"ccc\"" + - "</li>\n" + - "</ul>\n" ## ---- -name: print2 -class: PrintXmlEruby -input: | - <ul> - <% for item in list %> - <li><% print item %></li> - <% end %> - </ul> -src: | - @_out = _out = ''; _out << '<ul> - '; for item in list - ; _out << ' <li>'; print item ; _out << '</li> - '; end - ; _out << '</ul> - '; - _out -output: | - <ul> - <li><aaa></li> - <li>b&b</li> - <li>"ccc"</li> - </ul> +- name: stringbuffer1 + class: StringBufferEruby + input: *basic1_input +# <ul> +# <% for item in list %> +# <li><%= item %></li> +# <% end %> +# </ul> + src: | + _out = ''; _out << '<ul> + '; for item in list + ; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> + '; end + ; _out << '</ul> + '; + _out + output: *basic1_output +# <ul> +# <li><aaa></li> +# <li>b&b</li> +# <li>"ccc"</li> +# </ul> ## ---- -name: loadfile1 -testopt: load_file -#input: | -# <ul> -# <% for item in list %> -# <li><%= item %></li> -# <% end %> -# </ul> -input: - "<ul>\r\n <% for item in list %>\r\n <li><%= item %></li>\r\n <% end %>\r\n</ul>\r\n" -#src: | -# _out = ''; _out << "<ul>\n" -# for item in list -# _out << " <li>"; _out << ( item ).to_s; _out << "</li>\n" -# end -# _out << "</ul>\n" -# _out -src: - "_out = ''; _out << '<ul>\r\n'; for item in list \r\n; _out << ' <li>'; _out << ( item ).to_s; _out << '</li>\r\n'; end \r\n; _out << '</ul>\r\n';\n_out\n" -#output: | -# <ul> -# <li><aaa></li> -# <li>b&b</li> -# <li>"ccc"</li> -# </ul> -output: - "<ul>\n <li><aaa></li>\n <li>b&b</li>\n <li>\"ccc\"</li>\n</ul>\n" -# "<ul>\r\n <li><aaa></li>\r\n <li>b&b</li>\r\n <li>\"ccc\"</li>\r\n</ul>\r\n" +- name: simplified + class: SimplifiedEruby + input: | + <ul> + <% for item in list %> + <li> + <%= item %> + </li> + <% end %> + </ul> + src: | + _out = []; _out << '<ul> + '; for item in list ; _out << ' + <li> + '; _out << ( item ).to_s; _out << ' + </li> + '; end ; _out << ' + </ul> + '; + _out.join + output: | + <ul> + ^ + <li> + <aaa> + </li> + ^ + <li> + b&b + </li> + ^ + <li> + "ccc" + </li> + ^ + </ul> ## ---- -name: nomatch1 -desc: bug -input: | - <ul> - <li>foo</li> - </ul> -src: | - _out = ''; _out << '<ul> - <li>foo</li> - </ul> - '; - _out -output: | - <ul> - <li>foo</li> - </ul> +- name: bipattern1 + class: BiPatternEruby + #options: { :bipattern : '\[= =\]' } + input: | + <% for item in list %> + <%= item %> % <%== item %> + [= item =] = [== item =] + <% end %> + src: | + _out = []; for item in list + ; _out << ' '; _out << ( item ).to_s; _out << ' % '; _out << Erubis::XmlHelper.escape_xml( item ); _out << ' + '; _out << ' '; _out << ( item ).to_s; _out << ' = '; _out << Erubis::XmlHelper.escape_xml( item ); _out << ' + '; end + ; + _out.join + output: |4 + <aaa> % <aaa> + <aaa> = <aaa> + b&b % b&b + b&b = b&b + "ccc" % "ccc" + "ccc" = "ccc" +## +- name: bipattern2 + class: BiPatternEruby + options: { :bipattern: '\$\{ \}' } + input: | + <% for item in list %> + <%=item%> % <%==item%> + ${item} = ${=item} + <% end %> + src: | + _out = []; for item in list + ; _out << ' '; _out << (item).to_s; _out << ' % '; _out << Erubis::XmlHelper.escape_xml(item); _out << ' + '; _out << ' '; _out << (item).to_s; _out << ' = '; _out << Erubis::XmlHelper.escape_xml(item); _out << ' + '; end + ; + _out.join + output: |4 + <aaa> % <aaa> + <aaa> = <aaa> + b&b % b&b + b&b = b&b + "ccc" % "ccc" + "ccc" = "ccc" ## ---- -name: stdout1 -class: StdoutEruby -testopt: stdout -input: | - <ul> - <% for item in list %> - <li><%= item %></li> - <% end %> - </ul> -src: | - _out = $stdout; _out << '<ul> - '; for item in list - ; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> - '; end - ; _out << '</ul> - '; - nil -output: | - <ul> - <li><aaa></li> - <li>b&b</li> - <li>"ccc"</li> - </ul> +- name: percentline1 + class: PercentLineEruby + options: + input: | + <table> + % for item in list + <tr> + <td><%= item %></td> + <td><%== item %></td> + </tr> + % end + </table> + <pre> + %% double percent + % spaced percent + </pre> + src: | + _out = []; _out << '<table> + '; for item in list + ; _out << ' <tr> + <td>'; _out << ( item ).to_s; _out << '</td> + <td>'; _out << Erubis::XmlHelper.escape_xml( item ); _out << '</td> + </tr> + '; end + ; _out << '</table> + <pre> + '; _out << '% double percent + '; _out << ' % spaced percent + </pre> + '; + _out.join + output: | + <table> + <tr> + <td><aaa></td> + <td><aaa></td> + </tr> + <tr> + <td>b&b</td> + <td>b&b</td> + </tr> + <tr> + <td>"ccc"</td> + <td>"ccc"</td> + </tr> + </table> + <pre> + % double percent + % spaced percent + </pre> ## ---- -name: optimized1 -class: OptimizedEruby -input: | - <table> - <% for item in list %> - <tr> - <td><%= item %></td> - <td><%== item %></td> - </tr> - <% end %> - </table> - <ul><% for item in list %><li><%= item %></li><% end %></ul> -src: | - _out = '<table> - '; for item in list - ; _out << ' <tr> - <td>' << ( item ).to_s << '</td> - <td>' << Erubis::XmlHelper.escape_xml( item ) << '</td> - </tr> - '; end - ; _out << '</table> - <ul>'; for item in list ; _out << '<li>' << ( item ).to_s << '</li>'; end ; _out << '</ul> - ' - _out -output: | - <table> - <tr> - <td><aaa></td> - <td><aaa></td> - </tr> - <tr> - <td>b&b</td> - <td>b&b</td> - </tr> - <tr> - <td>"ccc"</td> - <td>"ccc"</td> - </tr> - </table> - <ul><li><aaa></li><li>b&b</li><li>"ccc"</li></ul> +- name: headerfooter1 + class: HeaderFooterEruby + options: + testopt: eval('ordered_list(list)') + input: | + <!--#header: + def ordered_list(list) + #--> + <ol> + <% for item in list %> + <li><%==item%></li> + <% end %> + </ol> + <!--#footer: end #--> + src: |4 + + def ordered_list(list) + + _out = []; _out << '<ol> + '; for item in list + ; _out << ' <li>'; _out << Erubis::XmlHelper.escape_xml(item); _out << '</li> + '; end + ; _out << '</ol> + '; + _out.join + end + output: | + <ol> + <li><aaa></li> + <li>b&b</li> + <li>"ccc"</li> + </ol> ## ---- -name: optimized2 -class: OptimizedXmlEruby -input: | - <table> - <% for item in list %> - <tr> - <td><%= item %></td> - <td><%== item %></td> - </tr> - <% end %> - </table> - <ul><% for item in list %><li><%= item %></li><% end %></ul> -src: | - _out = '<table> - '; for item in list - ; _out << ' <tr> - <td>' << Erubis::XmlHelper.escape_xml( item ) << '</td> - <td>' << ( item ).to_s << '</td> - </tr> - '; end - ; _out << '</table> - <ul>'; for item in list ; _out << '<li>' << Erubis::XmlHelper.escape_xml( item ) << '</li>'; end ; _out << '</ul> - ' - _out -output: | - <table> - <tr> - <td><aaa></td> - <td><aaa></td> - </tr> - <tr> - <td>b&b</td> - <td>b&b</td> - </tr> - <tr> - <td>"ccc"</td> - <td>"ccc"</td> - </tr> - </table> - <ul><li><aaa></li><li>b&b</li><li>"ccc"</li></ul> +- name: optimized1 + class: OptimizedEruby + input: &optimized1_input| + <table> + <% for item in list %> + <tr> + <td><%= item %></td> + <td><%== item %></td> + </tr> + <% end %> + </table> + <ul><% for item in list %><li><%= item %></li><% end %></ul> + src: | + _out = '<table> + '; for item in list + ; _out << ' <tr> + <td>' << ( item ).to_s << '</td> + <td>' << Erubis::XmlHelper.escape_xml( item ) << '</td> + </tr> + '; end + ; _out << '</table> + <ul>'; for item in list ; _out << '<li>' << ( item ).to_s << '</li>'; end ; _out << '</ul> + ' + _out + output: | + <table> + <tr> + <td><aaa></td> + <td><aaa></td> + </tr> + <tr> + <td>b&b</td> + <td>b&b</td> + </tr> + <tr> + <td>"ccc"</td> + <td>"ccc"</td> + </tr> + </table> + <ul><li><aaa></li><li>b&b</li><li>"ccc"</li></ul> ## ---- -name: optimized3 -desc: bug -class: OptimizedEruby -input: | - user = <%= "Foo" %> - <% for item in list %> - <%= item %> - <% end %> -src: | - _out = 'user = '; _out << ( "Foo" ).to_s << ' - '; for item in list - ; _out << ' ' << ( item ).to_s << ' - '; end - ; - _out -output: | - user = Foo - <aaa> - b&b - "ccc" +- name: optimized2 + class: OptimizedXmlEruby + input: *optimized1_input +# <table> +# <% for item in list %> +# <tr> +# <td><%= item %></td> +# <td><%== item %></td> +# </tr> +# <% end %> +# </table> +# <ul><% for item in list %><li><%= item %></li><% end %></ul> + src: | + _out = '<table> + '; for item in list + ; _out << ' <tr> + <td>' << Erubis::XmlHelper.escape_xml( item ) << '</td> + <td>' << ( item ).to_s << '</td> + </tr> + '; end + ; _out << '</table> + <ul>'; for item in list ; _out << '<li>' << Erubis::XmlHelper.escape_xml( item ) << '</li>'; end ; _out << '</ul> + ' + _out + output: | + <table> + <tr> + <td><aaa></td> + <td><aaa></td> + </tr> + <tr> + <td>b&b</td> + <td>b&b</td> + </tr> + <tr> + <td>"ccc"</td> + <td>"ccc"</td> + </tr> + </table> + <ul><li><aaa></li><li>b&b</li><li>"ccc"</li></ul> +## +- name: optimized3 + desc: bug + class: OptimizedEruby + input: | + user = <%= "Foo" %> + <% for item in list %> + <%= item %> + <% end %> + src: | + _out = 'user = '; _out << ( "Foo" ).to_s << ' + '; for item in list + ; _out << ' ' << ( item ).to_s << ' + '; end + ; + _out + output: | + user = Foo + <aaa> + b&b + "ccc" ## ---- -name: optimized4 -desc: single quotation and backslash -class: OptimizedEruby -input: | - a = "'" - b = "\"" - c = '\'' -src: | - _out = 'a = "\'" - b = "\\"" - c = \'\\\'\' - '; - _out -output: | - a = "'" - b = "\"" - c = '\'' +- name: optimized4 + desc: single quotation and backslash + class: OptimizedEruby + input: &optimized4_input| + a = "'" + b = "\"" + c = '\'' + src: | + _out = 'a = "\'" + b = "\\"" + c = \'\\\'\' + '; + _out + output: *optimized4_input ## diff --git a/test/test.rb b/test/test.rb new file mode 100644 index 0000000..243f963 --- /dev/null +++ b/test/test.rb @@ -0,0 +1,27 @@ +## +## $Rev$ +## $Release$ +## $Copyright$ +## + + +unless defined?(TESTDIR) + TESTDIR = File.dirname(__FILE__) + LIBDIR = TESTDIR == '.' ? '../lib' : File.dirname(TESTDIR) + '/lib' + $: << TESTDIR + $: << LIBDIR +end + + +require 'test/unit' +#require 'test/unit/ui/console/testrunner' +require 'assert-text-equal' +require 'yaml' +require 'testutil' + + +if $0 == __FILE__ + require "#{TESTDIR}/test-erubis.rb" + require "#{TESTDIR}/test-engines.rb" + require "#{TESTDIR}/test-bin.rb" +end diff --git a/test/testutil.rb b/test/testutil.rb new file mode 100644 index 0000000..bbd8b4c --- /dev/null +++ b/test/testutil.rb @@ -0,0 +1,86 @@ +### +### $Rev: 103 $ +### $Release$ +### $Copyright$ +### + +require 'yaml' + + +module TestEnhancer + + + module_function + + + def load_testdata(filename, options={}, &block) + _load_yaml(filename, :doc, options, &block) + end + + + def load_yaml_document(filename, options={}, &block) + _load_yaml(filename, :doc, options, &block) + end + + + def load_yaml_documents(filename, options={}, &block) + _load_yaml(filename, :docs, options, &block) + end + + + def _load_yaml(filename, type, options={}, &block) # :nodoc: + s = File.read(filename) + if filename =~ /\.rb$/ + s =~ /^__END__$/ or raise "*** error: __END__ is not found in '#{filename}'." + s = $' + end + unless options[:tabify] == false + s = s.inject('') do |sb, line| + sb << line.gsub(/([^\t]{8})|([^\t]*)\t/n) { [$+].pack("A8") } + end + end + # + case type + when :docs + hash_list = [] + YAML.load_documents(s) do |hash| hash_list << hash end + when :doc + hash_list = YAML.load(s) + else + raise "*** internal error" + end + # + identkey = options[:identkey] || 'name' + table = {} + hash_list.each do |hash| + ident = hash[identkey] + ident or raise "*** #{identkey} is not found." + table[ident] and raise "*** #{identkey} '#{ident}' is duplicated." + table[ident] = hash + yield(hash) if block + end + # + return hash_list + end + + + def define_testmethods(testdata_list, options={}, &block) + identkey = options[:identkey] || 'name' + testmethod = options[:testmethod] || '_test' + testdata_list.each do |hash| + yield(hash) if block + ident = hash[identkey] + s = "def test_#{ident}\n" + hash.each do |key, val| + code = " @#{key} = #{val.inspect}\n" + s << " @#{key} = #{val.inspect}\n" + end + s << " #{testmethod}\n" + s << "end\n" + $stderr.puts "*** load_yaml_testdata(): eval_str=<<'END'\n#{s}END" if $DEBUG + self.module_eval s + end + end + + +end |