[RUBY] I investigated the mechanism of attr_accessor (* Hoge :: ATTRIBUTES) that I sometimes see

Introduction

Occasionally you will see the following code. attr_accessor(*Hoge::ATTRIBUTES) When I was talking to my colleague Mr. S, I was wondering why this writing method works, and when I looked it up, it was interesting, so I will summarize it.

From the conclusion first

-The array can be expanded by adding * to the argument when calling the method. ・ ʻAtr_accessorcan receive multiple Symbols ・ When ʻattr_accessor (* Hoge :: ATTRIBUTES)is set, the array is expanded and multiple Symbols are passed.

Frequently used

I think it's common to define a constant array of attributes in one class and reuse it in multiple classes.

・ ・. I don't know what you're saying in a sentence ...

I think it's faster to actually see it, so let's take a look at the code immediately.

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

  attr_accessor(*Hoge::ATTRIBUTES)
end

class Huga
  attr_accessor(*Hoge::ATTRIBUTES)
end

In the case of this example, Hoge defines a constant array of attributes and Huga also uses it. This will reduce duplicate code. Convenient! !!

About the mechanism

By now, I hope you have somehow understood how to use it. However, it remains a mystery why it works ...

I tried various things to see how it actually works.

Try not to add * when passing as an argument

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

  attr_accessor(*Hoge::ATTRIBUTES)
end

class Huga
  #In front of Hoge`*`Is erased
  attr_accessor(Hoge::ATTRIBUTES) # == attr_accessor([:name, :age])
end

When I tried the above, the following error was displayed. TypeError: [:name, :age] is not a symbol nor a string

Looking at the error message, it seems that it says that it only accepts symbol or string. Looking at Reference,

[PARAM] name: Specify one or more Strings or Symbols.

It seems that an error occurred because the array could not be passed. The important part here is ** Specify one or more String or Symbol **.

What is the behavior when * is added in the first place?

Somehow, I've come to understand that the behavior changes depending on whether or not \ * is added to the ** argument **. When investigating how it changes concretely, I found this article and expanded the array by adding \ * and passed it. I found that I could do it.

I will actually try it.

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

Certainly, by adding *, it seems that the array is expanded and passed.

The identity of attr_accessor (* Hoge :: ATTRIBUTES)

By now, you may have already noticed, The part of ʻattr_accessor (* Hoge :: ATTRIBUTES) `is as follows.

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

In other words, the array was expanded by adding *, and multiple Symbols were passed to ʻattr_accessor`. As I mentioned earlier, the Reference

Specify one or more String or Symbol

Since it is possible to specify multiple Symbols, it seems that it was possible to set it without problems.

At the end

The more I knew about Ruby, the more new discoveries I made, and I thought again that it was an interesting language!

Reference article

-Reference -Expand Array

Recommended Posts

I investigated the mechanism of attr_accessor (* Hoge :: ATTRIBUTES) that I sometimes see
I investigated the internal processing of Retrofit
[Swift] I investigated the variable expansion "\ ()" that realizes the mysterious function of Swift UI.
I investigated the super that I met with the devise controller
I investigated the enclosing instance.
I will explain the nesting of for statements that kill beginners
I tried to summarize the words that I often see in docker-compose.yml
The story of Collectors.groupingBy that I want to keep for posterity
[Ruby] See the essence of ArgumentError
I read the source of ArrayList I read
I read the source of Integer
This and that of the JDK
I read the source of Long
I read the source of Short
I read the source of Byte
I read the source of String
[Spring Boot] I investigated how to implement post-processing of the received request.