[[プログラミング言語/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
  
  最低限、こんな感じで自分でも実装できます。


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS