Thursday, July 29, 2010

Rubyの特異メソッドと特異クラス

プログラミング言語Ruby P269辺りに特異メソッドと特異クラスについての解説がある。
読んだだけじゃ絶対にわすれるので、メモっとく。

特異メソッド
クラスに属するすべてのオブジェクトではなく、単一のオブジェクトだけのために定義されたメソッド
オブジェクトの特異メソッドは、そのオブジェクトのクラスによって定義されない。
そのオブジェクトに対応付けられた無名の特異クラスのインスタンスメソッドである。
無名の特異クラスのことをシングルトンクラス、メタクラスと呼ぶ。

各インスタンスごとに特異クラスを持つ。
classのインスタンスClass1の特異メソッドは、Class1クラスのクラスメソッドであり、
classのインスタンスであるClass1の特異クラスのインスタンスメソッドである。

試してみた。

# ClassクラスのインスタンスであるPointオブジェクトに特異メソッドを定義
# Pointクラスのクラスメソッドになる
class Point; end
def Point.sum x, y; x + y; end
p Point.sum 1,2  #=> 3

# 特異メソッドを複数定義時に便利な構文糖
class << Point
  def minus x, y; x - y; end
  def multi x, y; x * y; end
end
p Point.minus 1,2  #=> -1
p Point.multi 1,2  #=> 2

# クラス定義中にクラスメソッドを複数定義するときに便利な構文糖
# class << self は特異クラス(classのインスタンスであるPointクラスオブジェクト)
class Point
  class << self
    def div x, y; x / y; end
  end
  def self.eignclass 
    class << self; self; end
  end
end

# p1オブジェクトの特異メソッドを定義
p1 = Point.new
def p1.sum x, y, z; x + y + z; end
p p1.sum(1, 2, 3) #=> 6

# p2からはp1の特異メソッドは見えない
p2 = Point.new
#p p2.sum(1, 2, 3) #=> NoMethodError

class << p2
  def sum x, y ,z, a; x + y + z + a; end
  def multi x, y ,z, a; x * y * z * a; end
end
p p2.sum 1, 2, 3, 4 #=> 10
p p2.multi 1, 2, 3, 4 #=> 24

# p2からはP1特異メソッド特異メソッドは見えない
#p p1.sum 1, 2, 3, 4 #=> NoMethodError

# 実行結果
# 3
# -1
# 2
# 6
# 10
# 24


もう一丁。

class Class1
  puts "#{self.__id__} before open singleton class"
  class << self
    puts "#{self.__id__} opening singleton class"
  end
  def self.eignclass 
    class << self; self; end
  end
  puts "<<< " + self.to_s
end

class Class2
  puts ">>> " + self.to_s
  puts "#{self.__id__} before open singleton class"
  class << self
    puts "#{self.__id__} opening singleton class"
  end
  def self.eignclass 
    class << self; self; end
  end
  puts "<<< " + self.to_s
end
puts "------------"
puts "#{Class1.__id__} Class1.__id__"
puts "#{Class1.eignclass.__id__} Class1.eignclass.__id__"

puts "------------"
puts "#{Class2.__id__} Class2.__id__"
puts "#{Class2.eignclass.__id__} Class2.eignclass.__id__"

puts "------------"
c1 = Class1.new
puts "#{c1.__id__} c1's id"
class << c1 
  puts "#{self.__id__} c1's singleton class"
end

puts "------------"
c11 = Class1.new
puts "#{c11.__id__} c11's id"
class << c11
  puts "#{self.__id__} c11's singleton class"
end

puts "------------"
c2 = Class2.new
puts "#{c2.__id__} c2's id"
class << c2 
  puts "#{self.__id__} c2's singleton class"
end

puts "------------"
c21 = Class2.new
puts "#{c21.__id__} c21's id"
class << c21
  puts "#{self.__id__} c21's singleton class"
end

# 実行結果
# >>> Class1
# 70227334526040 before open singleton class
# 70227334526020 opening singleton class
# <<< Class1
# >>> Class2
# 70227334525980 before open singleton class
# 70227334525680 opening singleton class
# <<< Class2
# ------------
# 70227334526040 Class1.__id__
# 70227334526020 Class1.eignclass.__id__
# ------------
# 70227334525980 Class2.__id__
# 70227334525680 Class2.eignclass.__id__
# ------------
# 70227334525100 c1's id
# 70227334525040 c1's singleton class
# ------------
# 70227334524940 c11's id
# 70227334524880 c11's singleton class
# ------------
# 70227334524780 c2's id
# 70227334524720 c2's singleton class
# ------------
# 70227334524620 c21's id
# 70227334524560 c21's singleton class

Thursday, July 22, 2010

Rubyのクラスメソッド

プログラミング言語Ruby(P268)

クラスのクラスメソッドとは、そのクラスを表現するClassクラスのインスタンスの特異メソッドにすぎない。

RubyのModule, Class, include, extend, selfポインタ

プログラミング言語Ruby P258の内容のサンプル。

クラス階層が必要のないグローバル関数を、グローバルな名前空間を汚さないためにModuleとしてまとめる方法。
moduleに定義したインスタンスメソッドをmix-inする方法( include, extend)
includeはインスタンスメソッドとして織りまぜ、
extendは特異メソッドとして織りまぜる。

module SampleModule

  # class method
  def self.hello
    puts "hello"
  end

  # class method
  def self.goodby
    puts "goodby"
  end

  # instance method
  def good_morning
    puts "good_morning"
  end
end

class IncludeMod
  # インスタンスメソッドとしてinclude
  include SampleModule
end

class ExtendMod
  # クラスメソッドとしてextend
  # この時のselfはクラスの中、メソッド定義の外なので ExtendModクラスをサス(P225)
  self.extend SampleModule
  #ExtendMod.extend SampleModule
end

SampleModule.hello
SampleModule.goodby

IncludeMod.new.good_morning
ExtendMod.good_morning


Rubyの継承時のprivateメソッドには注意

プログラミング言語Ruby P248

サブクラスはPrivateメソッドを継承する。
サブクラスは親で定義されたprivateメソッドを呼び出せ、オーバーライドすることが可能。

他人が書いたクラスをサブクラス化するときは気をつけろ。
偶然、同じ名前のprivateメソッドをオーバーライドするとバグる。

Rubyではサブクラス化するのは、スーパークラスの実装を欲知っている時に限るべきだ。
継承ではなく、委譲するべき。

Ruby1.9からSymbolクラスにto_procが追加されたってか

プログラミング言語Rubyを読んでいる。
P217に、Ruby1.9からSynbolクラスにto_procが追加されたので、シンボルに&プレフィックスを付けると、イテレータにブロックとして渡せるようになった、と書いてある。

メモメモ。

def succ x; x + 1; end
p [1,2,3].map{|x| x + 1}
p [1,2,3].map{|x| succ x}
p [1,2,3].map(&:succ)
p [1,2,3].map(&self.method(:succ))
p [1,2,3].map{|x| self.method(:succ).call(x) }
p [1,2,3].map{|x| self.method(:succ).to_proc.call(x) }

Wednesday, July 21, 2010

Rubyで関数を継承?

勉強のためにRubyのライブラリでも見ていくことにした。
とりあえず一発目はtempfile.rbでも見てみるかということで、13行目。

class Tempfile < DelegateClass(File)
ほうほう、DelegateClassを継承しているのね。でも括弧なんだろ? おもむろにCtagsで飛んでみた。(delegate.rb) そしたら、ビックリ。
def DelegateClass(superclass)
関数じゃないですか。

分からん。。
また分かったら追記するってことでメモっておく。

追記
わかった。
def DelegateClass(superclass)
はクラスを返すメソッドなのね。

Delegate(クラス)で指定したクラスのpublic instance methodと
__getobj__, __setobj__をmodule_evalしたクラスを
継承したいからこんなことしてるのか。

Thursday, July 1, 2010

vrome 0.5.7 (chrome extention)でページ内日本語検索ができんぞ

/(スラッシュ)でページ内を日本語で検索しようとしても検索できない。
アルファベットならいけるけど。
Ctrl + fもnext pageに割り当ててられていて使えない。

不便過ぎて発狂しそうになったので、extentionのソースを変更してCtrl + f でChromeの検索窓が出るようにした。


kanbe@kanbe-laptop% locate vrome
/home/kanbe/.config/google-chrome/Default/Extensions/godjoomfiimiddapohpmfklhgmbfffjj/0.5.7/vromerc_example

kanbe@kanbe-laptop% cd /home/kanbe/.config/google-chrome/Default/Extensions/godjoomfiimiddapohpmfklhgmbfffjj/0.5.7
kanbe@kanbe-laptop% grep "<c-f>" **/*
frontend/main.js:  add("<c-f>" , Scroll.nextPage     );
..




main.jsのadd...をコメントアウトで終了。