From 9d5ec5e3bc01c6174dea048e118edee579c36565 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 7 Feb 2026 23:06:23 +0900 Subject: fix(style): fix codeblock style for rouge --- .../trick-2025-most-ruby-on-ruby-award/index.html | 153 ++++++++++----------- 1 file changed, 73 insertions(+), 80 deletions(-) (limited to 'services/nuldoc/public/blog/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/index.html') diff --git a/services/nuldoc/public/blog/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/index.html b/services/nuldoc/public/blog/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/index.html index 79e31d70..01cecbe3 100644 --- a/services/nuldoc/public/blog/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/index.html +++ b/services/nuldoc/public/blog/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/index.html @@ -15,7 +15,7 @@ RubyKaigi 2025 の TRICK で入賞した|REPL: Rest-Eat-Program Loop - +
@@ -161,8 +161,7 @@ 表示している。つまり、Ruby プログラムにルビを振った作品である。例えば、先頭の2行目の require は次のような HTML で構成されている。

-
<ruby class="IDENTIFIER">require<rp class="">(</rp><rt class="">リクワイア</rt><rp class="">)</rp></ruby>
-
+
<ruby class="IDENTIFIER">require<rp class="">(</rp><rt class="">リクワイア</rt><rp class="">)</rp></ruby>

順に使ったテクニックを解説していく。 @@ -173,12 +172,11 @@ 改めて quine について説明する。Quine とは、自身のソースコードを出力するようなプログラムである。Ruby では様々な方法で quine を書くことができるが、この作品で使っている基本形は以下のようなものである。

-
eval $s=<<'EOS'
-print "eval $s=<<'EOS'\n"
-print $s
-print "EOS\n"
-EOS
-
+
eval $s=<<'EOS' +
print "eval $s=<<'EOS'\n" +
print $s +
print "EOS\n" +
EOS

変数 $s に 2 行目、3 行目、4 行目が入っており、それに加えて 1 行目と 5 行目を出力すれば元のソースコードが得られる。実際には $s を加工してシンタックスハイライトや振り仮名を振ることになる。 @@ -193,24 +191,23 @@ print "EOS\nPrism を利用している。Prism.lex() を使うとトークナイズができるので、トークンに付いているソースコード位置の情報を使いつつ元のソースコードを復元する。

-
y = 1                 # 現在の行
-x = 0                 # 現在の列
-Prism.lex($s).value[..-2].each {|t, *|
-  l = t.location
-  r = l.start_line    # トークンの開始行
-  if y < r            # 改行が必要なら
-    p "\n" * (r - y)  #   改行を挿入して
-    x = 0             #   列の先頭へ戻る
-  end
-  c = l.start_column  # トークンの開始列
-  if x < c            # 空白が必要なら
-    p " " * (c - x)   #   空白を挿入
-  end
-  p ruby(t)           # トークン本体を出力
-  y = l.end_line      # 現在行を更新
-  x = l.end_column    # 現在列を更新
-}
-
+
y = 1 # 現在の行 +
x = 0 # 現在の列 +
Prism.lex($s).value[..-2].each {|t, *| +
l = t.location +
r = l.start_line # トークンの開始行 +
if y < r # 改行が必要なら +
p "\n" * (r - y) # 改行を挿入して +
x = 0 # 列の先頭へ戻る +
end +
c = l.start_column # トークンの開始列 +
if x < c # 空白が必要なら +
p " " * (c - x) # 空白を挿入 +
end +
p ruby(t) # トークン本体を出力 +
y = l.end_line # 現在行を更新 +
x = l.end_column # 現在列を更新 +
}

補足: 変数名がやたら短いのは、このあとの振り仮名データの量を削減するため。 @@ -219,21 +216,20 @@ print "EOS\n -

    <style>
-      /* ... */
-
-      .COMMENT {
-        color: #777;
-        font-style: italic;
-      }
-
-      .CONSTANT, .GLOBAL_VARIABLE, .INSTANCE_VARIABLE, .IDENTIFIER {
-        color: #088;
-      }
-
-      /* ... */
-    </style>
-
+
<style> +
/* ... */ +
+
.COMMENT { +
color: #777; +
font-style: italic; +
} +
+
.CONSTANT, .GLOBAL_VARIABLE, .INSTANCE_VARIABLE, .IDENTIFIER { +
color: #088; +
} +
+
/* ... */ +
</style>

トークン種別の列挙にはそれなりに文字数を使ってしまうのだが、今回の TRICK のレギュレーションでは index.html にサイズ制限がなかったので好きに色を付けることができた。 @@ -245,28 +241,27 @@ print "EOS\n -

def rt(t)
-  r = {
-    :"&&" => "1136",
-    :"=" => "04199275",
-    :"||" => "623147",
-    :$s => "41750825",
-    :* => "111775",
-    # ...
-    type: "310455",
-    utf_8: "70923803920853080440",
-    value: "48746992",
-    x: "08351525",
-    y: "7904",
-  }
-  kana(
-    r[:"#{t.type}"] ||
-    r[s = :"#{t.value.downcase}"] ||
-    s.end_with?(":") && r[:"#{s[..-2]}"] ||
-    nil
-  )
-end
-
+
def rt(t) +
r = { +
:"&&" => "1136", +
:"=" => "04199275", +
:"||" => "623147", +
:$s => "41750825", +
:* => "111775", +
# ... +
type: "310455", +
utf_8: "70923803920853080440", +
value: "48746992", +
x: "08351525", +
y: "7904", +
} +
kana( +
r[:"#{t.type}"] || +
r[s = :"#{t.value.downcase}"] || +
s.end_with?(":") && r[:"#{s[..-2]}"] || +
nil +
) +
end

トークンの種類 (t.type) またはトークンの文字列表現そのもの (t.value.downcase) を使ってテーブルを引いて振り仮名へ変換している。このテーブルのキー部分そのものにも振り仮名を振るために、トークンが : で終わっていれば : を取り除いて振り仮名を得ている (例: "value:""value""48746992")。 @@ -275,27 +270,25 @@ print "EOS\n -

def kana(s)
-  s
-    &.scan(/.{2}/)
-    &.map{|c| (0x30A0 + c.to_i).chr(Encoding::UTF_8)}
-    &.*("")
-end
-
+
def kana(s) +
s +
&.scan(/.{2}/) +
&.map{|c| (0x30A0 + c.to_i).chr(Encoding::UTF_8)} +
&.*("") +
end

例えば value に対応する振り仮名データ "48746992" であれば、次のような変換を経て振り仮名へと展開される。

-
  s
-    # => "48746992"
-    &.scan(/.{2}/)
-    # => ["48", "74", "69", "92"]
-    &.map{|c| (0x30A0 + c.to_i).chr(Encoding::UTF_8)}
-    # => ["バ", "リ", "ュ", "ー"]
-    &.*("")
-    # => "バリュー"
-
+
s +
# => "48746992" +
&.scan(/.{2}/) +
# => ["48", "74", "69", "92"] +
&.map{|c| (0x30A0 + c.to_i).chr(Encoding::UTF_8)} +
# => ["バ", "リ", "ュ", "ー"] +
&.*("") +
# => "バリュー"

これは後で気付いたのだが、Ruby は多倍長整数が扱えるので "48746992" のようなデータは単に 48746992 と書けばよかった。kana() 関数が多少長くはなるが、振り仮名データの数 x 2 バイト分サイズが減るのでこちらの方が短くなる。サイズ制限の都合で振り仮名を振るのを諦めた記号もあったのでもったいない。 -- cgit v1.3-1-g0d28