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