クラス、オブジェクト、変数 プログラミング Ruby 1.9 - 言語編 - 3章

前のエントリに引き続き「プログラミング Ruby 1.9 - 言語編 -」*1

プログラミングRuby 1.9 −言語編−

プログラミングRuby 1.9 −言語編−

気になったところを書き留めているので、
ピッケル本1.9が手元にない方はなにがなんやら?だと思います。
コードは本にあるサンプルを元にしているので、参考までにどーぞ。

前段


putsは、プログラムの標準出力に文字列を書き出すだけであることを覚えておいてください。
....
to_sのデフォルトの実装をオーバーライドして、オブジェクトの中身がわかりやすく出力されるようにしてみましょう。

class BookInStock
  def initialize(isbn, price)
    @isbn = isbn
    @price = Float(price)
  end
  def to_s
    "ISBN: #{@isbn}, price: #{@price}"
  end
end

puts BookInStock.new("isbn1", 3)
#=> #<BookInStock:0x87344cc @isbn="isbn1", @price=3.0> # to_s オーバーライド前
#=> ISBN: isbn1, price: 3.0 # to_s 用意後

仮想属性とメソッド

先のBookInStockクラスにprice_in_centsという読み書きのメソッドを用意します。

class BookInStock
  def price_in_cents
    Integer(price*100 + 0.5)
  end

  def price_in_cents=(cents)
    @price = cents / 100.0
  end
end

book = BookInStock.new("isbn1", 33.8)
puts book.price_in_cents #=> 3380
book.price_in_cents = 1234
puts book.price #=> 12.34

クラスの外から見たばあい、対応するインスタンス変数が存在しなくても
price_in_centsはクラスの属性として見えるので、「仮想属性」と呼ぶらしい。
では、このprice_in_centsは「メソッド」とどう違うかというと


内部状態はインスタンス変数として保持されます。外部状態は、属性と呼ばれるメソッドを介して外部に公開されます。
クラスが実行可能なその他のアクション、つまり内部状態を外部に見せるという以外のアクションが通常のメソッドです。

とのこと。
price_in_centsはインスタンス変数を操作しているかのようなメソッドなので「属性」扱いなんですね。
「明解な答えがない問い」だということなので、まぁそんなもんかと理解しておこうと思います。

クラス変数とクラスメソッド

csvライブラリが使いやすいとか、injectを使わずにeachで計算しているとかはさておき。
ロードするファイルを相対的に示せる「require_relative」は1.9以降に追加されたようですね。

アクセス制御

メソッドのアクセス制御については言語ごとに異なるので引用しておきます。

  • public メソッド: 誰でも呼び出せるメソッドです。アクセス制御は行われません。デフォルトのメソッド保護方式です(ただし、initialize は常にprivate なので除きます)。
  • protected メソッド: 定義元クラスおよびそのサブクラスのオブジェクトだけが呼び出せます。それ以外のオブジェクトによるアクセスは禁止されます。
  • private メソッド: 明示的なレシーバを指定して呼び出すことはできません。レシーバは常に自分自身(self)です。つまり、private メソッドは現在のオブジェクトのコンテキスト内でしか呼び出せません。別のオブジェクトのprivate メソッドを呼び出すことができません。

ちなみに、アクセス制御関数を使って、
以下のように各メソッドのアクセスレベルをクラスの末尾で設定できるようです。

class MyClass
  ...
  public :method1, :method4
  protected :method3
  private :method2
end

当然ながら、private メソッドのつもりで書いていても
アクセス制御関数でpublicにしてしまうと外部からアクセスできてしまいます。

class MyClass
  private
  def method1
    puts "this is method1"
  end

  public :method1
end

c = MyClass.new
c.method1 #=> "this is method1"

*1:これ以降は「ピッケル本1.9」とでも呼ぼう。表紙にピッケルの絵はないけど :-p