前のページ 次のページ 目次

7. 組込みライブラリ

7.1 instance_methods(nil)は何を返しますか

instance_methodsは,あるクラスのオブジェクトが持つメソッドを 返しますが,instance_methods(nil)は,スーパークラスから引き継いだ ものではなく,そのクラスで初めて定義されたメソッドを返します.

7.2 randがいつも同じ乱数列を出しますが

randは,プログラムが実行される度に同じ乱数列を生成します. 異なる乱数列を生成させるためには,srandで毎回異なる乱数の 種を与えてやる必要があります.srandを引数なしで呼ぶと,その時の 時間を種にしますので,異なる乱数列を生成させることができます.

7.3 0から51の中から重複のない5つをランダムに選ぶにはどうしますか

次のメソッドは,0からnまでの数の中からm個をランダムに選んだ配列を返します.
def sample(n, m)
  if m.zero?
    []
  else
    s = sample(n-1, m-1)
    t = rand(n+1)
    s.concat s.include?(t) ? n : t
  end
end
再帰形でなく書けば,次のとおりです.
def sample(n, m)
  s = []
  ((n-m)...n).each do |j|
    t = rand(j+2)
    s.concat s.include?(t) ? j+1 : t
  end
  s
end

7.4 Fixnumtruenilfalseが 即値だということですが,参照との違いは何ですか

特異メソッドを定義できないという制限があります.また,同じ数を 表わすFixnumのインスタンスは常に同じものになりますので, インスタンス変数を定義した場合には,それも同じものを示すことに なります.

7.5 nilfalseはどう違いますか

持っているメソッドの違いは,nil.methods - false.methodsfalse.methods - nil.methodsを表示してください.

ハッシュでは,nilを値として持つことができませんが, falseを持つことはできます.

メソッドが真偽を返す時は,truefalseを,そうでない 時は値かnilを返すようにすることが好まれます.

?のつくメソッドは,真偽を返すのが一般的ですが, そうでないものもあります.

7.6 ファイルを読み込んで書き換えても変化しません

open("example", "r+").readlines.each_with_index{|l, i|
  l[0,0] = (i+1).to_s + ": "}
とやっても,exampleに行番号がつきません. ファイルを書き換えているのではなく,readlinesで読み込んだ文字列を 変えているだけです.ファイルに書き戻してやらなければいけません.
io = open("example", "r+")
ary = io.readlines
ary.each_with_index{|l, i| l[0,0] = (i+1).to_s + ": "}
io.rewind
io.print ary
io.close

7.7 同じ名前のファイルに書き戻したいのですが

コマンドラインオプションの-i,もしくは,組込み変数$-i に""を指定することにより,同じ名前のファイルに書き戻すことができます.

上の問題は,次のように書くことができます.
$ ruby -i -ne 'print "#$.: #$_"' example
元のファイルを残しておきたければ,-i.bakなどとしてください.

7.8 ファイルに書き込んでそのファイルをコピーしましたが,全部コピーされません

open('file', 'w').print "This is a file.\n"
system 'cp file copy'
とやったのでは,コピーする時にfileに内容がフラッシュされて いません.きちんとcloseしてからコピーしましょう.
f = open('file', 'w')
f.print "This is a file.\n"
f.close
system "cp file copy"

7.9 パイプでlessに文字列を渡したのですが,表示されません

f = open '|less', 'w'
f.print "abc\n"
とやっても,直ちに終了してしまい,lessで眺めることができません. closeしてやると,そこでlessの終了を待ちます.
f = open '|less', 'w'
f.print "abc\n"
f.close
最初の行は,f = IO.popen 'less', 'w'としても同じ結果となります.

7.10 参照されないFileオブジェクトはどうなりますか

open("file").readというように参照されないFile オブジェクトは,次のガーベッジコレクションでcloseされて 捨てられます.

7.11 ファイルをcloseしないのは気持ちが悪いのですが

参照されなくなったFileオブジェクトは,GCで自動的にクローズ されますが,明示的にクローズするには,次の3つの構文から選んで下さい.
(1)
a = open "file"
begin
  a.each {|l| print l}
ensure
  a.close
end
(2)
IO.foreach("file") {|l| print l}
(3)
IO.readlines("file").each {|l| print l}

7.12 ファイルを時間の新しい順にソートしたいのですが

Dir.glob("*").filter{|f| [File.mtime(f), f]}.
  sort{|a,b| b[0]<=>a[0]}.filter{|e| e[1]}
とすると,カレントディレクトリの".",".."以外のファイルを更新時間の 新しい順にソートした配列を返します.更新時間の古い順にソートする なら,sortの後ろのブロックはなしにしても,いいですね.
Dir.glob("*").sort{|a,b| File.mtime(b)<=>File.mtime(a)}
でもソートすることができますが,比較する度にファイルにアクセスして 更新時間を調べますので,ソートするのに時間がかかります.

7.13 ファイル中の単語の出現頻度を調べたいのですが

ハッシュのデフォルト値に0を指定して,次のようにすることができます.
freq = Hash.new(0)
open("file").read.scan(/\w+/){|w| freq[w] += 1}
freq.keys.sort.each {|k| print k, "--", freq[k], "\n"}

7.14 条件に文字列を使ったとき,文字列が空("")の時にもtrueになります

Rubyでは,nilfalseだけが偽で,それ以外はすべて真に なります.文字列が空かどうかを知るには,""と比較,empty?を使う, length0と比較するなどの方法があります.

7.15 英語文字列の配列を辞書順にソートしたいのですが

ary.filter{|f| [f.downcase, f]}.sort.filter{|e| e[1]}
とします.downcaseで等しくなった場合に,元の文字列で比較を行うのが tipsです.

7.16 "abcd"[0]は,何を返しますか

文字aのコード97(Fixnum)を返します.これが文字aと一致するかどうか 調べるには,?aと比較します.

7.17 タブをスペースに展開したいのですが

aに展開したい文字列があるとして,次のどれかを使えばいいでしょう.
1 while a.sub!(/(^[^\t]*)\t(\t*)/){$1+' '*(8-$1.size%8+8*$2.size)}
1 while a.sub!(/\t(\t*)/){' '*(8-$~.begin(0)%8+8*$1.size)}
a.gsub!(/([^\t]{8})|([^\t]*)\t/n){[$+].pack("A8")}

7.18 バックスラッシュをエスケープするにはどうしますか

Regexp.quote('\\')で,エスケープされます.

gsubを使う場合には,gsub(/\\/, '\\\\')では,置換文字列が 構文解析で一度'\\'に変換され,実際に置き換えるときにもう一度'\'と 解釈されるので, gsub(/\\/, '\\\\\\')とする必要があります.\&がマッチ文字列を あらわすことを使えば,gsub(/\\/,'\&\&')と書けます.

gsub(/\\/){'\\\\'}とブロックを使う形にすれば,エスケープが1回しか 解釈されませんので,求める結果が得られます.

7.19 subsub!はどう違うのですか

subの場合はレシーバの状態は変化しません.文字列のコピーが 作られ,それに置換がほどこされて(置換が必要なければそのまま)返されます.

sub!ではレシーバそのものが変更されます.変更がない時には nilが返されます.

sub!のようにレシーバの状態を変化させるメソッドを 破壊的メソッドと 呼びます.Rubyでは同名のメソッドで破壊的なものとそうでないものがある場 合,破壊的なメソッドには慣例的に!をつけます.
def foo(str)
    str = str.sub(/foo/, "baz")
end

obj = "foo"
foo(obj)
print obj
# -> "foo"

def foo(str)
    str = str.sub!(/foo/, "baz")
end

foo(obj)
print obj
# -> "baz"
sub!のように破壊的なメソッドは予期しない効果をもたらすことがある ので,使用する場合は十分注意してください.

7.20 \Zのマッチする場所はどこですか

\Zは,文字列の最後の文字が\nでない時は文字列の末尾に, \nのときはこの改行の前にマッチします.

7.21 範囲オブジェクトのコンストラクタ.....はどう違いますか

..は終端を含み,...は終端を含みません.

7.22 関数ポインタはありますか

Proc.newproclambdaでProcオブジェクトを作れば, 関数ポインタのような働きをさせることができます.

7.23 threadforkはどう使い分けるのですか

threadforkはそれぞれ以下のような特徴を持っています. 一般にforkthreadを混ぜるのはよくないようです.

あと,Rubyのthreadはタイムシェアリング方式なので,threadを使 うことによって処理が速くなることはありません.

7.24 Marshalの使い方を教えてください

オブジェクトをファイルや文字列に格納しておき,後で再生できる ようにするものです.格納は
Marshal.dump obj, io, lev
という形式で行います.ioには書き込み可能なIOオブジェクト,levは オブジェクトが内容として他のオブジェクトを持っている時に,どこ までオブジェクトの内容を格納するかを決めます.lev段までオブジェクト をdumpしてもまだオブジェクトがある時には,そのオブジェクトのdumpは オブジェクトの参照になりますので,再生した時には,参照が変わって いるでしょうから,再生できないことになります.levのデフォルトは 100になっています.ioを省略した時には,文字列でdumpされます.

再生は
obj = Marshal.load io
または,
obj = Marshal.load str
という形式で,ioはdumpしたファイルを読み込み可能でopenしたもの, strはdumpした文字列を指定します.

7.25 例外処理はありますか

他の先進的な言語と同様にRubyも例外処理をサポートします.
begin
  (例外が発生しそうな処理)
rescue (例外クラス)
  (例外が発生した場合の処理)
ensure
  (必ず実行したい処理)
end
begin節で例外が発生するとrescue節が実行されます. ensure節は例外が発生してもしなくても必ず実行されます.rescueensureは省略できます.rescureの後ろに例外クラスが 指定されなかった場合は StandardErrorが指定されたものとみなされ,StandardErrorの サブクラスである例外が捕捉されます.

この式の値は,begin節の値です.

もっとも最近起った例外はグローバル変数$!により参照できます. 発生した例外の種類は$!.typeにより調べることができます.

7.26 trapはどのように使いますか

trap("PIPE") {raise "SIGPIPE"}

前のページ 次のページ 目次