🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

1回答

2353閲覧

ArgumentError: wrong number of arguments (given A, expected B)のA,Bの引数の判断の理解がしたいです。

退会済みユーザー

退会済みユーザー

総合スコア0

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

1グッド

2クリップ

投稿2018/12/15 04:07

編集2018/12/15 04:26

情報(FW/ツールのバージョンなど)
言語 ruby
FW ruby on rails

(初心者でなおかつ独学の為、根本的な所から違う場合あります。すみません。
勘違いが多すぎて何処から突っ込めばいいかわからない場合は、とりあえず『エラーの解決方法』と『どう判断したか』のみで大丈夫です。)

前提・実現したいこと

rails test:models実行時に出てくる
ArgumentError: wrong number of arguments (given A, expected B)のA,Bの判断方法が知りたいです。
今までは
A=呼び出し側の引数の数 B=メソッド側の引数の数 
と認識して、このエラー関係は解決していました。
ですがテスト実行時の場合の「呼び出し側の引数」はどこなのかで迷ってしまいました。
なのでちゃんと(given A, expected B)のA,Bの判断方法を教えて頂きたいです。

迷った理由

今までの ArgumentError: wrong number of arguments (given A, expected B)
のエラーでは大体引数を呼びだすフォームなどがありました。そしてそれに関連するメソッドを探して引数の数を調整していました。
ですが今回実行したテストコードの内容は
アドレスのフォーマット関係を入れた配列とeach doメソッド
のみです。
(すぐ下にソースコードも書いています)

考えれば考えるほど疑問点が出てきて、自分の考えがまとまらなくなってきたので
話口調で申し訳ありませんが、今まで考えた事を書いてみました。
出来ればこれも踏まえて、解説して貰えるとありがたいです。

=============================
アドレスのフォーマット関係を入れた配列が呼び出し側の引数なのかな?

でも引数は処理する関数とかメソッドがあって初めて引数って扱うし、
変数のみで引数として扱えるのか?

each doが手前の変数を引数として扱うメソッドだよなあ・・・。
じゃあこれが呼び出しの引数で合ってる?

%w[user@example.com USER@foo.COM A_US-ER@foo.bar.org first.last@foo.jp alice+bob@baz.cn] = valid_addresses = valid_address(each doの仮引数)

て考えたら1個だしgiven側の数字と合ってる。

じゃあB側のメソッド側の引数ってどこだろう???

メールフォーマットの検証のテストって関係ありそうなファイルはデータのバリテーション関係のコードが書いてる
user.rbぐらいしかないし・・・。

一応このファイルも終わりは end だしメソッドとして扱えるのかな?

わからない・・・。
====================

エラーコード

Running:

.....E

Error:
UserTest#test_email_validation_should_accept_valid_addresses:
ArgumentError: wrong number of arguments (given 1, expected 2)
test/models/user_test.rb:41:in test' test/models/user_test.rb:41:in block in class:UserTest'

ソースコード

ファイル名 user_test.rb

test "email validation should accept valid addresses" do
valid_addresses = %w[user@example.com USER@foo.COM A_US-ER@foo.bar.org
first.last@foo.jp alice+bob@baz.cn]
valid_addresses.each do |valid_address|
@user.email = valid_address
assert @user.valid?, "#{valid_address.inspect} should be valid"
end

ファイル名 user.rb

class User < ApplicationRecord
VALID_EMAIL_REGEX = /\A[\w+-.]+@[a-z\d-.]+.[a-z]+\z/i
format: { with: VALID_EMAIL_REGEX }
end

DrqYuto👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

troch

2018/12/15 11:31

test/models/user_test.rb:41 はコードのどこに該当するのか、ご教授願えますでしょうか。
退会済みユーザー

退会済みユーザー

2018/12/15 15:48

すみません。分からないなりにでも何とかまとめようとしたのが色々裏目に出てしまった様です。 users_test.rbのコード全体を載せます。 require 'test_helper' class UserTest < ActiveSupport::TestCase def setup @user = User.new(name: "Example User", email: "user@example.com") end test "should be valid" do assert @user.valid? end test "name should be present" do @user.name = " " assert_not @user.valid? end test "email should be present" do @user.email = " " assert_not @user.valid? end test "name should not be too long" do @user.name = "a" * 51 assert_not @user.valid? end test "email should not be too long" do @user.email = "a" * 244 + "@example.com" assert_not @user.valid? end test "email validation should accept valid addresses" do valid_addresses = %w[user@example.com USER@foo.COM A_US-ER@foo.bar.org first.last@foo.jp alice+bob@baz.cn] valid_addresses.each do |valid_address| @user.email = valid_address assert @user.valid?, "#{valid_address.inspect} should be valid" end test "email addresses be unique" do duplicate_user = @user.dup.upcase @user.save assert_not duplicate_user.valid? end end end 41は下から7行目の test "email addresses be unique" do です。
troch

2018/12/16 00:04

共有ありがとうございます。回答を期待いたしましたので、お手すきの際にでもご確認くださいますと幸いです。
guest

回答1

0

ベストアンサー

レシーバとメソッド、引数について整理してみます。
例えば、メソッドに渡された2つの引数を表示するだけの以下のようなインスタンスメソッドがあったとします。

Ruby

1class User 2 def hoge(num1, num2) 3 p num1 4 p num2 5 end 6end 7 8@user = User.new 9@user.hoge(1, 2) 10#=> 1 11#=> 2

この場合、@user.hoge(1, 2)は以下のような意味を持つと思います。

レシーバメソッド引数
@userhoge1(第一引数), 2(第二引数)

レシーバ(Userクラスのインスタンスである@user)に定義されたメソッドhogeには、
def hoge(num1, num2)と定義してありますので、
このメソッドを呼び出す際に、引数が2つ必要になります。
つまりメソッドを呼び出す際に引数が1つだったり、3つだったりした場合はエラーになります。この際に出てくるのが、ArgumentErrorだと思います。

Ruby

1# 引数が2つ欲しいのに、1つしか渡されていないというエラーメッセージ 2@user.hoge(1) #=> wrong number of arguments (given 1, expected 2) (ArgumentError) 3 4# 引数が2つ欲しいのに、3つ渡されているというエラーメッセージ 5@user.hoge(1, 2, 3) #=> wrong number of arguments (given 3, expected 2) (ArgumentError)

ところで以下のようなメソッドの場合はどうなるでしょうか。

Ruby

1def hoge(num) 2 p num 3end 4 5# hoge(1) #=> 1

特定のクラスやモジュール内に定義されていないメソッドの場合、一見レシーバがないように見えます。
Rubyではクラスやモジュール構文に囲まれていない、一番外側の部分のことをトップレベルと呼びます。
トップレベルはObjectクラスのインスタンスになります。
また、Rubyではレシーバを省略した場合、暗黙的にselfがレシーバになります。
したがってこのメソッドを実行する時は、イメージとして以下のように考えて良いと思います。

レシーバメソッド引数
@objecthoge1(第一引数)

以下のようにすると、メソッドを実行しているオブジェクト名が確認できて、わかりやすいかと思います。

Ruby

1def hoge(num) 2 p self.class 3 p num 4end 5 6hoge(1) 7#=> Object 8#=> 1

テストコードについて

私の環境で実験してみて、パスできたコードを共有致しますので、
ご参考くださいますと幸いです。

Ruby

1# app/models/user.rb 2class User < ApplicationRecord 3 VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+.[a-z]+\z/i 4 validates :email, format: { with: VALID_EMAIL_REGEX } 5 validates :email, length: { maximum: 255 } 6 validates :name, length: { maximum: 50 } 7 validates :name, presence: true 8 validates :name, uniqueness: true 9end 10 11# test/models/user_test.rb 12require 'test_helper' 13 14class UserTest < ActiveSupport::TestCase 15 def setup 16 @user = User.new(name: "Example User", email: "user@example.com") 17 end 18 19 test "should be valid" do 20 assert @user.valid? 21 end 22 23 24 test "name should be present" do 25 @user.name = " " 26 assert_not @user.valid? 27 end 28 29 test "email should be present" do 30 @user.email = " " 31 assert_not @user.valid? 32 end 33 34 test "name should not be too long" do 35 @user.name = "a" * 51 36 assert_not @user.valid? 37 end 38 39 test "email should not be too long" do 40 @user.email = "a" * 244 + "@example.com" 41 assert_not @user.valid? 42 end 43 44 test "email validation should accept valid addresses" do 45 valid_addresses = %w[user@example.com USER@foo.COM A_US-ER@foo.bar.org 46 first.last@foo.jp alice+bob@baz.cn] 47 valid_addresses.each do |valid_address| 48 @user.email = valid_address 49 assert @user.valid?, "#{valid_address.inspect} should be valid" 50 end 51 end 52 53 test "email addresses be unique" do 54 duplicate_user = @user.dup 55 @user.save 56 assert_not duplicate_user.valid? 57 end 58end

環境:
Mac OS High Sierra 10.13.6
Rails 5.2.1
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]

投稿2018/12/16 00:03

troch

総合スコア349

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/12/16 01:27 編集

凄くわかりやすい解説をありがとうございます! すみませんもう一つ聞きたいのですが、今回質問したエラー文で ArgumentError: wrong number of arguments (given 1, expected 2) expected 2は何処から来たのでしょうか? given 1の方は今回はレシーバが省略されているので、ルール上selfが来て1になったとわかりました。 ですがexpected の対象のメソッドである valid_addresses.each do |valid_address| は valid_address の仮引数が1つ定義されてるので given 1, expected 1 で返されるのではと悩んでいます。 それとも今回のexpectedの対象メソッドはeach文では無かったのでしょうか?
troch

2018/12/16 06:32

| それとも今回のexpectedの対象メソッドはeach文では無かったのでしょうか? はい、そう思います。 エラーコードに ------------------------------------ Error: UserTest#test_email_validation_should_accept_valid_addresses: ArgumentError: wrong number of arguments (given 1, expected 2) test/models/user_test.rb:41:in test' test/models/user_test.rb:41:in block in <class:UserTest>' ------------------------------------ とありますが、 test "email validation should accept valid addresses" do のエラーにもかかわらず、実際にエラーを発生させている箇所が test "email addresses be unique" do という別のテストになっています。 これはtest "email validation should accept valid addresses" doのブロックをendでちゃんと閉じていないので、そのテストメソッドの中にtest "email addresses be unique" doが入ってしまっているためだと思います。 イメージとしては以下のように test "aaaa" do eachとか色々な処理とかアサーション test "bbbb" do アサーション end end という風に、test "aaaa"の中にネストする形で別のテストであるtest "bbbb"が入っているような状態だと思います。 testメソッドは、引数にテスト名とブロックの2つを要求します。 テスト名はともかく、ブロックがうまく渡せなかったので、 ArgumentErrorになったのだと思います。
退会済みユーザー

退会済みユーザー

2018/12/16 06:56

かなり初歩的なミスが原因だったんですね・・・。 言われるまで全く気づきませんでした。 追加の質問まで丁寧に答えて下さり本当にありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問