こんにちは。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.
以上です。