Ruby Gold 練習問題3回目の振り返り
こんにちは。WEBエンジニアのホリさんです。
今回が第7回目の記事です。
概要
Ruby Goldの問題3回目を解いて、初めて知ったことについて共有させていただきます。
Module#refine
ブロック内のselfは無名モジュールになります。
以下のようにusing Rを定義すると、refine内のself.testが呼び出されると思いますが、selfは無名モジュールになるため、classのCのhelloが表示されます。
※usingはselfメソッド内では使えないです。
class C
def self.test
"hello"
end
end
module R
refine C do
def self.test
"hello mike"
end
end
end
using R
puts C.m1
=> "hello"
inspect
オブジェクトを人間が読める形式に変換した文字列。
以下のようにBar.new.inspectで、オブジェクト情報と同様の結果は
Bar.newでも返すことが可能です。
class Bar
def initialize
@bar = 1
end
end
Bar.new.inspect
=> "#<Bar:0x0300c868 @bar=1>"
Object.singleton_class
特異クラスを取得することができる。
特異クラスでselfを参照するとレシーバのオブジェクトが取得できます。
class C
def self._singleton
class << C
self
end
end
end
p C._singleton
=> #<Class:C>
Fiber#resume
実行するとFiber.yieldが最後に実行された行から再開するか、Fiber.newに指定したブロックの最初の評価を行います。
f = Fiber.new do |total|
Fiber.yield total + 10
end
p f.resume(100) + f.resume(5)
=> 115
yield
メソッド内部でyieldを使いブロックの実行結果を呼び出すことができる
def foo(a)
a + yield
end
puts foo("Taro") { "1" }
=> Taro1
Proc
Procメソッドはブロックを持ち運びできるようにしたオブジェクトで、callまたは[]で呼び出すことが可能です。
test = Proc.new { |n|
n * 3
}
puts test[2] * 2
=> 12
破壊的メソッドの場合は以下の通りエラーになる
a2 = "foo".freeze
a2.replace("bar") # can't modify frozen String (FrozenError)
Singleton
Singletonモジュールをインクルードすると、クラスメソッドinstanceを定義します。
オブジェクトIDがすべて同じ値を返していることから1つのインスタンスしか返せないことが分かります。
require 'singleton'
class Test
include Singleton
def foo
'test'
end
end
p Test.instance.foo
p Test.instance.__id__ # 700333300
p Test.instance.__id__ # 700333300
=>
"Hi, good morning!"
method_missing
method_missingは、継承先でもメソッドが見つからなかった場合に、呼び出されます。
モージュルにもmethod_missingがある場合でも、呼び出し元の今回だとBインスタンスのmethod_missingが優先的に呼ばれます。
module M
def method_missing(id, *args)
puts "C#method_missing"
end
end
class A
include M
def method_missing(id, *args)
puts "A#method_missing"
end
end
class B < A
def method_missing(id, *args)
puts "B#method_missing"
end
end
obj = B.new
obj.test_method
=> "B#method_missing"
Module.nesting
ネストの状態を表示します。
ネスト状態はすべて表示されますがネストが内側から順に表示されます。
module Test1
module Test2
p Module.nesting
end
end
=> [Test1::Test2, Test1]
selfのスーパークラス
selfはnewされたクラスのオブジェクトを指します。
スーパークラスでselfを参照したとしても、呼び出ししたクラスのnewのオブジェクトになります。
class Test1
def initialize
p self.class
end
end
class Test2 < Test1
end
Test2.new
=> Test2
beginのRuntimeError
RuntimeErrorはraiseの引数がない場合に発生する
begin
raise
rescue => e
puts e.class
end
superの引数
superを定義すると現在のメソッドと同じ引数が引き継がれます。
引数を渡さずにオーバーライドしたメソッドを呼び出す際はsuper()と指定する必要があります。
class Test1
def initialize
puts "Test1"
end
end
class Test2 < Test1
def initialize(*args)
super()
puts "Test2"
end
end
Test2.new(1,2,3,4,5)
参考URL
Discussion