gold対策。(基礎力確認問題12)
インスタンスメソッドfooをundefしているので、エラーになります。
module Mod def foo puts 'Mod' end end class Cls1 def foo puts 'Cls1' end end class Cls2 < Cls1 include Mod undef foo end Cls2.foo # => # ~> -:17:in `<main>': undefined method `foo' for Cls2:Class (NoMethodError)
これは通常の動きなのですが、クラスメソッドをundefする場合はどう書くのだろう?
と思ったのでやってみます。
クラスメソッドをundefする
ダメなやりかた
クラスやselfを指定する方法はNGです。
class C def self.foo; puts 'foo'; end undef C.foo end # ~> -:3: syntax error, unexpected '.', expecting keyword_end # ~> undef C.foo # ~>
class C def self.foo; puts 'foo'; end undef self.foo end # ~> -:3: syntax error, unexpected '.', expecting keyword_end # ~> undef self.foo # ~>
もちろんfooだけだと、インスタンスメソッドを対象にするのでエラーとなります。
class C def self.foo; puts 'foo'; end undef foo end # ~> -:3:in `<class:C>': undefined method `foo' for class `C' (NameError) # ~> from -:1:in `<main>'
これだとOK
特異クラスでやります。
class C def self.foo; puts 'foo'; end class << self undef foo end end
class_evalなら。(これはあんまり関係ないか)
class C def self.foo; puts 'foo'; end end C.class_eval do class << self undef foo; end end
undefとundef_methodについて
2つとも同様の機能ですが、引数に違いがあります。
undef文(式?)は、メソッド or Symbol が指定可能です。
undef_methodはメソッドなのでSymbolとStringです。
・undef文
class A def foo; puts 'foo'; end undef foo end class B def foo; puts 'foo'; end undef :foo end
ちなみに文字列はダメです。
class A def foo; puts 'foo'; end undef "foo" end
・undef_method
class A def foo; puts 'foo'; end undef_method :foo end
class A def foo; puts 'foo'; end undef_method 'foo' end
そもそもundefなんか使うのか?
ってことですが、メタプログラミングRuby(2章)で紹介されているように
ブランクスレートという使い方があるかと思います。
ブランクスレートは、メソッドをすべて削除した状態のことです。
method_missing()を安全に使う方法として、
レシーバのメソッドは削除するが、継承したメソッドをそのままにする
ということをやろうとすると、下記のようにundef_method()使って書けます。
class Computer instance_methods.each do |m| undef_method m unless m.to_s =~ /^__|method_missing|respond_to?/ end end
正規表現のところは、__id__, __send__、method_missing(), respond_to?()を残すためです。