Ruby 基礎

## 目次
1. [基礎文法](#1基礎文法)
1. [演算子](#2演算子)
1. [データ型](#3データ型)
1. [制御文](#4制御文)
1. [クラスとモジュール](#5クラスとモジュール)
1. [ライブラリ](#6ライブラリ)

## 1.基礎文法

### 基本的なルール
* すべてオブジェクト(文字列や配列、数値やnilなど）
* 改行が文の区切り、セミコロンで明示的に文の区切りをすることも可能
* バックスラッシュ(\\)を使うと、文がまだ続くことを明示できる

### 変数

* 「変数名 = 値」の形式で変数宣言ができる
* 変数名だけ宣言するとエラーになるため、何かしらの値を代入する必要がある

```ruby
# ローカル変数
# 先頭を英子文字か「_」にする
hoge = "hoge"

# インスタンス変数
# 先頭を「@」にする
@fuga = "fuga"

# クラス変数
# 先頭を「@@」にする
class Foo
  @@foo = 1
end

# グローバル変数
# 先頭を「$」にする
$bar = 999
```

### 定数

```ruby
# 先頭を英大文字にする
PIYO = "piyo"
```

### 疑似変数

* 特殊な変数のこと

|変数名|説明|
|---|---|
|self|メソッドの実行主体|
|nil|nil値|
|true|真偽値の真|
|false|真偽値の偽|
|\_\_FILE\_\_|ソースファイル名|
|\_\_LINE\_\_|ソースファイル中の行番号|
|\_\_ENCODING\_\_|ソースファイルのスクリプトエンコーディング|

### コメント

```ruby
# 単行コメント
# 「#」をつけることでコメント化
hoge = "hoge" # コメント

# 複数行コメント
# =begin から =endでコメント化
=begin
コメント1
コメント2
コメント3
=end

# 記述以降をすべてコメント化
# __END__ の記述以降は全てコメントになる
hoge = "hoge"
__END__
以降コメント化
コメント1
コメント2
コメント3

# マジックコメント
# ソースコードの先頭に書く「おまじない」のようなもの
# Rubyでは主にソースコードの文字を指定するために使用する
# encoding: utf-8
# -*- coding: utf-8 -*- 
# vim:set fileencoding=utf-8:
```

### 関数

* 関数名は英小文字か「_」で始まる必要がある
* 関数内で最後に評価した式が戻り値となる(returnは必要なし)
* returnを明示した場合は、その時点で呼び出し元に戻り値を返して処理が終了となる
* 引数がない場合は、()は省略しても良い
* <strong>慣例として、破壊的操作をするメソッドには文末に「!」をつける</strong>
* <strong>慣例として、真偽値を返すメソッドには文末に「?」をつける</strong>

```ruby
# 普通の関数
def sum(a, b)
  a + b
end

# デフォルト引数
# この場合、bの値を指定しない場合はb=1になる
def add(a,b = 1)
  a + b
end

# ()省略
def hello
  puts "hello"
end

# 可変長引数
# *cが可変長引数
def test(a, b, *c)
  # メソッドの処理
end
```

### 標準出力

```ruby
# puts
# 引数に与えた値を出力し、nilを返す
# 出力の後に改行される
puts "hoge"

# print
# 引数に与えた値を出力し、nilを返す
# 出力の後に改行なし
print "hoge"

# p
# 引数に与えた値を詳しく出力し、引数の値を返す
# 出力の後に改行される
p "hoge"
```

## 2.演算子

### 算術演算子

|演算子|説明|例|
|---|---|---|
|+|加算|1 + 2 (結果)3|
|-|減算|10 - 5 (結果)5|
|*|乗算|10 * 2 (結果)20|
|**|累乗|2 ** 3 (結果)8|
|/|除算|10 / 3 (結果)3|
|%|剰余|10 % 3 (結果)1|

### 比較演算子

|演算子|説明|
|---|---|
|==|等しい|
|!=|等しくない|
|>|より大きい|
|>=|以上|
|<|より小さい|
|<=|以下|

### 論理演算子

|演算子|説明|
|---|---|
|&&|AND演算子|
|｜｜|OR演算子|
|!|NOT演算子|

### ビット演算子

|演算子|説明|
|---|---|
|&|ビットAMD|
|｜|ビットOR|
|^|ビットXOR|
|~|ビット反転|
|<<|左シフト|
|>>|右シフト|

### 三項演算(条件演算)

**条件 ? 式1 : 式2**

trueなら式1
falseなら式2

### 文字列演算子

|演算子|説明|
|---|---|
|+|連結|
|<<|連結と代入|
|*|n回の繰り返し|

```ruby
# 連結
puts "aa" + "bb"  # aabb

# 連結と代入
s1 = "aa"
s2 = "bb"
puts s1 << s2 # aabb
puts s1 # aabb

# n回の繰り返し 
puts  "a" * 4 # aaaa
```

## 3.データ型

### 数値
* NumericからInteger, Floatにそれぞれクラスが分かれる
* 数値計算は他言語同様

|クラス|説明|
|---|---|
|Numeric|数値の親クラス|
|Integer|整数の親クラス|
|Bignum(Integerから派生)|大きな整数|
|Fixnum(INtegerから派生)|整数|
|Float|浮動小数点数|

※整数は値のサイズによって自動的にBignum, Fixnumへの変換が行われる

### 文字列

* Stringクラス
* ダブルクォート、シングルクォートで括った値が文字列となる
* ダブルクォートで囲んだ場合はエスケープシーケンスを解釈する
* ダブルクォートで囲った文字列には式の埋め込みが可能
* %記法で文字列を作ることも可能(クオートをエスケープする必要がない)
* 複数行はヒアドキュメント(行指向文字列リテラル)を使うと良い

```ruby
# シングルクォート
s1 = 'aabb'

# ダブルクォート
# 改行(エスケープシーケンス)や式の埋め込みが可能
s2 = "aa\nbb"

# 式の埋め込み
# #{式}という記述で埋め込みが可能
s3 = "#{1 + 1}"

#--------------------------------------------------

# パーセント記法
# %q! !(シングルクォートと同じ処理)
s1 = %q!aabb!

# %Q! !(ダブルクォートと同じ処理)
s2 = %Q!aa\nbb!

# %! ! (同じくダブルクォートと同じ処理)
s3 = %!#{1 + 1}!

#--------------------------------------------------

# ヒアドキュメント
# 書き方
<<識別子
1行目
2行目
3行目
識別子

a = <<TEXT
１行目
2行目
TEXT

# ※<<-TEXTのように、「-」をつけると、最後の識別子をインデントさせることができる
```

### 配列
* Arrayクラス
* インデックス番号を指定して値を取得できる。

```ruby
# 変数宣言
arr = ["hoge", "fuga", 10, true]

# 要素の取得
arr[2]  # 10

# 要素の追加
# <<を使うと、配列の最後に要素を追加できる
arr << 1

# 要素の削除
# delete_atメソッドを使う
arr.delete_at(1)

# 要素の上書き
arr[0] = 100
```

**さらに応用**

```ruby
# 配列の範囲を指定して値を取得する
a = [1,2,3,4,5]
a[1,3]  # [2,3,4]

# 取得する要素を複数指定
a.values_at(0,2,4)  # [1,3,5]

# 最後の要素を取得
a[-1]   # 5
a.last  # 5

# 最後から2番目の要素を取得
a[-2]      # 4
a.last(2)  # 4

# 最初の要素を取得
a.first  # 1

# 最初から2番目の要素を取得
a.first(2)  # 2

# 開始位置と長さを指定して要素を置き換える
a[1,3] = 100  # [1,100,100,100,5]

# pushを使って要素を追加
a.push(1)
a.push(2,3)

# deleteを使って一致した要素を削除
a.delete(2)  # 2(一致した要素がなければnilになる)
a  # [1,3,4,5]
```

**Array.newを使った配列の作成**

```ruby
# 配列の作成
a = Array.new  # []

# 要素が5つの配列を作成する
a = Array.new(5)  # [nil,nil,nil,nil,nil]

# 要素が5つで0を初期値とする配列を作成
a = Array.new(5, 0)  # [0,0,0,0,0]

# 要素数が10で1,2,3,1,2,3,...と繰り返す配列を作成
a = Array.new(10) { |n| n % 3 + 1 }  # [1,2,3,1,2,3,1,2,3,1]
```

**配列を複数使う**

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

# 配列の連結
# concatを使うと破壊的な変更となる
a.concat(b)  # [1,2,3], aは[1,2,3]に変更される

# +を使った連結(非破壊的)
a + b   # [1,2,3], aは変更されない

#--------------------------------------------------

a = [1,2,3]
b = [3,4,5]

# 配列の和集合(共通する要素が重複しないように連結する)
a | b  # [1,2,3,4,5]

# 配列の差集合(共通する要素を配列から取り除く)
a - b  # [1,2]

# 配列の積集合(共通する要素を返す)
a & b # [3]

# ※Setクラスを使って集合演算をすることもできる
```

### 範囲
* 1から5まで、aからeまでといった値の範囲を表すオブジェクト
* 「..」は最後の値を含む、「...」は最後の値を含まない

```ruby
# 1~5(最後の値を含む)
range1 = 1..5

# 1~4.999...(最後の値を含まない)
range2 = 1...5

# a~e(最後の値を含む)
range3 = a..e

# a~d(最後の値を含まない)
range4 = a...e
```

### ハッシュ

* Hashクラス
* 連想配列と同じ仕組み

```ruby
# ハッシュの変数宣言
# キー1 => 値1, キー2 => 値2, ...の書式で生成する
member = {"suzuki" => 20, "tanaka" => 30, "sato" => 40 }

# 値の取得
member["suzuki"] # 20

# キーと値の追加
member["takahashi"] = 50

# キーと値の削除
member.delete("tanaka")

# 値の上書き
member["suzuki"] = 30

# 繰り返し処理
member.each do |key, value|
  puts "#{key} : #{value}"
end
```

### シンボル
* 「:シンボルの名前」で宣言できる
* 表面上は文字列に似ているが、内部的には整数として扱うため、高速に値を比較できる
* 同じシンボルは同じオブジェクトであるため、メモリの使用効率が良い
* ハッシュのキーに使ったり、メソッドの引数に使ったりする

```ruby
# シンボルを使ったハッシュ
a = { :japan => 'yen', :us => 'dollar', :india => 'rupee' }
a[:japan] # 'yen'

# メソッドの引数にシンボルを使用
def test(a:true, b:true)
  # 省略
end
test(a:false, b:true)
```

### 真偽値
* falseとnilが「偽」
* それ以外が「真」

### 正規表現
* 「/正規表現/」で正規表現リテラルを作成する

```ruby
# 後で書く
```

### 型キャスト
```ruby
# 文字=>数値
num = "1".to_i # 1

# 数値=>文字
str = 1.to_s # "1"

# 整数=>浮動小数点数
num = 10.to_f # 10.0

# 浮動小数点数=>整数
num = 12.34.to_i # 12(小数点以下を切り捨て)
```

### nil
* 何も存在していない状態
* 他言語のnullと違って、オブジェクトなので注意

## 4.制御文

### 条件分岐
* if, unless, caseの書式がある

#### if文

```ruby
# 一般的なif文と同じ
# thenは省略可能
if 条件式1 then
  処理文1
elsif 条件式 then
  処理文2
else
  処理文3
end
```

#### unless文
```ruby
# 一般的なunless文と同じ

# thenは省略可能
unless 条件式 then
  処理文1
else
  処理文2
end
```

#### case文
```ruby
# 他言語で言うswitch文に該当
# thenは省略可能
case オブジェクト
when 値1 then
  処理文1
when 値2 then
  処理文2
when 値3,値4,値5 then
  処理文3
else
  処理文4
end
```

### 繰り返し文
* for, while, untilがある
* 他にも繰り返し処理を行う関数がある

#### for文
```ruby
# 一般的なfor文と同じ
# doは省略可能
for 変数 in オブジェクト do
  実行処理
end

# 範囲オブジェクト(..)を使ったfor文の例
for num in 1..3 do
  puts num
end
```

#### while文
```ruby
# 一般的なwhile文と同じ
# doは省略可能
while 条件式 do
  実行処理
end
```

#### until文
```ruby
# while文の逆の動きをする
until 条件式 do
  実行処理
end
```

#### eachメソッド
* 配列や範囲オブジェクトに対して何らかの処理を繰り返す場合、このeachメソッドで実装するのが一般的

```ruby
# 記述方法1
オブジェクト.each {|変数|
  実行処理
}

# 記述方法2
# doは省略可能
オブジェクト.each do |変数|
  実行処理
end
```

#### loopメソッド
* 終了条件の無い繰り返しを行うためのメソッド
* 終了したい場合は、breakを使う
* continueと同じ動きをしたい場合は、nextを使う

```ruby
loop {
  実行処理
}

# 例
num = 1
loop {
  puts num
  num += 1
  if num > 2 then
    break
  end
}
```

#### timesメソッド
* 一定の処理回数を繰り返したい場合に使用
* 数値オブジェクトの値分、処理を繰り返す

```ruby
# 記述方法1
数値オブジェクト.times{|変数|
  実行処理
}

# 記述方法2
数値オブジェクト.times do |変数|
  実行処理
end

# 例
3.times do |i|
  puts "#{i + 1}回目"
end
# 1回目
# 2回目
# 3回目
```

#### stepメソッド
* 数値に対して一定の回数処理を繰り返すためのメソッド
* limitには繰り返しの上限、stepnoには追加する数字を指定する

```ruby
# 記述方法1
オブジェクト.step(limit, stepno){|変数|
  実行処理
}

# 記述方法2
オブジェクト.step(limit, stepno) do |変数|
  実行処理
end

# 例
# 1を2ずつ増やしながら5を超えるまで繰り返す
1.step(5,2) {|x|
  puts x
}
# 1
# 3
# 5
```

#### uptoメソッド/downtoメソッド
* 数値に対して指定した値まで1加算/減算しながら処理を繰り返すメソッド

```ruby
# uptoメソッド
オブジェクト.upto(max) {|変数|
  実行処理
}
# downtoメソッド
オブジェクト.upto(min) {|変数|
  実行処理
}

# または

# uptoメソッド
数値オブジェクト.upto(max) do |変数|
  実行処理
end

# downtoメソッド
数値オブジェクト.downto(min) do |変数|
  実行処理
end

# 例(uptoメソッド)
# 2から1ずつ加算していき、4を超えるまで繰り返す
2.upto(4){|num|
  puts num # 2,3,4
}

# 例(downtoメソッド)
# 5から1ずつ減算していき、3を下回るまで繰り返す
5.downto(3) do |num|
  puts num # 5,4,3
end
```

#### 繰り返しで使用する制御関数
* break...処理の脱出
* next...繰り返し処理を途中で中断し、次の繰り返し処理に進める(continueと同じ意味)
* redo...繰り返し処理をやり直す(その回の繰り返し処理の最初に戻る)

### 例外処理

```ruby
# 例外処理
begin
  # エラーが発生する可能性のある処理
rescue
  # エラーが発生した場合の処理
else
  # エラーが発生しない場合の処理
ensure
  # エラー発生の有無に関わらず行う処理
end

# 任意にエラーを起こしたい場合
# raise
raise "error"
```

### ブロック
関数やメソッドの呼び出しの際に引数と一処理に渡す処理のかたまり

```ruby
# 下記のdo~endまでがブロック
[0,1,2].each do |i|
  puts i + 1
end

```

ブロックを受け取る関数を自分で作ることも可能
ブロックとして受け取った処理はyieldというキーワードで関数内で実行することができる

```ruby
# 定義
def block_func(v)
  puts v
  # yieldは関数がブロックを受け取っていないと例外が発生するため
  # その判定を行うblock_given?関数と使うと安全
  yield if block_given?
end

# 呼び出し
block_func("hoge") do
  puts "fuga"
end
```

## 5.クラスとモジュール

### クラス
* 「class クラス名~end」で定義する
* インスタンス変数は@変数名、クラス変数は@@変数名で定義する
* 初期化メソッド(コンストラクタ)は、「initialize」で定義する
* クラスメソッド(静的メソッド)は「self.メソッド名」で定義する

```ruby
# 一般的なクラスの定義
class User
  # クラス変数
  @@xyz = 0

  # 初期化メソッド(コンストラクタ)
  def initialize(id, name)
    @id = id
    @name = name
  end

  def show_info
    puts @id + @name
  end

  # クラスメソッド(静的メソッド)
  def self.hoge
    puts "hoge"
  end

  # クラスメソッドを複数定義したい場合
  class << self
    def method1
      # クラスメソッドの処理
    end
    def method2
      # クラスメソッドの処理
    end
  end

end

# インスタンス化
shoro = User.new("0001", "shiro")
shoro.show_info # 0001 shiro

# クラスメソッドの呼び出し
User.hoge # hoge
User::hoge # こういう書き方でもOK
```

#### クラスの継承
* サブクラス < スーパークラスで継承が可能
* superでスーパークラスのメソッドを呼びだし可能

```ruby
# 継承
class Fuga < Hoge
  # 処理

  # オーバーライドの例
  def initialize(name, price, time)
    super(name,price)  # name,priceを使ったスーパークラスのinitializeメソッドを呼び出す
    @time = time
  end

end
```
#### メソッドの公開レベル
* publicはクラスの外部からでも自由に呼び出せるメソッド(デフォルトはpublic)
* privateはクラスの外部からは呼び出せず、クラスの内部でのみ使えるメソッド(ただし、サブクラスでも呼び出すことが可能)
* protectedはそのメソッドを定義したクラス自身と、そのサブクラスのインスタンスメソッドからレシーバ付きで呼び出せる

```ruby
# privateの例
class User
  # ここから下で定義されたメソッドはprivate
  private

  def hello
    'hello'
  end

  # ただしクラスメソッドはprivateにならない
  # クラスメソッドをprivateにしたい場合は、class << selfの構文を使う
  def self.hello
    'hello'
  end
end
```

### モジュール
* モジュールはクラスのようにメソッドや定数を持つが、インスタンス化するという概念がない
* クラスにインスタンスメソッドを追加・上書きしたり、名前空間を提供するために使用する
* include、もしくはextendを使用してクラス内部に組み込む(includeだとインスタンス化して使用、extendだとクラスメソッドとして使用できる)

```ruby
# 定義
module Mod
  Version = "1.1.1"

  def v
    Version
  end

  def add(x,y)
    x + y
  end

  def self.hello
    "hello"
  end

  # モジュールメソッドとして定義
  module_function :v
end

puts Mod.v # 1.1.1
puts Mod::hello # hello

# モジュールをincludeする
class Cls
  include Mod
end
# インスタンス化して、addメソッドを呼び出す
cls = Cls.new
puts cls.add(1,2) # 3

# モジュールをextendする
class Cls
  extend Mod
end
# クラスメソッドとなっているため、直接addメソッドを呼び出す
puts Cls.add(1,2) # 3
```

## 6.ライブラリ
* 標準ライブラリ、組み込みラリブラリ、外部ライブラリ(gem)の3種類に分けることができる

### 標準ライブラリ
参照URL(使用できるライブラリ)
https://docs.ruby-lang.org/ja/latest/library/index.html

### 組み込みライブラリ
参照URL(使用できるライブラリ)
https://docs.ruby-lang.org/ja/latest/library/_builtin.html

### 外部ライブラリ(gem)
参照URL(使用できるライブラリ)
https://rubygems.org/

gemのコマンド

|コマンド|意味|例文|
|---|---|---|
|gem install \<gem\>|インストール|gem install spreadsheet|
|gem install -v \<version\>|特定のバージョンをインストール|gem instal spreadsheet -v 1.2.9|
|gem uninstall \<gem\>|アンインストール|gem uninstall spreadsheet|
|gem update|すべてのgemをアップデート|gem update|
|gem update \<gem\>|特定のgemをアップデート|gem update spreadsheet|
|gem search \<keyword\>|gemの検索|gem search spread|
|gem list|インストール済みgemを表示|gem list|
|gem info \<gem\>|インストール済みgemの情報を確認|gem info spreadsheet|
|gem help|ヘルプ|gem help|
|gem help commands|gemのコマンド一覧を調べる|gem help commands|
|gem help \<command>|gemのコマンドの使い方を調べる|gem help install|

### ライブラリの読み込み
* 「require ライブラリ名」で読み込みが可能
* requireはRubyを実行しているディレクトリがパスの起点になる
* require_relqtiveを使用した場合は、自分のファイルが存在しているディレクトリがパスの起点になる

```ruby
# dateライブラリを読み込み
require 'date'
Date.today

# 自分で作成したRubyプログラムを読み込み
# 語尾の.rbは省略可能
require './sample1.rb'
require './sample2'

# 自分のファイルを起点とした相対パスによる読み込み
require_relative '../bar/bye'
```