[[プログラミング言語/Ruby]] #contents * Ruby Language Digest [#xd7d634c] Ruby は行指向型言語です。つまり、改行が一文の区切りとなります。 文末記号としてセミコロン ';' も使えるのですが、一行に複数の文を書きたいのでも ない限り必要ありませんし、推奨されてもいません。 class NoVipError < StandardError ; end ↑セミコロンで文を区切る頻出例。中身のない例外クラスの定義。 なお、C言語 と同様に、バックスラッシュを打つことで行を継続させることが できますし、メソッド呼び出しの引数も複数行にわたって書くことができます。 どこでなにが複数行にわたっての記述が可能か、ということはおおむねユーザの直感に そぐうように決められているので、問題はないでしょう(C や Perl プログラマなら、 この直感はより鋭くなるでしょう)。 ** コメント [#pec5986f] #行末までコメントだぜ シェルスクリプトや Perl や Python と同じです。 =begin RDを書くところ。 =end このように、「'=begin'」のみの行から「'=end'」のみの行までの間もコメントとして 処理系には無視される。 クラスやメソッドの説明をRD(Ruby Document)形式で書くために使われたりする。 ** 変数 [#q44509e9] Ruby の変数には型がありません。 「すべてがオブジェクト」である Ruby では、変数はそのオブジェクトへの参照です。 Rubyの変数には数種類あり、識別子の先頭で書き分けます。 : ローカル変数 | local_variable 普通に英数字・アンダーバーで名前を付けます。 宣言は代入と同時、宣言されていないローカル変数の参照は NameError 例外を 起こします。 Ruby のローカル変数の宣言と評価順序はびみょーにかみ合ってません。 パースしていく感じで考えて下さい。 : グローバル変数 | $global_variable 危険なアイツ。 '$' を先頭につけます。一度も代入せずに参照すると nil を返します。そういう意味 でも危険です。'$var' と間違って '$val' とタイプしてもエラーになりません。 自分で作った変数だと「'$' が先頭 -> グローバル変数」なのですが、組み込み変数の中には例外(スレッドローカルだったり)があるので注意が必要です。 : 定数 | Constant 大文字で始めると定数にされます。 const や final のようなキーワードはありません。 宣言は代入と同時です。宣言されていない定数を参照すると NameError 例外が発生 します。この挙動を返るフックは存在しますが後述します。 Ruby の定数の縛りはちょっとゆるく、定数に再代入(初回の代入(=宣言)以降の代入) しても現在はエラーではなく警告が出るだけです。 また、Ruby の変数は前述のとおりオブジェクトへの参照なので、定数とするのも 参照です。 CONST_ARRAY = [] CONST_ARRAY.push 'hoge' なので、オブジェクトの操作はし放題です。オブジェクトの変更禁止は別の方法が あります。 : インスタンス変数 | @instance_variable Ruby で「オブジェクトの状態」を表現するもの。 '@' を先頭に付けます。一度も代入せずに参照すると nil を返します。 メンバー変数とでも言える機能ですが、オブジェクトの外からのアクセスは (リフレクション抜きでは)できません。 通常 setter・getter メソッドを定義します。 : クラス変数 | @@class_variable 名前どおりクラスが持つ変数です。 そのクラスと、そのクラスのオブジェクト両方からアクセスできます。さらに、 サブクラスに継承されたりします。若干スコープがややこしいです。 '@@' を先頭に付けます。一度も代入せずに参照すると NameError 例外が発生 します。 ** リテラル [#m578e446] Rubyのリテラル表現は豊富です。以下に代表的なものを挙げます。 *** 数値リテラル (Numeric) [#lbc01b3e] | 123 | 整数 | | 4567.89 | 実数 | | ?a | aの文字コード | *** 文字列リテラル (String) [#o8ef98d2] | "double_quote" | 式展開などが解釈されます | | 'single_quote' | 書いたままになります | | `back_quote` | コマンドとして実行し、出力を値とします | `back_quote` 構文の挙動は、実は Kernel#` というすごい名前のメソッドが 実現しています。 式展開とは: val = 123 puts "put #{val} value" このコードを実行すると、出力は put 123 value となります。式展開が有効なリテラル中で、#{...} で Ruby の式ならなんでも 置いてみると、それを評価した値の文字列表現が展開されます。 「式展開が有効なリテラル」と言いましたが、この機能が有効なのはダブルクォート 文字列に限らず、ヒアドキュメントや正規表現リテラルでも使えたりします。 *** 配列リテラル (Array) [#jb3c0ac8] [12, "abc", 123.45, some_method()] カンマで式を区切って並べて要素を指定します。もちろん一つも要素を指定しないで、 空の配列を作ることも可能です。 *** ハッシュリテラル (Hash) [#n1c30305] { "key" => "value", :KEY => 123 } 「キー => 値」という式のペアを、カンマで区切って指定します。もちろん一つも 要素を指定しないで、空のハッシュテーブルを作ることも可能です。 Ruby 1.9.x feature: { key1: "value", key2: 123 } キーが Symbol リテラルの場合、こういった書き方もできます。 *** シンボルリテラル (Symbol) [#g39bb67c] Symbol オブジェクトは、Ruby の識別子の実体でもあるオブジェクトです。 処理系に作られるものもあれば String#intern メソッドによって作られるものも あります。 「:ident」のようにリテラルが書けます。「:"*hoge*"」のように、識別子っぽくない Symbol をリテラルで書くにはクォートします。 ** ブロック付きメソッド呼び出し [#x961ec60] メソッドに引数としてオブジェクトを渡すのみならず、処理のカタマリ=ブロックを 渡すことができます。 method_name(arg, ...) do |x| ... end method_name(arg, ...){|x| ... } のように記述すると、method_name 内でこのブロックを呼び出すことが 出来ます。|...| で囲われた部分は、そのブロックが受け取る引数のためのローカル変数です。 メソッドの引数のようなものですが、メソッドと違ってブロックからは外側の ローカル変数を見ることが出来ます。 ざっくりと言ってしまうと、高階関数に渡すための無名関数のリテラル、と言えます。 例えば Lisp だと (mapcar #'(lambda (x) (* x 10)) '(1 2 3)) ; => (10 20 30) のようなことが、Ruby では [1, 2, 3].map{|x| x * 10 } # => [10, 20, 30] と書けます。 Ruby 1.9.x feature: ブロック引数の扱いが変わっています。 - 多重代入のような挙動から、メソッド引数のような扱いに変更されています。 - 外側の環境に同名のローカル変数があるのに、ブロック引数にもその名前を 使った場合、外側の環境の変数として扱われていたのに対し、新たに ブロックローカルな変数が確保されるようになります。 また、ブロックローカル変数宣言が可能になっています。 method_name(arg, ...){|x; a, b| ... } これで a や b も、外側のスコープに気兼ねせずに使える名前に なります。 ブロックを受け取った側では、yield を使ってブロックを関数呼び出しのように 呼び出せます。 def method_name(arg, ...) ... block_returning_value = yield(val) ... end この機能によって、制御構文のようなメソッドが Ruby にはいろいろあります。 ** Rubyの真偽評価 [#sfb10875] 以下に述べる条件分岐などで、Ruby の値(=オブシェクト)がどのように真偽評価される かを説明します。 結論から言うと、Ruby における偽とは false と nil であり、それ以外のあらゆる オブジェクトは真です。 明示的に真を表す代表的な値に true があります。 これら(true, false, nil)はそれぞれ TrueClass, FalseClass, NilClass の唯一の インスタンスです。 ** 制御構造 [#u6da8d06] *** 条件分岐 [#k68afffa] : if 文, if 修飾子 | if EXPR then ... end if EXPR [then] ... end ... if EXPR EXPR を評価して真ならば、... を実行する。 複数行に分けて書くならば(改行で区切りが明確なので) then は省略可能です。 if EXPR1 ... # (A) elsif EXPR2 ... # (B) else ... # (C) end EXPR1 を評価して真ならば (A) を実行して終わりますが、そうでない場合、 EXPR2 を評価して真ならば (B) を実行します。 こうした elsif 部の条件式も全部偽だった場合、(C) の else 部を実行します。 0 個以上の elsif 部の後に 0 ~ 1 個の else 部が書けます。 : unless 文, unless 修飾子 | if に似た文法をとりますが、unless は条件式の評価基準が逆です。 ... unless EXPR は、EXPR の評価が偽のときだけ ... を実行しますし、 unless EXPR ... (A) else ... (B) end は、EXPR の評価が真ならば (A) を実行し、そうでなければ (B) を実行します。 ただ、if における elsif に相当するパートはありません。 ** 繰り返し [#d785fa55] Ruby における繰り返し(ループ)のための文とは、 - while - until - for - イテレータ です。以下これら総称してただ単にループと呼びます。 : while 文 | while COND [do] ... end COND の評価が真である限り、中の文を実行します。do は省略可能です。 : until 文 | until COND [do] ... end while - until は if - unless の関係に対応し、COND の評価が偽である限り、 中の文を実行します。 : for 文 for IDENT in LIST_EXPR ... end Ruby の for 文は C などのものと違い、シェルスクリプトや Perl の foreach に 近いです。 これは、配列のように複数の要素の集合である LIST_EXPR(の評価結果)に対して、 その各要素を IDENT という変数に取り出して順次処理していくときに使われます。 in の後にとるオブジェクトには、each というメソッドがイテレータ(後述)として 実装されている必要があります。 for 文は内部でこのメソッドを呼んでいます。 : イテレータ | 例: Array#each array = [1, 2, 3, 4, 5] array.each do |x| p x #=> 1, 2, 3, 4, 5 end ブロック付きメソッド呼び出しで、「要素に対しての繰り返し」を隠蔽して 実装しています。 loop do ... end のように、一見制御構造のようなイテレータから、 1.upto(10) do |x| p x #=>1, 2, 3, ..., 9, 10 end のように、用途が特化した便利なイテレータもあります。 元々 Ruby のブロック付きメソッド呼び出し機能は、このようなイテレータメソッド を実装する狙いで、CLU という言語を参考にしたものです。 そうした歴史的経緯から、ちょっと前の文書だと 「ブロック付きメソッド呼び出しのブロック」ぐらいの意味で「イテレータ」という 言葉が使われていたりします。 : break, next, redo, retry | ループ内でのフロー制御文です。 : break | 現在のループから脱出します。 : next | 現在のループの、現在の回の残りの文を飛ばして、次の繰り返しに移ります。 : redo | 現在のループの、現在の回の繰り返しをまた初めからやり直します。 : retry | 現在のループを始めからやり直します。 ** 例外処理 [#p4e37c64] begin ... # (A) rescue ExClass => ex ... # (B) else ... # (C) ensure ... # (D) end (A) 内で起きた例外を rescue で捕捉します。 捕捉する例外クラス ExClass を指定して、変数 ex で実際に捕捉した 例外オブジェクトを参照します。 「rescue => ex」、「rescue ExClass」のように両者とも省略可能です。ExClass が 省略された場合は StandardError が指定されたものとして処理されます。 rescue 節は、発生した例外のクラスが ExClass、またはそのサブクラスの場合にその 例外を捕捉します。 並べた rescue 節がひとつも実行されなかった場合、(C) の else 部が実行されます。 そして最後に、例外が起きようが起きまいが、どの rescue 節あるいは else 節が実行 されようがされまいが、必ず締めに実行されるのが (D) の ensure 節です。 1 個以上の rescue 節のあとに 0 ~ 1 個の else 節が書けます。 そのあとに 0 ~ 1 個の ensure 節が書けます。 ** クラス定義 [#z33d56dc] せっかくのオブジェクト指向言語ですから、クラスの作り方をば。 class ClassName < SuperClass ... end 「< SuperClass」は名の通り継承するクラスを指定します。省略すると自動的に Object クラスを継承します。評価すればスーパークラスを返す式ならば置けます。 ClassNameは大文字で始める必要があります。定数と同じです(というか、まんま定数 なのですが)。 定義したクラスのインスタンスは obj = ClassName.new() のカタチで作れます。 カタチを見て判るとおり、new は予約語ではなくメソッド名で、普通に変数名とかにも 使えます。 生成したクラスを初期化したい場合、C++ や Java でいうコンストラクタのような ものを定義します。class ... end 内で定義される initialize() というメソッドが それです。new は自分の引数を initialize に丸投げします。 クラスと似たようなものにモジュールがあります。 module ModuleName ... end モジュールはクラスと違って継承できず、インスタンスも持てません。 しかし、include によってそのモジュールで定義した機能を クラス定義中に取り込むことができます(Mix-In)。 *** メソッド可視性の制御 [#t530a764] class ClassName public ... # (A) private ... # (B) protected ... # (C) end C++ や Java と語彙が一緒なので誤用されていることがたまにあります。 (A) で定義されたメソッドは public で、どこからでも呼べます。 (B) で定義されたメソッドは private で、そのオブジェクト自身のコンテキストで しか呼べません。 (C) で定義されたメソッドは protected で、private のような制御が成されますが、 自分のクラスがそのオブシェクトのクラスと同じ、あるいはサブクラスであるような オブシェクトのコンテキストでは public な制御がされます。 Ruby のメソッド呼び出し制御の着眼点は、「レシーバ.メソッド」という形で 呼び出すかどうか、に集約されます。 class Hoge def initialize priv # これはOK self.priv # NoMethodError end private def priv ... end end 同じコンテキストですらこうです。 それから、いくら private にしようがリフレクションでどうにでもなるゆるゆるな制御 なので、あてにし過ぎるのは止してください。 *** attr系メソッド -- アクセサ定義 [#pa36a72a] 「変数」の節で メンバー変数とでも言える機能ですが、オブジェクトの外からのアクセスは (リフレクション抜きでは)できません。 通常 setter・getter メソッドを定義します。 と述べました。 さて、その setter と getter ですが、set_member(val), get_member() のような ネーミングは Ruby では一般的ではありません。 obj.member = 123 obj.member あたかも属性のように、こう書きたいものです。そして Ruby では実際にこのような書き方が出来ます。Ruby パーサは、前者を member=() という名前のメソッド呼び出しと 解釈してくれるからです。 class C def member @member end def member=(val) @member = val end end これで、インスタンス変数をメソッドで属性のように扱えます。 定義する際においては他のメソッドとなんら変わりなく、代入値のチェックなども 自分で勝手に書けます。 ただ、そういった独自処理もしないのにいちいち上記のような setter・getter を手で 書くのは煩雑です。なのでこれに等しい処理は class C attr_accessor :member end で可能です。 : attr_reader | getter を定義 : attr_writer | setter を定義 : attr_accessor | 両方を定義 特別な構文のように見えますが、実はリフレクションを駆使して定型処理を便利に まとめた 1 メソッドに過ぎません。 def my_attr_reader(name) define_method(name){ instance_variable_get("@#{name}") } end def my_attr_writer(name) define_method("#{name}="){|val| instance_variable_set("@#{name}", val) } end 最低限、こんな感じで自分でも実装できます。