diff options
Diffstat (limited to 'public/posts')
18 files changed, 7150 insertions, 0 deletions
diff --git a/public/posts/2021-03-05/my-first-post/index.html b/public/posts/2021-03-05/my-first-post/index.html new file mode 100644 index 0000000..fbf7237 --- /dev/null +++ b/public/posts/2021-03-05/my-first-post/index.html @@ -0,0 +1,71 @@ +<!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="© nsfisis"> + <meta name="description" content="これはテスト投稿です。これはテスト投稿です。これはテスト投稿です。"> + <meta name="keywords" content=""> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>My First Post | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">My First Post</h1> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2021-03-05">2021-03-05</time>: 公開 + </li> + + </ol> + </section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + Test + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim +veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea +commodo consequat. Duis aute irure dolor in reprehenderit in voluptate +velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint +occaecat cupidatat non proident, sunt in culpa qui officia deserunt +mollit anim id est laborum.</p> +</div> + </div> +</section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2021-03-30/phperkaigi-2021/index.html b/public/posts/2021-03-30/phperkaigi-2021/index.html new file mode 100644 index 0000000..46fce9b --- /dev/null +++ b/public/posts/2021-03-30/phperkaigi-2021/index.html @@ -0,0 +1,1195 @@ +<!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="© nsfisis"> + <meta name="description" content="2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。"> + <meta name="keywords" content="カンファレンス,PHP,PHPerKaigi"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>PHPerKaigi 2021 | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">PHPerKaigi 2021</h1> + + <ul class="post-tags"> + + <li class="tag"> + <a href="/tags/conference/">カンファレンス</a> + </li> + + <li class="tag"> + <a href="/tags/php/">PHP</a> + </li> + + <li class="tag"> + <a href="/tags/phperkaigi/">PHPerKaigi</a> + </li> + + </ul> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2021-03-30">2021-03-30</time>: 公開 + </li> + + </ol> + </section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + PHPerKaigi 2021 参加レポ + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>2021-03-26 から 2021-03-28 +にかけて開催された、 <a href="https://phperkaigi.jp/2021/">PHPerKaigi 2021</a> +に一般参加者として参加した。 +弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> +(今年1月から勤務) +はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p> +</div> +<div class="paragraph"> +<p>このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。</p> +</div> +<div class="paragraph"> +<p>発表はトラック A、B に分かれていたのだが、今回はすべて A +トラックを視聴している (切り替えるのが面倒だっただけ)。</p> +</div> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + 凡例 + + </h3> + <div class="section-body"> + <div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>発表・スライドのメモ (引用ではない)</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>感想など</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + Day 0 前夜祭 (2021/03/27) + + </h3> + <div class="section-body"> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 17:30 [A] + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>PHP で AWS Lambda</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>Rails のプロジェクトを PHPer のメンバのみでメンテ →他のメンバもわかる +PHP にリプレースを検討</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>サーバレス</p> +</li> +<li> +<p>サーバ・インフラの管理が不要</p> +</li> +<li> +<p>アプリケーションコードの知識だけで保守可能</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>ゼロベースで作れる案件が (Railsの件とは別に) +あるため、そちらで試験的に導入?</p> +</div> +<div class="paragraph"> +<p>AWSの学習 AWS のドキュメント DevelopersIO</p> +</div> +<div class="paragraph"> +<p>AWS Lambda のカスタムランタイムで PHP を動かす</p> +</div> +<div class="paragraph"> +<p>サーバのセットアップや維持管理を気にしなくて良い サーバーレスで PHP +を動かすツールがすでにある サーバーレス構築はすんなり</p> +</div> +<div class="paragraph"> +<p>今は Laravel がルーティングしている Laravel Livewire を Lambda +に載せられないか? デプロイ方法は? バッチ処理は? (Lambda は +15分の制限)</p> +</div> +<div class="paragraph"> +<p>Lambda でコンテナイメージがサポートされるように</p> +</div> +<div class="paragraph"> +<p>抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>AWS Lambda のような Function as a Service +はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に +web サービスを作る具体的なイメージがまだ見えない (注: すべて for me +として書いている)。</p> +</div> +<div class="paragraph"> +<p>PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。</p> +</div> +<div class="paragraph"> +<p>勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP<br> +Laravel などでは動かなさそう) +だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 18:10 [A] + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>大規模サイトの SEO</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>大規模サイト (100万ページ以上) Google の基準</p> +</div> +<div class="paragraph"> +<p>クロールバジェットを意識したSEO</p> +</div> +<div class="paragraph"> +<p>大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト +(10,000以上) でコンテンツが目まぐるしく変更される +これを満たさないなら、クロールバジェットを考えなくてもいい</p> +</div> +<div class="paragraph"> +<p>サーチコンソール 「カバレッジ」の「除外」 +多すぎるのは問題→クロールバジェットを浪費している</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>クエリの順番を決める</p> +</li> +<li> +<p>空の値のルールを決めておく</p> +</li> +<li> +<p>リダイレクトすればインデックスはうまくいく</p> +</li> +<li> +<p>リンクが存在する限りクロールはされる</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>リニューアル前のURL</p> +</div> +<div class="paragraph"> +<p>インデックスは移行される +リンクのURLが存在する限り、別のURLとしてクロールされる +リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い +リニューアルで無視されるようになったパラメータも注意</p> +</div> +<div class="paragraph"> +<p>robotes.txt で拒否しているのにクロールされる 一時的に拒否を外して 404 や +301 を読ませる 内部リンクを確認する JS でのリンクに書き換え</p> +</div> +<div class="paragraph"> +<p>クエリパラメータからURLのパスに <code>/tokyo?area=HOGE</code> → <code>/tokyo/HOGE</code></p> +</div> +<div class="paragraph"> +<p>URL 設計だいじ</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>SEO (Search Engine Optimization) +は大して知らないので新鮮な話が多かった。その分語れることも少ない……。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 18:50 [A] + + </h4> + <div class="section-body"> + <div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>知覚可能 操作可能 理解可能 堅牢 ちゃんとしたHTMLを書く +(閉じタグ・入れ子構造など)</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>標準の HTML を適切に使う</p> +</li> +<li> +<p>WAI-ARIA</p> +</li> +<li> +<p>キーボードフレンドリー</p> +</li> +<li> +<p>マシンフレンドリー</p> +</li> +<li> +<p>SEOフレンドリー</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>button タグ →キーボード h1 タグ →スクリーンリーダー・クローラ a タグ</p> +</div> +<div class="paragraph"> +<p>WAI-ARIA HTML では表現できないセマンティクスを追加する</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>ロール</p> +<div class="ulist"> +<ul> +<li> +<p>何をするのか?</p> +</li> +<li> +<p>ユーザーアクションによって変化しない</p> +</li> +</ul> +</div> +</li> +<li> +<p>プロパティ</p> +<div class="ulist"> +<ul> +<li> +<p>関連づけられたデータ</p> +</li> +</ul> +</div> +</li> +<li> +<p>ステート</p> +<div class="ulist"> +<ul> +<li> +<p>現在の状態</p> +</li> +</ul> +</div> +</li> +</ul> +</div> +<div class="paragraph"> +<p>まずは標準の HTML 要素で解決する 何でもかんでも WAI-ARIA +を使えばいいというものではない</p> +</div> +<div class="paragraph"> +<p>マウスホバーでツールチップが出てくるが、キーボード操作では出てこない</p> +</div> +<div class="paragraph"> +<p>VoiceOver</p> +</div> +<div class="paragraph"> +<p>全ての属性を使う必要はない +あくまでアクセシビリティを上げるための方法の一つにすぎない</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>つい最近 WAI-ARIA +についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) +いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 19:30 [A] + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>PHP で FUSE</p> +</div> +<div class="paragraph"> +<p>個人的に楽しみだった発表。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>VFS (virtual filesystem) vs 具体的なファイルシステム</p> +</div> +<div class="paragraph"> +<p>最適な実装方法は状況により異なる</p> +</div> +<div class="paragraph"> +<p>アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS</p> +</div> +<div class="paragraph"> +<p>カーネルのプログラムを作るのは難しい +* 権限がデカすぎる +* システム全体がクラッシュ +* セキュリティリスク +* 開発サイクルを回しづらい +* ネイティブコードにコンパイルされる言語である必要がある</p> +</div> +<div class="paragraph"> +<p>Filesystem in USEr space (FUSE)</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>特定の C の関数を呼ぶことで filesystem が作れる</p> +</li> +<li> +<p>FFI を持つ言語なら FUSE が使える</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>SSHFS / s3fs / Docker Desktop</p> +</div> +<div class="paragraph"> +<p>Linux 以外でも使える</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>dokany (on Windows)</p> +</li> +<li> +<p>osxfuse</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>VFS: システムコールが呼ばれると、ファイルシステムによってコール FUSE: +カーネル空間からユーザ空間へ通信</p> +</div> +<div class="paragraph"> +<p>高レベルなラッパで型をつける</p> +</div> +<div class="paragraph"> +<p>PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>grep できる</p> +</li> +<li> +<p>sed できる</p> +</li> +<li> +<p>編集できる</p> +</li> +</ul> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>期待通りの興味深い発表だった。FUSE +自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。 +この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ +(ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。</p> +</div> + </div> +</section> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + Day 1 (2021/03/27) + + </h3> + <div class="section-body"> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 10:50 [A] + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>ATDD</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="ulist"> +<ul> +<li> +<p>ユーザーストーリー</p> +</li> +<li> +<p>ユニットテスト</p> +</li> +<li> +<p>CI/CD</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>ユーザストーリーの受け入れ条件が曖昧になりがち +デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている</p> +</div> +<div class="paragraph"> +<p>Q2の強化 アジャイルテストの4象限</p> +</div> +<div class="paragraph"> +<p>技術面/ビジネス面 +開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>Q1: 技術面 & チーム支援</p> +<div class="ulist"> +<ul> +<li> +<p>TDD</p> +</li> +<li> +<p>ユニットテストなど</p> +</li> +</ul> +</div> +</li> +<li> +<p>Q2: ビジネス面 & チーム支援</p> +<div class="ulist"> +<ul> +<li> +<p>ATDD</p> +</li> +<li> +<p>ビジネス面の受け入れテストで駆動する</p> +</li> +</ul> +</div> +</li> +</ul> +</div> +<div class="paragraph"> +<p>Agile Alliance ユーザストーリーのスキルレベルを高める</p> +</div> +<div class="paragraph"> +<p>テストピラミッド</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>UI Tests</p> +</li> +<li> +<p>Service Tests</p> +</li> +<li> +<p>Unit Tests</p> +</li> +<li> +<p>異なる粒度のテストを書く</p> +</li> +<li> +<p>高レベルになるほど、持つべきテストは少なくなる</p> +<div class="ulist"> +<ul> +<li> +<p>ピラミッド型になる</p> +</li> +</ul> +</div> +</li> +</ul> +</div> +<div class="paragraph"> +<p>高レベルテストが多すぎる→アイスクリームコーン アンチパターン</p> +</div> +<div class="paragraph"> +<p>ATDD (Acceptance TDD) API経由・UI経由での高レベルテスト E2E test</p> +</div> +<div class="paragraph"> +<p>ストーリ受け入れテスト</p> +</div> +<div class="paragraph"> +<p>入れ子のフィードバックループ ATDD(外側) と TDD(内側)</p> +</div> +<div class="paragraph"> +<p>外部品質・内部品質</p> +</div> +<div class="paragraph"> +<p>バーティカルスライスのデリバリー</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>cucumber</p> +</li> +<li> +<p>gauge</p> +</li> +<li> +<p>behat</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>ユビキタス言語 手動テストもspecに書く 自動化は可能だがコスパが悪い +失敗することがわかっているテスト(レッドテスト)はCIから外す +失敗時の原因究明が難しい 饒舌なエラーメッセージ 状況のスナップショット</p> +</div> +<div class="paragraph"> +<p>Continuous Testing</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>User Acceptance Test (UAT) +くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。 +高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 11:50 [A] + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>型解析を用いたリファクタリング</p> +</div> +<div class="paragraph"> +<p>型のある世界で生きてきた身として大いに楽しみにしていた発表。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="ulist"> +<ul> +<li> +<p>PHPStan</p> +</li> +<li> +<p>Phan</p> +</li> +<li> +<p>Psalm</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>autoload も認識できる bootstrapFiles</p> +</div> +<div class="paragraph"> +<p>編集箇所と利用箇所を CI でチェック ルールレベルを徐々に引き上げていく +警告が多すぎると見落としてしまう・無視されやすくなる</p> +</div> +<div class="paragraph"> +<p>型がついていないことによるエラーが多い</p> +</div> +<div class="paragraph"> +<p>型よりも詳細な検査 <code>Util_Assert::min</code></p> +</div> +<div class="paragraph"> +<p>SQL を静的解析 placeholder の型付け</p> +</div> +<div class="paragraph"> +<p>警告レベルを低いレベルから導入 タイプヒントを積極的に書いていく PHPStan +の拡張を追加する</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。 +今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で +Ruby の typeprof には注目している。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 12:30 [A] + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>昼食をとっていた。事前に何か食料を買っておくべきだった。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 13:10 [A] + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>Documentation as Code</p> +</div> +<div class="paragraph"> +<p>この発表も以前から非常に楽しみにしていた。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>開発開始までのオーバーヘッド 新規にチームにジョイン +担当範囲外の機能を理解 オンボーディングのコスト</p> +</div> +<div class="paragraph"> +<p>PHPerKaigi 2020 で発表あり</p> +</div> +<div class="paragraph"> +<p>継続的にシステムの理解を助けるドキュメント</p> +</div> +<div class="paragraph"> +<p>継続的ドキュメンテーション システムとドキュメントの乖離</p> +</div> +<div class="paragraph"> +<p>書いてあることが間違っている・足りない * 徐々にずれていく * +システムの更新タイミングとドキュメントの更新タイミングに差がある</p> +</div> +<div class="paragraph"> +<p>システムとドキュメントは対応関係がある * 間違ったドキュメント * +存在しないドキュメント</p> +</div> +<div class="paragraph"> +<p>システムとドキュメントの乖離を定量化する 継続的に +システムの更新に近いタイミングで ドキュメントを更新し続ける</p> +</div> +<div class="paragraph"> +<p>Documentation as Code</p> +</div> +<div class="paragraph"> +<p>コードと同じツールでドキュメントを書く * issue tracker * vcs * plain +text markup * automation</p> +</div> +<div class="paragraph"> +<p>開発者 システム ドキュメント 構造化データ ソフトウェア</p> +</div> +<div class="paragraph"> +<p>システムから構造化データを抽出する PHPDoc OpenAPI</p> +</div> +<div class="paragraph"> +<p>ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する</p> +</div> +<div class="paragraph"> +<p>ビューの単位でドキュメントに</p> +</div> +<div class="paragraph"> +<p>スタックトレースからのドキュメント生成</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な +(乖離しない) +情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 14:10 [A] + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>cookie による session 管理</p> +</div> +<div class="paragraph"> +<p>全体的に基本的な話だったので特に触れない。Cookie +やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 14:50 [A] + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>PHP のエラーと例外</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>エラー PHPエンジンがエラーを通知する 例外 プログラムが投げる</p> +</div> +<div class="paragraph"> +<p>PHP7-8とエラー</p> +</div> +<div class="paragraph"> +<p>PHPエンジンのエラーの一部が に変換されるようになった → try-catch +で捕捉できる</p> +</div> +<div class="paragraph"> +<p>は例外とは異なる</p> +</div> +<div class="paragraph"> +<p>PHP8 でエラーレベルの引き上げ</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>捕捉すべきもの</p> +<div class="ulist"> +<ul> +<li> +<p>recoverable</p> +</li> +</ul> +</div> +</li> +<li> +<p>捕捉すべきでないもの</p> +<div class="ulist"> +<ul> +<li> +<p>unrecoverable</p> +</li> +<li> +<p>開発時に対処できるもの</p> +</li> +</ul> +</div> +</li> +</ul> +</div> +<div class="paragraph"> +<p>例外 * 捕捉して事後処理 * 捕捉せず(or 捕捉した上で)さらに上に是非を問う</p> +</div> +<div class="paragraph"> +<p>開発段階で例外を把握し、ハンドリングを考えておく</p> +</div> +<div class="paragraph"> +<p>と</p> +</div> +<div class="paragraph"> +<p>はキャッチすべきでない</p> +</div> +<div class="ulist"> +<ul> +<li> +<p></p> +<div class="ulist"> +<ul> +<li> +<p>本番で起きてはいけない</p> +</li> +</ul> +</div> +</li> +<li> +<p></p> +<div class="ulist"> +<ul> +<li> +<p>本番で起きてはいけない →生じないのだから捕捉もしない</p> +</li> +</ul> +</div> +</li> +<li> +<p></p> +<div class="ulist"> +<ul> +<li> +<p>起こるかもしれないので本番環境でも考慮する</p> +</li> +</ul> +</div> +</li> +</ul> +</div> +<div class="paragraph"> +<p>捕捉して対応するのではなく、未然に防ぐ</p> +</div> +<div class="paragraph"> +<p>独自例外を使う を投げてしまうと、 catch ()せざるを得ない →catch +範囲が広すぎる</p> +</div> +<div class="paragraph"> +<p>SPL の例外を使う</p> +</div> +<div class="paragraph"> +<p>例外翻訳 +上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する +下位レイヤの知識に依存させない</p> +</div> +<div class="paragraph"> +<p>@throws 捕捉してほしい例外を書き連ねておく</p> +</div> +<div class="paragraph"> +<p>呼び出しもとに負わせたい責任</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で +PHP を書き始めてから 4ヶ月ほどになる)。</p> +</div> +<div class="paragraph"> +<p>個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell +などのエラーを「値として」扱う言語だと思っている。try-catch +は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は +C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる +(C のそれはまともな型付けではない。念のため)。</p> +</div> +<div class="paragraph"> +<p>PHP +のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 15:30 [A] + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>Laravel のメール認証</p> +</div> +<div class="paragraph"> +<p>Laravel +の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 16:10 [A] + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>gRPC</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>Unary RPCs Server streaming RPCs Client streaming RPCs Bidirectional +streaming RPCs</p> +</div> +<div class="paragraph"> +<p>Protobuf</p> +</div> +<div class="paragraph"> +<p>実装とAPIが乖離しにくい 自動生成 複数言語でも相互に使える</p> +</div> +<div class="paragraph"> +<p>マイクロサービスのサービス通信 スマホアプリ ゲームサーバ</p> +</div> +<div class="paragraph"> +<p>PHP では?</p> +</div> +<div class="paragraph"> +<p>PHP ではストリーミングが難しい リクエストごとにプロセスが使い捨て</p> +</div> +<div class="paragraph"> +<p>PHP ではgRPCのクライアントしか対応していない</p> +</div> +<div class="paragraph"> +<p>gRPC-Web ブラウザで扱うためのJSライブラリ+プロトコル</p> +</div> +<div class="paragraph"> +<p>HTTP/1.1 でも使える Unary RPC と Server streaming RPC のみ</p> +</div> +<div class="paragraph"> +<p>Envoy Nginx などで相互に gRPC と gRPC-Web で変換</p> +</div> +<div class="paragraph"> +<p>Amp イベント駆動な並行処理のフレームワーク</p> +</div> +<div class="paragraph"> +<p>HTTP/2 対応</p> +</div> +<div class="paragraph"> +<p>C#のgRPC-Webが楽</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>(発表の中でもまさに同じことをおっしゃっていたが) PHP +以外の方が向いているだろう、というのが第一の感想である。gRPC +はそれ自体というよりも Protobuf +というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 16:50 [A] + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>アーキテクチャテスト</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>Independent Core Layer Pattern</p> +</div> +<div class="paragraph"> +<p>開発初期のアーキテクチャが崩れる +アーキテクチャ観点のコードレビューができない</p> +</div> +<div class="paragraph"> +<p>どこにクラスを置けばよいか? ドキュメントがない</p> +</div> +<div class="paragraph"> +<p>アーキテクチャ設計に関する知識が属人化・暗黙知化</p> +</div> +<div class="paragraph"> +<p>ガイドライン * 最初にルールを決めるのは簡単 * +ルール通り作り始めるのも簡単 * +→維持するのが難しい、人が決めたものゆえ壊れやすい</p> +</div> +<div class="paragraph"> +<p>PHP の特性 * クラスは public * 可視性の制御が public / protected / +private のみ * 依存関係の制御が困難</p> +</div> +<div class="paragraph"> +<p>アーキテクチャテスト +クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>deptrac</p> +</li> +<li> +<p>phpat</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>Independent Core Layer Pattern</p> +</div> +<div class="paragraph"> +<p>アーキテクチャテストの失敗 * 実装誤り * or アーキテクチャが適切でない * +開発の過程でフィードバックしていく</p> +</div> +<div class="paragraph"> +<p>モジュラーモノリス→マイクロサービスへ</p> +</div> +</blockquote> +</div> + </div> +</section> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + Day 2 (2021/03/28) + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。</p> +</div> +<div class="paragraph"> +<p>残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + 全体の感想 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>Day 2 +にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも +(特に初参加者として) 嬉しいポイントだった。</p> +</div> +<div class="paragraph"> +<p>今回、雑談/登壇者への質問等向けに Discord +サーバもあったのだが、こちらは参加こそしたものの ROM +のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord +表示に +1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった +(さらにいうと Zoom +でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。</p> +</div> +<div class="paragraph"> +<p>1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord +しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。 +まあ初カンファレンスだし、とお茶を濁しておこう。</p> +</div> +<div class="paragraph"> +<p>さて、カンファレンスで一つ気になったことがある。それは、Discord +という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord +の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord +があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。</p> +</div> +<hr> +<div class="paragraph"> +<p>最後になりましたが、毎年の PHPerKaigi +開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました! +(ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)</p> +</div> +<div class="paragraph"> +<p>ではまた来年。</p> +</div> + </div> +</section> + </div> +</section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html b/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html new file mode 100644 index 0000000..16a8188 --- /dev/null +++ b/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html @@ -0,0 +1,209 @@ +<!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="© nsfisis"> + <meta name="description" content="C++ の属性構文の属性名には、キーワードが使える。ネタ記事。"> + <meta name="keywords" content="C++,C++ 17"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>【C++】属性構文の属性名にはキーワードが使える | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">【C++】属性構文の属性名にはキーワードが使える</h1> + + <ul class="post-tags"> + + <li class="tag"> + <a href="/tags/cpp/">C++</a> + </li> + + <li class="tag"> + <a href="/tags/cpp17/">C++ 17</a> + </li> + + </ul> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植 + </li> + + </ol> + </section> + <div class="paragraph"> +<p>この記事は Qiita から移植してきたものです。 元 URL: +<a href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b" class="bare">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</a></p> +</div> +<hr> +<div class="paragraph"> +<p>タイトル落ち。まずはこのコードを見て欲しい。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="cpp"><span class="cp">#include</span> <span class="cpf"><iostream></span><span class="cp"> +</span> +<span class="p">[[</span><span class="k">alignas</span><span class="p">]]</span> <span class="p">[[</span><span class="k">alignof</span><span class="p">]]</span> <span class="p">[[</span><span class="n">and</span><span class="p">]]</span> <span class="p">[[</span><span class="n">and_eq</span><span class="p">]]</span> <span class="p">[[</span><span class="k">asm</span><span class="p">]]</span> <span class="p">[[</span><span class="k">auto</span><span class="p">]]</span> <span class="p">[[</span><span class="n">bitand</span><span class="p">]]</span> +<span class="p">[[</span><span class="n">bitor</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">bool</span><span class="p">]]</span> <span class="p">[[</span><span class="k">break</span><span class="p">]]</span> <span class="p">[[</span><span class="k">case</span><span class="p">]]</span> <span class="p">[[</span><span class="k">catch</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">char</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">char16_t</span><span class="p">]]</span> +<span class="p">[[</span><span class="kt">char32_t</span><span class="p">]]</span> <span class="p">[[</span><span class="k">class</span><span class="p">]]</span> <span class="p">[[</span><span class="n">compl</span><span class="p">]]</span> <span class="p">[[</span><span class="k">const</span><span class="p">]]</span> <span class="p">[[</span><span class="k">const_cast</span><span class="p">]]</span> <span class="p">[[</span><span class="k">constexpr</span><span class="p">]]</span> +<span class="p">[[</span><span class="k">continue</span><span class="p">]]</span> <span class="p">[[</span><span class="k">decltype</span><span class="p">]]</span> <span class="p">[[</span><span class="k">default</span><span class="p">]]</span> <span class="p">[[</span><span class="k">delete</span><span class="p">]]</span> <span class="p">[[</span><span class="k">do</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">double</span><span class="p">]]</span> +<span class="p">[[</span><span class="k">dynamic_cast</span><span class="p">]]</span> <span class="p">[[</span><span class="k">else</span><span class="p">]]</span> <span class="p">[[</span><span class="k">enum</span><span class="p">]]</span> <span class="p">[[</span><span class="k">explicit</span><span class="p">]]</span> <span class="p">[[</span><span class="k">export</span><span class="p">]]</span> <span class="p">[[</span><span class="k">extern</span><span class="p">]]</span> <span class="p">[[</span><span class="nb">false</span><span class="p">]]</span> +<span class="p">[[</span><span class="k">final</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">float</span><span class="p">]]</span> <span class="p">[[</span><span class="k">for</span><span class="p">]]</span> <span class="p">[[</span><span class="k">friend</span><span class="p">]]</span> <span class="p">[[</span><span class="k">goto</span><span class="p">]]</span> <span class="p">[[</span><span class="k">if</span><span class="p">]]</span> <span class="p">[[</span><span class="kr">inline</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">int</span><span class="p">]]</span> +<span class="p">[[</span><span class="kt">long</span><span class="p">]]</span> <span class="p">[[</span><span class="k">mutable</span><span class="p">]]</span> <span class="p">[[</span><span class="k">namespace</span><span class="p">]]</span> <span class="p">[[</span><span class="k">new</span><span class="p">]]</span> <span class="p">[[</span><span class="k">noexcept</span><span class="p">]]</span> <span class="p">[[</span><span class="n">not</span><span class="p">]]</span> <span class="p">[[</span><span class="n">not_eq</span><span class="p">]]</span> +<span class="p">[[</span><span class="nb">nullptr</span><span class="p">]]</span> <span class="p">[[</span><span class="k">operator</span><span class="p">]]</span> <span class="p">[[</span><span class="n">or</span><span class="p">]]</span> <span class="p">[[</span><span class="n">or_eq</span><span class="p">]]</span> <span class="p">[[</span><span class="k">override</span><span class="p">]]</span> <span class="p">[[</span><span class="k">private</span><span class="p">]]</span> +<span class="p">[[</span><span class="k">protected</span><span class="p">]]</span> <span class="p">[[</span><span class="k">public</span><span class="p">]]</span> <span class="p">[[</span><span class="k">register</span><span class="p">]]</span> <span class="p">[[</span><span class="k">reinterpret_cast</span><span class="p">]]</span> <span class="p">[[</span><span class="k">return</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">short</span><span class="p">]]</span> +<span class="p">[[</span><span class="kt">signed</span><span class="p">]]</span> <span class="p">[[</span><span class="k">sizeof</span><span class="p">]]</span> <span class="p">[[</span><span class="k">static</span><span class="p">]]</span> <span class="p">[[</span><span class="k">static_assert</span><span class="p">]]</span> <span class="p">[[</span><span class="k">static_cast</span><span class="p">]]</span> <span class="p">[[</span><span class="k">struct</span><span class="p">]]</span> +<span class="p">[[</span><span class="k">switch</span><span class="p">]]</span> <span class="p">[[</span><span class="k">template</span><span class="p">]]</span> <span class="p">[[</span><span class="k">this</span><span class="p">]]</span> <span class="p">[[</span><span class="k">thread_local</span><span class="p">]]</span> <span class="p">[[</span><span class="k">throw</span><span class="p">]]</span> <span class="p">[[</span><span class="nb">true</span><span class="p">]]</span> <span class="p">[[</span><span class="k">try</span><span class="p">]]</span> +<span class="p">[[</span><span class="k">typedef</span><span class="p">]]</span> <span class="p">[[</span><span class="k">typeid</span><span class="p">]]</span> <span class="p">[[</span><span class="k">typename</span><span class="p">]]</span> <span class="p">[[</span><span class="k">union</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">unsigned</span><span class="p">]]</span> +<span class="p">[[</span><span class="k">virtual</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">void</span><span class="p">]]</span> <span class="p">[[</span><span class="k">volatile</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">wchar_t</span><span class="p">]]</span> <span class="p">[[</span><span class="k">while</span><span class="p">]]</span> <span class="p">[[</span><span class="n">xor</span><span class="p">]]</span> <span class="p">[[</span><span class="n">xor_eq</span><span class="p">]]</span> +<span class="c1">// [[using]]</span> +<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span> + <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Hello, World!"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> +<span class="p">}</span></code></pre> +</div> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>コンパイラのバージョン $ clang++ –version Apple clang version 11.0.0 +(clang-1100.0.33.8) Target: x86_64-apple-darwin19.6.0 Thread model: +posix InstalledDir: +/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin</p> +</div> +<div class="paragraph"> +<p>コンパイルコマンド (C17指定) $ clang –std=c++17 hoge.cpp</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>この記事から得られるものはこれ以上ないので以下は蛇足になる。</p> +</div> +<div class="paragraph"> +<p>別件で cppreference.com の +<a href="https://en.cppreference.com/w/cpp/language/identifiers">identifier +のページ</a> を読んでいた時、次の文が目に止まった。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="ulist"> +<ul> +<li> +<p>the identifiers that are keywords cannot be used for other purposes;</p> +<div class="ulist"> +<ul> +<li> +<p>The only place they can be used as non-keywords is in an +attribute-token. (e.g. <a id="private"></a> is a valid attribute) (since C++11)</p> +</li> +</ul> +</div> +</li> +</ul> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>キーワードでも属性として指定する場合は非キーワードとして使えるらしい。 +実際にやってみる。</p> +</div> +<div class="paragraph"> +<p>同サイトの <a href="https://en.cppreference.com/w/cpp/keyword">keywords のページ</a> +から一覧を拝借し、上のコードが出来上がった (C++17 +においてキーワードでないものなど、一部省いている)。 大量の警告 (unknown +attribute `〇〇' ignored) +がコンパイラから出力されるが、コンパイルできる。</p> +</div> +<div class="paragraph"> +<p>上のコードでは <code><a id="using"></a></code> をコメントアウトしているが、これは <code>using</code> +キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="cpp"><span class="c1">// using の例</span> +<span class="p">[[</span><span class="k">using</span> <span class="n">foo</span><span class="o">:</span> <span class="n">attr1</span><span class="p">,</span> <span class="n">attr2</span><span class="p">]]</span> <span class="kt">int</span> <span class="n">x</span><span class="p">;</span> <span class="c1">// [[foo::attr1, foo::attr2]] の糖衣構文</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>C++17 の仕様も見てみる (正確には標準化前のドラフト)。</p> +</div> +<div class="paragraph"> +<p>引用元: <a href="https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4" class="bare">https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4</a></p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>If a keyword or an alternative token that satisfies the syntactic +requirements of an identifier is contained in an attribute-token, it is +considered an identifier.</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>「<code>identifier</code> の構文上の要件を満たすキーワードまたは代替トークンが +<code>attribute-token</code> に含まれている場合、<code>identifier</code> +とみなされる」とある。どうやら間違いないようだ。</p> +</div> +<div class="paragraph"> +<p>ところで、代替トークン (alternative token) とは <code>and</code> (<code>&</code>) や <code>bitor</code> +(<code>|</code>) などのことだが、<code>identifier</code> +の構文上の要件を満たさないような代替トークンなどあるのか? +疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい +(参考: +<a href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</a>)</p> +</div> +<div class="ulist"> +<ul> +<li> +<p><code><%</code> → <code>{</code></p> +</li> +<li> +<p><code>%></code> → <code>}</code></p> +</li> +<li> +<p><code><:</code> → <code>[</code></p> +</li> +<li> +<p><code>:></code> → <code>]</code></p> +</li> +<li> +<p><code>%:</code> → <code>#</code></p> +</li> +<li> +<p><code>%:%:</code> → <code>##</code></p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>「<code>identifier</code> +の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。</p> +</div> +<div class="paragraph"> +<p>調べた感想: 字句解析器か構文解析器が辛そう</p> +</div> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2021-10-02/python-unbound-local-error/index.html b/public/posts/2021-10-02/python-unbound-local-error/index.html new file mode 100644 index 0000000..20e1e0e --- /dev/null +++ b/public/posts/2021-10-02/python-unbound-local-error/index.html @@ -0,0 +1,131 @@ +<!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="© nsfisis"> + <meta name="description" content="Python における UnboundLocalError の理由と対処法。"> + <meta name="keywords" content="Python,Python 3"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>【Python】クロージャとUnboundLocalError: local variable 'x' referenced before assignment | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">【Python】クロージャとUnboundLocalError: local variable 'x' referenced before assignment</h1> + + <ul class="post-tags"> + + <li class="tag"> + <a href="/tags/python/">Python</a> + </li> + + <li class="tag"> + <a href="/tags/python3/">Python 3</a> + </li> + + </ul> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植 + </li> + + </ol> + </section> + <div class="paragraph"> +<p>この記事は Qiita から移植してきたものです。 元 URL: +<a href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399" class="bare">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</a></p> +</div> +<hr> +<div class="paragraph"> +<p>本記事は Python 3.7.6 の動作結果を元にして書かれている。</p> +</div> +<div class="paragraph"> +<p>Python でクロージャを作ろうと、次のようなコードを書いた。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="python"><span class="k">def</span> <span class="nf">f</span><span class="p">():</span> + <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span> + <span class="k">def</span> <span class="nf">g</span><span class="p">():</span> + <span class="n">x</span> <span class="o">+=</span> <span class="mi">1</span> + <span class="n">g</span><span class="p">()</span> + +<span class="n">f</span><span class="p">()</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>関数 <code>g</code> から 関数 <code>f</code> のスコープ内で定義された変数 <code>x</code> を参照し、それに +1 を足そうとしている。 これを実行すると <code>x += 1</code> +の箇所でエラーが発生する。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>UnboundLocalError: local variable `x' referenced before assignment</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>local変数 <code>x</code> が代入前に参照された、とある。これは、<code>f</code> の <code>x</code> +を参照するのではなく、新しく別の変数を <code>g</code> 内に作ってしまっているため。 +前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<code>var</code> +を変数宣言のための構文として擬似的に利用している。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="python"><span class="c1"># 注: var は正しい Python の文法ではない。上記参照のこと +</span><span class="k">def</span> <span class="nf">f</span><span class="p">():</span> + <span class="n">var</span> <span class="n">x</span> <span class="c1"># f の local変数 'x' を宣言 +</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># x に 0 を代入 +</span> <span class="k">def</span> <span class="nf">g</span><span class="p">():</span> <span class="c1"># f の内部関数 g を定義 +</span> <span class="n">var</span> <span class="n">x</span> <span class="c1"># g の local変数 'x' を宣言 +</span> <span class="c1"># たまたま f にも同じ名前の変数があるが、それとは別の変数 +</span> <span class="n">x</span> <span class="o">+=</span> <span class="mi">1</span> <span class="c1"># x に 1 を加算 (x = x + 1 の糖衣構文) +</span> <span class="c1"># 加算する前の値を参照しようとするが、まだ代入されていないためエラー +</span> <span class="n">g</span><span class="p">()</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>当初の意図を表現するには、次のように書けばよい。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="python"><span class="k">def</span> <span class="nf">f</span><span class="p">():</span> + <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span> + <span class="k">def</span> <span class="nf">g</span><span class="p">():</span> + <span class="k">nonlocal</span> <span class="n">x</span> <span class="c1">## (*) +</span> <span class="n">x</span> <span class="o">+=</span> <span class="mi">1</span> + <span class="n">g</span><span class="p">()</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p><code>(*)</code> のように、<code>nonlocal</code> を追加する。これにより一つ外側のスコープ (<code>g</code> +の一つ外側 = <code>f</code>) で定義されている <code>x</code> を探しに行くようになる。</p> +</div> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2021-10-02/ruby-detect-running-implementation/index.html b/public/posts/2021-10-02/ruby-detect-running-implementation/index.html new file mode 100644 index 0000000..6fe62d7 --- /dev/null +++ b/public/posts/2021-10-02/ruby-detect-running-implementation/index.html @@ -0,0 +1,167 @@ +<!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="© nsfisis"> + <meta name="description" content="Ruby には複数の実装があるが、自身を実行している処理系の種類を スクリプト上からどのように判定すればよいだろうか。"> + <meta name="keywords" content="Ruby"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>【Ruby】自身を実行している処理系の種類を判定する | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">【Ruby】自身を実行している処理系の種類を判定する</h1> + + <ul class="post-tags"> + + <li class="tag"> + <a href="/tags/ruby/">Ruby</a> + </li> + + </ul> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植 + </li> + + </ol> + </section> + <div class="paragraph"> +<p>この記事は Qiita から移植してきたものです。 元 URL: +<a href="https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791" class="bare">https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791</a></p> +</div> +<hr> +<div class="paragraph"> +<p>Ruby +という言語には複数の実装があるが、それらをスクリプト上からどのようにして +programmatically に見分ければよいだろうか。</p> +</div> +<div class="paragraph"> +<p><code>Object</code> クラスに定義されている <code>RUBY_ENGINE</code> +という定数がこの用途に使える。</p> +</div> +<div class="paragraph"> +<p>参考: +<a href="https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_ENGINE.html">Object::RUBY_ENGINE</a></p> +</div> +<div class="paragraph"> +<p>上記ページの例から引用する:</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>ruby-1.9.1 <span class="nt">-ve</span> <span class="s1">'p RUBY_ENGINE'</span> +<span class="go">ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux] +"ruby" +</span><span class="gp">$</span><span class="w"> </span>jruby <span class="nt">-ve</span> <span class="s1">'p RUBY_ENGINE'</span> +<span class="go">jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java] +"jruby"</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>それぞれの処理系がどのような値を返すかだが、stack overflow +に良い質問と回答があった。</p> +</div> +<div class="paragraph"> +<p><a href="https://stackoverflow.com/a/9894232">What values for RUBY_ENGINE +correspond to which Ruby implementations?</a> より引用:</p> +</div> +<div class="quoteblock"> +<blockquote> +<table class="tableblock frame-all grid-all stretch"> +<colgroup> +<col style="width: 50%;"> +<col style="width: 50%;"> +</colgroup> +<thead> +<tr> +<th class="tableblock halign-center valign-top">RUBY_ENGINE</th> +<th class="tableblock halign-left valign-top">Implementation</th> +</tr> +</thead> +<tbody> +<tr> +<td class="tableblock halign-center valign-top"><p class="tableblock"><undefined></p></td> +<td class="tableblock halign-left valign-top"><p class="tableblock">MRI < 1.9</p></td> +</tr> +<tr> +<td class="tableblock halign-center valign-top"><p class="tableblock">`ruby'</p></td> +<td class="tableblock halign-left valign-top"><p class="tableblock">MRI >= 1.9 or REE</p></td> +</tr> +<tr> +<td class="tableblock halign-center valign-top"><p class="tableblock">`jruby'</p></td> +<td class="tableblock halign-left valign-top"><p class="tableblock">JRuby</p></td> +</tr> +<tr> +<td class="tableblock halign-center valign-top"><p class="tableblock">`macruby'</p></td> +<td class="tableblock halign-left valign-top"><p class="tableblock">MacRuby</p></td> +</tr> +<tr> +<td class="tableblock halign-center valign-top"><p class="tableblock">`rbx'</p></td> +<td class="tableblock halign-left valign-top"><p class="tableblock">Rubinius</p></td> +</tr> +<tr> +<td class="tableblock halign-center valign-top"><p class="tableblock">`maglev'</p></td> +<td class="tableblock halign-left valign-top"><p class="tableblock">MagLev</p></td> +</tr> +<tr> +<td class="tableblock halign-center valign-top"><p class="tableblock">`ironruby'</p></td> +<td class="tableblock halign-left valign-top"><p class="tableblock">IronRuby</p></td> +</tr> +<tr> +<td class="tableblock halign-center valign-top"><p class="tableblock">`cardinal'</p></td> +<td class="tableblock halign-left valign-top"><p class="tableblock">Cardinal</p></td> +</tr> +</tbody> +</table> +</blockquote> +</div> +<div class="paragraph"> +<p>なお、この質問・回答は +2014年になされたものであり、値は変わっている可能性がある。MRI (aka +CRuby) については執筆時現在 (2020/12/8) も <code>'ruby'</code> +が返ってくることを確認済み。</p> +</div> +<div class="paragraph"> +<p>この表にない主要な処理系として、https://mruby.org[mruby] は <code>'mruby'</code> +を返す。</p> +</div> +<div class="paragraph"> +<p><a href="https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35">mruby +該当部分のソース</a> より引用:</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="c"><span class="cm">/* + * Ruby engine. + */</span> +<span class="cp">#define MRUBY_RUBY_ENGINE "mruby"</span></code></pre> +</div> +</div> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html b/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html new file mode 100644 index 0000000..7ddf636 --- /dev/null +++ b/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html @@ -0,0 +1,392 @@ +<!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="© nsfisis"> + <meta name="description" content="Ruby 3.0 で追加される case in 構文と、then キーワードについて。"> + <meta name="keywords" content="Ruby,Ruby 3"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>【Ruby】then キーワードと case in | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">【Ruby】then キーワードと case in</h1> + + <ul class="post-tags"> + + <li class="tag"> + <a href="/tags/ruby/">Ruby</a> + </li> + + <li class="tag"> + <a href="/tags/ruby3/">Ruby 3</a> + </li> + + </ul> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植 + </li> + + </ol> + </section> + <div id="preamble"> +<div class="sectionbody"> +<div class="paragraph"> +<p>この記事は Qiita から移植してきたものです。 元 URL: +<a href="https://qiita.com/nsfisis/items/787a8cf888a304497223" class="bare">https://qiita.com/nsfisis/items/787a8cf888a304497223</a></p> +</div> +<hr> +</div> +</div> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + TL; DR + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p><code>case</code> - <code>in</code> によるパターンマッチング構文でも、<code>case</code> - <code>when</code> +と同じように <code>then</code> が使える (場合によっては使う必要がある)。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + <code>then</code> とは + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>使われることは稀だが、Ruby では <code>then</code> +がキーワードになっている。次のように使う:</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="ruby"><span class="k">if</span> <span class="n">cond</span> <span class="k">then</span> + <span class="nb">puts</span> <span class="s2">"Y"</span> +<span class="k">else</span> + <span class="nb">puts</span> <span class="s2">"N"</span> +<span class="k">end</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>このキーワードが現れうる場所はいくつかあり、<code>if</code>、<code>unless</code>、<code>rescue</code>、<code>case</code> +構文がそれに当たる。 上記のように、何か条件を書いた後 <code>then</code> +を置き、式がそこで終了していることを示すマーカーとして機能する。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="ruby"><span class="c1"># Example:</span> + +<span class="k">if</span> <span class="n">x</span> <span class="k">then</span> + <span class="n">a</span> +<span class="k">end</span> + +<span class="k">unless</span> <span class="n">x</span> <span class="k">then</span> + <span class="n">a</span> +<span class="k">end</span> + +<span class="k">begin</span> + <span class="n">a</span> +<span class="k">rescue</span> <span class="k">then</span> + <span class="n">b</span> +<span class="k">end</span> + +<span class="k">case</span> <span class="n">x</span> +<span class="k">when</span> <span class="nb">p</span> <span class="k">then</span> + <span class="n">a</span> +<span class="k">end</span></code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + なぜ普段は書かなくてもよいのか + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>普通 Ruby のコードで <code>then</code> +を書くことはない。なぜか。次のコードを実行してみるとわかる。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="ruby"><span class="k">if</span> <span class="kp">true</span> <span class="nb">puts</span> <span class="s1">'Hello, World!'</span> <span class="k">end</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>次のような構文エラーが出力される。</p> +</div> +<div class="literalblock"> +<div class="content"> +<pre>20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n' +if true puts 'Hello, World!' end + ^~~~ +20:1: syntax error, unexpected `end', expecting end-of-input +...f true puts 'Hello, World!' end</pre> +</div> +</div> +<div class="paragraph"> +<p>二つ目のメッセージは無視して一つ目を読むと、<code>then</code> か <code>;</code> +か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。</p> +</div> +<div class="paragraph"> +<p>ポイントは改行が <code>then</code> (や <code>;</code>) の代わりとなることである。<code>true</code> +の後に改行を入れてみる。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="ruby"><span class="k">if</span> <span class="kp">true</span> +<span class="nb">puts</span> <span class="s1">'Hello, World!'</span> <span class="k">end</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>無事 Hello, World! と出力されるようになった。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + なぜ <code>then</code> や <code>;</code> や改行が必要か + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>なぜ <code>then</code> や <code>;</code> や改行 (以下 「<code>then</code> 等」) +が必要なのだろうか。次の例を見てほしい:</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="ruby"><span class="k">if</span> <span class="n">a</span> <span class="n">b</span> <span class="k">end</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p><code>then</code> も <code>;</code> +も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。 +この例は二通りに解釈できる。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="ruby"><span class="c1"># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価</span> +<span class="k">if</span> <span class="n">a</span> <span class="k">then</span> + <span class="n">b</span> +<span class="k">end</span></code></pre> +</div> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="ruby"><span class="c1"># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、</span> +<span class="c1"># その結果が truthy なら何もしない</span> +<span class="k">if</span> <span class="n">a</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="k">then</span> +<span class="k">end</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p><code>then</code> 等はこの曖昧性を排除するためにあり、条件式は <code>if</code> から <code>then</code> +等までの間にある、ということを明確にする。 C系の <code>if</code> 後に来る <code>(</code>/<code>)</code> +や、Python の <code>:</code>、Rust/Go/Swift などの <code>{</code> も同じ役割を持つ。</p> +</div> +<div class="paragraph"> +<p>Ruby の場合、プログラマーが書きやすいよう改行でもって <code>then</code> +が代用できるので、ほとんどの場合 <code>then</code> は必要ない。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + <code>case</code> - <code>in</code> における <code>then</code> + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>ようやく本題にたどり着いた。来る Ruby 3.0 では <code>case</code> と <code>in</code> +キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして +<code>then</code> 等が必要になる。 (現在の) Ruby には formal +な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc +の説明は省略)。</p> +</div> +<div class="paragraph"> +<p><a href="https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986" class="bare">https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986</a></p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="yacc">p_case_body : keyword_in + { + SET_LEX_STATE(EXPR_BEG|EXPR_LABEL); + p->command_start = FALSE; + $<ctxt>1 = p->ctxt; + p->ctxt.in_kwarg = 1; + $<tbl>$ = push_pvtbl(p); + } + { + $<tbl>$ = push_pktbl(p); + } + p_top_expr then + { + pop_pktbl(p, $<tbl>3); + pop_pvtbl(p, $<tbl>2); + p->ctxt.in_kwarg = $<ctxt>1.in_kwarg; + } + compstmt + p_cases + { + /*%%%*/ + $$ = NEW_IN($4, $7, $8, &@$); + /*% %*/ + /*% ripper: in!($4, $7, escape_Qundef($8)) %*/ + } + ;</code></pre> +</div> +</div> +<div class="paragraph"> +<p>簡略版:</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="yacc">p_case_body : keyword_in p_top_expr then compstmt p_cases + ;</code></pre> +</div> +</div> +<div class="paragraph"> +<p>ここで、<code>keyword_in</code> は文字通り <code>in</code>、<code>p_top_expr</code> +はいわゆるパターン、<code>then</code> は <code>then</code> +キーワードのことではなく、この記事で <code>then</code> 等と呼んでいるもの、つまり +<code>then</code> キーワード、<code>;</code>、改行のいずれかである。</p> +</div> +<div class="paragraph"> +<p>これにより、<code>case</code> - <code>when</code> による従来の構文と同じように、<code>then</code> +等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="ruby"><span class="k">case</span> <span class="n">x</span> +<span class="k">in</span> <span class="mi">1</span> <span class="k">then</span> <span class="n">a</span> +<span class="k">in</span> <span class="mi">2</span> <span class="k">then</span> <span class="n">b</span> +<span class="k">in</span> <span class="mi">3</span> <span class="k">then</span> <span class="n">c</span> +<span class="k">end</span> + +<span class="k">case</span> <span class="n">x</span> +<span class="k">in</span> <span class="mi">1</span> + <span class="n">a</span> +<span class="k">in</span> <span class="mi">2</span> + <span class="n">b</span> +<span class="k">in</span> <span class="mi">3</span> + <span class="n">c</span> +<span class="k">end</span> + +<span class="k">case</span> <span class="n">x</span> +<span class="k">in</span> <span class="mi">1</span><span class="p">;</span> <span class="n">a</span> +<span class="k">in</span> <span class="mi">2</span><span class="p">;</span> <span class="n">b</span> +<span class="k">in</span> <span class="mi">3</span><span class="p">;</span> <span class="n">c</span> +<span class="k">end</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>ところで、<code>p_top_expr</code> には <code>if</code> による guard clause +が書けるので、その場合は <code>if</code> - <code>then</code> と似たような見た目になる。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="ruby"><span class="k">case</span> <span class="n">x</span> +<span class="k">in</span> <span class="mi">0</span> <span class="k">then</span> <span class="n">a</span> +<span class="k">in</span> <span class="n">n</span> <span class="k">if</span> <span class="n">n</span> <span class="o"><</span> <span class="mi">0</span> <span class="k">then</span> <span class="n">b</span> +<span class="k">in</span> <span class="n">n</span> <span class="k">then</span> <span class="n">c</span> +<span class="k">end</span></code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + まとめ + + </h2> + <div class="section-body"> + <div class="ulist"> +<ul> +<li> +<p><code>if</code> や <code>case</code> の条件の後ろには <code>then</code>、<code>;</code>、改行のいずれかが必要</p> +<div class="ulist"> +<ul> +<li> +<p>通常は改行しておけばよい</p> +</li> +</ul> +</div> +</li> +<li> +<p>3.0 で入る予定の <code>case</code> - <code>in</code> でも <code>then</code> 等が必要になる</p> +</li> +<li> +<p>Ruby の構文を正確に知るには (現状) <code>parse.y</code> を直接読めばよい</p> +</li> +</ul> +</div> + </div> +</section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html b/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html new file mode 100644 index 0000000..27f2632 --- /dev/null +++ b/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html @@ -0,0 +1,317 @@ +<!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="© nsfisis"> + <meta name="description" content="Rust のプリミティブ型は予約語ではなく普通の識別子である。 どのようにこれが名前解決されるのかを調べた。"> + <meta name="keywords" content="Rust"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>Rust のプリミティブ型はどこからやって来るか | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">Rust のプリミティブ型はどこからやって来るか</h1> + + <ul class="post-tags"> + + <li class="tag"> + <a href="/tags/rust/">Rust</a> + </li> + + </ul> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植 + </li> + + </ol> + </section> + <div id="preamble"> +<div class="sectionbody"> +<div class="paragraph"> +<p>この記事は Qiita から移植してきたものです。 元 URL: +<a href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565" class="bare">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</a></p> +</div> +<hr> +</div> +</div> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 前置き + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>Rust +において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="rust"><span class="nd">#![allow(non_camel_case_types)]</span> +<span class="nd">#![allow(dead_code)]</span> + +<span class="k">struct</span> <span class="nb">bool</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">char</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">i8</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">i16</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">i32</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">i64</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">i128</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">isize</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">u8</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">u16</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">u32</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">u64</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">u128</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">usize</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">f32</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">f64</span><span class="p">;</span> +<span class="k">struct</span> <span class="nb">str</span><span class="p">;</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>では、普段単に <code>bool</code> と書いたとき、この <code>bool</code> +は一体どこから来ているのか。rustc のソースを追ってみた。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>前提知識: 一般的なコンパイラの構造、用語。<code>rustc</code> そのものの知識は不要 +(というよりも筆者自身がよく知らない)</p> +</div> +</blockquote> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 調査 + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>調査に使用したソース (調査時点での最新 master)</p> +</div> +<div class="paragraph"> +<p><a href="https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98" class="bare">https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98</a></p> +</div> +<div class="paragraph"> +<p>どのようにして調べるか。rustc +の構造には詳しくないため、すぐに当たりをつけるのは難しい。</p> +</div> +<div class="paragraph"> +<p>大雑把な構造としては、<code>compiler</code> フォルダ以下に <code>rustc_*</code> +という名前のクレートが数十個入っている。これがどうやら <code>rustc</code> +コマンドの実装部のようだ。</p> +</div> +<div class="paragraph"> +<p><code>rustc</code> はセルフホストされている (= <code>rustc</code> 自身が Rust で書かれている) +ので、<code>bool</code> や <code>char</code> +などで適当に検索をかけてもノイズが多すぎて話にならない。 +しかし、お誂え向きなことに <code>i128</code>/<code>u128</code> +というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って +<code>git grep</code> してみる。</p> +</div> +<div class="literalblock"> +<div class="content"> +<pre>$ git grep "\bi128\b" | wc # i128 + 165 1069 15790 + +$ git grep "\bu128\b" | wc # u128 + 293 2127 26667 + +$ git grep "\bbool\b" | wc # cf. bool の結果 + 3563 23577 294659</pre> +</div> +</div> +<div class="paragraph"> +<p>165 +程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。</p> +</div> +<div class="literalblock"> +<div class="content"> +<pre>$ git grep "\bi128\b" +... +rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128)); +...</pre> +</div> +</div> +<div class="paragraph"> +<p><code>rustc_resolve</code> +というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="rust"><span class="cd">/// Interns the names of the primitive types.</span> +<span class="cd">///</span> +<span class="cd">/// All other types are defined somewhere and possibly imported, but the primitive ones need</span> +<span class="cd">/// special handling, since they have no place of origin.</span> +<span class="k">struct</span> <span class="n">PrimitiveTypeTable</span> <span class="p">{</span> + <span class="n">primitive_types</span><span class="p">:</span> <span class="n">FxHashMap</span><span class="o"><</span><span class="n">Symbol</span><span class="p">,</span> <span class="n">PrimTy</span><span class="o">></span><span class="p">,</span> +<span class="p">}</span> + +<span class="k">impl</span> <span class="n">PrimitiveTypeTable</span> <span class="p">{</span> + <span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-></span> <span class="n">PrimitiveTypeTable</span> <span class="p">{</span> + <span class="k">let</span> <span class="k">mut</span> <span class="n">table</span> <span class="o">=</span> <span class="nn">FxHashMap</span><span class="p">::</span><span class="nf">default</span><span class="p">();</span> + + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">bool</span><span class="p">,</span> <span class="n">Bool</span><span class="p">);</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">char</span><span class="p">,</span> <span class="n">Char</span><span class="p">);</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">f32</span><span class="p">,</span> <span class="nf">Float</span><span class="p">(</span><span class="nn">FloatTy</span><span class="p">::</span><span class="n">F32</span><span class="p">));</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">f64</span><span class="p">,</span> <span class="nf">Float</span><span class="p">(</span><span class="nn">FloatTy</span><span class="p">::</span><span class="n">F64</span><span class="p">));</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">isize</span><span class="p">,</span> <span class="nf">Int</span><span class="p">(</span><span class="nn">IntTy</span><span class="p">::</span><span class="n">Isize</span><span class="p">));</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">i8</span><span class="p">,</span> <span class="nf">Int</span><span class="p">(</span><span class="nn">IntTy</span><span class="p">::</span><span class="n">I8</span><span class="p">));</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">i16</span><span class="p">,</span> <span class="nf">Int</span><span class="p">(</span><span class="nn">IntTy</span><span class="p">::</span><span class="n">I16</span><span class="p">));</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">i32</span><span class="p">,</span> <span class="nf">Int</span><span class="p">(</span><span class="nn">IntTy</span><span class="p">::</span><span class="n">I32</span><span class="p">));</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">i64</span><span class="p">,</span> <span class="nf">Int</span><span class="p">(</span><span class="nn">IntTy</span><span class="p">::</span><span class="n">I64</span><span class="p">));</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">i128</span><span class="p">,</span> <span class="nf">Int</span><span class="p">(</span><span class="nn">IntTy</span><span class="p">::</span><span class="n">I128</span><span class="p">));</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">str</span><span class="p">,</span> <span class="n">Str</span><span class="p">);</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">usize</span><span class="p">,</span> <span class="nf">Uint</span><span class="p">(</span><span class="nn">UintTy</span><span class="p">::</span><span class="n">Usize</span><span class="p">));</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">u8</span><span class="p">,</span> <span class="nf">Uint</span><span class="p">(</span><span class="nn">UintTy</span><span class="p">::</span><span class="n">U8</span><span class="p">));</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">u16</span><span class="p">,</span> <span class="nf">Uint</span><span class="p">(</span><span class="nn">UintTy</span><span class="p">::</span><span class="n">U16</span><span class="p">));</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">u32</span><span class="p">,</span> <span class="nf">Uint</span><span class="p">(</span><span class="nn">UintTy</span><span class="p">::</span><span class="n">U32</span><span class="p">));</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">u64</span><span class="p">,</span> <span class="nf">Uint</span><span class="p">(</span><span class="nn">UintTy</span><span class="p">::</span><span class="n">U64</span><span class="p">));</span> + <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">u128</span><span class="p">,</span> <span class="nf">Uint</span><span class="p">(</span><span class="nn">UintTy</span><span class="p">::</span><span class="n">U128</span><span class="p">));</span> + <span class="k">Self</span> <span class="p">{</span> <span class="n">primitive_types</span><span class="p">:</span> <span class="n">table</span> <span class="p">}</span> + <span class="p">}</span> +<span class="p">}</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>これは初めに列挙したプリミティブ型の一覧と一致している。doc comment +にも、</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>All other types are defined somewhere and possibly imported, but the +primitive ones need special handling, since they have no place of +origin.</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>とある。次はこの struct +の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="rust"> <span class="cd">/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.</span> + <span class="cd">/// (略)</span> + <span class="k">fn</span> <span class="nf">resolve_ident_in_lexical_scope</span><span class="p">(</span> + <span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> + <span class="k">mut</span> <span class="n">ident</span><span class="p">:</span> <span class="n">Ident</span><span class="p">,</span> + <span class="n">ns</span><span class="p">:</span> <span class="n">Namespace</span><span class="p">,</span> + <span class="c1">// (略)</span> + <span class="p">)</span> <span class="k">-></span> <span class="nb">Option</span><span class="o"><</span><span class="n">LexicalScopeBinding</span><span class="o"><</span><span class="nv">'a</span><span class="o">>></span> <span class="p">{</span> + <span class="c1">// (略)</span> + + <span class="k">if</span> <span class="n">ns</span> <span class="o">==</span> <span class="n">TypeNS</span> <span class="p">{</span> + <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">prim_ty</span><span class="p">)</span> <span class="o">=</span> <span class="k">self</span><span class="py">.primitive_type_table.primitive_types</span><span class="nf">.get</span><span class="p">(</span><span class="o">&</span><span class="n">ident</span><span class="py">.name</span><span class="p">)</span> <span class="p">{</span> + <span class="k">let</span> <span class="n">binding</span> <span class="o">=</span> + <span class="p">(</span><span class="nn">Res</span><span class="p">::</span><span class="nf">PrimTy</span><span class="p">(</span><span class="o">*</span><span class="n">prim_ty</span><span class="p">),</span> <span class="nn">ty</span><span class="p">::</span><span class="nn">Visibility</span><span class="p">::</span><span class="n">Public</span><span class="p">,</span> <span class="n">DUMMY_SP</span><span class="p">,</span> <span class="nn">ExpnId</span><span class="p">::</span><span class="nf">root</span><span class="p">())</span> + <span class="nf">.to_name_binding</span><span class="p">(</span><span class="k">self</span><span class="py">.arenas</span><span class="p">);</span> + <span class="k">return</span> <span class="nf">Some</span><span class="p">(</span><span class="nn">LexicalScopeBinding</span><span class="p">::</span><span class="nf">Item</span><span class="p">(</span><span class="n">binding</span><span class="p">));</span> + <span class="p">}</span> + <span class="p">}</span> + + <span class="nb">None</span> + <span class="p">}</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>関数名や doc comment が示している通り、この関数は識別子 (identifier, +ident) を現在のレキシカルスコープ内で解決 (resolve) する。 +<code>if ns == TypeNS</code> のブロック内では、<code>primitive_type_table</code> (上記の +<code>PrimitiveTypeTable::new()</code> で作られた変数) に含まれている識別子 +(<code>bool</code>、<code>i32</code> など) +かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。</p> +</div> +<div class="paragraph"> +<p>なお、<code>ns</code> は「名前空間」を示す変数である。Rust +における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この +<code>if</code> +は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。</p> +</div> +<div class="paragraph"> +<p>重要なのは、これが <code>resolve_ident_in_lexical_scope()</code> +の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。</p> +</div> +<div class="paragraph"> +<p>動作がわかったところで、例として次のコードを考える。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="rust"><span class="nd">#![allow(non_camel_case_types)]</span> + +<span class="k">struct</span> <span class="nb">bool</span><span class="p">;</span> + +<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> + <span class="k">let</span> <span class="n">_</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="nb">bool</span><span class="p">;</span> +<span class="p">}</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>ここで <code>main()</code> の <code>bool</code> は <code>struct bool</code> +として解決される。なぜなら、プリミティブ型の判定をする前に <code>bool</code> +という名前の別の型が見つかるからだ。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + まとめ + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>Rust +のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。</p> +</div> + </div> +</section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html b/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html new file mode 100644 index 0000000..94912ed --- /dev/null +++ b/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html @@ -0,0 +1,299 @@ +<!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="© nsfisis"> + <meta name="description" content="Vim の autocmd events における BufWrite/BufWritePre がどう違うのかを調べた結果、 違いはないことがわかった。"> + <meta name="keywords" content="Vim"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>【Vim】autocmd events の BufWrite/BufWritePre の違い | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">【Vim】autocmd events の BufWrite/BufWritePre の違い</h1> + + <ul class="post-tags"> + + <li class="tag"> + <a href="/tags/vim/">Vim</a> + </li> + + </ul> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植 + </li> + + </ol> + </section> + <div id="preamble"> +<div class="sectionbody"> +<div class="paragraph"> +<p>この記事は Qiita から移植してきたものです。 元 URL: +<a href="https://qiita.com/nsfisis/items/79ab4db8564032de0b25" class="bare">https://qiita.com/nsfisis/items/79ab4db8564032de0b25</a></p> +</div> +<hr> +</div> +</div> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + TL; DR + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>違いはない。ただのエイリアス。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 調査記録 + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>Vim の autocmd events には似通った名前のものがいくつかある。大抵は +<code>:help</code> +に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。</p> +</div> +<div class="ulist"> +<ul> +<li> +<p><code>BufRead</code>/<code>BufReadPost</code></p> +</li> +<li> +<p><code>BufWrite</code>/<code>BufWritePre</code></p> +</li> +<li> +<p><code>BufAdd</code>/<code>BufCreate</code></p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>このうち、<code>BufAdd</code>/<code>BufCreate</code> に関しては、<code>:help BufCreate</code> に</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>The BufCreate event is for historic reasons.</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>とあり、おそらくは <code>BufAdd</code> +のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため +vim と neovim のソースコードを調査した。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>ソースコードへのリンク +<a href="https://github.com/vim/vim/tree/8e6be34338f13a6a625f19bcef82019c9adc65f2">vim +(調査時点での master branch)</a> +<a href="https://github.com/neovim/neovim/tree/71d4f5851f068eeb432af34850dddda8cc1c71e3">neovim +(上に同じ)</a></p> +</div> +</blockquote> +</div> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + vim のソースコード + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>以下は、autocmd events +の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。</p> +</div> +<div class="paragraph"> +<p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86" class="bare">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86</a></p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="c"> <span class="p">{</span><span class="s">"BufAdd"</span><span class="p">,</span> <span class="n">EVENT_BUFADD</span><span class="p">},</span> + <span class="p">{</span><span class="s">"BufCreate"</span><span class="p">,</span> <span class="n">EVENT_BUFADD</span><span class="p">},</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97" class="bare">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97</a></p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="c"> <span class="p">{</span><span class="s">"BufRead"</span><span class="p">,</span> <span class="n">EVENT_BUFREADPOST</span><span class="p">},</span> + <span class="p">{</span><span class="s">"BufReadCmd"</span><span class="p">,</span> <span class="n">EVENT_BUFREADCMD</span><span class="p">},</span> + <span class="p">{</span><span class="s">"BufReadPost"</span><span class="p">,</span> <span class="n">EVENT_BUFREADPOST</span><span class="p">},</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105" class="bare">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105</a></p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="c"> <span class="p">{</span><span class="s">"BufWrite"</span><span class="p">,</span> <span class="n">EVENT_BUFWRITEPRE</span><span class="p">},</span> + <span class="p">{</span><span class="s">"BufWritePost"</span><span class="p">,</span> <span class="n">EVENT_BUFWRITEPOST</span><span class="p">},</span> + <span class="p">{</span><span class="s">"BufWritePre"</span><span class="p">,</span> <span class="n">EVENT_BUFWRITEPRE</span><span class="p">},</span></code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + neovim のソースコード + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua +で書かれている。以下にある通り、はっきり <code>aliases</code> と書かれている。</p> +</div> +<div class="paragraph"> +<p><a href="https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124" class="bare">https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124</a></p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="lua"> <span class="n">aliases</span> <span class="o">=</span> <span class="p">{</span> + <span class="n">BufCreate</span> <span class="o">=</span> <span class="s1">'BufAdd'</span><span class="p">,</span> + <span class="n">BufRead</span> <span class="o">=</span> <span class="s1">'BufReadPost'</span><span class="p">,</span> + <span class="n">BufWrite</span> <span class="o">=</span> <span class="s1">'BufWritePre'</span><span class="p">,</span> + <span class="n">FileEncoding</span> <span class="o">=</span> <span class="s1">'EncodingChanged'</span><span class="p">,</span> + <span class="p">},</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>ところで、上では取り上げなかった <code>FileEncoding</code> だが、これは +<code>:help FileEncoding</code> にしっかりと書いてある。</p> +</div> +<div class="literalblock"> +<div class="content"> +<pre> *FileEncoding* +FileEncoding Obsolete. It still works and is equivalent + to |EncodingChanged|.</pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + まとめ + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。</p> +</div> +<div class="ulist"> +<ul> +<li> +<p><code>BufAdd</code>/<code>BufCreate</code></p> +<div class="ulist"> +<ul> +<li> +<p>→ <code>BufCreate</code> は歴史的な理由により (<code>`for historic reasons'') +存在しているため、新しい方 (`BufAdd</code>) を使う</p> +</li> +</ul> +</div> +</li> +<li> +<p><code>BufRead</code>/<code>BufReadPost</code></p> +<div class="ulist"> +<ul> +<li> +<p>→ <code>BufReadPre</code> との対称性のため、あるいは <code>BufWritePost</code> +との対称性のため <code>BufReadPost</code> を使う</p> +</li> +</ul> +</div> +</li> +<li> +<p><code>BufWrite</code>/<code>BufWritePre</code></p> +<div class="ulist"> +<ul> +<li> +<p>→ <code>BufWritePost</code> との対称性のため、あるいは <code>BufReadPre</code> +との対称性のため <code>BufWritePre</code> を使う</p> +</li> +</ul> +</div> +</li> +<li> +<p><code>FileEncoding</code>/<code>EncodingChanged</code></p> +<div class="ulist"> +<ul> +<li> +<p>→ <code>FileEncoding</code> は <code>`Obsolete'' +と明言されているので、`EncodingChanged</code> を使う</p> +</li> +</ul> +</div> +</li> +</ul> +</div> +<div class="paragraph"> +<p>ところでこの調査で知ったのだが、<code>BufRead</code> と <code>BufWrite</code> +は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら +<code>Pre</code>/<code>Post</code> 付きのものを使った方が分かりやすいだろう。</p> +</div> + </div> +</section> + </div> +</section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html b/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html new file mode 100644 index 0000000..2b66f2e --- /dev/null +++ b/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html @@ -0,0 +1,366 @@ +<!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="© nsfisis"> + <meta name="description" content="Vim で選択した行の順番を入れ替える方法。"> + <meta name="keywords" content="Vim"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>Vimで選択した行の順番を入れ替える | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">Vimで選択した行の順番を入れ替える</h1> + + <ul class="post-tags"> + + <li class="tag"> + <a href="/tags/vim/">Vim</a> + </li> + + </ul> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植 + </li> + + </ol> + </section> + <div id="preamble"> +<div class="sectionbody"> +<div class="paragraph"> +<p>この記事は Qiita から移植してきたものです。 元 URL: +<a href="https://qiita.com/nsfisis/items/4fefb361d9a693803520" class="bare">https://qiita.com/nsfisis/items/4fefb361d9a693803520</a></p> +</div> +<hr> +</div> +</div> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + バージョン情報 + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p><code>:version</code> の一部</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Jan 26 2020 11:30:30) macOS +version Included patches: 1-148 Huge version without GUI.</p> +</div> +</blockquote> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + よく紹介されている手法 + + </h2> + <div class="section-body"> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + <code>tac</code> / <code>tail</code> + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p><code>tac</code> や <code>tail -r</code> などの外部コマンドを <code>!</code> +を使って呼び出し、置き換える。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>:h v_!</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p><code>tac</code> コマンドや <code>tail</code> の <code>-r</code> +オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + <code>:g/^/m0</code> + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>こちらは外部コマンドに頼らず、Vim の機能のみを使う。<code>g</code> は <code>:global</code> +コマンドの、<code>m</code> は <code>:move</code> コマンドの略</p> +</div> +<div class="paragraph"> +<p><code>:global</code> コマンドは <code>:[range]global/{pattern}/[command]</code> +のように使い、<code>[range]</code> で指定された範囲の行のうち、<code>{pattern}</code> +で指定された検索パターンにマッチする行に対して、順番に <code>[command]</code> +で指定された Ex コマンドを呼び出す。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>:h :global</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p><code>:move</code> コマンドは <code>[range]:move {address}</code> のように使い、<code>[range]</code> +で指定された範囲の行を <code>{address}</code> で指定された位置に移動させる。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>:h :move</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p><code>:g/^/m0</code> のように組み合わせると、「すべての行を1行ずつ +0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。</p> +</div> +<div class="paragraph"> +<p>なお、<code>:g/^/m0</code> は全ての行を入れ替えるが、<code>:N,Mg/^/mN-1</code> とすることで +N行目から +M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="vim">command<span class="p">!</span> <span class="p">-</span>bar <span class="p">-</span><span class="nb">range</span><span class="p">=</span>% +<span class="se"> \</span> Reverse +<span class="se"> \</span> <span class="p"><</span>line1<span class="p">>,<</span>line2<span class="p">></span><span class="k">g</span><span class="sr">/^/</span><span class="k">m</span><span class="p"><</span>line1<span class="p">></span><span class="m">-1</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。</p> +</div> + </div> +</section> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + <code>:g/^/m0</code> の問題点 + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p><code>:global</code> +コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。<code>^</code> +は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。<code>'hlsearch'</code> +オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと +<code>n</code> コマンドなどの際に不便である。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>:h @/</p> +</div> +</blockquote> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 解決策 + + </h2> + <div class="section-body"> + <div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>[2020/9/28追記] より簡潔な方法を見つけたので次節に追記した</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>前述した <code>:Reverse</code> コマンドの定義を少し変えて、次のようにする:</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="vim"><span class="k">function</span><span class="p">!</span> <span class="nv">s:reverse_lines</span><span class="p">(</span>from<span class="p">,</span> <span class="k">to</span><span class="p">)</span> abort + <span class="nb">execute</span> <span class="nb">printf</span><span class="p">(</span><span class="s2">"%d,%dg/^/m%d"</span><span class="p">,</span> <span class="nv">a:from</span><span class="p">,</span> <span class="nv">a:to</span><span class="p">,</span> <span class="nv">a:from</span> <span class="p">-</span> <span class="m">1</span><span class="p">)</span> +<span class="k">endfunction</span> + +command<span class="p">!</span> <span class="p">-</span>bar <span class="p">-</span><span class="nb">range</span><span class="p">=</span>% +<span class="se"> \</span> Reverse +<span class="se"> \</span> <span class="k">call</span> <span class="p"><</span>SID<span class="p">></span>reverse_lines<span class="p">(<</span>line1<span class="p">>,</span> <span class="p"><</span>line2<span class="p">>)</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。</p> +</div> +<div class="paragraph"> +<p>この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが +<code>^</code> で上書きされることがなくなる。</p> +</div> +<div class="paragraph"> +<p>Vim のヘルプから該当箇所を引用する (強調は筆者による)。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>:h autocmd-searchpat</p> +</div> +<div class="paragraph"> +<p><strong>Autocommands do not change the current search patterns.</strong> Vim saves the +current search patterns before executing autocommands then restores them +after the autocommands finish. This means that autocommands do not +affect the strings highlighted with the `hlsearch' option.</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>これは autocommand +の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは +<code>:nohlsearch</code> のヘルプにある。同じく該当箇所を引用する +(強調は筆者による)。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>:h :nohlsearch</p> +</div> +<div class="paragraph"> +<p>(略) This command doesn’t work in an autocommand, because the +highlighting state is saved and restored when executing autocommands +|autocmd-searchpat|. <strong>Same thing for when invoking a user function.</strong></p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>この仕様により、<code>:g/^/m0</code> +の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 解決策 (改訂版) + + </h2> + <div class="section-body"> + <div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>[2020/9/28追記] より簡潔な方法を見つけたため追記する</p> +</div> +</blockquote> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="vim">command<span class="p">!</span> <span class="p">-</span>bar <span class="p">-</span><span class="nb">range</span><span class="p">=</span>% +<span class="se"> \</span> Reverse +<span class="se"> \</span> <span class="k">keeppatterns</span> <span class="p"><</span>line1<span class="p">>,<</span>line2<span class="p">></span><span class="k">g</span><span class="sr">/^/</span><span class="k">m</span><span class="p"><</span>line1<span class="p">></span><span class="m">-1</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>まさにこのための Exコマンド、<code>:keeppatterns</code> +が存在する。<code>:keeppatterns {command}</code> +のように使い、読んで字の如く、後ろに続く +Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>:h :keeppatterns</p> +</div> +</blockquote> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + コピペ用再掲 + + </h2> + <div class="section-body"> + <div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="vim"><span class="c">" License: Public Domain</span> + +command<span class="p">!</span> <span class="p">-</span>bar <span class="p">-</span><span class="nb">range</span><span class="p">=</span>% +<span class="se"> \</span> Reverse +<span class="se"> \</span> <span class="k">keeppatterns</span> <span class="p"><</span>line1<span class="p">>,<</span>line2<span class="p">></span><span class="k">g</span><span class="sr">/^/</span><span class="k">m</span><span class="p"><</span>line1<span class="p">></span><span class="m">-1</span></code></pre> +</div> +</div> + </div> +</section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html b/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html new file mode 100644 index 0000000..afb6eac --- /dev/null +++ b/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html @@ -0,0 +1,876 @@ +<!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="© nsfisis"> + <meta name="description" content="PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。"> + <meta name="keywords" content="カンファレンス,PHP,PHPerKaigi"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>PHPerKaigi 2022 トークン問題の解説 | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">PHPerKaigi 2022 トークン問題の解説</h1> + + <ul class="post-tags"> + + <li class="tag"> + <a href="/tags/conference/">カンファレンス</a> + </li> + + <li class="tag"> + <a href="/tags/php/">PHP</a> + </li> + + <li class="tag"> + <a href="/tags/phperkaigi/">PHPerKaigi</a> + </li> + + </ul> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2022-04-09">2022-04-09</time>: 公開 + </li> + + <li class="revision"> + <time datetime="2022-04-16">2022-04-16</time>: 2問目、3問目の解説を追加、1問目に加筆 + </li> + + </ol> + </section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + はじめに + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>本日開始された <a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> の PHPer +チャレンジにおいて、弊社 +<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> の問題を +3問作成した。この記事では、これらの問題の解説をおこなう。</p> +</div> +<div class="paragraph"> +<p>リポジトリはこちら: <a href="https://github.com/nsfisis/PHPerKaigi2022-tokens" class="bare">https://github.com/nsfisis/PHPerKaigi2022-tokens</a></p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 第1問 brainf_ck.php + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="o"><?</span><span class="n">php</span> + +<span class="k">declare</span><span class="p">(</span><span class="n">strict_types</span><span class="o">=</span><span class="mi">0</span><span class="no">O1</span><span class="p">);</span> + +<span class="kn">namespace</span> <span class="nn">Dgcircus\PHPerKaigi\Y2022</span><span class="p">;</span> + +<span class="cd">/** + * @todo + * Run this program to acquire a PHPer token. + */</span> + +<span class="n">https</span><span class="o">://</span><span class="n">creativecommons</span><span class="mf">.</span><span class="n">org</span><span class="o">/</span><span class="n">publicdomain</span><span class="o">/</span><span class="n">zero</span><span class="o">/</span><span class="mf">1.0</span><span class="o">/</span> + +<span class="err">\</span><span class="nb">error_reporting</span><span class="p">(</span><span class="o">~+!</span><span class="s1">'We are hiring!'</span><span class="p">);</span> + +<span class="nv">$z</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$f</span><span class="p">)</span> <span class="o">=></span> <span class="p">(</span><span class="k">fn</span><span class="p">(</span><span class="nv">$x</span><span class="p">)</span> <span class="o">=></span> <span class="nv">$f</span><span class="p">(</span><span class="k">fn</span><span class="p">(...</span><span class="nv">$xs</span><span class="p">)</span> <span class="o">=></span> <span class="nv">$x</span><span class="p">(</span><span class="nv">$x</span><span class="p">)(</span><span class="mf">...</span><span class="nv">$xs</span><span class="p">)))(</span><span class="k">fn</span><span class="p">(</span><span class="nv">$x</span><span class="p">)</span> <span class="o">=></span> <span class="nv">$f</span><span class="p">(</span><span class="k">fn</span><span class="p">(...</span><span class="nv">$xs</span><span class="p">)</span> <span class="o">=></span> <span class="nv">$x</span><span class="p">(</span><span class="nv">$x</span><span class="p">)(</span><span class="mf">...</span><span class="nv">$xs</span><span class="p">)));</span> +<span class="nv">$id</span> <span class="o">=</span> <span class="err">\</span><span class="nb">spl_object_id</span><span class="p">(</span><span class="mf">...</span><span class="p">);</span> +<span class="nv">$put</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$c</span><span class="p">)</span> <span class="o">=></span> <span class="err">\</span><span class="nb">printf</span><span class="p">(</span><span class="s1">'%c'</span><span class="p">,</span> <span class="nv">$c</span><span class="p">);</span> +<span class="nv">$mm</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$p</span><span class="p">,</span> <span class="nv">$n</span><span class="p">)</span> <span class="o">=></span> <span class="k">new</span> <span class="err">\</span><span class="nf">ArrayObject</span><span class="p">(</span><span class="err">\</span><span class="nb">array_fill</span><span class="p">(</span><span class="o">+!!</span><span class="p">[],</span> <span class="nv">$n</span><span class="p">,</span> <span class="nv">$p</span><span class="p">));</span> + +<span class="err">$👉</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=></span> <span class="p">[</span><span class="o">++</span><span class="nv">$mp</span><span class="p">,</span> <span class="o">++</span><span class="nv">$pc</span><span class="p">];</span> +<span class="err">$👈</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=></span> <span class="p">[</span><span class="o">--</span><span class="nv">$mp</span><span class="p">,</span> <span class="o">++</span><span class="nv">$pc</span><span class="p">];</span> +<span class="err">$👍</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=></span> <span class="p">[</span><span class="nv">$mp</span><span class="p">,</span> <span class="o">++</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">++</span><span class="nv">$m</span><span class="p">[</span><span class="nv">$mp</span><span class="p">]];</span> +<span class="err">$👎</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=></span> <span class="p">[</span><span class="nv">$mp</span><span class="p">,</span> <span class="o">++</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">--</span><span class="nv">$m</span><span class="p">[</span><span class="nv">$mp</span><span class="p">]];</span> +<span class="err">$📝</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=></span> <span class="p">[</span><span class="nv">$mp</span><span class="p">,</span> <span class="o">++</span><span class="nv">$pc</span><span class="p">,</span> <span class="nv">$put</span><span class="p">(</span><span class="nv">$m</span><span class="p">[</span><span class="nv">$mp</span><span class="p">])];</span> +<span class="err">$🤡</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=></span> <span class="k">match</span> <span class="p">(</span><span class="nv">$m</span><span class="p">[</span><span class="nv">$mp</span><span class="p">])</span> <span class="p">{</span> + <span class="o">+!!</span><span class="p">[]</span> <span class="o">=></span> <span class="p">[</span><span class="nv">$mp</span><span class="p">,</span> <span class="nv">$z</span><span class="p">(</span><span class="k">fn</span><span class="p">(</span><span class="nv">$loop</span><span class="p">)</span> <span class="o">=></span> <span class="k">fn</span><span class="p">(</span><span class="nv">$pc</span><span class="p">,</span> <span class="nv">$n</span><span class="p">)</span> <span class="o">=></span> <span class="k">match</span> <span class="p">(</span><span class="nv">$id</span><span class="p">(</span><span class="nv">$p</span><span class="p">[</span><span class="nv">$pc</span><span class="p">]))</span> <span class="p">{</span> + <span class="nv">$b</span> <span class="o">=></span> <span class="nv">$loop</span><span class="p">(</span><span class="o">++</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">++</span><span class="nv">$n</span><span class="p">),</span> + <span class="nv">$e</span> <span class="o">=></span> <span class="nv">$n</span> <span class="o">===</span> <span class="o">+!!</span><span class="p">[]</span> <span class="o">?</span> <span class="o">++</span><span class="nv">$pc</span> <span class="o">:</span> <span class="nv">$loop</span><span class="p">(</span><span class="o">++</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">--</span><span class="nv">$n</span><span class="p">),</span> + <span class="k">default</span> <span class="o">=></span> <span class="nv">$loop</span><span class="p">(</span><span class="o">++</span><span class="nv">$pc</span><span class="p">,</span> <span class="nv">$n</span><span class="p">),</span> + <span class="p">})(</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">-!</span><span class="p">[])],</span> + <span class="k">default</span> <span class="o">=></span> <span class="p">[</span><span class="nv">$mp</span><span class="p">,</span> <span class="o">++</span><span class="nv">$pc</span><span class="p">],</span> +<span class="p">};</span> +<span class="err">$🎪</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=></span> <span class="k">match</span> <span class="p">(</span><span class="nv">$m</span><span class="p">[</span><span class="nv">$mp</span><span class="p">])</span> <span class="p">{</span> + <span class="o">+!!</span><span class="p">[]</span> <span class="o">=></span> <span class="p">[</span><span class="nv">$mp</span><span class="p">,</span> <span class="o">++</span><span class="nv">$pc</span><span class="p">],</span> + <span class="k">default</span> <span class="o">=></span> <span class="p">[</span><span class="nv">$mp</span><span class="p">,</span> <span class="nv">$z</span><span class="p">(</span><span class="k">fn</span><span class="p">(</span><span class="nv">$loop</span><span class="p">)</span> <span class="o">=></span> <span class="k">fn</span><span class="p">(</span><span class="nv">$pc</span><span class="p">,</span> <span class="nv">$n</span><span class="p">)</span> <span class="o">=></span> <span class="k">match</span> <span class="p">(</span><span class="nv">$id</span><span class="p">(</span><span class="nv">$p</span><span class="p">[</span><span class="nv">$pc</span><span class="p">]))</span> <span class="p">{</span> + <span class="nv">$e</span> <span class="o">=></span> <span class="nv">$loop</span><span class="p">(</span><span class="o">--</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">++</span><span class="nv">$n</span><span class="p">),</span> + <span class="nv">$b</span> <span class="o">=></span> <span class="nv">$n</span> <span class="o">===</span> <span class="o">+!!</span><span class="p">[]</span> <span class="o">?</span> <span class="nv">$pc</span><span class="o">+!</span><span class="p">[]</span> <span class="o">:</span> <span class="nv">$loop</span><span class="p">(</span><span class="o">--</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">--</span><span class="nv">$n</span><span class="p">),</span> + <span class="k">default</span> <span class="o">=></span> <span class="nv">$loop</span><span class="p">(</span><span class="o">--</span><span class="nv">$pc</span><span class="p">,</span> <span class="nv">$n</span><span class="p">),</span> + <span class="p">})(</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">-!</span><span class="p">[])],</span> +<span class="p">};</span> +<span class="err">$🐘</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$p</span><span class="p">)</span> <span class="o">=></span> <span class="nv">$z</span><span class="p">(</span><span class="k">fn</span><span class="p">(</span><span class="nv">$loop</span><span class="p">)</span> <span class="o">=></span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=></span> + <span class="k">isset</span><span class="p">(</span><span class="nv">$p</span><span class="p">[</span><span class="nv">$pc</span><span class="p">])</span> <span class="o">&&</span> <span class="nv">$loop</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="mf">...</span><span class="p">(</span><span class="nv">$p</span><span class="p">[</span><span class="nv">$pc</span><span class="p">](</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)))</span> +<span class="p">)(</span><span class="nv">$mm</span><span class="p">(</span><span class="o">+!!</span><span class="p">[],</span> <span class="o">+</span><span class="p">(</span><span class="o">!</span><span class="p">[]</span><span class="mf">.</span><span class="o">!</span><span class="p">[])),</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$id</span><span class="p">(</span><span class="err">$🤡</span><span class="p">),</span> <span class="nv">$id</span><span class="p">(</span><span class="err">$🎪</span><span class="p">),</span> <span class="o">+!!</span><span class="p">[],</span> <span class="o">+!!</span><span class="p">[]);</span> + +<span class="err">$🐘</span><span class="p">([</span> + <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> + <span class="err">$🤡</span><span class="p">,</span> + <span class="err">$👉</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> + <span class="err">$👉</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> + <span class="err">$👉</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> + <span class="err">$👉</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> + <span class="err">$👈</span><span class="p">,</span> <span class="err">$👈</span><span class="p">,</span> <span class="err">$👈</span><span class="p">,</span> <span class="err">$👈</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> + <span class="err">$🎪</span><span class="p">,</span> + <span class="err">$👉</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span> + <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span> + <span class="err">$👉</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span> + <span class="err">$👉</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span> + <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span> + <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span> + <span class="err">$👈</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span> + <span class="err">$👉</span><span class="p">,</span> <span class="err">$👉</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span> + <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span> + <span class="err">$👈</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span> + <span class="err">$👈</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span> + <span class="err">$👉</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span> + <span class="err">$👉</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span> + <span class="err">$👈</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span> +<span class="p">]);</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。</p> +</div> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + 解説 + + </h3> + <div class="section-body"> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 絵文字 + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>まず目につくのは大量の絵文字だろう。 PHP +は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + プログラム全体 + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>Brainf*ck のインタプリタとプログラムになっている。 Brainf*ck +とは、難解プログラミング言語のひとつであり、ここで説明するよりも +Wikipedia の該当ページを読んだ方がよい。</p> +</div> +<div class="paragraph"> +<p><a href="https://ja.wikipedia.org/wiki/Brainfuck" class="bare">https://ja.wikipedia.org/wiki/Brainfuck</a></p> +</div> +<div class="paragraph"> +<p>なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。</p> +</div> +<div class="literalblock"> +<div class="content"> +<pre>+ + + + + + + + + + +[ + > + + + + > + + + + + + > + + + + + + + + + + + + + > + + + + + + + + + + + < < < < - +] +> + + + + + . +- - . +> - - - . +> - - - . +- - . +- . +< . +> > - - . ++ + + + + + + . +< - - - - . +< . +> + + . +> - . +< .</pre> +</div> +</div> +<div class="paragraph"> +<p>実行結果はこちら: <a href="https://ideone.com/22VWmb" class="bare">https://ideone.com/22VWmb</a></p> +</div> +<div class="paragraph"> +<p>それぞれの絵文字で表された関数が、各命令に対応している。</p> +</div> +<div class="ulist"> +<ul> +<li> +<p><code>$👉</code>: <code>></code></p> +</li> +<li> +<p><code>$👈</code>: <code><</code></p> +</li> +<li> +<p><code>$👍</code>: <code>+</code></p> +</li> +<li> +<p><code>$👎</code>: <code>-</code></p> +</li> +<li> +<p><code>$📝</code>: <code>.</code></p> +</li> +<li> +<p><code>$🤡</code>: <code>[</code></p> +</li> +<li> +<p><code>$🎪</code>: <code>]</code></p> +</li> +</ul> +</div> +<div class="paragraph"> +<p><code>,</code> (入力) に対応する関数はない +(このプログラムでは使わないので用意していない)。</p> +</div> +<div class="paragraph"> +<p>なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 絵文字の選択 + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code> +は弊社デジタルサーカスにちなんでいる。 また、<code>$🐘</code> は PHP +のマスコットの象に由来する。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + strict_types + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p><code>declare</code> 文の <code>strict_types</code> に指定できるのは、<code>0</code> か <code>1</code> +の数値リテラルだが、 <code>0x0</code> や <code>0b1</code> のような値も受け付ける。 今回は、PHP +8.1 から追加された、<code>0O</code> または <code>0o</code> から始まる八進数リテラルを使った。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + URL + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>ソースコードのライセンスを示したこの部分だが、</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="n">https</span><span class="o">://</span><span class="n">creativecommons</span><span class="mf">.</span><span class="n">org</span><span class="o">/</span><span class="n">publicdomain</span><span class="o">/</span><span class="n">zero</span><span class="o">/</span><span class="mf">1.0</span><span class="o">/</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>完全に合法な PHP のコードである。 <code>https:</code> 部分はラベル、<code>//</code> +以降は行コメントになっている。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + リテラルなしで数値を生成する + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 +PHP では、型変換を利用することで任意の整数を作り出すことができる。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="nb">assert</span><span class="p">(</span><span class="mi">0</span> <span class="o">===</span> <span class="o">+!!</span><span class="p">[]);</span> +<span class="nb">assert</span><span class="p">(</span><span class="mi">1</span> <span class="o">===</span> <span class="o">+!</span><span class="p">[]);</span> +<span class="nb">assert</span><span class="p">(</span><span class="mi">2</span> <span class="o">===</span> <span class="o">!</span><span class="p">[]</span><span class="o">+!</span><span class="p">[]);</span> +<span class="nb">assert</span><span class="p">(</span><span class="mi">3</span> <span class="o">===</span> <span class="o">!</span><span class="p">[]</span><span class="o">+!</span><span class="p">[]</span><span class="o">+!</span><span class="p">[]);</span> +<span class="nb">assert</span><span class="p">(</span><span class="mi">10</span> <span class="o">===</span> <span class="o">+</span><span class="p">(</span><span class="o">!</span><span class="p">[]</span><span class="mf">.</span><span class="o">+!!</span><span class="p">[]));</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p><code>[]</code> に <code>!</code> を適用すると <code>true</code> が返ってくる。それに <code>+</code> +を適用すると、<code>bool</code> から <code>int</code> ヘの型変換が走り、<code>1</code> が生成される。<code>10</code> +はさらにトリッキーだ。まず <code>1</code> と <code>0</code> を作り、<code>.</code> で文字列として結合する +(<code>'10'</code>)。これに <code>+</code> を適用すると、<code>string</code> から <code>int</code> +への型変換が走り、<code>10</code> が生まれる (コード量に頓着しないなら、<code>1</code> を 10 +個足し合わせてももちろん 10 が作れる)。</p> +</div> +<div class="paragraph"> +<p>また、<code>error_reporting</code> に指定しているのは <code>-1</code> である。 これは、<code>!</code> +によって文字列を <code>false</code> にし、<code>+</code> によって <code>false</code> を <code>0</code> +にし、さらにビット反転して <code>-1</code> にしている。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + <code>if</code> 文なしで条件分岐 + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>三項演算子ないし <code>match</code> 式を使うことで、<code>if</code> +を一切書かずに条件分岐ができる。 また、<code>&&</code> / <code>||</code> も使えることがある。 +遅延評価が不要なケースでは、<code>[$t, $f][$cond]</code> +のような形で分岐することもできる。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + <code>while</code>、<code>for</code> 文なしでループ + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>不動点コンビネータを使って無名再帰する +(詳しい説明は省略する。これらの単語で検索してほしい)。 ここでは、一般に +Z コンビネータとして知られるものを使った (<code>$z</code>)。</p> +</div> +<div class="paragraph"> +<p>実際のところ、<code>$🤡</code> や <code>$🎪</code>、<code>$🐘</code> は、一度 Scheme (Lisp の一種) +で書いてから PHP に翻訳する形で記述した。</p> +</div> +<div class="paragraph"> +<p>なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) +ので、 あまりに長い brainf*ck +プログラムを書くとスタックオーバーフローする。</p> +</div> + </div> +</section> + </div> +</section> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 第2問 riddle.php + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="o"><?</span><span class="n">php</span> + +<span class="cd">/********************************************************* + * This program displays a PHPer token. * + * Guess 'N'. * + * * + * Hints: * + * - N itself has no special meaning, e.g., 42, 8128, * + * it is selected at random. * + * - Each element of $token represents a single letter. * + * - One letter consists of 5x5 cells. * + * - Remember, the output is a complete PHPer token. * + * * + * License: * + * https://creativecommons.org/publicdomain/zero/1.0/ * + *********************************************************/</span> +<span class="k">const</span> <span class="no">N</span> <span class="o">=</span> <span class="mi">0</span> <span class="cm">/* Change it to your answer. */</span><span class="p">;</span> +<span class="nb">assert</span><span class="p">(</span><span class="mi">0</span> <span class="o"><=</span> <span class="nc">N</span> <span class="o">&&</span> <span class="nc">N</span> <span class="o"><=</span> <span class="mb">0b11111_11111_11111_11111_11111</span><span class="p">);</span> + +<span class="nv">$token</span> <span class="o">=</span> <span class="p">[</span> + <span class="mh">0x14B499C</span><span class="p">,</span> + <span class="mh">0x0BE34CC</span><span class="p">,</span> <span class="mh">0x01C9C69</span><span class="p">,</span> + <span class="mh">0x0ECA069</span><span class="p">,</span> <span class="mh">0x01C2449</span><span class="p">,</span> <span class="mh">0x0FDB166</span><span class="p">,</span> <span class="mh">0x01C9C69</span><span class="p">,</span> + <span class="mh">0x01C1C66</span><span class="p">,</span> <span class="mh">0x0FC1C47</span><span class="p">,</span> <span class="mh">0x01C1C66</span><span class="p">,</span> + <span class="mh">0x10C5858</span><span class="p">,</span> <span class="mh">0x1E4E3B8</span><span class="p">,</span> <span class="mh">0x1A2F2F8</span><span class="p">,</span> +<span class="p">];</span> +<span class="k">foreach</span> <span class="p">(</span><span class="nv">$token</span> <span class="k">as</span> <span class="nv">$x</span><span class="p">)</span> <span class="p">{</span> + <span class="nv">$x</span> <span class="o">=</span> <span class="nv">$x</span> <span class="o">^</span> <span class="nc">N</span><span class="p">;</span> + + <span class="nv">$x</span> <span class="o">=</span> <span class="nb">sprintf</span><span class="p">(</span><span class="s1">'%025b'</span><span class="p">,</span> <span class="nv">$x</span><span class="p">);</span> + <span class="nv">$x</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="n">search</span><span class="o">:</span> <span class="p">[</span><span class="s1">'0'</span><span class="p">,</span> <span class="s1">'1'</span><span class="p">],</span> <span class="n">replace</span><span class="o">:</span> <span class="p">[</span><span class="s1">' '</span><span class="p">,</span> <span class="s1">'#'</span><span class="p">],</span> <span class="n">subject</span><span class="o">:</span> <span class="nv">$x</span><span class="p">);</span> + <span class="nv">$x</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="nb">str_split</span><span class="p">(</span><span class="nv">$x</span><span class="p">,</span> <span class="n">length</span><span class="o">:</span> <span class="mi">5</span><span class="p">));</span> + <span class="k">echo</span> <span class="s2">"</span><span class="si">{</span><span class="nv">$x</span><span class="si">}</span><span class="se">\n\n</span><span class="s2">"</span><span class="p">;</span> +<span class="p">}</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。 +トークンを得るためには、ソースコードを読み、定数 <code>N</code> +を特定する必要がある。</p> +</div> +<div class="paragraph"> +<p>ここでは、私の想定解を解説する。</p> +</div> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + 読解 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>まずはソースコードを読んでいく。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="nv">$token</span> <span class="o">=</span> <span class="p">[</span> + <span class="c1">// 略</span> +<span class="p">];</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>数値からなる <code>$token</code> があり、各要素をループしている。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"> <span class="nv">$x</span> <span class="o">=</span> <span class="nv">$x</span> <span class="o">^</span> <span class="nc">N</span><span class="p">;</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>まずは排他的論理和 (xor) を取り、</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"> <span class="nv">$x</span> <span class="o">=</span> <span class="nb">sprintf</span><span class="p">(</span><span class="s1">'%025b'</span><span class="p">,</span> <span class="nv">$x</span><span class="p">);</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>二進数に変換して、</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"> <span class="nv">$x</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="n">search</span><span class="o">:</span> <span class="p">[</span><span class="s1">'0'</span><span class="p">,</span> <span class="s1">'1'</span><span class="p">],</span> <span class="n">replace</span><span class="o">:</span> <span class="p">[</span><span class="s1">' '</span><span class="p">,</span> <span class="s1">'#'</span><span class="p">],</span> <span class="n">subject</span><span class="o">:</span> <span class="nv">$x</span><span class="p">);</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>0 を空白に、1 を <code>#</code> にし、</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"> <span class="nv">$x</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="nb">str_split</span><span class="p">(</span><span class="nv">$x</span><span class="p">,</span> <span class="n">length</span><span class="o">:</span> <span class="mi">5</span><span class="p">));</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>5文字ごとに区切ったあと、改行で結合している。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + ヒント + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>次に、ソースコードに書いてあるヒントを読んでいく。</p> +</div> +<div class="ulist"> +<ul> +<li> +<p><code>N</code> それ自体は、42 や 8128 +といったような特別な意味を持たず、ランダムに決められている</p> +</li> +<li> +<p><code>$token</code> の各要素は、1文字を表す</p> +</li> +<li> +<p>1文字は 5x5 のセルからなる</p> +</li> +<li> +<p>出力されるのは、完全な PHPer トークンである</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>ここで、PHPer トークンは必ず <code><mark></code> 記号から始まることを思いだすと、 +<code>$token</code> の最初の数字 <code>0x14B499C</code> は、変換の結果 <code></mark></code> +になるのではないかと予想される (なお、このことは、リポジトリの README +ファイルに追加ヒントとして書かれている)。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + 解く + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code> +に変換されるような <code>N</code> を見つければよい。</p> +</div> +<div class="paragraph"> +<p><code>N</code> は高々</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="nb">assert</span><span class="p">(</span><span class="mi">0</span> <span class="o"><=</span> <span class="nc">N</span> <span class="o">&&</span> <span class="nc">N</span> <span class="o"><=</span> <span class="mb">0b11111_11111_11111_11111_11111</span><span class="p">);</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="o"><?</span><span class="n">php</span> + +<span class="nv">$x</span> <span class="o">=</span> <span class="mh">0x14B499C</span><span class="p">;</span> + +<span class="nv">$x</span> <span class="o">=</span> <span class="nv">$x</span> <span class="o">^</span> <span class="nc">N</span><span class="p">;</span> + +<span class="nv">$x</span> <span class="o">=</span> <span class="nb">sprintf</span><span class="p">(</span><span class="s1">'%025b'</span><span class="p">,</span> <span class="nv">$x</span><span class="p">);</span> +<span class="nv">$x</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="n">search</span><span class="o">:</span> <span class="p">[</span><span class="s1">'0'</span><span class="p">,</span> <span class="s1">'1'</span><span class="p">],</span> <span class="n">replace</span><span class="o">:</span> <span class="p">[</span><span class="s1">' '</span><span class="p">,</span> <span class="s1">'#'</span><span class="p">],</span> <span class="n">subject</span><span class="o">:</span> <span class="nv">$x</span><span class="p">);</span> +<span class="nv">$x</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="nb">str_split</span><span class="p">(</span><span class="nv">$x</span><span class="p">,</span> <span class="n">length</span><span class="o">:</span> <span class="mi">5</span><span class="p">));</span> + +<span class="nb">assert</span><span class="p">(</span><span class="nv">$x</span> <span class="o">===</span> + <span class="s2">" # # </span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span> + <span class="s2">"#####</span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span> + <span class="s2">" # # </span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span> + <span class="s2">"#####</span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span> + <span class="s2">" # # "</span><span class="p">);</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>この一連の変換に対する逆変換を考えると、次のようになる。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="o"><?</span><span class="n">php</span> + +<span class="nv">$x</span> <span class="o">=</span> + <span class="s2">" # # </span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span> + <span class="s2">"#####</span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span> + <span class="s2">" # # </span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span> + <span class="s2">"#####</span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span> + <span class="s2">" # # "</span><span class="p">;</span> + +<span class="nv">$x</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="s1">''</span><span class="p">,</span> <span class="nb">explode</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="nv">$x</span><span class="p">));</span> +<span class="nv">$x</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="n">search</span><span class="o">:</span> <span class="p">[</span><span class="s1">' '</span><span class="p">,</span> <span class="s1">'#'</span><span class="p">],</span> <span class="n">replace</span><span class="o">:</span> <span class="p">[</span><span class="s1">'0'</span><span class="p">,</span> <span class="s1">'1'</span><span class="p">],</span> <span class="n">subject</span><span class="o">:</span> <span class="nv">$x</span><span class="p">);</span> +<span class="nv">$x</span> <span class="o">=</span> <span class="nb">bindec</span><span class="p">(</span><span class="nv">$x</span><span class="p">);</span> + +<span class="nv">$n</span> <span class="o">=</span> <span class="nv">$x</span> <span class="o">^</span> <span class="mh">0x14B499C</span><span class="p">;</span> + +<span class="k">echo</span> <span class="s2">"N = </span><span class="nv">$n</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>これを実行すると、<code>N</code> が得られる。</p> +</div> + </div> +</section> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 第3問 toquine.php + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>ソースコードはこちら。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="o"><?</span><span class="n">php</span> + +<span class="c1">// License: https://creativecommons.org/publicdomain/zero/1.0/</span> +<span class="c1">// This is a quine-like program to generate a PHPer token.</span> +<span class="c1">// Execute it like this: php toquine.php | php | php | php | ...</span> + +<span class="nv">$s</span> <span class="o">=</span> <span class="sh"><<<'Q' +<?cuc +// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/ +// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra. +// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ... +%f$f = %f; +$f = fge_ebg13($f); $kf = [ +%f, +]; +$g = ahyy.snyfr; sbe ($v = 0; $v <= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr +$g .= vzcybqr("\a", fge_fcyvg(fge_ercynpr(['0','1'], [' ','##'], fcevags(pue(37) . '025o', $kf[$v])), 012)) . "\a\a"; +$jf = neenl_znc(sa($j) => vzcybqr(', ', $j), neenl_puhax(neenl_znc(sa($k) => fcevags('0k' . pue(37) . '07K', $k), $kf), 10)); +cevags($f, $g, fge_ebg13("<<<'Q'\a{$f}\aQ"), vzcybqr(",\a", $jf)); +Q;</span> +<span class="nv">$s</span> <span class="o">=</span> <span class="nb">str_rot13</span><span class="p">(</span><span class="nv">$s</span><span class="p">);</span> <span class="nv">$xs</span> <span class="o">=</span> <span class="p">[</span> +<span class="mh">0x0AFABEA</span><span class="p">,</span> <span class="mh">0x1F294A7</span><span class="p">,</span> <span class="mh">0x1F2109F</span><span class="p">,</span> <span class="mh">0x1F294A7</span><span class="p">,</span> <span class="mh">0x0002800</span><span class="p">,</span> <span class="mh">0x1F2109F</span><span class="p">,</span> <span class="mh">0x0117041</span><span class="p">,</span> <span class="mh">0x1F294A7</span><span class="p">,</span> <span class="mh">0x1FAD6B5</span><span class="p">,</span> <span class="mh">0x1F295B7</span><span class="p">,</span> +<span class="mh">0x010FC21</span><span class="p">,</span> <span class="mh">0x1FAD6B5</span><span class="p">,</span> <span class="mh">0x1151151</span><span class="p">,</span> <span class="mh">0x010FC21</span><span class="p">,</span> <span class="mh">0x1F294A7</span><span class="p">,</span> <span class="mh">0x1F295B7</span><span class="p">,</span> <span class="mh">0x1FAD6B5</span><span class="p">,</span> <span class="mh">0x1F294A7</span><span class="p">,</span> <span class="mh">0x1F295B7</span><span class="p">,</span> <span class="mh">0x1F8C63F</span><span class="p">,</span> +<span class="mh">0x1F8C631</span><span class="p">,</span> <span class="mh">0x1FAD6B5</span><span class="p">,</span> <span class="mh">0x17AD6BD</span><span class="p">,</span> <span class="mh">0x17AD6BD</span><span class="p">,</span> <span class="mh">0x1F8C63F</span><span class="p">,</span> <span class="mh">0x1F295B7</span><span class="p">,</span> +<span class="p">];</span> +<span class="nv">$t</span> <span class="o">=</span> <span class="kc">null</span><span class="mf">.</span><span class="kc">false</span><span class="p">;</span> <span class="k">for</span> <span class="p">(</span><span class="nv">$i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nv">$i</span> <span class="o"><=</span> <span class="nb">intdiv</span><span class="p">(</span><span class="k">__LINE__</span><span class="o">-</span><span class="mo">035</span><span class="p">,</span><span class="mi">6</span><span class="p">);</span> <span class="o">++</span><span class="nv">$i</span><span class="p">)</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="k">isset</span><span class="p">(</span><span class="nv">$xs</span><span class="p">[</span><span class="nv">$i</span><span class="p">]))</span> <span class="k">break</span><span class="p">;</span> <span class="k">else</span> +<span class="nv">$t</span> <span class="mf">.</span><span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="nb">str_split</span><span class="p">(</span><span class="nb">str_replace</span><span class="p">([</span><span class="s1">'0'</span><span class="p">,</span><span class="s1">'1'</span><span class="p">],</span> <span class="p">[</span><span class="s1">' '</span><span class="p">,</span><span class="s1">'##'</span><span class="p">],</span> <span class="nb">sprintf</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="mi">37</span><span class="p">)</span> <span class="mf">.</span> <span class="s1">'025b'</span><span class="p">,</span> <span class="nv">$xs</span><span class="p">[</span><span class="nv">$i</span><span class="p">])),</span> <span class="mo">012</span><span class="p">))</span> <span class="mf">.</span> <span class="s2">"</span><span class="se">\n\n</span><span class="s2">"</span><span class="p">;</span> +<span class="nv">$ws</span> <span class="o">=</span> <span class="nb">array_map</span><span class="p">(</span><span class="k">fn</span><span class="p">(</span><span class="nv">$w</span><span class="p">)</span> <span class="o">=></span> <span class="nb">implode</span><span class="p">(</span><span class="s1">', '</span><span class="p">,</span> <span class="nv">$w</span><span class="p">),</span> <span class="nb">array_chunk</span><span class="p">(</span><span class="nb">array_map</span><span class="p">(</span><span class="k">fn</span><span class="p">(</span><span class="nv">$x</span><span class="p">)</span> <span class="o">=></span> <span class="nb">sprintf</span><span class="p">(</span><span class="s1">'0x'</span> <span class="mf">.</span> <span class="nb">chr</span><span class="p">(</span><span class="mi">37</span><span class="p">)</span> <span class="mf">.</span> <span class="s1">'07X'</span><span class="p">,</span> <span class="nv">$x</span><span class="p">),</span> <span class="nv">$xs</span><span class="p">),</span> <span class="mi">10</span><span class="p">));</span> +<span class="nb">printf</span><span class="p">(</span><span class="nv">$s</span><span class="p">,</span> <span class="nv">$t</span><span class="p">,</span> <span class="nb">str_rot13</span><span class="p">(</span><span class="s2">"<<<'D'</span><span class="se">\n</span><span class="si">{</span><span class="nv">$s</span><span class="si">}</span><span class="se">\n</span><span class="s2">D"</span><span class="p">),</span> <span class="nb">implode</span><span class="p">(</span><span class="s2">",</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="nv">$ws</span><span class="p">));</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>コメントにもあるとおり、次のようにして実行すれば答えがでてくる。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>php toquine.php | php | php | php | ...</code></pre> +</div> +</div> +<div class="paragraph"> +<p>実際にはもう少しパイプで繋げなければならない。</p> +</div> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + 解説 + + </h3> + <div class="section-body"> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + プログラム全体 + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>コメントにもあるとおり、これは quine (風) のプログラムになっている。 +Quine +とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。</p> +</div> +<div class="paragraph"> +<p>このプログラムは、実行すると自身とほとんど同じプログラムを出力する。 +異なるのはトークンになっている部分のみである。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + トークン + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p><code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code> +とほぼ同じなので省略する。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + 状態保持 + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>トークンの何文字目まで出力したかを、ソースコードを変えずに (quine +なので) 覚えておく必要がある。 +このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<code><em>LINE</em></code> +から情報を取得している。</p> +</div> + </div> +</section> + + + + + +<section class="section-3"> + <h4 id="" class="section-header"> + + ROT 13 + + </h4> + <div class="section-body"> + <div class="paragraph"> +<p>Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。 +これがあまり美しくないので、<code>toquine.php</code> では、ROT 13 +変換を使って難読化した。</p> +</div> +<div class="paragraph"> +<p>それにしてもなぜこんなものが標準ライブラリに……。</p> +</div> + </div> +</section> + </div> +</section> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + おわりに + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。</p> +</div> +<div class="paragraph"> +<p>今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、 +来年は 5問、より面白い問題を持っていきます。</p> +</div> +<div class="paragraph"> +<p>実はもう作りはじめているので、どうか来年もありますように……。</p> +</div> + </div> +</section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html b/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html new file mode 100644 index 0000000..628d3f8 --- /dev/null +++ b/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html @@ -0,0 +1,222 @@ +<!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="© nsfisis"> + <meta name="description" content="ターミナルに任意の文字のバナーを表示するためのツールを Go で書いた。"> + <meta name="keywords" content=""> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>term-banner: ターミナルにバナーを表示するツールを書いた | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">term-banner: ターミナルにバナーを表示するツールを書いた</h1> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2022-04-24">2022-04-24</time>: 公開 + </li> + + <li class="revision"> + <time datetime="2022-04-27">2022-04-27</time>: -f オプションについて追記 + </li> + + </ol> + </section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + はじめに + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>こんなものを作った。</p> +</div> +<div class="literalblock"> +<div class="content"> +<pre>$ term-banner 'Hello, World!' 'こんにちは、' '世界!'</pre> +</div> +</div> +<div class="paragraph"> +<p>image::https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png[term-banner +のスクリーンショット]</p> +</div> +<div class="paragraph"> +<p>コマンドライン引数として渡した文字列をターミナルに大きく表示する。</p> +</div> +<div class="paragraph"> +<p>リポジトリはこちら: <a href="https://github.com/nsfisis/term-banner" class="bare">https://github.com/nsfisis/term-banner</a></p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + Motivation + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>以前、https://github.com/nsfisis/big-clock-mode[big-clock-mode] +という似たようなプログラムを書いた。 これは tmux の <code>:clock-mode</code> +コマンドに着想を得たもので、<code>:clock-mode</code> +よりも大きく現在時刻を表示する。</p> +</div> +<div class="paragraph"> +<p><code>big-clock-mode</code> +を開発したのは、次のようなシチュエーションで使うためである。 +弊社では現在リモートワークが基本だが、web +会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。 +こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。</p> +</div> +<div class="paragraph"> +<p>それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。</p> +</div> +<div class="paragraph"> +<p>しばらく便利に使っていたのだが、ひとつ不満点が出てきた。それは、再開する時刻がいつだったかを覚えておかなければならないということだ。 +どこかにメモしておいてもいいが、せっかくなら現在時刻とともに表示させておきたい。</p> +</div> +<div class="paragraph"> +<p>そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。 +まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + プログラム + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>全体の流れは次のようになっている。</p> +</div> +<div class="olist arabic"> +<ol class="arabic"> +<li> +<p>フォントファイルを読み込む</p> +</li> +<li> +<p>コマンドライン引数を Shift-JIS に変換する (フォントが Shift-JIS +基準で並んでいるため)</p> +</li> +<li> +<p>1文字ずつレンダリングしていく</p> +</li> +</ol> +</div> +<div class="paragraph"> +<p><code>big-clock-mode</code> が Go 製なので、今回も Go で書いた。 PNG +が標準ライブラリにあったり、Shift-JIS +のエンコーディングが準標準ライブラリにあったりしたのは助かった。</p> +</div> +<div class="paragraph"> +<p>フォントファイルは <code>go:embed</code> +で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。 +仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + フォント + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>フリーの 8x8 +ビットマップフォントである、https://littlelimit.net/misaki.htm[美咲フォント +2021-05-05a 版] を使わせていただいた。</p> +</div> +<div class="paragraph"> +<p>はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。 +同じく 8x8 +で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。</p> +</div> +<div class="paragraph"> +<p>美咲フォントは、平仮名・片仮名に留まらず、JIS +第一・第二水準の漢字までサポートしている。 +第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。</p> +</div> +<div class="paragraph"> +<p>さらに言うと、実のところ美咲フォントは実サイズ 7x7 +で作られており、余白が設けられている。 +これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。 +おかげでコーディングまで楽になった。</p> +</div> +<div class="paragraph"> +<p>ゴシック体と明朝体があったが、私の好みで明朝体の方にした。 +ただ、ゴシック体の方が見やすい気がするので、フォントを選べるように後ほど拡張するかもしれない。</p> +</div> +<div class="paragraph"> +<p>2022-04-27 追記: <code>-f</code> オプションで選べるようにした。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + おわりに + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>あなたもターミナルに住んでみませんか?</p> +</div> + </div> +</section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2022-05-01/phperkaigi-2022/index.html b/public/posts/2022-05-01/phperkaigi-2022/index.html new file mode 100644 index 0000000..4168136 --- /dev/null +++ b/public/posts/2022-05-01/phperkaigi-2022/index.html @@ -0,0 +1,324 @@ +<!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="© nsfisis"> + <meta name="description" content="2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。"> + <meta name="keywords" content="カンファレンス,PHP,PHPerKaigi"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>PHPerKaigi 2022 | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">PHPerKaigi 2022</h1> + + <ul class="post-tags"> + + <li class="tag"> + <a href="/tags/conference/">カンファレンス</a> + </li> + + <li class="tag"> + <a href="/tags/php/">PHP</a> + </li> + + <li class="tag"> + <a href="/tags/phperkaigi/">PHPerKaigi</a> + </li> + + </ul> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2022-05-01">2022-05-01</time>: 公開 + </li> + + </ol> + </section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + はじめに + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>2022-04-09 から 2022-04-11 +にかけて開催された、https://phperkaigi.jp/2022/[PHPerKaigi 2022] +に、一般参加者として参加した。 +弊社https://www.dgcircus.com/[デジタルサーカス株式会社] +はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p> +</div> +<div class="paragraph"> +<p>昨年のレポートは<a href="/posts/2021-03-30/phperkaigi-2021">こちら</a>。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 感想 + + </h2> + <div class="section-body"> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + 厳選おすすめトーク + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>多くの素晴らしいトークの中から、特におすすめのものを +5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。</p> +</div> +<div class="paragraph"> +<p><a href="https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b">予防に勝る防御なし +- 堅牢なコードを導く様々な設計のヒント</a></p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>PHP +はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。</p> +</div> +<div class="paragraph"> +<p>本講演では PHP 8.1 +をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p><a href="https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e">PHPのエラーを理解して適切なエラーハンドリングを学ぼう</a></p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice +理解していますか?<br> +これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!<br> +またそれらを理解した上でのエラーハンドリングを学びましょう。</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p><a href="https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d">エラー監視とテスト体制への改善作戦</a></p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>毎日流れてくるエラーに皆さんはどう向き合ってますか?<br> +エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。<br> +サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、<br> +エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p><a href="https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7">ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか</a></p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。</p> +</div> +<div class="paragraph"> +<p>最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には<br> +・「(私の思う)良い設計」を実現するための意思決定<br> +・「ISUCONの問題」という位置付けに由来する取捨選択<br> +・移植中に遭遇したトラブルとその解決策<br> +といった文脈や葛藤が存在しています。</p> +</div> +<div class="paragraph"> +<p>本発表はそれらを共有することで<br> +・PHPアプリケーションの設計、実装事例として役立ててもらう<br> +・ISUCONの言語移植に興味を持ってもらう<br> +・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう<br> +ことを目的とします。</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p><a href="https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854">チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた</a></p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。</p> +</div> +<div class="paragraph"> +<p>フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。</p> +</div> +<div class="paragraph"> +<p>このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。</p> +</div> +</blockquote> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + トークン問題の作成 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>今回は、PHPer チャレンジ用に弊社のトークン問題を +3題作成した。こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + PHPer チャレンジ + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p><a href="https://fortee.jp/phperkaigi-2022/challenge">1位</a>になった。<br> +また、賞品として <a href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</a> +をいただいた。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + カンファレンス全体への感想 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p><a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a> +では、こんなことを書いた。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>1つ個人的な反省点としては、(中略) Discord +しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。<br> +まあ初カンファレンスだし、とお茶を濁しておこう。</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>この反省を踏まえ、今年は積極的にほかの場 (公式の Discord +サーバや、アンカンファレンス) にも参加した。<br> +これにより、参加体験の質がはるかに向上した。特に Discord +に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる +(ことが多い) +ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。</p> +</div> +<div class="paragraph"> +<p>なお、アンカンファレンスについては、1日目の終わりにhttps://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e[トークン問題の解説放送]もおこなった。</p> +</div> +<div class="paragraph"> +<p>また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。 +今年は +3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。</p> +</div> + </div> +</section> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + そして来年へ……? + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の +4つを目標としたい。</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>プロポーザルを出す</p> +</li> +<li> +<p>PHPer チャレンジのトークン問題を 5題作成する</p> +</li> +<li> +<p>現地に行く</p> +</li> +<li> +<p>PHPer チャレンジで圧勝する</p> +</li> +</ul> +</div> +<hr> +<div class="paragraph"> +<p>最後になりましたが、PHPerKaigi +のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。</p> +</div> +<div class="paragraph"> +<p>ではまた来年。</p> +</div> + </div> +</section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html b/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html new file mode 100644 index 0000000..471678a --- /dev/null +++ b/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html @@ -0,0 +1,276 @@ +<!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="© nsfisis"> + <meta name="description" content="PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。"> + <meta name="keywords" content="カンファレンス,PHP,PHP カンファレンス"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h1> + + <ul class="post-tags"> + + <li class="tag"> + <a href="/tags/conference/">カンファレンス</a> + </li> + + <li class="tag"> + <a href="/tags/php/">PHP</a> + </li> + + <li class="tag"> + <a href="/tags/phpcon/">PHP カンファレンス</a> + </li> + + </ul> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2022-08-27">2022-08-27</time>: 公開 + </li> + + </ol> + </section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + はじめに + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>本日 <a href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</a> +が開催された (らしい)。</p> +</div> +<div class="paragraph"> +<p>カンファレンスには参加できなかったものの、懇親会の LT +で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。</p> +</div> +<div class="paragraph"> +<p>ツイート: <a href="https://twitter.com/m3m0r7/status/1563397620231712772" class="bare">https://twitter.com/m3m0r7/status/1563397620231712772</a><br> +スライド: +<a href="https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3" class="bare">https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3</a></p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 解 + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>細かいレギュレーションは不明だったので、勝手に定めた。</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>コマンドライン引数の第1引数で受けとる</p> +</li> +<li> +<p>結果は標準出力に出す</p> +</li> +<li> +<p>コンマの直後にはスペースを1つ置く</p> +</li> +<li> +<p>末尾コンマは禁止</p> +</li> +<li> +<p>数字でないものは入ってこないものとする</p> +</li> +<li> +<p>負数は入ってこないものとする</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>書いたものがこちら:</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="p">[</span><span class="o"><?</span><span class="n">php</span> <span class="nv">$n</span><span class="o">=</span><span class="nv">$argv</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span><span class="k">foreach</span><span class="p">([</span><span class="mi">1</span><span class="n">e4</span><span class="p">,</span><span class="mi">5</span><span class="n">e3</span><span class="p">,</span><span class="mi">2</span><span class="n">e3</span><span class="p">,</span><span class="mi">1</span><span class="n">e3</span><span class="p">,</span><span class="mi">500</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">50</span><span class="p">,</span><span class="mi">10</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">1</span><span class="p">]</span><span class="k">as</span><span class="nv">$x</span><span class="p">)</span><span class="k">for</span><span class="p">(;</span><span class="nv">$n</span><span class="o">>=</span><span class="nv">$x</span><span class="p">;</span><span class="nv">$n</span><span class="o">-=</span><span class="nv">$x</span><span class="p">)</span><span class="nv">$r</span><span class="p">[]</span><span class="o">=</span><span class="nv">$x</span><span class="p">;</span><span class="k">echo</span> <span class="nb">implode</span><span class="p">(</span><span class="s1">', '</span><span class="p">,</span><span class="nv">$r</span><span class="o">??</span><span class="p">[]);</span><span class="cp">?></span>]</code></pre> +</div> +</div> +<div class="paragraph"> +<p>しめて 123 バイトとなった (末尾改行を含めずにカウント)。</p> +</div> +<div class="paragraph"> +<p>こちらは改行とスペースを追加したバージョン:</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="p">[</span><span class="o"><?</span><span class="n">php</span> + +<span class="nv">$n</span> <span class="o">=</span> <span class="nv">$argv</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span> +<span class="k">foreach</span> <span class="p">([</span><span class="mi">1</span><span class="n">e4</span><span class="p">,</span> <span class="mi">5</span><span class="n">e3</span><span class="p">,</span> <span class="mi">2</span><span class="n">e3</span><span class="p">,</span> <span class="mi">1</span><span class="n">e3</span><span class="p">,</span> <span class="mi">500</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">50</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="k">as</span> <span class="nv">$x</span><span class="p">)</span> + <span class="k">for</span> <span class="p">(;</span> <span class="nv">$n</span> <span class="o">>=</span> <span class="nv">$x</span><span class="p">;</span> <span class="nv">$n</span> <span class="o">-=</span> <span class="nv">$x</span><span class="p">)</span> + <span class="nv">$r</span><span class="p">[]</span> <span class="o">=</span> <span class="nv">$x</span><span class="p">;</span> +<span class="k">echo</span> <span class="nb">implode</span><span class="p">(</span><span class="s1">', '</span><span class="p">,</span> <span class="nv">$r</span> <span class="o">??</span> <span class="p">[]);</span> + +<span class="cp">?></span>]</code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 使用したテクニック + + </h2> + <div class="section-body"> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + 指数表記 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>割と多くの言語のゴルフで使えるテクニック。<code>e</code> +を用いた指数表記で、大きな数を短く表す。このコードでは +<code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + foreach や for の中身を1つの文に + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p><code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、通常 <code>{</code> +を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<code>{</code> と <code>}</code> +を省略できる。C言語などでも使える。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + $r に初期値を入れない + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>PHP では、<code>$r[] = …​</code> +のような配列の末尾に追加する式を実行したとき、<code>$r</code> が未定義だった場合は +<code>$r</code> +を勝手に定義して空の配列で初期化してくれる。これを利用すると、<code>$r = [];</code> +のような初期化が不要になる。</p> +</div> +<div class="paragraph"> +<p>ただし、プログラムに 0 が渡されるとループを一度も回らないので、<code>$r</code> +が未定義になってしまい、<code>implode()</code> +に渡すところでエラーになる。それを防ぐために <code>$r ?? []</code> を使っている。</p> +</div> +<div class="paragraph"> +<p>もし 0 が渡されたケースを無視するなら、これが不要になるので 4 +バイト縮む。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + PHP タグの外に文字列を置く + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>PHP では、<code><?php</code> <code>?></code> +で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず +<code>[</code> と <code>]</code> を出力するので、そのまま書いてやればよい。</p> +</div> + </div> +</section> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + おわりに + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>最後になりましたが、https://twitter.com/m3m0r7[めもりー] +さん、楽しい問題をありがとうございました。</p> +</div> + </div> +</section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html b/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html new file mode 100644 index 0000000..e452599 --- /dev/null +++ b/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html @@ -0,0 +1,140 @@ +<!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="© nsfisis"> + <meta name="description" content="先日、私の勤めるデジタルサーカス株式会社が、PHP Foundation へ寄付をおこないました。 本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。"> + <meta name="keywords" content=""> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>弊社の PHP Foundation への寄付に寄せて | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">弊社の PHP Foundation への寄付に寄せて</h1> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2022-08-31">2022-08-31</time>: 公開 + </li> + + </ol> + </section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + はじめに + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p><strong>注: +これは私個人の意見であり、所属する組織を代表するものではありません。</strong></p> +</div> +<div class="paragraph"> +<p>先日、私の勤める <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> が +<a href="https://opencollective.com/phpfoundation">PHP Foundation</a> へ $2,000 +の寄付をおこないました。</p> +</div> +<div class="paragraph"> +<p>記事: <a href="https://www.dgcircus.com/news/581" class="bare">https://www.dgcircus.com/news/581</a></p> +</div> +<div class="paragraph"> +<p>本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + なぜ? + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>組織としての寄付理由は前掲した記事に譲るとして、ここでは、私が社内でこの件を推進した理由について書くことにします。</p> +</div> +<div class="paragraph"> +<p>当時の考えを端的にまとめた社内チャットの投稿があったので、それを引用します:</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="paragraph"> +<p>結局これを通したい (私の中での) +最大の理由が、「自分の勤める会社が、これをやる会社であってほしい」というのがあり、↑にしても、感情ベースの理由しか出せていないというのが説得力に欠けている理由なのだと思いますが、寄付の報告が流れてきたり、OSS +のフリーライドの話が流れてきたりするたびに、自尊心が毀損される、というか +(これは大袈裟すぎる表現で、実際にはそこまで明確に傷ついているわけではありませんが)。</p> +</div> +<div class="paragraph"> +<p>追記: 「肩身が狭くなる」というのがより適切でした。</p> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>※文中の「↑にしても」は、ここに載せていない別の投稿を指しています。</p> +</div> +<div class="paragraph"> +<p>OSS を金銭的に支援したり、技術カンファレンスへ協賛したり (あるいは +<a href="https://twitter.com/tomzoh">CTO</a> がカンファレンスを年2で主催したり: +<a href="https://iosdc.jp">iOSDC</a> <a href="https://phperkaigi.jp">PHPerKaigi</a>) +といった行為は、コミュニティへの貢献であると同時に、社員に対する精神的福利厚生でもあると言えるでしょう +(知らんけど)。これらは、技術や技術者を大切にする組織である、ということの、対外的にも対内的にも強力なメッセージなのです。</p> +</div> +<div class="paragraph"> +<p>以上が、私が社内で寄付の件を進めた (かなり私的な) 理由です。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + おわりに + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>最終的に社としての寄付まで漕ぎ着けられたのは、もちろん私の力ではなく役員の方々の決定によるものです。この場を借りて感謝申し上げます。</p> +</div> + </div> +</section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html b/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html new file mode 100644 index 0000000..c2dc8ab --- /dev/null +++ b/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html @@ -0,0 +1,929 @@ +<!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="© nsfisis"> + <meta name="description" content="PHP で、fizzbuzz を書いた。ただし、1行あたりに使える文字数は2文字まで。"> + <meta name="keywords" content="PHP"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>【PHP】fizzbuzz を書く。1行あたり2文字で。 | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">【PHP】fizzbuzz を書く。1行あたり2文字で。</h1> + + <ul class="post-tags"> + + <li class="tag"> + <a href="/tags/php/">PHP</a> + </li> + + </ul> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2022-09-28">2022-09-28</time>: 公開 + </li> + + <li class="revision"> + <time datetime="2022-09-29">2022-09-29</time>: 小さな文言の修正・変更 + </li> + + </ol> + </section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 記事の構成について + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>この記事は、普通の fizzbuzz +を徐々に変形して最終形にしていく、という構成で書かれている。最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、 +<a href="https://gist.github.com/nsfisis/04c227d5a419867472a0b23a83ad2919#file-fizzbuzz-php-2-letters-per-line-and-supports-php-8-x-without-warnings">このページ</a> +にソースコードがあるので、そちらを先に見てほしい。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + レギュレーション + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>PHP で、次のような制約の下に fizzbuzz を書いた。</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>1行あたりの文字数は2文字までに収めること (ただし <code><?php</code> タグは除く)</p> +<div class="ulist"> +<ul> +<li> +<p>厳密な定義: <code><?php</code> タグ以降のソースコードが、2 byte ごとに +ラインフィード (LF) で区切られること</p> +</li> +</ul> +</div> +</li> +<li> +<p>スペースやタブを使用しないこと</p> +</li> +<li> +<p>ループのアンロールをしないこと</p> +<div class="ulist"> +<ul> +<li> +<p>100 回ループの代わりに 100 回コードをコピペ、というのは禁止</p> +</li> +</ul> +</div> +</li> +<li> +<p>PHP 7.4〜8.1 で動作すること</p> +</li> +<li> +<p>実行時に Notice や Warning が出ないこと</p> +</li> +<li> +<p>標準的なインストール構成の PHP で実現できること +(デフォルトで有効になっていない拡張等を使わないこと)</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>備考: PHP には <code>short_open_tag</code> +というオプションがあり、これを有効にするとファイル冒頭の <code><?php</code> +の代わりに <code><?</code> +を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト +off になっている環境が多いようなので、今回は使わないことにした。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 主な障害 + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>1行あたりの文字数など、適当に改行を挟めばいいだけではないのか?</p> +</div> +<div class="paragraph"> +<p>特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="c"><span class="cp">#\ +i\ +n\ +c\ +l\ +u\ +d\ +e\ +<\ +s\ +t\ +d\ +i\ +o\ +.\ +h\ +>\ +</span><span class="cm">/* +*/</span><span class="cp"> +</span><span class="n">i</span>\ +<span class="n">n</span>\ +<span class="n">t</span>\ +<span class="cm">/* +*/</span> +<span class="n">m</span>\ +<span class="n">a</span>\ +<span class="n">i</span>\ +<span class="n">n</span><span class="p">(</span> +<span class="p">){</span> +<span class="n">f</span>\ +<span class="n">o</span>\ +<span class="n">r</span><span class="p">(</span> +<span class="n">i</span>\ +<span class="n">n</span>\ +<span class="n">t</span>\ +<span class="cm">/* +*/</span> +<span class="n">i</span><span class="o">=</span> +<span class="mi">1</span><span class="p">;</span> +<span class="n">i</span><span class="o"><</span> +<span class="mi">1</span>\ +<span class="mi">0</span>\ +<span class="mi">0</span><span class="p">;</span> +<span class="n">i</span>\ +<span class="o">+</span>\ +<span class="o">+</span><span class="p">)</span> +<span class="k">if</span> +<span class="p">(</span><span class="n">i</span> +<span class="o">%</span>\ +<span class="mi">15</span> +<span class="o">==</span> +<span class="mi">0</span><span class="p">)</span> +<span class="n">p</span>\ +<span class="n">r</span>\ +<span class="n">i</span>\ +<span class="n">n</span>\ +<span class="n">t</span>\ +<span class="n">f</span><span class="p">(</span> +<span class="s">"\ +F\ +i\ +z\ +z\ +B\ +u\ +z\ +z\ +%\ +c\ +"</span><span class="p">,</span> +<span class="mi">10</span> +<span class="p">);</span> + +<span class="cm">/* あとは同じように普通のプログラムを変形するだけなので省略 */</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。</p> +</div> +<div class="paragraph"> +<p>さて、PHP +ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、<code>echo</code> +で出力することや、<code>for</code> でループすること、<code>new</code> +でインスタンスを生成することができない。特に、出力は fizzbuzz +をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。</p> +</div> +<div class="paragraph"> +<p>当然、名前が3文字以上ある関数も使えない。なお、標準 PHP +の範囲内において、名前が 2文字以下の関数は以下のとおりである:</p> +</div> +<div class="ulist"> +<ul> +<li> +<p><code>_</code>: <code>gettext</code> のエイリアス</p> +</li> +<li> +<p><code>dl</code>: 拡張モジュールをロードする</p> +</li> +<li> +<p><code>pi</code>: 円周率を返す</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>(環境によって多少は変わるかも)</p> +</div> +<div class="paragraph"> +<p>2文字の関数を定義しまくった拡張モジュールを用意しておいて <code>dl()</code> +で読み込む行為は、レギュレーションで定めた</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="ulist"> +<ul> +<li> +<p>標準的なインストール構成の PHP で実現できること +(デフォルトで有効になっていない拡張等を使わないこと)</p> +</li> +</ul> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>に反する +(というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。</p> +</div> +<div class="paragraph"> +<p>また、2文字だと文字列がまともに書けないのも辛い。<code>''</code> だけで +2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP +では文字列リテラル中に生の改行が書けるので</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="nv">$a</span> +<span class="o">=</span><span class="s1">' +a'</span> +<span class="p">;;</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>とすると <code>$a</code> は <code>"\na"</code> になるのだが、余計な改行が入ってしまう。</p> +</div> +<div class="paragraph"> +<p>これらの障害をどのように乗り越えるのか、次節から見ていく。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 解説 + + </h2> + <div class="section-body"> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + 普通の (?) fizzbuzz + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>まずは普通に書くとしよう。</p> +</div> +<div class="literalblock"> +<div class="content"> +<pre><?php + +for ($i = 1; $i < 100; $i++) { + echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"; +}</pre> +</div> +</div> +<div class="paragraph"> +<p>素直に書いた fizzbuzz +とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + <code>for</code> の排除 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p><code>for</code> +は、3文字もある長いキーワードである。こんなものは使えない。<code>array_</code> +系の関数を使って、適当に置き換えるとしよう。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="o"><?</span><span class="n">php</span> + +<span class="nv">$s</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">);</span> +<span class="nb">array_walk</span><span class="p">(</span> + <span class="nv">$s</span><span class="p">,</span> + <span class="k">fn</span><span class="p">(</span><span class="nv">$i</span><span class="p">)</span> <span class="o">=></span> + <span class="nb">printf</span><span class="p">(((</span><span class="nv">$i</span> <span class="o">%</span> <span class="mi">3</span> <span class="o">?</span> <span class="s1">''</span> <span class="o">:</span> <span class="s1">'Fizz'</span><span class="p">)</span> <span class="mf">.</span> <span class="p">(</span><span class="nv">$i</span> <span class="o">%</span> <span class="mi">5</span> <span class="o">?</span> <span class="s1">''</span> <span class="o">:</span> <span class="s1">'Buzz'</span><span class="p">)</span> <span class="o">?:</span> <span class="nv">$i</span><span class="p">)</span> <span class="mf">.</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">),</span> +<span class="p">);</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p><code>array_walk</code> や <code>range</code>、<code>printf</code> といった <code>for</code> +よりも長いトークンが現れてしまったが、これは次節で直すことにする。なお、<code>echo</code> +は文 (statement) であり式 (expression) ではないので、式である <code>printf</code> +に置き換えた。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + 関数呼び出しの短縮 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p><code>range</code>、<code>array_walk</code>、<code>printf</code> +は長すぎるのでどうにかせねばならない。ここで、PHP +の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="o"><?</span><span class="n">php</span> + +<span class="nv">$r</span> <span class="o">=</span> <span class="s1">'range'</span><span class="p">;</span> +<span class="nv">$w</span> <span class="o">=</span> <span class="s1">'array_walk'</span><span class="p">;</span> +<span class="nv">$p</span> <span class="o">=</span> <span class="s1">'printf'</span><span class="p">;</span> + +<span class="nv">$s</span> <span class="o">=</span> <span class="nv">$r</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">);</span> +<span class="nv">$w</span><span class="p">(</span> + <span class="nv">$s</span><span class="p">,</span> + <span class="k">fn</span><span class="p">(</span><span class="nv">$i</span><span class="p">)</span> <span class="o">=></span> + <span class="nv">$p</span><span class="p">(((</span><span class="nv">$i</span> <span class="o">%</span> <span class="mi">3</span> <span class="o">?</span> <span class="s1">''</span> <span class="o">:</span> <span class="s1">'Fizz'</span><span class="p">)</span> <span class="mf">.</span> <span class="p">(</span><span class="nv">$i</span> <span class="o">%</span> <span class="mi">5</span> <span class="o">?</span> <span class="s1">''</span> <span class="o">:</span> <span class="s1">'Buzz'</span><span class="p">)</span> <span class="o">?:</span> <span class="nv">$i</span><span class="p">)</span> <span class="mf">.</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">),</span> +<span class="p">);</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>これで関数を呼び出している所は短くなった。では、<code>$r</code> や <code>$w</code> や +<code>$p</code>、また <code>'Fizz'</code> や <code>'Buzz'</code> はどうやって +1行2文字に収めるのか。次のテクニックへ移ろう。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + 余談: PHP 8.x で動作しなくてもいいなら + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="ulist"> +<ul> +<li> +<p>PHP 7.4〜8.1 で動作すること</p> +</li> +</ul> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という +PHP 7.x までの仕様が利用できる。例えば、 <code>Fizz</code> +という文字列が欲しければ、次のようにする。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="nv">$f</span> +<span class="o">=</span><span class="nc">F</span> +<span class="mf">.</span><span class="n">i</span> +<span class="mf">.</span><span class="n">z</span> +<span class="mf">.</span><span class="n">z</span> +<span class="p">;;</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>こうして簡単に文字列を作れる。なお、この仕様は 7.x +時点でも警告を受けるので、<code>@</code> 演算子を使って抑制してやるとよい。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="nv">$f</span> +<span class="o">=@</span> +<span class="nc">F</span><span class="mf">.</span> +<span class="o">@</span><span class="n">i</span> +<span class="mf">.</span><span class="c1">#</span> +<span class="o">@</span><span class="n">z</span> +<span class="mf">.</span><span class="c1">#</span> +<span class="o">@</span><span class="n">z</span> +<span class="p">;;</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>むしろ、このことがわかっていたからこそ PHP 8.x +での動作を要件に課したところがある。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + 文字列リテラルの短縮 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>実際に使った手法の説明に移る。</p> +</div> +<div class="paragraph"> +<p>ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 +(<code>&</code>、<code>|</code>、<code>^</code>) +をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="nv">$a</span> <span class="o">=</span> <span class="s2">"12345"</span><span class="p">;</span> +<span class="nv">$b</span> <span class="o">=</span> <span class="s2">"world"</span><span class="p">;</span> + +<span class="c1">// $a ^ $b は次のコードと同じ</span> +<span class="nv">$result</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span> +<span class="k">for</span> <span class="p">(</span><span class="nv">$i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nv">$i</span> <span class="o"><</span> <span class="nb">min</span><span class="p">(</span><span class="nb">strlen</span><span class="p">(</span><span class="nv">$a</span><span class="p">),</span> <span class="nb">strlen</span><span class="p">(</span><span class="nv">$b</span><span class="p">));</span> <span class="nv">$i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> + <span class="nv">$result</span> <span class="mf">.</span><span class="o">=</span> <span class="nv">$a</span><span class="p">[</span><span class="nv">$i</span><span class="p">]</span> <span class="o">^</span> <span class="nv">$b</span><span class="p">[</span><span class="nv">$i</span><span class="p">];</span> +<span class="p">}</span> + +<span class="k">echo</span> <span class="nv">$result</span><span class="p">;</span> +<span class="c1">// => F]AXQ</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>これを踏まえ、次のコードを見てみよう。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="nv">$x</span> <span class="o">=</span> <span class="s2">"x</span><span class="se">\n</span><span class="s2">Om</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span> +<span class="nv">$y</span> <span class="o">=</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">k!</span><span class="se">\n</span><span class="s2">o"</span><span class="p">;</span> +<span class="nv">$r</span> <span class="o">=</span> <span class="nv">$x</span> <span class="o">^</span> <span class="nv">$y</span><span class="p">;</span> +<span class="k">echo</span> <span class="s2">"</span><span class="nv">$r</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>実行すると、<code>range</code> が表示される。さて、PHP +では文字列リテラル中に生の改行を直接書いてもよいのだった +(「主な障害」の節を参照のこと)。書きかえてみよう。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="nv">$x</span> +<span class="o">=</span><span class="s1">'x +Om +'</span><span class="p">;</span> +<span class="nv">$y</span> +<span class="o">=</span><span class="s1">' +k! +o'</span> +<span class="p">;</span> + +<span class="nv">$r</span> <span class="o">=</span> <span class="nv">$x</span> <span class="o">^</span> <span class="nv">$y</span><span class="p">;</span> +<span class="k">echo</span> <span class="s2">"</span><span class="nv">$r</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>さらに <code>#</code> を使って適当に調整すると、次のようになる。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="nv">$x</span> +<span class="o">=</span><span class="c1">#</span> +<span class="s1">'x +Om +'</span><span class="p">;</span> +<span class="nv">$y</span> +<span class="o">=</span><span class="s1">' +k! +o'</span> +<span class="p">;</span><span class="c1">#</span> +<span class="nv">$r</span> +<span class="o">=</span><span class="c1">#</span> +<span class="nv">$x</span> +<span class="o">^</span><span class="c1">#</span> +<span class="nv">$y</span> +<span class="p">;</span><span class="c1">#</span> + +<span class="k">echo</span> <span class="s2">"</span><span class="nv">$r</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>1行あたり2文字で、<code>range</code> +という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。</p> +</div> +<div class="paragraph"> +<p>備考: <code>Buzz</code> 中にある小文字の <code>u</code> は、このロジックだと non-printable +な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。</p> +</div> + </div> +</section> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 完成系 + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>完成したものがこちら。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="o"><?</span><span class="n">php</span> + +<span class="nv">$x</span> +<span class="o">=</span><span class="c1">#</span> +<span class="s1">'i +S'</span> +<span class="p">;;</span> +<span class="nv">$y</span> +<span class="o">=</span><span class="s1">' +b! +'</span><span class="p">;</span> +<span class="nv">$c</span> +<span class="o">=</span><span class="c1">#</span> +<span class="nv">$x</span> +<span class="o">^</span><span class="c1">#</span> +<span class="nv">$y</span> +<span class="p">;</span><span class="c1">#</span> +<span class="nv">$x</span> +<span class="o">=</span><span class="c1">#</span> +<span class="s1">'x +Om +'</span><span class="p">;</span> +<span class="nv">$y</span> +<span class="o">=</span><span class="s1">' +k! +o'</span> +<span class="p">;</span><span class="c1">#</span> +<span class="nv">$r</span> +<span class="o">=</span><span class="c1">#</span> +<span class="nv">$x</span> +<span class="o">^</span><span class="c1">#</span> +<span class="nv">$y</span> +<span class="p">;</span><span class="c1">#</span> +<span class="nv">$x</span> +<span class="o">=</span><span class="c1">#</span> +<span class="s1">'k +Sk +~} +Ma +'</span><span class="p">;</span> +<span class="nv">$y</span> +<span class="o">=</span><span class="s1">' +x! +s! +k! +'</span><span class="p">;</span> +<span class="nv">$w</span> +<span class="o">=</span><span class="c1">#</span> +<span class="nv">$x</span> +<span class="o">^</span><span class="c1">#</span> +<span class="nv">$y</span> +<span class="p">;</span><span class="c1">#</span> +<span class="nv">$x</span> +<span class="o">=</span><span class="c1">#</span> +<span class="s1">'z +Hd +G'</span> +<span class="p">;</span><span class="c1">#</span> +<span class="nv">$y</span> +<span class="o">=</span><span class="s1">' +x! +~! +'</span><span class="p">;</span> +<span class="nv">$p</span> +<span class="o">=</span><span class="c1">#</span> +<span class="nv">$x</span> +<span class="o">^</span><span class="c1">#</span> +<span class="nv">$y</span> +<span class="p">;</span><span class="c1">#</span> +<span class="nv">$x</span> +<span class="o">=</span><span class="c1">#</span> +<span class="s1">'L +[p +'</span><span class="p">;</span> +<span class="nv">$y</span> +<span class="o">=</span><span class="s1">' +c! +'</span><span class="p">;</span> +<span class="nv">$f</span> +<span class="o">=</span><span class="c1">#</span> +<span class="nv">$x</span> +<span class="o">^</span><span class="c1">#</span> +<span class="nv">$y</span> +<span class="p">;</span><span class="c1">#</span> +<span class="nv">$x</span> +<span class="o">=</span><span class="c1">#</span> +<span class="s1">'H +[p +'</span><span class="p">;</span> +<span class="nv">$y</span> +<span class="o">=</span><span class="s1">' +_! +'</span><span class="p">;</span> +<span class="nv">$b</span> +<span class="o">=</span><span class="c1">#</span> +<span class="nv">$x</span> +<span class="o">^</span><span class="c1">#</span> +<span class="nv">$y</span> +<span class="p">;</span><span class="c1">#</span> +<span class="nv">$b</span> +<span class="p">[</span><span class="mi">1</span> +<span class="p">]</span><span class="o">=</span> +<span class="nv">$c</span> +<span class="p">(</span><span class="c1">#</span> +<span class="mi">13</span> +<span class="o">*</span><span class="mi">9</span> +<span class="p">);</span> +<span class="nv">$s</span> +<span class="o">=</span><span class="c1">#</span> +<span class="nv">$r</span> +<span class="p">(</span><span class="mi">1</span> +<span class="p">,(</span> +<span class="mi">10</span> +<span class="o">**</span> +<span class="mi">2</span><span class="p">)</span> +<span class="p">);</span> +<span class="nv">$w</span> +<span class="p">(</span><span class="c1">#</span> +<span class="nv">$s</span> +<span class="p">,</span><span class="c1">#</span> +<span class="k">fn</span> +<span class="p">(</span><span class="c1">#</span> +<span class="nv">$i</span> +<span class="p">)</span><span class="c1">#</span> +<span class="o">=></span> +<span class="nv">$p</span> +<span class="p">((</span> +<span class="p">(</span><span class="c1">#</span> +<span class="nv">$i</span> +<span class="o">%</span><span class="mi">3</span> +<span class="o">?</span><span class="c1">#</span> +<span class="s1">''</span> +<span class="o">:</span><span class="c1">#</span> +<span class="nv">$f</span> +<span class="p">)</span><span class="mf">.</span> +<span class="p">(</span><span class="c1">#</span> +<span class="nv">$i</span> +<span class="o">%</span><span class="mi">5</span> +<span class="o">?</span><span class="c1">#</span> +<span class="s1">''</span> +<span class="o">:</span><span class="c1">#</span> +<span class="nv">$b</span> +<span class="p">)</span><span class="o">?</span> +<span class="o">:</span><span class="c1">#</span> +<span class="nv">$i</span> +<span class="p">)</span><span class="c1">#</span> +<span class="mf">.</span><span class="s1">' +'</span><span class="p">)</span> +<span class="p">);</span></code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 感想など + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>PHP は、スクリプト言語の中だとシンタックスシュガーが少ない +(体感)。この挑戦は不可能に思われたが、PHP +マニュアルとにらめっこしていたらなんとかなった。</p> +</div> +<div class="paragraph"> +<p>みんなもプログラムを細長くしよう。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 余談2: 別解 + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>PHP では、バッククォートを使ってシェルを呼び出せる。これは <code>shell_exec</code> +関数と等価である。さて、PHP +ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える +(当然だが、呼び出されるシェルに依存する。Bash +なら大丈夫だろう。知らんけど)。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="o"><?</span><span class="n">php</span> + +<span class="nb">printf</span><span class="p">(</span><span class="err">`</span> +<span class="n">e</span><span class="err">\</span> +<span class="n">c</span><span class="err">\</span> +<span class="n">h</span><span class="err">\</span> +<span class="n">o</span><span class="err">\</span> + <span class="err">\</span> +<span class="mi">1</span><span class="err">\</span> +<span class="mi">2</span><span class="err">\</span> +<span class="mi">3</span><span class="err">\</span> +<span class="err">`</span><span class="p">);</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>なお、ここでは簡単のため出力に <code>printf</code> をそのまま使っているが、実際には +<code>printf</code> という文字列を合成して可変関数で呼び出す。</p> +</div> +<div class="paragraph"> +<p>ただし、これでは</p> +</div> +<div class="quoteblock"> +<blockquote> +<div class="ulist"> +<ul> +<li> +<p>スペースやタブを使用しないこと</p> +</li> +</ul> +</div> +</blockquote> +</div> +<div class="paragraph"> +<p>に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。</p> +</div> +<div class="paragraph"> +<p>もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="o"><?</span><span class="n">php</span> + +<span class="nv">$c</span> <span class="o">=</span> <span class="s1">'chr'</span><span class="p">;</span> + +<span class="err">$</span><span class="p">{</span> +<span class="s1">'_ +'</span><span class="p">}</span> +<span class="o">=</span><span class="c1">#</span> +<span class="nv">$c</span> +<span class="p">(</span><span class="c1">#</span> +<span class="mi">32</span> +<span class="p">)</span><span class="mf">.</span> +<span class="nv">$c</span> +<span class="p">(</span><span class="c1">#</span> +<span class="mi">92</span> +<span class="p">);</span> + +<span class="nb">printf</span><span class="p">(</span><span class="err">`</span> +<span class="n">e</span><span class="err">\</span> +<span class="n">c</span><span class="err">\</span> +<span class="n">h</span><span class="err">\</span> +<span class="n">o</span><span class="err">\</span> +<span class="err">$</span><span class="p">{</span> +<span class="s1">'_ +'</span><span class="p">}</span> +<span class="mi">1</span><span class="err">\</span> +<span class="mi">2</span><span class="err">\</span> +<span class="mi">3</span><span class="err">\</span> +<span class="err">`</span><span class="p">);</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>先程と同じく、<code>chr</code> や <code>printf</code> を生成する部分は長くなるので省いた。</p> +</div> +<div class="literalblock"> +<div class="content"> +<pre>${ +'_ +'}</pre> +</div> +</div> +<div class="paragraph"> +<p>は変数で、中にはスペースとエスケープが入っている +(<code>chr(32) . chr(92)</code>)。シェルに渡されている文字列は次のようになる。</p> +</div> +<div class="literalblock"> +<div class="content"> +<pre>e\ +c\ +h\ +o\ + \ +1\ +2\ +3\</pre> +</div> +</div> +<div class="paragraph"> +<p>これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz +のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう +(試してないけど)。</p> +</div> +<div class="paragraph"> +<p>ということでこれは別解ということにしておく。</p> +</div> +<div class="paragraph"> +<p>ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。</p> +</div> +<div class="literalblock"> +<div class="content"> +<pre>${ +'_ +'}</pre> +</div> +</div> +<div class="paragraph"> +<p>最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。</p> +</div> + </div> +</section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html b/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html new file mode 100644 index 0000000..efb7239 --- /dev/null +++ b/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html @@ -0,0 +1,291 @@ +<!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="© nsfisis"> + <meta name="description" content="来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、 ボツになった問題を公開する (その 1)。"> + <meta name="keywords" content="PHP,PHPerKaigi"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>PHPerKaigi 2023: ボツになったトークン問題 その 1 | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">PHPerKaigi 2023: ボツになったトークン問題 その 1</h1> + + <ul class="post-tags"> + + <li class="tag"> + <a href="/tags/php/">PHP</a> + </li> + + <li class="tag"> + <a href="/tags/phperkaigi/">PHPerKaigi</a> + </li> + + </ul> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2022-10-23">2022-10-23</time>: 公開 + </li> + + </ol> + </section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + はじめに + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) +の、 <a href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</a> +において、昨年と同様に、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> +から、トークン問題を出題予定である。</p> +</div> +<div class="paragraph"> +<p>昨年のトークン問題の記事はこちら: +<a href="/posts/2022-04-09/phperkaigi-2022-tokens">PHPerKaigi 2022 +トークン問題の解説</a></p> +</div> +<div class="paragraph"> +<p>すでに 2023 +年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi +開催を待つ間に紹介しようと思う。</p> +</div> +<div class="paragraph"> +<p>10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 問題 + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>注意: これはボツ問なので、得られたトークンを PHPerKaigi +で入力してもポイントにはならない。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="o"><?</span><span class="n">php</span> + +<span class="nv">$π</span> <span class="o">=</span> <span class="nv">$argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">??</span> <span class="kc">null</span><span class="p">;</span> +<span class="k">if</span> <span class="p">(</span><span class="nv">$π</span> <span class="o">===</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span> + <span class="k">exit</span><span class="p">(</span><span class="s1">'No input.'</span><span class="p">);</span> +<span class="p">}</span> +<span class="nv">$π</span> <span class="o">=</span> <span class="nb">trim</span><span class="p">(</span><span class="nv">$π</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">is_numeric</span><span class="p">(</span><span class="nv">$π</span><span class="p">))</span> <span class="p">{</span> + <span class="k">exit</span><span class="p">(</span><span class="s1">'Invalid input.'</span><span class="p">);</span> +<span class="p">}</span> + +<span class="nv">$s</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="nb">array_map</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="mf">...</span><span class="p">),</span> <span class="nb">str_split</span><span class="p">(</span><span class="nv">$π</span><span class="p">,</span> <span class="mi">2</span><span class="p">)));</span> + +<span class="nb">preg_match</span><span class="p">(</span><span class="s1">'/(\x23.+?) /'</span><span class="p">,</span> <span class="nv">$s</span><span class="p">,</span> <span class="nv">$m</span><span class="p">);</span> +<span class="nv">$t</span> <span class="o">=</span> <span class="nv">$m</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">??</span> <span class="s1">''</span><span class="p">;</span> + +<span class="k">if</span> <span class="p">(</span><span class="nb">md5</span><span class="p">(</span><span class="nv">$t</span><span class="p">)</span> <span class="o">===</span> <span class="s1">'056e831a4146bf123e8ea16613303d2e'</span><span class="p">)</span> <span class="p">{</span> + <span class="k">echo</span> <span class="s2">"Token: </span><span class="si">{</span><span class="nv">$t</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span> +<span class="p">}</span> <span class="k">else</span> <span class="p">{</span> + <span class="k">echo</span> <span class="s2">"Failed.</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span> +<span class="p">}</span></code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + トークン入手方法 + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>ソースを見るとわかるとおり、<code>$argv[1]</code> を参照している。それを <code>$π</code> +なる変数に代入しているので、円周率を渡してみる。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>php Q.php 3.14 +<span class="go">Failed.</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>失敗してしまった。精度を上げてみる。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>php Q.php 3.1415 +<span class="go">Failed.</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>だめだった。これを成功するまで繰り返す。</p> +</div> +<div class="paragraph"> +<p>最初にトークンが得られるのは、小数点以下 16 +桁目まで入力したときで、こうなる。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>php Q.php 3.1415926535897932 +<span class="gp">Token: #</span>YO</code></pre> +</div> +</div> +<div class="paragraph"> +<p>めでたくトークン「#YO」が手に入った。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 解説 + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>短いので頭から追っていく。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="nv">$π</span> <span class="o">=</span> <span class="nv">$argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">??</span> <span class="kc">null</span><span class="p">;</span> +<span class="k">if</span> <span class="p">(</span><span class="nv">$π</span> <span class="o">===</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span> + <span class="k">exit</span><span class="p">(</span><span class="s1">'No input.'</span><span class="p">);</span> +<span class="p">}</span> +<span class="nv">$π</span> <span class="o">=</span> <span class="nb">trim</span><span class="p">(</span><span class="nv">$π</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">is_numeric</span><span class="p">(</span><span class="nv">$π</span><span class="p">))</span> <span class="p">{</span> + <span class="k">exit</span><span class="p">(</span><span class="s1">'Invalid input.'</span><span class="p">);</span> +<span class="p">}</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>入力のバリデーション部分。数値のみ受け付ける。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="nv">$s</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="nb">array_map</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="mf">...</span><span class="p">),</span> <span class="nb">str_split</span><span class="p">(</span><span class="nv">$π</span><span class="p">,</span> <span class="mi">2</span><span class="p">)));</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p><code>$π</code> を 2 文字ごとに区切り (<code>str_split</code>)、数値を ASCII +コードと見做して文字に変換 (<code>chr</code>) して結合 (<code>implode</code>) している。</p> +</div> +<div class="paragraph"> +<p>例えば、<code>$π</code> が <code>'656667'</code> だったとすると、<code>65</code>、<code>66</code>、<code>67</code> に対応した +<code>'A'</code>、<code>'B'</code>、<code>'C'</code> へと変換され、<code>'ABC'</code> になる。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="nv">$π</span> <span class="o">=</span> <span class="s1">'656667'</span><span class="p">;</span> +<span class="nv">$s</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="nb">array_map</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="mf">...</span><span class="p">),</span> <span class="nb">str_split</span><span class="p">(</span><span class="nv">$π</span><span class="p">,</span> <span class="mi">2</span><span class="p">)));</span> +<span class="k">echo</span> <span class="nv">$s</span><span class="p">;</span> +<span class="c1">// => ABC</span></code></pre> +</div> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="nb">preg_match</span><span class="p">(</span><span class="s1">'/(\x23.+?) /'</span><span class="p">,</span> <span class="nv">$s</span><span class="p">,</span> <span class="nv">$m</span><span class="p">);</span> +<span class="nv">$t</span> <span class="o">=</span> <span class="nv">$m</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">??</span> <span class="s1">''</span><span class="p">;</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>正規表現でマッチングしている。<code>\x23</code> は <code>#</code> +と同じであることに留意すると、この正規表現は「<code>#</code> から始まる 2 +以上の長さ (含 <code>#</code>) +の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi +におけるトークンである。</p> +</div> +<div class="paragraph"> +<p>なお、<code>#</code> を直接書いていないのは、<code>/#.+?) /</code> と書くと、<code>#.+?)</code> +という意図せぬトークンが登録されてしまうからである。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="php"><span class="k">if</span> <span class="p">(</span><span class="nb">md5</span><span class="p">(</span><span class="nv">$t</span><span class="p">)</span> <span class="o">===</span> <span class="s1">'056e831a4146bf123e8ea16613303d2e'</span><span class="p">)</span> <span class="p">{</span> + <span class="k">echo</span> <span class="s2">"Token: </span><span class="si">{</span><span class="nv">$t</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span> +<span class="p">}</span> <span class="k">else</span> <span class="p">{</span> + <span class="k">echo</span> <span class="s2">"Failed.</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span> +<span class="p">}</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>最後にトークンのハッシュ値を見て、想定解かどうかを確認する。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + おわりに + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>円周率を何桁も計算して ASCII +コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。</p> +</div> +<div class="paragraph"> +<p>最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた +(ちなみに、それでも <code>M_PI</code> や <code>pi()</code> +では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100 +万桁目くらいに埋まっていてくれたほうがよかったかもしれない。</p> +</div> + </div> +</section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/2022-10-28/setup-server-for-this-site/index.html b/public/posts/2022-10-28/setup-server-for-this-site/index.html new file mode 100644 index 0000000..c070c03 --- /dev/null +++ b/public/posts/2022-10-28/setup-server-for-this-site/index.html @@ -0,0 +1,630 @@ +<!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="© nsfisis"> + <meta name="description" content="GitHub Pages でホストしていたこのサイトを VPS へ移行したので、 そのときにやったことのメモ。99 % 自分用。"> + <meta name="keywords" content="備忘録"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>【備忘録】このサイト用の VPS をセットアップしたときのメモ | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="single"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <article class="post-single"> + <header class="post-header"> + <h1 class="post-title">【備忘録】このサイト用の VPS をセットアップしたときのメモ</h1> + + <ul class="post-tags"> + + <li class="tag"> + <a href="/tags/note-to-self/">備忘録</a> + </li> + + </ul> + + </header> + <div class="post-content"> + <section> + <h2 id="changelog">更新履歴</h2> + <ol> + + <li class="revision"> + <time datetime="2022-10-28">2022-10-28</time>: 公開 + </li> + + </ol> + </section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + はじめに + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS +に移行した。そのときにおこなったサーバのセットアップ作業を書き残しておく。99 +% 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。</p> +</div> +<div class="paragraph"> +<p>未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + VPS + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p><a href="https://vps.sakura.ad.jp/">さくらの VPS</a> の 2 GB +プラン。そこまで真面目に選定していないので、困ったら移動するかも。</p> +</div> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 事前準備 + + </h2> + <div class="section-body"> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + サーバのホスト名を決める + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>モチベーションが上がるという効能がある。今回は藤原定家から取って +``teika'' +にした。たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + SSH の鍵生成 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>ローカルマシンで鍵を生成する。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-b</span> 521 <span class="nt">-f</span> ~/.ssh/teika.key +<span class="gp">$</span><span class="w"> </span>ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-b</span> 521 <span class="nt">-f</span> ~/.ssh/github2teika.key</code></pre> +</div> +</div> +<div class="paragraph"> +<p><code>teika.key</code> はローカルからサーバへの接続用、<code>github2teika.key</code> +は、GitHub Actions からサーバへのデプロイ用。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + SSH の設定 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p><code>.ssh/config</code> に設定しておく。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="ssh_config">Host teika + HostName ********** + User ********** + Port ********** + IdentityFile ~/.ssh/teika.key</code></pre> +</div> +</div> + </div> +</section> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 基本のセットアップ + + </h2> + <div class="section-body"> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + SSH 接続 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + ユーザを作成する + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。<code>sudo</code> +グループに追加して <code>sudo</code> できるようにし、<code>su</code> で切り替え。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>adduser <span class="k">**********</span> +<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>adduser <span class="k">**********</span> <span class="nb">sudo</span> +<span class="gp">$</span><span class="w"> </span>su <span class="k">**********</span> +<span class="gp">$</span><span class="w"> </span><span class="nb">cd</span></code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + ホスト名を変える + + </h3> + <div class="section-body"> + <div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo hostname </span>teika</code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + 公開鍵を置く + + </h3> + <div class="section-body"> + <div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">mkdir</span> ~/.ssh +<span class="gp">$</span><span class="w"> </span><span class="nb">chmod </span>700 ~/.ssh +<span class="gp">$</span><span class="w"> </span>vi ~/.ssh/authorized_keys</code></pre> +</div> +</div> +<div class="paragraph"> +<p><code>authorized_keys</code> には、ローカルで生成した <code>~/.ssh/teika.key.pub</code> と +<code>~/.ssh/github2teika.key.pub</code> の内容をコピーする。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + SSH の設定 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>SSH の設定を変更し、少しでも安全にしておく。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo cp</span> /etc/ssh/sshd_config /etc/ssh/sshd_config.bak +<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>vi /etc/ssh/sshd_config</code></pre> +</div> +</div> +<div class="ulist"> +<ul> +<li> +<p><code>Port</code> を変更</p> +</li> +<li> +<p><code>PermitRootLogin</code> を <code>no</code> に</p> +</li> +<li> +<p><code>PasswordAuthentication</code> を <code>no</code> に</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>そして設定を反映。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>systemctl restart sshd +<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>systemctl status sshd</code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + SSH で接続確認 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>今の SSH +セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH +の設定に不備があった場合に締め出しをくらう。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>ssh teika</code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + ポートの遮断 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>デフォルトの 22 番を閉じ、設定したポートだけ空ける。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw deny ssh +<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw allow <span class="k">*******</span> +<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw <span class="nb">enable</span> +<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw reload +<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw status</code></pre> +</div> +</div> +<div class="paragraph"> +<p>ここでもう一度 SSH の接続確認を挟む。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + GitHub 用の SSH 鍵 + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>GitHub に置いてある private リポジトリをサーバから clone したいので、SSH +鍵を生成して置いておく。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-b</span> 521 <span class="nt">-f</span> ~/.ssh/github.key +<span class="gp">$</span><span class="w"> </span><span class="nb">cat</span> ~/.ssh/github.key.pub</code></pre> +</div> +</div> +<div class="paragraph"> +<p><a href="https://github.com/settings/ssh">GitHub の設定画面</a> +から、この公開鍵を追加する。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>vi ~/.ssh/config</code></pre> +</div> +</div> +<div class="paragraph"> +<p>設定はこう。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="ssh_config">Host github.com + HostName github.com + User git + IdentityFile ~/.ssh/github.key</code></pre> +</div> +</div> +<div class="paragraph"> +<p>最後に接続できるか確認しておく。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="go">ssh -T github.com</span></code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + パッケージの更新 + + </h3> + <div class="section-body"> + <div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt update +<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt upgrade +<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt update +<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt upgrade +<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt autoremove</code></pre> +</div> +</div> + </div> +</section> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + サイトホスティング用のセットアップ + + </h2> + <div class="section-body"> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + DNS に IP アドレスを登録する + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>このサーバは固定の IP アドレスがあるので、<code>A</code> +レコードに直接入れるだけで済んだ。</p> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + 使うソフトウェアのインストール + + </h3> + <div class="section-body"> + <div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt <span class="nb">install </span>docker docker-compose git make</code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + メインユーザが Docker を使えるように + + </h3> + <div class="section-body"> + <div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="go">sudo adduser ********** docker</span></code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + HTTP/HTTPS を通す + + </h3> + <div class="section-body"> + <div class="paragraph"> +<p>80 番と 443 番を空ける。</p> +</div> +<div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw allow 80/tcp +<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw allow 443/tcp +<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw reload +<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw status</code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + リポジトリのクローン + + </h3> + <div class="section-body"> + <div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">cd</span> +<span class="gp">$</span><span class="w"> </span>git clone git@github.com:nsfisis/nsfisis.dev.git +<span class="gp">$</span><span class="w"> </span><span class="nb">cd </span>nsfisis.dev +<span class="gp">$</span><span class="w"> </span>git submodule update <span class="nt">--init</span></code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + certbot で証明書取得 + + </h3> + <div class="section-body"> + <div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>docker-compose up <span class="nt">-d</span> acme-challenge +<span class="gp">$</span><span class="w"> </span>make setup</code></pre> +</div> +</div> + </div> +</section> + + + + + +<section class="section-2"> + <h3 id="" class="section-header"> + + サーバを稼動させる + + </h3> + <div class="section-body"> + <div id="source." class="listingblock"> +<div class="content"> +<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>make serve</code></pre> +</div> +</div> + </div> +</section> + </div> +</section> + + + + + +<section class="section-1"> + <h2 id="" class="section-header"> + + 感想 + + </h2> + <div class="section-body"> + <div class="paragraph"> +<p>(業務でなく) +個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。次の式年遷宮では、手順の一部だけでも自動化したいところ。</p> +</div> + </div> +</section> + </div> + </article> + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> diff --git a/public/posts/index.html b/public/posts/index.html new file mode 100644 index 0000000..029251b --- /dev/null +++ b/public/posts/index.html @@ -0,0 +1,315 @@ + + + + + + + + + + +<!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="© 2021 nsfisis"> + <meta name="description" content="記事一覧"> + <link rel="icon" type="image/svg+xml" href="/favicon.svg"> + <title>Posts | REPL: Rest-Eat-Program Loop</title> + <link rel="stylesheet" href="/hl.css"> + <link rel="stylesheet" href="/style.css"> + <link rel="stylesheet" href="/custom.css"> + </head> + <body class="list"> + <header class="header"> + <nav class="nav"> + <p class="logo"> + <a href="/">REPL: Rest-Eat-Program Loop</a> + </p> + </nav> + </header> + <main class="main"> + <header class="page-header"> + <h1>Posts</h1> + </header> + + <article class="post-entry"> + <a href="/posts/2022-10-28/setup-server-for-this-site/"> + <header class="entry-header"> + <h2>【備忘録】このサイト用の VPS をセットアップしたときのメモ</h2> + </header> + <section class="entry-content"> + <p> + GitHub Pages でホストしていたこのサイトを VPS へ移行したので、 そのときにやったことのメモ。99 % 自分用。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2022-10-28">2022-10-28</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/"> + <header class="entry-header"> + <h2>PHPerKaigi 2023: ボツになったトークン問題 その 1</h2> + </header> + <section class="entry-content"> + <p> + 来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、 ボツになった問題を公開する (その 1)。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2022-10-23">2022-10-23</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/"> + <header class="entry-header"> + <h2>【PHP】fizzbuzz を書く。1行あたり2文字で。</h2> + </header> + <section class="entry-content"> + <p> + PHP で、fizzbuzz を書いた。ただし、1行あたりに使える文字数は2文字まで。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2022-09-28">2022-09-28</time>, updated on <time datetime="2022-09-29">2022-09-29</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2022-08-31/support-for-communty-is-employee-benefits/"> + <header class="entry-header"> + <h2>弊社の PHP Foundation への寄付に寄せて</h2> + </header> + <section class="entry-content"> + <p> + 先日、私の勤めるデジタルサーカス株式会社が、PHP Foundation へ寄付をおこないました。 本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2022-08-31">2022-08-31</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2022-08-27/php-conference-okinawa-code-golf/"> + <header class="entry-header"> + <h2>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h2> + </header> + <section class="entry-content"> + <p> + PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2022-08-27">2022-08-27</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2022-05-01/phperkaigi-2022/"> + <header class="entry-header"> + <h2>PHPerKaigi 2022</h2> + </header> + <section class="entry-content"> + <p> + 2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2022-05-01">2022-05-01</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/"> + <header class="entry-header"> + <h2>term-banner: ターミナルにバナーを表示するツールを書いた</h2> + </header> + <section class="entry-content"> + <p> + ターミナルに任意の文字のバナーを表示するためのツールを Go で書いた。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2022-04-24">2022-04-24</time>, updated on <time datetime="2022-04-27">2022-04-27</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2022-04-09/phperkaigi-2022-tokens/"> + <header class="entry-header"> + <h2>PHPerKaigi 2022 トークン問題の解説</h2> + </header> + <section class="entry-content"> + <p> + PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2022-04-09">2022-04-09</time>, updated on <time datetime="2022-04-16">2022-04-16</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2021-10-02/vim-swap-order-of-selected-lines/"> + <header class="entry-header"> + <h2>Vimで選択した行の順番を入れ替える</h2> + </header> + <section class="entry-content"> + <p> + Vim で選択した行の順番を入れ替える方法。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2021-10-02">2021-10-02</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/"> + <header class="entry-header"> + <h2>【Vim】autocmd events の BufWrite/BufWritePre の違い</h2> + </header> + <section class="entry-content"> + <p> + Vim の autocmd events における BufWrite/BufWritePre がどう違うのかを調べた結果、 違いはないことがわかった。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2021-10-02">2021-10-02</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2021-10-02/rust-where-are-primitive-types-from/"> + <header class="entry-header"> + <h2>Rust のプリミティブ型はどこからやって来るか</h2> + </header> + <section class="entry-content"> + <p> + Rust のプリミティブ型は予約語ではなく普通の識別子である。 どのようにこれが名前解決されるのかを調べた。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2021-10-02">2021-10-02</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2021-10-02/ruby-then-keyword-and-case-in/"> + <header class="entry-header"> + <h2>【Ruby】then キーワードと case in</h2> + </header> + <section class="entry-content"> + <p> + Ruby 3.0 で追加される case in 構文と、then キーワードについて。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2021-10-02">2021-10-02</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2021-10-02/ruby-detect-running-implementation/"> + <header class="entry-header"> + <h2>【Ruby】自身を実行している処理系の種類を判定する</h2> + </header> + <section class="entry-content"> + <p> + Ruby には複数の実装があるが、自身を実行している処理系の種類を スクリプト上からどのように判定すればよいだろうか。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2021-10-02">2021-10-02</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2021-10-02/python-unbound-local-error/"> + <header class="entry-header"> + <h2>【Python】クロージャとUnboundLocalError: local variable 'x' referenced before assignment</h2> + </header> + <section class="entry-content"> + <p> + Python における UnboundLocalError の理由と対処法。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2021-10-02">2021-10-02</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/"> + <header class="entry-header"> + <h2>【C++】属性構文の属性名にはキーワードが使える</h2> + </header> + <section class="entry-content"> + <p> + C++ の属性構文の属性名には、キーワードが使える。ネタ記事。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2021-10-02">2021-10-02</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2021-03-30/phperkaigi-2021/"> + <header class="entry-header"> + <h2>PHPerKaigi 2021</h2> + </header> + <section class="entry-content"> + <p> + 2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2021-03-30">2021-03-30</time> + </footer> + </a> + </article> + + <article class="post-entry"> + <a href="/posts/2021-03-05/my-first-post/"> + <header class="entry-header"> + <h2>My First Post</h2> + </header> + <section class="entry-content"> + <p> + これはテスト投稿です。これはテスト投稿です。これはテスト投稿です。 + </p> + </section> + <footer class="entry-footer"> + Posted on <time datetime="2021-03-05">2021-03-05</time> + </footer> + </a> + </article> + + </main> + <footer class="footer"> + © 2021 nsfisis + </footer> + </body> +</html> |
