Ruby Tips!

RubyのTipsを紹介します

ファイルの最後にデータを追記する

ファイルの最後にデータを追記するには、openのオプションにaを指定して追記モードでファイルをオープンして、書き込みを行えば良い。

open('foo.txt', 'a'){|f|
  f.puts 'hoge'
}

ファイルをオープンするオプションの詳細についてはファイルを開く - Ruby Tips!を参照。

配列の中から最大値・最小値を求める

配列の中から最大値・最小値を求めるにはArray#maxArray#minを使う。

p [1, 2, 3, 4, 5].max #=> 5
p [1, 2, 3, 4, 5].min #=> 1

デフォルトでは最大値・最小値を求めるための比較は<=>で行われる。ブロックを渡すと比較の処理を置き換えることができる。例えば文字列を数値化して比較するには以下のように書ける。

p ["1", "2", "3", "4", "5"].max{|a, b| a.to_i <=> b.to_i } #=> "5"
p ["1", "2", "3", "4", "5"].min{|a, b| a.to_i <=> b.to_i } #=> "1"

上記ではArray#maxArray#minを使ったが、比較の前にオブジェクトを事前に変換するのであれば、Array#max_byArray#min_byを使って、同様の処理が以下のように書ける。

p ["1", "2", "3", "4", "5"].max_by{|o| o.to_i } #=> "5"
p ["1", "2", "3", "4", "5"].min_by{|o| o.to_i } #=> "1"

TCPクライアントを実装する

TCPクライアントを実装するにはsocketライブラリのTCPSocketを使う。以下は簡単なHTTPクライアントの例である。

require 'socket'
TCPSocket.open('www.yahoo.co.jp', 80){|s|
  s.print "GET / HTTP/1.0\r\n\r\n"
  print s.read
}

TCPSocket.openには、接続先のIPまたはホスト名と、ポート番号を指定する。ブロックには接続済みのソケットが渡される。ソケットはIOのサブクラスなので、IOと同様にprintreadといったメソッドを使って、自由に通信することができる。ブロックを抜けるとソケットは自動的にcloseで閉じられる。

TCPSocket.openにブロックを渡さない場合は、接続済みのソケットが返される。こちらは通信が終わったら自分でTCPSocket#closeで通信を閉じる必要がある。以下は上記のコードをブロックを使わずに書きなおした例である。

require 'socket'
begin
  s = TCPSocket.open('www.yahoo.co.jp', 80)
  s.print "GET / HTTP/1.0\r\n\r\n"
  print s.read
ensure
  s.close if s
end

Rubyの文字列リテラルについて

Rubyには多数の文字列リテラルが存在する。1つずつ見てみよう。

まず式展開が不要な文字列はシングルクオート'を使う。'\以外、エスケープが不要なのも利点である。

p 'foo' #=> "foo"

式展開が必要な文字列はダブルクオート"を使う。Rubyの文字列の中で最も基本的なリテラルと言えるだろう。

p "foo" #=> "foo"

式展開が不要で、記号を多用したい場合は、%qによる文字列リテラルが便利だ。リテラルを囲う文字は自由に選択できる。また改行を含むこともできる。

p %q(foo) #=> "foo"

%Q%qの式展開ありのバージョンだ。式展開が必要な場合はこちらを使う。

p %Q(foo) #=> "foo"

文字列が複数行に渡る場合はヒアドキュメントを使うと良い。ヒアドキュメント中でも式展開が利用できる。

p <<STR
foo
bar
buz
STR
#=> "foo\nbar\nbuz\n"

ヒアドキュメントは<<の代わりに<<-を使うと、終端行をインデントすることができる。

  p <<-STR
foo
bar
buz
  STR
#=> "foo\nbar\nbuz\n"

また識別子を'で囲んだシングルクオートヒアドキュメントでは、\を含めて、囲んだ文字列がそのまま文字列となる。

p <<'STR'
foo\
bar\
buz\
STR
#=> "foo\\\nbar\\\nbuz\\\n"

平方根を求める

Rubyで数値の平方根を求めるにはMath.sqrtを使う。また、平方根はべき乗Numeric#**を使って、1/2乗として求めることもできる。負の数の平方根複素数を表すComplexオブジェクトとして得られる。

require 'complex'
p Math.sqrt(2) #=> 1.4142135623730951
p 2 ** 0.5 #=> 1.4142135623730951
p Math.sqrt(-2) #=> (0+1.4142135623730951i)

文字を置換する

文字列中のある文字を別の文字に置換するにはString#trが利用できる。以下は文字bを、Bに置換する例である。

p "foo bar buz".tr('b', 'B') #=> "foo Bar Buz"

String#trの引数に複数文字からなる文字列を指定すると、両方に対応する位置の文字にそれぞれ置換される。以下はbBに、fFに置換する例である。

p "foo bar buz".tr('bf', 'BF') #=> "Foo Bar Buz"

文字列を置換する

文字列を置換するにはString#subまたはString#gsubを使う。String#subはマッチした最初の1つだけを、String#gsubはマッチしたすべての文字列を置換した新しい文字列を返す。

これらのメソッドの基本的な使い方は第1引数に置換対象の文字列か正規表現を指定し、第2引数に置換後の文字列を指定する方法だ。

p "foo bar buz".sub('b', 'p') #=> "foo par buz"
p "foo bar buz".gsub(/b/, 'p') #=> "foo par puz"

第2引数を指定する代わりに、ブロックを指定することもできる。この場合はブロックの評価結果で置換対象の文字列が置換される。より複雑な置換を行うことが可能だ。

p "foo bar buz".gsub(/b\w*/){|m| m.upcase } #=> "foo BAR BUZ"

なお、これらのメソッドには、新しい文字列を返すのではなく、文字列を破壊的に置換するString#sub!String#gsub!もある。