simanのブログ

ゆるふわプログラマー。競技プログラミングやってます。Ruby好き

Rubyのオープンクラスについて

Rubyでは既存のクラスを再定義することができる。これを「オープンクラス」と読んだりします。

例えば配列の合計値を求めたい場合。Arrayクラスにはsumメソッドは無いので新しくメソッドを作る必要があります。

array = [1,2,3,4,5]

def sum(array)
  array.inject(:+)
end

p sum(array)
15

このようなsumメソッドを作成するのもいいのだが、Rubyならもっとスマートに解決できる方法がある。

改良版

array = [1,2,3,4,5]

class Array
  def sum
    self.inject(:+)
  end
end

p array.sum
15

こんな感じでArrayクラスにsumを定義させることでスマートにsumメソッドを記述することができるようになるのである。


ここでintroductionメソッドを新たに作成し、そのメソッド内のselfを確認してみる。

array = [1,2,3,4,5]

class Array
  def introduction
    puts "myself is #{self}"
    puts "my class is #{self.class}"
  end
end

array.introduction
myself is [1, 2, 3, 4, 5]
my class is Array

上の実行結果からintroductionメソッド内でのselfは呼び出された配列であることがわかる。そして配列のクラスはArrayクラスである


オープンクラスの問題点

オープンクラスの問題点としては、既存のクラスに元から存在していたメソッドを上書きしてしまうといったことがある。そうならないようにするためには、メソッドを定義するまえにmethod_defined?などで確認などを行なっておくとよいです。

array = [1,2,3,4,5]

class Array
  unless method_defined?(:each)
    def each
      self.times{ "hello" }
    end
  else
    puts "each method has already been defined"
  end
end

array.each do |n|
  puts n
end
each method has already been defined
1
2
3
4
5

ちゃんとeachメソッドを守ることが出来ました。