- Ruby / Rails関連
週刊Railsウォッチ(20210209後編)Rubyでミニ言語処理系を作る、Kernel#getsの意外な機能、CSSのcontent-visibilityほか
こんにちは、hachi8833です。
🔗Ruby
🔗 Rubyでミニ言語処理系を作る
つっつきボイス:「少し前の記事です」「お〜、Rubyで言語処理系を作ってライフゲームまで動かしたんですね」「VMも自分で作ったのか」
参考: 言語処理系とは
「へ〜、この記事では便利なサポート系の外部ツールを使わずに、Rubyと最小限のgemだけで言語処理を書いてるんですね」「これはいい勉強になりそう」「こういうのは作ってて楽しいですよね」
「小さな言語処理系を一度自分で作ってみるのは大事」「そうそう」「難しすぎることをしてないのもポイントだと思います: リポジトリもシンプルですし、外部ツール群的なものも作っていませんね」「なるほど」
「外部ツールを作り始めると処理系全体がどんどん大きくなってしまいますけど、この記事はVMも純粋なVMにとどめていますし、コンパイラを作らずにコード生成機を直接書いてそこからアセンブリコードを出力しているようですね」「ふ〜む」「グラフィック部分も手作りしているとは面白い!」「外部ツールを作らずに、自分が掌握できる最小限の構成で処理系を作るというのがいいと思いました👍」
「ところで、大学のコンピュータサイエンスの授業で使われていたような古典的な教科書に、よくこういう感じのミニ処理系の作り方が載ってましたね: LISPの教科書あたりでそういうのを見た覚えがちょっとあります」「そうそう、スタックマシンを作って動かすような言語処理系はよくこういう構成になりますよね」「オレオレチューリングマシン的なヤツですね🦾」
参考: LISP - Wikipedia
参考: スタックマシン - Wikipedia
参考: チューリングマシン - Wikipedia
「自分で言語処理系を作るときは、とにかく最後まで作り切れるかどうかが最大の分かれ目」「そうそう、そこなんですよ」「小さくても言語系を作るのは根性要りますから」「でもそれを乗り越えて作り切れば、得るものは大きい」
「自分なら、ひとりでやるより人数集めて勉強会形式でやるかも」「自分はむしろひとりでやりたいかな」「お、こういうものこそ大学のゼミみたいな場の方がはかどりそうですけど?」「そういう面ももちろんあると思いますけど、こういうものを作るなら他の人の進捗を待たずに自分のペースでやりたい方なので」「それもわかります😆」
🔗 method_missing
の実用的な使い方3種(Ruby Weeklyより)
つっつきボイス:「Rubyのmethod_missing
は、エラーハンドリング、メソッドのdelegation、DSL(Domain Specific Language: ドメイン固有言語)やライブラリで使える、まさにそのとおりですね」
参考: BasicObject#method_missing
(Ruby 3.0.0 リファレンスマニュアル)
参考: ドメイン固有言語 - Wikipedia
🔗 method_missing
よもやま話
「ところで、最近はRubyでDSLを作るいい教材ってあるのかな?以前はRubyでDSLを作るいい学習サイトがあったんですが、今は閉鎖してしまったんですよ」「ありゃ、残念」「そういう教材では必ずといっていいほどmethod_missing
を使うテクニックが紹介されていますね」「『パーフェクトRuby』のような大きな書籍ならカバーされていると思いますが、RubyのDSLでのmethod_missing
の使い方を手軽に学べる本もあるといいですよね」
「他の言語をやっていた人がRubyをやってみて驚くことのひとつが、このmethod_missing
だろうなと思います」「たしかに!」「Rubyではこんなことができるのか!という一種の感動がありますね」
学習サイトの代わりに、method_missing
とDSLについて書かれている英語記事をいくつか見繕いました。
参考: Writing a Domain-Specific Language in Ruby
参考: Metaprogramming: Writing in Ruby with... Ruby | Toptal
🔗 Rubyのgets
つっつきボイス:「意外に短い記事ですね」「Rubyの生のgets
に驚きの挙動ってあったかな?」
# 同記事より
#!/usr/bin/env ruby
puts "What is your name?"
your_name = gets.chomp
puts "Hi, #{your_name}!"
「上のコードを./gets.rb 123
のように引数を渡して実行するとエラーになる、これは当然そうなりますよね」「ですよね、引数で渡したものをgets
で取れるというのは聞いたことないかも」「他の言語だとできたりするのかな?」
なお、以下は手元のRuby 3.0.0で上のコードを実行した結果です。
./gets.rb:4:in `gets': No such file or directory @ rb_sysopen - 123 (Errno::ENOENT)
from ./gets.rb:4:in `gets'
from ./gets.rb:4:in `<main>'
「Rubyの英語ドキュメント↓を見てみると...え?Kernel#gets
にはARGV(Rubyスクリプト実行時に渡す引数の配列)を取る機能があるって書いてある!」「マジですか!?」「これは知らなかった」
参考: gets
-- Module: Kernel (Ruby 3.0.0)
Returns (and assigns to
$_
) the next line from the list of files inARGV
(or$*
), or from standard input if no files are present on the command line. Returns nil at end of file.
ruby-doc.orgより
# ruby-doc.orgより
ARGV << "testfile"
print while gets
「日本語のドキュメントにも書かれてる↓」「ARGFはARGVをファイルとみなしたオブジェクトとある: ということはgets
にはファイル名を引数で渡せるのか!」「上でエラーになった123
は、123
という名前のファイルがないからエラーになったということなんですね」「やっと話が見えてきたかも」
参考: Kernel.#gets
(Ruby 3.0.0 リファレンスマニュアル)
ARGFから一行読み込んで、それを返します。行の区切りは引数 rs で指定した文字列になります。
rs に nil を指定すると行区切りなしとみなしてファイルの内容をすべて読み込みます。ARGVに複数のファイル名が存在する場合は1度に1ファイルずつ読み込みます。空文字列 "" を指定すると連続する改行を行の区切りとみなします (パラグラフモード)。
読み込んだ文字列は組み込み変数 $_ にもセットされます。
docs.ruby-lang.orgより
「いや〜今までは記事にもあるようにずっと$stdin.gets
でARGVを取ってましたけど↓、Kernel#gets
でARGVを取れるなんて思いもよらなかった」「たしかに驚きですね」「gets
メソッドのこの挙動にはちょっとびっくりしました」
# 同記事より
your_name = $stdin.gets.chomp
参考: argc,argvは何の略 | C言語のTipsとサンプル | C入門 基本情報対策講座のcClip
🔗 Rubyのプリントデバッグを便利にするライブラリ
ruby: もう puts/p をデバッグに使わない! デバッグライブラリ IceCream の Ruby 版 - Qiita https://t.co/1RWtYCqrZ9
— はてブ::プログラミング言語非公式bot (@RSS_hateb_l_Roy) January 30, 2021
つっつきボイス:「Matzがリツイートしているのを見かけたので取り上げてみました」「ricecreamというプリントデバッグに便利なgemを作った記事のようですね」
「ic
は引数をそのまま戻り値として返してくれるから、式展開の中で使ったり以下のようにreturn
に書いたりできるのが使いやすそう」「他にもいくつか機能があるようですね」
# 同記事より
return "result = #{ic foo.bar}"
「この機能がRuby本体に入ったら便利かも」「元記事にもありますけど、上と同じことはpp
でもできますね」「ちなみにpp
はrequire
しないと使えないんですよ(追記参照)」「Rubyのコンフィグでこういうデバッグ出力をオンオフできると便利かもしれませんね」「こういうツールは比較的作りやすいと思うので、自分で作ってみるのもいいと思います」
参考: library pp
(Ruby 3.0.0 リファレンスマニュアル)
参考: class PP
- Documentation for Ruby 3.0.0
「ところでデバッグプリントを消し忘れることってありませんか?」「それはコミット前に消さないといけませんよね」「おっしゃるとおり😅」
追記(2020/02/10)
pp
について以下のご指摘をいただきました🙇。ありがとうございます!
> 「ちなみにppはrequireしないと使えないんですよ」
とありますが、require "pp" は Ruby 2.5 から不要になったようです! https://t.co/lvoqtF3cz4— 🐝 (@ima1zumi) February 9, 2021
「元記事を見ると、もともとPythonにicecreamという同じようなプリントデバッグツールがあるらしい↓」「Ruby版のicecreamだからricecreamと名付けたのかもしれませんね」「アイスクリームのアイコンがかわいい!」「sorbet↓のアイコンをちょっと思い出しました」「単にアイスクリームとシャーベットというモチーフが似ているだけだと思いますけどね」
🔗DB
🔗 Googleのsqlcommenter(Publickeyより)
つっつきボイス:「sqlcommenterはまだ使ったことがありませんが、Railsだと類似のgemが以前からいろいろありますね: ただ、他のフレームワークだとそういうツールがあるとも限らないので、そういうところでは便利なのかもしれないと思いました」
「sqlcommenterは、対応しているデータベースが比較的多いとか、OpenCensusのようなツールと組み合わせて使えたりするらしい」「いわゆるAPM(Application Performance Management)ツールでもそれに近いことができますね」「なるほど」「使いたい人が使うということでよいと思います」
参考: OpenCensus(OpenTelemetry)とは | フューチャー技術ブログ
参考: 【ツール8選】APMツールとは?基本解説やおすすめツールをご紹介! | QEEE
🔗クラウド/コンテナ/インフラ/Serverless
🔗 sudo脆弱性がmacOSにも影響
つっつきボイス:「sudo脆弱性は先週も間話題にしましたね(ウォッチ20210202)」「現時点ではAppleから情報はまだ出てないようです」
「Linuxのsudo脆弱性と似てるというだけで多少違いがありそうな感じ」「日本語記事にはそう出ていますね↓」
参考: sudoコマンドの脆弱性、「macOS」にも影響 - ZDNet Japan
「Linuxと違ってmacOSのバイナリはIntel版でもMach-Oバイナリですし、メモリマップなども違っているので、まったく同じ攻撃方法が使えるとはあまり思えませんが、sudoの脆弱性という視点から見て類似のものがMac版でも見つかった可能性ならありそう」「ふむふむ」「Macのsudoの脆弱性はソースコードレベルではたぶんLinuxのsudo脆弱性と違うだろうという気はしていますが、英語記事を眺めた感じでは、heap overflowにつながる可能性が書かれていたり、どうやらAPIレベルでは同じような結果になるらしい」
参考: Mach-O - Wikipedia
参考: Heap Overflow: Vulnerability and Heap Internals Explained - Infosec Resources
「これはAppleの対応を待つしかないでしょうね」「Windowsを使ってる人は大丈夫なんですね、いいな〜」
🔗CSS/HTML/フロントエンド/テスト/デザイン
🔗 CSSのcontent-visibility
参考: content-visibility - CSS: カスケーディングスタイルシート | MDN
参考: CSS Containment - CSS: カスケーディングスタイルシート | MDN
つっつきボイス:「英語記事からの翻訳みたいなので、元記事を開いてみよう↓」
参考: content-visibility: the new CSS property that boosts your rendering performance
「元記事にcodepenのリンクがありますね↓」「これでやってみましょうか」(一同でしばらく動かしてみる)
See the Pen
Content-visibility Demo: Base (Content Visibility on Grids) by Una Kravets (@una)
on CodePen.
「Rerunボタンを押すといいのかな?」「動かしてみたけどまだピンとこない...」
「これかな?ちょっとわかりにくいですけど、codepenの表示を下にスクロールすると、途中でページが長くなったのが今スクロールバーに反映されたのが一瞬見えました」「え、今のがそうなんですか?」「Zoom越しだとうまく見えないかも...」「ではもう一度」「あ、ちょっと見えたかも」「下にスクロールすると何度かページの長さが変わっているように見えますね」
「CSSの末尾でcontent-visibility: auto;
が指定されているから、この部分に効いてるんでしょうね」「あ、ここですか」
<!- https://codepen.io/una/pen/rNxEWLo より-->
.grid-3,
.grid-2,
.p-group-flex {
content-visibility: auto;
}
「通常のWebページを開いてそのままにしていれば、JavaScriptでlazy loadingなどを行わない限り、ページが長くてもレンダリングはすべて終わっているものなので、普通ならスクロールしたときにページの縦の長さは変わらないはずですよね」「はい、そうですよね」「今codepenでやったように、レンダリングが終わっているはずのページを下にスクロールすると縦の長さが伸びたということは、ブラウザに表示されているページの中でそれまでビューポート↓に入っていなかった部分、つまりそれまでレンダリングされていなかった部分がレンダリングされたということなんでしょうね」「なるほど!」「ちょっと雰囲気がつかめてきたかも」「元記事を読まずに今試してみた限りでは、たぶんそうなんだろうと推測しました」「弊社のbabaさんのようなCSSに詳しい人に聞いてみたい」
参考: ビューポートの概念 - CSS: カスケーディングスタイルシート | MDN
「どうやらcontent-visibility: auto;
は、ビューポートにさしかかるまでレンダリングを遅延するプロパティのようですね: これがlazy renderingのようなものだとすると、lazy loadingとは別物と考えるのがよさそうな気がしました」「なるほど、ちょっと腹落ちしました」「無条件に使うよりも、調べてから使う方がよさそう」「もう少しわかりやすい見せ方があるといいんですけどね」
auto
この要素は、レイアウトの封じ込め、スタイルの封じ込め、およびペイントの封じ込めをオンにします。要素がユーザーに関連していない場合は、その内容もスキップします。非表示とは異なり、スキップされたコンテンツは、ページ内検索、タブオーダーナビゲーションなどのユーザーエージェント機能に対して通常どおり利用可能である必要があり、通常どおりフォーカス可能で選択可能である必要があります。
MDN:content-visiblity
より
後編は以上です。
バックナンバー(2021年度第1四半期)
週刊Railsウォッチ(20210208前編)Rails次期リリースがバージョン7に決定、thoughtbotのアプリケーションセキュリティガイドほか
- 20210202後編 Ruby 3 irbのmeasureコマンド、テストを関数型言語のマインドセットで考えるほか
- 20210201前編 Webpackerのガイドがマージ、RailsはRuby 3でどのぐらい速くなったかほか
- 20210126後編 Google Cloud FunctionsがRubyをサポート、Ruby 3のパターンマッチングでポーカーゲームほか
- 20210125前編 Railsリポジトリのデフォルトブランチがmainに変更、Rails 6.1はMySQLのENUM型に対応済みほか
- 20210120後編 Ruby 3.0の新機能で遊ぶ、RubyスニペットをJSに変換するRuby2JS、rspec-parameterized gemほか
- 20210113後編 Ruby 3.0 Ractor解説記事、Vercelホスティングサービス、教育用OS xv6ほか
- 20210112前編 Active Recordの範囲指定バリデーション改善、soleとfind_sole_byメソッド、AlgoliaとRailsほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsの最新情報などの記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)