基本的なRubyの文法

## はじめに

ドットインストールにてRubyを勉強しているのですが、写経だけだとなかなか頭に入らないので、学んだことや疑問に思って調べたこと、自分で考えたことなどを書いていきたいと思います。
丸写ししない、間違ったことを書かないよう気をつけましたが、何かご指摘があれば教えていただけると幸いです。

## 標準出力

```ruby
print "hello" # helloと表示される
puts "hello"  # hello + 改行
p "hello"     # "hello"のように""も表示されオブジェクトの種類が分かりやすいように表示される
```

putsはput stringの略。pはデバッグによく使われ、以下のような場合に役立つ。

```ruby
a = [1, 3]
b = ["1", "3"]

puts a # 1 3
puts b # 1 3

p a # [1, 3]
p b # ["1", "3"]
```

## 変数、定数

```ruby
fruit = "apple" # 変数
PI = 3.141592 # 定数
```

変数名は英小文字かアンダースコア (_)から始める。
定数名は慣習的に全て英大文字で書く。

## 数値

```ruby
# 四則演算
p 5 + 3 # 8
p 5 - 3 # 2
p 5 * 3 # 15
p 5 / 3 # 1 
p 5.0 / 3 # 1.6666666666666667

## 分数
p Rational(3, 5) + Rational(3, 7) # (36/35)
p 3/5r + 3/7r                     # (36/35)

# その他
p 3**3 # 9 べき乗
p 11 % 4 # 3 剰余

# 数値に関するメソッド
p 9.4.round # 9 四捨五入
p 9.5.round # 10 四捨五入
p 9.6.floor # 9 小数点以下切り捨て
p 9.6.ceil # 10 小数点以下切り上げ
```

## 文字列

```ruby
# 改行文字列を埋め込みたい、式展開を使いたい場合はダブルクォーテーション ("")を使う
puts "hoge hoge" # hoge hoge

puts "hoge /"hoge/" hoge" # hoge "hoge" hoge

a = "fuga"
puts "hoge #{a} hoge" # hoge fuga hoge

# 改行文字列、式展開を使わない場合シングルクォーテーションでも良い
puts 'hoge hoge'

# 文字連結 (+)
puts "hoge" + "fuga" # hogefuga

# 文字列の繰り返し (*)
puts "hoge" * 10 # hogehogehogehogehogehogehogehogehogehoge
```

英語の文字列を出力しようとする際にシングルクォーテーションだと「don’t」などアポストロフィとかぶってしまうため、基本的にはダブルクォーテーションを使った方が良さそうだと思いました。

## !、?がついたメソッド

```ruby
# !は破壊的なメソッドであることを示す
a = "hoge"
puts a.reverse # egoh
puts a # hoge

puts a.reverse! # egoh
puts a #egoh

# ?は真偽値を返すメソッドであることを示す
b = "fuga"
b.empty? # false

c = ""
c.empty? # true
```

下記記事にあるように、

> `"!"が付く・付かない＝破壊的・非破壊的`ではなく、Rubyにおける`!`はあくまでも`!`のつかないメソッドよりも「危険」であることを示す目印のようなものとなります。
> 

みたいなので注意です。私はこれを知らなかったので、記事を書くためにいろいろ調べてるうちに気づけてよかったです。

[【Ruby】「!」が付かない破壊的メソッドまとめ](https://qiita.com/k-penguin-sato/items/ab2267ca99d5aedcc40a)

## 配列

```ruby
fruits = ["apple", "watermelon", "kiwi"]

p fruits[0] # "apple"
p fruits[-1] # "kiwi"
p fruits[1..2] # ["watermelon", "kiwi"]
p fruits[1..] # ["watermelon", "kiwi"]

fruits[1..2] = ["muscat", "melon"]
p fruits # ["apple", "muscat", "melon"]

# 要素の追加
p fruits.push("banana") # ["apple", "muscat", "melon" "banana"]
p fruits << "muscat" # ["apple", "muscat", "melon" "banana", "muscat"]

# 要素の挿入
p fruits.insert(1, "orange") # ["apple", "orange", "muscat", "melon" "banana", "muscat"]
# 先頭に要素を挿入
p fruits.unshift("mango") # ["mango", "apple", "orange", "muscat", "melon" "banana", "muscat"]
```

## ハッシュ

```ruby
ages = { "freddie" => 45, "edgar" => 40, "michael" => 70 }
ages = { "freddie": 45, "edgar": 40, "michael": 70 } # 上記と同じ意味

p ages[:freddie] # 45
p ages[:edgar] #40

ages[:michael] = 50
p ages[:michael] # 50
```

## 条件分岐

```ruby
# if文
age = 40

if age > 100
	puts "100より上"
elsif age > 60
	puts "60より上、100以下"
else
	puts "60以下"
end

# 以下のようにも書ける
puts "100より上" if age > 100

# case文
fruit = "banana"

case fruit
when "kiwi", "melon"
  puts "the color is green"
when "grape"
	puts "the color is blue"
when "banana", "pineapple"
	puts "the color is yellow"
end
```

## 繰り返し

```ruby
# for文
for i in 0..4 do
	puts "#{i}: hoge"
end

# eachメソッド
(0..4).each do |i|
	puts "#{i}: hoge"
end

["orange", "banana", "grape"].each do |fruits|
	puts fruits
end

{ "freddie" => 45, "edgar" => 40, "michael" => 50 }.each do |name, age|
	puts "#{name}: #{age}"
end

# while文
i = 0
while i < 5 do
	puts "#{i}: hoge"
	i += 1
end

# timesメソッド
5.times do |i|
	puts "#{i}: hoge"
end

# loop文
i = 0
loop do
  if i == 10
    break # loop文を終了させる
  end
  
  puts i
  i += 1
end
```

iをインクリメントさせる際、他言語でよくあるi++という書き方がRubyではできないことに注意。また、for文、while文のdoは省略可能。

## クラス

```ruby
class User

  @@num_user = 0 # クラス変数

  VERSION = 1.1 # クラス定数

  attr_accessor :first_name, :last_name # setterとgetterを合わせたもの
  # attr_reader :first_name, :last_name # getterだけ使いたい場合はattr_readerを使う

  def initialize(first_name, last_name)
    @@num_user += 1
    @first_name = first_name
    @last_name = last_name
  end

  def greet # インスタンスメソッド
    puts "Welcome, #{getName}!"
  end

  def self.info # クラスメソッド
    puts "VERSION#{VERSION}: #{@@num_user} instance(s)."
  end

  private # プライベートメソッド。クラス内でのみ使用できる

    def getName
      return "#{@first_name}_#{@last_name}"
    end
end

freddie = User.new("Freddie", "Mercury")
freddie.greet # Welcome, Freddie_Mercury!
michael = User.new("Michael", "Jackson")
michael.greet # Welcome, Michael_Jackson!

puts User::VERSION # 1.1
User.info    # VERSION1.1: 2 instance(s).

# attr_accessorを設定した場合
puts freddie.first_name # Freddie
freddie.first_name = "Michael"
puts freddie.first_name # Michael

# attr_readerを設定した場合
# setterが設定されていないため上記のfreddie.first_name = "Michael"の箇所でエラー発生

# attr_accessor, attr_readerどちらも設定しなかった場合
# getterがないため、上記freddie.first_nameでエラー
# setterがないため、上記freddie.first_name = "Michael"でエラー
```

## クラスの継承

```ruby
class AdminUser < User
	def sayBye
		puts "Good bye, #{getName}"
	end

	# オーバーライド
	def greet
		puts "Hello, #{getName}!"
	end
end

cyndi = AdminUser.new("Cyndi", "Lauper")
cyndi.sayBye # Good bye, Cyndi_Lauper
cyndi.greet # Hello, Cyndi_Lauper!
```

## 参考記事

以下の記事を参考にさせていただきました。

- [Ruby入門](https://dotinstall.com/lessons/basic_ruby_v3)

- [シングルクォーテーションとダブルクォーテーションの違い（Rubyの文字列）](https://qiita.com/ryosuketter/items/ddad508cb0124e4fe378)
- [【Ruby】「!」が付かない破壊的メソッドまとめ](https://qiita.com/k-penguin-sato/items/ab2267ca99d5aedcc40a)