![]() |
「そう、私はこのテクニカルマニュアルに今出てることになってるんだけど、ピックアップを探していたら、変な動物の町で道に迷ってしまったんだ・・・」 |
![]() |
||
「ああ、おたくの町は変だと思うよ。そこら中動物だらけだ!」 |
「うがー!! ばかげている!!
今じゃ電話交換手まで私のトラックを盗むのを助けてるんだ!!」 |
「キツネの大統領のマルコス・レジナルドが一枚噛んでると思ってるの?」 |
オリジナルズの壮大な計画に巻き込まれていることも知らず、背の高いキツネと、ずっと背の低いキツネは、非常事態の地であるウィグズルの街へと迷い込んだ。できるなら私は彼らにそのことを知らせ たい。海岸にある孵化場へとさらっていき、彼らのとがった耳は押さえて魚の卵の山の中に隠し、豪華な隠れ家にかくまいたい。そして私は彼らの上に立って微動だにしない影を投げかけ、毅然とライフルを構える。
しかし私にはできない。打ち明けなければならないが、私は自分の面倒を見なければならないのだ。上の階の電球を交換しなきゃならない。無料のハロゲン電球がちょうど郵便で届いたところだ。誰かが私にそれを使わせようとしているらしい。だから私はその電球をねじ込む。そして 私はそこにただ立って、微動だにしない影を投げかけ、毅然とライフルを構える。
その影がきれいでくっきりしているなら、私はそれをそのまま保とう。
1. 私が車を探しているなら
![]() |
||
「座れて楽になったよ。まったくひどいことになった」 |
「君にそんな目で見られるのは嫌だな」 |
「私の鬱屈した感情を助長しようというの? 私の気楽な性格を押しつぶ
してしまおうと?」 |
私はこの2人が外にいるのを見るのが好きだ。彼らはスタジオの中ではすごく退屈していた。それで彼らは奇妙なスローガンなんかをでっち上げはじめた。とあるフレーズを繰り返し 、それに執着した。そんな不自然なキツネのナンセンスは我慢できない。
これだけは言っておこう。私は本当にものごとを大学みたいにやろうと努めている。大学には行ったことがないので、自分の書く文章が学問の世界が要求する厳格な基準に合っている かわからないが、大学には友達がたくさんいて、中には研究で世界をまわっている人もいるので、彼らのハイカルチャーのブレンドに私の調子を合わせるように努めよう。
ときどき私は学のある友達を越える仕事をした自分に拍手を送る——人気のない廊下でだけだ。人前で頭突きしたりしない——私は実際 、学派がまだ彼らの本の中にしかなく変り続けているうちから受け入れてきた。
私はプリイベンチュアリストだ。私がそれに関わるようになってずいぶん長くなるし、そうしてきたことを良かったと思っている。あなた方の中にはすでにこの本にマルクス主義の記号を探し始めている人もいる ことだろう。残念ながらそのような解釈は切り捨てざるを得ない。しかしあなたの引き出したニヒリスト的結論はどんなものであれ、研究する価値があるだろう。
何にしても、レトリックを使うのはやめることにしよう。私がプリイベンチュアリズムに触れたのは、それが我々が我慢してきたポストモダニズムに対する新鮮でやさしい代替であるということを別にすると、この 超カルトがウィグズルの住人に無料の落とし物サービスを提供しているからだ。
require 'open-uri'
open( "http://preeventualist.org/lost" ) do |lost|
puts lost.read
end
私はキツネたちにこのサービスのことを知らせる手段がない。彼らのトラックはすぐにこのリストに載ることだろうと思う。依然、ここには善意があるのだ。
あなたがインターネットに接続されているなら、上のRubyコードがそのWebページをインターネットからダウンロードして画面に表示するはずだ†。メッセージは以下のような内容だ:
†このサービスは現在は機能していない。
プリイベンチュアリストの遺失物記録簿 (啓発された人のための無料のサービス) --- 毎日更新されます。定期的にチェックしてください! --- このサービスの一部は アシュレー・レイモンド・ユース・スタディ・クランに 委託され援助を受けています ... すべての標章と権利は ポリウェイフ明け渡し執行官、ペリー・W・L・フォン・フローリングの 卓越した著述のもとに登録されています。彼はまた ベガーズ・コミュニティ・カップに7回連続で優勝しています。 ... この記録簿について ============== はじめての方はこれをお読みください。以下にサービスについての簡単な説明があります。最初に、我々の 愛すべき執行官から重要なお知らせがあります。(子どもたちはみんな彼をアンクル・フォン・ガファンクル と呼んでいます。笑) 重要なお知らせ =========== / 2005年4月15日 / 大ニュースです。ウィグズルとオーディッシュ地域の8チャンネルに私たちは出ました。コーリーが見ていま す。私が出て、それからジェリー・マザーズも出ました。見てなかったらコーリーにメールしてください。 彼が一番良く説明してくれるでしょう。私に言えるのは、これが私の手ぶりじゃないということです!! (チ ャンネル8を見ている人たちのためのジョークです。) ハリーとチャンネル8ニュースチームの皆さんに感謝!! - ペリー / 2005年4月7日 / 私たちは本部でカーペットを調べましたが、ケイトリンのクリップボードを見張っていたなら、彼女がそれ を投稿するにはあまりに控えめな女性だとわかるでしょう。それは彼女にとってとても重要なことです。彼 女は夫の受け口を撮ったとても高価なパノラマX線写真を持っていて、受け口が もっと目立っていた頃に 旦那さんがロボコップのコスチュームを着て撮った大切な写真にクリップで留めていました。彼女は(私に) 「彼らがそれを見れば私の言ったことの意味がわかるわ」と言いました。私にはそれが何を意味するのかわ かりません。 :( 私がチェックしたのは: * フロントデスク * ホール * 待合室 * トイレ * キャンディー入れ * 大型テレビ のあたり * ランチカウンター * 見習いの部屋 * 軽業師の古い部屋(桜の木の絵のあるやつ) * サーバルー ム * 階段。部屋をもっと見つけたらこのリストを アップデートします。 - 愛を込めて、ペリー / 2005年2月25日 / サーバが3時に落ちました。私は君たちに腹を立てています。軽業師は下の階に直るまでいることでしょう :O -- 追記: 直った。復帰したぞ!! - ペリー / 2005年2月23日 / 今日はいろいろ騒ぎがありました。スタンリー兄弟サーカスは12頭のラマとトレーラーとたくさんのマスタ ーキーと5つのテントをなくしました。彼らはまだなくなったものを探しています。冷静に。私はみんなの助 けが必要です。このエンターテナーたちは何も持っていません。文字通りに。今日私は男の1人に紫色 のステッカーをやりました(これは私がやさしいそぶりとしてするのを好んでいることです)。そして彼は実 際その上で眠り、ピザソースの材料をその上で育てています。彼らはどん底にいるのです。 だから寄付をお願いします。私たちはpaypalも何もありません。だから寄付したいと思ったら、何でもいい から見つけたものを送ってください(子供用自転車とか、腐りやすいものの缶詰ひと月分とか)。そしてサー カスの人たちの名前を上に書いておいてください。 - ペリー / 2004年11月15日 / プリイベンチュアリストの日の売り出しです。今日何かなくしたら、誰か何かを見つけた人の家から(40ドル 以下の価値の)景品を1つ持ってくることができます。私たちはこれをすごく楽しんでいます!! 私は去年これ でローイングマシーンを手に入れました。すごく気に入っています!! - ペリー
ユース・スタディ・クランはこのサービスの運営をとてもよくやっていると思う。これはちょっといんちきで陳腐だが、動物たちが所有権を本能的な仕方で主張しあうのを止め られるのであれば、私は敬意を払う。
しかしプリイベンチュアリストは若者のグループなのだろうか? そんなことがありうるだろうか? プリイベンチュアリストになる前に、少なくとも本物の冷笑主義の洗礼を受ける必要がある。そしてまず学校には通えない。だから私には分からない。
プリイベンチュアリストの遺失物記録簿の解説に戻ろう。
L&Fサーバの使い方 =============== L&Fは無料のサービスです。ものをなくしたり見つけたりするのは、プリイベンチュアリストのライフスタ イルを形作る不可欠なものです。あなたの信条に合うといいのですが。 私たちはHTMLは使いません。作業を簡単にするためです。私たちのスタッフはすでに1日15時間働いています。 (ターク、ありがとう!! ホレス、ありがとう!!) あなたは私たちのサービスでなくしたものを探すことができます。また、なくした(あるいは見つけた)ものを 記録簿に追加することができます。これはしかるべきアドレスをブラウザに入力することで行います。 検索 ==== なくしたものを検索するには、以下のアドレスを使います: http://preeventualist.org/lost/search?q={検索語} {検索語}を検索語で置き換えてください。たとえば"cup"を探すには以下のようにします: http://preeventualist.org/lost/search?q=cup そうすると、なくしたり拾われたりしたcupの一覧が表示されます。 なくしたcupだけ探したい場合や、拾われたcupだけ探したいという場合には、`searchlost'や`searchfound' のページを見てください: http://preeventualist.org/lost/searchlost?q=cup
私はゲームをしているわけではない。私はトラックがどこにあるのか知っている。本当に、あなたのことをじらしているわけではない。すぐに教えてあげる。ただキツネたちを見てと言っているだけだ。
![]() |
||
|
|
「この公園はシマウマのにおいがする」 |
彼らはお手上げだ。しかしここにすばらしいツールがある。この混乱から脱出するための鍵になるかもしれない。何か手がかりがないか探ってみたい。
require 'open-uri'
# 語`truck'を含む落し物をすべて検索する。
open( "http://preeventualist.org/lost/searchfound?q=truck" ) do |truck|
puts truck.read
end
このリストに背の高いキツネのトラックの情報はないようだ。それはかまわない。どうせキツネたちはぼうっとしているので、私たちには少し時間がある。
あなたはインターネットからWebページを取得する簡単なテクニックをすでに学んでいる。OpenURI
ライブラリを使うやつだ。これは私の好きなルビイストの1人である田中哲が書いたものだ。彼はインターネットから読むのを自分のコンピュータのファイルを読むのと同じ
くらいに簡単にしてくれた。
前の章で、あなたの極悪非道なアイデアをテキストファイルとして保存した。そのファイルはRubyでopen
を使って読むことができる。
require 'open-uri'
# 自分のコンピュータのフォルダからアイデアのファイルを開く
open( "フォルダ/アイデア-教会の椅子にレタスを隠す.txt" ) do |idea|
puts idea.read
end
ファイルは入出力オブジェクトだ。あなたはファイルの読み書きができる。Rubyでは、すべてのIO(input-output)オブジェクトはread
メソッドとwrite
メソッドを持っている。open
メソッドはIOオブジェクトを滑り台でブロックの中に落とし、それを使えるようにする。IOは外の世界へのチケットだ。刑務所の鉄格子から差し込む日の光だ。(もっともあなたはOpenURI
でWebページに書き込むことはできない。Webサーバにコピーするためのツールを見つける必要がある。たとえばFTPプログラムのような。)
教会の椅子にレタスを隠すことに関するあなたの極悪なアイデアを読みたい人がいて、あなたがそれをWebページとしてポストしていたと仮定すると、
require 'open-uri'
# Webサイトで読めるようになっているアイデアファイルを開く。
open( "http://your.com/idea-about-hiding-lettuce-in-the-church-chairs.txt" ) do |idea|
puts idea.read
end
OpenURI
ライブラリはまた、FTPアドレスも解釈できる。これはあなたがファイルを保存できる場所の選択肢を広げてくれる。あなたのコンピュータの中でも、インターネット上のどこかでもいい。
ファイルを1行1行読む
あなたがOpenURI
を使い、open
メソッドとread
メソッドでWebから情報を得るとき、ページ
は1つのString
として取得される。何かを探している場合や、ページが大きくメモリを節約したい
という場合には、ページを1度に1行ずつ読んでいくこともできる。
require 'open-uri'
open( "http://preeventualist.org/lost/searchfound?q=truck" ) do |truck|
truck.each_line do |line|
puts line if line['pickup']
end
end
上のコードはpreeventualistのサイトで見つかったトラック(truck)のリストを取得し、語‘pickup’を含んでいる行だけを表示する。そのようにして記述を削 って、肝心な行だけを対象として探すことができる。
上の例はインデックスの角カッコを文字列に対して使い、角カッコの中の語を文字列の中に探す。角カッコの中身は文字列'pickup'
なので、文字列line
の中で語“pickup”を探すことになる。
![]() |
||
「公園にいると少なくとも可笑しくしなきゃいけないないというプレッシャーは感じなくて済むね」 |
「我々は可笑しいということになっていたの?」 |
「でも今はこの新しい役がすごく気に入ってるよ——この本の破壊者だ!」 |
Webページがread
でロードされると、ページ全体がメモリに読み込まれる。通常
それは数千バイトにしかならない。しかしページが大きい(数メガバイトある)場合には
、たぶんeach_line
を使い、1度に1行ずつ読んでメモリを使いすぎるのを避けたいと思うだろう。
子ブロックへの委譲
Rubyでは、しばしばイテレータを次のような仕方で使う。イテレータは、配列やハッシュといったコレクションのそれぞれの要素を順にたどるときに使われる。IOの対象を行のコレクションと見なしてみよう。イテレータはこの行のコレクションを這い進むことができる。
class IO
# each_lineメソッドの定義。引数リストを持たないことに注意。ブロックは引数として
# 書いてもらう必要がない。
def each_line
until eof? # ファイルの終わりまで・・・
yield readline # 行をブロックに渡す
end
end
end
yield
キーワードはブロックを使う一番簡単な方法だ。一語で済む。カーテンに引き紐があり、スーツケースにハンドルがあるのと同じようなものだ。メソッドの中で点滅するyield
ボタンを押すと、そのメソッドにくっついているブロックが実行される。ブロック内のコードが終了するまでボタンが強い赤色に輝く。それから点滅状態に戻る。やりたければ
ボタンをまた押すことができる。
def yield_thrice
yield
yield
yield
end
yield
ボタンを3回素早く叩き、ブロックは3回その人生を生きる。
irb> a = ['最初に生まれる。', 'それから明滅するイメージの人生。', 'そして最後に終わりを迎える。']
irb> yield_thrice { puts a.shift }
# 以下のようにプリントされる:
# 最初に生まれる。
# それから明滅するイメージの人生。
# そして最後に終わりを迎える。
shift
メソッドは配列の最初の要素を引っ張り出す。shift
の床屋は髪を刈ってそれを手渡す。それから頭皮。それをずっと続けて、哀れな男が何もなくなるまで削っていく。
メソッドにくっついたブロックを見たわけだが、Rubyのメソッドはどれでも、後ろにブロックを付けることができる。
# メソッドにブロックをくっつける簡潔なスタイル。
# ここではブロックは中括弧で囲まれている。
open( "idea.txt" ) { |f| f.read }
# メソッドにブロックをくっつける冗長なスタイル。
# ここではブロックはdoとendで囲まれている。
open( "idea.txt" ) do |f|
f.read
end
yield
に引数を渡すと、その引数はブロックにも渡される。ブロックはメソッドのオートバイに
取り付けられた小さなサイドカーに乗っている。砂漠を疾走する彼らに吹き付ける風の中、メソッドは引数リストを大声でブロックに向かって叫ぶ。ブロックは自分のヘルメットを叩いて、「わかったよ、ちゃんと頭に入った」と伝える。
# メソッドは2つのファイルを開き、結果のIOオブジェクトを滑り台でくっついたブロックの中に落とす。
def double_open filename1, filename2
open( filename1 ) do |f1|
open( filename2 ) do |f2|
yield f1, f2
end
end
end
# それぞれのファイルの中身を並べてプリントする。
double_open( "idea1.txt", "idea2.txt" ) do |f1, f2|
puts f1.readline + " | " + f2.readline
end
あなたはyield
キーワードが道路標識と何の関係があるのかと不思議に思うかもしれない。それはいい質問だ。そしてそれにはいい答えがある。あなたがメソッドを実行するとき、あなたはそのメソッドに
プログラムのコントロールを渡している。コントロールして自分の仕事を為し、そして答えを持って戻ってくるようにと言っているのだ。
yield
では、メソッドは交差点で止まり、コントロールをあなたに、あなたのブロックに返す。メソッドは仕事を再開する前にあなたに仕事をさせてくれる。だからeach_line
メソッドがファイルから行を実際に読み込む仕事をする間、each_line
メソッドにくっついているブロックはその行を渡され、サイドカーの中でその行に対してせっせと作業するチャンスが与えられる。
金張りの箱の中のプリイベンチュアリズム
OpenURI
や、yield
を使って自分のイテレータを書く方法について、あなたはずいぶんと学んだ。遺失物サービスを使う方法も分かっている。本当に、あなたはウィグズルのガラクタの引き出しを私なしで探せるようになっている。
このサービス全体を1つのクラスの中に包み込んでしまおう。
require 'open-uri'
module PreEventualist
def self.open page, query
qs =
query.map do |k, v|
URI.escape "#{ k }=#{ v }"
end.join "&"
URI.parse( "http://preeventualist.org/lost/" + page + "?" + qs ).open do |lost|
lost.read.split( "--\n" )
end
end
def self.search word
open "search", "q" => word
end
def self.searchlost word
open "searchlost", "q" => word
end
def self.searchfound word
open "searchfound", "q" => word
end
def self.addfound your_name, item_lost, found_at, description
open "addfound", "name" => your_name, "item" => item_lost,
"at" => found_at, "desc" => description
end
def self.addlost your_name, item_found, last_seen, description
open "addlost", "name" => your_name, "item" => item_found,
"seen" => last_seen, "desc" => description
end
end
コードというのはある時点で何かきちっとした形に整えてやる必要がある。上のモジュールをpreeventualist.rb
という名前で保存しよう。
このモジュールはプリイベンチュアリストのサービスを使うためのとてもシンプルなライブラリだ。これはまさにライブラリの書かれる仕方だ。モジュールかクラスを手早く作り、ファイルに収め、それが気に入って世界の人 たちにもその恩恵を分け与えたいと思うなら、それをWebにのっける。
私が前にOpenURI
を使ったみたいに、あなたのモジュールは使うことができる。
irb> require 'preeventualist'
irb> puts PreEventualist.search( 'truck' )
irb> puts PreEventualist.addfound( 'ホワイ', 'Rubyのスキル', 'ウィグズル公園',
"Rubyのスキルが身に付けられます!\npoignantguide.netへお越しください!" )
2. 一方、ヤマアラシは給油に立ち寄っている
![]() |
||
「9番ポンプ」 |
|
「凧は売ってる?」 |
3. スポンサー付きのドラゴン退治
![]() |
||
「ぼくはドラゴンを退治した!」 |
「ドラゴンの顔をウィザブラムで吹き飛ばした」 ドッカーン 「シーッ! 友達が休んでるんだ!」 |
「何が幸運かってわかる? |
「考えてみてよ」とキツネ小が言った。「僕たちの中には冒険する時間がない人もいる。大きな責任を負っていたり仕事があったりするんだ。生活の手段ってやつだよ。わかる?」
「ヘーイ、ぼくの仕事はドラゴンを殺すことだったんだ!!」ちっぽけなウサギが叫んだ。目を瞬かせ、木から木へ、沼から沼へと半狂乱に跳ね回りながら。「やつの鼻は大きな責任だった!! やつの煙たい息はぼくが考慮すべき問題だった!! ぼくはあそこに行くだけでタクシー代に50ドル払った。これは大きな大きな試練だった。君はぼくにかなわない。批難できない。ぼくの英雄性は絶対的に非の打ち所がない。ぼくの手段全体が、絶対的にアンズ不能だ。レスターに聞いてみて」
「レスターって、誰?」とキツネ小が聞いた。
「レスターはタクシーの運転手さ! 彼はドウェムジーズアレイの基地に駐車したんだ!!」 ウサギはスーパーコンピュータのスクリーンセーバーみたいに狂ったように飛び跳ねた。「ドウェムジーに聞いて!!」、
「ふうん」とキツネ小が言った。キツネ大の方を振り向いて見ると、彼はまっすぐ腰掛けて遠くを見つめていた。「えっ、ドウェムジーズアレーに駐車場があるの?」
「そうとも!! それにプレッツェルスタンドも!!」
「だけど隊列なんでしょ? それがチュロを売ってるわけ?」
「チョコラバだ!!」ウサギが言った。
「じゃあ暗闇で光る紐は売ってる? 髪に付けたり、手に持ったりするやつ——」
「ブレイドクエスト!!」
「セールスマンのコミッションの分け前をもらうべきだよ」キツネ小が言った。「みんな君がドラゴンを殺すのを見に来たわけでしょ?」
「しかーし!! チョコラバを引っ張り出すやっとこはぼくがやってるわけじゃない」
「言っただけだよ。殺すところは君がやってるわけだよね。だったら君は分け前をもらう権利がある」
「あっ、しまった!! お気に入りのレタスをドウェムジーズアレイに置いてきた!!」ウサギが金切り声を上げ、揺れるオークの木の間を儀式用サーベルみたいにくるくる回った。遠くから「それともレスターのトランクかも?」と言った。
「ちょっとじっとしてられないの??」キツネ小が言った。
「僕のラジオは」キツネ大が一瞬生気を取り戻して言った。「ピックアップの中だ」。彼の目は相変わらずぼんやりしていた。彼の視線は震えた後に止まり、別な時間の別な場所を思い出していた。メリーランドへのドライブ 。ライオネル・リッチーの声がはっきりと聞こえる。ワイパーは動くのが少し早すぎる。家に車をつける。母親が戸口に出迎える。彼女はすごくふわふわしたキツネだ。涙とメーキャップ。
背もたれにどすんと寄り掛かった。「あのヤマアラシは私のプリセットを変えたに違いない」
ウサギはベンチのひじかけに飛び乗って、近くで話した。「しかし!! すぐにぼくはドラゴンの頭とドラゴンの舌のジュースを楽しむだろう!!」ウサギは静かに座って優しく手を握り合わせた。
「(シナモンバーみたいな味だといいんだけど)」ウサギが心から囁いた。
「シナモンなら好きだ」とキツネ小が言った。「僕もいつか君と一緒に殺しに行きたい」
「そうすべきだね」とウサギは言い、目を輝かせた。
「よだれだ。よだれを出してるんじゃない?」
「もちろん!!」ウサギは興奮して目からスティッキーウィップが飛び出した。(スティッキーウィップについては後の補足に書く。私が忘れているようだったら教えてほしい。ジョリー・パトリック・ソブゴブリンの「純粋主義者 のための新しい網膜クリームの概要」も参照。動物の飾り付きのクリップを置いているとこならどこでも手に入る。)
「ああ、すっかり興味を引かれちゃった。全部聞きたいね」キツネ小がきっぱりと言った。「エントチュについて話してよ。ああ、それにドウェムジーのことも。誰なの? 彼を動かしているものは何? それから僕がまだついていっているようなら、ウサギを動かしているものが何なのか教えて。そして僕たちの手を取って、なくしたトラックの試練を導いてほしい。僕は他のなによりも慰めを必要としてる。今だったら宗教だって信じるよ。君の勇敢さと君からにじみ出る達成感を僕は求めている。パイプは持ってる? 僕たちが結ぶ儀式の道具になるよ」
それからウサギはドウェムジーと、ドウェムジーの伝説と、ドウェムジーのやり方について詳しく説明しはじめた。ドウェムジーの話の多くと同様、ウサギの話は装飾だらけだった。スモッチキス、私だけが語るべき微妙な話があるのだ。
ドウェムジーが誰なのか決して聞かないでほしい。彼は明らかに黒幕で、その居場所や本当の素性を決して明かさない。彼は王国を持っている。彼は火の鬼を生み出した。馬はどこ にいても彼の臭いを感じ取る。なにより、彼は官能的な快楽を知っている。そしてこれが・・・
これが彼のアレイだ。
ドウェムジーズアレイ
![]() |
||
「ドウェムジーズアレイは最高だ!! |
「こいつは血の付いたパズルだ」 |
「演奏しながら俺は、耳を聾するスタンディングオベーションと深い個人的な涙の間を漂っていた」 |
あなたはドウェムジーズアレイの入り口に立っている。あなたはアレイの奥深くにいて死にかけているウサギだ。
class Dragon < Creature
life 1340 # タフさの度合い
strength 451 # 逆巻く血脈
charisma 1020 # 歯を見せる笑顔
weapon 939 # 炎の息
end
激しく渦巻く溶岩が不協和音を立てて坑道を通りドウェムジーの森の永遠の天蓋の中に深く入り込み・・・飢えた野生のストーキュパインの腹から 脆い夜の叫びが聞こえ・・・グラハムクラッカーを食べてお昼寝したすぐあとの湿ったガチョウの子を食べる・・・正式には孤児だが自動車販売代理店のコングロマリットの所有する傘に守られ た飢えているカバの中・・・どろどろした青いエリクサーの蓋をしていない小瓶の下に・・・とどまりつづける・・・これまで・・・乱されることのな かった・・・ドウェムジー!!!
![]() |
||
「自分の幸運をそんなに鼻にかけるものじゃないよ・・・そんなのいつでもなくなってしまう」 |
「実際はそうじゃない。幸運は魅力があって、人々をヒーローの目で見るときにやってくるんだ。そして木の精と母なる自然が幸運を与えてくれるんだ」 |
「僕がドラゴンなら、間違いなく木の精と母なる自然を最優先の仕事として殺すね」 |
ドウェムジーズアレイがわからないなら、それはドウェムジーの問題だ。彼は私たちの人生を複雑にするためにこのゲームをデザインしたのだ。単純なものだったら、私たちが腕に大切に抱 いて畏敬の念を感じる冒険とはならないだろう。
ドウェムジーズアレイにはとても深く曲がりくねった歴史がある。単純に「ドウェムジーズアレイ」と繰り返すだけでは信任状を得るのに十分ではない。私についてきて欲しい。何年かさかのぼ り、それがメタプログラミングとイルカで始まった60年代に連れて行ってあげよう。
あなたはメタプログラミングというのはファックス機の間で私用の電話をしたときにはじめて耳にしたハッカーの言葉だと思うかもしれない。ほんとのところ、真実 はそれよりもっと奇妙だということを話すために私はここにいる。メタプログラミングはイルカのいるところでドラッグをやっていたときに生まれたのだ。
60年代にジョン・C・リリーという多産な科学者が、体の仕組みを調べようと自分の感覚を材料に実験し始めた。私はこれに関係がある。道の真ん中にパイを持って立っているとき、あるいは聖堂の中に隠れているときに、私はこれを良くやる。私は自分自身を調べるために立ち止まる。これはほとんど不可能なことが証明された。私は罫線入りのノート3ページを代数式で埋めたが、そのどれも何も説明しはしなかった。ついでながら、パイというのは、数学的にとても容易に表現できる。
しかし科学者のリリーは実験を別の方向に進めた。彼はイルカと一緒にいるときにLSDを摂った。ときには暖かい海水で満たされた暗く悲痛な隔離タンクの中で。 すごく寒々としている。しかしそれは科学だったのだ! (彼が犯罪者だとは考えないことだ。1966年までは、Sandoz Laboratoriesが誰でも関心のある科学者にただでLSDを配っていたのだ。)
ドラッグ、イルカ、そして喪失。それがリリーの探索をメタなものに向けた。彼は、人とコンピュータを比較するメンタルプログラミングに関する本を書いた。あなたは次の引用を読む間に摂取するものを選んでいい——ほとんどの場合ひとつまみの塩に手を伸ばすだろう——しかし 芝生の上でグレートフルデッドのショーがあったり、熱狂的な人たちが地下室にあふれたりすることはないと請け合おう。
人が学ぶことを学ぶとき、人はモデルを作り、シンボルや、アナロジーを使い、メタファーを作り、つまり、言語や数学やアートや政治やビジネスなどを作り、利用する。脳(皮質)のサイズの上で大きな部分 を言語とそれにかかわる部分が占めている。学ぶことを学ぶこと、シンボル、メタファー、モデルといちいち繰り返すのを避けるため、これらの働きの基本になっているアイデア をメタプログラミングという記号で表すことにする。
ジョン・C・リリー、人間バイオコンピュータにおけるプログラミングとメタプログラミング、
ニューヨーク、1972年
私たちは学ぶ。しかし最初に学ぶことを学ぶ。私たちは心の中にプログラミングをセットアップし、それがプログラミングをさらに推し進めるための道となる。(リリーは 主として、彼がバイオコンピュータと呼ぶ脳と神経システムのプログラミングについて話している。)
リリーのメタプログラミングというのはむしろ、心象を与えるとか、自分自身を再構築するといったことだった。このような思考は、シャーマニズムに手を出し、タロットカードの上に手をかざし、空手の練習のために早起きする人々 に直接繋がるものだ。メタプログラミングはニューエージだと言 えるかもしれないが、それは最近では古き良きナード性とともに寝袋の中に収まっている。(あなたがGoogleで「C++ Metaprogramming」と検索してここに来たのなら、もう少し我慢してほしい。ただあなたにその検索をさせた神経経路は燃やしてしまってくれ。どうもありがとう。)
メタ自体は著者の時代でも違いなく語られている。
現実に対する感覚的反応というのはすべて、現実の解釈だ。甲虫もサルも彼らの世界を明らかに解釈している。そして彼らが理解したものに基づいて行動している。私たちの 身体的感覚はそれ自体解釈の器官なのだ。私たちを動物と区別しているのは、それらの解釈を解釈できるという私たちの能力だ。その意味で、人間の言語はすべてメタ言語なのだ。それは我々の体、我々の 感覚器官の「言語」の二次的な反映なのだ。
テリー・イーグルトン、理論のあと、ロンドン、2003年、第3章
その意味で、プログラミング自体メタ言語だと言うことができる。すべてのコードは、行動の言語を、まだ行われていないが間もなく行われるプランの言語を語る。マシンの中の役者 たちの舞台演出だ。私は以前これ をセンチメンタルに捉えていた。
しかし今では私たちの研究も進み、メタプログラミングの世界へと歩を進めているが、恐れることはない。それは依然としてあなたが見てきたRubyと違わない。それがドウェムジーがあなたにそれを押しつけることに呵責を感じない理由だ。すぐにそれは、足し算や引き算と同じくらい簡単にわかるようになる。最初それは、顔の方に飛んでくる蛍をはじめて見 たときのように、強烈に明るく見えるかもしれない。それから、それはオハイオでの暮らしをずっと良くしてくれる小さな揺れる光になる。
メタプログラミングとはコードを書くコードを書くということだ。しかしそれはM・C・エッシャーがスケッチするようにではない。プログラムは前に戻って自分自身を上書きすることはないし、画面から飛び出してあなたの手からキーボードをひったくることもない。それよりはずっと小さなことだ。
それはむしろあなたがサーカスで手に入れた小さなオレンジ色の錠剤に似ている。それを口に入れると、コーティングが溶けて、歯の裏側で大きな柔らかいスポンジのブロントサウルスが出てくる。それがあなたの舌を滑り降りて自由に飛び回り、草地をはしゃぎ回 って、「パパ!」と叫ぶのだ。そしてそれ以来、彼がイライラしてトラックを襲うときには、そのトラックはきれいな火花を散らすことだろう。
誰かが小さなオレンジ色の錠剤を水道の下に置いたとする。自分の舌の上にではなく、水道の下にだ。これは別な変化をもたらす。泣き叫ぶスポンジの八つ子を生む。へその緒や何やかや。それでもトラックを片づけるのには手頃だ。しかしまったく違った種類のシャモアだ。そしてある日、この8匹は、バイオリン演奏会 に出てパパに涙を流させる。
メタプログラミングはコードを錠剤の形に詰め込み、ほんのちょっと水を垂らすだけで広がりはじめる。さらに重要なのは、錠剤の反応をコントロールできるということで、鱗 のあるのっそりしたブロントサウルスが作られるようにできる。あるいはもちろん八つ子でもいい。あるいはお針子でも。あるいは猫の脳みそでも。あるいはドラゴンでも。
class Dragon < Creature
life 1340 # タフさの度合い
strength 451 # 逆巻く血脈
charisma 1020 # 歯を見せる笑顔
weapon 939 # 炎の息
end
これはまだメタプログラミングではない。ただの錠剤だ。メタプログラミングの結果だ。いったん立ち止まって怪物自体を見てみることにしよう。メスと顕微鏡を使って肉体の内部へと進む前に。
Dragon
はクラスだ。もう何度も見ているだろう。Dragon
はCreature
クラスの子孫だ。
目を上げて、私を見て。Creature
クラスはメタプログラミングコードを含んでいる。あなたはRubyのどこででも使えるメタプログラミングコードを書くことができる。Creature
やDragon
の中でも、String
の中でも、Object
の中でも、どこででもだ。ここで挙げる例では、メタコードの最も一般的な形態である、自分のクラスの中でだけ使うメタプログラミングに焦点を当てる。
Dragon
の特徴のそれぞれはただのクラスメソッドだ。
これは次のように書くこともできる:
class Dragon < Creature
life( 1340 ) # タフさの度合い
strength( 451 ) # 逆巻く血脈
charisma( 1020 ) # 歯を見せる笑顔
weapon( 939 ) # 炎の息
end
括弧を取った方がすっきりするので、括弧は省略することにする。メソッドをいくつかまとめて使うのではっきりさせたいという時だけ括弧を使うようにしよう。
Creatureのコード
横隔膜のところでスライスしてCreature
の内部を見せよう。このコードをdwemthy.rb
という名前で保存して。
# ドウェムジーズアレイの生命力の中心
class Creature
# このクラスのメタクラスを取得する
def self.metaclass; class << self; self; end; end
# 特徴(trait)を素敵できれいに表現するための先進的なメタプログラミングコード
def self.traits( *arr )
return @traits if arr.empty?
# 1. それぞれの変数にアクセサを用意する
attr_accessor *arr
# 2. それぞれのtraitにクラスメソッドを追加する
arr.each do |a|
metaclass.instance_eval do
define_method( a ) do |val|
@traits ||= {}
@traits[a] = val
end
end
end
# 3. それぞれのモンスターについて、initializeメソッドはそれぞれのtraitの
# デフォルトの値を使う
class_eval do
define_method( :initialize ) do
self.class.traits.each do |k,v|
instance_variable_set("@#{k}", v)
end
end
end
end
# Creatureの属性はリードオンリー
traits :life, :strength, :charisma, :weapon
end
最後の行に注目してほしい。つまりtraits
をセットアップしている行だ。その前にあるコードはすべてtraits
クラスメソッドをセットアップしている。これは前の章のLotteryTicket
を思い出させる。
class LotteryTicket
attr_reader :picks, :purchased
end
traits
とattr_reader
のどちらも単なるクラスメソッドだ。attr_reader
がLotteryTicket
で使われたとき、裏ではメタプログラミングが動き出して、風船を膨らませ、インスタンス変数 @picks
と@purchased
に対するリーダーメソッドを作り出していた。
traits
メソッドのコードは私がずっと仄めかしていたメタプログラミングだ。コードのコメントが、traitsを追加するときにたどる3つの段階を明らかにしている。
-
traitsのリストが
attr_accessor
に渡され、それぞれのインスタンス変数に対するリーダーのコードとライターのコードを生成する。 - それぞれのtraitに対してクラスメソッドが追加される(たとえば
life
クラスメソッドが:life
に対して追加される)。これらのクラスメソッドはあなたがtraits
やattr_accessor
を使うのと同じようにクラス定義で使われる。このようにしてそれぞれのcreatureとtraitの組に対してポイントを指定 できるようになる。 - 初期化メソッドを追加して新しいモンスターのプロパティをセットアップし、適切なポイントを与え、そして——パワーアップ! パワーアップ! モンスターが生きてるぞ!
この3ステップの素晴しいところは、あなたがRubyにモンスターのコードをどう書けばいいのか教えているということだ。Rubyがtraits
のところに来ると:
class Creature
traits :life, :strength, :charisma, :weapon
end
Rubyは裏でコードを埋め、トゲだらけの緑色の心臓を移植し、プルコードを引いて体をジャンプスタートさせる。RubyはCreature
クラスのメタプログラミングを使い、様々なメソッドを作り出し、traits
リストを次のような形に展開する:
class Creature
# 1. リーダ / ライタ メソッドを用意する
attr_accessor :life, :strength, :charisma, :weapon
# 2. creatureの中で使う新しいクラスメソッドを追加する
def self.life( val )
@traits ||= {}
@traits['life'] = val
end
def self.strength( val )
@traits ||= {}
@traits['strength'] = val
end
def self.charisma( val )
@traits ||= {}
@traits['charisma'] = val
end
def self.weapon( val )
@traits ||= {}
@traits['weapon'] = val
end
# 3. initializeはそれぞれのtraitにデフォルトのポイントを設定する
def initialize
self.class.traits.each do |k,v|
instance_variable_set("@#{k}", v)
end
end
end
そうすると、トランプに印刷したらぴったりなくらい短いこの6行のDragon
のコードを、Rubyは喜んで受け入れるようになる。
class Dragon < Creature
life 1340 # タフさの度合い
strength 451 # 逆巻く血脈
charisma 1020 # 歯を見せる笑顔
weapon 939 # 炎の息
end
Eval - 最小のメタプログラマ
メタプログラミングのコードは普通のRubyではあるが、追いかけるのは難しいかもしれない。この時点であなたの目が眼窩の中でぐるぐる回り、膝が動かなくなっていたとしても理解できる。上のコードで一番トリッキーなのは、instance_eval
メソッド とclass_eval
メソッドを呼んでいるところだ。私がeval
について説明している間、
関節にタイガーバームでも塗っておくといい。
私たちはメタプログラミングの話をしている。コードを書くコードを書くということだ。eval
メソッドはこの横町に出入りしている。さすらいのeval
はあなたが文字列の中に収めたコードを受け取ってそのコードを実行する。
drgn = Dragon.new
# これは次のように書くのと同じだ・・・
drgn = eval( "Dragon.new" )
# あるいは、こう書いてもいい・・・
eval( "drgn = Dragon.new" )
穴の開いたプログラムを書いてみることにしよう。新しいDragon
を作るプログラムを書くかわりに、Dragon
が入る部分を穴にしておくのだ。
print "どのモンスタークラスと戦いますか? "
monster_class = gets
eval( "monster = " + monster_class + ".new" )
p monster
(訳注: 変数monsterが前に使われていないとp monsterが未定義の変数エラーになる)
このプログラムはモンスターの名前を尋ねる。あなたがDragon
とタイプすると、monster_class
変数に文字列"Dragon"
が設定される。eval
の中でいくつかの文字列がつなぎ合わされて、"monster =
Dragon.new"
という文字列ができる。そしてeval
が実行されると、monster
変数にはDragon
オブジェクトが設定され、戦いの準備ができる。
これはすごい! いまやプレーヤーがモンスターを選べるようになったのだ!
もちろんこれはプレーヤーが実在するモンスタークラスを指定してくれることを当てにしている。彼らがBotanicalWitch
(植物女)とタイプしてBotanicalWitch
クラスがなかったなら、彼らは顔に例外をたたきつけられることになる。
簡単に言うと、eval
は実行するその場でコードを作ることができるのだ。これは有用であり、かつ危険でもある。
Creature
クラスのメタプログラミングで使われていたinstance_eval
メソッドとclass_eval
メソッドは、ただのeval
と若干異なっている。これらの2つの特別なメソッドはeval
と同じようにコードを実行させるが、しかしクラスやオブジェクトの中に入り込んで、そこでコードを実行するのだ。
# instance_evalメソッドはオブジェクトのインスタンスメソッドの中であるかのように
# コードを実行する
irb> drgn = Dragon.new
irb> drgn.instance_eval do
irb> @name = "Tobias"
irb> end
irb> drgn.instance_variable_get( "@name" )
=> "Tobias"
# class_evalメソッドはクラス定義の中であるかのようにコードを実行する
irb> Dragon.class_eval do
irb> def name; @name; end
irb> end
irb> drgn.name
=> "Tobias"
上で見てわかるとおり、instance_eval
メソッドとclass_eval
メソッドは文字列のかわりにコードブロックを取ることもできる。それがドウェムジーズアレイでものごとがなされる仕方なのだ。
人を見くびった解説や意味ありげな併記はもう十分だ——ドウェムジーズアレイはどこにあるんだ??
注意して歩いて——ここにドウェムジーズアレイの残りの半分がある!!
このコードをdwemthy.rb
に追加して。
class Creature
# このメソッドは戦いで受けたダメージを適用する
def hit( damage )
p_up = rand( charisma )
if p_up % 9 == 7
@life += p_up / 4
puts "[#{ self.class }は魔法で#{ p_up }パワーアップした!]"
end
@life -= damage
puts "[#{ self.class }は死んだ。]" if @life <= 0
end
# このメソッドは戦いの1ターンを行う
def fight( enemy, weapon )
if life <= 0
puts "[#{ self.class }は戦うには死にすぎている!]"
return
end
# 敵を攻撃
your_hit = rand( strength + weapon )
puts "[あなたの攻撃は#{ your_hit }ポイントのダメージを与えた!]"
enemy.hit( your_hit )
# 敵の反撃
p enemy
if enemy.life > 0
enemy_hit = rand( enemy.strength + enemy.weapon )
puts "[敵の攻撃で#{ enemy_hit }ポイントのダメージを受けた!]"
self.hit( enemy_hit )
end
end
end
class DwemthysArray < Array
alias _inspect inspect
def inspect; "#<#{ self.class }#{ _inspect }>"; end
def method_missing( meth, *args )
answer = first.send( meth, *args )
if first.life <= 0
shift
if empty?
puts "[ワオ。あなたはドウェムジーズアレイを全滅させた!]"
else
puts "[準備して。#{ first.class }が現れた。]"
end
end
answer || 0
end
end
このコードはCreature
に2つのメソッドを追加する。hit
メソッドは他のCreature
からの攻撃に対応する。fight
はそのCreature
に対してあなたの一撃を加える。
あなたのCreature
が攻撃を受けると、防御が働いて、charisma
値を使ってパワーアップする。この現象の背後にある秘密については聞かないでほしい。乱数が選択されて単純な算術が行われる。あなたが幸運なら、何ポイントかライフポイントが手に入る。@life += p_up / 4
。
それから敵の攻撃が来る。@life
-= damage
。これがCreature#hit
メソッドの働く仕組みだ。
fight
メソッドはまず自分のCreature
が生きているか確認する。それから敵に対してランダムな攻撃を加える。敵は攻撃をしのぐと、反撃のチャンスを得る。これがCreature#fight
メソッドの働く仕組みだ。
DwemthysArray
についてはすぐに説明する。ほんとにするって。そうするのが楽しいんだ。しばらくhitしたりfightしたりしていよう。
あなたを登場させる。
あなたはこのウサギの派生物をいじり回してもいい。しかしドウェムジーの公式な範例では、そのコードは——そしてキャラクタ
の全体が——明示的に以下のように記述されている。これをrabbit.rb
という名前で保存しよう。
class Rabbit < Creature
traits :bombs
life 10
strength 2
charisma 44
weapon 4
bombs 3
# 小さなブーメラン
def ^( enemy )
fight( enemy, 13 )
end
# 英雄の剣は無制限だ!!
def /( enemy )
fight( enemy, rand( 4 + ( ( enemy.life % 10 ) ** 2 ) ) )
end
# レタスはあなたの体力を上げ、余った葉っぱは敵の顔に飛んでいく!!
def %( enemy )
lettuce = rand( charisma )
puts "[ヘルシーなレタスであなたの体力が#{ lettuce }ポイント回復した!!]"
@life += lettuce
fight( enemy, 0 )
end
# 爆弾。ただし3つしか持っていない!!
def *( enemy )
if @bombs.zero?
puts "[うわっ!! 爆弾が切れた!!]"
return
end
@bombs -= 1
fight( enemy, 86 )
end
end
あなたには4つの武器がある。ブーメラン。英雄の剣。レタス。それに爆弾だ。
はじめるには、irb
を起動して、ここまでで作ったライブラリをロードしよう。
irb> require 'dwemthy'
irb> require 'rabbit'
それから、あなた自身を展開する。
irb> r = Rabbit.new
irb> r.life
=> 10
irb> r.strength
=> 2
いいぞいいぞ。
ウサギはスキューバアルゼンチンと戦う!
あなたはシートベルトもせず、香水を付けただけでドウェムジーズアレイに突入するむわけにはいかない。悪魔のカドリールを慎重に進む必要がある。あるいは南の藪と石炭の迷宮を通り抜ける必要がある。
とりあえずは、こっそり水路の白い残留物に隠れよう。そしてScubaArgentine
に忍び寄るのだ。
class ScubaArgentine < Creature
life 46
strength 35
charisma 91
weapon 2
end
戦いを始めるには、あなたを1つと、ScubaArgentine
を1つ作る。
irb> r = Rabbit.new
irb> s = ScubaArgentine.new
よし、小さなブーメランで攻撃だ!
irb> r ^ s
[あなたの攻撃は2ポイントのダメージを与えた!]
#<ScubaArgentine:0x808c864 @charisma=91, @strength=35, @life=44, @weapon=2>
[敵の攻撃で28ポイントのダメージを受けた!]
[Rabbitは死んだ。]
なんてことだ!! 私たちのウサギが死んでしまった!!
無慈悲な展開だ。だけどあなたにウサギの国に帰ってくれと言うわけにもいかない。あなたが死ななかったふりをして、新しいウサギを作ることにしよう。
irb> r = Rabbit.new
# ブーメランで攻撃!
irb> r ^ s
# 英雄の剣が切り裂く!
irb> r / s
# レタスを食べて体力が回復!
irb> r % s
# 爆弾が3つある!
irb> r * s
これはなかなかかっこいいと思わない? rabbit.rb
のコードは算術記号を置き換えてRabbit
だけの特別な使い方をしている。Rubyでは算術オペレータの振る舞いを変えることができる。なんにしても、算術オペレータはメソッドにすぎないのだ!
# ブーメランは通常はXORオペレータだ。
irb> 1.^( 1 )
=> 0
# 英雄の剣は通常は数を割る。
irb> 10./( 2 )
=> 5
# レタスは割り算の余り。
irb> 10.%( 3 )
=> 1
# 爆弾はかけ算だ。
irb> 10.*( 3 )
=> 30
そうするのが適切である場合には、自分のクラスで算術オペレータを使って構わない。Rubyは算術オペレータをいろいろなクラスで使っている。たとえば配列もいくつかの算術オペレータを持っている。ri Array
でインスタンスメソッドの一覧を出せば見ることができる。
# プラスオペレータは2つの配列を組み合わせて1つの配列にする。
irb> ["D", "W", "E"] + ["M", "T", "H", "Y"]
=> ["D", "W", "E", "M", "T", "H", "Y"]
# マイナスは2番目の配列の要素をすべて最初の配列から取り除く
irb> ["D", "W", "E", "M", "T", "H", "Y"] - ["W", "T"]
=> ["D", "E", "M", "H", "Y"]
# かけ算は配列の要素を繰り返す
irb> ["D", "W"] * 3
=> ["D", "W", "D", "W", "D", "W"]
あなたはこれが数学的にどういう意味があるのかと不思議に思っているかもしれない。配列に3を足したらどうなるのか? 文字列に数を足したら? Rubyはどう反応するのだろう?
これらのオペレータが単なるメソッドであることを思い出してほしい。これらのオペレータは読める言葉になっていないので、それが何をするのか言い当てるのは少し難しくなる。ri
を使おう。あなたは
これらのオペレータがしばしば他の読める名前を持ったメソッドと同じであることに気付くだろう。オペレータとメソッドで好きな方を選んで使えばいい。よりわかりやすいと思える方を。
# 割り算するのにオペレータメソッドを使うか・・・
irb> 10 / 3
=> 3
# ・・・あるいは読めるメソッドを使うか?
irb> 10.div 3
=> 3
Rabbitの剣が割る仕方も同じことだ。
ドウェムジーズアレイの厳しい現実があなたを叩き潰そうと待ちかまえている!!
最後のやつを酸素チューブを使ってプレイチョークをかけて片づけたら、アレイに入る時だ。私はあなたにやれるか疑問に思っている。あなたは戦斧を家に置いてきてしまった。あなたが弱いやつ相手に爆弾を全部使っ たりしていないことを願っている。
あなたには6匹の敵がいる。
class IndustrialRaverMonkey < Creature # 工業的乱痴気モンキー
life 46
strength 35
charisma 91
weapon 2
end
class DwarvenAngel < Creature # ドワーベンエンジェル
life 540
strength 6
charisma 144
weapon 50
end
class AssistantViceTentacleAndOmbudsman < Creature # 副アシスタント触手オンブズマン
life 320
strength 6
charisma 144
weapon 50
end
class TeethDeer < Creature # 歯ジカ
life 655
strength 192
charisma 19
weapon 109
end
class IntrepidDecomposedCyclist < Creature # 恐れを知らぬ腐りかけのサイクリスト
life 901
strength 560
charisma 422
weapon 105
end
class Dragon < Creature # ドラゴン
life 1340 # tough scales
strength 451 # bristling veins
charisma 1020 # toothy smile
weapon 939 # fire breath
end
これがドウェムジーズアレイに生き、呼吸しているモンスターたちだ。彼らがどうやってここに来たのかは知らない。誰も知らないのだ。IntrepidDecomposedCyclist
はきっと10段変速に乗ってきたんだろうと思うが、他のやつについてはわからない。
どうしても知る必要があるというのなら、他のやつはここで生まれたのだということにしておこう。先に進んでもいい?
ドウェムジーズアレイに深く入っていくほど、挑戦はどんどん難しくなっていく。
dwary = DwemthysArray[IndustrialRaverMonkey.new,
DwarvenAngel.new,
AssistantViceTentacleAndOmbudsman.new,
TeethDeer.new,
IntrepidDecomposedCyclist.new,
Dragon.new]
闘い進むにつれ、モンスターが次々と現れてくる。あなたが素早ければ、天使のかぎ爪に肩を貫かれることなく、恐ろしい話を持って逃げ帰ることができるかもしれない。
でははじめよう。
irb> r % dwary
ああ、それから「私は死ぬには若すぎる」というのはなしだ。そんなくだらないことは聞きたくない。私はあなたに若き亡者たちを侮辱させるつもりはない。彼らは私たちの未来だ。我々の未来が終わったら、それが来るのだ。
![]() |
||
「行こう。あのウサギは何て?」 |
「ワオ。それはすごい偉業だな。彼はこの日を一生忘れることはないだろう」 |
「みんなぼくがいかに幸運か噂してる!」 |
ドウェムジーズアレイの作り方
風が止むところまで早送りしよう。ドラゴンは撃破された。卑しき輩たちはひれ伏している。私たちはあなたを好きだ。あなたに忠誠を尽くす。
しかしあなたの鼓膜を食い破っているムカデは何? 指でほじっても、そいつを追い出すことができない! なんてことだ! 地獄のドウェムジーズアレイがまた現れた。正体を現せ、ドウェムジー!
ここにアレイの正体を暴露しよう。
class DwemthysArray < Array
alias _inspect inspect
def inspect; "#<#{ self.class }#{ inspect }>"; end
def method_missing( meth, *args )
answer = first.send( meth, *args )
if first.life <= 0
shift
if empty?
puts "[ワオ。あなたはドウェムジーズアレイを全滅させた!]"
else
puts "[準備して。#{ first.class }が現れた。]"
end
end
answer || 0
end
end
今では、あなたも継承に慣れ親しんでいると思う。DwemthysArray
クラスはArray
を継承し、Array
のように振る舞う。あんなミステリーであるにしては、中身は驚くほど簡単だ。そうじゃない?
つまりはArrayということだ。モンスターでいっぱいの。しかしここで追加されているコードは何なのだろう?
Inspect
inspect
メソッドはドウェムジーズアレイに本当に必要なものというわけではない。これはアレイのお客様へのサービスとしてドウェムジーが追加したものだ。(多くの人が彼をねじけていると言い、多くの人が彼を陰鬱だと言うが、彼が私たちのためにしつらえてくれた処置に敬意を感じないとしたら、私たちは無知のそしりを逃れないだろう。)
Rubyのオブジェクトはみなinspect
メソッドを持っている。これはObject
クラスで定義されているので、親から子へと受け継がれ、生まれたばかりのちっぽけなオブジェクトにもみんなあるのだ。
irb> o = Object.new
=> #<Object:0x81d60c0>
irb> o.inspect
=> "#<Object:0x81d60c0>"
これに気付いた? irb
でオブジェクトを作ると、このごちゃごちゃした#<Object>
というのが転げ出てくる! これはオブジェクトの小さな名札だ。inspect
メソッドは名札を作る。名札はただの文字列だ。
irb> class Rabbit
irb> attr_accessor :slogan
irb> def initialize s; @slogan = s; end
irb> def inspect; "#<#{ self.class }は「#{ @slogan }」と言う>"; end
irb> end
irb> class FakeRabbit < Rabbit
irb> end
irb> Rabbit.new "ぼくはドラゴンの顔を吹っ飛ばした!!"
=> #<Rabbitは「ぼくはドラゴンの顔を吹っ飛ばした!!」と言う>
irb> FakeRabbit.new "かくかくしかじか・・・"
=> #<FakeRabbitは「かくかくしかじか・・・」と言う>
これは実はirb
が言い返しているのだ。あなたがirb
で何かのコードを実行するとき、そのコードが返す値がinspect(検査)される。これは便利だ。これはあなたとirb
の間でちょっとした会話をしているのだ。irb
はあなたの言ったことをただ繰り返し、あなたが自分で言ったことを確認できるようにしている。
あなたは自分のRubyプロンプトを簡単に作ることができる。
loop do
print ">> "
puts "=> " + eval( gets ).inspect
end
このプロンプトでは1行より長いRubyコードを書くことはできない。しかしこれがインタラクティブRubyの本質部分なのだ。どう思う?
最近学んだ2つのコンセプトが、もっとも好ましい仕方で1つになっている。eval
は打ち込まれたコードを受け取ってそれを実行する。そしてeval
のレスポンスがinspectされる。
さて、irb
であなたがモンスターと闘っていると、ドウェムジーズアレイがinspectされ、まだ残っているモンスターを返す。
![]() |
||
「キャットマンブルーバーガーには何が入ってるの?」「ネズミとオニオンソテー」 |
「じゃあ焼いたチーズだけもらえない?」 |
「——ペカンの実をちりばめたチキンがないのはまだわかるけど——しか
しオムレツがないって?? ここの動物たちがおいしいニラを食べたことないなんて言わないでよ」 |
メソッドが見つかりません
あなたが「ディアドラ!」と呼んだら10人が答えるというのは嫌じゃない? Rubyではそういうことは決して起こらない。あなたがdeirdre
メソッドを呼ぶと、ただ1つのdeirdre
メソッドが答える。2つのメソッドの名前を同じにすることはできないのだ。2番目のdeirdre
メソッドを付け加えたとしたら、最初のは消えてしまう。
しかしいろんな名前に答えるメソッドなら作ることはできる。
class NameCaller
def method_missing( name, *args )
puts "あなたは'" + name.to_s + "'を呼んで言う:"
args.each { |say| puts " " + say }
puts "しかしそこには誰もいない。"
end
def deirdre( *args )
puts "ちょうどそこにいたdeirdreにあなたは言う:"
args.each { |say| puts " " + say }
puts "そして彼女はその一瞬一瞬を楽しんでいる。"
puts "(私は彼女があなたのことを詩人だと思ったと思うよ。)"
end
end
上のdeirdre
メソッドを呼んだとき何が起こるか、あなたはわかることと思う。ディアドラはその一瞬一瞬を、あなたの目もくらむような詩的な声の響きを楽しむことだろう。
しかしsimon
を呼んだらどうなるのだろう?
irb> NameCaller.new.simon( 'ねえ?', 'ねえ? サイモン?' )
あなたは'simon'を呼んで言う:
ねえ?
ねえ? サイモン?
しかしそこには誰もいない。
そう、method_missing
というのは留守番電話みたいなもので、メソッド呼び出しを横取りするのだ。ドウェムジーズアレイではみんな自動転送サービスを使っており、あなたがアレイを攻撃すると、その攻撃はアレイにいる最初のモンスターへと送られる。
def method_missing( meth, *args )
answer = first.send( meth, *args )
# ... コードを省略 ...
end
気をつけて! 痩せたちっぽけなmethod_missing
が応戦相手を割り当てた!
4. はっきりさせておこう。ヤマアラシは今、海の方にいる
![]() |
||
|
|
「あまり高く行かないで」 |
5. 歩いて、歩いて、歩いて、歩いたりとか
2匹のキツネたちの周りで夜が更けていった。歌うフクロネズミでいっぱいの路地を抜け、表通りではしわくちゃの遊び着を着てブリーフケースを持ったシマウマたちがぶつかりながら通り過ぎ ていった。彼らは歩き続けた。
店はもう、うねった金属製のシャッターを下ろしていた。溝からはい出したコロオギが小銭を押していた。
![]() |
||
「マルコス大統領に対して君のような悪感情を呼び起こすのは難しいよ」 |
「彼は私の家族の財産を横領してないし、妹を無理に妻にして私を家族から遠ざけてもいないし、私のパイロット免許を取り上げてもいなければ、私の一輪車のタイヤをパンクさせてもいない」 |
「あいつはおじいさんが引っ越す時、小型グランドピアノを運ぶのを手伝わなかったんだぞ!」 |
「なんにしても、あいつがひどい大統領だってことは認めなきゃいけない」とキツネ小が言った。「マルコス大統領がキツネの副大統領にウサギを選 ぶなんてどういう了見なんだろう」
「副大統領? あの眉毛のあるウサギのこと?」
「そうじゃなくて、大きなたらこ唇のやつさ」とキツネ小が言った。
しかし彼らの会話は、歩道の上の空に突然現れたそばかすだらけの猫の顔によって中断された。
![]() |
||
「トラックを探してるの?」「うわっ、なに?」 |
「ああ、僕はこの本の別なキャラクタで、君たちの章をたまたま覗いていたんだ」「僕らはまだ本の中にいたの?!」 |
「ああ、今第7章だ。みんなRubyを勉強してるよ。素晴らしいことだ」 |
これはどういうことだ?
![]() |
||
「この素敵な午後を君らのために台無しにしたくない・・・」 |
「彼の妹が・・・彼の妹が自殺を図ったんだ・・・彼女はホワイに電話して・・・」 |
「キャー!」 |
ああ、これは面白い。さらなるメタ。
ブリクシーとキツネたちの議論をわざわざ描こうとは思わない。推測に過ぎないのだ。彼らに私の家族の事情がどうしてわかると言うんだ? 私は妹を愛している。ずっと昔から彼女を崇拝していた。(妹のクウィルのことだ。)
数ヶ月前にとても辛いことがあって、私が普通でなかったことは認める。私は母の家の裏庭でプール脇の長椅子に横になっていた。ドクターペッパーを飲み、ドイツ風のチョコレートケーキを食べた。私は子供用のフォークで食べていた。他のフォークはみんな皿洗い器の中 で、それしかなかったのだ。フォークには 角が3つあった。
母がクウィルのことを話し始めた。あの子がズボンやバッグにどんなに金を使っていることかと。500ドルもするバッグ。それからこう言った。「それをなくしちゃうのよ。電話ですっかりハイになってるみたいだった」。(母はクウィルが麻薬を吸っていると思いこんでいた。)
母が時にどれほど観察が鋭いかということに気付いた。だから母が「私は実際あの子がコカインをやってるんじゃないかと思っている」と言ったとき、私は立ち上がってコーラを庭の向こうに投げ捨てた。
それは森のどこかに飛んでいった。私たちは長い間話していていたので、缶を投げたときには暗くなっていた。私は少し歩き回り、それから声の限りを尽くして叫んだ。
叔父のマイクがガラス戸を開けて立っていて、私を見ていた。彼はまったくオロオロして「OK、OK、私が・・・」みたいなことを言った。彼のグラスの中の紅茶が揺れ、そこら中に 飛び散った。そしてどこかへ行った。彼は人にものを言うのがあまりうまくなかった。彼はむしろたれこみ屋だ。そして大げさだった。
![]() |
||
「じゃあ、先に進もう・・・」 |
「ただこの道を進むの?」 |
「あ・・・バスが来る・・・」 |
だから、すっかり正直に言うと、私は少しおかしくなっていた。ああ、狂っていたとも。私はそれに対処した。クウィルは定期的に電話をかけてくる。つまらない理由のために、私は滅多に彼女に電話しない。
加えて、彼女は結局自殺したわけではなかった。だからそれは問題ではない。誰に本当のことがわかる? 彼女はただウォッカをたくさん飲んだだけだ。そして彼女は体が小さかった。だからクウィルがウォッカをがぶ飲みするのを見ているのは怖かった。彼女は無理して飲んでいた。
しかし何で私はこんな話をしているんだ? これじゃ私が失望しているみたいに彼女に見えるだけだ。あるいは私が間抜けなように。
どうも脱線してしまったようだ。何の話だっけ? ブリクスはキツネたちがトラックを追跡するのを手助けしている。ああ、そういう話だった。
![]() |
カエルがバスの座席を占めている |
「このバスには乗れないよ」とキツネ小が言った。
「乗って乗って」とブリクスが言った。「何をためらってるの? ああ、カエルか。なに、ちょっと押し込めばいいよ」ブリクスが後ろから押した。
「ねえ」とキツネ大が言った。「こっちは階段に立ってるんだ、誰か詰めてよ!」
「通れた? 若いキツネ君?」とネコが言った。
「いや」とキツネ小が言った。「見えない? 運転手がずっと頭を振っている。僕はどうも不安だ。彼は僕たちを乗せたくないみたいだ」
「進んで」とブリクスが言った。彼はステップから下りて、バスの周りを歩き、プレキシガラスの窓から中を覗いた。「ああ、ちょっとわからない。カエルがたくさん乗ってるみたいだ」。彼は窓を叩いた。「ちょっと、詰めてよ!」
そしてそれがウィグズルの長距離バスに乗るということの現実だった。すごく競争が激しいのだ。朝のバスがあまりに混んでいるので、ホワイトカラーの動物たちはみんな夜の間カエルに席取りをさせているのだ。どういうものか、それでうまくいっているのだ。これが彼らのワークフローと経済の中心になっているのだ。
少しばかり想像力を働かせれば、パーセント記号が傾けたカエルの顔に見えるだろう。頭の中でイメージできた? それでは、文字列の中に居座っているカエルをお見せすることにしよう。
# %s書式は文字列を入れるため。
irb> "席は%sと%sによって占められている。" % ['カエル', '歯のあるカエル']
=> "席はカエルと歯のあるカエルによって占められている。"
# %d書式は数字を入れるため、%f書式は浮動小数点数を入れるためのもの。
irb> frogs = [44, 162.30]
irb> stats = "カエルは%d席を占めてブルークリスタルを%f払った。"
irb> stats % frogs
=> "カエルは44席を占めてブルークリスタルを162.30払った。"
# 書式制御は型について柔軟で、文字列を渡して数として書式指定することができる。
irb> frogs = ['44', '162.30']
irb> stats % frogs
=> "カエルは44席を占めてブルークリスタルを162.30払った。"
ここで見ているのはString
クラスでの %
メソッドの使用だ。このメソッドは文字列と配列を取って、それを一緒にして新しい文字列を作る。配列の中の要素は(順番通りに)取り出され、確保してある席に置かれる。それが1日の始まりで、カエルはその役割を果たしたのだ。
# String#%メソッドも他のメソッドのような呼び出し方ができる。
irb> "ちょっと詰めてよ、%sさん。".%( '歯のあるカエル' )
=> "ちょっと詰めてよ、歯のあるカエルさん。"
# 文字列と配列の間にパーセント記号を置くもっと見栄えのいいやり方で呼んでみよう。
irb> "これが君の今年1098番目のステートメントだ、%sさん。" % ['歯のあるカエル']
=> "これが君の今年1098番目のステートメントだ、歯のあるカエルさん。"
これはまたKernel::format
メソッドやKernel::sprintf
メソッドとしても使える。(C言語には同じような働きをするsprintf
メソッドがある。)
irb> format "カエルは%d重に積み重なって、%dマイル/hで移動した。", 5, 56
=> "カエルは5重に積み重なって、56マイル/hで移動した。"
ほとんどの場合書式指定子%s
(文字列)、
%d
(整数) 、%f
(浮動小数点数)だけで用が足りるだろう。 %p
プレースホルダを使うと、オブジェクトのinspect
が実行される。
そういうわけで、様々な種類のデータを組み立てて文字列を作る場合に、カエルの書式指定はとても便利だ。ri sprintf
のページを見れば、あらゆる種類の書式指定子について学ぶことができる。ここでは簡単なヒントだけいくつか示
しておこう。
配列の要素を配列に入っているのとは違う順序で文字列の中に配置したいとしよう。そういう場合には、パーセント記号の後に番号を付けることで特定の要素を指定することができる(1$
が最初の要素、2$
が2番目の要素、という具合に)。
irb> "このバスはあと%1$dカ所に止まります。%2$d時までにもう%1$dカ所です。" % [16, 8]
=> "このバスはあと16カ所に止まります。8時までにもう16カ所です。"
2番目のヒントは、それぞれの要素に対して文字数、つまり幅を指定できるということだ。要素がその幅より小さい場合は、余分な空白が要素の前に置かれる。詰め物をするわけだ。幅を負の数で指定すると、要素は左詰めになって、空白がその後に置かれる。
# 30字幅
irb> "バスの後部には: %30s。" % ['カエル']
=> "バスの後部には: カエル。"
# 左詰で30字幅
irb> "バスの前部には: %-30s。" % ['カエル']
=> "バスの前部には: カエル 。"
キツネ小はバスの運転手をずっと見上げていた。彼がバスに乗ろうとしなかったことを思い出して!
「何が問題なの?」とキツネ大が言った。「ただ中に乗って、通路に立ってればいいんじゃない?」
「ほんとにこのバスに乗るつもり? 運転手は手がないんだよ」とキツネ小がキツネ大の耳元でささやいた。「彼は手のかわりに吸盤がついてる」
「だから? 触手のある動物には運転ができないっていうの?」
「彼がハンドル操作でへましそうだってだけじゃない。あのたくさんの足をみんなペダルに載せてるんだ。どう見てもいい考えじゃないね。別なバスを探そう。ほら」
「彼はたぶんああやってずっと運転してきたんだよ。今になって急に事故を起こし出すっていうの?」
「バスは事故を起こすさ」キツネ小が言った。「起こすやつは。あれは事故を起こしそうな気がする」
「くだらない!」そしてキツネ大は運転手に向かって大声で言った。「ねえ、運ちゃん、このバスを運転してどれくらいになるの?」
運転手は帽子の下から暗く見つめ、体を彼らの方へ向けようとしたが、触手はハンドルに張り付いたままだった。前足を勢いよく引いたがそれでも離れないので、バンドルに向かい、 腺から滑る分泌物を絞り出そうと集中しはじめた。粘液の泡がにじみ出てきた。
「早くここから離れよう」とキツネ大が言い、2匹は通りの方へ逃げ出して、ブリクスにぶつかった。
「しょうがない、バスは満席だ」とブリクスが言った。「中がカエルでいっぱいなのがわかっていて、なんで運転手がバスを止めたのかわからないよ」
「あいつは我々にぶつかるところだったんじゃないかと話していたんだ」とキツネ大が言った。「それからドアを開けて予定通りの停車みたいなフリをしたんだ」
「ブリクス、言っておくけど、その可能性についてはっきり声に出して議論したわけじゃなくて、それで正式に同意するチャンスがなかったけど、僕にはまったくありそうなことだと思えるね」とキツネ小が言った。
「バスはみんなあんな風にいっぱいなんじゃないかと思う」とブリクスは唇をかみ、考え、あたりを見回しながら言った。「ただちょっと・・・」。南の方のアパート群を指さした。「しかしたぶん・・・」。ブリクスは空を見上げて星を調べ、頭をかいて、指先で小さくつつく動作で星座を数えた。
「君は僕たちの進路を星を見て決めるつもりなの」とキツネ小が聞いた。
ブリクスは黙って、ペンキ屋の裏のみすぼらしい道を通して北の方に目をこらした。しかし彼らの後を追って副道を行く前に、スモッチキス、私はあなたのためにもう一匹カエルを用意している。 それは何でも載せられる長い睡蓮の葉の上にいる。
irb> cat = "ブリクス"
irb> puts "#{ cat }は何を見てるの? #{ cat }は気付いているの??"
=> "ブリクスは何を見てるの? ブリクスは気付いているの??"
前の小さなカエル(%s
や%d
)は1つの文字列に対するプレースホルダに過ぎなかった。文字列の上で場所取りをするのだ。
こちらの睡蓮の葉はナンバー記号のつぼみで始まる。電話機についているのを見たことがあるだろう。つぼみの後の部分は、2枚の睡蓮の葉っぱで縁取られている。葉っぱは中括弧で、これもコードブロックの蟹のハサミとして前に何度も目にしている。
空の睡蓮の葉っぱ
"#{}"
は空の文字列""
になる。
二重引用符の中に睡蓮の葉っぱがあるときには、Rubyは2枚の葉っぱの間にあるコードを実行する。睡蓮の葉っぱは取り除かれて、かわりにコードの実行結果が置かれる。この睡蓮の葉っぱの置き換えは、式展開と呼ばれている。
irb> fellows = ['ブリクス', 'キツネ大', 'キツネ小']
irb> puts "#{ fellows.join 'と' }の旅についていこう。"
=> "ブリクスとキツネ大とキツネ小の旅についていこう。"
睡蓮の葉っぱは丈夫でどんなコードでも中に入れられる。上の例ではArray#join
を使ったが、何でも好きなものを入れられる。オブジェクトのメソッド呼び出しでも、if
文やcase
文でも、クラス定義さえ入れることができる。
irb> blix_went = :北
irb> puts "ブリクスは黙っていたが、#{ blix_went }の方へ向かい、#{
if blix_went == :北
'ペンキ屋の裏のみすぼらしい道を進んだ'
elsif blix_went == :南
'アパートの群れへと入っていった'
else
'・・・彼がどこへ行ったのか誰も知らない'
end }。しかし彼らの後を追う前に・・・"
=> "ブリクスは黙っていたが、北の方へ向かい、ペンキ屋の裏のみすぼらしい道を進んだ。
しかし彼らの後を追う前に・・・"
キツネたちはブリクシーの後について、ペンキ屋の裏を通り、ひび割れてでこぼこのあるアスファルトの道を進んだ。ぼろほろな路地にある店はみんな寄りかかり合って立っていた。ある場所では舗石が地面から突き出し 、道は危なっかしく、 乱雑に連なった岩棚みたいになっていた。まるで都市計画者がプレートテクトニクスを讃えて作ったかのようだ。小さなドラッグストアが地面の下に滑り込んでほとんど見えなくなっていた。
しかしそこは本当にカラフルだった。ペンキ屋が古いペンキを隣近所に投げ出していた。ペンキ屋に最も近い店は、窓枠も雨樋も何百色というペンキが詰まっていた。それに壁や敷石 にも。
基本的にペンキ屋のポーチから始まっているその道は、巨大な不調和の中へと、乏しく染められたマーケットへと続いていた。
さらに進むと、歯医者の建物が赤いペンキに飲み込まれていて、その上に未熟な画家が煙突を通って煤だらけの暖炉に落ちた大きな赤ん坊の絵を描いていた。衝突によって立ち上る灰の煙を描く粗い黒のストロークは、子供の腕と背に生えた濃い毛のように見えた。その子供はたっぷりした髪を 生やすには幼すぎたが、豊かなブロンドの巻き毛が子供の頭から流れ出ていた。子供の足の下には、「ビール飲み」と いう文字が書かれていた。
同じ画家が歯医者の隣の図書館も襲って、足のない赤ん坊のチームが輝く鎖で緑色のスポーツカーをぬかるみの中から引っ張り出している絵を壁いっぱいに手早く描いていた。ここでもまた、すごい金の巻き毛だ!
「答えがほしい」その風景を前に立ち止まってキツネ大が言った。
「そんなものはないんじゃないかという気がし始めたよ」とキツネ小が言った。「ここにあるのが答えなのかも」
「ビール飲みが?」キツネ大が言った。彼は図書館の壁に近づいて、遠近法的に近くにいた足のない子供の1人のほっぺたに触った。その子供の頬にはあご骨が無数にあるように見えた。
ブリクスはさらに2軒先に進んで、歪んだ煉瓦造りの間の舗装された谷間を、R・Kのゴリラ造幣局という金属のステッカーが戸についている建物の所まで来た。その建物にはR・Kのゴリラ造幣局で使えるさまざまな支払いオプションや身分証を表す小さなロゴが貼られていた。窓の格子にさえ、保険情報開示やセキュリティ警告や政府の認可シールが並んでいた。それらすべてに加え、破れたポスターや広告をステッカーが覆い、それをさらにカーボン紙が覆っていた。そしてそのすべてに、どこへでも入り込んでくるペンキの跳ね散らかしが混じり合っていた。
![]() |
||
|
「言ってくれ・・・オレの金は原始的か?? この紙が人間の紙の未開な形態だと思うか? オレの長い指は気味悪いか? ええ??」 |
「ああ、僕らが入ってきたとき、あんたはそのお金を食べようとしていた」 |
「新鮮な紙の舌触りが好きなんだ」とカウンターのゴリラが言った。彼の指は札をそっとこすっていた。彼は扇子に拡げた札に顔を近づけ、紙の札の臭いを鼻で嗅いだ。
「今夜はR・Kはいるの?」ブリクスが聞いた。
「R・Kはいない」とゴリラのレジ係が言った。彼は3人の旅行者の方に体を向けて、カウンターの上に金を等間隔に離し、縁をきれいにそろえて並べた。「この中でどれが一番価値が高いと思うね?」
キツネたちは違う種類の札を眺めた。「たぶん——違うな、きっとこれは——待って、バナナが描いたのってある? だって——いや、果物もぶら下がるロープもないや——これは難しいな!」 キツネ小がつぶやいた。そして声を低めて、「難しくてわからない。これは何を表しているんだろう? シンボルか何か? 札にシンボルしか描かれていないなら、どれが一番価値があるか当てるのは僕たちには不可能だ」
「だから推測しなと言ったんだ」ゴリラは札を一枚ずつ順に叩いた。「ほら、確率は5分の1だ」
「シンボルが何か意味しているなら」キツネ大が言った。「当てられるはずだ」
「当てられるとも」とキツネ小が言った。
「いや」とゴリラがいった。「シンボルに意味はない」
「誰が作ったにせよ、お金には意味があるはずだ」とキツネ小が言った。「なぜこのシンボルを使っているのか?」濃いインクで印刷されたアンパサンドを指さした。
「ああ、君がお金の臭いを嗅いで夢想しているところを向こうから見たんだ」とキツネ大が言った。「このシンボルは君にはたくさんの意味があるに違いない!」
「それは違う」とゴリラが言った。
ここで私が口を挟めるのであれば、私はシンボルには意味があると思う。意味がたくさんは詰まってないかもしれないし、割れ目から漏れ出しはしないかもしれないが、一片の意味があるだろうことは 間違いない。
irb> $:
=> ["/usr/lib/ruby/site_ruby/1.8", "/usr/lib/ruby/site_ruby/1.8/i686-linux", "/usr/lib/ruby/site_ruby",
"/usr/lib/ruby/1.8", "/usr/lib/ruby/1.8/i686-linux", "."]
アメリカのお金の記号で始まる変数はグローバル変数だ。グローバル変数はプログラムのどこからでも、どのスコープの中からでも見える。(ドクター・チャムはこの変数をオリジナルズのコンピュータを探るときに使っていた。)
それではドル記号にコロンが続くのが、require
でファイルをロード
するときにRubyが探すディレクトリの配列を表すのはなぜなのだろう?
ドル記号は「グローバル」を意味する。だけどコロンの方は何だ?
歴史的に、多くのオペレーティングシステムでは、ディレクトリのリストはコロンで区切られている。私はこのコロンを、ディレクトリの中でファイルを探すひと組の目だと思うのが好きだ。私たちは目の後に見張るリストを置 いておくのだ。
特別なグローバル変数が他にもいくつかある。
irb> $" # $"変数はrequireでロードされたすべてのファイルを保持している。
=> ["irb.rb", "e2mmap.rb", "irb/init.rb", ... "rbconfig.rb"]
# これらのファイルはどこか別なところに格納されているが、その中のコードはこのプログラム
# で使われている。脚注なんかで他の人の仕事を引用するのに似ているので二重引用符
# を使う。
irb> $0 # $0変数は実行中のプログラムのファイル名を保持している。
=> "irb" # ゼロは数え上げの最初の数字だと見なせるので、この変数は「このプログラムはどこか
# ら始まったのか?」と言う質問に答えるのだ。
irb> $* # $*変数はプログラムに渡されたすべての引数を保持している。
=> ['--prompt', 'simple']
# Rubyのメソッドが引数を配列で取るときにアスタリスクを使うことを覚えていれば、これは
# 簡単に覚えられるだろう。
# $!は最近発生した例外を保持している。ここでエクスクラメーションは警告状態にあることを示している。例
# 外だー!
irb> begin
irb> raise TypeError, "この情報はちょっと信じられない。"
irb> rescue
irb> p $!
irb> end
=> #<TypeError: この情報はちょっと信じられない。>
# $@は最近起きた例外のバックトレースを保持している。バックトレースは例外が発生したときにRubyがどこに
# いたかを示している。
irb> begin
irb> raise TypeError, "この情報はちょっと信じられない。"
irb> rescue
irb> p $@
irb> end
=> ["(irb):25:in `irb_binding'", "/usr/lib/ruby/1.8/irb/workspace.rb:52:in `irb_binding'",
"/usr/lib/ruby/1.8/irb/workspace.rb:52"]
「私は君のことを覚えていない」とブリクスがゴリラのことを興味深そうに見ながら言った。「君はR・Kの子供か何かなのか?」
「ねえったら!」エクスクラメーションマークのついた札をゴリラの鼻先に突き出しながらキツネ小が言った。「これに意味がないなんて言わないで! エクスクラメーションマークが付いているくらいだから、これはきっと重要なのに違いないんだ。もしかしたら緊急の時に使うのかも! 病院の支払いとかそんなときに!」
「そうだ、手術だ!」キツネ大が言った。
ゴリラは帽子のつばの下からキツネたちをうんざりしたように見つめた。「いや、違う。手術代にこれを払うことはできない」
「しかし僕たちの話の要点はわかるよね」とキツネ小が言った。彼は他の札を何枚か手に取った。「この札は手術代には使えないと言ったね? それはつまり手術以外の何かの目的があるというふうに聞こえる。じゃあこのクエスチョンマーク のついたやつだ。これは何のため?」
「おい、それを返せ」ゴリラはカウンター越しに札を掴もうとしたが、彼の長い親指が邪魔をして、札を掴んだと思うと、毎回自分の長い親指を掴んでいた。
「おい、おい、こいつ怒ってるぞ」とキツネ大が面白そうに手を叩いた。「何でだろう。我々が興味深い意味について口にしたとたんに彼が怒りはじめたのに気付いた? 当たってるんだ! 我々はゲームをこんなに早く解いてしまったんだ!」
「僕たちやったんだ!」キツネ小が言った。彼の一方の肘はゴリラに捕まれていて、もう一方の腕でアンダースコアの書かれた札を振っていた。「これは床関係のものを買うのに使うんだ。タイルとかリノリウムとか」
「わかった」とキツネ大がゴリラの指をほどきながら言った。「あとはどっちが価値が高いか見当をつければいいだけた。手術かリノリウムか! これは簡単だ!」
「違う、違うぞ!」ゴリラが叫び、キツネ小を捕まえて平手でぶち始めた。「お前らはサルの金のことを何も分っちゃいない!! お前らは自分たちの金さえ持っていない!!」
「自分たちのお金なんて簡単に持つことができるよ!」キツネ大が言い、サルの帽子を取って部屋の向こうに投げた。帽子は飛んでいって貸金庫の裏に落ちた。「君の帽子はあそこだ!」
「ねえ、お札を彼に返しなよ」とブリクスが腕を振りながら言った。「この男は役に立つかもしれないんだ」
「ぶつのやめてったら!」キツネ小が叫んだ。「このドットのあるやつがほとんどわかるところなんだ!!」
突然、警告なしに非常な正確さをもって、キツネ大がサルの鼻を掴んで顔をカウンターに打ち付けた。カウンターの上にあったペンとインク台が震え、キツネ大が「バン!」と言った。 ゴリラの目が眠たげに回り、腕と・・・それから首と・・・そして頭がカウンタ裏の床に滑り落ちた。
あなたが使いたいと思うかもしれないグローバル変数をもういくつか挙げておこう。
irb> $/ # $/はラインセパレータで、通常は\nがセットされており、これは_Enter_あるいは行末を
=> "\n" # 表している。スラッシュはファイルの中の行を切る剣だ。
# ラインセパレータはeach_lineやreadlinesメソッドが文字列をばらばらに分ける仕方を制御する。
irb> "ジェフ,ジェリー,ジル\nマイケル,メアリー,マートル".each_line { |names| p names }
=> "ジェフ,ジェリー,ジル\n"
=> "マイケル,メアリー,マートル"
# ラインセパレータを変えると、each_lineのようなメソッドの働き方を変える。
# ラインセパレータをカンマに変えるとどうなるか見てみよう。
irb> $/ = ','
irb> "ジェフ,ジェリー,ジル\nマイケル,メアリー,マートル".each_line { |names| p names }
=> "ジェフ,"
=> "ジェリー,"
=> "ジル\nマイケル,"
=> "メアリー,"
=> "マートル"
irb> $, # $,変数はジョイン・セパレータで、Array#joinやKernel::printで文字列をつなぎ合
=> nil # わせるときに使われる。カンマが接続文字としてよく使われる。
# ジョイン・セパレータは通常空だ。
irb> ['ろうそく', 'スープ', 'さば'].join
=> "ろうそくスープさば"
irb> $, = ' * '; ['ろうそく', 'スープ', 'さば'].join
=> "ろうそく * スープ * さば"
# しかし普通はグローバル変数を変える必要はない。
irb> ['ろうそく', 'スープ', 'さば'].join ' # '
=> "ろうそく # スープ # さば"
irb> $; # $;変数はスプリット・セパレータで、文字列をString#splitでスプリットするときに使われ
=> nil # る。
# スプリットセパレータは通常空になっている。その場合、String#splitは文字列をホワイトスペースのあ
# るところで分離する。
irb> "ろうそく スープ\nさば".split
=> ["ろうそく", "スープ", "さば"]
irb> $; = 'そ'; "ろうそく スープ\nさば".split
=> ["ろう", "く スープ\nさば"]
# しかし、普通はグローバル変数を使う必要はない。
irb> "ろうそく # スープ # さば".split ' # '
=> ["ろうそく", "スープ", "さば"]
ゴリラ造幣局の外では、ブリクスがキツネたちを叱りつけていた。「あの男の助けを借りることもできたのに! R.K. がどこにいるか彼が知っていれば、彼の情報が利用できたんだ!」
「僕たちはサルのお金なんか必要ないよ!」とキツネ小が言った。「僕たちは自分のお金を作れる!」
「我々は電気リストバンドだって支持する!」とキツネ大が言った。
「彼の金は役立たずだ」とブリクスが言った。「あれはゴリラのお金だ。価値がない。ブルークリスタルよりも悪い」
「しかし何かの目的は持っているはずだ」とキツネ大が言った。
「いや、目的なんてないんだ」とキツネ小が言った。「あいつは単に無価値だと言ってた」
「だけどリノリウムや手術はどうなんだ?」キツネ大が言った。
「ああ、そうだ」キツネ小がブリクスに向かって言った。「リノリウムや手術はどうなの?」
「病院で働いているのがみんなゴリラで、ホームセンターチェーンが厳密にゴリラによって運営されているなら、そう、リノリウムや手術代に使えるろう。しかしすごくずさんなリノリウムと、ぞっとするような手術になるだろうことは請合ってもいい。君たちがあの経済を生き延びられるとは思わないね」
「じゃあ、R・K がそんなに悪賢いなら」キツネ大がずるそうに笑いながら言った。「どうして彼はそんな役立たずな通貨を印刷してるわけ?」
「別な活動を隠蔽するためさ」とブリクス。「それはそうと、君がそんなに賢いなら、どうしてあの哀れなゴリラを乱暴に打ち付けたりしたんだ?」
「あれはいたずらだと思ったんだ」としょげながらキツネ大が言った。「ここにいる友達が、一日中私がどんな極限状態にあったか話してくれるよ」
「そして君の怒りがついに煙を出す鼻を持ち上げたわけだ!」キツネ小が言った。「君はついにそのヤギ髭にふさわしいものになったんだ」
![]() |
||
羽のある巻物運搬人 |
「おい! 私たちを運んでくれ!!」 |
|
道を進んでいきながら、2匹のキツネにはどこに向かっているのかもわからなかったが、このような緊急時でもあり、ブリクスに先導させながら、今では楽しく時を過ごしていた。彼らはブリクスの後を無頓着に横道にそれながらついていき、通り過ぎる人を邪魔して午後を過ごした。
彼らのそんな実況中継の対象の1つは羽のある巻物の運び屋で、即座に宣誓され、公認される必要のある文書をひと組のコウモリが運んでいた。彼らには遅れることが許されず、素早 さが要求され、巻物を巻く時間さえなく、スイスチーズを放り出してドアから飛び出す必要があった。
この運び屋はRubyでデリミッテドタイプと呼ばれるものを表している。長い一連の文字が巻物を構成し、その両端にはコウモリが配置されて丸まった羽で巻物を支えている。
始めのコウモリは%w
と書かれた帽子をかぶっており、これは巻物が言葉(word)の集まりであることを示している。
irb> bats = %w{The Winged Scroll Carriers}
=> ['The', 'Winged', 'Scroll', 'Carriers']
%w
コウモリと巻物をRubyに渡すと、語の配列が出てくる。このシンタックスはそれぞれの語をカンマと引用符で飾るという面倒なことをやりたくない場合のためのショートカットになっている。
あなたはとても急いでいて一刻の猶予もないのだ。それで言葉をコウモリの間に手早くメモし、どこで切ればいいかはRubyに判断させるのだ。
コウモリが違えば帽子も違う。たとえば、%x
の帽子は外部プログラムを実行する。
irb> %w{ruby --help}
=> ["ruby", "--help"]
irb> %x{ruby --help}
=> "Usage: ruby [switches] [--] [programfile] [arguments] ..."
私のお気に入りは%Q
の帽子で、単に%
と書くこともできる。これは二重引用符付きの文字列と同じように振る舞うが、何行にも及ぶ
長い文字列を扱うときには見た目が良くなる。たとえばeval
で新しいメソッドを追加しようとしているものとしよう。
m = "bats!"
eval %{
def #{ m }
puts "|" * 100
end
}
二重引用符の文字列と同じように、中で式展開の蓮の葉っぱを使うこともできる。
![]() |
||
|
クローンの実 |
「食べれば食べるほど、あなたが増えていく!」 |
ブリクシーは頭を振った。「やれやれ」
「うわっ! 手に子供ができた」小さなキツネの胎児が手の平から出てくるのを見てキツネ大が言った。
「でも、いい実なんだ」とブリクスが言った。「その実で作ったワインを飲むと歯に目玉でできる。それだけさ」
「あっ、痛い!」キツネ小が叫んだ。頭の毛穴からミニチュアの彼が絞り出てきていた。しかしそのすぐ後には、彼は小さな自分を抱えて子守歌を歌っていた。「 またとない、またとない、ナイチンゲールが優しく歌った。瞬く星の光、静かに眠る、スズカケの切り株の上で」
Rubyのオブジェクトを複製するのには、木の実くらいのコードしか必要でない。
irb> tree = [:berry, :berry, :berry]
=> [:berry, :berry, :berry]
irb> treechild = tree.clone
=> [:berry, :berry, :berry]
clone
メソッドはRubyオブジェクトの正確なコピーを作成する。これは普通の代入とどう違うのだろう?
irb> tree_charles_william_iii = tree
=> [:berry, :berry, :berry]
変数にオブジェクトを代入するというのはニックネームを新たに作るだけだ。上の配列はいまやtree_charles_william_iii
と呼べるようになった。あるいは短くtree
と呼ぶこともできる。同じオブジェクトに違う名前だ。
しかしながら、クローンの方はオブジェクトのコピーだ。コピーは元のオブジェクトに影響を与えることなく変更することができる。
irb> treechild << 'flower'
=> [:berry, :berry, :berry, 'flower']
irb> tree
=> [:berry, :berry, :berry]
clone
メソッドはオブジェクトに付随するものすべてをコピーするわけではない。上の配列の場合、配列だけがコピーされ、中のシンボルや文字列はコピーされない。
dup
メソッドもオブジェクトをコピーするものと思っているかもしれないが、dup
メソッドはclone
ほど正確にコピーするわけではない。たとえば"frozen"なRubyオブジェクトがあって変更できなかったとする。このオブジェクトをclone
すると、その正確なコピーが作られ、コピーもまたfrozenになっている。しかしdup
を使った場合にはfrozenでないコピーが作られ、値を変えたければ変えることができる。
clone
メソッドではオブジェクトのメタクラスもコピーされるが、dup
の方ではコピーされない。
irb> o = Object.new
irb> class << o
irb> def nevermore; :nevermore; end
irb> end
irb> o.clone.nevermore
=> :nevermore
irb> o.dup.nevermore
# NoMethodError: undefined method `nevermore' for #<Object:0xb7d4a484>
# from (irb):7
しかしいつもオブジェクトのコピーを作る必要があるわけではない。collect
やgsub
やformat
といったメソッドの多くは、その仕事の一環としてオブジェクトのコピーを作るからだ。
![]() |
||
「ゴホッ」 |
ピンクの煙を吐くシカ |
##### |
丘を越え、谷を下り、彼らはピンク色の煙を吐くシカのいる草地に出た。シカの言葉で飾られたピンクの煙が重なり合って太陽はぼんやりとなり、地平はグレープフルーツのグラデーションに染 まり、草地の上に光を宿していた。雲は互いにすれ違い、あるものは上の方へ、カナダにいる親戚の方へと向かい、他のものは受取人の蹄から読める距離に着地した。
「止って! お願い!」キツネ大が叫んだ。「息ができない煙の中に入るつもりはないよ!」
「何を叫んでいるの?」ブリクスが言った。 彼の足の後ろを薄い雲の電報が漂っていた。「囁き以上の大きな声を出す必要はないよ。この長くて薄っぺらな雲は通常ただの呟きかため息だ。最後まで言い終わりさえしていないかもしれない」
「あの雲に書かれているのはみんなシカの言葉なの?」とキツネ小が聞いた。
「助けて! みんなどこにいるんだ?」濃いもうもうとした煙と鋭く薄い雲からなる激しい弁舌に取り巻かれてキツネ大が言った。彼はぐるっと回ってそれぞれの方向に「誰かいたら返事して!」と叫んだ。
彼は濃い雲の中の切れ目を探し、両手でかきながら進んだ。冗長で怒りに満ちた雲は彼を前に突き出し、文の間の短い区切りの中に彼を押し込めることで応えた。彼は くぼみの中に落ち、雲の層が押し寄せてくるのを頭を下げてやり過ごした。
「ああ、シカにはこれが読める」とブリクスが言った。「連中は相手の顔めがけて鼻の穴からこの煙を吹き付けるんだ。僕はシカの恋愛詩に跨った男のことを聞いたことがある」
「バカじゃないの」とキツネ小が言った。
「ああ」とブリクス。「その男というのは僕だ」。ブリクスは腕を伸ばして、頭の上で渦巻いている煙の層につかまった。「どの雲が泣き言で、どの雲が大言壮語か見分けられ さえすればいいんだ」。ブリクスは雲につかまったまま移動し、雲が上向くところで手をゆるめて、足が地面に沿ってゆっくり移動し続けるようにした。「ああ、これはいい方の雲だ。箒の柄 みたいに長い。ちょうど車みたいな形の雲を見つけた男がいるよ。風防に、サイドエアバッグに、パワーステアリング付いている。不思議だよね!」
「そしてその男というのは——」
「僕さ!」そしてブリクスは長い凍った雲に、ぶら下がっている文字を足がかりにしてよじ登り、誇らしげに立って、小さなキツネのとがった影のずっと上の方に浮いていた。
「僕にだってできるよ」とキツネ小が言った。「ノッポと僕はいつもジェットスキーしてるんだ。僕は自分のジェットスキーにちゃんと立ってる。これだって似たようなものさ」
流れてくる煙の間をキツネ大は走り抜けた。文をばらばらにし、文字はごちゃまぜの語になって地面に散らばったが、シカの通信の陰鬱な部分がじめじめした不透明な霧になっている ところで行き詰ってしまった。
一方小さな相棒の方は、細い列になった煙を腕に抱え、滑り降りながら「タリホー!」と叫んだ。しかし彼はあまりにしっかりとつかまっていたため、雲が腕の中で蒸発して下に落っこちた。
あなたはRubyを使い始めたばかりなので、最初は正規表現がよく理解できないかもしれない。Regular Expression Libraryから正規表現を切り取って、その式がどうして機能するのか全然わからないままコードに貼り付けているのかもしれない。 それでうまくいくなら!
loop do print "パスワードを入力してください: " password = gets if password.match( /^\w{8,15}$/ ) break else puts "** パスワードが間違っています! \
パスワードは8文字から15文字である必要があります!" end end
読めないシカ語がこのコード例の中にあるのがわかる? /^\w{8,15)$/
は正規表現だ。翻訳させていただくと、この正規表現は「英字か数字かアンダースコアだけを許容してください。8文字以上、15文字以下で」と言っている。
正規表現はRubyやそのほかのたくさんの言語に組込まれているミニ言語だ。しかしミニと言うべきじゃないかもしれない。正規表現はこんがらがっていて複雑で、Rubyプログラム 自体よりずっと難しいものになりうるからだ。
正規表現の使い方はいたって簡単だ。あのシカのようにやるのだ。難しいのは煙を作るとこだけで、煙に肘を引っかけてマスタードプレッツェルの犬を買いにウィンナーシュニッツェルまでドライブしていくのは簡単なことだ。
irb> "good_password".match( /^\w{8,15}$/ )
=> #<MatchData:0xb7d54218>
irb> "this_bad_password_too_long".match( /^\w{8,15}$/ )
=> nil
String#match
メソッドは正規表現を使うもっとも簡単な方法だ。match
メソッドは文字列が正規表現で記述されたルールにマッチするかチェックする。正規表現は文字列に対してだけ使えて、一連の条件に文字列が合うか調べる。条件が合えば、MatchData
オブジェクトが返される。マッチしなければnil
が返される。
文字列の中を検索するというのが最も基本的な正規表現の使い方だ。大きなファイルがあって、その中にある単語やフレーズを探したいとしよう。前から少し時間がたったので、 プリイベンチュアリストの遺失物レジストリを再び検索してみることにしよう。
require 'preeventualist'
PreEventualist.searchfound( 'truck' ) do |page|
page.each_line do |line|
puts line if line.match( /truck/ )
end
end
これは以前に語“truck”を含む行を検索したのとあまり違わない。前はputs line if line['truck']
を使ったが、これはただ単語を探す場合に使えるもっと
簡単な方法だ。正規表現/truck/
はこれと等価だ。単語“truck”が文字列のどこかにないか探すのだ。
しかし、大文字になっていたらどうだろう。Truck。そしたらどうする?
puts line if line.match( /[Tt][Rr][Uu][Cc][Kk]/i )
文字クラスというのは、角カッコで囲まれた区画のことだ。それぞれの文字クラスはその位置でマッチすべき文字のリストを与える。(最初の
文字は大文字のT
か小文字のt
にマッチする。2番目のはR
かr
にマッチする。以下同様。)
これは以下のようなもっと簡単な書き方ができる:
puts line if line.match( /truck/i )
正規表現の末尾にある修飾子i
は検索するときに大文字小文字を区別しないように
指定している。これはTruckにマッチする。TRUCKに
もマッチする。TrUcKにもマッチする。そしてそのほかの大文字/小文字を変えたものにもマッチする。
そうだ、あなたのトラックには何かのモデルナンバーがついているかもしれない。T-1000だったかT-2000だったか。よく覚えてない。確かT何千だ。
puts line if line.match( /T-\d000/ )
このシカ語を見て。\d
は数字を表す。これは正規表現における数字に対するプレースホルダだ。正規表現はT-1000、
T-2000からT-9000までのどれかにマッチするようになった。
文字クラス | ||
\d |
数字にマッチする | [0-9] とも書ける |
\w |
英数字(英字、数字、アンダースコア)にマッチする | [A-Za-z0-9_] とも書ける |
\s |
ホワイトスペース(スペース、タブ、CR、LF)にマッチする | すなわち[ \t\r\n] |
\D |
数字以外にマッチする | 否定形のセット[^\d] と同じ |
\W |
英数字以外にマッチする | [^\w] と同じ |
\S |
ホワイトスペース以外にマッチする | [^\s]と 同じ |
. |
ピリオドはすべてにマッチする |
正規表現の構築では、これらのプレースホルダをつなぎ合わせ、探すものを表すようにする。1文字の数字にホワイトスペースが続いている所を探すなら、/\d\s/
だ。3つの数字が続くのは/\d\d\d/
だ。最初のスラッシュと最後のスラッシュは正規表現の始めと終わりを示す。
数字が3つ続くのは/\d{3}/
とも書ける。\d
のような文字クラスのすぐ後に量指定子を置いて、その文字クラスを何回繰り返すか指定することができる。
量指定子 | ||
{n} |
正確にn 回 | 正確に3つ数字が並ぶのは /\d{3}/ |
{n,} |
n 回以上 | 3文字以上の英字が並ぶのは /[a-z]{3,}/i |
{n,n2} |
n 回以上、n2 回以下 | 数字かカンマが3から9文字続く場合 /[\d,]{3,9}/
|
* |
アスタリスク * は{0,} の略記法 |
コロンの後に0文字以上の英数字が続く場合
/:\w*/ |
+ |
プラスは {1,} の略記法 |
マイナス記号かプラス記号が1文字以上続く /[-+]+/ |
? |
クエスチョンマークは {0,1} の略記法 |
3桁の数字の後にオプショナルなピリオドが続く /\d{3}[.]?/
|
すごく良く使われる正規表現は、電話番号にマッチするものだ。アメリカの電話番号は(地域コードも含め)数字文字クラスと量指定子でマッチさせることができる。
irb> "Call 909-375-4434" =~ /\d{3}-\d{3}-\d{4}/
=> 5
irb> "The number is (909) 375-4434" =~ /[(]\d{3}[)]\s*\d{3}-\d{4}/
=> 14
今回は、式を検索するのにmatch
のかわりに=~
オペレータを使った。このオペレータはマッチオペレータで、等号記号にチルダがついている。チルダは煙突の縁から出てくる煙りみたいに見える。正規表現みたいな謎の言葉を煙にしてはき出すシカ
のイメージで覚えることにしよう。チルダの煙は、正規表現を指し示している。
マッチオペレータは数を返す。この数は、文字列の中で正規表現がマッチした位置を示している。だからマッチオペレータが5
を返すなら、「マッチ
部分の前に5文字ある」ということだ。
マッチした文字列全体が必要なら、マッチオペレータを使っている場合には特別なグローバル変数$&
で取得できる。match
メソッドを使っている場合には、MatchData
オブジェクトを文字列に変換すればマッチした文字列が得られる。
# =~ と $& を使う。
irb> "The number is (909) 375-4434" =~ /[(]\d{3}[)]\s*\d{3}-\d{4}/
=> 14
irb> $&
=> "(909) 375-4434"
# MatchDataオブジェクトを使う。
irb> phone = /[(]\d{3}[)]\s*\d{3}-\d{4}/.match("The number is (909) 375-4434")
=> #<MatchData:0xb7d51680>
irb> phone.to_s
=> "(909) 375-4434"
ルビイストの多くは、グローバル変数でなくローカル変数のオブジェクトを使う2番目の方法を好んでいる。グローバル変数を使うのは大ざっぱなやり方で、簡単に上書きされてしまうからだ。2つの正規表現を続けて使うなら、グローバル変数は2番目の結果で上書きされる。しかしローカル変数を使うなら、2つのマッチ部分を両方とも保持しておくことができる(別な 変数を使っている限り)。
マッチ以外の正規表現の一般的な使い方として、Rubyで検索置換を行うというのがある。たとえば"cat"という語を探して"banjo"に置き換えることがてきる。 確かにこれは文字列 でも正規表現でもやることができる。
irb> song = "I swiped your cat / And I stole your cathodes"
irb> song.gsub 'cat', 'banjo'
=> "I swiped your banjo / And I stole your banjohodes"
irb> song.gsub /\bcat\b/, 'banjo'
=> "I swiped your banjo / And I stole your cathodes"
gsub
メソッドは“global substitution”
の意味だ。最初の例では“cat”と同時に“cathodes”の最初の3文字も置き換えられているのに注意してほしい。文字列にはシンプルなsub
メソッドもあり、これは置換を1回だけ行う。
ブリクスとキツネたちが草地にいる良くしゃべるシカの吐く濃いピンクの煙を進む中、この章は終わる。
6. ヤマアラシがどっかに行ってないか確認するために立ち寄っただけ
![]() |
||
|
「帽子が落ちてる」 |
|
7. 出かけています
熱気球で逃げるクウィル。
バンジョーチャンピオンの幕。
バンジョーを傘にしている
クウィル。
ビゲロー(風船を付けたまま行ってしまった犬)に出会った頃のある日、私がガレージセールで買ったボードゲームを引きずってアパートに帰ってくると、クウィルがポーチにいた。彼女は3年くらいというものサンアントニオにいたので、私は驚いた。彼女は私のアパートのポーチで寝袋に入って眠っていた。
彼女は美術学校に行くお金を使い果たしていたので、私のところで5ヶ月かそこら過ごした。
私は中古の2段ベッドを手に入れた。夜にはベッドに座ってお互いにノートに書いた物語りを読み合った。私は探偵少年の本を書いていて、彼は同じテニスチームにいた子供を殺した犯人を、動物たちの助けを借りながら見つける。クウィルは少年が自分の でっちあげたカルトに入る子供を新聞広告で募り、彼らがロケット船を作る ことになるという話を書いていた。しかし彼女の本の大半の部分で子どもたちは森で迷子になっていて、全然方向性がなく、私は毎晩聞いていてスリルを感じた。
そう、毎晩毎晩が、詩と、物語と、近所の人にするいたずらのアイデアだった。近所のジャスティンはWarhammer のファンで、本物の剣とかチュニックとかを集めていた。私たちはアルミホイルで鎧を作り、彼のアパートを 襲撃することにした。私たちは彼のアパートを略奪し、彼はそれが気に入っていた。それで彼も自分の鎧をアルミホイルで作り、みんなでスタジオに行って写真を撮ってもらった。
4人のクウィルがジャッカルの死骸を食べる。
私は自分の人生があなたのより少しでもマシだと言うつもりはない。私はただ妹がいないのを寂しく思っているだけだ。今では人生はもうあのときのようではなくなってしまった。私たちは溶解するか なにかしてしまったのだ。
私にはわからない。私は混乱している。これが成長というものなのか? 羽が抜け落ちるのを眺めているのが? そしてその羽が最も愛らしいものだったとしても?
私はそれをすべて止めてしまったのが誰なのか言うのに困難を感じている。誰が誰を愛するのをやめたのか? 私は気にかけるのをやめたのか? あるいは私は彼女を2次元でしか見ておらず、別な角度から見ようとしなかったのかもしれない。私は平面だけ見ていた。そして彼女は私が見ていない間にz軸を上がり、私の方は座標をたどる宿題をしたことがなかった。幾何学的な木の枝と、円の上に居続ける私と。
ブリクスは正しかった。私はこの本を書き続けられる状態にない。これをふるい落とせるまで、お別れだ。
![]() |
「ねえ、戻ってきて!!!
僕たちをここに置いていくつもり??」 |