目次

5.  メソッド(method)

 

ここまでで結構な数の種類のメソッドを見てきました。 puts とか gets など...です。 (突然ですがクイズです。: ここまで出てきたすべてのメソッドを 挙げてみてください。10個あるはずです。回答は後ほど。 ) 今までメソッドが本当は何者なのかについて話してはきませんでした。 というより、何をするかは知っているのですが、何なのかは知りません。

しかし、本当は、それこそが メソッドを表している言い方なのです。つまり メソッドとは何かを行うものということです。(文字列や整数や浮動小数点数のような) オブジェクトをRubyの名詞とするなら、メソッドは動詞のようなものです。 そして、英語の文法と同様、その動作を行う 主体の名詞がなくては 動詞を意味あるものにすることはできません。たとえば'tick' (訳註:時計が時を刻むという意味)は何かを起こすものではなくて、時計が しなければならないことです。英語では "The clock ticks."といいます。 Rubyでは、これをclock.tickと書きます。(訳註:間の.に注意) (もちろん、ここで、clockをRubyのオブジェクトであると仮定しています。) プログラマはこのことを「clocktickメソッドを呼ぶ。」というような 言い方をします。

さっきのクイズやってみましたか? よろしい! では答えです。 まずは、先ほど述べたばかりの命令たち puts, gets, そして chomp は覚えているでしょう。 次に、変換メソッドto_i, to_f, そして to_sについてもおそらく大丈夫 だったのではないでしょうか? ということは残り4つですが、どうでしょう、わかりましたか? 残りのメソッドというのは計算機を作るときに用いた記号、+, -, *, そして /のことです。 これらは演算メソッドと呼ばれます。

先ほど、すべての動詞に名詞が必要なように、すべてのメソッドには オブジェクトが必要であると言いました。 通常、どのオブジェクトがそのメソッドを実行している主体なのか というのはすぐわかります。clock.tickの例や 101.to_sでわかるように、メソッドにはたいていその前に ドットがあってその前にオブジェクトが書いてあるからです。 しかし、演算メソッドのように時々それが明確ではないことがあります。 でも、実は5 + 5というのは、5.+ 5の省略形だったのです。 たとえば次のようにしてみればわかりますね。

puts 'hello '.+ 'world'
puts (10.* 9).+ 9
hello world
99

この書き方はあまりかっこよくはないので、これ以降はもうこんなふうには書かないと 思いますが、演算メソッドを使っているときに実際には 何が 起きてるのかというのを理解するには重要です。 (私の機械では上のような書き方をすると warning: parenthesize argument(s) for future version のような警告(warning) が表示されます。 これは、コード自体は順調に動作するけれど、コードの意味していることが あいまいだから、将来のバージョンのためにもカッコ(parenthesis)をもっと 使いなさい、と忠告しているのです。) これはまた、なぜ'pig'*5は実行できて5*'pig'がだめなのかに 対するより深い理解を提供します。 'pig'*5'pig'に掛け算をしろと告げていますが、 5*'pig'では5に対して掛けろと指示しています。 'pig'はそれを5つコピーして、それらをみんな 加え合わせる方法を知っていますが、 5自分自身を'pig'個複製して足し合わせる 方法を知らないわけです。

ではputsgets はどうなんだということになりますが、もちろん これについても説明しないといけませんね。 これらのオブジェクトはどこにあるのでしょう。 英語では、主語が取り除かれることがあります。 たとえば、悪漢が「死ね!(Die!)」と叫んだとすると暗黙の主語は叫ばれた人です。 Rubyでは、私が puts 'to be or not to be' と言ったなら、これは正確には self.puts 'to be or not to be' と言っていることを意味しています。 それでは、selfとはいったい何でしょう。自分自身? 実は、これはあなたが「今いる」ところを指し示している特別な変数なのです。 「今いる」とは何でしょう。まだ、オブジェクトの中に入る 方法については 説明してはいないのですが、その話の前にまず、プログラムの実行の際にはいつも必ず ひとつの大きなオブジェクトの中に入っている、ということを理解してください。 そのオブジェクトとは...、そう、プログラム全体です。 ラッキーなことにプログラム全体の中にあるメソッド、たとえば、putsとか getsとかですが、はそんなにたくさんはありません。 これを見てください。selfがあってもなくても結果は同じでしょう?(訳注:これは、著者の誤りで、 試してもうまくいかないと思います。理由はputsKernelの プライベートメソッドだからなのですが、そのことはここで理解できなくても問題ないと思います。)

variable = 3
puts variable
self.puts variable
3
3

これまでメソッドの概念を説明しましたが、完全にフォローできなくても大丈夫です。 大事なことは、すべてのメソッドは必ず何らかのオブジェクトによって実行されるのだ、ということです。 たとえそのメソッドの直前に、ドット(.)が見当たらなくてもです。 このことが理解できていれば十分です。

文字列メソッド特選

それではここからいろいろなメソッドについて学んでいきましょう。 まずは楽しい文字列のメソッドからです。 とはいっても、これから示すメソッドを全部覚える必要は全くありません。 忘れたらこのページを見直せばいいんですから。 今から文字列にできることのほんの少し をお見せしたいと思います。 事実、私自身文字列メソッドの半分も覚えているわけではありません。 —それでかまわないのです。なぜならインターネット上にすべての 文字列のメソッドのリストと説明を含むすばらしいリファレンスが存在するからです。 (このチュートリアルの終わりで、それをどこで見つければ良いのかを教えます。) 事実、私は全部のメソッドを覚えたいとも 思いません。 それはたとえば辞書のすべての単語を覚えるようなものです。 私は辞書のすべての単語を知らなくても十分英語が話せます...というより、辞書とはそういう ものでしょう?ということで、あなたもメソッド全部を知らなくても大丈夫 です。

さて、最初の文字列のメソッドはreverseです。これはある文字列の逆さ読みの 文字列を返します。(訳註:ASCII文字列に限ります。)

var1 = 'stop'
var2 = 'stressed'
var3 = 'Can you pronounce this sentence backwards?'

puts var1.reverse
puts var2.reverse
puts var3.reverse
puts var1
puts var2
puts var3
pots
desserts
?sdrawkcab ecnetnes siht ecnuonorp uoy naC
stop
stressed
Can you pronounce this sentence backwards?

これをみるとわかるように reverse は、オリジナルの文字列を 逆さにはしていません。新しい逆さ文字列を作って返しているだけです。 それが var1reverse のメソッドを呼び出した後でも var1'stop' のままである理由です。

次の文字列メソッドは length です。このメソッドはその文字列の文字数 (スペースを含みます。)を返します。

puts 'あなたのフルネームは何ですか?'
name = gets.chomp
puts 'あなたの名前は ' + name.length +
     ' 文字だったって知っていましたか, ' + name + '?'
あなたのフルネームは何ですか?
Christopher David Pine
#<TypeError: can't convert Fixnum into String>

あれれ! 何かおかしいようです。 name = gets.chompの行の後でエラーが起こっているようですね。 何が変だかわかりますか。考えてみましょう。

問題はlengthにあります。このメソッドは数を返します。しかし、 ここは文字列が欲しいところです。答えは簡単。これにto_sを 付け足せばいいんです。(うまくいきますように・・)

puts 'あなたのフルネームは何ですか?'
name = gets.chomp
puts 'あなたの名前は ' + name.length.to_s +
     ' 文字だったって知っていましたか, ' + name + '?'
あなたのフルネームは何ですか?
Christopher David Pine
あなたの名前は 22 文字だったって知っていましたか, Christopher David Pine?

いやぁ、知らなかったなぁ。注意: これは私の名前のキャラクタ 数(スペースを含む)であって 文字 数ではありません。(数えてみてください。) (訳註:著者は記号を含む文字を「キャラクタ(character)」、アルファベットの文字を 「文字(letter)」という言葉で使い分けています。日本語ではどちらも「文字」と訳しますが、 今後は、上記のように区別します。) 文字数を計算するプログラムだったら、ファーストネーム、ミドルネーム、ラストネームと 別々に聞いてそれらの文字列の長さ(length)を足し合わせるという手を使えばよいでしょう。 (訳註:日本人の名前なら、ミドルネームは要りませんね。) さぁ、やってみてごらんなさい。待ってますから。

できましたか?はいよろしい。プログラムするのは楽しいですよね。 これから何章か進むと、びっくりするくらいいろいろなことができるようになりますよ。

文字列のアルファベットの大小(つまり、大文字とか小文字とか)に関してもそれを変える 様々なメソッドがあります。 upcaseはすべての小文字を大文字に変えます。 逆にdowncaseはすべての大文字を小文字にします。 swapcaseは大文字を小文字に小文字を大文字にお互いに逆にします。 最後に、capitalizeは最初のアルファベットの文字を大文字にして、残りを downcaseと同じように小文字にします。

letters = 'aAbBcCdDeE'
puts letters.upcase
puts letters.downcase
puts letters.swapcase
puts letters.capitalize
puts ' a'.capitalize
puts letters
AABBCCDDEE
aabbccddee
AaBbCcDdEe
Aabbccddee
 a
aAbBcCdDeE

予想通り。puts ' a'.capitalizeの行で見られるようにcapitalizeメソッドは 最初の文字 ではなく、最初のキャラクタを大文字にします。 また、前に見てきたのと同じようにいろいろなメソッドを読んだ後でもletterの変数の指し示す 内容は変わっていません。このことをくどくど言うつもりはありませんが、理解しておくことは重要です。 メソッドの中には対応するオブジェクトを変化させてしまう ものも存在します。 ただ、まだ出てきてはいませんし、しばらくは出てこないでしょう。

特選メソッドの最後は視覚フォーマット系のものです。 まずはcenterです。このメソッドは文字列の最初と最後にスペースをつけて 元の文字列を中央寄せします。しかし、putsに対して何を表示したいのかを 告げたように、あるいは+に対して何を足したいのかを示したように、 centerには、文字列をどのくらいの幅でセンタリングしたいのかを告げます。 たとえば、次のような詩を中央よせしたいなら、こんなふうにします。

lineWidth = 50
puts(              'ハバードのおばさんが'.center(lineWidth))
puts(              '食器棚の中に座ったよ'.center(lineWidth))
puts(        'カードとホエーを食べながら'.center(lineWidth))
puts(            '蜘蛛がそばにやってきて'.center(lineWidth))
puts(            'おばさんの隣に座ったよ'.center(lineWidth))
puts('かわいそうな犬は一目散に逃げ出した'.center(lineWidth))
          ハバードのおばさんが          
          食器棚の中に座ったよ          
     カードとホエーを食べながら      
        蜘蛛がそばにやってきて         
        おばさんの隣に座ったよ         
かわいそうな犬は一目散に逃げ出した

ふむ。この詩の続きがこの後どうなるかは思いつきません。私は怠け者ですから。 (.center(lineWidth)を縦に並べたかったので、詩の文字列の前に 余分なスペースを入れました。この方がきれいだと思ったからです。 プログラマはよくプログラムの中で何がきれい(pretty)かというのにこだわっていて、 たまには、意見が分かれたりします。あなたも、プログラムを書くようになればなるほど 自分のスタイルが身についていくと思います。) 怠ける(being lazy)ということに関して言えば、プログラミングには怠け心は 悪いことばかりではないのです。たとえば上のプログラムで、詩の行の長さをどんなふうに 変数lineWidthに記録したかを見てください。 こうすることで、もし、後で見返してこの詩をより幅広くしたくなったとしても、 センタリングさせたいすべての行の行幅の数字を変える代わりに、プログラムの最初の行だけを ちょっと変えるだけで済んでしまいます。 もし、とても長い詩だったら、ずいぶんの時間が稼げます。こんなふうな怠け癖は プログラミングにとっては美徳なのです。

ところで、このセンタリングに関しては...ワープロがするほど美しくはないことに気が 付いたかも知れません。もし完璧なセンタリング(それもより美しいフォントで)を望むなら ワープロを使うべきです。Rubyはすばらしい道具ではあるけれど、どんな道具も すべて の仕事に最適ということはありえません。

残り2つのフォーマットメソッドはljustrjustです。これは それぞれ左寄せ(left justify)右寄せ(right justify) の意味です。 これらのメソッドはそれぞれ右側と左側だけにスペースを埋めると言うことが違うだけで、 centerと似ています。では、この3つを全部使って見ましょう。

lineWidth = 40
str = '--> 文章 <--'
puts str.ljust  lineWidth
puts str.center lineWidth
puts str.rjust  lineWidth
puts str.ljust (lineWidth/2) + str.rjust (lineWidth/2)
--> 文章 <--                          
             --> 文章 <--             
                          --> 文章 <--
--> 文章 <--            --> 文章 <--

練習問題

• 「怒ったボス」のプログラムを書いてみましょう。 まず、無作法に何が望みか聞いてきます。 で、何を答えようと「怒ったボス」はそれを叫び返して、あなたを首にします。 たとえば、もし給料上げてくださいとタイプしたとすると なにぃ? "給料上げてください" だとー!! おまえは首だ!! と、叫び返してきます。

center, ljust, そして rjust を使ってもう少し何かやってみましょう。こんな感じの「目次」を表示する プログラムを書いてみてください。

               目  次                       
                                            
1章:  数                                p. 1
2章:  文字                             p. 72
3章:  変数                            p. 118

すこし程度の高い数学

(この節は完全にオプショナルです。ある程度の数学の知識を前提としています。 もし興味がなかったら、制御構造へ直接 飛んでいっても何の問題もありません。ただ、乱数の節をチラッと 眺めておくと役に立つかもしれません。)

数に対するメソッドは文字列ほどは多くありません。(とは言っても、私が全部頭に 入れているわけではありませんが。)さて、ここでは、演算のためのメソッドの残りと 乱数発生メソッド、そして三角関数や超越関数(代数で表せない関数、指数関数など)の メソッドを持っているMathオブジェクトについてみていきましょう。

もっと演算メソッド

演算メソッドのうち**(べき乗)と%(余り)を 紹介しましょう。Rubyで「5の2乗」を言いたいときは5**2と書きます。 指数のところには、小数を使うこともできるので、5の平方根を求めることもできます。 つまり5**0.5とします。 一方、余りメソッドは数で割り算をしたときの余りを返します。たとえば 7を3で割ると答えは2で余りは1です。では、プログラムを見てみましょう。

puts 5**2
puts 5**0.5
puts 7/3
puts 7%3
puts 365%7
25
2.23606797749979
2
1
1

最後の行から、(うるう年ではない)1年というのは、何週間かとプラス1日であることが わかりますね。なので、例えば今年の誕生日が火曜日だったら来年は水曜日になると予測 できます。また、余りメソッドは浮動小数点数にも使うことができます。 小数に余りというのはちょっと不思議かもしれませんが、基本的に、 できるだけ道理にかなったやり方で実現されているようです。 とにかく、これに関してはいろいろ試してみることをお勧めします。

乱数発生の節に進む前に述べておく最後のメソッドはabsです。 これは数の絶対値を返します。

puts((5-2).abs)
puts((2-5).abs)
3
3

(訳註:括弧の使い方に注意してください。こうしないとエラーが起きてしまいます。)

乱数

Rubyには、とても素敵な乱数発生機がついています。ランダムに選んだ数字を 得るためのメソッドはrandです。randと、後に何もつけずに 呼び出すと、0.0以上1.0未満の浮動小数点数を 得ることができます。また、randを(例えば5のような) 整数を後につけて呼び出すと0以上5未満(つまり、 0から4までの5つの中から1つ)の整数が選ばれます。

では実際にrandがどう動くか見てみましょう。(このページをリロードすると、 毎回この数字は変わります。)ここにあるプログラムは、実際に今、実行しているものだ というのを知っていましたか?

puts rand
puts rand
puts rand
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(1))
puts(rand(1))
puts(rand(1))
puts(rand(99999999999999999999999999999999999999999999999999999999999))
puts('天気予報によると, 今日の降水確率は '+rand(101).to_s+'% です,')
puts('でも予想は予想ですから.')
0.8978627693158
0.611750596563793
0.996306943553799
60
74
46
0
0
0
71118566296139243280956223660807289260273030273413497392234
天気予報によると, 今日の降水確率は 51% です,
でも予想は予想ですから.

ここで、0から100までの間の数字を得るのにrand(101) という使い方をしているのに注意してください。あるいは、rand(1)が 常に0を返すというのがわかるでしょうか? このように、返ってくる値の範囲をしっかり理解していないと、 randを使った時に非常に気づきにくい大きな間違いを犯してしまう ことになります。 プロのプログラマの、それも店で買うことのできる最終製品のプログラムの中にも このミスが潜んでいることがあります。 私がかつて持っていたCDプレーヤで「ランダムプレイ」を選ぶと、ランダムに曲が 演奏されていくのですが、最後の曲だけは...演奏されなかったのです。 (このプレーヤに1曲だけ入ったCDを入れたとき、何事かと思いました。)

時には、プログラムを実行するたびに違う乱数ではなくて、 同じ 乱数が同じ順序で返ってくるようなrandメソッドが欲しい ことも起こるんじゃないでしょうか? (例えば、かつて私は、コンピュータゲームの中で ランダムに構成された世界を作るのにランダムに作られる数値を使っていました。で、 ある1つの世界が非常に気に入ったとしたら、もう一度その世界でプレイしたくなる でしょうし、それを友達に送りたくもなります。)これをするためには、 乱数の種(seed)srandを使ってセットする必要があります。 こんなふうに。

srand 1776
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts ''
srand 1776
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
24
35
36
58
70

24
35
36
58
70

同じ数で種を与えると、毎回同じ動作をするようになります。 また、(srandを使わなかったときのように)毎回異なる数字が 出るようにしたくなったら、srand 0とすればよいのです。 これにより、種として本当にランダムな数字(コンピュータの現在時刻を ミリセカンドの単位で用いたり)を使うようになります。

Math オブジェクト

最後にMathオブジェクトについてみて行きましょう。 とりあえず使っているところを見てください。

puts(Math::PI)
puts(Math::E)
puts(Math.cos(Math::PI/3))
puts(Math.tan(Math::PI/4))
puts(Math.log(Math::E**2))
puts((1 + Math.sqrt(5))/2)
3.14159265358979
2.71828182845905
0.5
1.0
2.0
1.61803398874989

最初に気がつくことはおそらく::という表現でしょう。 これは、スコープ解決演算子(scope operator) というもの なのですが、これを説明するのは、んー、このチュートリアルの範囲(scope)を 超えているようです。えーと、これは駄洒落じゃないですよ:)。 ここでは、Math::PIというのが、まさにあなたがそうだろうと 思っているものだというだけにとどめておきましょう。

また、上で見てもらえばわかる様に、Mathはまともな関数電卓 に当然あるべきすべての関数を持っています。そして例のとおり、 浮動小数点数は正確な値に非常に近い近似値 になっています。

さて、それでは制御構造 へと、進みましょう!

 

目次