クラスとモジュール
クラス定義
class
キーワードを用いて、先頭大文字でクラスを定義します。
class Foo < Object
DEFINE_NAME = "hoge"
def initialize
end
end
Foo::DEFINE_NAME
foo = Foo.new
- class内に定義した定数は
::
演算子で参照可能 new
メソッドでインスタンスを生成initialize
メソッドでクラスの初期化処理を定義することが出来る
インスタンスメソッド
インスタンスメソッドを定義するには、クラス定義の中でメソッドを定義します。
メソッドの末尾には疑問符や感嘆符を使うことが出来ます。オブジェクトの状態を真偽値で返す場合は疑問符を、破壊的なメソッドを表す場合は感嘆符を使用するという慣習があります。
class Foo
def call
end
end
foo = Foo.new
foo.call
アクセサメソッド
attr_accessor
, attr_reader
, attr_writer
,キーワードを使用することでアクセサメソッドを定義することが可能です。
class Foo
attr_accessor :name # getter/setterがそれぞれ定義される
attr_reader :sex # getterが定義される
attr_writer :age # setterが定義される
end
foo = Foo.new
foo.name = "hoge"
foo.name
foo.sex
foo.age = 10
クラスメソッド
Rubyではクラスもオブジェクトの1つであり、クラスに対してメソッドを呼び出すことが出来ます。self
キーワードがついているメソッドがクラスメソッドとして定義されます。
class Foo
# 個別でクラスメソッドを定義
def self.hoge
"hoge"
end
# 複数まとめてクラスメソッドを定義
class << self
def bar
"bar"
end
end
end
Foo.hoge # hoge
Foo.bar # bar
メソッドの呼び出し制限
- public : 制限なし
- private : レシーバを省略するかたちでしか呼び出せない
- protected : そのメソッドが定義されたのと同じクラス、またはサブクラスのインスタンスからしか呼び出せない
protectedメソッドは他の言語のprotectedとは異なり、同じクラスに属しているインスタンスのメソッドの中であれば、異なるインスタンスのprotectedなメソッドを呼び出すことが出来ます。
protectedのような呼び出し制限が必要となる場合はほとんどないため、基本privateメソッドを用いる方が主流です。
クラスの継承
Rubyは単一継承をサポートしており、クラスを定義する時に1つだけスーパークラスを指定することが出来ます。クラスを定義する時にスーパークラスを指定しなければ、自動的にObject
クラスが継承されます。
class Parent
def greet
"Hi"
end
end
class Child < Parent
end
Child.superclass # Parent
child = Child.new
child.greet # Hi
サブクラスはスーパークラスのインスタンスメソッド、クラスメソッドを継承します。しかし、サブクラスはインスタンス変数についての情報は継承しません。クラスはインスタンス変数に関する情報は持っておらず、インスタンス変数はインスタンスメソッドの中で定義されるからです。
メソッドのオーバライド
スーパークラスにあるメソッドと同名のメソッドをサブクラスで再定義することを、メソッドのオーバライドといいます。これにより、機能をそのサブクラスに適したものに変更したり、拡張することが出来ます。
メソッドの中でsuper
を呼び出すことで、スーパークラスに定義されている同名のメソッドを呼び出すことが出来ます。スーパークラスのメソッドには、サブクラスのメソッド呼び出しで受け取った引数が自動的に渡されます。
class Parent
def greet
"Hi"
end
end
class Child < Parent
def greet(name)
super + "\t" + name
end
end
特異メソッド
オブジェクトは、クラスに定義されたメソッドの他に、そのオブジェクト児湯のメソッドを持つことが出来ます。これを特異メソッドと呼びます。
class Foo
end
foo = Foo.new
def foo.test
print "this test"
end
foo.test
クラス定義のネスト
クラス定義の中にネストしてクラスを定義することが可能です。
class My
class SweetClass
end
end
My.new
My::SweetClass.new
モジュール
module Foo
def test
end
end
モジュールの特徴
- インスタンスを生成することはできない
- 継承することは出来ない
モジュールの用途
- 名前空間を作る
- モジュールのメソッドをあるクラスのインスタンスメソッドとして取り込む
- モジュールのメソッドをあるオブジェクトの特異メソッド(クラスメソッド)として取り込む
- モジュール関数を定義して使う
メソッドをクラスのインスタンスメソッドとして取り込む
モジュールに定義されたメソッドは、クラスのインスタンスメソッドとして取り込む事ができます。これをMix-inと言います。インスタンスメソッドとしてモジュールを取り込むにはinclude
を用います。
module Greetable
def greet_to(name)
puts "Hello, #{name}. class is #{self.class}."
end
end
class Alice
include Greetable
end
alice = Alice.new
alice.greet_to("Bob") # => "Hello, Bob. class is Alice."
メソッドをオブジェクトに取り込む
モジュールに定義されたメソッドは、オブジェクトの特異メソッドとして取り込むが出来ます。オブジェクトにモジュールのメソッドを取り込むには、extend
を用います。
module Greetable
def greet_to(name)
puts "Hello, #{name}. class is #{self.class}."
end
end
o = Object.new
o.extend Greetable
o.greet_to("World") # "Hello, World. class is Object."
モジュール関数
サブルーチンとして利用されることを目的としたメソッドは、モジュール関数として定義されることがあります。モジュール関数とは「privateなインスタンスメソッドであると同時に、モジュールの特異メソッドでもある」メソッドのことを指します。モジュール関数としてメソッドを定義することで、そのメソッドを2つの方法で使うことが出来るようになります。
# モジュールから直接呼び出す
Math.sqrt(4)
# includeして使う
include Math
sqrt(4)
モジュールに定義したメソッドをモジュール関数にする
module MyFunctions
def my_module_function
puts "Called"
end
module_function :my_module_function
end
複数のモジュール関数を定義する
module MyFunctions
module_function
def my_first_functin
"first"
end
def my_second_functin
"second"
end
end
クラスやモジュールを自動的にロードする
毎回必ずロードするとは限らない外部ファイルの読み込みには、autoload
を用いることが出来ます。
autoload :MySweets
MySeeets # ここでrequireされる
オブジェクト
ほとんどのクラスはObject
クラスから派生したサブクラスです。スーパークラスを指定しなかった場合は自動的にObjectクラスを継承します。
class MyClass
end
MyClass.superclass # => Object
オブジェクトの基本的な振る舞い
Objectくらすには、そのオブジェクトの情報を返すメソッドや比較演算子など、オブジェクトとしての基本的な機能が実装されています。
o = Object.new
# 自身についての情報を返す
o.class # => Object
o.is_a?(Object) # => true
o.object_id # オブジェクト児湯のID
オブジェクトへの変更を禁止する
Object#freeze
を呼び出すと、レシーバへの破壊的な操作を禁止することが出来ます。freezeされたオブジェクトに変更を加えようとするとRuntimeError
が発生します。
オブジェクトをコピーする
オブジェクトをコピーするにはObject#dup
やObject#clone
を用います。どちらのメソッドも汚染状態も含めてオブジェクトをコピーします。
Object#clone
はfreezeの状態や、特異メソッドの情報も含めてコピーします
original = Object.new
original.object_id
original.freeze
copy_dup = original.dup
copy_dup.object_id
copy_dup.frozen? # => false
copy_clone = original.clone
copy_clone.object_id
copy_clone.frozen? # => true
汚染されたオブジェクト
Rubyにはセーフレベルという、外部からの入力によって危険な操作が行われることを未然に防ぐ機能があります。
環境変数やコマンドライン引数など、外部からの入力は汚染されたオブジェクトとして扱われます。セーフレベルを適切に設定すると、汚染されたオブジェクトを用いた危険な操作が禁止されます。
オブジェクトが汚染されているかどうかは、Object#tainted?
で確認できます。
$SAFE # => 0
Object.new.tainted? # false
ENV["HOME"].tainted? # true
rcfile = ENV["HOME"] + "/.zshrc"
rcfile.tainted? # true 汚染されたオブジェクトを元に生成されたオブジェクトも汚染されたオブジェクトになる
セーフレベル
レベル | 概要 |
---|---|
0 | デフォルトのセーフレベル。IOや環境変数、コマンドライン引数から得られた文字列には汚染マークがつく |
1 | 汚染マークがつく対象は0と同じ。汚染されたオブジェクトを引数としたファイル操作、コマンドの実行、シグナルのトラップなどが禁止される |
2 | 汚染マークがつく対象は0と同じ。1の制限に加え、プロセスに関する操作も禁止される。 |
3 | このレベルで生成されたでオブジェクトにはすべて汚染マークがつく。2までの制限に加え、汚染を解除することなどが禁止される。 |
4 | 汚染マークがつく対象は3と同じ。3までの制限に加え、グローバル変数や汚染されていないオブジェクトの変更、メソッドの再定義などが禁止される |