きり丸の技術日記

技術検証したり、資格等をここに残していきます。

Rubyでリフレクションしてメソッドを呼び出す(public_send)

Javaだと面倒だったリフレクションがRubyだと簡単にできてしまったので、メモします。

もっと詳しく書いている記事はありますので、私の記事はメモレベルです。

環境

  • GitHub Codespaces
  • Ruby
    • 3.0
  • RSpec

対応

準備

適当なクラスを用意します。今回の記事では、Reflectionクラスを自作します。

class Reflection
    def house(name: "")
        name == "" ? "house" : format("%s house", name)
    end

    def mouse(sum: 0)
        sum == 0 ? "mouse" : format("%s mouse", sum)
    end

    def nose()
        "nose" 
    end
end

使用方法

次の使い方をします。

# 使い方
# 第一パラメータはメソッド名(文字列でもSymbolでも可)
# 第二パラメータはメソッドに渡すパラメータ
obj.public_send(name, *args)

# 実際の使い方
Reflection.new.public_send("house")
Reflection.new.public_send(:house, "kirimaru")

発生しうるエラーは次のとおりです。

  • ArgumentError
    • リフレクションで指定したパラメータのメソッドが存在しない
  • NoMethodError
    • 指定したメソッド名が存在しない

テストコード

RSpecで動作確認したときのコードです。

require 'rails_helper'

RSpec.describe 'リフレクションクラスの確認', type: :model do
  let(:reflection) {Reflection.new}

  describe 'リフレクションの確認' do
    it "ArgumentError" do
        expect do
            reflection.public_send()
        end.to raise_error(ArgumentError)
    end 

    context 'パラメータなし' do
        it "houseを呼び出す" do
            expect(reflection.public_send("house")).to eq "house"
        end 

        it "mouseを呼び出す" do
            expect(reflection.public_send("mouse")).to eq "mouse"
        end 

        it "noseを呼び出す" do
            expect(reflection.public_send("nose")).to eq "nose"
        end 

        it "gorillaを呼び出す" do
            expect do
                reflection.public_send("gorilla")
            end.to raise_error(NoMethodError)
        end 
    end

    context 'パラメータあり' do
        it "houseを呼び出す" do
            expect(reflection.public_send(:house, name: "baki")).to eq "baki house"
        end 

        it "mouseを呼び出す" do
            expect(reflection.public_send("mouse", sum: 123)).to eq "123 mouse"
        end 

        it "noseを呼び出す" do
            expect do
                reflection.public_send("nose", name: "aaa")
            end.to raise_error(ArgumentError)
        end 

        it "gorillaを呼び出す" do
            expect do
                reflection.public_send("gorilla", name: "aaa")
            end.to raise_error(NoMethodError)
        end 
    end
  end
end    

ソースコード

終わりに

私は普段Java触っているので、Rubyはまだまだ駆け出しレベルです。

Javaだとリフレクションを使用するのに少々手間かかりましたが、Rubyだと簡単に使えてびっくりしました。動的型付き言語だとリフレクション機能とか容易に使えるようになっているんですかね。

まだまだRuby, Railsを本業レベルには持っていけていないので、知識をつけていきたいです。

今のところ、Rubyの感覚としてはギリギリまで制約を緩くしている言語で、単純に作る分には楽だが、保守すると大変な言語だという認識でいます。


この記事がお役に立ちましたら、各種SNSでのシェアや、今後も情報発信しますのでフォローよろしくお願いします。

参考情報

類似情報

f:id:nainaistar:20211026120519p:plain