n個の項目の配列に一致するパターン

概要

Rails でモデルをテストしていますが、関連付けの 1 つに n 個の項目があることを主張したいと思います。私は、assert_pattern matcher がそれを行うための非常に良い方法であることを発見しました。

assert_pattern do
  author.books.to_a =>
    [Book,
    Book,
    Book,
    Book,
    Book]
end

ただし、そのような項目の大きなリストがあると、読むのが難しい場合があることもわかりました。 Ruby で通常行う方法で配列を拡張してみました。

assert_pattern do
  author.books.to_a => [Book]*5
end

ただし、パターン マッチャー内では、これは構文エラーになります。

test/models/book_test.rb:39: syntax error, unexpected '*', expecting `end' or dummy end (SyntaxError)
    author.books.to_a => [Book]*5
                               ^

長さに応じたパターンを作成する簡潔な方法はありますか?

解決策

私はそうは思わない。 ^(expression) を使用してパターン内で任意の式を使用できますが、マッチングはまったく異なります。

リテラル [pattern, …, *variable] 構文を使用する場合、例:

ary => [Foo, Bar, Baz]

Ruby はまず ary の長さが 3 であることを確認し、次に次のように各要素を個別に照合します。

クラスまたはモジュールの場合、これは is_a? と同等です。チェック。

上の例では、[Foo, Bar, Baz] は実際の配列ではないことに注意してください。パターン マッチングでは配列のような構文を使用するだけです。この構文内では、* をワイルドカードとして使用したり、値を変数にバインドしたりすることもできます。

^(式) 構文を使用する場合、例:

ary => ^([Foo, Bar, Baz])

Ruby はその式の結果を単一の値として扱い、チェックを 1 つだけ実行します。

=== を介して両方の配列を比較することは、各要素を個別にチェックすることと同等ではないため、あなたの場合は機能しないようです。

[Book, Book] === [Book.new, Book.new] #=> false

カスタム === 動作を持つ配列またはマッチャー オブジェクトを構築できます。ただし、その時点では、パターン マッチングの代わりに単純なアサーションを使用する方が簡単でしょう。例:

assert do
  author.books.count == 5 && author.books.to_a.all?(Book)
end

(多態性の関連付けや STI を扱っている場合を除き、型チェックは不要になる可能性があります)