Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby 2.0 から Ruby 3.0 を駆け足で振り返る

osyo
January 30, 2021

Ruby 2.0 から Ruby 3.0 を駆け足で振り返る

【オンライン開催】Burikaigi2021 の登壇資料です。
https://toyama-eng.connpass.com/event/198500/

osyo

January 30, 2021
Tweet

More Decks by osyo

Other Decks in Programming

Transcript

  1. アジェンダ アジェンダ ⾃⼰紹介 Ruby とは Ruby 2.0 以前の歴史 Ruby 2.0

    ~ 3.0 までを振り返る どういう機能が追加されてきたのかを振り返ってみる 最近のモダンな機能紹介‧デモ Ruby 2.7, 3.0 の機能紹介 まとめ
  2. ⾃⼰紹介 ⾃⼰紹介 名前: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
  3. わたしと 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
  4. まつもとゆきひろ(通称: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 とは
  5. 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 がリリース
  6. 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
  7. 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"
  8. 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 の注意点やその他の新機能
  9. 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 リファレンスマニュアル)
  10. 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 リファレンスマニュアル)
  11. 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
  12. 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 の主な新機能
  13. 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 の新機能と変更点
  14. 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)
  15. 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
  16. 終端なし 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 ファイル
  17. 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]
  18. 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
  19. 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
  20. 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
  21. パターンマッチ パターンマッチ 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
  22. パターンマッチ 続き パターンマッチ 続き 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]) # => " わからない"
  23. 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) }
  24. 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}]
  25. 右代⼊ ( ⼀部実験的) 右代⼊ ( ⼀部実験的) 左辺の値を右辺の変数に代⼊する構⽂ コードは通常左から右に向かって記述する、その流れのまま代⼊式 を書くことができるので気持ちよくコードがかける #

    左辺の値を右辺の変数に代⼊する 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
  26. 右代⼊ ( ⼀部実験的) 続き 右代⼊ ( ⼀部実験的) 続き この右代⼊はパターンマッチを利⽤している なので

    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
  27. エンドレスメソッド定義 エンドレスメソッド定義 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
  28. Ractor ( 実験的) Ractor ( 実験的) Ractor は Ruby で並列処理を⾏うためのライブラリ

    Ruby + Actor の略 Ruby 3.0 では実験的な機能でまだちょっと不安定 CPU のコアごとに独⽴した処理を実⾏できる 基本的に処理ごとにメモリ領域は共有せず、よりスレッドセーフな 実装になっている 参照: Ruby 3.0 の Ractor を⾃慢したい - クックパッド開発者ブログ Ruby の Ractor で ActiveObject を作る Ruby に So ware Transactional Memory (STM) を⼊れようと思った 話 - クックパッド開発者ブログ
  29. 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
  30. 型周りのサポート 型周りのサポート 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 の関係に ついてのノート - クックパッド開発者ブログ
  31. 最近の 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
  32. まとめ まとめ Ruby が誕⽣してから今年で28 年になる Ruby が死んだと毎年⾔われているががんばって開発されている ちゃんと⽣きてるんじゃあ 特に近年では新しい構⽂などが取り込まれる傾向にある わたしはまだ

    Ruby を使い始めて浅いのでスライドを書いてて昔の Ruby について知ることができてよかった ⾃分が使っている⾔語がどのように開発されているのか調べてみる と⾊々と学びがある そのが機能が追加された背景とか調べてみたりすると楽しい Ruby は書いてて気持ちがよいのでぜひぜひ触ってみましょう!
  33. 参照 参照 Ruby とは Rubyist Hotlinks 【第 1 回】 まつもとゆきひろさん

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