😸

ActionController::Parameters#requireを自作する

2023/10/13に公開

概要

https://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-require を参考に、ActionController::Parameters#requireを自作します。

実装

seitou.rb
# frozen_string_literal: true

class Seitou
  class ParameterMissing < StandardError; end

  attr_reader :parameters

  def initialize(parameters = {})
    @parameters = parameters
  end

  def require(key)
    return key.map { |k| require(k) } if key.is_a?(Array)

    return_parameter = @parameters[key]

    raise ParameterMissing if [nil, "\t"].include?(return_parameter) || return_parameter.empty?

    self.class.new(return_parameter)
  end

  def ==(other)
    @parameters == other.parameters
  end
end

単体テスト

seitou_spec.rb
# frozen_string_literal: true

require_relative '../seitou'

RSpec.describe Seitou do
  describe '#require' do
    context 'when pass single key' do
      it {
        expect(described_class.new(person: { name: 'Francesco' }).require(:person)).to eq described_class.new({ name: 'Francesco' })
      }
    end

    context 'when not pass single key' do
      it {
        expect do
          described_class.new(person: { name: 'Francesco' }).require(:name)
        end.to raise_error(described_class::ParameterMissing)
      }
    end

    context 'when parameter is nothing' do
      it {
        expect { described_class.new.require(:person) }.to raise_error(described_class::ParameterMissing)
      }
    end

    context 'when value is nil' do
      it {
        expect { described_class.new(person: nil).require(:person) }.to raise_error(described_class::ParameterMissing)
      }
    end

    context 'when value is \t' do
      it {
        expect { described_class.new(person: "\t").require(:person) }.to raise_error(described_class::ParameterMissing)
      }
    end

    context 'when value is {}' do
      it {
        expect { described_class.new(person: {}).require(:person) }.to raise_error(described_class::ParameterMissing)
      }
    end

    context 'when given an array of keys' do
      it {
        expect(described_class.new(user: { name: :sidehara }, profile: { name: :sidehara }).require(%i[user profile]))
          .to eq [described_class.new(name: :sidehara), described_class.new(name: :sidehara)]
      }
    end

    context 'when fetch terminal values' do
      it {
        expect(described_class.new(person: { name: 'Francesco' }).require(:person).require(:name).parameters).to eq 'Francesco'
      }
    end
  end
end

感想

次の点について実装を省いています。

  • オブジェクトの存在確認
  • 末端の値を取得する場合の挙動

次回は、この点について忠実に実装しようかと考えています。

Discussion