CGI::escapeHTML

CGI::escapeHTMLメソッドを使うと、HTMLのエスケープが行われます。to_sをつけてから与えないとエラーになってしまいました。おそらくescapeHTMLメソッドに文字列以外を渡してしまうとまずいのでしょう。
疑問 CGI::escapeHTMLとCGI.escapeHTMLはどこが違うのでしょう。どちらでも動くようですが、ニュアンスはどう異なるのでしょう。::はスコープ演算子、.はクラスメソッドということだと思うのですが…。Perlな人には::のほうが親しみやすいとは思いますけれど。→コロンとピリオド

#!ruby
require "cgi"

cgi = CGI.new

print <<"EOD"
Content-type: text/html

<html>
<title>Hello</title>
<body>
<h1>Hello</h1>
<form method="post">
name:
<br>
<input type="text" name="name" value="">
<br>
message:
<br>
<textarea name="message">
</textarea>
<br>
<input type="submit" value="send">
</form>
<hr>
<dl>
    <dt>name</dt><dd>#{CGI::escapeHTML(cgi.params["name"].to_s)}</dd>
    <dt>message</dt><dd>#{CGI::escapeHTML(cgi.params["message"].to_s)}</dd>
</dl>
</body>
</html>
EOD

CGI.new

CGI.newで得たオブジェクトはハッシュです。与えられたフィールドはcgi.params[フィールド名]で得ることができます。
以下のCGIでは、ユーザが入力した文字列をエスケープせずに出力しますので、XSS脆弱性があります。

#!ruby
require "cgi"

cgi = CGI.new

print <<"EOD"
Content-type: text/html

<html>
<title>Hello</title>
<body>
<h1>Hello</h1>
<form method="post">
name:
<br>
<input type="text" name="name" value="">
<br>
message:
<br>
<textarea name="message">
</textarea>
<br>
<input type="submit" value="send">
</form>
<hr>
<dl>
    <dt>name</dt><dd>#{cgi.params["name"]}</dd>
    <dt>message</dt><dd>#{cgi.params["message"]}</dd>
</dl>
</body>
</html>
EOD

CGI

だいぶ練習できたので、そろそろCGIに挑戦してみます。

#!ruby
print <<"EOD"
Content-type: text/html

<html>
<title>Hello</title>
<body>
<h1>Hello</h1>
</body>
</html>
EOD

open("| command", "r")

openの第一引数を|で始めるとコマンドを意味します。第二引数が"r"なら実行結果から読み込むことができます。ブロックパラメータはIOオブジェクトです。

open("| dir /s/b", "r") { |file|
    print file.class, "\n"
    while line = file.gets
        print "-- #{line.chomp} --\n"
    end
}

Time.now

Time.nowは現在日時を返します。Time.newと一字違いですが、やっていることは同じです。

print Time.now

行頭にclassがある行を検索

標準入力の各行に対して処理を行うというのは基本的なパターンです。行頭にclassがある行を検索してみました。

while line = gets
    if line =~ /^class/
        print $_
    end
end

getsは$_に代入

getsの戻り値は特殊変数$_にも代入されます。getsの戻り値は入力終端でnilになりますから、以下のプログラムで標準入力をすべて標準出力にコピーすることになります。

while gets
    print $_
end

ri -T -w 128

riの出力をページャを通さずに表示するには-Tオプションをつけます。
画面幅を128桁にするには-w 128オプションをつけます。

ri -T -w 128 IO#gets

loopほか

Rubyでは、times, loop, eachはメソッドで、for, while, untilはメソッドではありません。

loop {
    print "Infinite loop!\n"
}

each

timesはIntegerのメソッドでしたが、eachはArray(など)のメソッドです。

range = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
range.each { |i|
    print "i = #{i}\n"
}

until

whileに対するuntilは、ifに対するunlessのようなものですね。

i = 0
until 10 <= i
    print "i = #{i}\n"
    i += 1
end

forと配列

配列を指定してfor文をまわすこともできます。

range = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
for i in range
    print "i = #{i}\n"
end

for

範囲を指定してfor文をまわします。x..yは[x, y]で、x...yは[x, y)です。forはメソッドではありません。

for i in 0..9
    print "i = #{i}\n"
end

for i in 0...10
    print "i = #{i}\n"
end

ri -c

ri -cで、riが知っているクラスとモジュールの一覧が表示されます。

代入の有無とメソッド呼び出し

Rubyでは、変数とメソッドの区別が付かないとき、以前に代入があるかどうかを調べて判断します。

def f
    "function\n"
end

print f             # => function
f = "var\n"
print f             # => var
print f()           # => function

intern

Rubyでは、:をつけるとシンボルが得られます。同じシンボルは同じオブジェクトです。

print :Rubyco, "\n"         # => Rubyco
if :Rubyco == :Rubyco
    print "1 Same\n"        # => 1 Same
end
if :Rubyco.object_id == :Rubyco.object_id
    print "2 Same\n"        # => 2 Same
end

追記: 同じオブジェクトかどうかを比較するのに == は不適切でした。Object#equal?を使うべきでしょう。

print :Rubyco, "\n"         # => Rubyco
if :Rubyco.equal?(:Rubyco)
    print "1 Same\n"        # => 1 Same
end
if :Rubyco.object_id == :Rubyco.object_id
    print "2 Same\n"        # => 2 Same
end

追記:id:nekokakさんから、ブックマークでobject_idの比較は==でよいの?と指摘がありました。ええと、ええと…ここでは:Rubycoと:Rubycoのobject_idが同じ値かどうかを見ているだけですから、(object_idのidentityではなくequalityを調べている)ので、==でよいのではないかと思います。

print :Rubyco, "\n"         # => Rubyco
if :Rubyco.equal?(:Rubyco)
    print "1 Same\n"        # => 1 Same
end
if :Rubyco.object_id.equal?(:Rubyco.object_id)
    print "2 Same\n"        # => 2 Same
end

ちなみに、Rubyではすべてがオブジェクトなので、object_idもオブジェクトです。以下実験です。

p :Rubyco.object_id.class   #=> Fixnum

idとobject_id

Rubyで、"string".idを使おうとしたら、warning: Object#id will be deprecated; use Object#object_idという警告が出ましたのでobject_idを使います。
文字列リテラルは、コード中に出てくると新たにnewするようです。object_idが異なるのでわかります。

if "string".object_id != "string".object_id
    print "Diff\n"
end
# => Diff

インデント付きヒアドキュメント

Rubyでは、<<の後に-をつけると、終端文字列にインデントをつけることができます。

print <<"EOD"
Hello, hello, hello.
Hello, hello, hello.
Hello, hello, hello.
EOD

print <<-"EOD"
    Hello, hello, hello.
    Hello, hello, hello.
    Hello, hello, hello.
    EOD