これだけ知っておけば十分。(2万字)
情報源
予約語
BEGIN class ensure nil self when END def false not super while alias defined? for or then yield and do if redo true __LINE__ begin else in rescue undef __FILE__ break elsif module retry unless __ENCODING__ case end next return until
番号指定パラメータ
_1 _2 _3 _4 _5 _6 _7 _8 _9
1行コメント
# コメント
複数行コメント
=begin 複数行の コメント =end
シンボル
:some_symbole
:[_a-zA-Z][_a-zA-Z0-9]+
識別子
名前の付け方に制約がある。
| 種別 | 規約 | 例 |
|---|---|---|
| 定数 | 先頭1字目が英大文字 | Const = 1, CONST = 1 |
| モジュール | 先頭1字目が英大文字 | module Mod; end |
| クラス | 先頭1字目が英大文字 | class Cls; end |
| メソッド | - | def met; end, def Met; end |
変数は先頭1字目が英小文字。
| 種別 | 規約 | 例 |
|---|---|---|
| ローカル変数 | - | local = 1 |
| グローバル変数 | 接頭辞$ |
$global = 1 |
| インスタンス変数 | 接頭辞@ |
@ins = 1 |
| クラス変数 | 接頭辞@@ |
@cls = 1 |
- 再定義するとどうなるか
- 未定義を参照するとどうなるか
| 項目 | 再定義 | 未定義 |
|---|---|---|
| 定数 | 警告&代入 | エラー |
| モジュール | 追加、上書きされる | エラー |
| クラス | 追加、上書きされる | エラー |
| メソッド | 上書きされる | エラー |
| ローカル変数 | 代入 | エラー |
| グローバル変数 | 代入 | エラー |
| インスタンス変数 | 代入 | nilを返す |
| クラス変数 | 代入 | エラー |
警告は処理が継続されるが、エラーは中断される。
組込ライブラリ
Kernelモジュール
require
外部ファイルをロードする。
require 'bundler'
式
ふつう式といえば評価したとき値が定まるものを指す。たとえば以下のようなもの。
1 + 2 #=> 3
Rubyはほぼすべて式である。ifでさえ式だ。returnの引数で値を指定しないかぎり、最後に実行した式の戻り値を返す。
x = if true 1 else 2 end p x #=> 1
式は()でグループ化し優先度をあげたり、;で立て続けに書いてワンライナーにできる。
0 == (13 % 2)
a = 1; b = 2
文
メソッドの引数に指定できない式のことを「文」と呼び分けることがある。
and,or,notif/unless/rescue修飾式など
def m(a); p a; end m(1 and 2) #=> syntax error, unexpected `and', expecting ')'
でも()で囲うと式として使える。
m((1 and 2)) #=> 2
メソッド
メソッドは複数の式をまとめたもの。
定義
def m end
呼出
m
戻り値は最後に実行した式の戻り値を返す。
def m :m end
m #=> :m
returnに引数を渡せばその値を返せる。
def m return :m end
m #=> "A"
引数を受け取れる。
def m(a) p a end
m 'A' #=> "A"
引数の種類は次の通り。
| 種類 | 例 | キー | デフォルト式 | 複数 |
|---|---|---|---|---|
| 引数 | a |
位置 | なし | ⭕ |
| 引数 | a = 1 |
位置 | あり | ⭕ |
| 可変長引数 | *args |
位置 | 有無 | ❌ |
| キーワード引数 | k: |
名前 | なし | ⭕ |
| キーワード引数 | k:'v' |
名前 | あり | ⭕ |
| キーワード可変長引数 | **kwargs |
名前 | 有無 | ❌ |
| ブロック引数 | &block |
名前 | 有無 | ❌ |
定義順は以下のとおり。
- デフォルト式のない引数(複数指定可)
- デフォルト式のある引数(複数指定可)
*を伴う引数(1つだけ指定可)- デフォルト式のない引数(複数指定可)
- キーワード引数(複数指定可)
**を伴う引数(1つだけ指定可)&を伴う引数(1つだけ指定可)
処理のまとまりには以下の種類がある。
| 呼び方 | 概要 | 例 |
|---|---|---|
| 関数 | レシーバがない。別名スタティックメソッド。 | func(p1) |
| メソッド | レシーバがある。 | ins.met(p1), Cls::met(p1) |
| クロージャ | 匿名関数、関数ポインタ、デリゲート等ともいう。 | block.call(p1) |
メソッド一覧。
| 種別 | 概要 | 呼出例 |
|---|---|---|
| メソッド | トップレベルに定義したメソッド | m |
| モジュール関数 | モジュールにmodule_functionで定義したメソッド |
M |
| モジュールクラスメソッド | モジュールにselfで定義したメソッド |
M::m |
| モジュールインスタンスメソッド | モジュールに定義したメソッド | クラスにMixinする |
| 特異メソッド | 特定のインスタンス専用メソッド | ins.m |
| インスタンスメソッド | クラスに定義したインスタンスがもつメソッド | ins.m |
| クラスメソッド | クラスに定義したクラスがもつメソッド | `` |
クロージャ一覧。
| 種別 | 定義例 |
|---|---|
| イテレータ | {|i| ...} |
| proc | proc {|i| ...} |
| lambda | lambda {|i| ...} |
なお{...}はdo ... endに変更できる。それはprocやlambdaでも同じ。このときクロージャ内ローカル変数iは外側からも参照できるようになる。ほかにもブロック引数を省略しつつ呼び出したり、呼出をyieldでなくブロック変数からcallすることで行うなど複数の記法ができる。以下にパターン例を示す。
| 種別 | 定義例 | 呼出例 |
|---|---|---|
| イテレータ1 | {...} |
def m; yield |
| イテレータ1 | {...} |
def m(&block); block.call |
| イテレータ1 | `{ | p1,p2| ...}|def m; yield p1, p2` |
| イテレータ1 | `{ | p1,p2| ...}|def m(&block); block.call p1, p2` |
| イテレータ2 | do ... end |
def m; yield |
| イテレータ2 | do ... end |
def m(&block); block.call |
| イテレータ2 | `do | p1,p2| ... end|def m; yield p1, p2` |
| イテレータ2 | `do | p1,p2| ... end|def m(&block); block.call p1, p2` |
| proc | proc {...} |
def m(p); p.call |
| proc | proc {...} |
def m(&block); block.call |
| proc | `proc { | p1,p2| ...}|def m; yield p1, p2` |
| proc | `proc { | p1,p2| ...}|def m(&block); block.call p1, p2` |
| proc | proc do ... end |
def m(p); p.call |
| proc | proc do ... end |
def m(&block); block.call |
| proc | `proc do | p1,p2| ... end|def m; yield p1, p2` |
| proc | `proc do | p1,p2| ... end|def m(&block); block.call p1, p2` |
| lambda | lambda {...} |
def m(p); p.call |
| lambda | lambda {...} |
def m(&block); block.call |
| lambda | `lambda { | p1,p2| ...}|def m; yield p1, p2` |
| lambda | `lambda { | p1,p2| ...}|def m(&block); block.call p1, p2` |
| lambda | lambda do ... end |
def m(p); p.call |
| lambda | lambda do ... end |
def m(&block); block.call |
| lambda | `lambda do | p1,p2| ... end|def m; yield p1, p2` |
| lambda | `lambda do | p1,p2| ... end|def m(&block); block.call p1, p2` |
モジュール
module Mod; end
module Mod end
クラスと違ってインスタンス化できない。newメソッドがない。
名前空間にしたり、Mixin(クラスやインスタンスへメソッドを提供)する。
名前空間
名前空間として使う。とくに定数の入れ物として。
module Mod MAX = 100 end p Mod::MAX #=> 100
モジュール関数
定義
module Mod def some p 'モジュール関数' end module_function :some end
呼出
Mod::some
Mod.some
クラスメソッド
モジュールなのにクラスメソッドとはこれいかに。便宜上の名前である。
定義
module Mod def self.some p 'クラス関数' end end
呼出
Mod::some
Mod.some
⚠後述するMixinしたクラスやインスタンスからは呼び出せない!
インスタンスメソッド
モジュールはインスタンス化できないのにインスタンスメソッドとはこれいかに。便宜上の名前である。
定義
module Mod def some p 'モジュール関数' end end
⚠後述するMixin(include,prepend,extend)しなければ呼び出せない!
クラス
class C; end
class C end
コンストラクタ
定義
class C def initialize p 'コンストラクタ' end end
呼出
C.new
インスタンスメソッド
定義
class C def m p :m end end
呼出
C.new.m
クラスメソッド
他言語でいうクラスメソッドは、Rubyでいう「クラスの特異メソッド」である。ちなみに「クラスの」とつかない単なる「特異メソッド」は「インスタンスの特異メソッド」を指す。
定義
class C def self.m p :self_m end end C.public_methods false #=> [:m, :allocate, :superclass, :new]
呼出
C::m
C.m
以下のような記法がある。
class C def C.m p :self_m end end C.public_methods false #=> [:m, :allocate, :superclass, :new]
class C; end def C.m; :self_m; end C.public_methods false #=> [:m, :allocate, :superclass, :new]
class C; end class << C def m p :self_m end end C.public_methods false #=> [:m, :allocate, :superclass, :new]
module M def m; p :self_m; end end class C extend M end C.public_methods false #=> [:m, :allocate, :superclass, :new]
module M def m; p :self_m; end end class C; end C.extend M C.public_methods false #=> [:m, :allocate, :superclass, :new]
インスタンス変数
定義
class C def initialize @age = 0 end end
呼出
class C def initialize @age = 0 some p @age end def some @age += 1 end end class D < C def initialize @age += 1 end end C.new #=> 1 C.new #=> 1 C.new.some #=> 2 D.new #=> undefined method `+' for nil:NilClass (NoMethodError)
- インスタンス変数はコンストラクタ
initialize内で宣言する - インスタンス変数は接頭辞
@がつく - インスタンス変数は
privateである- クラス内でしか参照できない
- 親クラスからも参照できない
- インスタンス変数はインスタンス固有である
- 別のインスタンス変数と値を共有しない
クラス変数
定義
class C @@ins_count = 0 end
呼出
class C @@ins_count = 0 def initialize @@ins_count += 1 p @@ins_count end end class D < C def initialize @@ins_count += 1 super end end C.new #=> 1 C.new #=> 2 D.new #=> 4 C.new #=> 5
- クラス変数はクラス定義内?で宣言する
- クラス変数は接頭辞
@@がつく - クラス変数はクラス内か親クラス内でしか参照できない
- クラス変数はインスタンス間で共有する
アクセサ
インスタンス変数はprivateである。ふつうは参照できないが、接頭辞@を省いたゲッター/セッターメソッドを自動作成する糖衣構文がある。
| 糖衣構文 | ゲッター | セッター | 推奨 | 補足 |
|---|---|---|---|---|
attr |
⭕ | ❌ | ❌ | Ruby3.2で廃止予定 |
attr_reader |
⭕ | ❌ | ⭕ | |
attr_writer |
❌ | ⭕ | ⭕ | |
attr_accessor |
⭕ | ⭕ | ⭕ |
以下は同等のコードである。
class C attr_accessor :name end
class C def initialize @name = nil end def name; @name; end def name=(v); @name = v; end end
試してみる。
class C attr_accessor :name, :age end c = C.new p c.name #=> nil c.name = 'ytyaru' p c.name #=> "ytyaru"
アクセス修飾子
クラス定義したメンバのスコープを定義する。
アクセス修飾子|概要
--------------|----
private|自分のクラス定義内からしか参照できない
protected|自分またはサブクラスからしか参照できない
public`|上記に加え、クラスのインスタンスからも参照できる
デフォルトはpublic。
以下コードは同じ。
class C public def a; end def b; end protected def c; end def d; end private def e; end def f; end end C.new.public_methods false #=> [:b, :a] C.new.protected_methods false #=> [:c, :d] C.new.private_methods false #=> [:e, :f]
class C def a; end def b; end def c; end def d; end def e; end def f; end public :a, :b protected :c, :d private :e, :f end C.new.public_methods false #=> [:b, :a] C.new.protected_methods false #=> [:c, :d] C.new.private_methods false #=> [:e, :f]
継承
継承とは、あるクラスの実装を別のクラスに受け継ぐことである。
class C def m; :m; end end class D < C end D.new.m
DはCを継承している。このときの関係を以下のように呼称する。
| クラス | 呼び方 |
|---|---|
C |
親,基底,スーパー |
D |
子,派生,サブ |
特異クラス
特異クラスとはすべてのオブジェクトがひとつだけ持てる。特異メソッドを定義できる。singleton_classで参照する。
class C; end p C.singleton_class #=> #<Class:C> p C.new.singleton_class #=> #<Class:#<C:0x014ef278>>
上記コードのとおり、クラスオブジェクトも、インスタンスオブジェクトも、どちらもそれぞれひとつずつ特異クラスsingleton_classを持っている。
特異メソッド
ある特定のオブジェクトのみが持つメソッド。
class C; end C.new.m #=> undefined method `m' for #<C:0x0171e598> (NoMethodError) c = C.new def c.m; '特異メソッド'; end c.m #=> "特異メソッド"
上記はインスタンスオブジェクトが持つ特異メソッドである。ふつう特異メソッドといえば、インスタンスオブジェクトが持つ特異クラスに定義された特異メソッドのことを指す。
それに対して、クラスオブジェクトが持つ特異クラスに定義された特異メソッドのことをクラスメソッドと呼ぶ。
class C; end def C.m; :self_m; end p C::m #=> :self_m
Mixin
Mixinとは、モジュールの実装をクラスへ組み込むことである。
module Mod def m; :m; end end class C include Mod end C.new.m
| Mixin | 概要 |
|---|---|
include |
モジュールのインスタンスメソッドをクラスに組み込む |
prepend |
includeと同じだがクラスに同名シンボルがあればモジュール側を優先する |
exntend |
includeと同じだが特異メソッドとして組み込む |
継承リスト
継承リストとは、クラスやモジュールの一覧である。参照メソッドを特定するためのもので、継承やMixinされたときの優先度がそのままリストになっている。
| 継承 | 継承リスト | 位置 | 呼出 |
|---|---|---|---|
class C |
C.ancestors |
[C, ...] |
C.new.m |
class D < C |
D.ancestors |
[D, C, ...] |
D.new.m |
class C; end class << C def m; :m; end end p C.singleton_class.ancestors #=> [#<Class:C>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, PP::ObjectMixin, Kernel, BasicObject] p C.method :m #=> #<Method: C.m() (irb):3> p C.singleton_class.method :m #=> undefined method `m' for class `#<Class:#<Class:C>>' (NameError)
Rubyにおけるメソッド作成のすべて
- トップレベル
mainオブジェクトにメソッドを追加する - モジュールオブジェクトにメソッドを追加する
- モジュール関数
- クラスメソッド
- インスタンスメソッド
- インスタンスオブジェクトにメソッドを追加する
- クラスオブジェクトにメソッドを追加する
- 特異クラスオブジェクトにメソッドを追加する
- クロージャとしてメソッドを追加する
BEGIN,END- イテレータ
{}(ブロック、ブロックつきメソッド呼出)do-end
proc(Proc.new)lambda
以下はすべてCクラスオブジェクトにメソッドを追加する。
class C def self.m; :m; end end class C def C.m; :m; end end class C; end class << C def m; :m; end end
特異クラスにメソッドを追加する
| Mixin | 継承リスト | 位置 | 呼出 |
|---|---|---|---|
include |
C.ancestors |
[C, M, ...] |
C.new.m |
prepend |
C.ancestors |
[M, C, ...] |
C.new.m |
exntend |
C.singleton_class.ancestors |
[#<Class:C>, M, ...] |
C::m |
継承リストの順序は次の通り。
- 特異クラス
- 自クラス
prepend(後からprependするほど高)include(後からincludeするほど高)- 親クラス
クラスオブジェクトがもつメソッドの探索優先順位。
module M; def m; :m; end; end class C; end C.singleton_class.prepend M # 1 class C; def self.m; :c; end; end # 2 C.singleton_class.include M # 3 == C.new.exntend M
インスタンスオブジェクトがもつメソッドの探索優先順位。
module M; def m; :m; end; end class C; end ins = C.new def ins.m; :ins_m; end # 1 C.new.prepend M # 2 class C; def self.m; :c; end; end # 3 C.new.include M # 4 class D < C; self.m; :d; end; end # 5
継承
class C; end class D < C; end p C.ancestors #=> [C, Object, PP::ObjectMixin, Kernel, BasicObject] p D.ancestors #=> [D, C, Object, PP::ObjectMixin, Kernel, BasicObject]
もし同名のメソッドがあれば、継承リストの先頭から探す。
class C; def m; :m; end; end class D < C; def m; :n; end; end p C.ancestors #=> [C, Object, PP::ObjectMixin, Kernel, BasicObject] p D.ancestors #=> [D, C, Object, PP::ObjectMixin, Kernel, BasicObject] p C.new.m #=> m p D.new.m #=> n
C.new.mは、C.newの継承リスト[C, Object, ...]の先頭Cにメソッドmがあるのでそれを呼び出す。もしCになければ次のObjectにmメソッドがないか探索する。
D.new.mは、D.newの継承リスト[D, C, Object, ...]の先頭Dにメソッドmがあるのでそれを呼び出す。Cのそれとは違い、:mでなく:nを返していることから違うメソッドが呼ばれたことがわかる。
super
superは親メソッドを参照する。
class C; def m; :m; end; end class D < C; def m; super; end; end p C.ancestors #=> [C, Object, PP::ObjectMixin, Kernel, BasicObject] p D.ancestors #=> [D, C, Object, PP::ObjectMixin, Kernel, BasicObject] p C.new.m #=> m p D.new.m #=> m
他言語でのsuperは親クラスを指すが、Rubyは親メソッドを指す。
include
includeはモジュールのインスタンスメソッドをクラスに追加する。
module M; def m; :m; end; end class C include M end p C.new.m #=> :m
includeは継承リスト項目としてモジュールを追加する。その順序は、includeしたクラス自身の後ろである。
module M; def m; :m; end; end class C include M def m; :c; end end p C.new.m #=> :c p C.ancestors #=> [C, M, Object, PP::ObjectMixin, Kernel, BasicObject]
もし同名メソッドがあれば継承リストの先頭から探索する。この場合はCのmが最初にみつかる。次にMのm。なので最初に見つかったC.mを呼び出す。
prepend
prependはモジュールのインスタンスメソッドをクラスに追加する。
module M; def m; :m; end; end class C prepend M end p C.new.m #=> :m
prependは継承リスト項目としてモジュールを追加する。その順序は、prependしたクラス自身の前である。
module M; def m; :m; end; end class C prepend M def m; :c; end end p C.new.m #=> :m p C.ancestors #=> [M, C, Object, PP::ObjectMixin, Kernel, BasicObject]
もし同名メソッドがあれば継承リストの先頭から探索する。この場合はMのmが最初にみつかる。次にCのm。なので最初に見つかったM.mを呼び出す。
extend
extendはモジュールを特異クラスの継承リストに追加する。
extendはモジュールのインスタンスメソッドを特異クラスの特異メソッドとして追加する。
module M; def m; :m; end; end class C extend M end p C::m #=> :m p C.m #=> :m p C.singleton_class.ancestors #=> [#<Class:C>, M, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, PP::ObjectMixin, Kernel, BasicObject] p C.method :m #=> #<Method: #<Class:C>(M)#m() (irb):1> p C.singleton_class.method :m #=> undefined method `m' for class `#<Class:#<Class:C>>' (NameError) p C.new.singleton_class.method :m #=> #<Method: #<Class:C>(M)#m() (irb):1> p C.ancestors #=> [C, Object, PP::ObjectMixin, Kernel, BasicObject] p C.new.singleton_class.ancestors #=> [#<Class:#<C:0x01088790>>, C, Object, PP::ObjectMixin, Kernel, BasicObject]
特異クラスはすべてのオブジェクトがひとつずつ持てる。singleton_classで取得できる。
extendしたらそのクラスのクラスオブジェクト、インスタンスオブジェクトのうち、どちらの特異クラスの特異メソッドとして追加されるのか。上記コードをみてわかるとおり、:mメソッドはインスタンスオブジェクトがもつ特異クラスの特異メソッドとして追加される。クラスオブジェクトがもつ特異クラスの特異メソッドとしては追加されていない。undefined methodエラーになる。
extendは継承リスト項目として特異クラスを追加する。その順序は最前列である。
module M; def m; :m; end; end class C extend M def self.m; :c; end end p C::m #=> :c p C.m #=> :c p C.new.m #=> undefined method `m' for #<C:0x00845358> (NoMethodError) p C.ancestors #=> [C, Object, PP::ObjectMixin, Kernel, BasicObject] p C.new.singleton_class.ancestors #=> [#<Class:#<C:0x00a9b870>>, C, Object, PP::ObjectMixin, Kernel, BasicObject]
extendしたとき特異クラスの特異メソッドはインスタンスオブジェクトに追加される。
もし同名メソッドがあれば継承リストの先頭から探索する。この場合はMのmが最初にみつかる。次にCのm。なので最初に見つかったM.mを呼び出す。
オブジェクト
オブジェクトとは状態と振る舞いをもったメモリ実体である。
Rubyはリテラルもオブジェクトである。Javaのリテラルはプリミティブ型といい、単なる状態にすぎずメソッドを持っていない。それと比べてRubyはリテラルもオブジェクトであり、メソッドを持っている。
たとえば3は数値リテラルである。Integer型でありtimesメソッドを持っている。3回ブロックを実行する。
3.times {|i| p i}
インスタンス
インスタンスもオブジェクトの一種である。ただし、自分で作成したクラスをnewして返ってきたものを特にインスタンスと呼ぶ。なぜならRubyはすべてがオブジェクトであるから。そしてnewできるのはクラスだけなので特別に呼び分けるのだと思われる。
3 # 3 もIntegerクラスのインスタンスと言えるが「リテラル」と呼ぶほうが一般的 a = 4 # a もIntegerクラスのインスタンスと言えるが「変数」と呼ぶほうが一般的 class C; end # C もClassクラスのインスタンスと言える。また定数の一種とも言える。だがクラスオブジェクトともいう。だが定義である「クラス」と呼ぶほうが一般的 c1 = C.new # c をインスタンスと呼ぶ。オブジェクトの一種ではあるが、自作クラスをnewした戻り値を特に「インスタンス」と呼び分ける。
リテラル
| 種類 | コード例 |
|---|---|
| 数値 | 3 |
| 文字列 | 'str' |
| バックスラッシュ記法 | \n |
| 配列 | [1,2,3] |
| ハッシュ | [key: 'value', key2: 'v2'] |
| 範囲 | 1 .. 7, (1..) |
| シンボル | :my_symbol |
以下は式やシェルを展開できる。
| 種類 | コード例 |
|---|---|
| 式展開 | "#{var}" |
| コマンド展開 | `date`, %x{date} |
| ヒアドキュメント | <<EOS ... EOS |
| 正規表現 | /^ruby$/, %r|ruby| |
| %記法 | 概要 |
|---|---|
%!STRING! |
ダブルクォート文字列 |
%Q!STRING! |
同上 |
%q!STRING! |
シングルクォート文字列 |
%x!STRING! |
コマンド出力 |
%r!STRING! |
正規表現 |
%w!STRING! |
要素が文字列の配列(空白区切り) |
%W!STRING! |
要素が文字列の配列(空白区切り)。式展開、バックスラッシュ記法が有効 |
%s!STRING! |
シンボル。式展開、バックスラッシュ記法は無効 |
%i!STRING! |
要素がシンボルの配列(空白区切り) |
%I!STRING! |
要素がシンボルの配列(空白区切り)。式展開、バックスラッシュ記法が有効 |
!の部分には改行を含めた任意の非英数字を使える(%w、%W、%i、%Iは区切りに空白、改行を用いるため、!の部分には使えない)。!は(),[],{},<>にすることもできる。
%w(ab cd ef) #=> ["ab", "cd", "ef"] %w(ab\ cd ef) #=> ["ab cd", "ef"]
定数
頭文字が英大文字の変数は定数になる。命名規則的にはすべて大文字のスネークケースが望ましい。
Const = 100 CONST = 100
なお、再代入することができてしまう。警告は出るが代入は妨げられない。値が変わってしまう。なので本来の定数とは言い難い。
CONST = 100 CONST = 101 #=> warning: already initialized constant CONST
変数
演算子
高い ::
[]
+(単項) ! ~
**
-(単項)
* / %
+ -
<< >>
&
| ^
> >= < <=
<=> == === != =~ !~
&&
||
.. ...
?:(条件演算子)
=(+=, -= ... )
not
低い and or
| 種別 | 演算子 |
|---|---|
| スコープ演算子 | :: |
| 算術演算子 | **, *, /, %, +, -, ,, ,, ``, |
| ビット演算子 | !, ~, <<, >>, &, |, ^, not,and,or |
| 比較演算子 | >, >=, <, <=, ===, !=, !~, ,, ``, |
| 宇宙船演算子 | <=> |
| 代入演算子 | == |
| 正規表現演算子? | =~ |
| 論理演算子 | &&, || |
| 範囲演算子 | .., ... |
| 条件演算子 | (条件) ? 真値 : 偽値 |
| 自己代入演算子 | +=, -=, *=, /=, %=, **=, ||=, ... |
| 配列演算子? | [], []= |
| ? | +(単項), -(単項) |
1 <=> 2 # -1 左 < 右 2 <=> 1 # 1 左 > 右 2 <=> 2 # 0 左 == 右 2 <=> '2' # nil 比較不可
a = nill a ||= 1 p a #=> 1 b = 2 b ||= 1 p b #=> 2
代入
a = 1
自己代入
a ||= 1 a += 1 a -= 1
多重代入
a, b = 1, 2
制御式
| 種類 | 予約語 |
|---|---|
| 分岐 | (条件) ? 真 : 偽, if/unless, case-when, case-in |
| 繰り返し | while/until, for, each, loop, times, updo, downdo, break/next/redo |
| 例外処理 | raise, begin-rescue-else-ensure-end, retry |
| 開始処理 | BEGIN |
| 終了処理 | END |
| 制御返し | return |
1行で書ける書式がある。
(1 == 1) ? 'A' : 'B' #=> "A" p 'A' if 1 == 1 #=> "A" p 'A' unless 1 == 2 #=> "A"
break while true break until false
p 'A' rescue raise #=> "A"
条件分岐
(条件) ? 真 : 偽if/unlesscase-whencase-in
(1 == 1) ? 'A' : 'B' #=> "A" p 'A' if 1 == 1 #=> "A" p 'A' unless 1 == 2 #=> "A"
if 1 == 1 'A' elsif 1 == 2 'B' else 'C' end #=> "A"
v = unless 1 == 2 'A' else 'B' end #=> "A"
case 7 when 1,3,5,7,9 '奇数' when 0,2,4,6,8 '偶数' else '範囲外' end
case 7 in 1|3|5|7|9 '奇数' in 0|2|4|6|8 '偶数' else '範囲外' end
unlessはelsifが使えないcase-inは網羅的に書かねばならない
条件式としての範囲式
条件式としての範囲式には以下のような記法がある。
$age = 10 case $age when 0 .. 2 "baby" when 3 .. 6 "little child" when 7 .. 12 "child" when 13 .. 18 "youth" else "adult" end
$age = 10 case $age in 0 .. 2 "baby" in 3 .. 6 "little child" in 7 .. 12 "child" in 13 .. 18 "youth" else "adult" end
フリップフロップ
10.times {|i| if (i==2)..(i==4) p "#{i}" end }
フリップフロップには以下のような縛りがある。
- ブロック内でないと動作しない?
else,elsifが使えない
以下は思ったように実行されなかった。
age = 10 if (age==0)..(age==100) p '死ぬまで働け!' end #=> nil #"死ぬまで働け!"が期待値だった
$age = 10 if ($age==0)..($age==2); 'baby'; elsif ($age==3)..($age==6); 'little child'; elsif ($age==7)..($age==12); 'child'; elsif ($age==13)..($age==18); 'youth'; else; 'adult'; end #=> "adult" # "child"が期待値だった
一度廃止にしたけど廃止にするのを廃止にしたらしい。なんだかなぁ。使いこなせない。どうなっているのかよくわからん。ネットにもフリップフロップが意味不明というお嘆きの声があがっていた。
繰り返し
while/untilforeachlooptimesupdodowndobreak/next/redo
break while true break until false
while true p 'while' break end until false p 'until' break end
一度だけ実行する形式。C言語でいうdo-while。
begin p 'do-while' break end while true begin p 'do-until' break end until false
例外処理
raisebegin-rescue-else-ensure-endretry
例外を発生させる。
raise
例外をキャッチする。
p 'A' rescue raise #=> "A"
例外処理。
begin raise rescue => e p e else p 'else' ensure p 'ensure' end
開始処理
BEGIN { p 'BEGIN' }
終了処理
END { p 'END' }
制御返し
def m return 5 end p m #=> 5
対象環境
- Raspbierry pi 4 Model B
- Raspberry Pi OS buster 10.0 2020-08-20 ※
- bash 5.0.3(1)-release
- Ruby 3.0.2
$ uname -a Linux raspberrypi 5.10.52-v7l+ #1441 SMP Tue Aug 3 18:11:56 BST 2021 armv7l GNU/Linux