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

週刊Railsウォッチ: Ruby 3.2のParser目玉機能ほか(20221130後編)

こんにちは、hachi8833です。Herokuの無料プランが先ごろ終了しましたね。

週刊Railsウォッチについて

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

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

🔗Ruby

🔗 Ruby 3.2のParser目玉機能


つっつきボイス:「この記事はとても面白く読みました👍: RubyVM::AbstractSyntaxTreeに追加されたkeep_tokensを使うとAST(Abstract Syntax Tree: 抽象構文木)から元のコードを完全に再現できるようになった話とかいろいろ興味深い」「Bisonを3.0にアップグレードする話も出てますね(ウォッチ20221122)」

参考: module RubyVM::AbstractSyntaxTree (Ruby 3.1 リファレンスマニュアル)
参考: 抽象構文木 - Wikipedia

「記事ではRubyのヒアドキュメントにも言及していて、自分はヒアドキュメントがASTの中でどう扱われているのかが気になっていたので興味深い」「ヒアドキュメントの解析って大変そう」

# 同記事より
root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY, keep_tokens: true)
str = <<~EOS + "ABC"
  abc
  123
EOS
RUBY

root.tokens
# =>
[[0, :tIDENTIFIER, "str", [1, 0, 1, 3]],
 [1, :tSP, " ", [1, 3, 1, 4]],
 [2, :"=", "=", [1, 4, 1, 5]],
 [3, :tSP, " ", [1, 5, 1, 6]],
 [4, :tHEREDOC_BEG, "<<~EOS", [1, 6, 1, 12]],
 [8, :tSP, " ", [1, 12, 1, 13]],
 [9, :+, "+", [1, 13, 1, 14]],
 [10, :tSP, " ", [1, 14, 1, 15]],
 [11, :tSTRING_BEG, "\"", [1, 15, 1, 16]],
 [12, :tSTRING_CONTENT, "ABC", [1, 16, 1, 19]],
 [13, :tSTRING_END, "\"", [1, 19, 1, 20]]]

root.all_tokens
# =>
[[0, :tIDENTIFIER, "str", [1, 0, 1, 3]],
 [1, :tSP, " ", [1, 3, 1, 4]],
 [2, :"=", "=", [1, 4, 1, 5]],
 [3, :tSP, " ", [1, 5, 1, 6]],
 [4, :tHEREDOC_BEG, "<<~EOS", [1, 6, 1, 12]],
 [5, :tSTRING_CONTENT, "  abc\n", [2, 0, 2, 6]],
 [6, :tSTRING_CONTENT, "  123\n", [3, 0, 3, 6]],
 [7, :tHEREDOC_END, "EOS\n", [4, 0, 4, 4]],
 [8, :tSP, " ", [1, 12, 1, 13]],
 [9, :+, "+", [1, 13, 1, 14]],
 [10, :tSP, " ", [1, 14, 1, 15]],
 [11, :tSTRING_BEG, "\"", [1, 15, 1, 16]],
 [12, :tSTRING_CONTENT, "ABC", [1, 16, 1, 19]],
 [13, :tSTRING_END, "\"", [1, 19, 1, 20]],
 [14, :nl, "\n", [1, 20, 1, 21]]]

root.tokens.map{_1[2]}.join # => "str = <<~EOS + \"ABC\""

参考: ヒアドキュメント (行指向文字列リテラル) -- リテラル (Ruby 3.1 リファレンスマニュアル)

str = <<~EOS + "ABC"みたいにも書けるのが何とも独特」「よく見たら<<~RUBY<<~EOSが入れ子になってる」「ヒアドキュメントの中にヒアドキュメントを書けるとは!」「ここまでくるとRubyMineのシンタックスハイライトも完全な表示はできなさそう: 貼ってみたらやっぱりできなかった↓」「内側のヒアドキュメントは文字列として扱われるんですね」

🔗 ciao: HTTP URLエンドポイントのHTTPステータスコードをチェック(Ruby Weeklyより)

brotandgames/ciao - GitHub


同サイトより


つっつきボイス:「前にも似たようなツールを取り上げたことがあったかも」「エンドポイントの死活などをチェックできるRuby製ツールですね: このciaoの場合はDocker Hubイメージもあるので、Dockerコンテナの生存チェックというかコンテナでちゃんとリッスンされているかどうかのチェックもできるのがよさそう」

参考: brotandgames/ciao - Docker Image | Docker Hub

「通常Dockerでrestart=alwaysを指定して起動した場合は、コンテナプロセスが死んだときに自動的に再実行されるんですが、プロセスは死んでないけど異常な挙動をする状態になってしまったりすると再起動されないんですよ: そういうときに正常確認をプロセス状態ではなくきちんとHTTPリクエストなどで確認できるものがある方がより適切な監視になりますね」「なるほど」「ciaoは外部APIの死活監視も合わせて行えるので、compose.yamlに入れておくと便利そう👍」

🔗 gemoji: 絵文字の情報を表示

github/gemoji - GitHub


つっつきボイス:「gemojiという名前が面白い」「こんなふうに絵文字の名前を取れるんですね↓」「絵文字を自分で追加もできるのね」「★が4100個ってすごい」

# 同リポジトリより
>> Emoji.find_by_alias("cat").raw
=> "🐱"  # Don't see a cat? That's U+1F431.

>> Emoji.find_by_unicode("\u{1f431}").name
=> "cat"

「絵文字の定義はどこから取ってくるんだろう?」「自前で持っているのかな?」「db/emoji.jsonにあった↓」

// 同リポジトリより
[
  {
    "emoji": "😀"
  , "description": "grinning face"
  , "category": "Smileys & Emotion"
  , "aliases": [
      "grinning"
    ]
  , "tags": [
      "smile"
    , "happy"
    ]
  , "unicode_version": "6.1"
  , "ios_version": "6.0"
  }
, {
    "emoji": "😃"
  , "description": "grinning face with big eyes"
  , "category": "Smileys & Emotion"
  , "aliases": [
      "smiley"
    ]
  , "tags": [
      "happy"
    , "joy"
    , "haha"
    ]
  , "unicode_version": "6.0"
  , "ios_version": "6.0"
  }
...

「SQLiteのDBに登録してもよさそうですけど」「そうするとSQLiteのライブラリがないと動かなくなる」「たしかにこれならピュアRubyだけで動かせますね」

🔗 RubyでRangeが重なっているかどうかを比較する


つっつきボイス:「記事にもあるように、RangeになっていればRange#cover?で重なりをチェックできますね↓」「Range#cover?はピュアRubyでできるんですね」「RailsのActive Supportにはoverlaps?というRangeの拡張もあります」

参考: Range#cover? (Ruby 3.1 リファレンスマニュアル)
参考: §13.3 overlaps? -- Active Support コア拡張機能 - Railsガイド

🔗DB

🔗 Active Recordモデルからカラムを安全に削除する(Ruby Weeklyより)


つっつきボイス:「定番かなと思いつつ取り上げてみました」「マイグレーションでカラムを削除する前にignored_columnsを使うのはまさに定番」「知らなかった人はぜひ使いましょう」

# 同記事より
class Thing < ApplicationRecord
  # ...
  self.ignored_columns = ["old_column"]
  # ...
end
# 同記事より
class RemoveOldColumnFromThings < ActiveRecord::Migration[7.0]
  def change
    remove_column :things, :old_column
  end
end

参考: ActiveRecordモデルのカラムを消すときにignored_columnsが必要な理由 - Progate Tech Blog

参考: Rails API ignored_columns -- ActiveRecord::ModelSchema::ClassMethods

追記(2022/12/05)

以下の情報をいただきました。ありがとうございます!
=ではなく+=で代入するのがポイントなんですね。

なお現時点のAPIドキュメント更新はedge APIドキュメントにのみ反映されています。

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

🔗 AWSがFinchをリリース

runfinch/finch - GitHub


つっつきボイス:「Finchは一部でDocker Desktopの代替みたいに言われていたようですが、AWSの記事を見るとno GUIと書かれているんですよね」「自分もMacbookにFinchをインストールしてみましたが、GUIはありませんでした」「やはり」「Finchのアンインストール方法がわからなくて焦ったんですが、アプリケーションの中にuninstall.shを見つけました」

🔗JavaScript

🔗 TypeScript で仕様が一目瞭然な定数ファイルを書く


つっつきボイス:「知人のJSプログラマーが推していた記事です」「"単位の処理は文字列と数値を別に
"とか」「このあたりは言語によっていろいろ異なるので、TypeScriptならではの書き方の工夫なんでしょうね: いずれにしろ明確な意図を持って書くのは重要👍」

「ところで、記事のトップにある"IDE 等による入力補助"は割と大事だと思います: 今ならIDEやAIによる補完がなるべく効きやすいように構造を意識して書いておくのがおすすめ」「何でもベタに文字定数で書いてしまって補完の候補が増え過ぎるとかありますよね」「ただ環境変数は名前空間をフラットにしかできないので、環境変数も入ってくると面倒になりがち」「あ、たしかに」

「コード以外に、たとえばTerraformの変数なんかもきちんと宣言しておくとうまく参照されるようになりますね」

参考: Terraform by HashiCorp

「最近はあまりなくなったけど、AWSでリソース名の文字数が多すぎるとダメだったこともありました」「え〜」「リソースによるんですが、リソース名が最大32文字のものがあって、アプリケーション名_デプロイ対象名_変数名みたいなわかりやすい名前にしようとすると、すぐあふれてTerraformに怒られたりするんですよ: たとえば以下のissueだとAWSではロードバランサ名が最大32文字と書かれている↓」「GCEは最大63文字なのに」「やってみないとなかなかわからないハマりポイント」

参考: Limit length of load balancer names · Issue #6812 · kubernetes/kubernetes

🔗 Deno Deploy


つっつきボイス:「これまた知人のJSプログラマーがDeno Deployのエクスペリエンスのよさに感激していました」「JSの言語ランタイムであるDenoが有料と無料のデプロイサービスを立ち上げていたんですね: 初めて使う人の敷居が低くなるのはいいことだと思います👍」「言語ではないけど、JS向けのクラウドサービスであるVercelも敷居を下げるという意味では似ているかもしれませんね↓」

参考: Develop. Preview. Ship. For the best frontend teams – Vercel

「この記事↓を見ていて思ったけど、今はDenoのクラウド実行環境があまり一般的でないから、Denoが率先してそういう場所を公式に用意したのかも」「Deno公式がやっているのはその意味では安心感ありそうですね」「Rubyランタイムのバージョンが2.7からなかなか更新されないAWS Lambdaよりはまめに更新してもらえそう😆」

参考: Deno Deployでコードをサクッと実行してURL APIも試す
参考: Lambda ランタイム - AWS Lambda


「言語やツールがこういうふうにデプロイ先も提供することは過去にもいくつかありましたけど、うまくいった場合といかなかった場合が思い出されますね」「言語やツールはクラウドサービスと別物感ありますよね」「言語やツールが自前のクラウドサービスに強く依存しすぎると、ロックインをおそれてエンタープライズが利用をためらうこともありそう」

「DockerはDocker Hubが必須みたいなものだから、クラウドサービスを提供するのは納得」「Redisも、ソフトウェアとして配布されているもの以外にクラウドサービスも提供しています↓」「Redisもやっているとは知りませんでした」「あとElastic Searchもオープンソース版とクラウドサービス提供をやってますね」

参考: Redis Enterprise Cloud Pricing | Redis
参考: オフィシャルのElasticsearch料金:Elastic Cloud、マネージドのElasticsearch | Elastic

🔗言語/ツール/OS/CPU

🔗 Dynamic Macro


同記事より


つっつきボイス:「増井俊之さんが考案したそうです」「エディタで同じ操作を2回実行すると自動的にマクロとして登録されて、Ctrl-Tを押すと再実行できるのか」「シンプルだけどうまいアイデア😋」「マクロはエディタととても相性のいい機能ですね」「EmacsやVimでもマクロを極めている人がいっぱいいますよね」

参考: 増井俊之 - Wikipedia
参考: マクロ (コンピュータ用語) - Wikipedia

「ちなみにJetBrains IDEにはExpanding/shrinking selectionという機能があって、口頭だとちょっと説明しにくいんですが、エディタでコードブロックの内側の行をクリックするたびにテキストの選択範囲が順次外側に広がる↓」「あ〜、このインテリジェントな選択機能はたしかに便利でした」「むちゃくちゃ便利」

参考: Expanding/shrinking selection - GoLand Guide

「JetBrains IDEのマクロはとても強力で、マクロでもこのExpanding/shrinking selectionを使えるんですが、惜しいことにマクロの実行がかなり遅い」「ありゃ〜」「マクロは一瞬で終わって欲しいのに、1千行とか処理させるとめちゃくちゃ時間がかかったりするんですよ...」


後編は以上です。

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

週刊Railsウォッチ: Hanami 2.0リリース、Railsに関わる技術の体系化を目指した本ほか(20221129前編)

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

Rails公式ニュース

Ruby Weekly

RubyFlow

160928_1638_XvIP4h


CONTACT

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