ruby aliasの使い方
gold対策(模擬試験12)。
この手の問題も間違った気がする。
alias式
aliasは式なので、識別子、symbolが利用できます。
下記出力となるようにaliasの内容を回答させる問題。
メソッド名が引っ掛けですが、先に指定するのが新しいメソッド名です。
Hello, World Hello, Ruby World
識別子指定の場合。
def method puts 'Hello, World' end alias old_method method def method old_method puts 'Hello, Ruby World' end method
Symbol指定の場合。
def method puts 'Hello, World' end alias :old_method :method def method old_method puts 'Hello, Ruby World' end method
文字列を指定するとエラーになります。
alias_ng_string.rb:5: syntax error, unexpected tSTRING_BEG alias 'old_method' 'method' ^
本筋から離れますが、tSTRING_BEG ってなんでしょう?聞き慣れないですね。
ググると、parse.y が引っかかるので、その筋の定義のようです。
第10章 パーサ
alias_method
こちらもundefと一緒で引数に指定できるのは、Symbolと文字列です。 aliasとの違いはグローバル変数の別名をつけることはできないことだそうです。 new_methodという名前で別名を付ける例。 Symbol指定の場合。
class C def method puts 'Hello, World' end alias_method :new_method, :method def new_method method puts 'Hello, Ruby World' end end C.new.new_method # >> Hello, World # >> Hello, Ruby World
文字列指定の場合。
class C def method puts 'Hello, World' end alias_method 'new_method', 'method' def new_method method puts 'Hello, Ruby World' end end C.new.new_method # >> Hello, World # >> Hello, Ruby World
rubyのundefについて
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?()を残すためです。
rubyのインスタンスメソッドとクラスメソッド
gold対策。(基礎力確認問題11)
class Cls1 def Cls1.foo puts 'Cls1' end end class Cls2 < Cls1 def foo puts 'Cls2' end end Cls2.foo # >> 'Cls1' Cls2.new.foo # >> Cls2
これ自体は、とてもシンプルですが
gold受験だけでなくruby書く上でも
以下のことを理解しておいた方が良いんじゃないかという気がしてきたので
自分の頭の整理のつもりで書いてみます。
includeでクラスメソッドを追加するには?
moduleにクラスメソッドを記述してclassでincludeしてみる
こんな風に書いてみて、うまくいかない経験は結構あるかと思います。
module M def self.foo puts "M" end end class Cls1 include M end Cls1.foo # ~> -:10:in `<main>': undefined method `foo' for Cls1:Class (NoMethodError)
そこで特異クラスを拡張します
module M def foo puts "M" end end class Cls1 class << self include M end end Cls1.foo # >> M
クラスメソッドってものが、クラスの特異メソッドであることと
特異メソッドの住む場所が、特異クラスであること
が理解できると分かるようになるかと思います。
このあたりは、メタプログラミングRubyが詳しいので割愛します。
extend
extendで同様の実装が可能です。
module M def foo puts "M" end end class Cls1 extend M end Cls1.foo # >> M
ついでにクラスマクロ
ちょっと話がはずれますが
Railsやプラグインのソースコードでよく見る書き方です。
クラスマクロと呼ばれているものです。
attr_accessor()みたいなもんですね。
module M def self.included(base) base.extend(ClassMethods) end module ClassMethods def foo(*args) puts args end end end class Cls1 include M foo :bar, :baz end # >> bar # >> baz