Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

週刊Railsウォッチ: Ruby 3.1で多重代入の評価順が変更、Stimulusコンポーネントとベストプラクティスほか(20211222後編)

こんにちは、hachi8833です。今年最後の週刊Railsウォッチ後編をお送りします。

週刊Railsウォッチについて

  • 各記事冒頭には🔗でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • お気づきの点がありましたら@hachi8833までメンションをいただければ確認・対応いたします🙏

TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)

🔗Ruby

🔗 Ruby 3.1で多重代入の評価順が変更


つっつきボイス:「Ruby 3.1のリリースノートをチェックしていて、この変更を見つけました」


#4443より

「お、obj, obj.foo = obj.foo, objみたいなコードはめったに書かないと思いますが、Rubyの仕様↓に書かれているとおりの挙動にするなら改修が必要ということになるんでしょうね」「左から右に評価される方がたしかに自然」

参考: JISX3017:2013 プログラム言語Ruby

「この#4443はよく見ると11年前に立てられたものでした」「そんなに昔だったとは」「それをJeremy Evansさんが拾って実装したという流れでした↓」

参考: Evaluate multiple assignment left hand side before right hand side by jeremyevans · Pull Request #4390 · ruby/ruby

「Ruby内部のスタックの動きも書かれている↓」「Jeremyさんスゴい」「修正によって多重代入のパフォーマンスが落ちるらしいけど、こういう多重代入はめったに行われないだろうから大丈夫そうかな」「多重代入の評価順で挙動が変わるようなコードはめったに書かないでしょうね」「issueを上げたmameさんなら書きそう」

self                                      # putself
abc                                       # send
abc, self                                 # putself
abc, foo                                  # send
abc, foo, 0                               # putobject 0
abc, foo, 0, [bar, baz]                   # evaluate RHS
abc, foo, 0, [bar, baz], baz, bar         # expandarray
abc, foo, 0, [bar, baz], baz, bar, abc    # topn 5
abc, foo, 0, [bar, baz], baz, abc, bar    # swap
abc, foo, 0, [bar, baz], baz, def=        # send
abc, foo, 0, [bar, baz], baz              # pop
abc, foo, 0, [bar, baz], baz, foo         # topn 3
abc, foo, 0, [bar, baz], baz, foo, 0      # topn 3
abc, foo, 0, [bar, baz], baz, foo, 0, baz # topn 2
abc, foo, 0, [bar, baz], baz, []=         # send
abc, foo, 0, [bar, baz], baz              # pop
abc, foo, 0, [bar, baz]                   # pop
[bar, baz], foo, 0, [bar, baz]            # setn 3
[bar, baz], foo, 0                        # pop
[bar, baz], foo                           # pop
[bar, baz]                                # pop

🔗 Qeweney: 機能豊富なRuby向けHTTPリクエスト/レスポンスAPI(Ruby Weeklyより)


つっつきボイス:「Rackを改善したqeweneyというgemを作ってみたという記事だそうです」

digital-fabric/qeweney - GitHub

「qeweneyの読み方がわからない😅」「この図に表わされているものを改良した感じかな↓: 図を見る限りでは、Webアプリが受けるリクエストとHTTP/1やHTTP/2のアダプタを切り離しているんでしょうね」「ふむふむ」「Rackの内部はよくわからないけど、Rackでは切り離せないんじゃないかな」


同記事より

「インターフェイスは、respondで書くあたりとかがRackと違ってますね↓」

# 同記事より
# Rack
app = ->(env) do
  [
    200,
    {'Content-Type' => 'text/plain'},
    ['Hello, world!']
  ]
}

# Qeweney
app = ->(req) do
  req.respond('Hello, world!', 'Content-Type' => 'text/plain')
end

「こちらを見るとリクエストをRackに渡すこともできるみたい↓」「Qeweneyはまだ開発途中のようですが、Rackよりもパフォーマンスを優先して作っているらしい」

# redirect to another URL
req.redirect(alternative_url)

# redirect to HTTPS
req.redirect_to_https

# serve a static file
req.serve_file(file_path)

# serve from an IO
req.serve_io(io)

# serve from a Rack app
req.serve_rack(app)

# Upgrade to arbitrary protocol
req.upgrade(protocol)

🔗 regexp_parser: 正規表現パーサー(Ruby Weeklyより)

ammar/regexp_parser - GitHub


つっつきボイス:「正規表現を解析するRuby製パーサーだそうです」「どんなふうに使うんだろう?」「こじらせて読むのがつらくなった正規表現を解読するのに使うとかかな」「あるある」

# 同リポジトリより
require 'regexp_parser'

Regexp::Scanner.scan /(ab?(cd)*[e-h]+)/  do |type, token, text, ts, te|
  puts "type: #{type}, token: #{token}, text: '#{text}' [#{ts}..#{te}]"
end

# output
# type: group, token: capture, text: '(' [0..1]
# type: literal, token: literal, text: 'ab' [1..3]
# type: quantifier, token: zero_or_one, text: '?' [3..4]
# type: group, token: capture, text: '(' [4..5]
# type: literal, token: literal, text: 'cd' [5..7]
# type: group, token: close, text: ')' [7..8]
# type: quantifier, token: zero_or_more, text: '*' [8..9]
# type: set, token: open, text: '[' [9..10]
# type: set, token: range, text: 'e-h' [10..13]
# type: set, token: close, text: ']' [13..14]
# type: quantifier, token: one_or_more, text: '+' [14..15]
# type: group, token: close, text: ')' [15..16]

「そういえば正規表現を解析してくれるregex101というWebサービスがありますね↓」「これめちゃ愛用しています」「こんなのがあるんですね」

参考: regex101: build, test, and debug regex

「regex101に正規表現を入れるといい感じに解析して、リファレンスも表示してくれる」「正規表現をステップ実行できるのもありがたいです🙏」「regex101はRubyの正規表現(Onigmo)には対応していないのか...」「RubularならRubyの正規表現をチェックできますよ↓」

参考: Rubular: a Ruby regular expression editor

k-takata/Onigmo - GitHub

はじめての正規表現とベストプラクティス1: 基本となる8つの正規表現

その他Ruby

つっつきボイス:「_ko1さんのこのツイートがとても面白かった」

「JSONで表現可能なハッシュをRubyでシリアライズしてからデシリアライズしてハッシュとして取り込むのがどれが一番速かったかをテストしてみたら、最速はmsgpackでしたが、JSONモジュールが意外に速かったという話↓」「へ〜、JSONやるな〜」「自分はMarshalが最速だと思っていたけどそうでもないんだなと気付かされました」

# ruby 3.1.0dev (2021-12-13T05:04:19Z fix_local_tp_memor.. 7ad3e2a982) [x86_64-linux]

                 user     system      total        real
JSON         4.942976   0.059088   5.002064 (  5.002097)
msgpack      4.146010   0.039891   4.185901 (  4.185935)
eval        13.473455   0.080030  13.553485 ( 13.553678)
Marshal      7.512279   0.110032   7.622311 (  7.622328)

msgpack/msgpack-ruby - GitHub

参考: module JSON (Ruby 3.0.0 リファレンスマニュアル)
参考: module Marshal (Ruby 3.0.0 リファレンスマニュアル)

「追加されたコメントを見ると、ファイルサイズはMarshalのが一番小さいのね↓」

$ ls h* -hl
-rw-rw-r-- 1 ko1 ko1 207K Dec 15 16:00 h.iseq
-rw-rw-r-- 1 ko1 ko1 249K Dec 15 16:00 h.json
-rw-rw-r-- 1 ko1 ko1 202K Dec 15 16:00 h.marshal
-rw-rw-r-- 1 ko1 ko1 204K Dec 15 16:00 h.msgpack
-rw-rw-r-- 1 ko1 ko1 254K Dec 15 16:00 h.rson

「お、I/OをなくすとMarshalがJSONに近づいてる↓」「iseq.dumpは遅いけどiseq.evalは速いのも面白い」

                 user     system      total        real
JSON         4.603379   0.008869   4.612248 (  4.612306)
msgpack      4.016187   0.009970   4.026157 (  4.026212)
eval        13.732086   0.050009  13.782095 ( 13.782156)
iseq.eval    2.844302   0.010015   2.854317 (  2.854358)
Marshal      5.147343   0.009985   5.157328 (  5.157333)

🔗クラウド/コンテナ/インフラ/Serverless

🔗 Google Cloud SpannerがRailsのActive Recordに対応(Publickeyより)


つっつきボイス:「お〜、このアダプターはGoogle公式なのがいいですね👍」「ほんとだ」「公式だとそれだけで導入しやすいんですよ」

googleapis/ruby-spanner-activerecord - GitHub

# 同リポジトリより
development:
  adapter: "spanner"
  project: "<google project name>"
  instance: "<google instance name>"
  credentials: "<google credentails file path>"
  database: "app-dev"

参考: Cloud Spanner  |  Google Cloud

「Active RecordからSpannerにアクセスできるということなんですね」「制約を見るとカラムでDEFAULTが使えないとあるけど、SpannerにそもそもDEFAULTがないのね」「テーブルは主キーが必須か」「Railsのadd_indexでフィールド長を指定できないらしい」「この辺はCloud Spannerからくる制約なんでしょうね」

参考: Cloud Spannerの主キーの設計. Spannerがパフォーマンスを発揮するには主キーの設計が非常に重要です。そこで… | by Toyohito Murooka | google-cloud-jp | Medium
参考: add_index -- ActiveRecord::ConnectionAdapters::SchemaStatements

「公式なら使ってみようかなという気持ちになりますね: ちなみにoracle-enhancedアダプタ↓はよく使われていて実績もあるけど公式ではないんですよ」

rsim/oracle-enhanced - GitHub

🔗JavaScript

🔗 Stiumulus関連のサイト2つ

stimulus-components/stimulus-components - GitHub


つっつきボイス:「Rails 7でStimulusが正式に導入されたので、Stimulusの情報を掲載しているサイトをいくつか見つけました」「Stimulusのコンポーネントリストと、よいStimulusの書き方ですね」「コンポーネントによってはデモサイトもあって↓、Bootstrapのコンポーネントリスト的な感じなのがなかなかよさそう👍」

参考: Stimulus Animated Number
参考: Stimulus Chartjs

参考: Components · Bootstrap

StimulusのChartjsは普通に本家Chartjsを取り入れているけどバージョンは2.9.32か: ちょうどさっき調べていたんですが、Chartjsの最新は3.6.2で、2系で書かれたチャートがAPIレベルで互換性がなくて動かなかったんですよ」「なるほど、3.xは別物な感じですね」「チャートを作り込んでからチャートライブラリで非互換が発生するとつらい😢」

参考: Chart.js | Open source HTML5 Charts for your website


「もうひとつのBetter StimulusJSは↓、Stimulusのベストプラクティスを紹介しています」「こちらは個人っぽいですね」「上のStimulusコンポーネントサイトも公式っぽく見えたけどどうやら個人っぽいかも」

julianrubisch/better-stimulus - GitHub


ちなみに本家Stimulusのリポジトリは以下です↓。

hotwired/stimulus - GitHub


後編は以上です。来年もTechRachoと週刊Railsウォッチをどうぞよろしくお願いします。

バックナンバー(2021年度第4四半期)

週刊Railsウォッチ: Rails 7リリース、5.2系と6.0.x系のサポート終了時期決定、localhost gemで自己署名証明書生成ほか(20211221前編)

今週の主なニュースソース

ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。

Ruby Weekly

Publickey

publickey_banner_captured


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。