Rust yew の function_component が動かない
yewで遊ぶぞーとなって一番手こずったところ。
yew 0.20.0ではyew::start_app
が無くなっているので、yewの(古い)チュートリアルにあるコードはそもそも動かない。
かといってdocsにあるExampleもそのままでは動かない。具体的にはyew::Renderer:<App>::new().render();
の部分で could not find `Renderer` in `yew`
と言われる。
そのものズバリなissueで答えが出てた。
Cargo.toml
ファイルのdependenciesのyew
の項目にfeatures
を指定するとよい。
yew = { version = "0.20.0", features = ["csr"] }
よく見るとyewのdocsのRender
にcsr
というfeaturesのタグが貼ってある。これそういう意味だったのか。つまりCargoのマニュアルをあまり真面目に読んでいなかったのが敗因。
おまけ。function_componentとwasm_bindgenで動かす時のHelloWorldのサンプル:
src/lib.rs
use wasm_bindgen::prelude::wasm_bindgen; use yew::prelude::{function_component, html, Html}; #[function_component(App)] fn app() -> Html { html! { <div><h1>{"Hello, World!"}</h1></div> } } #[wasm_bindgen(start)] pub fn run_app() { yew::Renderer::<App>::new().render(); }
Cargo.toml
[package] name = "yew-app-fn" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib", "rlib"] [dependencies] wasm-bindgen = "0.2.83" yew = { version = "0.20.0", features = ["csr"] }
MSYS2でRuby開発環境を作る
ウィルスバスターその他いろいろに阻まれてrubyinstaller+DevKit(MSYS2)のインストールに失敗したみなさん。いっそMSYS2そのものをインストールしてしまいましょう。64bitのWindowsの7以降を対象にしています。10ならだいたいOKだと思います。
英語だけどがんばって。Installationの節を順番に実行していきます。
- ダウンロードします。ダウンロードしましょう。
- ダウンロードした"msys2-x86_64-XXXXXXXX.exe"を実行します。XXXXXXXXのところはなんか数字が入ります。1でダウンロードしたファイルです。
- 画像のとおり、インストール先を選びましょう。だいたいそのままでOKです。
- インストールしたら"Run MSYS2 now."をチェックして終了しましょう。
- なんかウィンドウが出ますよね。こういうコマンド入力できる画面を「ターミナル」と呼びます。ターミナルエミュレーターの略です。まずコマンド
pacman -Syu
を実行します。pacmanは、パッケージ(ソフトウェアのに必要なファイル一式のようなもの)を管理するソフトで、だいたいスマホのAppStoreやGoogle Play Storeと似たようなやつです。無料なので安心してください。pacman -Syu
は、全てのパッケージを更新チェックして更新するという意味です。例で出ている最後のエラーはだいたい「再実行してください」という意味です。これが出ると一旦ターミナルが終了します。 - スタートメニューか、見つからなければインストールしたフォルダの中から、"MSYS2"を実行してください。またターミナルが開くと思います。先程のようなエラーが出た場合はここでpacmanを再実行します。
pacman -Su
です。前のやつから"y"が一文字消えているのは、今回は更新チェックをしなくてよいからです。さっきしたからね。 - これでMSYS2使えるようになったよ(以下略)
とりあえずここまでで良いでしょう。次はRubyをインストールします。
$ pacman -S ruby
これでおわりです。今日の時点ではRuby 3.0.0がリリースされていますが、まだパッケージが更新されていないのでRuby 2.7.2-1が入るのではないかと思います。
$ ruby --version
このように今どのバージョンが入っているかを確認して、適切なバージョンのマニュアルを見るようにしましょう。マニュアルはここでバージョンを選ぶことができます。
一応、which
コマンドで、Rubyがどこにインストールされているかを見ておいてください。
$ which ruby /usr/bin/ruby
みたいになっていたら成功です。パスが/c/
で始まっている場合は、CGIの例題が動かない可能性があるのでPATHなどを見なおす必要があります。くわしい人に相談してください。
CGIを書こう
タイトル「インターネットになろう」にしようと思ったけどやめた。
今回はちょっとWebをやってみます。「そろそろ何をやりたいか考えてみよう」と言いたいところですが、そんな簡単に見つかるなら幸せなことで、それはそれで良いのですが、普通はとりあえずできることを増やしながら「これ面白いな」と思うことを見つけていくというのが良いでしょう。
準備(Windows使いのプログラマ向け)
まずはサンプルを動かしてみてほしかったのですが、Windowsだと肝心な部分がどうしても動かなかったのでちょっと下準備をします。
WindowsのPCを使っていて、Rubyのインストールで「RubyInstaller」を使っていて、現在はコマンドプロンプト(Rubyといっしょにインストールされている"Start Command Prompt for Ruby"みたいなやつを含む)を使ってRubyを書いている人向けの情報です。
おそらく最初に以下のようなページからrubyinstaller-devkit-2.7.2-1-x64.exe
やrubyinstaller-2.7.2-1-x64.exe
をダウンロードしてインストールしたのではないでしょうか。
名前に"devkit"と入っている方のファイルがある人はそのまま、無い方のファイルの人はdevkitのファイルをダウンロードしてください。ファイルをなくした人もダウンロードしなおしてください。
そして再度インストールしてください。ただし、今度は途中のモジュール選択の部分で"MSYS2"をインストールするようにチェックを入れてください。最初にインストールした時と同様にコマンドプロンプトのウィンドウが開いて色々質問されると思いますが、全部そのままEnterを押しておけば大丈夫です。
インストールが終わったら、今までと同じようにコマンドプロンプトを立ち上げてください。そのあと、bash
コマンドを実行してください。ちょっと見た目が変りましたね。bash
は、おおむね今までのコマンドプロンプトと似たようなものですが、色んな機能があったりなかったりします。でも今までどおりcd
もdir
も使えるので安心してください。dir
の代わりにls
も使えますし、もちろんruby
もirb
も使えます。
では、ここからはbashを使っているという前提でいきます。
WEBrickを使う
ここではWEBrickというWebサーバを使ってみます。Webサーバとはなんぞやというのはまあやってみればなんとなくわかるでしょう。マニュアルはこれまでとは違い「標準添付ライブラリ All libraries」のページにあります。ページには大量のライブラリがありますが、ネットワークの節の"webrick"のページを見てください。
library webrick (Ruby 2.7.0 リファレンスマニュアル)
概要にサンプルコードが載っています。「以下は Web サーバとして完全に動作するスクリプトです。」とのことなので、とりあえずこれを適当なファイル名(ここではweb.rb
とします)のファイルに打ち込むかコピペしてください。
require 'webrick' srv = WEBrick::HTTPServer.new({ :DocumentRoot => './', :BindAddress => '127.0.0.1', :Port => 20080}) srv.mount('/view.cgi', WEBrick::HTTPServlet::CGIHandler, 'view.rb') srv.mount('/foo.html', WEBrick::HTTPServlet::FileHandler, 'hoge.html') trap("INT"){ srv.shutdown } srv.start
これを実行します。
% ruby web.rb [2021-02-05 19:57:11] INFO WEBrick 1.6.0 [2021-02-05 19:57:11] INFO ruby 2.7.0 (2019-12-25) [x86_64-linux] [2021-02-05 19:57:11] INFO WEBrick::HTTPServer#start: pid=111395 port=20080
このように、なにかメッセージが出てそのままプログラムが停止すると思います(細かい数字は違うかもしれません)。エラーが出たり終了してしまったら何か書き間違いがあるかもしれません。書き間違いは熟練プログラマでもよくあることなので注意深く探してみましょう。
この状態で、Webブラウザを開いてURL http://localhost:20080 にアクセスしてみてください。ファイル一覧みたいなものが見えたら成功です。たぶんさきほど作ったファイル(web.rb)が見えているんじゃないでしょうか。ファイル名をクリックすると中身が見られます。インターネットっぽくなってきましたね。
終了する時はコマンドの画面に戻ってC-C
です。サンプルコードの中の最後から2行目trap("INT"){ srv.shutdown }
の部分が、C-C
を押したら終了するという意味になっています。書かないと終了できなくて不便です。ウィンドウ閉じたら終了したりするんだろうか? よくわかりません。別に試さなくてもよいでしょう。最悪PCを再起動すれば終了します。
ファイルにアクセスする
まず、/hoge.html
にアクセスします。URLは http://localhost:20080/hoge.html です。"Not Found"のような文字が表示されたと思います。それで正常です。つまり「"hoge.html"というファイルはありません」ということです。実際に無いので、これはこれで正しい。
では"hoge.html"というファイルを作ってみましょう。何か適当なことを書いて、現在ソースを置いているのと同じフォルダに"hoge.html"という名前で保存します。内容が思いつかない人はこうしましょう。
You just don't have enough fight in you!
ファイルを保存して再度、http://localhost:20080/hoge.html にアクセスしてみましょう。「You just don't have enough fight in you!」または適当に書いた文字が表示されていれば成功です。文字化けした人は、アルファベット以外を書きましたね。このように、Webサーバはファイルをブラウザに配信することができます。HTMLが書けるならHTMLを書くともうちょっとそれらしくなります。文字化けした人は、HTMLでエンコードを指定するか、ブラウザの設定でエンコードをいじるか、なんかやってみてください。
これだけでも何かと便利なので覚えておくと良いでしょう。
次に、/foo.html
にアクセスします。URLは http://localhost:20080/foo.html です。/hoge.html
にアクセスした時と同じ結果になったと思います。なっていない人は、コードのどこかを間違えていると思います。がんばって間違いを探しましょう。この間違いさがしを専門用語でデバッグとも言います(デバッグはもっと広い意味での間違いさがしですが)。
同じ結果になるのは、コードの中のsrv.mount('/foo.html', WEBrick::HTTPServlet::FileHandler, 'hoge.html')
の行の効果です。これで「"/foo.html"にアクセスした時は"hoge.html"のファイルを返す」という意味になります。詳しくはWEBrickのマニュアルにありますが、難しいのでまた別に解説してもいいと思っています。話せば長くなります(たのしい)。
プログラムにアクセスする(CGI)
本題です。ファイルにアクセスしてファイルが返る、または適当なパス(ここでは"/foo.html")にアクセスしてファイルが返るように、プログラムを実行して実行結果をブラウザに返すといったようなことができます。ものすごく簡単に言うと、このような仕組みをCGIと言います。
まだ解説していない以下の行に注目してください。
srv.mount('/view.cgi', WEBrick::HTTPServlet::CGIHandler, 'view.rb')
これは日本語訳すると「"/view.cgi"にアクセスされたら"view.rb"を起動してその結果を返す」という意味です。ここで出てくる"view.rb"はRubyのプログラムです。そんなものは存在しないので、現時点で http://localhost:20080/view.cgi にアクセスすると「Internal Server Error」みたいなのが出ると思います。Webサービスがエラーになった時にこのような画面を見たことがある人もいるかもしれません。つまりそういうことです。
ということで、ファイル"view.rb"を用意します。内容は以下のようにしてください。
#!/usr/bin/env ruby print "Content-Type: text/plain\r\n\r\n" print "Ciao!"
保存して http://localhost:20080/view.cgi にアクセスして、"Ciao!"と表示されれば成功です。print "Ciao!"
の部分を好きなように改造して遊んでみるといいと思います。これまで使っていたputs
も使えます。
うまくいかなかった人は以下を試してみてください。うまくいった人にはすみませんが、ここまで含めてプログラミングです。
view.cgi
のコードに間違いが無いか確認する- ブラウザの画面に出るエラーメッセージを確認して手掛かりを探す
ruby web.rb
を実行した方のウィンドウで、最近出ているメッセージから原因を探す- 1行目に間違いが無いか確認する(1行目は絶対に
#!
で始まらないといけない) - 1行目の書き方を変える。
C-C
でbashに戻って、which ruby
コマンドを実行する。実行した結果の文字列を1行目の"#!"の後に入れる。例えばwhich ruby
の結果が/usr/bin/ruby
だったら1行目は#!/usr/bin/ruby
にする
それでもわからなかった場合や、動いたけどなんで動いたのか気になった場合は、何をしたかも含めて文章でもスクリーンショットでも良いので添えて詳しい人に聞いてみてください。
倫理的なやつ
ここで作ったプログラムには何の危険もありませんし、自分以外の誰にもアクセスできません。安全です。というのをわかった上で。
これでなんらかのプログラムを使ったサービスをインターネットで公開できるようになりました。大抵はそのままではファイアウォールだったりネットワーク設定だったりに阻まれてそのままインターネットに公開というわけにはいきませんが、理論的にはこれで全世界に公開できるサービスを作ることができるようになったということになります。きっとそのために勉強をすればすぐにできるでしょう。
ただし、ここから先、本当にインターネットに公開しようとすると色々な現実的な問題が発生します。今回はまだ外のシステムにアクセスするようなことはしていませんが、単に公開するだけでも、例えばどこか知らない誰かからの攻撃の危険にさらされます。プログラムに脆弱性があった場合、もしくはプログラムに非は無くとも利用しているWEBrickやRubyそのものに脆弱性があった場合、そこを突かれてシステムが乗っ取られたり、不正アクセスのための踏み台にされることがあります。つまり直接的に誰かに迷惑をかけるだけでなく、知らないうちに悪事に加担してしまう恐れまである。それは非常にマズい。いわゆるハッキングとかクラッキングとかいうやつです。
ということで、何か作って公開したいと思った時は、詳しい人に相談するか、インターネットセキュリティや倫理についてしっかり勉強するなどしてからやるようにしてください。
実際のところ、悪事を働くための技術や守るための技術の理屈はすごく難しいですが、対策する方法自体はそんなに難しくないことが多いので、「これやっとけば大丈夫よ」くらいのアドバイスで済むことが多いです。
ただそれはそれとして、クラッキングというやつの仕組みはそこそこ楽しいので、悪用しない前提で勉強するのは楽しいと思います。死ぬほど難しいけどそれなりの需要はあります。
それから
今回はここで終わりです。今回はこれまでと違って説明を省いた部分が大量にあります。ここから先は、これまでのどこがおもしろかったかで進む方向を決めると良いでしょう。どの方向に行っても1歩目までは大抵サポートできると思います。
ざっと思いつくのはこんな感じです。
- もっと色々できるWebサービスを作りたい
- ここで出てきたURLの意味がわからん(localhostとか:20080とか)
- コードの中の
WEBrick::HTTPServer.new
のオプションは一体何(:DocumentRoot => './',
とか:BindAddress => '127.0.0.1',
とか:Port => 20080
) - 文字化け直したい
trap("INT")
の詳細が知りたい- WEBrickが何をしているのかを知りたい
- そもそもrubyみたいなのを作りたい
これ以外にも色々なことを思うかもしれません。ほとんどの共通部分は同じではありますが、特にどこが気になるかによってかなり分野が違っていたりするので、おすすめする本なども変わってくると思います。私も挙げた分についてはそこそこ知っているものもあるので聞いてみてもいいかもしれません。半分くらいRubyじゃないですけども。
2時間でわかる繰り返し
今回は繰り返しの話です。
繰り返しというのは要するに同じことや似たようなことを何回もやる、ということですが、そのやり方はたくさんあります。これはRubyだからということではなく、様々なプログラミング言語で様々な繰り返しの方法があります。その多数の中から状況によって適切なやり方を選択できるということが、プログラミングの上達につながるといって良いでしょう。
ただしこれは非常に難しい。一流と呼ばれるプログラマでも間違えることが多々ありますし、正解が存在しないということもあります。
なので、ここではとりあえずどういうパターンがあるのかを見て「そういうものもあるんだな」と思っておく、というところから始めましょう。
無限ループ
まずは無限ループからです。無限ループというのはそもそもプログラミング用語であり、その名の通り、特定の処理を無限に繰り返します。最も一般的な書き方はこうです。
while true puts "ainachan" end
これを実行すると"ainachan"と連呼しつづける迷惑なやつになります。C-C
で止めてあげましょう。
原理としては、マニュアルの「制御構造」のページに書いてあります。while
は、その後に続く式がfalse
になるまで永遠に繰り返す文ですが、今回の場合は式の部分にtrue
と書き込んでいるので、false
になることはありません。つまり無限に繰り返すということです。
無限に繰り返して終わらないというのは困ったようにも思えますが、普通のプログラムならまあC-C
を入力すれば終わりますし、終わらないということがそれなりに便利なともあります。
余談ですが、例えば今まさに使っているブラウザとかエディタのようなGUIアプリケーションは、これまでに作ってきたHelloWorldやMegaGreeter(20分ではじめるRuby)などのようにやることやったらすぐ終了してしまうというのでは困るので、どこかしらで無限ループのようなことをしています。OSとかもそうです。
ただ、普通は終わらないと困るので、終わらせる方法をC-C
以外で用意しておくのが普通です。
例えば、ループするかどうかを判断する変数つづける
を使います。(変数は実は日本語も使えます)
つづける = true while つづける puts "ainachan" つづける = false end
これを実行するとどうなるでしょうか。while文は、つづける
がtrue
の間は無限に繰り返しますが、ainachanと言った後でつづける
がfalse
になるので、そのままwhile文は終了し、1回しか"ainachan"は出力されません。これだとループの意味は無いので、普通はif文をからめてこういう感じになります。
つづける = true while つづける puts "ainachan" if 終了条件 つづける = false end end
この終了条件
の部分には、「どういう時に終わらせたいか」という条件式が入ります。例はちょっと後で。
無限ループ2
無限ループの書き方についてもいくつかあります。普通は先ほど説明した通りに書くのが良いのですが、こういうパターンもあります。
puts "ainachan" while true
今度は1行です。これは「while装飾子」というパターンです。先ほどと同じくマニュアルの制御構造のページのwhileの節の次に書いてあります。これはwhileの後の条件がtrue
になるまでwhileの前の文を繰り返すという意味です。基本的には1行を繰り返すのですが、複数の行を1行として扱うbegin
〜end
と組み合わせると以下のようになります。
begin puts "ainachan" puts "anchan" end while true
ほとんど最初のwhile true 〜 end
と同じように動くように見えますが、while装飾子とbegin endを組み合わせた場合だけちょっと違う動きをします。while装飾子のtrue
をfalse
に変えてみてください。
begin puts "ainachan" puts "anchan" end while false
条件式がfalse
なのでループは実行されないように見えますが、1回だけ実行されます。「1回は少なくとも実行したい」という時はこのような書き方をします。滅多にありませんが、稀にそう思うことがあります。なにかスッキリしない時に思い出すと良いでしょう。
無限ループ3
until
というのもあります。これは単にwhile
の条件のtrue
とfalse
が逆になっただけで、ほとんど同じです。until 式
の部分はwhile not 式
と書けば全く同じなので実のところあまり見かけませんが、でもなにかそれでは気持ち悪い時に使います。
Rubyにはそういう「同じだけど名前が違う」とか「ほとんど同じだけどすごく細かいところが違う」という機能がたくさんあります。一番気持ちいいやりかたでやると良いでしょう。
4回繰り返す
4回繰り返します。まずはこうです。
puts "ainachan" puts "ainachan" puts "ainachan" puts "ainachan"
4回繰り返しました。あまりにも単純ですが、これはこれで正解になることがあります。開発初期のとりあえずやってみようという段階や動作確認ではこういう感じでもよいことがあります。コピペも有効に使っていきましょう。
4回繰り返す (n回繰り返す)
「4回」というように、回数が決まっている場合はIntegerクラスのtimes
メソッドを使うのが簡単です。
4.times { puts "ainachan" }
これなら100回にしたくなった時にも4の部分を書き換えればよいので簡単です。
4
の部分を変数にするのも良いでしょう。n回繰り返すパターンは以下です。
n = 4 # 今回は4回繰り返します n.times { puts "ainachan" }
n
をメソッドのパラメータにすると、指定した回数だけ繰り返すメソッドも作ることができます。今日は4回、明日は10回繰り返したい、という場合などに便利です。
def renko(n) n.times { puts "ainachan" } end renko(4)
for文を使って4回繰り返す (timesの別の使い方)
times
にはブロック({ ... }
)を指定する以外にも使い方があります。
例えば、以下のようにfor文といっしょに使えます。
for i in 4.times puts "ainachan" end
ここで、i
は、何回目かという情報が入っています。for文の中でputs i
などして確かめてみるとよいでしょう。0
から始まり、1
, 2
, 3
と表示されると思います。このように回数は0
から始まりn - 1
でおわります。そしてこのfor文のコードは以下と同じです。
4.times {|i| puts "ainachan" }
times
のブロックは、このようにカウンタi
を受け取ることができます。ブロックの中でputs i
するとまた同じようになるはずです。
また、for文のパターンは以下のコードとも全く同じです。そもそも実は、このコードの省略形がfor文です。Rubyにはこのような同じ処理の書き換えパターンがよく登場します。くわしくは「制御構造」のマニュアルに書いてあります。ここではeach
が出てきます。
4.times.each {|i| puts "ainachan" }
Integerクラスのtimes
はブロックをつけないとEnumeratorを返すとマニュアルに書いてあります。Enumeratorというのは「なんか数えられるやつ」くらいの意味です。数字だったりリストだったり、そういう何かです。そしてマニュアルで言うとEnumeratorクラスの中にeach
メソッドがあります。eachなのでつまり、「それぞれの要素に対してブロックを実行する」という意味で、これが数字やリストに対して実行すると繰り返しになります。
4回繰り返す (カウンタを使う)
ここで、現在の繰り返し回数i
がわかるということは、i
を使って以下のように書くこともできます。
100.times {|i| if i < 4 puts "ainachan" end }
日本語で説明すると、「100回繰り返し、繰り返し回数が4回未満なら"ainachan"と表示する」ということになります。これはこれでいいのですが、普通は100回も繰り返さずに、4回以上になった時点でやめればよいのです。というパターンが以下のコードです。
100.times {|i| if i >= 4 break end puts "ainachan" }
これが「100回繰り返すが、4回以上になったらやめる」です。ループの中でbreak
と書くと、break
が実行された時点でループそのものが終了します。「ループを抜ける」とも表現します。このようにループは途中でやめることもできます。
4回繰り返す (whileとカウンタを使う)
最初に出てきたwhile文を使って以下のように書くこともできます。
i = 0 while i < 4 puts "ainachan" i += 1 end
1. while文にはカウンタが無いので自分でi = 0
と定義します
2. i
が4未満の場合に繰り返します
3. "ainachan"って表示
4. i
に1を足します
5. 2に戻る
大事なのは2と4です。4で自分でちゃんと数えてあげる必要があります。4が無いと無限ループします。
また、無限ループとbreak
を使って以下のように書くこともできます。
i = 0 while true if i >= 4 break end puts "ainachan" i += 1 end
このように、whileの条件式をループ内のif文で代用することもできます。
ただ、これだと条件がi < 4
だったのがi >= 4
と逆になっていてちょっとややこしいかもしれません。そういう時のために、前にちょっと紹介したuntil
や、if
の逆のunless
というものがあります。試しに書いてみるとこうなります。
# unlessとbreakを使うパターン i = 0 while true unless i < 4 break end puts "ainachan" i += 1 end
# untilを使うパターン i = 0 until i >= 4 puts "ainachan" i += 1 end
どのやりかたが良いかというのは状況によるとしか言えません。大抵は状況により最適な方法は存在しますが、1つとは限りませんし、確固たる理屈があるわけでもなく経験則という場合も多いです。とりあえずは気持ちの良いものを使いましょう。
3回に1回違うことをする
3回に1回、"ainachan"じゃなくて"anchan"と表示してみましょう。一番簡単なのはこうだと思います。
puts "ainachan" puts "ainachan" puts "anchan" puts "ainachan" puts "ainachan" puts "anchan"
無限にやるならこうです。
while true puts "ainachan" puts "ainachan" puts "anchan" end
ここで考えなおしてみましょう。「3回に1回」ということは、ループの回数を数えてカウンタが3の倍数の時だけ表示を変えればよいのです。その実装が以下のコードになります。
i = 1 while true if i % 3 == 0 puts "anchan" else puts "ainachan" end i += 1 end
%
というものが出てきましたが、これはmod演算といって、割り算の余りを出す演算子です。要するにifの条件式は「i
を3で割った余りが0ならば」という意味になります。つまり「3の倍数ならば」ということです。前と違ってi = 0
ではなくi = 1
から始まっているのは、最初の1回目で"anchan"と表示しないためです。ちなみに%
の詳細はIntegerクラスのマニュアルにあります。
余談ですが、10年くらい前にはこのようにループとifを使いこなせてmodの意味がわかっていればプログラマとして就職できるという噂がありました。実際どうだったのかはよくわかりません。
リストの中身に従って繰り返す
1行目は"ainachan"、2行目は"anchan"、3行目は"mendako"と表示しようと思います。これも繰り返しで表現することができます。要するに「表示する」という部分は同じなので、文字列のリストを作って、それぞれに対してputs
してあげればよいのです。というのが以下のコードです。
["ainachan", "anchan", "mendako"].each {|s| puts s }
ここで[ ... ]
の部分はArrayクラスのメソッドです。この["ainachan", "anchan", "mendako"]
の部分で配列(Array: リストのようなもの)を作っています。配列にも前に少し紹介したeach
メソッドがあり、ブロックの中でそれぞれに対してputs
を実行します。s
には配列の中身が1つずつ入ってきます。とりあえず書いてみればなんとなくわかると思います。
これを使って「3回に1回〜」を実現することもできます。こんな感じです。
["ainachan", "ainachan", "anchan"].each {|s| puts s }
無限にやるならこれ自体をループしてしまえばよいのです。
while true ["ainachan", "ainachan", "anchan"].each {|s| puts s } end
無限の場合は、Arrayクラスのcycle
メソッドを使って書くこともできます。cycleは配列に含まれる要素を繰り返すメソッドで、["ainachan", "anchan", "mendako"].cycle
のように書くと["ainachan", "anchan", "mendako", "ainachan", "anchan", "mendako", "ainachan", "anchan", "mendako", ...]
のような感じになります。要するに以下を実行してみましょう。先程のコードと同じ結果になるはずです。
["ainachan", "ainachan", "anchan"].cycle.each {|s| puts s }
ということはつまり、以下のコードは一番最初の無限ループのコードと同じ結果になります。
["ainachan"].cycle.each {|s| puts s }
意味は少し複雑になって、「"ainachan"だけが含まれた配列(["ainachan"])を無限に繰り返して(cycle)、その中身を全て(each)表示する(puts)」ということになります。この場合も、どちらが良いのかは状況次第です。
もちろん、break
と組み合わせて"mendako"がきたらループを抜けるというようなこともできます。
["ainachan", "anchan", "mendako", "kumachka"].each {|s| if s == "mendako" break end puts s } end
この場合は"mendako"と"kumachka"は表示されません。
繰り返しの途中でやりなおしたり次に行ったりする
break
と似た話で、繰り返しの途中で後の処理をせずに次に行きたいことがあります。例えば、以下のコードです。
["aina", "an", "mendako", "kumachka"].each {|s| print s if s == "mendako" puts next end puts "chan" }
このコードの意味は、「文字列が"mendako"の時だけ"chan"を付けない」という意味になります。ここでprint
は、改行せずに文字列を表示するメソッドです。それと、puts
はうしろに何も指定しないと改行だけするメソッドになります。
"mendako"のif文の中にnext
という命令があります。これは繰り返し(each
のブロック)の中の処理を途中で辞めて次の繰り返しに行く、という意味で、この場合はput "chan"
を実行せずに次の"kumachka"の処理に移ります。実行してみるとなんとなくわかると思います。
このnext
と似たものとしてredo
があります。こちらは次に行かずに、今と同じものをもう一度やりなおします。つまり以下のようにnext
をredo
に置き換えたものを実行すると、"mendako"を処理しようとしてredo
されて再度"mendako"を処理しようとするので無限ループします。
["aina", "an", "mendako", "kumachka"].each {|s| print s if s == "mendako" puts redo end puts "chan" }
redo
はあまり使うことはないかもしれませんが、もう一度やればうまくいくという状況があれば思い出してください。リトライ(retry
)というのもあって似ていますが、たぶんリトライの方が出番は多いと思います。後で説明します。
範囲にしたがって繰り返す
Rangeについて書こうと思ったけどあまり変わらないのでやめ。(1..4)
や(1...5)
のように数字の範囲を指定することができます。これらはRangeクラスのオブジェクトで、each
メソッドがあるので、(1..4).each {|i| puts i }
とかやってみてください。
再帰
再帰は少し変わったパターンです。うまく使えばわかりやすくなりますが、なかなか難しい概念ですし、性能も良いとは言えないところがあるのでさほど使われることはありません。でも状況によってはすごく有用なこともあるという、そういうものです。そういうのもあるんだなと思っておくだけでも良いでしょう。
メソッドは自分自身を呼び出すことができます。これを利用して無限ループを書くことができます。
def ainachan puts "ainachan" ainachan # 自分自身(ainachanメソッド)を呼び出し end ainachan
ainachanメソッドの中でさらにainachanメソッドを呼び出しています。それだけでは最初の1回目が実行されないので、最後にainachanメソッドを呼び出しています。これを実行すると、無限ループの時と同様に"ainachan"と表示され続けるはずですが、続けているうちに途中でSystemStackError
みたいなエラーが出て止まると思います。これは実行した環境(状況みたいなもの)によって変わるのでなんとも言えませんが、数秒で止まる人もいれば数時間も止まらない人もいると思います。それはまあそういうものです。
このエラーは自分自身を呼び出す(これを再帰といいます)回数が多すぎた時に起きます。このようなエラーが発生する可能性があるので、再帰はあまり性能がよくないとされています。一応それを克服する方法もありますが、それなりに特殊なことになるので難しい。
ここで何が起きているか、何故エラーが起きるかというと、Rubyの外の話も色々と関わってくるので、ここでは説明しませんが、そちらの方に興味があればそういう方向に行くのもアリです。(私はそっちの方が詳しいです)
実のところ、再帰というのはすごく強力な概念なので、ここで説明している繰り返しのほとんどを再帰を使って書き直すことができます。ただ、エラーが起きることもあるように、Rubyを含む多くのプログラミング言語ではあまり効率が良くないので、かなり限られた状況でしか使われません。逆に言うと再帰で書けるコードのほとんどは他の繰り返しに置き換えることができるのです。必要以上に避ける必要もありませんが、繰り返しで書けるならできるだけ繰り返しで書く方が良いでしょう。
リトライ(と例外)
繰り返すことの目的のひとつとして、エラーが起きたからやり直すというものがあります。つまりリトライです。redo
と似ていますが、こちらはコンピュータの本質的な問題に対処するための仕組みです。
コンピュータには同じ処理でももう1回やれば成功するかもしれないという事があります。例えば外部のデバイスと通信するときです。
つながっていないハードディスクに書き込もうとするとエラーになりますが、つないでからリトライすると成功するかもしれません。インターネットにつながっていない時に通信しようとするとエラーになりますが、時間が経って再接続された後だと成功するかもしれません。
このように、プログラムとしては間違いは無くてもコンピュータそのものの状況(故障など)や世の中の状況(当然ながらインターネットを使うプログラムは世界が滅ぶと使えません)によって実行が不可能になるということがあります。これをRubyでは例外(Exception)と呼んでいます。Rubyではエラーも例外の仲間です。エラーと言った時は例外の話をしていると思って問題ありません。前節で出てきたSystemStackErrorもエラーであり、Rubyでは例外の一種です。
例題として例外を起こすとなるとそれなりの準備もあって面倒くさいので、サンプルコードでは例外を発生させる命令を使います。例外は、一番簡単なものとしては他のオブジェクトと同じくExceptionクラスを使ってException.new
で作ることができます。これだけではただのクラスと同じなので、「発生させる」といった場合にはraise
命令を使う必要があります。つまりこうです。
raise Exception.new
この一行をirbなどで実行してみてください。これまで散々見てきたようなエラーが起きた時みたいな表示が出たらたぶん成功です。本当にエラーだったらなんかごめんなさい。
このraise
というのは、例外を発生させる命令です。あまり使うことはありませんが、プログラムの中でなにか想定外のことが起きた時に使います。存在しないメソッドを呼んだ時や、想定しない使い方をした時などに発生します。例えば、Integerメソッドにはmendakoメソッドは存在していないので2.mendako
はNoMethodErrorという例外が起きますし、1を0で割った時にどうなるかは誰にもわからないので1 / 0
はZeroDivisionErrorが起きます。irbなどで試してみてください。
ちなみにraise
では適当な文字を指定することもできます。なにか適当な名前を思いつかない時はエラーメッセージを投げておけばOKです(raiseを使うことを「投げる」と言うことがあります)。つまりこういうことができます。
raise "例外が起きたよ"
Rubyでは、例外が起きた時に何かをすることができます。そして「例外が起きた時にできる何か」の中にはリトライというものがあります。これを使って無限ループを作ることができます。具体的にはこうです。
begin puts "ainachan" raise "なんかエラー" # 例外が発生 rescue retry end
これを実行すると無限ループすることを確認できると思います。
例外(エラー)が起きそうな場所はbegin ... rescue ... end
で囲む必要があります。この中のbegin ... rescue
の中でエラーが発生するとrescue ...
の間のプログラムが実行されます。この場合はretry
です。retry
は、rescue
に対応するbegin
まで戻って、そのbegin
のところからやり直しますという命令です。つまりここでは、raise
のところで例外が発生するのでrescue
の節が実行されてretry
の作用でbegin
のところまで戻って再びputs "ainachan"
が実行されることになります。
試しにraise "なんかエラー"
の行を削除してみてください。例外が発生しなくなるので1回だけ"ainachan"が表示されて終了すると思います。rescue ... end
の節は、その前の節で何事も起きなければ実行されることはありません。
これが何の役に立つのかというと、例えば通信エラーだった場合にはretryの前に再接続のプログラムを実行すれば良いわけです。あまり使うことは無いかもしれませんが、みなさんが使う通信やファイル読み書きのプログラムではライブラリの中のどこかでこのような処理をしています。機会があったあ思い出してみてください。
おわり
このように、繰り返しひとつとってもプログラムにはやりかたがたくさんありますし、目的もたくさんあります。もちろんここで説明した意外にも様々なパターンがありますが、少なくともRubyにおいてはほとんどがここで挙げたパターンの組み合わせになると思います。
「色々なやり方があるんだな」とわかった上で、やり方を探しつつ、時にはより良い方法を探してマニュアルを読んだり先人のコードを読んだり詳しい人(私を含む)に尋ねたりして、良いコードを書けるようにがんばってみてください。
「20分ではじめるRuby」解説 4ページ目
前回: 「20分ではじめるRuby」解説 3ページ目 - yunomuのブログ
最後です。
実行
まずは3ページ目に戻って、「ファイルに保存して実行」です。
このファイルを“ri20min.rb”という名前で保存して、“ruby ri20min.rb”と 実行しましょう。
メモ帳でもなんでもいいので、MegaGreeterの書いてあるソースコード部分を全部打ち込みます。別にコピペでもいいです。ただ、打ち込んでみて雰囲気を感じるのも最初は良いものです。ここで「メモ帳は使いにくにな」と思って壮大なテキストエディタ探しの旅に出るのも楽しいかもしれません。WindowsだとEmEditorとかTeraPadなどが有名ですが、そういうRubyに対応したエディタだとソースコードに自動的に色をつけてくれたりして、見やすくなることがあります。
書いたソースコードを保存します。保存場所は、コマンドラインでirb
などを実行しているディレクトリ(フォルダ)がいいでしょう。dir
コマンドなどを実行するとファイル一覧が表示されると思いますが、その一覧の中に"ri20min.rb"があればとりあえず成功です。実行しましょう。
C:¥Users¥yunomu> ruby ri20min.rb
こんな感じで。
例の通りに表示されていれば成功です。なんかエラーが出た場合は、中身を見てみましょう。FileNotFoundErrorならファイル名(ri20min.rb)を間違えているか、保存場所が違います。SyntaxErrorやNameErrorやNoMethodErrorの場合は、どこかに打ち間違いとかがあります。メッセージで出ている場所の近辺を探してみましょう。
コメント
'#'で始まる行は意味が無いので何を書いてもいいよという話です。マニュアルでは、Ruby言語仕様の「字句構造」のところにあります。内容は1行くらいしかありません。
次の一文、
このファイルの最初の行は 特別な行で、Unix系のOSではファイルをどう実行するかをシェルに知らせてくれます。
これは、先ほど書いたソースコード(ri20min.rb)の一行目のこれのことです。
#!/usr/bin/env ruby
これはUnix系のOSの時だけ関係ある話で、別に無くても構いませんし、Windowsとかだと無意味だったり書き方が違ったりします。まあ書かなくてもいいでしょう。
if, elsif, else, end
say_hi
の中でif
を使っていますね。if文です。これは条件分岐といって、「晴れていたら外に出かける。そうでなければ家でゲーム」みたいなやつです。条件分岐が出てくるとかなりプログラミングっぽさが出てきます。
マニュアルはRuby言語仕様の「制御構造」のページです。条件分岐の節の最初にifの項目があります。とりあえず例をirbかなにかで書いて実行してみるとよいでしょう。制御構造は慣れていても書き方をよく忘れるのでよくお世話になるページのひとつです。
今まではなんとなく流していましたが、「文法」と書いてあるブロックを見てみましょう。
if 式 [then] 式 ... [elsif 式 [then] 式 ... ] ... [else 式 ... ] end
これはif文の書き方を示しています。[
と]
で囲まれている部分は、あってもなくても良いという意味です。なのでthen
は書いても書かなくても良いということです。面倒なので書かなくてよいです。
say_hi
では一番複雑な、if, elsif, elseが全部登場するパターンで書かれています。つまり一番シンプルなのは以下のパターンです。式がtrueなら"hello"と出力し、falseなら何もしません。
if 式 puts "hello" end
「式」の部分には、例にあるように、true
かfalse
になる何らかの式が入ります。age >= 12
はage
が12以上ならtrueということです。true(真)
かfalse(偽)
になる値のことを真偽値(bool)と言います。
もちろん>=
にもマニュアルがあります。これはIntegerのメソッドなので、Builtin librariesのIntegerクラスのページにあります。
self >= other -> bool
比較演算子。数値として等しいまたは大きいか判定します。
これは、age >= 12
の例で説明すると、self
(age: Integerの数値)がother
(12: これもIntegerの数値)以上どうかを真偽値(bool)で表すという意味で、正しければtrue
という意味になります。要するに数学の"≧"です。
elsif
は、おそらく"else if"の略で、最初のifの条件で引っかからなかった場合にもう一度条件を書く場合に登場します。例えばこのように使います。
if age < 12 # ageが12より小さい時の処理 elsif age < 15 # ageが12より小さくなくて、15より小さい時 elsif age < 18 # ageが12より小さくなくて、15より小さくなくて、18より小さい時 else # それ以外 end
このように、elsif
はいくつでも書くことができます。else
はそれ以外の場合がある時に1つだけ書くことができます。elsif
もelse
も省略しても構いません。
演算子式
ついでに、演算子式について。
メソッドの中には演算子と呼ばれるものがあります。演算子メソッドは特別な書き方ができます。例えば、+
はIntegerのメソッドですが、普通のメソッドのように1.+(2)
と書くこともできますが、1 + 2
と書くこともできます。これが実は特別な話だったのです。
@names.nil?
say_hi
のif文の式のところに書いてある@names.nil?
とはなにか。@names
は一旦initialize
の中で定義されている変数だと思ってください。その上で@names.nil?
は、Builtin librariesのObjectクラスのページに説明があります。
つまり、@names == nil
と同じ意味です。ここでnil
というのは、無です。他の言語ではnullだったりします。つまり@names.nil?
は@names
が無(nil
)だった場合にtrue
になります。
さらにnil
とは何か。nil
はNilClassのオブジェクトです。Builtin librariesのページからNilClassのマニュアルを探して見てみましょう。メソッドのマニュアルを見てみると、おおむね虚無っぽい挙動をしていることがわかると思います。
nil
はどのような時に使うのか。それは、変数を作りたいけどまだ具体的な値を入れたくない時に使います。例えば以下のコードのように、tall
の値によって内容を変えたい時などです。
a = nil # 変数aを作りたいが中身がまだ決まっていない。 if tall > 150 a = "anchan" else a = "ainachan" end puts a
ただしこの場合は、if文が値を返すので以下のように書いた方が良いです。(if文のマニュアルを確認してください)
a = if tall > 150 "anchan" else "ainachan" end puts a
でも似たような場合でもa = nil
と書いてから何かやった方が便利な時もあるので、そういう時のためにnil
というものが存在します。プログラミングはひとつのことをやるためにいくつもの答えが存在します。その中から適切なものを選ぶために、良い例も良くない例も一応見ておきましょう。上の例でどちらがいいのかは、ちょっこれだけではなんとも言えないというのが正直なところです。
最後に'?'がついているメソッド
マニュアルをざっと見てまわった方はお気づきかもしれませんが、メソッドの中には'?'で終わるメソッドがあります。@names.nil?
もそうですし、例えばIntegerには結構たくさんあります。
Integerクラスのマニュアルを見てみましょう。インスタンスメソッドの項目にeven?
やodd?
があります。これは偶数か奇数かを判定するメソッドです。他にも、Numberから継承したメソッドの項目にはpositive?
やnegative?
なんかもあります。意味はマニュアルを見ればわかるでしょう。継承についてはまた別に説明します。
'?'がついているメソッドには共通の特徴があります。「bool値を返す」ということです。つまり'?'がついたメソッドはtrue
かfalse
の値を返します。
これは厳密にはルールではないのですが、お約束です。「'?'がついているメソッドではbool値を返すようにしよう」という暗黙の約束がRubyの世界にはあります。別に守る必要は無いのですが、守った方がみんなわかりやすくて便利だよねということです。Rubyに限らずプログラミング言語にはこういうお約束が時々あります。会社やチームによって決められることもあります。特に守る必要も無いのですが、一人の時は自分ルールを持っておくと後で助かることもあるかもしれません。チームにルールがある場合はそちらに従うと良いでしょう。そういうあいまいなことも時々あります。
おわり
「20分ではじめるRuby」の4ページ目が、最初のsay_hi
メソッドの途中で終わりました。次回はつづきで、4ページ目その2という感じで続けていきます。その3くらいまでいきそうな気がしますがよろしくお願いします。
「20分ではじめるRuby」解説 3ページ目
前回: 「20分ではじめるRuby」解説 2ページ目 - yunomuのブログ
オブジェクトを作る
それではgreeterオブジェクトを作り、使ってみましょう。
から始まります。最初から飛ばしていますね。
2ページ目の最後にclass Greeter
を書きましたね。これがクラスだという話でした。クラスとは何か。クラスとは、「整数」とか「文字列」のような、値の形のようなものです。「型」と言う時もあります。
1ページ目の時に「整数(Integer)」のマニュアルを見ましたが、そのIntegerもクラスです。マニュアルのBuiltin librariesのページで「クラス」の節の中からIntegerを探したのを覚えているでしょうか。Integerはクラスなので、マニュアルのクラスの節に書かれています。逆に、クラスの節に書かれているものは全てクラスなので、ここからの説明はおおむねあてはまります。そしてクラスはここに並んでいる以外にも自分で作ることもできます。つまりその作ったものがGreeter
です。
Greeter.new
のところから見てみましょう。
irb(main):035:0> greeter = Greeter.new("Pat")
このnew
というのは、クラスを元にオブジェクトを作るというメソッドです。オブジェクトというのは、クラス(型)に対する値のことで、つまりInteger
クラスのオブジェクトが2
や3
で、String
クラスのオブジェクトが"あいなちゃん"
とか"anchan"
とかになるイメージです。わかりますか。
IntegerやStringはリテラル(前回出てきた)でオブジェクトを作れますが、それ以外のほとんどのクラスではnew
メソッドを使ってオブジェクトを作ります。
new
メソッドのマニュアルはどこにあるかというと、おおむねほとんどのクラスにそれぞれあります。Stringにもあります。適当なクラスのマニュアルを探して見てみましょう。「特異メソッド」の項目にあるはずです。ただし、Integerにはnew
はありません。例外的にそういうクラスもあります。例外というのはどこにでもあります。そういうものだと思っておきましょう。
その上でGreeter.new("Pat")
が何をしているか。new
は実は2ページ目で書いたinitialize
を呼び出しています。ここの部分↓
irb(main):025:1> def initialize(name = "World") irb(main):026:2> @name = name irb(main):027:2> end
その後に出てくるgreeter.say_hi
やgteeter.say_bye
はそのままsay_hi
やsay_bye
を呼び出していますが、new
だけはinitialize
を呼び出します。これはnew
が特別だからで、その件についてはObject
クラスのマニュアルの中に書かれています。ややこしいですが、オブジェクトという用語とは別にObjectという名前のクラスが存在します。Builtin librariesのページのクラスの節からObject
のマニュアルを見てみましょう。
「privateメソッド」と書かれている節にinitialize
があると思います。ここに、要するにここで説明したようなことが書いてあります。new
を実行するとinitialize
が実行されます。何故そんなことになっているのか気になる場合は聞いてくれれば記事が増えます。
SyntaxError
irb(main):038:0> greeter.@name SyntaxError: (irb):38: syntax error, unexpected tIVAR, expecting '('
これはsyntax、つまり文法のエラーです。Rubyとしての書き方がなにか間違えている時に出るエラーです。エラーメッセージでは「'('がくるはずだったのになにかおかしい」というようなことが書かれていますが、そもそもRubyの規則に則っていないのでSyntaxErrorの場合のメッセージはあまり当てにならないことが多いです。'('や')'の書き忘れというパターンが多い気がします。がんばって探しましょう。
Objectの殻の中
ここではGreeter.instance_methods
を使って呼び出すことができるメソッドの一覧を出しています。この後、Greeter.instance_methods(false)
とfalse
を渡して見やすくしていますが、その前の大量に出てきた出力は何か。それこそが、マニュアルのクラスObject
のページで書かれていたメソッドたちです。
引数falseを渡します。 これは祖先のクラスで定義されたメソッドが不要であることを意味します。
と説明にあります。この「先祖のクラスで定義されたメソッド」という言葉の中の「先祖のクラス」というのがつまりObjectクラスです。Objectクラスは自分で定義したものも含めて全てのクラスの先祖になります。自動的になります。Rubyではそういうルールになっています。そのことは、Objectクラスのマニュアルの「要約」の節に書かれています。これはそういう意味です。
クラスの変更 - まだ間に合います
ここではattr_accessor
が出てきます。このマニュアルはBuiltin librariesのクラス節のClassのページにあります。クラスそのものもオブジェクトで、言わばClassクラスのオブジェクトなのです。これが重要になるのは何か既存のものの動きを書き換えたいとかそういうマニアックな欲求がある時なので、そういうのも後でいいでしょう。Rubyはなんでもアリなところがあるのでこういう機能はちょいちょい出てきます。
MegaGreeterあたりのこと
ここで急に「ファイルに書いてみましょう」と言われて驚いたかと思います。その前にひとつ。
ここで出てくる"quit"はIRBの特殊なコマンドですが、exit
はRubyの機能です。マニュアルで言うとBuiltin librariesのモジュールKernelにあります。前回(2ページ目)の記事で解説したKernelモジュールです。ここにexit
も「Rubyプログラムの実行を終了します。」と書いてあります。
それともうひとつ、「コントロールキーを押しながらDキーを押します。」について。これは専門用語で、Ctrl-D
とかC-D
とか^D
とも書きます。「ここでデータは終わりですよ」という意味です。IRB以外のコマンドでも使えることがあるのでたまに思い出すといいかもしれません。
これとは別に「コントロールキーを押しながらCキーを押す」というのもあります。Ctrl-C
とかC-C
とか^C
とも書きます。これは制御不能になった時に押します。具体的には無限ループになってしまった時などです。
以下のコードをIRBで実行してみましょう。
irb(main):011:1* while true irb(main):012:1* puts "ainachan" irb(main):013:0> end
これが"ainachan"連呼野郎です。止まりません。制御不能です。なのでC-C
で止めます。止まりましたよね? 止まらなかったらごめん。どうしようもないわ。
「20分ではじめるRuby」解説 2ページ目
前回: 実際のところ20分ではじまるかもしれないけどよくわからないよねRuby - yunomuのブログ
つづき。「20分ではじめるRuby」の今回は2ページ目についてです。
今回もマニュアルを見ながらいきましょう。
docs.ruby-lang.org
www.ruby-lang.org
メソッド定義
メソッドを定義しましょう。こういう感じのやつです。
def hi(name) puts "Hello #{name}!" end
まず「メソッド」というのは、これまで機能とか関数とか言っていたやつのことです。専門的には少し違いがありますが、Rubyのマニュアル上ではほとんど同じような意味で書かれているので、だいたいメソッドとか関数とか言っておけば通じると思います。前回出てきたputs
やMath.sqrt
や、四則演算の+
や*
なんかもメソッドです。
定義というのは、「書く」くらいの意味です。別に「作る」でもよいです。
メソッド定義のやり方は、前回の組み込みライブラリの話とは違い、リファレンスマニュアルのトップページの「Ruby言語仕様」の節にあります。Rubyの文法の「クラス/メソッドの定義」のところです。その先のページの「メソッド定義」の節で書き方が説明されています。例がいくつかありますが、今回の例に近いのはhello
やfoo
が出てくるやつだと思います。メソッド定義のやりかたを忘れたらこのページに戻ってきましょう。気になる例を自分で書いてみるのもいいかもしれませんが、結構高度なものもあるのでまだよくわからないかもしれません。機会があれば別に説明します。
「Stringに穴を開ける」?
表現が謎ですが、先程のhiメソッドでname
を文字列に埋め込んで"Hello #{name}!"
としていたやつについて。やってみておわかりのとおり、埋め込んでいます。この埋め込みは、文字列の機能だからStringの機能かと思いきや、実は違って、これも「Ruby言語仕様」の中にあります。「リテラル」の項目です。
このように、機能が見つからない時はもしかしたら言語仕様の中にあるかもしれないというのはRubyではよくあるので、「そういうものか」くらいに思っておいてください。
リテラルとは、プログラムの中に書かれた値そのものです。具体的には"Hello World"
という文字列とか、2
とか3
とかの数値とかのことです。例えば文字列の場合、"
や'
で囲むとRubyプログラムの中で使える文字列になります。数字はそのまま書いただけで数値になります。こういうルールや仕組みを「リテラル」と呼びます。
このマニュアルのリテラルのページには、どういう書き方をすると文字列や数値として認識されるのか、とか、例に出てきたような埋め込みの書き方などが書かれています。具体的には、埋め込みは「文字列リテラル」の節の「式展開」の項目に書かれています。
文字列リテラルについては、ちょっと面白いのは式展開の前の項目の「バックスラッシュ記法」です。例えば以下のような文字列を表示したい場合
よっしゃよっしゃ わっしょい
つまり、改行をしたい場合にどうするか。puts
は必ず最後に改行するのでputs
を2回書いてもよいです。
puts "よっしゃよっしゃ" puts "わっしょい"
でもこれをバックスラッシュ記法を使うと1行でも書けます。
puts "よっしゃよっしゃ\nわっしょい"
このように、\n
を書いた部分が改行になります。文字列を"よっしゃよっしゃ\nわっしょい\a"
にすると、表示は変わりませんがなんか「ピ」とか音が鳴るかもしれません。環境によっては鳴らないかも。音はともかく、改行は便利なので覚えておくといいと思います。
変数について
そういえば、前回の「20分ではじめるRuby」1ページ目の最後に変数が出てきていました。こういうやつです。
irb(main) > a = 3 ** 2
計算結果をa
に格納して使い回すことができるやつです。変数は数値や文字列と同じように関数に渡したり(puts a
, hi(a)
)、文字列に埋め込んだり("Hello #{a}"
)できます。
変数については、Ruby言語仕様の「変数と定数」の項目にあります。前回出てきたのはこのページの中の「ローカル変数」というやつです。見てみると「名前は小文字で初めましょう」とか書いてあると思います。ここには主にそういうルールと、あとスコープについて書かれています。スコープというのは、その変数を使うことができる範囲のことです。定義する前に使ってはいけないとか、有効になってない場所でも使えないとか、そういう話です。詳しくはサンプルコードを動かしてみてください。
この「変数と定数」のページでは、他にも色々な種類の変数を扱っています。書き方が変わるとルールやスコープが変わってきます。そのうち出てくるので新しいものを見かけたらまたこのページに戻ってきてもいいでしょう。「20分ではじめる」でもひととおり出ているので、このページのサンプルコードを書いてみるというのもいいかもしれません。
Greeterあたりのこと
ここでclass
が出てきます。最初からやってきて、このあたりでよくわからなくなった人も多いんじゃないでしょうか。実際、クラスを書くという時はプログラムが結構大きくなった時とか大きいものを作ろうとしている時が多いので、覚えてもしばらくはあまり登場機会は無いかもしれません。ただ、それなりのものを作ろうという時や、既存のプログラムを改造する時などには必ず出てくるので、一応やっておいてもいいでしょう。
書き方などは、言語仕様の「クラス/メソッドの定義」のページです。メソッドの時に出てきたページです。結構色々できるんですが、それはまあ追い追い。
ここで@name
というのが出てきますね。これはインスタンス変数といって、これも言語仕様の「変数と定数」のページで出てきます。クラスの中でだけ使える変数です。説明は次のページでちょっとありますね。