1
0

More than 3 years have passed since last update.

[Ruby]オープンクラスについて理解する

Last updated at Posted at 2021-05-19

オープンクラスとは

いつでも既存のClassを再オープンして、その場で修正出来ること。

オープンクラスの例

新規メソッドを作成

※Stringクラスにfooメソッドを追加してみる

class String
  def foo
    self + 'foo!'
  end
end

'My name is '.foo #=> "My name is foo"

既存のメソッドを上書き

※superclassメソッドを上書きしてみる

# 通常の動作
String.superclass #=> Object

class String
  def superclass
   'superclass!'
  end
end

# 上書き後の動作
String.superclass #=> "superclass!"

オープンクラスの問題点

既存のメソッドを上書きしてしまうことが可能なので、他の部分で上書きしたメソッドが使用されていた場合、エラーもしくは想定外の動作をしてしまいます。

このように、オープンクラスにより既存のメソッドを置き換えることをモンキーパッチと言います。

モンキーパッチは善?悪?

結論を先に言うと、ケース・バイ・ケースです。
意図的にモンキーパッチした場合は、悪いことでは無いので、「善」と言えます。
逆に、意図していない状態でモンキーパッチしてしまった場合は、「悪」と言えてしまいます。

注意点

オープンクラスを用いる際は、、

  • 全ての関連するデータが保持しても問題のない機能か見極める
  • テストコードを書く
  • 拡張Stringクラスを定義
  • (Ruby2.0以上の場合は)Refinementsを用いる

上記のポイントを意識することが重要です!

Refinementsとは

指定したクラスまたはモジュールだけに対して、ブロックで指定した機能を提供できるモジュールを定義します。これは、既存の機能を局所的に修正したい場合などに用いる事ができます。

usingは「ここ以降でRefinementsが有効」という意味で、モジュールに対して適用します。
refineはRefinementsとして拡張するclassの指定です。

# Fooクラスの定義
class Foo
  # fooメソッドの定義
  def foo
    puts "Foo#foo"
  end
end

# Barモジュールの定義
module Bar
  # FooクラスをRefinementsとして拡張
  refine Foo do
    def foo
      puts "Bar::Foo#foo"
    end
  end
end

f = Foo.new
f.foo # => "C#foo"

# ここ以降でRefinementsが有効
using Bar

f = Foo.new
f.foo # => "Bar::Foo#foo"

終わりに

オープンクラスは、便利な分、ダークサイドも併せ持つメタプログラミングなので、理解して使うことが大事だと思いました。しかし、武器にすれば心強い。。!

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0