青山です。

Wed, Feb 03, 1999 at 08:30:48AM +0900 において
IKARASHI Akira さん曰く:

> CGI.pmを利用したソースを見たことはあるのですが、
> 自分でhtmlを書くときもよくタグを閉じるのを忘れてしまうので、
> start_html で始めて end_html で終わるという約束を守らないと
> うまくいかないモデルは、使いづらそうだと感じていました。

この点は同感です。HTML generator についての方に書いたように、Ruby で実
装する場合にはイタレータを利用するなどして、自然に書けるようにした方が
良いと思います。() の嵐という手もありますが...

> そこで、コンポーネント的に組み合わせていって、最終的に CGI.message を
> 使えばいいかと思っていました。適当に書いてみると、こんな感じです。
> 一般的でないのは、使いづらいからなのでしょうか?

CGI.message が良くないと思われるのは、機能と名前が不明確であるという点
です。CGI のメッセージとは何か、エラー出力や簡易メッセージの出力ならば、
text/plain の方が適切ではないか、そのようなあたりです。

また、HTML の出力としても間違った出力の元になりやすいという事もありま
す。

> input1 = CGI.tag1("INPUT", {"TYPE"=>"BUTTON", "VALUE"=>"BUTTON"})
> input2 = CGI.tag1("INPUT", {"TYPE"=>"TEXT", "VALUE"=>"TEXT"})
> form1 = CGI.tag2("FROM", input1 + input2)
> msg1 = "message<BR>"
> 
> CGI.message(msg1 + form1, "TITLE")

この場合、<P>message<BR><FORM>...</FORM></P> となりますが、P エレメン
トはブロックレベルのエレメントを含む事ができないにもかかわらず、FORM
というブロックレベルのエレメントを含んでしまっています。

つまり、P エレメントを自動的に付加してしまう CGI.message は機能的にも
制限があり、標準的機能としては不適切と思われるわけです。

(正確な解釈は <P>message<BR></P><FORM>...</FORM></P> で、包含関係の間
違いではなく </P> が余計にあるという間違いですが。)

ところで、この CGI.tag というのは面白いアイディアですね。次のような感
じにすると汎用性のあるインターフェイスになりますが、いかがでしょう。

input1 = CGI.tag("INPUT", {"TYPE"=>"BUTTON", "VALUE"=>"BUTTON"})
input2 = CGI.tag("INPUT", {"TYPE"=>"TEXT", "VALUE"=>"TEXT"})
form1  = CGI.tag("FORM"){ input1 + input2 }
msg1   = CGI.tag("P"){ "message" + CGI.tag("BR") }

print CGI.header,
      CGI.tag("HTML"){
        CGI.tag("HEAD"){ CGI.tag("TITLE"){"TITLE"} } +
        CGI.tag("BODY"){ msg1 + form1 }
      }


タブの展開でパッチはちょっと大きくなってしまいました。


--- cgi-lib.rb.org	Wed Feb  3 13:21:59 1999
+++ cgi-lib.rb	Thu Feb  4 00:33:43 1999
@@ -25,6 +25,20 @@
 #
 # print CGI.header("HTTP/1.0 200 OK", "Content-Type: text/html")
 # print CGI.header # == print CGI.header("Content-Type: text/html")
+#
+# make HTML tag string
+# CGI.tag("element", {"attribute_name"=>"attribute_value"}){"content"}
+#
+# print CGI.tag("HTML"){
+#         CGI.tag("HEAD"){ CGI.tag("TITLE"){"TITLE"} } +
+#         CGI.tag("BODY"){
+#           CGI.tag("FORM", {"ACTION"=>"test.rb", "METHOD"=>"POST"}){
+#             CGI.tag("INPUT", {"TYPE"=>"submit", "VALUE"=>"submit"})
+#           } +
+#           CGI.tag("HR")
+#         }
+#       }
+
 
 # if running on Windows(IIS or PWS) then change cwd.
 if ENV['SERVER_SOFTWARE'] =~ /^Microsoft-/ then
@@ -67,7 +81,13 @@
     str.gsub!(/%([0-9a-fA-F]{2})/){ [$1.hex].pack("c") }
     str
   end
-  module_function :escape, :unescape
+
+  # escape HTML
+  def escapeHTML(str)
+    str.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;")
+  end
+
+  module_function :escape, :unescape, :escapeHTML
 
   def initialize(input = $stdin)
 
@@ -97,12 +117,12 @@
     if ENV.has_key?('HTTP_COOKIE')
       @cookie = {}
       ENV['HTTP_COOKIE'].split("; ").each do |x|
-	key, val = x.split(/=/,2).collect{|x|unescape(x)}
-	if @cookie.include?(key)
-	  @cookie[key] += "\0" + (val or "")
-	else
-	  @cookie[key] = (val or "")
-	end
+        key, val = x.split(/=/,2).collect{|x|unescape(x)}
+        if @cookie.include?(key)
+          @cookie[key] += "\0" + (val or "")
+        else
+          @cookie[key] = (val or "")
+        end
       end
     end
   end
@@ -121,6 +141,13 @@
     (options['path']    ? '; path='    + options['path']   : '') +
     (options['expires'] ? '; expires=' + options['expires'].strftime("%a, %d %b %Y %X %Z") : '') +
     (options['secure']  ? '; secure' : '')
+  end
+
+  def CGI.tag(element, attributes = {})
+    "<" + escapeHTML(element) + attributes.collect{|name, value|
+      " " + escapeHTML(name) + '="' + escapeHTML(value) + '"'
+    }.to_s + ">" +
+    (iterator? ? yield.to_s + "</" + escapeHTML(element) + ">" : "")
   end
 
   def CGI.message(msg, title = "", header = ["Content-Type: text/html"])



-- 
青山 和光 Wakou Aoyama <wakou / fsinet.or.jp>