[RAILS] A story about a very useful Ruby Struct class

Trigger

I participated in Tochigi Ruby Conference 09 remotely, and the LT I saw there I can't ask you anymore! How to use Struct and future possibilities I learned about the Struct class for the first time. What made this so convenient! So I decided to write an article as an enlightenment. I've been touching Ruby for 10 years, but I still have discoveries. Nice! ~~ Just not learning ?? ~~

What is a Struct class?

Ruby 2.7.0 Reference Manual Struct Class

Structure class. Struct.new will generate a new subclass of this class. Individual structs are generated from subclasses using Struct.new. Each structure subclass defines access methods for the members of the structure.

If you explain with your own interpretation

A convenient struct class that makes it easy to create objects with properties (and methods) of any name

How to use

#Generate a subclass of Struct with 4 parameters
BreakwaterClub = Struct.new(:id, :name, :grade, :age)
#Create an instance of the generated subclass
bucho = BreakwaterClub.new(1, 'kuroiwa', 3)

#The created instance has a parameter name accessor method
p bucho.name
#=> "kuroiwa"
bucho.age = 17

#The age that was not set at the time of initialization is set
p bucho
#=>#<struct BreakwaterClub id=1, name="kuroiwa", grade=3, age=17>
# keyword_init:By specifying true, keyword arguments can be passed at initialization.
#Keyword arguments are easier to understand, but the number of characters is large, so you can choose which one to use.
BreakwaterClub = Struct.new(:id, :name, :grade, :age, keyword_init: true)

hina = BreakwaterClub.new(name: 'tsurugi', grade: 1)

What makes you happy compared to Hash and arrays?

Arrays and Hash that are often used when writing small processes in Ruby. I also use it when organizing while outputting processing that I haven't been able to organize in my head yet.

#Array
bucho = [1, 'kuroiwa', 3]
bucho[0] #=>1
bucho[1] #=>'kuroiwa'
bucho[2] #=>3

# Hash
bucho = {id: 1, name: 'kuroiwa', grade: 3}
bucho[:id]    #=>1
bucho[:name]  #=>'kuroiwa'
bucho[:grade] #=>3

An error will occur if you specify an undefined parameter.

I'm grateful for this because when I define it in Hash, I don't notice it even though it's Typo, and there is something like "Why doesn't it work ... it should match ...".

senpai = BreakwaterClub.new(name: 'ohno', grade: 2)
senpai[:height] #=>NameError (no member 'height' in struct)
senpai.height   #=>NoMethodError
#You can refer to it even if you do not define it as Hash
senpai[:height] #=>nil

Struct class is accessible and type conversion is possible like array and Hash

In other words, you can think of it as upward compatible.

natsumi = BreakwaterClub.new(name: 'hodaka', grade: 1)
#It can be accessed like an array. The order of indexes is`Struct.new`In the order defined in
natsumi[0] #=>nil
natsumi[1] #=>'hodaka'
#Can be accessed like Hash
natsumi[:id]    #=>nil
natsumi[:grade] #=>1
#Can be converted to an array or a Hash
natsumi.to_a #=>[nil, "hodaka", 1, nil]
natsumi.to_h #=>{:id=>nil, :name=>"hodaka", :grade=>1, :age=>nil}

Method definition is possible

Method can be defined by specifying a block at the time of Struct.new

BreakwaterClub = Struct.new(:id, :name, :grade, :age, keyword_init: true) do
  def gakunen
    "#{grade}Grade"
  end
end
# `Struct.new`It is also possible to create a subclass that inherits the Struct class generated in
Class BreakwaterClub < Struct.new(:id, :name, :grade, :age, keyword_init: true)
  def gakunen
    "#{grade}Grade"
  end
end

It seems deprecated to define a subclass that inherits the Struct class itself. I still don't understand a little well here. Since the inheritance source Struct class is a dynamically generated anonymous class, I think it is due to indefiniteness.

reference:

-What's wrong with inheriting from an anonymous class (Ruby) -[Fail when loading more than once on irb](https://ja.stackoverflow.com/questions/11734/irb%e3%81%a72%e5%9b%9e%e4%bb%a5%e4%b8 % 8aload% e3% 81% 99% e3% 82% 8b% e3% 81% a8% e5% a4% b1% e6% 95% 97% e3% 81% 99% e3% 82% 8b) --Document quote below

If you specify a block

If a block is specified in Struct.new, the block is evaluated with the defined Struct as the context. The defined Struct is also passed to the block parameter.

Customer = Struct.new(:name, :address) do def greeting "Hello #{name}!" end end Customer.new("Dave", "123 Main").greeting # => "Hello Dave!"

 > This method is recommended when customizing Struct. This is because anonymous classes may no longer be used when customizing by creating subclasses of anonymous classes.
> [SEE_ALSO] [Class.new](https://docs.ruby-lang.org/ja/latest/method/Class/s/new.html)

## Summary
 The Struct class is convenient. I think it's a Ruby-like class with a wide variety of description methods.

### Struct class summary
 --Structure class that can define arbitrary parameters and methods
 --Accessible like an array or Hash, and type conversion is also possible
 --An error will occur if the parameter name is not specified at the time of initialization (it will be `nil` if it is Hash).

### When is it convenient to use?
 ――When it's done with an array or Hash, but it's better to define it as a Class
 ――When you want to write a little code and do verification
 --When you don't have enough ideas to define a Class
 ――When you want to test via API that you can't hit with it

 I haven't tried it yet, but I felt that it could be used even when testing with Rails Rspec.
 You can feel free to try irb, so if you are interested, please try it.




Recommended Posts

A story about a very useful Ruby Struct class
A murmur about the utility class
A story about converting character codes from UTF-8 to Shift-jis in Ruby
A story about an arithmetic overflow that you shouldn't encounter in Ruby
A story about creating a library that operates next-generation sequencer data with Ruby ruby-htslib
A story about Java 11 support for Web services
A story about the JDK in the Java 11 era
A story about Apache Wicket and atomic design
A story about making a Builder that inherits the Builder
A story about trying to operate JAVA File
A story about a new engineer reading a passion programmer
About Ruby symbols
About class inheritance.
About Ruby Hashes
Class in Ruby
About Ruby arrays
About Ruby inheritance
About ruby block
About Java class
About Ruby Hashes
About Ruby Symbols
About Ruby variables
About Ruby methods
[PHP] A story about outputting PDF with TCPDF + FPDI
What is the difference between a class and a struct? ?? ??
[Ruby / Rails] Set a unique (unique) value in the class
A story about trying to get along with Mockito
A story about trying hard to decompile JAR files
A story about reducing memory consumption to 1/100 with find_in_batches
A story about introducing Evolutions into the Play Framework
A story about developing ROS called rosjava with java
A story about starting a Java-related book club for newcomers
A story about making catkin_make of rosjava compatible offline
The story of introducing a very Rails-like serverless framework "Ruby on Jets" into the production environment