LoginSignup
9
9

More than 5 years have passed since last update.

Proc#parameters を利用した Hash の拡張が便利

Last updated at Posted at 2015-12-18

概要

Little Things: Introspecting Block Parameters という記事で紹介されていた Hash の拡張がエレガントでかつ便利だったのでご紹介します。

利用方法

まず、以下のコードを実行して Hash#using を実装します。
(少し改変していますが、上のリンクに記載されているコードと内容は同じです。)

class Hash
  include(
    Module.new do
      def using(&block)
        values = block.parameters.map { |_, name| self[name] }

        block.call(*values)
      end
    end
  )
end

次に、実際に Hash#using を使ったコードを実行してみます。

students = [{ name: 'ヒロ', from: '山形県', room: 101 }, { name: '沙英', room: 102 }]

students.each do |student|
  description = student.using do |name, from, room|
    "#{name}の出身地は#{from || '不明'}です。ひだまり荘の #{room} 号室に住んでいます。"
  end

  puts(description)
end
ヒロの出身地は山形県です。ひだまり荘の 101 号室に住んでいます。
沙英の出身地は不明です。ひだまり荘の 102 号室に住んでいます。

このように Hash が持つ情報を使った処理をサクッと実装したい時に使えると思います。

普段、例えば Struct を使って、

Student = Struct.new(:name, :from, :room) do
  def description
    "#{name}の出身地は#{from || '不明'}です。ひだまり荘の #{room} 号室に住んでいます。"
  end
end

students = [{ name: 'ヒロ', from: '山形県', room: 101 }, { name: '沙英', room: 102 }]

students.each do |student|
  arguments = student.values_at(*Student.members) # ["ヒロ", "山形県", 101] or ["沙英", nil, 102]
  description = Student.new(*arguments).description

  puts(description)
end

と書いていたのを Hash だけで書けるようになるので便利だなと感じました。

Proc#parameters について

Proc#parameters は Proc オブジェクトの引数を返すメソッドです。

procedure = lambda { |yuno, miyako = '宮ちゃん', *others| }
procedure.parameters #=> [[:req, :yuno], [:opt, :miyako], [:rest, :others]]

このように引数名を取得できるので、上で紹介した手法は引数名を Hash の key と一致させることで実現していたのですね。この引数名をうまく使ったトリックが目から鱗でエレガントに感じました。

参考

9
9
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9