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

週刊Railsウォッチ: ShopifyのYJIT記事、RubyGemsのgem execコマンドほか(20230202後編)

こんにちは、hachi8833です。

週刊Railsウォッチについて

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

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

🔗Ruby

🔗 Ruby 3.2のYJITはproductionで使えるレベル(Ruby Weeklyより)


つっつきボイス:「Shopifyの記事で、YJIT開発の中心メンバーであるMaxime Chevalier-Boisvertさん↓の記事です」「ShopifyはRubyに多くの技術投資を行ってきていて、YJITもそのひとつとしてフィーチャーされていますよね」

YJIT: CRuby向けの新しいJITコンパイラを構築する(翻訳)

以下は同記事で引用されていたツイートです↓

「ところで、Ruby 3.2のYJITベンチマーク記事の中でNoah GibbsさんのMastdonでの発言が引用されていて、現在のYJITデフォルト設定はメソッドが30回呼ばれると最適化するので、単体テストではYJITをオフにしておく方がよさそうとのことです↓」「お、なるほど」

参考: Benchmarking Ruby 3.2 with YJIT - by Peter Solnica

@solnic @joeldrapper デフォルトではYJITは30回呼び出されたメソッドを最適化する(この値はコマンドラインのパラメータで変更可能)。しかしメソッドの利用頻度が高くない場合はYJITはあまり有効でないので、単体テストでのYJITの利用は原則としておすすめしない。
Noah Gibbs

Benchmarking Ruby 3.2 with YJIT - by Peter Solnicaの引用より

「30回実行すると最適化が効くみたいな動作は、もしかすると状況によってはテストが不安定になるかもしれませんね: たとえばテストコード内でRailsのActive SupportのTime.currentを2回連続で実行したときに、YJITが無い場合は安定して少し進んだ時刻が返るけど、YJITが効いた場合には間の処理が早くなって同じ時刻が返るかもしれない、みたいなことはあり得るかも」「あ、そうか」「まあそもそもそういうテストコードはtravelを使って適切に記述すべきという話でもありますが」

参考: Rails API current -- Time

🔗 polars-ruby: 高速なカラム指向データライブラリPolarsのRubyラッパー

ankane/polars-ruby - GitHub


つっつきボイス:「これはruby-jp Slackで知りました: 以前も話題にしたApache Arrow(ウォッチ20190402)のカラム指向データストアのメモリモデルをRustで実装したPolarsというライブラリがあって、polars-rubyはそのラッパーだそうです」「よく見たらankaneさんが作ったgemだ」

pola-rs/polars - GitHub

「こういうのを高速に行えるということでしょうね: データサイエンス方面で標準的なApache Parquetのフォーマットも扱えるらしい↓」「なるほど」「こういう機能を単体で使えるgemがあると、AWS Lambdaみたいなところでちょっと動かしたりするときなんかに便利かもしれませんね」

# https://github.com/ankane/polars-rubyより
#From a CSV
Polars.read_csv("file.csv")
# or lazily with
Polars.scan_csv("file.csv")

# From Parquet
Polars.read_parquet("file.parquet")

# From Active Record
Polars.read_sql(User.all)
# or
Polars.read_sql("SELECT * FROM users")

# From a hash
Polars::DataFrame.new({
  a: [1, 2, 3],
  b: ["one", "two", "three"]
})

# From an array of hashes
Polars::DataFrame.new([
  {a: 1, b: "one"},
  {a: 2, b: "two"},
  {a: 3, b: "three"}
])

# From an array of series
Polars::DataFrame.new([
  Polars::Series.new("a", [1, 2, 3]),
  Polars::Series.new("b", ["one", "two", "three"])
])

参考: Apache Arrow - PG-Strom Manual
参考: Parquet | Databricks

つっつき後に、Apache ArrowはApache Parquetを元に構築されたと教わりました↓

🔗 RubyのEnumerableのドキュメントは読んでおけ(Ruby Weeklyより)


つっつきボイス:「実際EnumerableはRubyに組み込まれた強力な機能なので、ドキュメントはマジで読んでおく価値があると思います」「Enumerableを使いこなすとこんなに短く書けるというコード例もありますね」

参考: module Enumerable - Documentation for Ruby 3.3
参考: module Enumerable (Ruby 3.2 リファレンスマニュアル)

# 同記事より
def longest_string(strings)
  longest = ""
  strings.each do |str|
    longest = str if str.length > longest.length
  end
  longest
end

# Enumerable#max_byを使うとこう書ける
def longest_string(strings)
  strings.max_by(&:length)
end

「ところでこの記事にもオチがあるんですが、末尾の▶をクリックしてみてください↓」「おや、この記事もChatGPTにこれを質問して書かれているのね」「このブログの"Blogging with AI"シリーズは別のレビュアーによるチェックを行ってから公開しているそうです」

▶Prompt for ChatGPT
One thing I feel would be really helpful for junior and even intermediate Rubyists is to become really familiar with the methods provided by Ruby's Enumerable module, which is included in Arrays, Hashes, and Sets among other things. How would you convince developers to read up on that, with a few examples of naive approaches to problems with each or map being replaced with more appropriate Enumerable methods?
同記事より

🔗 RubyGemsにgem execサブコマンド追加の提案


つっつきボイス:「まだドラフトですが、npm exec的なgem execコマンドをRubyGems追加してはどうかというプルリクがrubygemsのリポジトリに上がっています」

gem execが使えると便利になるんでしょうか?」「これが使えると嬉しいと思いますね: gemビルトインコマンドのバージョン指定実行もできるようになりますし、他にも、現在だと、あるコマンドを実行したいときに、それがgemからインストールされたものなのか、他のパッケージによってインストールされたのかがわかりにくくなることが割とあるんですよ: gem execが使えれば、gemによってインストールされたコマンドが実行されることが明確になる」

「これはbundle execだとできそうでできないんですよ: たとえばbundle exec lsを実行するとシェルのパスにあるlsコマンドの方が実行されてしまいますが、gem execが使えれば、指定したgemによってインストールされた独自のlsコマンドを確実に実行できる」「そういうことなんですね」「使えるようになったら積極的に使いたい👍」

概要

RubyGemsにgem execサブコマンドを追加して、rubygems.orgやユーザー独自のgemサーバーにあるgemを、そのgemが現在インストールされているかどうかとは無関係に(必要ならgemをインストールして)実行できるようにする。

動機

npx / npm execにインスパイアされた。これは既にgemxという別gemが存在するが、見つけにくいうえに、RubyGmes標準の組み込みコマンドではなく単独のgemとして依存することになる。

ガイドレベルの解説

gem execコマンドは、gem installを実行して、インストールされた実行可能ファイルを実行するショートカットと考えられる。
たとえば、gem exec rails new .を実行するとrails new .をカレントディレクトリで実行する。gem install railsを手動で実行する必要はなく、rails newを一度実行するだけで、それ以外のrailsコマンドは実行しない(rails newではGemfileが生成されるため)。

もう少し完全な実行例:

$ gem exec --gem cocoapods -r '> 1' -r '< 1.3' -v -- pod install --no-color --help

これは、cocoapods gemのpod実行ファイルを用いて、バージョン1〜1.3を指定してpod install --no-color --helpを実行する。
(中略)
リファレンスレベルの解説

gemexecという新しいサブコマンドがRubyGemsに追加される。

gem execは、gemのインストールに独自のgemパスを利用する(必要な場合)。そして、既存のgemセットから要求されるバイナリのロードを試みる。
バイナリが見つからない場合は、そのgemをインストールし(デフォルトではバイナリと同じ名前になるが、コマンドラインオプションで変更可能)、そのライブラリを有効にして実行する。

欠点

これは純粋に追加を提案するものなので、既存ユーザーには影響しないはず。

Bundler を使う場合やGemfileを使うユーザーが混乱する可能性がある。
まず、gem execを実行するときは、Gemfileを完全に無視することを計画している。これは、gemの取得元をGemfileでカスタマイズしようとしている場合に混乱する可能性がある。
さらに、gem execbundle execコマンドと紛らわしく、両者の動作はそれぞれ異なる。
この混乱を改善できそうな方法は、gem execでは要求された実行ファイルが現在のバンドルに存在するかどうかをチェックし、存在する場合はbundle execを使うようユーザーに促すというもの。

Add RFC for gem exec command by segiddins · Pull Request #45 · rubygems/rfcsより

🔗 設計・セキュリティ

🔗 スライド: 和暦を正しく扱うための暦の話


つっつきボイス:「BPS Webチーム内ミーティングでも少し話題になった和暦の話ですね」「和暦がこんなにややこしいとは思わなかった」「うるう月を表すUndecimberって造語かと思ったらラテン語由来なんですね」「そういえば江戸時代の太陰暦にもうるう月があった」「スペルが微妙に違うUndecemberは"13月を表すユーモラスな語とされる"ですって」

参考: Undecimber - Wikipedia

「元号の話あたりはプログラミングをやっている人にも好きな人がいそう」「歴史学者がどうやって元号や年号を解決していたのか何となく気にはなっていました」「歴史の教科書でもそのあたりが書き換わったりしますよね」「そういえばCivilizationにも古典の技術にCalendar(暦)があった」「Civilizationは学びの多いゲーム」

参考: データ/テクノロジー/古典 - Civilization4(Civ4 シヴィライゼーション4) 攻略Wiki

「こういう世界があるという驚きを感じられるスライド👍」

🔗 Danger のコマンドインジェクション


つっつきボイス:「ruby-jp Slackのセキュリティチャンネルで知りました」「Dangerって何だっけと思ったらコードの自動レビューツールか」「CIでこういうツールを連携させたりしますね」

danger/danger - GitHub

「"細工された名前のブランチで実行されると任意のコマンドを実行できる問題"、これはこの間のGitの脆弱性並に怖いヤツ」「git cloneすると任意のコマンド実行、怖すぎ...」

参考: 「Git」に3件の脆弱性 ~修正版のv2.39.1が公開 - 窓の杜

「シェルは便利なんだけど、コマンドラインの引数に渡した文字列を展開する文化はよくないとつくづく思う」「以前も話したRubyのShellwordsのような文字列エスケープを使って安全にやりたい(ウォッチ20200225)」「ですね」「でもRubyからのシェルコマンド実行はShellwordsで守ることはできますが、Rubyから実行するシェルスクリプト側での引数の処理が甘いと結局そこが脆弱になったりすることはあるんですよ」

参考: module Shellwords (Ruby 3.2 リファレンスマニュアル)
参考: 【 eval 】コマンド――文字列を評価、連結して実行する:Linux基本コマンドTips(170) - @IT

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

🔗 AWSのsso login


つっつきボイス:「babaさんのSlack書き込みで知りました↑」「aws configure ssoコマンドでURLとリージョンを渡すとブラウザが開いて認証できるんですね↓」

# 同記事より
$ aws configure sso
SSO start URL [None]: https://my-sso-portal.awsapps.com/start
SSO region [None]:us-east-1

SSO authorization page has automatically been opened in your default browser.
Follow the instructions in the browser to complete this authorization request.

「AWSアカウントが複数ある場合はこんなふうに選択できる↓」

There are 2 AWS accounts available to you.
> DeveloperAccount, developer-account-admin@example.com (123456789011) 
  ProductionAccount, production-account-admin@example.com (123456789022)

「期限切れの一時認証を自動更新してくれる、これなら使ってみたい👍」「新しいAWS CLIはいろいろ便利になっていますね」「後から登場するツールはこうあって欲しい」

IAM Identity Center にサインインしていて、キャッシュされた認証情報が期限切れでない限り、AWS CLI は必要に応じて期限切れ AWS の一時認証情報を自動的に更新します。
AWS IAM Identity Center (successor to AWS Single Sign-On) を使用するための AWS CLI の設定 - AWS Command Line Interfaceより

🔗 Apache Airflow


つっつきボイス:「APIの死活監視にも使えそうなApache Airflowというオープンソースのワークフロー管理ソフトウェアを見つけました」

「触ったことはないけど、雰囲気としてはワークフローエディタで作ったデータを中間言語的な形でエクスポートして、サイトに書かれているさまざまなサービスとインテグレーションする感じかな」「ドキュメントを見るといろんなサービスとインテグレーションできるみたいですね」「Apacheのプロダクトだからそれなりに手堅く作られていそう」「データ収集もできるみたい」

「このあたりはGitLabのワークフローエディタを思わせますね↓: dependencyがあるとか、並列化可能かどうかを指定するみたいな部分はたいていのワークフローで共通していますね」


What is Airflow? — Airflow Documentationより

「JP1とかSenjuみたいなエンタープライズ向けの有償ワークフローをちょっと思い出した」「なつかしい名前ですね」

「Docker HubにもApache AirFlowがあって、ドキュメントにもDocker利用について書かれていました」「Apache AirFlowをローカルのDocker環境で使えるということですね: 機会があったら使ってみようかな」


後編は以上です。

バックナンバー(2023年度第1四半期)

週刊Railsウォッチ: Ruby 3.2のベンチマーク記事、dry-cliで高度なCLIを作るほか(20230201後編)

Ruby Weekly

Publickey

publickey_banner_captured


CONTACT

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