LoginSignup
2
2

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-05-02

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

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

Ruby 2.3を前提にします

はじめに

Rubyは動的型付け言語で, 変数宣言が不要

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

文法

変数と定数

ローカル変数 hoge

小文字から始まるとローカル変数
関数宣言の内側から参照できない
関数宣言とクラス宣言だけがスコープを作る(制御構造は作らない)

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

$から始まるとグローバル変数

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

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

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

リテラル

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

演算子

  • 四則演算 : 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はエラー)

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

制御構造

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

if / unless

nilfalseだけが偽と評価される, 0""は真

then は省略可能

if age >= 20 then
  puts "adult"
elsif age >= 13 then
  puts "teenage"
else
  puts "child"
end

最後に評価したものを使う例

type = if age >= 20 then "adult" else "child" end

unlessif notと同じ

unless baby?
  feed_meat
end

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

a = 0 if a.nil?

case-when

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

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===3true を返す

while/until

doは省略可能
1行なら後置出来る

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

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

for

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

10回ループ

10.times do |i|
  puts i #=> 0, 1, ... 9.
end

配列の走査

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

添字と共に走査

["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

メソッド呼び出し

関数呼び出しのカッコは省略できる

  • puts(1, "str")よりもputs 1, "str"
  • exit()よりexit

このため, 命令のようにかける

ブロック付き呼び出し

他言語でいうラムダ式的扱い
{}do endに機能的な違いはない
一行なら{}, 複数行ならdo endと使い分ける事が多い

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

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

関数定義

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

def hey(name="unknown") # デフォルト引数
  puts "hey #{name}!"
end
# ここから下でheyが使える
def comp(x, y)
  return y-x > 0, y - x #=> 2要素配列を返す
end
c, v = comp 1, 3

ブロック付き関数の定義

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

標準ライブラリ

Kernel

ここに定義されているモジュール関数はプログラム内のどこでも使える

  • 標準出力 : 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

ここに定義されているメソッドは大抵のオブジェクトで使える

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

数値 Numeric

  • 切り上げ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は多倍長整数である

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

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

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

  • 三角関数 : Math.cos(Math::PI) #=> -1
  • 対数関数 : Math.log(Math::E) #=> 1
  • 平方根 : Math.sqrt(2) #=> 1.4142135623730951

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

配列 Array

  • 長さ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]

破壊的変更

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

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

  • 配列走査 : [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]
# 画面外に出た敵を殺して, 配列から削除する例
enemys.map!{|enemy|
  if enemy.out_of_window? # 敵が画面外なら
    enemy.die
    nil # nilを返す
  else # そうでなければ
    enemy # そのまま
  end
}.compact! # nilを削除

文字列 String

Arrayと似たメソッドを持つ

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

連想配列 Hash

  • {a: 1, b:2}[:a] == 1

構造体のようなクラス Struct

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

メソッド定義もできる

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

Time.nowで現在時刻を得られる
time1 - time2は差を秒で返す

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

参照とコピー

代入は参照の値渡し

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

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

デフォルトではクラス外からアクセス出来ない
外から参照するアクセサを設定することが出来る

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

クラス変数 @@hoge

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

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

クラス定数

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

class MyMath
  TAU = Math::PI * 2
end
p MyMath::TAU #=> 6.283185307179586

クラスメソッド

self.をつける

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

継承

class Enemy < Sprite

end

クラスの再オープン

クラス定義は上書きできる

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2