他言語の人がrubyを書くためのヒント(リファレンスの要約)

KMCの新入生向けラピッドゲームコーディング祭りのための記事
Rubyリファレンスの要約

リファレンス: http://docs.ruby-lang.org/ja/2.3.0/doc/index.html
対話環境(REPL)には**[pry](http://pryrepl.org/)**を用いる

Ruby 2.3を前提にします

# はじめに
Rubyは**動的型付け言語**で, 変数宣言が**不要**

```rb
pry(main)> hoge = 1 # 数値を代入
=> 1
pry(main)> hoge.class
=> Fixnum 
pry(main)> hoge = "str" # 文字列を代入して上書き
=> "str"
pry(main)> hoge.class
=> String
pry(main)> piyo
NameError: undefined local variable or method `piyo' for main:Object
```


# 文法
## [変数と定数](http://docs.ruby-lang.org/ja/2.3.0/doc/spec=2fvariables.html)
### ローカル変数 `hoge`
小文字から始まるとローカル変数
関数宣言の内側から**参照できない**
関数宣言とクラス宣言だけがスコープを作る(制御構造は作らない)

```rb
pry(main)> local_variable = 10
=> 10
pry(main)> def test; puts local_variable; end  
=> :test
pry(main)> test # testを呼び出す
NameError: undefined local variable or method `local_variable' for main:Object
```  
### グローバル変数 `$hoge`
`$`から始まるとグローバル変数

```rb
pry(main)> $global_variable = 10
=> 10
pry(main)> def test; $global_variable *= 20; end
=> :test
pry(main)> test # testを呼び出す
=> 200
pry(main)> $global_variable
=> 200
pry(main)> $undefined_variable # 未定義はnil
=> nil
```

rubyに`-w`オプションをつけて起動すると未定義のグローバル変数でWarningを出してくれる。

### 定数 `Hoge`
大文字から始まると定数
再代入をすると警告が出る**だけ**

```rb
pry(main)> ConstVariable = 10
=> 10
pry(main)> ConstVariable = 20
(pry):59: warning: already initialized constant ConstVariable
(pry):57: warning: previous definition of ConstVariable was here
=> 20
```

## [リテラル](http://docs.ruby-lang.org/ja/2.3.0/doc/spec=2fliteral.html)
+ [`nil`](http://docs.ruby-lang.org/ja/2.3.0/class/NilClass.html), [`false`](http://docs.ruby-lang.org/ja/2.3.0/class/FalseClass.html), [`true`](http://docs.ruby-lang.org/ja/2.3.0/class/TrueClass.html), `self`
+ 整数 [Integer](http://docs.ruby-lang.org/ja/2.3.0/class/Integer.html) : 10進`123`, `1_000_000_007`, 16進`0xffff`, 2進`0b1011`, 8進`0377`
+ 浮動小数 [Float](http://docs.ruby-lang.org/ja/2.3.0/class/Float.html) : `123.45` `1.2e-3`
+ 有理数 [Ratioal](http://docs.ruby-lang.org/ja/2.3.0/class/Rational.html) : `42r`
+ 複素数 [Complex](http://docs.ruby-lang.org/ja/2.3.0/class/Complex.html) : `42i`
+ 文字列 [String](http://docs.ruby-lang.org/ja/2.3.0/class/String.html) : `"string\n"` `'string\n'`
  * 式展開`"2 * 2 = #{2 * 2}" #=> "2 * 2 = 4"`
  * 文字列リテラルの中で改行して良い
+ 配列 [Array](http://docs.ruby-lang.org/ja/2.3.0/class/Array.html) : `[0, 1, "hoge"]`
  * [%記法](http://docs.ruby-lang.org/ja/2.3.0/doc/spec=2fliteral.html#percent) `%W(hoge  #{2*2}) #=> ["hoge", "4"]`
+ ハッシュ [Hash](http://docs.ruby-lang.org/ja/2.3.0/class/Hash.html) : `{ a:"A", b:"B" }`
+  範囲式 [Range](http://docs.ruby-lang.org/ja/2.3.0/class/Range.html) : 終端を含む`"a" .. "z"'`, 含まない`1 ... 10`
  * 配列展開 `[*1..3] #=> [1,2,3]`
+ シンボル [Symbol](http://docs.ruby-lang.org/ja/2.3.0/class/Symbol.html) : `:hoge`, 演算子`:+`
+ 正規表現 [Regexp](http://docs.ruby-lang.org/ja/2.3.0/doc/spec=2fregexp.html) : `/.*/`

## [演算子](http://docs.ruby-lang.org/ja/2.3.0/doc/spec=2foperator.html)

+ 四則演算 : `1 + 2`, `3 * 4 - 1`
+ 代入: `a = [1, 2, 3]`, `b = a`
+ 自己代入 : `i += 1`, `a ||= 1`
+ 多重代入 : `a, b = 1, 2`
+ 分割代入 : `x, y, z = [1, 2, 3]`
+ 配列の残り : `head, *tail = [1, 2, 3, 4]`
+ ネストした分割 : `(x, y), z = [[1, 2], 3]` : 
+ 条件演算子 : `x == 0 ? 1 : 0` (?周りの空白は必要)
+ nil ガード : `nil&.size #=> nil` (`nil.size`はエラー)

**インクリメントは存在しない**

## [制御構造](http://docs.ruby-lang.org/ja/2.3.0/doc/spec=2fcontrol.html)

最後に評価したものが**式の値**となる

### if / unless
`nil`と`false`**だけ**が偽と評価される, `0`や`""`は真

`then` は省略可能

```rb
if age >= 20 then
  puts "adult"
elsif age >= 13 then
  puts "teenage"
else
  puts "child"
end
```
最後に評価したものを使う例

```rb
type = if age >= 20 then "adult" else "child" end
```
`unless`は`if not`と同じ

```rb
unless baby?
  feed_meat
end
```

式一つなら**後置if**が出来る

```rb
a = 0 if a.nil?
```

### case-when
多言語のswitch-caseの**強化版**
`===`演算子を内部で使う
breakは**不要**

```rb
case age
when 0..12
  puts "child"
when 13..19
  puts "teenage"
when 25, 42, 61 # or 条件
  puts "yaku"
else
  puts "adult"
end
```
`0..12===3` が `true` を返す

## while/until
doは省略可能
1行なら後置出来る

breakはbreakだが, continueではなく**next**
`break val`で値を返せる
**redo**はループ条件を無視して現在の繰り返しをやり直す

```rb
while x > 1 do
  x = if x.even? then x / 2 else 3 * x + 1 end
end
```

```rb
x = if x.even? then x / 2 else 3 * x + 1 end while x > 1
```

## for
存在はするが, Enumerator(後述)が便利なため使われない

### 10回ループ
```rb
10.times do |i|
  puts i #=> 0, 1, ... 9.
end
```
### 配列の走査

```rb
["a", "b", "c"].each do |c|
  puts c #=> a, b, c.
end
```

### 添字と共に走査

```rb
["a", "b", "c"].each.with_index do |c,i|
  puts [c,i] #=> ["a", 0] ["b", 1] ["c", 2]
end
```

## begin-resure
例外捕捉
rescue内で**retry**でを書くと, beginからやり直せる

```
begin
  raise NameError, "missing hogehoge"
rescue => e
  p e
end
```

## [メソッド呼び出し](http://docs.ruby-lang.org/ja/2.3.0/doc/spec=2fcall.html)
関数呼び出しのカッコは**省略**できる

+ `puts(1, "str")`よりも`puts 1, "str"`
+ `exit()`より`exit`
 
このため, 命令のようにかける

### ブロック付き呼び出し
他言語でいうラムダ式的扱い
`{}`と`do end`に機能的な違いはない
一行なら`{}`, 複数行なら`do end`と使い分ける事が多い

```rb
[1,2,3].each{|i| puts i }

[[1,3],[2,2],[3,1]].each do |(a, t)| # 分割代入
  t.times do
    puts a
  end
end
```

## 関数定義

関数名の最後に`?`,`!`が使える

```rb
def hey(name="unknown") # デフォルト引数
  puts "hey #{name}!"
end
# ここから下でheyが使える
```

```rb
def comp(x, y)
  return y-x > 0, y - x #=> 2要素配列を返す
end
c, v = comp 1, 3
```

ブロック付き関数の定義

```rb
def double
  yield 0
  yield 1
end
double{|i| puts "hello #{i}" }
```

# [標準ライブラリ](http://docs.ruby-lang.org/ja/2.3.0/library/_builtin.html)

## [Kernel](http://docs.ruby-lang.org/ja/2.3.0/class/Kernel.html)
ここに定義されているモジュール関数はプログラム内のどこでも使える

+ 標準出力 : `print "hoge", "piyo"`
+ 出力して改行 : `puts "hoge", "piyo"`
+ 見やすく出力 : `p "hoge"`
+ プログラムを終了 : `exit`  
+ 10秒停止: `sleep 10`
+ ファイル読み込み : `open("a.txt").readlines #=> ["a\n", "b\n"]`
+ 乱数
  + 整数乱数 : `rand(3) #=>0,1,2`
  + [0,1)の乱数 : `rand #=>0.13521686772195707`
  + さいころ : `rand(1..6)`

## [Object](http://docs.ruby-lang.org/ja/2.3.0/class/Object.html)
ここに定義されているメソッドは大抵のオブジェクトで使える

+ nil判定 : `hoge.nil?`
+ 文字列変換 : `100.to_s`, `[1,2,3].to_s`
+ 変更禁止 : `hoge.freeze`
+ 浅いコピー : `["a","b"].clone`

## 数値 [Numeric](http://docs.ruby-lang.org/ja/2.3.0/class/Numeric.html)

+ 切り上げ`1.2.ceil`, 切り下げ`1.2.floor`, 四捨五入`1.2.round`
+ 絶対値 : `-1.2.abs`
+ 整数同士は切り捨て : `10 / 3 #=> 3` 
+ 小数になる : `10.0 / 3 #=> 3.3333333333333335`
+ 剰余 : `8 % 3 #=> 2`,`-8 % 3 #=> 1` (割る数が正なら**非負**)
+ 累乗 : `2 ** 10 #=> 1024`
+ nビット目 : `0b1101[1] #=> 0` 
+ 文字列に変換 : `12.to_s #=> "12"`

### **インクリメントは存在しない**
`i++`を書いてしまうと, 構文解析エラー出るので注意したい

### 整数　[Integer](http://docs.ruby-lang.org/ja/2.3.0/class/Integer.html)は多倍長整数である

**※Ruby2.4ではIntegerに統合されたので, この項は重要ではない。**

FixnumとBignumクラスが存在するが, どちらもIntegerを継承している
Fixnumでオーバーフローすると, 自動でBignumに変換される


```rb
pry(main)> a = 10 ** 10
=> 10000000000
pry(main)> a.class
=> Fixnum
pry(main)> a.class.superclass
=> Integer
pry(main)> a = a ** 10
=> 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
pry(main)> a.class
=> Bignum
pry(main)> a.class.superclass
=> Integer
```

## [Math](http://docs.ruby-lang.org/ja/2.3.0/class/Math.html)
+ 三角関数 : `Math.cos(Math::PI) #=> -1`
+ 対数関数 : `Math.log(Math::E) #=> 1`
+ 平方根 : `Math.sqrt(2) #=> 1.4142135623730951`

乱数``rand``はKernelに定義されている

## 配列 [Array](http://docs.ruby-lang.org/ja/2.3.0/class/Array.html)
+ 長さ5のnilの配列 : `Array.new(5) #=> [nil,nil,nil,nil,nil]`
+ 添字で初期化 : `Array.new(5){|i| i} #=> [0,1,2,3,4]`
+ 値で初期化 : `Array.new(5){"h"} #=> ["h","h","h","h","h"]`
+ `[*0..4] == [0,1,2,3,4]`, `('a'..'d').to_a == ['a','b','c','d']`


+ `a = [0,1,2,3,4]`のとき
  + 参照 : `a[2] #=> 2`
  + 負数参照 : `a[-1] #=> 4` (負数は後ろから)
  + 範囲参照 : `a[1..3] #=> [1,2,3]`
  + 負の範囲 : `a[1..-2] #=> [1,2,3]`
  + 開始位置, 個数 : `a[2,2] #=> [2,3]`
+ 長さ : `[0,1,2].size #=> 3`
+ 最初の場所 : `[1,2,3,5,8].index(3) #=> 2`, `[1,2].index(10) == nil`
+ 含む? : `[2,3,14,1].include?(14) #=> true`
+ 連結 : `[1,2,3] + [4,5,6] #=> [1,2,3,4,5,6]`
+ nilを削除 : `[1,nil,3,nil].compact #=> [1,3]`
+ 文字列をつなげる : `["h","e","l","l","o"].join(",") #=> "h,e,l,l,o"`
* 反転 : `[0,1,2].reverse #=> [2,1,0]`
* ランダムに選ぶ : `["a","b","c"].sample #=> "a" or "b" or "c"`
* ランダムに並べる : `[0,1,2,3].shuffle #=> [3,1,0,2]`

### 破壊的変更操作

それぞれ`a = [1,2,3]`のとき

+ 最後に挿入 : `a.push(10); a #=> [1,2,3,10]`
+ 最後を取り出す : `a.pop #=> 1; a #=> [2,3]`
+ 先頭に挿入 : `a.unshift(10); a #=> [10,1,2,3]`
+ 先頭を取り出す : `a.shift #=> 1; a #=> [2,3]`
+ push : `a << 10; a #=> [1,2,3,10]`
+ 位置, 値を挿入 : `a.insert(2,10); a #=> [1,2,10,3]`
+ 添字で削除 : `a.delete_at(1); a #=> [1,3]`
+ 値を削除 : `a.delete(2); a #=> [1,3]`
+ 同じ値で埋める : `a.fill{5}; a #=> [5,5,5]`


#### 破壊的変更
`!`を最後につけると破壊的変更を行う物がある

```rb
pry(main)> a = [*0..2]                                                           
=> [0, 1, 2]
pry(main)> a.reverse # aは変更されない
=> [2, 1, 0]
pry(main)> a
=> [0, 1, 2]
pry(main)> a.reverse! # 破壊的
=> [2, 1, 0]
pry(main)> a # aが変更される
=> [2, 1, 0]
```

### [Enumerable](http://docs.ruby-lang.org/ja/2.3.0/class/Enumerable.html)

* 配列走査 : `[0,1,2].each{|a| puts a}`
* 要素を置き換える : `[1,2,3].map{|a| a*a} #=> [1,4,9]`
* マッチするもの : `[1,2,3,5,8,13].select{|a| a.even?} #=> [2,8]`
* しないもの : `[1,2,3,5,8,13].reject{|a| a.even?} #=> [1, 3, 5, 13]`
* 添字とmap : `[0,0,0].map.with_index{|a,i| i} #=> [0,1,2]`
* 畳み込み: `(1..10).reduce{|res, n| res + b} #=> 55`
* すべて成立?: `[2, 8, 6].all?{|n| n.even?} #=> true` (any?, none?, one?)
* 2つずつ重なって : `(1..4).each_cons(2){|v| p v}` `[1,2] [2,3] [3,4]`
* 2つずつ重ならず : `(1..6).each_slice(2){|v| p v}` `[1,2] [3,4] [5,6]`
* 最大値 : `[5, 3, 6].max #=> 6`
* ソート : `[5, 3, 6].sort #=> [3, 5, 6]`

```rb
# 画面外に出た敵を殺して, 配列から削除する例
enemys.map!{|enemy|
  if enemy.out_of_window? # 敵が画面外なら
    enemy.die
    nil # nilを返す
  else # そうでなければ
    enemy # そのまま
  end
}.compact! # nilを削除
```

## 文字列 [String](http://docs.ruby-lang.org/ja/2.3.0/class/String.html)

Arrayと似たメソッドを持つ

* 結合 : `"hello" + "world" == "helloworld"`
* 文字ごとの配列 : `"hello".chars == ["h","e","l","l","o"]`
* 配列に分ける : `"1,2,3".split(",") == ["1","2","3"]`
* 数値に変換 : `"123".to_i == 123`

## 連想配列 [Hash](http://docs.ruby-lang.org/ja/2.3.0/class/Hash.html)

* `{a: 1, b:2}[:a] == 1`

## 構造体のようなクラス [Struct](http://docs.ruby-lang.org/ja/2.3.0/class/Struct.html)

```rb
Point = Struct.new(:x, :y) # Pointクラスを作る
point = Point.new(0,3) # Pointクラスのインスタンス
p [point.x, point.y] #=> [0, 3]
```

メソッド定義もできる

```rb
Enemy = Struct.new(:x, :y) do
  def move
    @x += 10
    @y += 10
  end
  def pos
    [@x, @y]
  end
end
enemy = Enemy.new(10,10)
p enemy.pos #=> [10, 10]
enemy.move
p enemy.pos #=> [20, 20]
```

## 時刻 [Time](http://docs.ruby-lang.org/ja/2.3.0/class/Time.html)
`Time.now`で現在時刻を得られる
`time1 - time2`は差を秒で返す

```rb
t0 = Time.now
10000.times{Array.new(1000)}
time_erapsed = Time.now - t0;
p time_erapsed #=> 0.141656284
```

## 参照とコピー

代入は**参照の値渡し**

```rb
origin = ["hoge", "piyo"]
same = origin # `same`と`origin`は同じ参照
shallow = origin.clone # Array*だけ*複製 要素は*同じ参照*
deep = origin.map{|s| s.clone} # 要素も複製
origin[0] = "XXXX" # 参照を上書き
origin[1].reverse! # 参照先を変更
p origin #=> ["XXXX", "oyip"]
p same #=> ["XXXX", "oyip"] # originと同じ参照
p shallow #=> ["hoge", "oyip"] # 要素の変更の影響を受ける
p deep #=> => ["hoge", "piyo"] # 変更されない
```

# クラス
コンストラクタは`new`ではなく`initialize`

```rb
class Person
  attr_accessor :name, :age
  def initialize(name, age) # コンストラクタ
    @name = name
    @age = age
  end
  
  def prof # インスタンスメソッド
    "#{@name} is #{@age} years old."
  end
end

me = Person.new("wass", 10)
p [me.name, me.age] #=> ["wass", 10]
puts me.prof #=> wass is 10 years old.
```

## インスタンス変数 `@hoge`
デフォルトではクラス外からアクセス出来ない
外から参照するアクセサを設定することが出来る

```rb
class Pet
  attr_accessor :weight # 書き込み読み込み可
  attr_reader :name # 読み込みのみ可
  attr_writer :lifespan # 書き込みのみ可
end
```

## クラス変数 `@@hoge`
同じクラスのインスタンス間で共有できるグローバル変数

```rb
class Session
  @@endpoint = "http://..."
  # セッターを自分で定義する例
  def self.endpoint=(url)
    @@endpoint=url
  end
end
Session.endpoint = "https://..."
p Session.endpoint #=> "https://..."
```

## クラス定数
クラスの中の定数にアクセスするには`::`を用いる

```rb
class MyMath
  TAU = Math::PI * 2
end
p MyMath::TAU #=> 6.283185307179586
```
## クラスメソッド
`self.`をつける

```rb
class MyMath
  def self.sec(x)
    1/Math.cos(x)
  end
end
p MyMath.sec(Math.PI) #=> -1.0
```

## 継承

```rb
class Enemy < Sprite

end
```
## クラスの再オープン
クラス定義は上書きできる

```rb
class Array
  def head_tail
    h , *t = self
    return h, t
  end
end
p [1,2,3].head_tail #=> [1, [2, 3]]
```