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
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
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が知っているクラスとモジュールの一覧が表示されます。
timesメソッド
timesメソッドによる繰り返しです。
10.times {|i| print "i = #{i}\n" }
代入の有無とメソッド呼び出し
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
インデント付きヒアドキュメント
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