こんにちは。ikedaです。
以前ご紹介したgem Faradayの実装例で、blockを解説することがあったのですが
blockを利用した書き方について触れていなかったので書いていきたいと思います。完全に小ネタです。
blockの書き方ですが、引数にblock宣言することと、yieldを利用する2通りあります。
ブロックを引数で持つ場合
class Hoge
def initialize(&block)
block.call
end
end
Hoge.new do
p "Hello"
end
# => "Hello"
# => #<Hoge:0x007ff4f480cca8>
Hoge.new { p "Hello" } # 上記と同じ意味です。
# => "Hello"
# => #<Hoge:0x007ff4f480cca8>
Hoge.new # ブロックを渡していないのでエラー
# => NoMethodError: undefined method `call' for nil:NilClass
引数として持たない場合
class Fuga
def initialize()
yield(self) if block_given?
# block_given?でブロックが与えられているか調べる
end
end
Fuga.new do |fuga|
fuga.class
end
# => #<Fuga:0x007ff4f4160c60>
Fuga.new { self.class }
# => #<Fuga:0x007ff50b29e340>
Fuga.new
# => #<Fuga:0x007ff4f4153c18>
上記で書いている通りyieldにインスタンスを引数に渡して返すこともできるので次のような書き方ができます。
*block_given?について詳しくはこちらへ
ブロック利用例
class Person
attr_accessor :name, :age, :job
def initialize(&block)
yield(self) if block_given?
end
end
person = Person.new do |per|
per.name = "ikeda"
per.age = 99
per.job = "engineer"
end
puts person.name
# => "ikeda"
puts person.age
# => 99
puts person.job
# => "engineer"
selfが自分自身を指しているのでインスタンスを返却してブロック内で値をセットしています。
gem Faradayでも使われていて、そちらではstructと合わせて実装されていますね。
[おまけ]instance_evalを利用したblockの記述
class Person
attr_accessor :name
def intialize()
yield(self) if block_given?
end
private
def fuga
puts "Hi, I'm #{name.nil? ? "piyo" : self.name}."
end
end
Person.new.instance_eval { fuga }
# => Hi, I'm piyo.
Person.new.instance_eval do
fuga
end # こちらも同じ意味です。
# => Hi, I'm piyo.
Person.new do |per|
per.name = "neko"
per.instance_eval { fuga }
end
# => Hi, I'm neko.
以上です。