From: Masatoshi SEKI Date: 1999-03-20T02:10:10+09:00 Subject: [ruby-list:13031] Re: Tiny eRuby ----Next_Part(Sat_Mar_20_02:10:50_1999_893)-- Content-Type: Text/Plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit 咳です。ねぼけてます。 > > ruby-dev の方で一時期話題になっていた eRuby を実装してみました。 > > ...(略)... > > HTMLの文書や定型文の作成などに便利そうです。 > > お目汚しにどうぞ。 > ろいろ使えそうですよね。LaTeX の文書にテーブルコマンドを生成する Ruby > スクリプトを埋め込んだりとか。 そうですよね。いろいろ応用がありそうです。 ePerl の方はどういう応用があるんだろう。 土岐さん、パッチありがとうございました。 ほぼそのままあてました。 ついでに自分で見つけたバグ(resultが動かない)の修正を かねて $SAFE を指定してスクリプトを実行できるようにしました。 ERb.new(文字列, [整数]) でERbを生成すると第二引数を $SAFE に設定して実行します。 CGIなどで使う時に安心できます。 ERbが $SAFE に対応できたので、shttpsrv-1.04 を改造して eRuby ファイル対応にしてみました。 近いうちにパッチを出します。 # eRuby ファイルの拡張子はなんとすれば良いのでしょう? .rhtml?? > * `<%= [値] %>' タグは `print [値]' に置換されますが、これだと snip > 値を括弧でで括って `<%= [値] %>' が `print ([値])' に置換され > るように変更しました。 すみません。 バグでした。 > * 笠原 基之さんの getoptlong ライブラリ > (http://www.sra.co.jp/people/m-kasahr/ruby/getoptlong/) > を使っていくつかオプションを追加してみました。 > -d, --debug デバッグモード > -r ライブラリのロード > -v, --version バージョンの表示 > -w 冗長モード > これらはわたしがあったらいいなと思ったオプションです。 getoptlongって標準でインストールされてるんじゃなかったんですね。 一瞬 getopts に書き直すか悩んだのですがそのままにしました。 -S 整数 $SAFE の指定 を追加しました。 -- 咳 ----Next_Part(Sat_Mar_20_02:10:50_1999_893)-- Content-Type: Text/Plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=erb.rb #!/usr/local/bin/ruby # $Id: erb.rb,v 1.19 1999/03/19 16:45:48 mas Exp $ # $Author: mas $ # Copyright (c) 1999 Masatoshi SEKI require 'enumre.rb' # http://www2a.biglobe.ne.jp/%7Eseki/ruby/enumre.rb class ERb Revision = '$Date: 1999/03/19 16:45:48 $' def version "erb.rb [#{ERb::Revision.split[1]}]" end module_function :version class StringIO def initialize(str='') @str = str.to_s end attr :str def print (*arg) if $, sep = $, else sep = '' end write(arg.join(sep)) end def write(str) @str.concat(str) end def as_stdout(&proc) begin writer = self.new save = $> $> = writer proc.call writer.str ensure $> = save if save end end module_function :as_stdout def as_stdout_safe(safe, &proc) begin writer = self.new save = $> $> = writer th = Thread.start { $SAFE = safe proc.call writer.str } Thread.join th th.value ensure $> = save if save end end module_function :as_stdout_safe end def pre_compile(s) list = [] s.each_line do |line| line.gsub!(/(<%#)|(<%=)|(<% )|( %>)/) do |m| "\n#{m}\n" end list += line.split("\n") list.push("\n") end # list からコメントを取り除く list = @comment.gsub(list) { nil } # print に置換 list = @print.gsub(list) { v = @print.matching_data[1].join ['<% ', "print (#{v})", ' %>'] } end module_function :pre_compile private :pre_compile def compile(s) cmdlist = [] str_table = [] list = pre_compile(s) # 先頭からstagまでを置換 list = @head.sub(list) { match = @head.matching_data match[1].join.each do |line| cmdlist.push("print #{line.dump}") end nil } list = @compile.gsub(list) { match = @compile.matching_data cmdlist.push(match[1].join) match[3].join.each do |line| cmdlist.push("print #{line.dump}") end nil } list.join.each do |line| cmdlist.push("print #{line.dump}") end cmdlist.join("\n") end module_function :compile private :compile def setup_compiler first = ARegexpFirst.new stag = ARegexpEq.new('<% ') etag = ARegexpEq.new(' %>') commenttag = ARegexpEq.new('<%#') printtag = ARegexpEq.new('<%=') any = ARegexpAny.new.repeat(0, nil).greedy(false) notstag = ARegexpEq.new('<% ').negate.repeat(0, nil).greedy(true) @head = ARegexp.new([first, notstag]); @comment = ARegexp.new([commenttag, any, etag]) @print = ARegexp.new([printtag, any, etag]) @compile = ARegexp.new([stag, any, etag, notstag]) end module_function :setup_compiler private :setup_compiler def initialize(str, safe_level=nil) @src = ERb.compile(str) @safe_level = safe_level end attr :src setup_compiler # 実行し、結果を印字する def run(b=TOPLEVEL_BINDING) if @safe_level print self.result(b) else eval(@src, b) end end # 実行し、結果を文字列で返す def result(b=TOPLEVEL_BINDING) if @safe_level StringIO.as_stdout_safe(@safe_level) { eval(@src, b) } else StringIO.as_stdout { eval(@src, b) } end end end if __FILE__ == $0 require "getoptlong" opt_parser = GetoptLong.new([ "-x", GetoptLong::NO_ARGUMENT ], [ "-n", GetoptLong::NO_ARGUMENT ], [ "-d", "--debug", GetoptLong::NO_ARGUMENT ], [ "-S", GetoptLong::REQUIRED_ARGUMENT ], [ "-r", GetoptLong::REQUIRED_ARGUMENT ], [ "-v", "--version", GetoptLong::NO_ARGUMENT ], [ "-w", GetoptLong::NO_ARGUMENT ]) opt_parser.each_option do |name, arg| case name when "-x" # ruby source $output = true when "-n" # line number $number = true when "-w" # verbose $VERBOSE = true when "-v" # version STDERR.puts ERb.version exit when "-d" # debug $DEBUG = true when "-r" # require require arg when "-S" # safe level $safe_level = arg.to_i end end src = $<.read exit 1 unless src erb = ERb.new(src, $safe_level) if $output if $number l = 1 for line in erb.src puts "%3d %s"%[l, line] l += 1 end else puts erb.src end else erb.run end end ----Next_Part(Sat_Mar_20_02:10:50_1999_893)----