7-5-3 Rubyの強力な言語仕様の側面を理解しよう

インスタンスのデータに値を代入する

インスタンス内で共通で使うことができるデータは、インスタンス変数です。

外部からインスタンス変数に値を代入する為には、代入用のメソッドを別途クラスに定義する必要があります。

代入用のメソッドを定義するには、def メソッド=(引数)と記述します。

体験で確認したエラーメッセージからも読み取れるように、代入用のメソッド名はイコール(=)までを含めたものとなります。

よって、イコールがない場合のメソッド名とは別のメソッドとして認識されます。

前ページ「7-5-2 健康診断を行うクラスをアクセサメソッドを使って実装しよう」の例では、MedicalExaminatorクラスのheight=メソッドとheightメソッドとは別物ということになります。

アクセサメソッド

アクセサメソッドは、attr_writerattr_readerattr_accessorの後の半角スペースの後に、インスタンス変数の@抜きの文字列をシンボルで記述することで使用できます。

attr_writer

attr_writerは、シンボルで記述した名前のメソッドでインスタンス変数に代入する処理を同時に行います。

前ページ「7-5-2 健康診断を行うクラスをアクセサメソッドを使って実装しよう」の例で言うと、attr_writer :heightと定義すれば、インスタンス.height = 代入したい値のように使うことができます。

この式が評価されると、インスタンス変数@heightに値が代入されます。

attr_writerを使ったプログラムは、以下のプログラムと同じ動作となります。

# attr_writerを使用した場合
class MedicalExaminator
  attr_writer :height
end

# attr_writerを使用しない場合
class MedicalExaminator
  def height=(height)
    @height = height
  end
end

attr_reader

attr_readerは、シンボルで記述した名前のメソッドでインスタンス変数の値を戻り値として返却します。

前ページ「7-5-2 健康診断を行うクラスをアクセサメソッドを使って実装しよう」の例で言うと、attr_reader :heightと定義すれば、インスタンス.heightのように使うことができます。

この式が評価されると、インスタンス変数@heightの現在の値を取り出すことができます。

attr_readerを使ったプログラムは、以下のプログラムと同じ動作となります。

# attr_readerを使用した場合
class MedicalExaminator
  attr_reader :height
end

# attr_readerを使用しない場合
class MedicalExaminator
  def height
    @height
  end
end

attr_accessor

attr_accessorは、attr_writerattr_readerの両方の定義を同時に行います。

インスタンス変数をメソッドのように使って代入したり参照したりすることを簡単に行えるようになります。

なお体験の例で確認した通り、複数定義したい場合は、アクセサメソッドの後にシンボルをカンマ区切りで記述します。

attr_accessorを使ったプログラムは、以下のプログラムと同じ動作となります。

# attr_accessorを使用した場合
class MedicalExaminator
  attr_accessor :height
end

# attr_accessorを使用しない場合
class MedicalExaminator
  def height=(height)
    @height = height
  end

  def height
    @height
  end
end

アクセサメソッドのまとめ

まとめると、アクセサメソッドには以下の3つの種類があります。

アクセサメソッドの種類 用途
attr_writer 外部からインスタンス変数へ書き込みのみ許可する。外部からの読み込みは許可しない。
attr_reader 外部からインスタンス変数の読み込みのみ許可する。外部からの書き込みは許可しない。
attr_accessor 外部からインスタンス変数の読み込み/書き込みの両方を許可する。

前ページ「7-5-2 健康診断を行うクラスをアクセサメソッドを使って実装しよう」の例で確認した通り、アクセサメソッドは、インスタンス変数を外部から操作する為に強力なサポートをしてくれます。

DSL

アクセサメソッドは、オブジェクト指向スクリプト言語としてのRubyの特徴を表しています。

このアクセサメソッドのように、attr_accessor :heightなど、特定の宣言をすることで、普通にプログラムを記述するよりも単純化できる仕組みのことをDSL(Domain Specific Language:ドメイン固有言語)と呼びます。

Rubyにおけるアクセサメソッドは、DSLの中でも内部DSLと言われ、あるプログラムによって別のプログラムを記述する仕組みを提供してくれています。

このようなRubyの特徴は、メタプログラミングと呼ばれます。

メタプログラミングについての詳細は、入門者向けの解説範囲を超えているので解説は省略します。

しかし、「Rubyといえばメタプログラミング」と言っても言い過ぎではないほどRubyというプログラミング言語の特徴をよく表現しています。

メタプログラミングはRubyの面白い部分でもあるので、本サイトが物足りなくなった方は是非ご自身で調べてみてください。

スコープ(範囲)とは

クラスのpublicメソッドやprivateメソッドの違いは、インスタンスからアクセスできるか否かの違いでした。

言い換えると、アクセス可能な範囲がメソッドの種類によって異なるといえます。

アクセサメソッドの違いは、インスタンスから書き込めるか(write)、読み込めるか(read)、その両方かという違いでした。

言い換えると、インスタンス変数へのアクセス可能な範囲がアクセサメソッドの種類によって異なるといえます。

このように、アクセス可能性が異なる範囲のことをスコープと呼びます。

光が当たらない場所は暗くて見えないように、スコープによってできること/できないことが異なります。

まとめ

  • アクセサメソッドを使って、インスタンス変数にクラス外部から間接的にアクセスできる
  • アクセサメソッドは、内部DSLと呼ばれ、Rubyのメタプログラミングの特徴をよく表している