diff options
Diffstat (limited to 'vhosts/blog/public/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/index.html')
| -rw-r--r-- | vhosts/blog/public/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/index.html | 285 |
1 files changed, 0 insertions, 285 deletions
diff --git a/vhosts/blog/public/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/index.html b/vhosts/blog/public/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/index.html deleted file mode 100644 index 1c36083a..00000000 --- a/vhosts/blog/public/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/index.html +++ /dev/null @@ -1,285 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <meta name="author" content="nsfisis"> - <meta name="copyright" content="© 2025 nsfisis"> - <meta name="description" content="RubyKaigi 2025 で開催された TRICK において、『最もRuby on Ruby賞』として審査員賞をいただいた。"> - <meta name="keywords" content="カンファレンス,Ruby,RubyKaigi,TRICK"> - <meta property="og:type" content="article"> - <meta property="og:title" content="RubyKaigi 2025 の TRICK で入賞した|REPL: Rest-Eat-Program Loop"> - <meta property="og:description" content="RubyKaigi 2025 で開催された TRICK において、『最もRuby on Ruby賞』として審査員賞をいただいた。"> - <meta property="og:site_name" content="REPL: Rest-Eat-Program Loop"> - <meta property="og:locale" content="ja_JP"> - <link rel="icon" type="image/svg+xml" href="/favicon.svg"> - <title>RubyKaigi 2025 の TRICK で入賞した|REPL: Rest-Eat-Program Loop</title> - <link rel="stylesheet" href="/style.css?h=9513229b52eb2041b99ba1b959305633"> - </head> - <body class="single"> - <header class="header"> - <div class="site-logo"> - <a href="/">REPL: Rest-Eat-Program Loop</a> - </div> - <nav class="nav"> - <ul> - <li> - <a href="/about/">About</a> - </li> - <li> - <a href="/posts/">Posts</a> - </li> - <li> - <a href="/slides/">Slides</a> - </li> - <li> - <a href="/tags/">Tags</a> - </li> - </ul> - </nav> - </header> - <main class="main"> - <article class="post-single"> - <header class="post-header"> - <h1 class="post-title">RubyKaigi 2025 の TRICK で入賞した</h1> - <ul class="post-tags"> - <li class="tag"> - <a href="/tags/conference/">カンファレンス</a> - </li> - <li class="tag"> - <a href="/tags/ruby/">Ruby</a> - </li> - <li class="tag"> - <a href="/tags/rubykaigi/">RubyKaigi</a> - </li> - <li class="tag"> - <a href="/tags/trick/">TRICK</a> - </li> - </ul> - </header> - <div class="post-content"> - <section id="changelog"> - <h2><a href="#changelog">更新履歴</a></h2> - <ol> - <li class="revision"> - <time datetime="2025-04-20">2025-04-20</time>: 公開 - </li> - </ol> - </section> - <section id="section--intro"> - <h2><a href="#section--intro">はじめに</a></h2> - <p> - 2025-04-16 から 2025-04-18 にかけて開催された <a href="https://rubykaigi.org/2025/" rel="noreferrer" target="_blank">RubyKaigi 2025</a> に参加した (私が参加できたのは 1日目の 2025-04-16 のみ)。 - </p> - <p> - 地元松山での大規模なカンファレンスということでスケジュールに無理を言わせて 1日目だけでもと参加したのだが、そこで開催された <a href="https://github.com/tric/trick2025" rel="noreferrer" target="_blank">TRICK 2025</a> で審査員賞をいただいた。 - </p> - <p> - この記事では、提出した作品の紹介と解説をおこなおうと思う。 - </p> - </section> - <section id="section--trick"> - <h2><a href="#section--trick">TRICK とは</a></h2> - <p> - TRICK とは RubyKaigi で不定期に開催されているコンテストで、Ruby で書かれた「変わった」コードを表彰する。早い話が <a href="https://www.ioccc.org/" rel="noreferrer" target="_blank">IOCCC</a> の Ruby 版である。 - </p> - <p> - 存在を知ってから次こそは出したいと思っていたところ、ちょうど RubyKaigi の地元開催と被ったのでこれ幸いとエントリーした。 - </p> - </section> - <section id="section--my-work"> - <h2><a href="#section--my-work">作品紹介</a></h2> - <p> - 今回頂いたのは審査員賞の一つ eto award (公式の賞の名前に合わせて敬称略) で、“Most Ruby-on-Ruby” Award (『最もRuby on Ruby賞』) として受賞した (IOCCC と同じく、それぞれの賞に個別の名前が付く)。 - </p> - <p> - ソースコード等はこちら: <a href="https://github.com/tric/trick2025/tree/main/10-nsfisis" rel="noreferrer" target="_blank">https://github.com/tric/trick2025/tree/main/10-nsfisis</a> - </p> - <p> - 今回の TRICK では <code>ruby.wasm</code> の使用が認められている。 - </p> - <blockquote> - <ul> - <li> - <strong>(NEW)</strong> You can use <a href="https://github.com/ruby/ruby.wasm" rel="noreferrer" target="_blank">ruby.wasm</a>. - </li> - </ul> - </blockquote> - <p> - 適当に HTTP サーバを立てて <a href="https://github.com/tric/trick2025/blob/main/10-nsfisis/index.html" rel="noreferrer" target="_blank"><code>index.html</code></a> を開くと、次のように <a href="https://github.com/tric/trick2025/blob/main/10-nsfisis/entry.rb" rel="noreferrer" target="_blank"><code>entry.rb</code></a> の内容が表示される。 - </p> - <p> - <img alt="ブラウザで表示された index.html のレンダリング結果。entry.rb の内容がシンタックスハイライトされて表示されており、英単語や記号に振り仮名が振られている" src="/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/screenshot.png"> - </p> - <p> - 自身のソースコードを出力するプログラム、いわゆる quine の亜種になっている。 - </p> - <p> - しかし、このプログラムは単にソースコードをそのまま出力するのではなく、 - </p> - <ul> - <li> - シンタックスハイライトして、 - </li> - <li> - 英単語や記号に振り仮名を振って、 - </li> - <li> - HTML で、 - </li> - </ul> - <p> - 表示している。つまり、Ruby プログラムにルビを振った作品である。例えば、先頭の2行目の <code>require</code> は次のような HTML で構成されている。 - </p> - <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">ruby</span><span style="color:#6F42C1"> class</span><span style="color:#24292E">=</span><span style="color:#032F62">"IDENTIFIER"</span><span style="color:#24292E">>require<</span><span style="color:#22863A">rp</span><span style="color:#6F42C1"> class</span><span style="color:#24292E">=</span><span style="color:#032F62">""</span><span style="color:#24292E">>(</</span><span style="color:#22863A">rp</span><span style="color:#24292E">><</span><span style="color:#22863A">rt</span><span style="color:#6F42C1"> class</span><span style="color:#24292E">=</span><span style="color:#032F62">""</span><span style="color:#24292E">>リクワイア</</span><span style="color:#22863A">rt</span><span style="color:#24292E">><</span><span style="color:#22863A">rp</span><span style="color:#6F42C1"> class</span><span style="color:#24292E">=</span><span style="color:#032F62">""</span><span style="color:#24292E">>)</</span><span style="color:#22863A">rp</span><span style="color:#24292E">></</span><span style="color:#22863A">ruby</span><span style="color:#24292E">></span></span></code></pre> - </div> - <p> - 順に使ったテクニックを解説していく。 - </p> - <section id="section--my-work--quine"> - <h3><a href="#section--my-work--quine">Quine</a></h3> - <p> - 改めて quine について説明する。Quine とは、自身のソースコードを出力するようなプログラムである。Ruby では様々な方法で quine を書くことができるが、この作品で使っている基本形は以下のようなものである。 - </p> - <div class="codeblock numbered"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#005CC5">eval</span><span style="color:#24292E"> $s</span><span style="color:#032F62">=<<'EOS'</span></span> -<span class="line"><span style="color:#032F62">print "eval $s=<<'EOS'</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#032F62">print $s</span></span> -<span class="line"><span style="color:#032F62">print "EOS</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#032F62">EOS</span></span></code></pre> - </div> - <p> - 変数 <code>$s</code> に 2 行目、3 行目、4 行目が入っており、それに加えて 1 行目と 5 行目を出力すれば元のソースコードが得られる。実際には <code>$s</code> を加工してシンタックスハイライトや振り仮名を振ることになる。 - </p> - </section> - <section id="section--my-work--syntax-highlight"> - <h3><a href="#section--my-work--syntax-highlight">シンタックスハイライト</a></h3> - <p> - シンタックスハイライトは、トークナイズとトークン種別に応じた色付けの2段階からなる。 - </p> - <p> - トークナイズには Ruby 3.4 からデフォルトのパーサになった <a href="https://github.com/ruby/prism" rel="noreferrer" target="_blank">Prism</a> を利用している。<code>Prism.lex()</code> を使うとトークナイズができるので、トークンに付いているソースコード位置の情報を使いつつ元のソースコードを復元する。 - </p> - <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#E36209">y</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> 1</span><span style="color:#6A737D"> # 現在の行</span></span> -<span class="line"><span style="color:#E36209">x</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> 0</span><span style="color:#6A737D"> # 現在の列</span></span> -<span class="line"><span style="color:#005CC5">Prism</span><span style="color:#24292E">.</span><span style="color:#6F42C1">lex</span><span style="color:#24292E">($s).</span><span style="color:#6F42C1">value</span><span style="color:#24292E">[..</span><span style="color:#D73A49">-</span><span style="color:#005CC5">2</span><span style="color:#24292E">].</span><span style="color:#6F42C1">each</span><span style="color:#24292E"> {|t, *|</span></span> -<span class="line"><span style="color:#E36209"> l</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> t.</span><span style="color:#6F42C1">location</span></span> -<span class="line"><span style="color:#E36209"> r</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> l.</span><span style="color:#6F42C1">start_line</span><span style="color:#6A737D"> # トークンの開始行</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> y </span><span style="color:#D73A49"><</span><span style="color:#24292E"> r </span><span style="color:#6A737D"># 改行が必要なら</span></span> -<span class="line"><span style="color:#005CC5"> p</span><span style="color:#032F62"> "</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#D73A49"> *</span><span style="color:#24292E"> (r </span><span style="color:#D73A49">-</span><span style="color:#24292E"> y) </span><span style="color:#6A737D"># 改行を挿入して</span></span> -<span class="line"><span style="color:#E36209"> x</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> 0</span><span style="color:#6A737D"> # 列の先頭へ戻る</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#E36209"> c</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> l.</span><span style="color:#6F42C1">start_column</span><span style="color:#6A737D"> # トークンの開始列</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> x </span><span style="color:#D73A49"><</span><span style="color:#24292E"> c </span><span style="color:#6A737D"># 空白が必要なら</span></span> -<span class="line"><span style="color:#005CC5"> p</span><span style="color:#032F62"> " "</span><span style="color:#D73A49"> *</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">-</span><span style="color:#24292E"> x) </span><span style="color:#6A737D"># 空白を挿入</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#005CC5"> p</span><span style="color:#6F42C1"> ruby</span><span style="color:#24292E">(t) </span><span style="color:#6A737D"># トークン本体を出力</span></span> -<span class="line"><span style="color:#E36209"> y</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> l.</span><span style="color:#6F42C1">end_line</span><span style="color:#6A737D"> # 現在行を更新</span></span> -<span class="line"><span style="color:#E36209"> x</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> l.</span><span style="color:#6F42C1">end_column</span><span style="color:#6A737D"> # 現在列を更新</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> - </div> - <p> - 補足: 変数名がやたら短いのは、このあとの振り仮名データの量を削減するため。 - </p> - <p> - トークン種別に応じた色付けは CSS でおこなっている。出力する HTML のクラス名に <code>Prism::Token#type</code> を指定しておいて、<code>index.html</code> でそれぞれのクラスにスタイルを当てた。 - </p> - <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E"> <</span><span style="color:#22863A">style</span><span style="color:#24292E">></span></span> -<span class="line"><span style="color:#6A737D"> /* ... */</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1"> .COMMENT</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#005CC5"> color</span><span style="color:#24292E">: </span><span style="color:#005CC5">#777</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#005CC5"> font-style</span><span style="color:#24292E">: </span><span style="color:#005CC5">italic</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1"> .CONSTANT</span><span style="color:#24292E">, </span><span style="color:#6F42C1">.GLOBAL_VARIABLE</span><span style="color:#24292E">, </span><span style="color:#6F42C1">.INSTANCE_VARIABLE</span><span style="color:#24292E">, </span><span style="color:#6F42C1">.IDENTIFIER</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#005CC5"> color</span><span style="color:#24292E">: </span><span style="color:#005CC5">#088</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D"> /* ... */</span></span> -<span class="line"><span style="color:#24292E"> </</span><span style="color:#22863A">style</span><span style="color:#24292E">></span></span></code></pre> - </div> - <p> - トークン種別の列挙にはそれなりに文字数を使ってしまうのだが、今回の TRICK のレギュレーションでは <code>index.html</code> にサイズ制限がなかったので好きに色を付けることができた。 - </p> - </section> - <section id="section--my-work--ruby-text"> - <h3><a href="#section--my-work--ruby-text">振り仮名</a></h3> - <p> - それぞれの英単語や記号に対応した振り仮名のデータは、プログラム中に埋め込まれている。 - </p> - <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">def</span><span style="color:#6F42C1"> rt</span><span style="color:#24292E">(t)</span></span> -<span class="line"><span style="color:#E36209"> r</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#005CC5"> :"&&"</span><span style="color:#24292E"> => </span><span style="color:#032F62">"1136"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> :"="</span><span style="color:#24292E"> => </span><span style="color:#032F62">"04199275"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> :"||"</span><span style="color:#24292E"> => </span><span style="color:#032F62">"623147"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> :$s</span><span style="color:#24292E"> => </span><span style="color:#032F62">"41750825"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> :*</span><span style="color:#24292E"> => </span><span style="color:#032F62">"111775"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#6A737D"> # ...</span></span> -<span class="line"><span style="color:#005CC5"> type:</span><span style="color:#032F62"> "310455"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> utf_8:</span><span style="color:#032F62"> "70923803920853080440"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> value:</span><span style="color:#032F62"> "48746992"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> x:</span><span style="color:#032F62"> "08351525"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> y:</span><span style="color:#032F62"> "7904"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#6F42C1"> kana</span><span style="color:#24292E">(</span></span> -<span class="line"><span style="color:#24292E"> r[</span><span style="color:#005CC5">:"#{t.</span><span style="color:#6F42C1">type</span><span style="color:#005CC5">}"</span><span style="color:#24292E">] </span><span style="color:#D73A49">||</span></span> -<span class="line"><span style="color:#24292E"> r[s </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> :"#{t.</span><span style="color:#6F42C1">value</span><span style="color:#005CC5">.</span><span style="color:#6F42C1">downcase</span><span style="color:#005CC5">}"</span><span style="color:#24292E">] </span><span style="color:#D73A49">||</span></span> -<span class="line"><span style="color:#24292E"> s.</span><span style="color:#6F42C1">end_with?</span><span style="color:#24292E">(</span><span style="color:#032F62">":"</span><span style="color:#24292E">) </span><span style="color:#D73A49">&&</span><span style="color:#24292E"> r[</span><span style="color:#005CC5">:"#{s[..</span><span style="color:#D73A49">-</span><span style="color:#005CC5">2]}"</span><span style="color:#24292E">] </span><span style="color:#D73A49">||</span></span> -<span class="line"><span style="color:#005CC5"> nil</span></span> -<span class="line"><span style="color:#24292E"> )</span></span> -<span class="line"><span style="color:#D73A49">end</span></span></code></pre> - </div> - <p> - トークンの種類 (<code>t.type</code>) またはトークンの文字列表現そのもの (<code>t.value.downcase</code>) を使ってテーブルを引いて振り仮名へ変換している。このテーブルのキー部分そのものにも振り仮名を振るために、トークンが <code>:</code> で終わっていれば <code>:</code> を取り除いて振り仮名を得ている (例: <code>"value:"</code> → <code>"value"</code> → <code>"48746992"</code>)。 - </p> - <p> - このテーブルはサイズ制限を突破するために圧縮されており、<code>kana()</code> 関数で展開される。 - </p> - <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">def</span><span style="color:#6F42C1"> kana</span><span style="color:#24292E">(s)</span></span> -<span class="line"><span style="color:#24292E"> s</span></span> -<span class="line"><span style="color:#D73A49"> &.</span><span style="color:#6F42C1">scan</span><span style="color:#24292E">(</span><span style="color:#032F62">/.{2}/</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49"> &.</span><span style="color:#6F42C1">map</span><span style="color:#24292E">{|c| (</span><span style="color:#005CC5">0x30A0</span><span style="color:#D73A49"> +</span><span style="color:#24292E"> c.</span><span style="color:#6F42C1">to_i</span><span style="color:#24292E">).</span><span style="color:#6F42C1">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">Encoding</span><span style="color:#24292E">::</span><span style="color:#005CC5">UTF_8</span><span style="color:#24292E">)}</span></span> -<span class="line"><span style="color:#D73A49"> &.*</span><span style="color:#24292E">(</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49">end</span></span></code></pre> - </div> - <p> - 例えば <code>value</code> に対応する振り仮名データ <code>"48746992"</code> であれば、次のような変換を経て振り仮名へと展開される。 - </p> - <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E"> s</span></span> -<span class="line"><span style="color:#6A737D"> # => "48746992"</span></span> -<span class="line"><span style="color:#D73A49"> &.</span><span style="color:#6F42C1">scan</span><span style="color:#24292E">(</span><span style="color:#032F62">/.{2}/</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#6A737D"> # => ["48", "74", "69", "92"]</span></span> -<span class="line"><span style="color:#D73A49"> &.</span><span style="color:#6F42C1">map</span><span style="color:#24292E">{|c| (</span><span style="color:#005CC5">0x30A0</span><span style="color:#D73A49"> +</span><span style="color:#24292E"> c.</span><span style="color:#6F42C1">to_i</span><span style="color:#24292E">).</span><span style="color:#6F42C1">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">Encoding</span><span style="color:#24292E">::</span><span style="color:#005CC5">UTF_8</span><span style="color:#24292E">)}</span></span> -<span class="line"><span style="color:#6A737D"> # => ["バ", "リ", "ュ", "ー"]</span></span> -<span class="line"><span style="color:#D73A49"> &.*</span><span style="color:#24292E">(</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#6A737D"> # => "バリュー"</span></span></code></pre> - </div> - <p> - これは後で気付いたのだが、Ruby は多倍長整数が扱えるので <code>"48746992"</code> のようなデータは単に <code>48746992</code> と書けばよかった。<code>kana()</code> 関数が多少長くはなるが、振り仮名データの数 x 2 バイト分サイズが減るのでこちらの方が短くなる。サイズ制限の都合で振り仮名を振るのを諦めた記号もあったのでもったいない。 - </p> - </section> - </section> - <section id="section--outro"> - <h2><a href="#section--outro">おわりに</a></h2> - <p> - 本っ当に取りたかったので心から嬉しいです。全部で 3作提出したのですが、他の 2つも選外佳作として選出していただけた上、そのうちの “Least Truthful” については最後に Matz 氏から言及があり、審査員賞と合わせて望外の栄誉となりました。 - </p> - <p> - ありがとうございました! - </p> - </section> - </div> - </article> - </main> - <footer class="footer"> - © 2021 nsfisis - </footer> - </body> -</html> |
