4. super のきほん class Super
def hello
puts 'Super: Hello World!'
end
end
class Sub < Super
def hello
super
end
end
Sub.new.hello
#=> Super: Hello World!
4
スーパークラスの
同名 method を探索
→ 実行
5. super のきほん
class Super
def hello
puts 'Super: Hello World!'
end
end
module Mod
def hello
puts 'Mod: Hello World from mod.'
end
end
class Sub < Super
include Mod
def hello
super
end
end
Sub.new.hello
#=> Mod: Hello World from mod.
5
正しくは:
継承上位の
同名 method を探索
→ 実行
6. super のきほん
class Ultra
def hello
puts 'Ultra: Hello World from Ultra.'
end
end
class Super < Ultra
end
class Sub < Super
def hello
super
end
end
Sub.new.hello
#=> Ultra: Hello World from Ultra.
6
正しくは:
継承上位の
同名 method を探索
→ 実行
7. super class Super
def hello(*args)
puts "Super: Hello #{args.join(',')}!"
end
end
class Sub < Super
def hello(*args)
super
end
end
Sub.new.hello('a', 'b', 'c')
#=> Super: Hello a,b,c!
7
引数の渡し方
● そのまま
● 無し
● 独自に設定
8. super() class Super
def hello(*args)
puts "Super: Hello #{args.join(',')}!"
end
end
class Sub < Super
def hello(*args)
super()
end
end
Sub.new.hello('a', 'b', 'c')
#=> Super: Hello !
8
引数の渡し方
● そのまま
● 無し
● 独自に設定
9. super(arg1, arg2) class Super
def hello(*args)
puts "Super: Hello #{args.join(',')}!"
end
end
class Sub < Super
def hello(*args)
super('Japan', 'JP', 'ja')
end
end
Sub.new.hello('a', 'b', 'c')
#=> Super: Hello Japan,JP,ja!
9
引数の渡し方
● そのまま
● 無し
● 独自に設定
10. パッチ
特定の method の
一部だけ変更したい
まさか ruby -v < 2.0 ってことは
ないですよね…?
class Target
def hello
puts "Hello World!"
end
end
module Japan
def hello
puts "Hello Japan!"
super
end
end
Target.prepend Japan
Target.new.hello
#=> Hello Japan!
#=> Hello World!
10
14. やってみる
方針1:
同名のmethod を
define_method して、
その中で super を呼ぶ
$attrs = [:foo, :bar]
class MyClass
attr_writer *$attrs
end
module MyPatch
$attrs.each do |attr|
define_method("#{attr}=") do |val|
super(val)
puts 'this is patched!'
end
end
end
MyClass.prepend MyPatch
obj = MyClass.new
obj.foo = 'test'
14
15. やってみる
方針2:
module_eval して
同名 method を定義し、
その中で super を呼ぶ
$attrs = [:foo, :bar]
class MyClass
attr_writer *$attrs
end
module MyPatch
$attrs.each do |attr|
module_eval <<~EVAL, __FILE__, __LINE__ + 1
def #{attr}=(val)
super
puts "this is patched!"
end
EVAL
end
end
MyClass.prepend MyPatch
obj = MyClass.new
obj.foo = 'test'
15
※ module_eval == class_eval
18. super の引数
`block (2 levels) in <module:MyPatch>': implicit argument passing of super from method defined by
define_method() is not supported. Specify all arguments explicitly. (RuntimeError)
18
module MyPatch
$attrs.each do |attr|
define_method("#{attr}=") do |val|
super
puts 'this is patched!'
end
end
end
パッチ部分をこのように書くと
怒られてしまう
19. super の引数
`block (2 levels) in <module:MyPatch>': implicit argument passing of super
from method defined by define_method() is not supported. Specify all
arguments explicitly. (RuntimeError)
19
define_method で定義された method の中では
super に暗黙的に引数を渡すことはサポートされてないよ。
だから明示的にすべての引数を書いて渡してね。
ko1 氏曰く「どーしても実装出来なかったからです.誰か,実装方法を教えてください. (原文ママ)」とのこと。
http://www.atdot.net/~ko1/diary/200806.html#d14
20. Exception の例
20
module MyPatch
$attrs.each do |attr|
define_method("#{attr}=") do |val|
super(val)
raise 'ERROR!!!'
end
end
end
define_method の場合
Traceback (most recent call last):
1: from tmp.rb:17:in `<main>'
tmp.rb:10:in `block (2 levels) in <module:MyPatch>': ERROR!!! (RuntimeError)
21. Exception の例
21
module MyPatch
$attrs.each do |attr|
module_eval <<~EVAL, __FILE__, __LINE__ + 1
def #{attr}=(val)
super
raise 'ERROR!!!'
end
EVAL
end
end
module_eval の場合
Traceback (most recent call last):
1: from tmp.rb:19:in `<main>'
tmp.rb:11:in `foo=': ERROR!!! (RuntimeError)