Slide 1

Slide 1 text

Rubyのエラーをちょっと整理(初級者向け) Rubyのエラー, エラー⽂をちょっと⾒てみます。 @universato Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 1

Slide 2

Slide 2 text

⾃⼰紹介 universato(ユニヴァーサトウ)ことユニです。 ⼀定の範囲で、好きによんで下さい。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 2

Slide 3

Slide 3 text

最初に スライドの枚数が多く、発表では⾶ばすページも多いですが、 別の場所に置くので、暇なときにゆっくり⾒ていって下さい。 検証︓Ruby 2.7.1 ※2ヶ⽉後の年内に、バージョン3.0がでる予定。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 3

Slide 4

Slide 4 text

ザックリした⽬次 エラーの分類 構⽂エラー(主なsyntax error, Hashとブロック、8進数) 実⾏時エラー ArgumentError, TypeError 参考記事・参考書籍 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 4

Slide 5

Slide 5 text

エラーの分類 ⼀般なエラーの段階別の分類 構⽂エラー = シンタックスエラー(Syntax error) 実⾏時エラー = ランタイムエラー(Runtime error) ザックリいうと、 構⽂エラーは、⽂法=構⽂(syntax)が正しくないコードが実⾏できない。 実⾏時エラーは、実⾏中に起きるエラー。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 5

Slide 6

Slide 6 text

構⽂エラー = シンタックスエラー 構⽂・⽂法(stntax)が正しくなくプログラムが実⾏できないエラー。 原則、構⽂エラーがあると、プログラムが実⾏されません。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 6

Slide 7

Slide 7 text

Rubyでの構⽂エラー = シンタックスエラーのエラー Rubyでの主なシンタックスエラー ブロックが、⾜りなかったり、対応できていない。 end が⾜りない。 波括弧 {} が対応できていない。 配列やハッシュの中にカンマに過不⾜がある。 変なところに記号や予約語がある。 ハッシュをブロックと勘違いされる。 解釈できない数値がある。ex) 0o80 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 7

Slide 8

Slide 8 text

構⽂エラーの例: ブロックの終わりの } を書き忘れる Ruby (1..3).each { |i| puts i ↓ Main.rb:2: syntax error, unexpected end-of-input, expecting '}' end-of-input はわかりにくいですが、「実⾏してるファイルの終わり」の意味。 全体を訳すと「Main.rbというファイルの2⾏⽬で、シンタックスエラーです︕ 予期せ ぬファイルの終端です、 } を期待していたのに」という意味。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 8

Slide 9

Slide 9 text

Rubyの構⽂エラーの例: 変なところに記号や予約語がある = ↓ Main.rb:1: syntax error, unexpected '=' (訳: 構⽂エラー、予期せぬ`=`) 変なところに記号や予約語があることによるエラーです。 記号1⽂字だけでもエラーの⽂が全然違ったりするので、試してみると⾯⽩いかもしれ ないです。例) @ , + , ' , / , % , = , : , ! Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 9

Slide 10

Slide 10 text

Rubyの構⽂エラーの例: doと|i|の位置を間違える 慣れてない頃、よくこうやって順番を間違えていた記憶 5.times |i| do end ↓ Main.rb:1: syntax error, unexpected `do' (訳: 構⽂エラー、予期せぬ`do`) 5.times |i| do ^~ 「unexexpected `|'」と表⽰されるべきな気がするが、「do」がでる。 エラーの箇所はわかるけど、エラー内容はちょっとわかりにくい気がする。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 10

Slide 11

Slide 11 text

Rubyの構⽂エラーの例: カンマが過剰 [,] ↓ Main.rb:1: syntax error, unexpected ',', expecting ']' 要素がないのに , が急に現れて、予期せぬ , となっている。 無駄なカンマがあるときに⾒られるエラー。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 11

Slide 12

Slide 12 text

Rubyの構⽂エラーの例: カンマが不⾜ p [1 2] ↓ Main.rb:1: syntax error, unexpected integer literal, expecting ']' p [1 2] ^ 要素の間の , が不⾜していて、予期せぬ整数(integer)があることによるエラー。 【余談】⽂字列の間に空⽩があっても、1つの⽂字列になります(何故?) "Hello, " "world!" #=> "Hello, world!" Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 12

Slide 13

Slide 13 text

Rubyの構⽂エラーの例: ⽂字列の囲い込み忘れ p 'Hello, world! ↓ Main.rb:1: unterminated string meets end of file p 'Hello, world! ⽂字列を囲み忘れたことによるエラー。 syntax errorだけど、エラー⽂にsyntax errorと表⽰されないパターン. エラー⽂を直訳すると「終了のない⽂字列が、ファイルの終わりに交わった」(?) Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 13

Slide 14

Slide 14 text

Rubyの構⽂エラーの例: ハッシュをブロックと勘違いされる これは、ちょっと有名なやつです。 p {"Ruby" => 1993, "C" => 1972} ↓ Main.rb:1: syntax error, unexpected =>, expecting '}' p {"Ruby" => 1993, "C" => 1972} ^~ ハッシュのつもりで {} を書いても、 ブロックの {} と勘違いされてエラーになります。 ※ p({~}) と引数を丸括弧で囲めば、ちゃんと動きます。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 14

Slide 15

Slide 15 text

8進数に関するシンタックスエラー p 0o10 #=> 8 p 010 #=> 8 p 080 # Invalid octal digit (訳: 有効でない8進数) Main.rb:3: Invalid octal digit p 080 ^~ Rubyでは、 0 始まりや 0o 始まりの数値は、8進数として解釈されます。 8進数は 0 〜 7 の数値で構成されるので、 8 や 9 があるとエラーになります。 ※多くの他⾔語でも、 0 か 0o のどちらかをサポートしています。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 15

Slide 16

Slide 16 text

File::Stat#modeの数値は8進数(lsコマンドの内部の数値) RubyのFile::Stat#modeで返ってくる数字について (by yupa-san) inode(7) - Linux manual page S_IFSOCK 0140000 socket # s S_IFLNK 0120000 symbolic link # l S_IFREG 0100000 regular file # - S_IFBLK 0060000 block device # b S_IFDIR 0040000 directory # d S_IFCHR 0020000 character device # c S_IFIFO 0010000 FIFO # p 左から、1桁⽬が「8進数であることを⽰す0」で、2, 3桁⽬がファイルのタイプ、その 次が特別なパーミッションで、残り3桁が普通のパーミッション。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 16

Slide 17

Slide 17 text

Ruby以外の8進数リテラルの扱い C, Java, Python 2 …… 0 始まりだと、8進数。 Rust, Swift, Crystal, Python 3 …… 0o と書く必要あり。 Crystal, Python 3 …… 0 始まりだと、sytanx error。 Rust, Swift …… 0 始まりだと、10進数。 JavaScript …… 0o も 0 も書けるが、 0 始まりの処理が特殊。 8 か 9 が含まれていると10進数となり、 0 〜 7 のみだと8進数になる。 昔からあるメジャーな⾔語CやJavaでは 0 始まりは8進数でしたが、わかりにくいし古 い表記といえそうなので、 0o 始まりで書いた⽅が良さそうです。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 17

Slide 18

Slide 18 text

Rubyの2進数のエラーが難しい 8進数に8や9が混ざると「 Invalid octal digit (訳: 有効でない8進数)」とわかりやすいエ ラー⽂がでるのに、2進数は異なっていて難しいです。 p 0b20101 ↓ Main.rb:1: numeric literal without digits p 0b20101 ^~ Main.rb:1: syntax error, unexpected integer literal, expecting end-of-input p 0b20101 ^~~~~ エラー⽂を訳すと「 0b は数字のない数値リテラルだ」と「構⽂エラー︓予期せぬ数値 リテラル 20101 だ、ファイルの終わりを期待してたのに」となる。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 18

Slide 19

Slide 19 text

実⾏時エラー = ランタイムエラー 構⽂エラーがなくコードが実⾏され始めて、実⾏中に起きるエラー。 実⾏時に起きるRubyの代表的なエラー(例外)のクラスを少し紹介していきます。 ArgumentError , TypeError Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 19

Slide 20

Slide 20 text

ArgumentError と TypeError この2つは、メソッドの引数が誤っているときの代表的なエラー。 ⼀般に、Argumentは「引数」、Typeは「型」で、よく使われる専⾨⽤語です。 なお、Rubyのこの⽂脈では、Typeは「型」というより「クラス」。 ArgumentError 引数の数が異なるときのエラー。 引数の数にもクラスにも問題ないが、期待しない性質のときのエラー。 その他: 引数がないパターン等 TypeError 引数の数は同じだけど、期待しないクラスのときのエラー。 その他: 引数がないパターン等 上記のような傾向があります。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 20

Slide 21

Slide 21 text

ArgumentError 主に2種類のエラーに⼤別されます。 引数の数が異なるパターン 引数の数にもクラスにも問題ないが、期待しない性質だったとき。 引数のクラスが異なるときは TypeError と別個の括りなのに、 ArgumentError に2種類のエラーがあるのは違和感……。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 21

Slide 22

Slide 22 text

ArgumentError : i) 引数が異なるとき エラー⽂が読めれば、ほぼ簡単に修正できるエラーです。 p 1024.to_s #=> "1024" p 1024.to_s(2) #=> "10000000000" p 1024.to_s(:delimited, locale: :fr) #=> ArgumentError ※Railsでは to_s が拡張され桁区切りを指定できますが、素のRubyは出来ません。 ↓ Main.rb:3:in `to_s': wrong number of arguments (given 2, expected 0..1) (ArgumentError) from Main.rb:3:in `' given 2, expected 0..1 は「2つの引数が与えられたけど、期待した個数は0~1個」の 意味ですね。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 22

Slide 23

Slide 23 text

【余談】引数の数の違うときのエラー⽂の歴史 p 1024.to_s(:delimited, locale: :fr) #=> ArgumentError ↓ Before (Ruby 〜2.2) wrong number of arguments (2 for 0..1) (ArgumentError) After (Ruby 2.3 〜 2.7) wrong number of arguments (given 2, expected 0..1) (ArgumentError) エラー⽂、だいぶわかりやすくなっている。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 23

Slide 24

Slide 24 text

ArgumentError : ii) 引数の数・クラス以外の性質に問題があるとき p [0] * 3 #=> [0, 0, 0] p [0] * -1 # negative argument (ArgumentError) Main.rb:2:in `*': negative argument (ArgumentError) from Main.rb:2:in `' プログラミング⾔語の中でも珍しい部類ですが、Rubyの演算⼦はメソッド。 Array (配列)のインスタンスメソッド * は引数に Integer を1つとって、 その引数の数だけ配列のサイズを倍にします。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 24

Slide 25

Slide 25 text

TypeError 主なパターンは、 引数の数に問題はないが、引数のクラスが異なるとき。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 25

Slide 26

Slide 26 text

TypeError i) String#+ "1" + 1 ↓ Main.rb:1:in `+': no implicit conversion of Integer into String (TypeError) String クラスのメソッド + は、⽂字列どうしを結合する⽬的で、あるべき引数は String クラスです。しかし、実際の引数は Integer の 1 で、内部で Integer を String に変換できるか検証され「 Integer から String への暗黙の変換はできない」 と⾔われています。 【余談】このケースでは、引数側に⽂字列に変換する to_str が実装されていれば、内 部で暗黙の変換を⾏われます。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 26

Slide 27

Slide 27 text

TypeError ii) integer#+ 1 + "1" ↓ Main.rb:1:in `+': String can't be coerced into Integer (TypeError) from Main.rb:1:in `' Integer と String を逆にすると、エラー⽂に聞き慣れない単語"coerced"がでてきま す。「 String は Integer に強制(的に変換)できなかった」みたいな意味。 マニアックな話ですが、数値クラスは異なるクラスの演算を⾏うときは、内部で coerce というメソッドを⽤いクラスを統⼀してから演算しています。 String クラス に coerce メソッドを実装してあげれば、エラーは解決します(!?) Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 27

Slide 28

Slide 28 text

ArgumentError , TypeError は、いい加減? Ruby の例外クラスは分類が粗すぎる or 細かすぎる - まめめも (2009/4/23) 実際、TypeError と ArgumentError の区別ってかなりいい加減に決められている ように感じます。 a = []; a << a a.flatten #=> tried to flatten recursive array (ArgumentError) (1...5.0).max #=> cannot exclude non Integer end value (TypeError) このように ArgumentError , TypeError は、引数がなくても⽣じます。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 28

Slide 29

Slide 29 text

最後に ご静聴ありがとうございました。 間違いがあったら教えて下さると嬉しいです。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 29

Slide 30

Slide 30 text

参考記事 - Rubyリファレンスマニュアル(通称るりま) Rubyリファレンスマニュアル ArgumentError (Ruby リファレンスマニュアル) TypeError (Ruby リファレンスマニュアル) Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 30

Slide 31

Slide 31 text

参考記事・参考書籍 『Ruby 超⼊⾨』 2-7「エラーメッセージを読み解く」 『プロを⽬指すためのRuby⼊⾨』(通称: チェリー本 ) 第11章 Ruby の例外クラスは分類が粗すぎる or 細かすぎる - まめめも Ruby のエラーメッセージを読み解く(初⼼者向け)その 1 - Qiita Ruby のエラーメッセージを読み解く(初⼼者向け)その 2 - Qiita どの8進数リテラルが使えるかはプログラミング⾔語によって異なる - Qiita Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 31

Slide 32

Slide 32 text

その他 本スライドは、Marp Nextで作成しました。 残りのページのスライドは、検証⽤などのメモです。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 32

Slide 33

Slide 33 text

JavaScriptの0始まりの8進数の不思議な挙動 JavaScript Node.js v12.18.3 console.log(080); // 80 console.log(010); // 8 console.log(0o10); // 8 console.log(0O10); // 8 console.log(0o10); // SyntaxError: Invalid or unexpected token JavaScriptは 0 始まりの処理が特殊。 0 始まりでも 8 か 9 が含まれているときは10進数 0 始まりで 0 〜 7 のみで構成されるときは8進数。 0o 始まりだと、必ず8進数で、 8 などがあると構⽂エラー。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 33

Slide 34

Slide 34 text

Pythonの8進数の挙動 Python 3.8.2 print(0o10) # 8 print(0O10) # 8 print(010) # SyntaxError: leading zeros in decimal integer literals # are not permitted; use an 0o prefix for octal integers Pythonは、2 -> 3にかけて 010 のような 0 始まりの8進数を構⽂レベルで禁⽌した。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 34

Slide 35

Slide 35 text

RustやSwiftでは、 0 始まりは10進数の扱い Rust fn main(){ let n = 010; println!("{}", n); } print(010) // 010 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 35

Slide 36

Slide 36 text

0始まりで書きたくなる状況は、⽂字列の⽅が良さそう birthday = 0107 breakfast = 0730 tel = 0120_0000_0000 post_code = 010_0000 こういう電話番号や郵便番号は、0始まりがあったり、計算するものでもなかったり、 様々な理由により、⽂字列で管理した⽅が良いと思われる。 【参考】invalid octal digit エラーが起きたとき - Qiita datetime: DateTime.new(2015,10,08,00,00,00) Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 36

Slide 37

Slide 37 text

numeric literal without digits Bug #2407: numeric literal without digits - Ruby master - Ruby Issue Tracking System 0o_, 0x_ などprefixの直後に _ が来た場合には、このエラーを意 図的に出しています。_というのは数値表現の数字と数字の間に⼊る もので、prefixと数字の間に⼊るものではない、と考えたからです。 「エラーメッセージがわかりにくい」とか「prefixと数値の間に _ が⼊って何が悪い」などのいう指摘は、今後考慮しないとは⾔いま せんが、少なくとも現時点ではこれは仕様です。 10年以上前の2009年のMatz⽒の発⾔。 0o_101 の⽅がわかりやすいような? ⾃分は書く機会がないけど、機会があったらハマる気がする。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 37

Slide 38

Slide 38 text

バッククォートとシングルクォートからなる引⽤符 Rubyのエラー⽂を⾒てると、引⽤符としてバッククォートとシングルクォートで囲ま れた処理が⾏われる。LATEXなどでは引⽤符は `hoge' と囲むもので、 ❛hoge❜ と表⽰し てくれるとのこと。もし ❜hoge❜ だと変ですよね。逆に、開始と終了で同じ記号を使う のは、プログラマの怠惰な⽅法なのだとか(?)。 Rubyのエラーをちょっと整理(初級者向け) 2020/10/24 38