7-7-3 クラスをオブジェクトと捉えた特殊な書き方をおさえよう

クラスを記述する別の方法と無名クラス

クラス定義をClassクラスのオブジェクトと捉えた場合、これまでとは別の書き方でクラスを定義することができます。

クラス名 = Class.new doendと記述することは、class クラス名endとほぼ同じ意味になります。

この別の書き方は、見方を変えると、定数にClassクラスのインスタンスを生成して代入する表現であると言えます。

この記述方法を通して、Rubyのプログラミング言語としての特徴をより深く理解することができます。

また、クラス名には、先頭をアルファベット大文字で定義しますが、先頭をアルファベット小文字、つまり通常の変数として定義する場合、クラス名がないClassクラスのオブジェクトを生成することもできます。

このようなクラスのことを無名クラスと呼びます。

クラスメソッドを記述する別の方法と名前空間

クラスメソッドを定義するには、これまで確認してきた方法では以下の2つがありました。

  • メソッド名の前にself.を記述する
  • class << selfendの中にメソッドを記述する

この定義方法とは別に、Rubyではクラス定義の外側からクラスメソッドを定義することもできます。def クラス名.メソッド名endと記述します。

これは、通常のメソッドを定義する方法と似ていますが、違うのは通常のメソッドではクラス名は記述しませんでしたが、クラスメソッドを後付けする場合はクラス名を記述しドット(.)でメソッド名を繋げて定義する点です。

このような記述を通して、「6章 メソッドを使ってプログラミングする」で確認したように、単純にメソッドを定義する場合と異なるのは、該当のメソッドがどこで使用することができるかの範囲(スコープ)を決めていることです。

前ページ「7-7-2 特別なクラスやメソッドの存在を確認しよう」の例で言うと、def SpecialClass.call_class_methodとクラス名を指定して定義することで、このメソッドを呼び出すには、SpecialClass.call_class_methodSpecialClassクラスを指定する必要があります。

逆に、メソッドをクラス名を指定せずdef call_class_methodのように定義した場合は、call_class_methodとクラス名を指定せずに呼び出すことができます。

クラスの中に定数やメソッドを定義することで、扱える範囲が変わります。この扱える範囲のことを名前空間と呼びます。

SpecialClassなどのクラス名は、データや処理が扱える範囲を指定する名前空間であると捉えることができます。

6章 メソッドを使ってプログラミングする」の形式のように直接メソッドを定義している名前空間はグローバルな名前空間と表現することもあります。他にも、トップレベルと呼ぶこともあります。

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

クラスのインスタンスを生成した後に、def インスタンス.メソッド名と記述し、そのインスタンス専用のメソッドを後から付け加えることができます。

このメソッドはそのインスタンスのみで有効です。このメソッドのことを特異メソッドと呼びます。

特異メソッドはインスタンスに後付けされたものなので、元のクラスには何も変更が加えられていません。

それでは特異メソッドが実装されているのはどこにあるのでしょうか。

Ruby内部では、インスタンスそのものに実装されているという扱いではなく、特異メソッドが実装されている仮のクラスがあてがわれています。

このクラスのことを特異クラスと呼びます。

前ページ「7-7-2 特別なクラスやメソッドの存在を確認しよう」の例で確認したように、特異クラスはインスタンス.singleton_classとすることで取得することができます。

特異クラスを表示すると#<Class:#<SpecialClass:0x007f8c8091cd78>>などとなっています。

これは「SpecialClassのインスタンスが指定されたClassクラスのインスタンス」という意味です。

特異クラスがRubyではどのように見えているかを確認することができます。

特異メソッドがどのクラスに存在していることを確認するには、クラス名.method_defined?(メソッド名のシンボル)と記述します。

前ページ「7-7-2 特別なクラスやメソッドの存在を確認しよう」の例では、元のSpecialClassクラスには特異メソッドであるcall_singleton_methodメソッドが存在せずfalseで返却され、特異クラスにはcall_singleton_methodメソッドが存在するのでtrueが返却されています。

メタプログラミング

Rubyの特徴としてよく登場するメタプログラミングですが、これまで確認した例だけでは、その実体がよく分からない部分もあるでしょう。

メタプログラミングとは、課題解決の為に直接プログラミングするのではなく、より簡単にプログラミングする為のプログラムを書くことです。

本節で確認したRubyの言語仕様は、このような側面を強力にサポートするものです。

Rubyのメタプログラミングは難しい側面もありますが、RubyGemsなど世の中のOSS(オープンソースソフトウェア)では広く使われています。

Ruby製の便利なライブラリがたくさん普及した背景には、Rubyの言語としての柔軟性が強く影響していると言えます。

クラスをオブジェクトと捉えた特殊な書き方のまとめ

  • RubyでクラスはClassクラスのインスタンスであると解釈できる
  • class宣言だけでなく、Class.newを使ってクラスを定義できる
  • クラスメソッドをトップレベルで定義できる
  • インスタンスに後から特異メソッドを追加でき、このとき特異クラスが内部的に存在する