1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

たまに見かけるattr_accessor(*Hoge::ATTRIBUTES)の仕組みについて調べてみた

Last updated at Posted at 2020-09-03

#はじめに
たまに下記のようなコードを見かけることがあります。
attr_accessor(*Hoge::ATTRIBUTES)
同僚のSさんと話している時に、この書き方でなぜ動くんだろうという話になり、調べてみたら面白かったのでまとめておこうと思います。

#先に結論から
・メソッド呼び出しをする時に引数に*をつけると配列を展開することができる
attr_accessorは複数個のSymbolを受け取ることができる
attr_accessor(*Hoge::ATTRIBUTES)とした時に、配列が展開されて複数個のSymbolが渡される

#よく見る使われ方
よく見るのは、あるクラスで属性の定数配列を定義して複数のクラスで使い回すというものだと思います。

・・。
文章だと何を言ってるか分かりませんね・・

実際に見た方が早いと思うので、早速コードを見てみましょう。

class Hoge
  ATTRIBUTES = %i[
    name
    age
  ].freeze

  attr_accessor(*Hoge::ATTRIBUTES)
end

class Huga
  attr_accessor(*Hoge::ATTRIBUTES)
end

この例の場合は、Hogeで属性の定数配列を定義してあげて、Hugaでも使いまわしています。
これにより、重複したコードを減らすことができます。便利!!

#仕組みについて
ここまでで、なんとなく使い方は分かっていただけたと思います。
ですが、なぜこれで動くかは謎のままです・・

実際にどのような仕組みになっているかを確かめるためにいろいろ試してみました。
##引数で渡す時に*をつけないでみる

class Hoge
  ATTRIBUTES = %i[
    name
    age
  ].freeze

  attr_accessor(*Hoge::ATTRIBUTES)
end

class Huga
  # Hogeの前の`*`を消してます
  attr_accessor(Hoge::ATTRIBUTES) # == attr_accessor([:name, :age])
end

上記を実行してみると以下のようなエラーが表示されました。
TypeError: [:name, :age] is not a symbol nor a string

エラーメッセージを見ると、symbolstringしか受け付けないよと言われてるみたいです。
リファレンスをみると、

[PARAM] name: String または Symbol を 1 つ以上指定します。

とあり、配列は渡すことができないためエラーになっていたようです。
ここで、重要なのはString または Symbol を 1 つ以上指定の部分です。

##そもそも*をつけたときの挙動って?
なんとなく、引数に*をつけるかつけないかで挙動が変わるというところまでは分かってきました。具体的にどう変わるのかを調べていると、こちらの記事を見つけ、*をつけることで配列を展開して渡すことができるということが分かりました。

実際に試してみます。

pry(main)> p([1,2])
[1, 2]
pry(main)> p(*[1,2])
1
2

確かに*をつけることで、配列が展開されて渡されてるようです。

##attr_accessor(*Hoge::ATTRIBUTES)の正体
ここまでで、既にお気づきの方もいるかもしれませんが、
attr_accessor(*Hoge::ATTRIBUTES)の部分は以下のようになります。

class Hoge
  ATTRIBUTES = %i[
    name
    age
  ].freeze

  attr_accessor(*Hoge::ATTRIBUTES) # == attr_accessor(:name, :age)
end

class Huga
  attr_accessor(*Hoge::ATTRIBUTES) # == attr_accessor(:name, :age)
end

つまり、*をつけることで配列が展開され、attr_accessorには複数個のSymbolが渡されていました。
先ほども触れましたが、リファレンスには

String または Symbol を 1 つ以上指定

とあり、複数個のSymbolを指定することが可能なので、問題なく設定できていたようです。

#終わりに
Rubyは知れば知るほど新しい発見があって、面白い言語だなーと改めて思いました!

#参考記事

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?