クラスの拡張

ここではクラスやオブジェクトを拡張する手段について紹介します。


クラスの継承

Rubyでもクラスを継承して新たにクラスを作ることが可能です。継承したクラスではスーパークラスのメソッドが利用できます。クラスの継承は以下の構文で記述します。

class クラス名 < スーパークラス名
#クラスの定義
end

スーパークラス名を省略した場合はObjectクラスがスーパークラスとなります。継承したクラスではスーパークラスのメソッドをオーバーライドすることも可能です。スーパークラスの同名メソッド呼ぶときはキーワードsuperを用います。

<class_inheritance.rb>
class SampleSuper
def initialize(name = "you")
@name = name
end

def morning(hour)
print "Good morning ", @name,
", It is ", hour.to_i, "am(SampleSuper)\n"
end

def hello
print "Hello ", @name, ".\n"
end

def evening
print "Good evening ", @name, "(SampleSuper)\n"
end
end

class Sample < SampleSuper
def morning(hour) #morningメソッドをオーバーライド
super #スーパークラスのメソッドの呼び出し。引数を指定
end #しなくても引数を渡していることに注意

def hello #helloメソッドをオーバーライド
print "Hello ", @name, " (Sample)\n" #クラス変数も継承
end

def bye
print "Good Bye ", @name, " (Sample)\n"
end
end

s = Sample.new("John")
s.morning(7)   #superを呼び出すサブクラスのメソッド
s.hello   #オーバーライドしたメソッド
s.evening   #スーパークラスのメソッド
s.bye   #新たに定義したメソッド

<実行結果>
C:\ruby>ruby class_inheritance.rb
Good morning John, It is 7am(SampleSuper)
Hello John (Sample)
Good evening John(SampleSuper)
Good Bye John (Sample)

Rubyでの継承は単一継承のみですが、後述のMix-inを使うことで他の機能もクラスに取り込むことができます。


定義済みクラスの拡張(オープンクラス)

Rubyでは(組み込みクラスを含め)定義済みクラスにメソッドを追加することができます。構文は次の通りです。

class 既存クラス名
def メソッド
#メソッド定義
end
end


次のサンプルコードは、組み込みクラスStringに、文字列から単語数を求めるメソッドcount_wordを追加した例です。

<count_word.rb>
class String
def count_word
return self.split(/\s+/).size
end
end

if ARGV.size == 1 then
puts ARGV[0].count_word
else
puts "Usage : ruby count_word.rb [String]"
end

<実行結果>
C:\ruby>ruby count_word.rb "Hello, Ruby World"
3


特異メソッド

Rubyではクラスではなくオブジェクトにメソッドを定義することができます。このようなメソッドを特異メソッドと呼びます。特異メソッドは定義されたオブジェクトのみ有効で、別のオブジェクトでは使用できません。特異メソッドは以下の構文で記述します。

def オブジェクト名.メソッド名
  #メソッド定義
end

<singular_method.rb>
class Foo
end

foo1 = Foo.new
foo2 = Foo.new

def foo1.sing_method #foo1のみ特異メソッドを定義
puts "Method is called"
end

foo1.sing_method     #foo1の特異メソッドの呼び出し
foo2.sing_method     #foo2に対しては未定義のためエラー

<実行結果>
C:\ruby>ruby singular_method.rb
Method is called
singular_method.rb:12:in `<main>': undefined method `sing_method'
for #<Foo:0xc43908> (NoMethodError)


ライブラリのロード(require)

Rubyにはライブラリをロードする機能があります。ロードできるものは、Rubyスクリプト(.rb)とRuby拡張ライブラリ(.so, .o, .dllなど)です。以下の一行をプログラム中に記述することでライブラリをロードすることができます。

require feature


このfeatureにはライブラリのファイルへのパスを指定します。featureが絶対パスの場合はfeatureからロードします。相対パスの場合は以下の場所からライブラリを探します。

  • ・組み込み変数「$:」または「$LOADPATH」に設定されているディレクトリ
  • ・rubyコマンドを "-I" オプションで指定したディレクトリ(ruby –I lib_dir

ライブラリの拡張子が.rbや.soなどの場合は拡張子を省略できます。またロードするファイルが、requireするファイルと同一ディレクトリにある場合は、./featureと記述することで読み込むことができます。

<sub_prog.rb>

class Foo
def hello
puts "hello"
end
end

<main_prog.rb>
require './sub_prog'

foo = Foo.new
foo.hello

<実行結果>
C:\ruby>ruby main_prog.rb
hello


モジュール

モジュールとはメソッドや定数をまとめたものです。クラスに近いものですが、インスタンス化できないことや、継承することができない点で異なります。
モジュールは、名前空間の提供や、後述するMix-inによるクラスの拡張を行うときに利用します。以下の構文で記述します。

module モジュール名
#クラスや定数の定義

#モジュール関数を宣言するときは以下のように記述
def self.メソッド名
#処理
end
#または以下のように記述
def モジュール名.メソッド名
#処理
end
end

モジュール内のクラスや定数にアクセスするときは、「モジュール名::」を先頭に付けます。メソッドにアクセスするときは、「モジュール名.メソッド名」とします。
次のサンプルコードはモジュールを名前空間として利用する例です。名前空間により、Fooクラスやprintメソッドが別々のものとして解釈されています。

<module.rb>
module M1
class Foo
def print
puts "M1's print method."
end
end
end

module M2
class Foo
def print
puts "M2's print method."
end
end
end

module M3
Const = 100
def M3.bar
puts "M3's bar method"
end
end

m1 = M1::Foo.new
m1.print
m2 = M2::Foo.new
m2.print

print "M3 Const:", M3::Const, "\n"
M3.bar

<実行結果>
C:\ruby>ruby module.rb
M1's print method.
M2's print method.
M3 Const:100
M3's bar method


Mix-in

Mix-inとはモジュールを使ってクラスを拡張する仕組みです。Rubyのクラス継承は単一継承のみですが、Mix-inの仕組みを使うことで多重継承と同じ目的で利用することができます。
モジュールをクラス内で用いるにはincludeメソッドを使います。こうすることで、モジュールの中のメソッドをincludeしたクラスのインスタンスメソッドのように呼び出すことができます。モジュール内のMix-in用のメソッドは、「モジュール名.」や「self.」を付ける必要はありません。

<include.rb>
module Foo
def foo_method
puts "hello"
end
end

class Bar
include Foo   #モジュールをinclude
end

bar = Bar.new
bar.foo_method #モジュールのメソッドを呼び出し

<実行結果>
C:\ruby>ruby mixin_include.rb
hello

またextendメソッドを使うことで、モジュールのメソッドをクラスメソッドとして追加したり、任意のオブジェクトに追加したりすることも可能です。

<mixin_exclude.rb>
module Foo
def foo_method
puts "hello"
end
end

class Bar
extend Foo   #クラスメソッドとして利用可能にする
end

Bar.foo_method #クラスメソッドとして呼び出し

str = "abcde" #文字列オブジェクト生成
str.extend Foo #オブジェクトにモジュールのメソッドを追加
str.foo_method


<実行結果>
C:\ruby>ruby mixin_exclude.rb
hello
hello