Slide 1

Slide 1 text

【オンライン開催】Burikaigi2021 【オンライン開催】Burikaigi2021 Ruby 2.0 から Ruby 3.0 を Ruby 2.0 から Ruby 3.0 を 駆け⾜で振り返る 駆け⾜で振り返る

Slide 2

Slide 2 text

アジェンダ アジェンダ ⾃⼰紹介 Ruby とは Ruby 2.0 以前の歴史 Ruby 2.0 ~ 3.0 までを振り返る どういう機能が追加されてきたのかを振り返ってみる 最近のモダンな機能紹介‧デモ Ruby 2.7, 3.0 の機能紹介 まとめ

Slide 3

Slide 3 text

⾃⼰紹介 ⾃⼰紹介 名前:osyo Twitter : github : ブログ : 趣味で Ruby にパッチを投げている Ruby 2.5 ~ 3.0 まで何らかのパッチ投げてるぞい… Ruby 基礎⽂法最速マスターって記事を書いたので Ruby が気になる ⼈は読んでみてね!!! オンライン勉強会が多いので去年はあちこちの勉強会に参加 @pink_bangbi osyo-manga Secret Garden(Instrumental) 令和時代の Ruby 基礎⽂法最速マスター Fukuoka.rb Hamada.rb kawasaki.rb nikotama.rb Sendai.rb Shibuya.rb Shinjuku.rb Tama.rb Toyama.rb Gotanda.rb Entaku.rb Grow.rb Hamamatsu.rb kanazawa.rb Kobe.rb Machida.rb mitaka.rb Ruby Tuesday toruby ⻄⽇暮⾥.rb

Slide 4

Slide 4 text

わたしと Ruby わたしと Ruby Ruby 1.8,1.9 :はじめて Ruby を知る eval こわい、と思っていた記憶 Ruby 2.1 :初めて Ruby を書き始める チャットボットを Ruby でつくってた Ruby 2.2 :Ruby をガッツリ触り始める メタプログラミングで遊びまくっていた Ruby 2.4 :Ruby 本体にパッチを投げ始める 開発中の Ruby 2.5 に投げた が取り込まれた Ruby 2.5 :お仕事で Ruby を使い始める ここで初めて Rails を本格的に使い始める Ruby 2.6, 2.7, 3.0 :毎バージョンごとにパッチを投げる 最近は細々したバグ修正パッチが多い… 最近:気になった Ruby の開発チケットをブログにまとめたりしてる メソッド追加のパッチ https://secret-garden.hatenablog.com/archive/category/bugs.ruby

Slide 5

Slide 5 text

Ruby とは Ruby とは

Slide 6

Slide 6 text

まつもとゆきひろ(通称:matz )が開発したオブジェクト指向⾔語 強い動的型付け⾔語 Perl や Smalltalk 、Lisp の影響を受けている プリミティブな型も含めてすべてがオブジェクトとして扱われる コードを書いていて『楽しい‧気持ちがいい』をコンセプトに⾔語 設計されている MRI (Matz Ruby Interpreter )がいわゆる Ruby と呼ばれる処理系 他には JVM 上で動作する JRuby や 組み込み向けの軽量な mruby などが存在している 実務では主に Web フレームワークの Ruby on Rails で利⽤されている Ruby は死んだ? まだ⽣きてるよ!! 去年の 2020 年12 ⽉25 ⽇に Ruby 3.0 がリリース Ruby とは Ruby とは

Slide 7

Slide 7 text

Ruby 2.0 以前の歴史 Ruby 2.0 以前の歴史

Slide 8

Slide 8 text

Ruby 2.0 以前の歴史 Ruby 2.0 以前の歴史 1993 年:Ruby が誕⽣( 開発が開始) 1995 年:Ruby が発表 1996 年:Ruby 1.0 がリリース 2003 年:Ruby 1.8 がリリース 2004 年:Ruby on Rails が公開 2005 年:Ruby on Rails 1.0 がリリース 2007 年:Ruby 1.9.0 がリリース ここで初めて YARV と呼ばれる仮想マシンが導⼊された 1.8 までは AST をインタラクティブに実⾏していた 1.9 からはバイトコードに置き換えて実⾏している 2009 年:Ruby 1.9.1 がリリース 1.9 系の初めての安定版 2011 年:JIS 規格(JIS X 3017 )が制定 2012 年:ISO/IEC 規格(ISO/IEC 30170 )として承認 2013 年:Ruby 2.0 がリリース

Slide 9

Slide 9 text

Ruby 2.0 ~ 3.0 までを振り返る Ruby 2.0 ~ 3.0 までを振り返る

Slide 10

Slide 10 text

Ruby 2.0 Ruby 2.0 : キーワード引数の追加 正規表現エンジンとして⿁⾞の fork である Onigumo( ⿁雲) を採⽤ デフォルトのスクリプトエンコーディングが UTF-8 に変更 以前は US-ASCII だった デバッグ⽤のトレース機能として TracePoint API が追加 クラスが定義されたときやメソッドが呼ばれたタイミングなどで 任意の処理をフックすることができる機能 この機能を利⽤して profile などが実装されている 2013/02/24 にリリース NEWS # ラベル: でキーワード引数を定義 def log(msg, level: "ERROR") puts "[#{ level }] #{ msg }" end log("OK") # => [ERROR] OK log("NG", level: "WARNING") # => [WARNING] NG

Slide 11

Slide 11 text

Ruby 2.0 続き Ruby 2.0 続き 継承リストの先頭にモジュールを追加する Module#prepend メソッド が追加 module NameIs def name "name is #{super}" end end class Homu # prepend すると先に NameIs のメソッドが呼ばれる prepend NameIs def name "homu" end end # Homu の継承リスト p Homu.ancestors # => [NameIs, Homu, Object, Kernel, BasicObject] p Homu.new.name # => "name is homu"

Slide 12

Slide 12 text

Ruby 2.0 続き Ruby 2.0 続き Refinements が実験的に実装 特定のファイルでのみクラス拡張が反映される 参照 module StringEx # refine を使って String に新しいメソッドを定義する refine String do def twice self + self end end end # using したファイルでのみ String#twice が使える using StringEx p "homu".twice Ruby 2.0.0 リリース特集 Ruby 2.0.0 の注意点やその他の新機能

Slide 13

Slide 13 text

Ruby 2.1 Ruby 2.1 : Ruby 2.0 で実験的に追加された Refinements が正式に採⽤ ファイルだけではなくて class の中でも using できるようになった キーワード引数でデフォルト値を省略できるように変更 Ruby 2.0 ではデフォルト値が必須だった 新しい整数リテラルとして r と i が追加 メソッドを定義する def がメソッド名のシンボルを返すように変更 参照: 2013/12/25 にリリース NEWS p 42r.class # => Rational p 42i.class # => Complex method_name = def twice(value:) value + value end p method_name # => :twice NEWS for Ruby 2.1.0 (Ruby 3.0.0 リファレンスマニュアル)

Slide 14

Slide 14 text

Ruby 2.2 Ruby 2.2 : シンボルのガベージコレクトを実装 以前はシンボルが解放されずに残ったままになり、⼤量にリクエ ストが投げられて新しいシンボルが⽣成され続けてメモリが枯渇 する問題があった 参照: nil / true / false オブジェクトが frozen 化 Hash リテラルのキーでクオートが使えるように変更 参照: 2014/12/25 にリリース NEWS ( 翻訳) Ruby 2.2 のシンボル GC { "hoge": 1 } # => {:hoge=>1} { "#{"foo" + "bar"}": 1 } # => {:foobar=>1} NEWS for Ruby 2.2.0 (Ruby 3.0.0 リファレンスマニュアル)

Slide 15

Slide 15 text

Ruby 2.3 Ruby 2.3 : Frozen String Literal プラグマコメントが追加 safe navigation operator( 通称ぼっち演算⼦ &. ) が追加 did_you_mean gem が標準ライブラリに追加 2015/12/25 にリリース NEWS # frozen_string_literal: true # ⽂字列リテラルがデフォルトで frozen 化される p "hoge".frozen? # => true # レシーバが nil の場合はメソッドは呼ばれずに nil を返す p nil&.hoge # => nil p "hoge".cahrs # output: # error: undefined method `cahrs' for "hoge":String (NoMethodError) # Did you mean? chars # chr

Slide 16

Slide 16 text

Ruby 2.3 続き Ruby 2.3 続き Hash#dig / Array#dig メソッドが追加 インデントを取り除いてくれるヒアドキュメントの記法が追加 参照: user = { address: { tel: [111, 2222, 3333] } } # ネストしてる値を 1 回で取得する # user[:address][:tel][2] を dig メソッドで取得できる p user.dig(:address, :tel, 2) # => 3333 # キーがない場合はその時点で探索を終了して nil を返す p user.dig(:address, :tel2, 2) # => nil # ヒアドキュメント内でインデントしても先頭のインデントのスペースは追加 されない str = <<~EOS homu mami saya mado EOS p str.split("\n") # => ["homu", "mami", " saya", "mado"] サンプルコードでわかる!Ruby 2.3 の主な新機能

Slide 17

Slide 17 text

Ruby 2.4 Ruby 2.4 : ハッシュテーブルの内部実装が変更されて⾼速化された 詳細: Fixnum クラスと Bignum クラスが Integer クラスに統合 基本的に整数は Fixnum で扱われているが極端に値が⼤きい、⼩ さい時に Bignum を利⽤していた コード上で対話環境を起動することができる binding.irb が実装 参照: 2016/12/25 にリリース NEWS PHP とPython とRuby の連想配列のデータ構造が同時期に同 じ⽅針で性能改善されてた話 - hnw の⽇記 def plus(a, b) result = a + b # この処理が呼ばれた時に対話環境が起動する # 対話環境内でローカル変数などが参照できる binding.irb return result end サンプルコードでわかる!Ruby 2.4 の新機能と変更点

Slide 18

Slide 18 text

Ruby 2.5 Ruby 2.5 : pp が⾃動ロードされるように変更 require "pp" と書かずによくなった rescue/else/ensure が do/end ブロック内にも直接書けるように変更 トップレベルの定数探索の仕組みが変更 2017/12/25 にリリース NEWS # do ~ ensure ~ end をまとめてかける hoge do # ... ensure # ... end class User; end class Address; end # 2.4 まではトップレベルの定数まで探索されてしまっていた p Address::User # 2.4 => User # 2.5 => error: uninitialized constant Address::User (NameError)

Slide 19

Slide 19 text

Ruby 2.5 続き Ruby 2.5 続き Kernel#yield_self メソッドが追加 Hash#slice メソッドが追加 キーワード引数で Struct の初期化ができるように設定を追加 # レシーバを受け取ってブロックの結果を返すメソッド p 42.yield_self { |a| a.to_s + a.to_s } # => "4242" homu = { id: 1, name: "homu", age: 14 } # 指定したキーの要素のみを返す p homu.slice(:name, :age) # => {:name=>"homu", :age=>14} # keyword_init: true にすると User = Struct.new(:name, :age, keyword_init: true) # ここでキーワード引数を使って初期化できる homu = User.new(name: "homu", age: 14) サンプルコードでわかる!Ruby 2.5 の主な新機能と変更点 Part 1

Slide 20

Slide 20 text

終端なし Range リテラルを追加 (1..) のように終端を省略して Range リテラルを定義できる JIT コンパイラが導⼊ ⾃動的に YARV のバイトコードからバイナリコードに変換して⾼ 速に動作させる仕組み bundler が default gems として追加 これによりデフォルトで bundle コマンドが使えるようになった Ruby コードの抽象構⽂⽊を扱うライブラリが実験的に追加 Kernel#yield_self の別名として #then が追加 #select / #select! の別名として #filter / #filter! が追加 Proc を関数合成する Proc#<< と Proc#>> が追加 参照: Ruby のJIT コンパイラを理解したい!rubykaigi の⾹りを添えて プロと読み解く Ruby 2.6 NEWS ファイル

Slide 21

Slide 21 text

Ruby 2.7 Ruby 2.7 : パターンマッチ構⽂が実験的に導⼊ irb のサポートが強化 コンパクション GC を導⼊ ⼿動で GC.compact メソッドを呼ぶことでコンパクションを⾏う Ruby 3.0 で⾏われるキーワード引数の⾮互換対応の前準備 ⾮互換になる書き⽅をすると警告が出るように対応 (..10) のように先端なし Range リテラルを追加 2019/12/25 にリリース NEWS # 5 以下 を Range で表現して探索するようなことができる p (1..10).grep(..5) # => [1, 2, 3, 4, 5]

Slide 22

Slide 22 text

Ruby 2.7 続き Ruby 2.7 続き 改⾏を含むメソッドチェインをコメントアウト可能に対応 デフォルトのブロックの仮引数として Numbered Parameters が導⼊ (通称ナンパラ) 引数をフォワードする (...) 記法を追加 hoge # ここでコメントアウトできるようになった # .foo .bar # _1 が第⼀引数、_2 が第⼆引数を参照する plus = proc { _1 + _2 } plus.call 1, 2 # => 3 p (20..30).map { _1.to_s(16) } # => ["14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e"] def foo(...) # foo の引数をそのまま bar にフォワードする bar(...) end

Slide 23

Slide 23 text

Ruby 2.7 続き Ruby 2.7 続き Enumerable#tally が追加 Enumerable#filter_map を追加 参照: # 配列の要素数とその要素を Hash として返す ["a", "b", "c", "b"].tally #=> {"a"=>1, "b"=>2, "c"=>1} # ブロックの戻り値が偽なら結果から取り除く p (1..10).filter_map { _1 + _1 if _1.even? } # => [4, 8, 12, 16, 20] プロと読み解くRuby 2.7 NEWS

Slide 24

Slide 24 text

Ruby 3.0 Ruby 3.0 : Ruby 3.0 は Ruby 2.0 と⽐較して3 倍早くすることを⽬標にしてきた 「Optcarrot ベンチマーク」では JIT コンパイル時に 3 倍早くなっ ており⽬標を達成できた パターンマッチが正式に採⽤ 並列処理をサポートする Ractor ライブラリが実験的に追加 型のサポートを⾏う RBS と TypeProf の 2 つのライブラリが追加 キーワード引数の⾮互換な変更 詳しくは 右代⼊が追加 エンドレスメソッド定義が追加 正規表現リテラルや Range リテラルがデフォルトで frozen 化 参照: 2020/12/25 にリリース NEWS こちら プロと読み解く Ruby 3.0 NEWS - クックパッド開発者ブログ Ruby 3.0 Advent Calendar 2020

Slide 25

Slide 25 text

最近のモダンな機能紹介‧デモ 最近のモダンな機能紹介‧デモ

Slide 26

Slide 26 text

パターンマッチ パターンマッチ Ruby 2.7 で実験的に⼊って 3.0 で正式に導⼊された case expr; in pattern; end という書き⽅になる # 各要素ごとに in で条件(型)を指定できる # その要素を => で変数に束縛できる # * で複数の要素を受け取ることも可能 # マッチしなかったら else 節にくる # マッチしなくて else 節がなければ例外 case [1, "homu", 14] in [Integer, String => name, Integer => age] { name: name, age: age } in [Integer, Integer => age, String => name] { name: name, age: age } in [first, *middle, last] middle in [] [] else {} end

Slide 27

Slide 27 text

パターンマッチ 続き パターンマッチ 続き Hash 形式でも記述できる キーの要素ごとに条件を指定できる def check(user) case user # age が 20 未満 in { name:, age: (..20) } "#{name} は魔法少⼥です" # age が 20 以上 in { name:, age: (20..) } "#{name} は魔法少⼥ではありません" # それ以外 else " わからない" end end p check({ name: " ほむ", age: 14 }) # => " ほむは魔法少⼥です" p check({ name: " マミ", age: 30 }) # => " マミは魔法少⼥ではありません" p check([" まどか", 14]) # => " わからない"

Slide 28

Slide 28 text

1 ⾏ in ( 実験的) 1 ⾏ in ( 実験的) パターンマッチを 1 ⾏でかける構⽂ これは Ruby 3.0 では実験的な機能になる 使⽤すると実験的な警告が出るので注意 Ruby 2.7 でも使⽤できるが挙動がちょっと違うので注意 # これは普通のパターンマッチ case user in { name: String, age: (..20) } end # 上のパターンマッチが 1 ⾏でかける # マッチしてたら true を返し、そうでなければ false を返す # warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby! user in { name: String, age: (..20) }

Slide 29

Slide 29 text

1 ⾏ in ( 実験的) 続き 1 ⾏ in ( 実験的) 続き 1 ⾏ in は真理値を返すので if ⽂などの条件式として利⽤できる user = { name: "mami", age: 30 } # 条件分岐をより細かく記述できる if user in { name: String, age: (..20) } puts "OK" else puts "NG" end users = [ { name: "homu", age: 14 }, { name: "mami", age: 15 }, { name: "mado", age: 14 } ] # こんな感じで _1 と併⽤するとより簡潔に要素の絞り込みができる pp users.select { _1 in { name: /^m/, age: (..15) } } # => [{:name=>"mado", :age=>14}]

Slide 30

Slide 30 text

右代⼊ ( ⼀部実験的) 右代⼊ ( ⼀部実験的) 左辺の値を右辺の変数に代⼊する構⽂ コードは通常左から右に向かって記述する、その流れのまま代⼊式 を書くことができるので気持ちよくコードがかける # 左辺の値を右辺の変数に代⼊する 42 => value # 左からコードを書いてそのまま変数に代⼊できる (1..10).select { _1.even? }.map { _1 + _1 } => result pp result # => [4, 8, 12, 16, 20] # ちなみにインスタンス変数やグローバル変数には代⼊できないので注意 # error: syntax error, unexpected instance variable 1 => @value 2 => $value

Slide 31

Slide 31 text

右代⼊ ( ⼀部実験的) 続き 右代⼊ ( ⼀部実験的) 続き この右代⼊はパターンマッチを利⽤している なので Hash の要素をの中⾝を直接受け取ることができる この書き⽅は Ruby 3.0 では実験的な警告が出るので注意 user = { name: "mami", age: 15 } # パターンマッチのように特定のキーの要素を束縛できる user => { name:, age: } pp name # => "mami" pp age # => 15 # もっと厳密にパターンを書くこともできる user => { name: String => name, age: (..20) => age } pp name pp age # in とは違いパターンにマッチしなかったら例外が発⽣する user => { name: Integer } # => raise NoMatchingPatternError

Slide 32

Slide 32 text

エンドレスメソッド定義 エンドレスメソッド定義 1 ⾏でメソッドが定義できるようになった end を書かなくてメソッドが定義できるのでエンドレスメソッド 元々は だったのが matz の意向ではいっち ゃったエイプリルフールネタ # end を書かずにメソッドが定義できる # 引数がある場合は () は省略できないので注意 def twice(a) = a + a p twice 42 # => 84 # 引数がない場合は () は省略できる def value = 42 # また = 付きメソッドは定義できないので注意 # error: setter method cannot be defined in an endless method definition def value=(value) = @value = value

Slide 33

Slide 33 text

Ractor ( 実験的) Ractor ( 実験的) Ractor は Ruby で並列処理を⾏うためのライブラリ Ruby + Actor の略 Ruby 3.0 では実験的な機能でまだちょっと不安定 CPU のコアごとに独⽴した処理を実⾏できる 基本的に処理ごとにメモリ領域は共有せず、よりスレッドセーフな 実装になっている 参照: Ruby 3.0 の Ractor を⾃慢したい - クックパッド開発者ブログ Ruby の Ractor で ActiveObject を作る Ruby に So ware Transactional Memory (STM) を⼊れようと思った 話 - クックパッド開発者ブログ

Slide 34

Slide 34 text

Ractor ( 実験的) 続き Ractor ( 実験的) 続き Ractor デモ # Ractor.new のブロックが並列処理として実⾏される # .new の引数をブロックの引数として受け取る事ができる ractor = Ractor.new(10) do |loop_count| loop_count.times do puts :hello sleep 0.3 end end # 並列処理が終了するまでブロッキングする # p ractor.take 10.times do puts :world sleep 0.3 end

Slide 35

Slide 35 text

型周りのサポート 型周りのサポート Ruby 3.0 では Ruby の型情報を記述するために RBS を利⽤する .rbs ファイルに Ruby のような構⽂で型情報を記述する Ruby 3.0 ではこの RBS をサポートするライブラリが追加された RBS: .rbs ファイルや RBS ⾃体を扱うライブラリ TypeProf: Ruby コードを解析して .rbs を⾃動⽣成するライブラリ また Ruby 3.0 時点では標準では型チェックを⾏う機能は⼊らない steep という外部ライブラリで .rbs を使った型チェックを⾏うこ とができる 参照: TypePorf デモ Ruby 3 の静的解析ツール TypeProf の使い⽅ - クックパッド開発者 ブログ Ruby 3 の静的解析機能のRBS 、TypeProf 、Steep 、Sorbet の関係に ついてのノート - クックパッド開発者ブログ

Slide 36

Slide 36 text

最近の irb 事情 最近の irb 事情 Ruby 2.7 以前では GNU Readline で対話環境を実装していた Ruby の標準ライブラリにも readline がある Ruby 2.7 では GNU Readline をピュア Ruby で実装した reline というラ イブラリが開発され irb はそれを利⽤するように改良された これにより Ruby 2.7 以降では以下のような機能が irb で利⽤できるよ うになった 複数⾏編集機能 シンタックスハイライト 簡単なコード補完 リファレンスの参照機能 Ruby 3.0 では measure 機能が追加された 実⾏時間が簡単に計測できるようになる gem install stackprof すると measure :stackprof でメソッドのプロ ファイリングも⾏われる 参照:IRB’s Built-in Measure | Jemma Issroff

Slide 37

Slide 37 text

まとめ まとめ

Slide 38

Slide 38 text

まとめ まとめ Ruby が誕⽣してから今年で28 年になる Ruby が死んだと毎年⾔われているががんばって開発されている ちゃんと⽣きてるんじゃあ 特に近年では新しい構⽂などが取り込まれる傾向にある わたしはまだ Ruby を使い始めて浅いのでスライドを書いてて昔の Ruby について知ることができてよかった ⾃分が使っている⾔語がどのように開発されているのか調べてみる と⾊々と学びがある そのが機能が追加された背景とか調べてみたりすると楽しい Ruby は書いてて気持ちがよいのでぜひぜひ触ってみましょう!

Slide 39

Slide 39 text

参照 参照 Ruby とは Rubyist Hotlinks 【第 1 回】 まつもとゆきひろさん まつもとゆきひろの履歴書|仕事中にこっそり作ったRuby が世界を 驚かせるまで - ぼくらの履歴書|トップランナーの履歴書から「仕 事⼈⽣」を深掘り! まつもと× 笹⽥、Ruby 1.9 を語る − @IT これからの Ruby と今の Ruby について - Speaker Deck 12 ⽉25 ⽇にリリースされる Ruby 3.0 に備えよう! - Speaker Deck

Slide 40

Slide 40 text

ご清聴 ご清聴 ありがとうございました ありがとうございました