Tambourine作業メモ

主にスキル習得のためにやった作業のメモ。他人には基本的に無用のものです。

持て余しているStream Deckでメールの振り分けが出来るようになった

知人がStream Deckを購入して、便利につかっているようである

note.com

実は我が家にも妻がかっこよさそうだからという理由で買って持て余しているStream Deckがある。それも一番大きいサイズのXLを持て余している。持て余し方が豪快だ。

どうみても使っていないのでかっぱらってきたのだが、意外に使い道がない。

やりたいなと思っていたのが、メールの振り分け。私は未読メールを受信ボックスに溜めておいて、読んだら分類してフォルダに移す。常に受信ボックスには未読のメールと処理されてないToDoメールだけが残るようにしている。

MacのMailアプリはこのフォルダの振り分けが面倒くさい。1つずつ、マウスで選んで移していた。どうにかならないのか。でも、そもそもキーボードでこの処理が出来ないと登録出来ない。ショートカットにそういう機能がないのかなあ・・・AppleScriptだと出来るのかなあ・・・とぼんやり考えていたが、今日、この記事を見つけた。

book.mynavi.jp

ずいぶんと古い記事だ。しかし、やってみたら今でもちゃんと動く。「ショートカットキーの登録名を移動したいフォルダ名にするとそこに移動するショートカットキーになる」という仕組みが大変にキモいが、これでやりたいことが出来た。

よく使う移動先にショートカットキーを登録し、それらをぜんぶStream Deckのボタンに割り当てた。なんぜ32個もボタンがあるので、好きなだけ登録出来る・・・4つで済んだ。ぽちぽちボタンを押すだけで未読メールが処理出来る。素晴らしい。

残り28個のボタンの使い道は、引き続き募集中である。え、ページとか登録出来るの・・・する日は来るんだろうか。

WindowsにJavaをインストールする

会社から支給はされているものの、BYODしたMacを日常的に使っているので放置気味のWindowsJavaを入れてみたい。

スタートの状態では、JDKはどこにもないし、JAVA_HOMEも設定されていない。

ひとむかし前であれば、おもむろにOracleのサイトに行き、インストーラー付きのものをダウンロードして入れれば良かったのだが、いまやJavaディストリビューションは多彩だ。きしださんのブログを「きしだ Java インストール」とかでググり、好きなもののインストーラーをダウンロードして実行すれば良い。

良いのだが、この記事で出てくるwingetを試してみたい。wingetはまだ出来て何年も経っていない、Microsoft自身がやってるコマンドラインのパッケージマネージャーらしい。

まず、wingetとだけ打ってみる

PS C:\Users\tambara > winget
v1.5.2201 の Windows パッケージ マネージャー
Copyright (c) Microsoft Corporation. All rights reserved.

WinGet コマンド ライン ユーティリティを使用すると、コマンド ラインからアプリケーションやその他のパッケージをインストールできます。

使用法: winget [<コマンド>] [<オプション>]

使用できるコマンドは次のとおりです:
  install    指定されたパッケージをインストール
  show       パッケージに関する情報を表示します
  source     パッケージのソースの管理
  search     アプリの基本情報を見つけて表示
  list       インストール済みパッケージを表示する
  upgrade    利用可能なアップグレードの表示と実行
  uninstall  指定されたパッケージをアンインストール
  hash       インストーラー ファイルをハッシュするヘルパー
  validate   マニフェスト ファイルを検証
  settings   設定を開くか、管理者設定を設定する
  features   試験的な機能の状態を表示
  export     インストールされているパッケージのリストをエクスポート
  import     ファイル中のすべてのパッケージをインストール
  pin        パッケージ ピンの管理

特定のコマンドの詳細については、そのコマンドにヘルプ引数を渡します。 [-?]

次のオプションを使用できます。
  -v,--version              ツールのバージョンを表示
  --info                    ツールの一般情報を表示
  -?,--help                 選択したコマンドに関するヘルプを表示
  --wait                    終了する前に任意のキーを押すプロンプトをユーザーに表示します
  --logs,--open-logs        既定のログの場所を開く
  --verbose,--verbose-logs  WinGet の詳細ログを有効にする
  --disable-interactivity   対話型プロンプトを無効にします

その他のヘルプについては、次を参照してください: https://aka.ms/winget-command-help

どこかで見たようなサブコマンドたちである。バージョンが1未満だとプレビュー版なのでアップデートしなければならないらしいが、1.5と書いてあるので大丈夫だろう。使ってみよう。

winget listしてみると、インストール済みのソフトウェア達が表示される。これは別にwingetでインストールしたものとは限らないみたい。秀丸エディタとか出てくる。

名前                                  ID                                    バージョン          利用可能 ソース
---------------------------------------------------------------------------------------------------------------
Ubuntu                                Canonical.Ubuntu.2204                 2204.2.33.0                  winget
Dolby Access                          DolbyLaboratories.DolbyAccess_rz1teb… 3.18.872.0
Lenovo Commercial Vantage             E046963F.LenovoSettingsforEnterprise… 10.2305.30.0
ELAN TrackPoint for Thinkpad          ELANMicroelectronicsCorpo.ELANTrackP… 24.121.18.0
Git                                   Git.Git                               2.36.0              2.42.0   winget
Google Chrome                         Google.Chrome                         > 116.0.5845.111             winget
秀丸エディタ (9.13)                   Hidemaru                              9.13

こんな感じだ。Gitがリストされていて、ここでバージョンアップ出来そうな雰囲気だ。やってみよう。

PS C:\Users\tambara > winget upgrade Git.Git
見つかりました Git [Git.Git] バージョン 2.42.0
このアプリケーションは所有者からライセンス供与されます。
Microsoft はサードパーティのパッケージに対して責任を負わず、ライセンスも付与しません。
ダウンロード中 https://github.com/git-for-windows/git/releases/download/v2.42.0.windows.1/Git-2.42.0-64-bit.exe
  ██████████████████████████████  58.3 MB / 58.3 MB
インストーラーハッシュが正常に検証されました
パッケージのインストールを開始しています...
インストーラーは管理者として実行するように要求するため、プロンプトが表示されます。
インストールが完了しました

なるほど。

では、さっそくここからJDKをインストールしてみよう。

winget searh javaしてみる

関係のないものがいっぱい見つかるが、まあ、だいたいなんでもある

IBM Semeruがなくて寂しかったが、winget search semeru したらちゃんと出てきた。

では、Temurinを入れてみることにする。

PS C:\Users\tambara > winget install EclipseAdoptium.Temurin.20.JDK
見つかりました Eclipse Temurin JDK with Hotspot 20 [EclipseAdoptium.Temurin.20.JDK] バージョン 20.0.2.9
このアプリケーションは所有者からライセンス供与されます。
Microsoft はサードパーティのパッケージに対して責任を負わず、ライセンスも付与しません。
ダウンロード中 https://github.com/adoptium/temurin20-binaries/releases/download/jdk-20.0.2+9/OpenJDK20U-jdk_x64_windows_hotspot_20.0.2_9.msi
  ██████████████████████████████   166 MB /  166 MB
インストーラーハッシュが正常に検証されました
パッケージのインストールを開始しています...
インストールが完了しました

なんだ、msiがダウンロードされるのか。ただし、GUIインストーラーは表示はされるものの触る必要はなく、勝手に閉じて完了した。

無事、javaコマンドが起動した

PS C:\Users\tambara > java -version
openjdk version "20.0.2" 2023-07-18
OpenJDK Runtime Environment Temurin-20.0.2+9 (build 20.0.2+9)
OpenJDK 64-Bit Server VM Temurin-20.0.2+9 (build 20.0.2+9, mixed mode, sharing)

PATHは設定されているけど、JAVA_HOMEはないみたい

PS C:\Users\tambara > $env:PATH
C:\Program Files\PowerShell\7;C:\Program Files\Eclipse Adoptium\jdk-20.0.2.9-hotspot\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;(以下略)
PS C:\Users\tambara> $env:JAVA_HOME

では、2つ目をインストールするとどうなるか。IBM Semeruを入れてみよう。

インストール完了後、java -versionしてみる

PS C:\Users\tambara > java -version
openjdk version "17.0.7" 2023-04-18
IBM Semeru Runtime Open Edition 17.0.7.0 (build 17.0.7+7)
Eclipse OpenJ9 VM 17.0.7.0 (build openj9-0.38.0, JRE 17 Windows 11 amd64-64-Bit Compressed References 20230418_439 (JIT enabled, AOT enabled)
OpenJ9   - d57d05932
OMR      - 855813495
JCL      - 9d7a231edbc based on jdk-17.0.7+7)

変わっちゃった。

PS C:\Users\tambara > $env:PATH
C:\Program Files\PowerShell\7;C:\Program Files\Semeru\jdk-17.0.7.7-openj9\bin;C:\Program Files\Eclipse Adoptium\jdk-20.0.2.9-hotspot\bin;C:\WINDOWS\system32;C:\WINDOWS;(以下略)
PS C:\Users\318535760>

たぶん、単にPATHの順番だな。SemeruもJAVA_HOMEは設定しないようだ。

macOSにJavaをインストールする

JavamacOSで特別な扱いをされている。

インストール直後から/usr/binにjavaコマンドは存在する。が、実行するとしょーもないことを言う。

tambara@TAMBARAnoMacBook ~ % /usr/bin/java
The operation couldn’t be completed. Unable to locate a Java Runtime.
Please visit http://www.java.com for information on installing Java.

こう言われたら、Javaが入ってないかちゃんとセットアップされていない状態である。

Javaは今ではいろいろなディストリビューションから提供されているし、バージョンも様々である。かつてはJavaで動作するアプリケーションをインストールすると、それが要求するJDK/JREがセットで導入されて、アプリケーションごとに山ほどJDK/JREがインストールされているなんてことがあったものだが、そういうのはよろしくないので、特別扱いで複数のJavaがインストール出来る仕組みが用意されている。そのため、Javaがインストールされるのは/Library/Java/JavaVirtualMachinesと決められている。インストール直後から放置の私のサブマシンではここはからっぽである。

では、まず基本として、brewのcoreにあるopenjdkをインストールしてみよう。brew install javaするとopenjdkがインストールされる。今、homebrewのcoreにあるjavaはopenjdkだけ。

インストールの最後に以下の様に表示される。

==> Summary
🍺  /usr/local/Cellar/openjdk/20.0.1: 637 files, 322.5MB
==> Running `brew cleanup openjdk`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
==> Caveats
==> openjdk
For the system Java wrappers to find this JDK, symlink it with
  sudo ln -sfn /usr/local/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk

openjdk is keg-only, which means it was not symlinked into /usr/local,
because macOS provides similar software and installing this software in
parallel can cause all kinds of trouble.

If you need to have openjdk first in your PATH, run:
  echo 'export PATH="/usr/local/opt/openjdk/bin:$PATH"' >> ~/.zshrc

For compilers to find openjdk you may need to set:
  export CPPFLAGS="-I/usr/local/opt/openjdk/include"

openjdkは「keg-only」だと言っている。kegってのはビールの樽のことで、「注ぐのは自分でやってね」というコトらしい。シンボリックリンクなんかは作らないので自分でやってくれと。というわけで、

sudo ln -sfn /usr/local/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk

しろと仰せ。する。

すると、javaコマンドが動き出す。

tambara@TAMBARAnoMacBook ~ % java -version
openjdk version "20.0.1" 2023-04-18
OpenJDK Runtime Environment Homebrew (build 20.0.1)
OpenJDK 64-Bit Server VM Homebrew (build 20.0.1, mixed mode, sharing)

/Library/Java/JavaVirturalMachines以下に1つしかJDKがないと、そのままそれを使ってくれる。PATHをセットする必要はない。このJavaは/usr/bin/javaだと認識されている。

tambara@TAMBARAnoMacBook ~ % which java
/usr/bin/java

また、今はだいぶ必要性が失われているが、かつてはJAVA_HOMEという環境変数が必要なことも多かった。今、何もしていないのでJAVA_HOMEは定義されていないが、定義したければ/usr/libexec/java_homeというコマンドが用意されているので、この出力がJAVA_HOMEに入るようにすればよい。-Vで今、システムに認識されているJDKを一覧してくれる。

tambara@TAMBARAnoMacBook ~ % /usr/libexec/java_home     
/usr/local/Cellar/openjdk/20.0.1/libexec/openjdk.jdk/Contents/Home
tambara@TAMBARAnoMacBook ~ % /usr/libexec/java_home -V
Matching Java Virtual Machines (1):
    20.0.1 (x86_64) "Homebrew" - "OpenJDK 20.0.1" /usr/local/Cellar/openjdk/20.0.1/libexec/openjdk.jdk/Contents/Home
/usr/local/Cellar/openjdk/20.0.1/libexec/openjdk.jdk/Contents/Home

さて、別のJDKを入れてみよう。変わっているところで、IBM Semeru Runtimeを入れてみよう。これはかつて別のところで提供されていたIBMのOpenJ9というJVMだ。IBMの製品に添付されているJVMなので、作ったアプリがWebSphereで動く予定なら使ってみてもいいかもしれない。

https://developer.ibm.com/languages/java/semeru-runtimes/downloads/

に行き、適切なバージョンをダウンロードしよう。今度は最新のLTSであるJava17を入れてみることにする。

IBM Semeru Runtimeのインストール

java_homeコマンドを実行してみよう。

tambara@TAMBARAnoMacBook ~ % /usr/libexec/java_home -V
Matching Java Virtual Machines (2):
    20.0.1 (x86_64) "Homebrew" - "OpenJDK 20.0.1" /usr/local/Cellar/openjdk/20.0.1/libexec/openjdk.jdk/Contents/Home
    17.0.8 (x86_64) "IBM Corporation" - "IBM Semeru Runtime Open Edition 17" /Library/Java/JavaVirtualMachines/ibm-semeru-open-17.jdk/Contents/Home
/usr/local/Cellar/openjdk/20.0.1/libexec/openjdk.jdk/Contents/Home

増えている。

java_homeコマンドに-vとバージョンを指定すると、JAVA_HOMEに指定するべきパスが変わる。

tambara@TAMBARAnoMacBook ~ % /usr/libexec/java_home -v 17.0.8
/Library/Java/JavaVirtualMachines/ibm-semeru-open-17.jdk/Contents/Home

これをJAVA_HOMEにセットしてやると、/usr/bin/javaの動きが変わる。

tambara@TAMBARAnoMacBook ~ % export JAVA_HOME=`/usr/libexec/java_home -v 17.0.8`
tambara@TAMBARAnoMacBook ~ % echo $JAVA_HOME
/Library/Java/JavaVirtualMachines/ibm-semeru-open-17.jdk/Contents/Home
tambara@TAMBARAnoMacBook ~ % java --version
openjdk 17.0.8 2023-07-18
IBM Semeru Runtime Open Edition 17.0.8.0 (build 17.0.8+7)
Eclipse OpenJ9 VM 17.0.8.0 (build openj9-0.40.0, JRE 17 Mac OS X amd64-64-Bit Compressed References 20230718_503 (JIT enabled, AOT enabled)
OpenJ9   - d12d10c9e
OMR      - e80bff83b
JCL      - 77b0f754805 based on jdk-17.0.8+7)

Ubuntu 23.04をインストールしてみる

手元にWindowsマシンが2台あって、1台は仕事場モニターのすぐ脇にあるモニターに繋がっている。もう1台は、ScanSnapの横においてある。

仕事場モニターのすぐ横のマシンは、会社PCでは出来ないような実験をするためにあって、ScanSnapの横のマシンは当然、自炊PDFを作るためにある(ScanSnapとUSBで繋がっている)。

しかし、普段使っていてわかったのは、仕事場モニターのすぐ横に置いてあったとしてもそのマシンを触る度にそのマシンに繋がっているキーボードとマウスを手元に持ってくるのは面倒で、仕事マシンからリモートデスクトップで繋いで使った方が便利だということ。で、ScanSnap用PCも、スキャンしているときはScanSnapの側においたモニターに繋いで扱った方が便利なんだけども、スキャンしたPDFの編集やチェックはリモートデスクトップで繋いた方が便利だということ。とにかく、リモートデスクトップはすごく便利。

もうひとつ、調子が悪くなった先代のScanSnap用PC(CPUはHaswellだった年代物)の代わりに導入したminisforum GK41は3万円以下で買えるくせにWindows11がサックサクで動いてとても素晴らしいんだけども、なんとScanSnapのスキャン画像の取り込みが遅かった・・・。Scan Snap iX1400は毎分40枚読み込めるすごいスキャナなんだけども、ScanSnapが読み終えてもPC側がそれを認識し終わるまでに3倍ぐらいの時間がかかってた。ヘタすれば先代より遅い・・・なぜ?確かにGK41に積んでいるCeleron J4125の能力はしょっぱいけども、Haswell世代より全然マシのはずなのに・・・GPUを結構使ってたりするのかな?

というわけで、実験用PCをScanSnapの側に移動し、ScanSnap関係のドライバといきなりPDFをインストールした。自炊の効率がすごく上がった。

余ったCeleron J4125マシンには、久しぶりにLinuxをインストールしてみることにした。大学院生の頃はThinkpad 240にKondara MNU/Linuxというすっとぼけた日本産ディストリビューションを入れてEmacsgnuplotRubyLaTeX修士論文を書いていたが、実にそれ以来のデスクトップLinuxである。ちなみに、Rubyはあれからずっと使っているが、Emacsを捨ててVim派になったし(仕事でEmacsがないUnixサーバにログインすることがちょいちょいあるので、Vi遣いに転向した)、gnuplotも(そもそもグラフを滅多に作らないなあ)、LaTeXも(CSSがあればHTMLで何でもできるからなあ)、卒業してから一度も触ってない。

もちろん、仕事でLinuxサーバを構築をしたことがまったく無いわけではないんだけども真面目に管理者をやったことは実はないし(私の勤めている会社は、商用のUNIXを売っているのだ)、普段使いのUnixとしてはmacOSはとても快適だ。

とはいえ、デスクトップLinuxのエコシステムをまったく知らないのも恥ずかしい。私用をカンタンにこなせる環境をサクッと作ってみようと思う。次に考えるのは、ディストリビューションなんだけども、完全にド素人なので素直にubuntuにする。仕事と絡めるならRPM系がいいんだろうし、Arch LinuxGentoo Linuxのような玄人好みのディストリビューションに憧れもある・・・が、その辺に楽しくハマる時間はないのである。せめて、LTSである22.04.3ではなく、Lastestである23.04にしておこう。

さて、どうやってインストールするのか。インストールメディアをUSBメモリに入れ、USBからブートさせればよいのだろう。そこまではわかるが、具体的な手法はよくわからない。検索すると

  1. isoイメージをダウンロードし、rufusというWindowsのツールがあるのでそれでUSBへ書き込めばよい
  2. Windowsの設定にシステム > 回復 > 復元 で起動ドライブを選べる(この設定項目の意図としては、Windowsのインストールメディアパーティションからブートさせてシステムの再インストールをするものみたい)

ということがわかった。1つ目は特に問題が無かったんだけども、2つ目の方は初めての体験だった。オールドスクーラーとしては、PCを起動してBIOSメニューに入れさえすればブートドライブを変更することは出来るんだけど、たいていPCごとにBIOSメニューに入る方法が違うので戸惑うことになる。それをUEFIの時代はやらなくていいわけだ(Windowsがすでにインストールされているならば、だけど)。えらい。というわけで試してみたんだけど、USBドライブから起動することは出来なかった。上手く動かずにWindowsが上がってきちゃう。ただ、このメニューからPC再起動直後にBIOSメニューに入ることは出来たので、結局、いつものようにブート設定を変えてインストールできた。BIOSメニュー起動方法は結局知らずに出来たので、進歩と言えば進歩なのかな?

USBからブートしてしまえば、あとのインストールは何も迷うことはないので省略。あ、そうでもなかったかも。以下の点が気になった。まあ、そのぐらい

  • 標準じゃなくてJapanese Remixのisoを使った。そういうものがあるのなら、乗っかっておくべきだろう
  • ディスクのパーティション設定がよくわからなかった。付いてるSSD全体を1パーティションでやってくれて構わないんで「ディスクを削除」みたいな奴を選んでみた。具体的にどういう設定になったのかは、後で確かめてみないとよくわからない。swapとかどうなるんだろう。そもそも、今でもswapパーティションが今でも必要なのかもよく知らない。
  • ファイルシステムを選べるところがあって、LVMとZFSを選ぶところがあったので、LVMにチェックをいれてみた。しかし、LVMはファイルシステムでは無いと思う。何がどうなっているのかはあとで確かめたいし、LVMが使えるのなら、後でUSBハードディスクを挿してPV作ったりして遊んでみたい。

Jekyllで遊んでみる

自分のパソコンのホームディレクトリには、これまでいじったいろんなソフトウェアの自作チートシートや有用なリンク集を集めたメモがある。

これらは古くはRDで書いてあって、どこかのタイミングでMarkdownで書き直した。ちまちまと書きためていて、rakeコマンドでHTMLファイルを生成出来るようにしてある。しかし、見たいタイミングでrakeで最新化するのは面倒くさいので、ついついMarkdownのまま見てしまったりする。

こういうもののHTML生成は、現代的には静的サイトジェネレーターを使うのが正しいらしい。というわけで、Rubyで作られた静的サイトジェネレーターでGithub Pagesの中の人であるJekyllをいじってみることにする。

いつもの通り、gemとbundlerでインストールは出来てしまう。

> gem install bundler jekyll
Fetching bundler-2.4.13.gem
Successfully installed bundler-2.4.13
Parsing documentation for bundler-2.4.13
Installing ri documentation for bundler-2.4.13
Done installing documentation for bundler after 0 seconds
Fetching forwardable-extended-2.6.0.gem
Fetching safe_yaml-1.0.5.gem
Fetching terminal-table-3.0.2.gem
Fetching pathutil-0.16.2.gem
Fetching liquid-4.0.4.gem
Fetching kramdown-2.4.0.gem
Fetching unicode-display_width-2.4.2.gem
Fetching mercenary-0.4.0.gem
Fetching kramdown-parser-gfm-1.1.0.gem
Fetching ffi-1.15.5.gem
Fetching rb-inotify-0.10.1.gem
Fetching rb-fsevent-0.11.2.gem
Fetching listen-3.8.0.gem
Fetching jekyll-watch-2.2.1.gem
Fetching google-protobuf-3.23.2-arm64-darwin.gem
Fetching sass-embedded-1.62.1-arm64-darwin.gem
Fetching jekyll-sass-converter-3.0.0.gem
Fetching concurrent-ruby-1.2.2.gem
Fetching i18n-1.13.0.gem
Fetching http_parser.rb-0.8.0.gem
Fetching eventmachine-1.2.7.gem
Fetching em-websocket-0.5.3.gem
Fetching colorator-1.1.0.gem
Fetching public_suffix-5.0.1.gem
Fetching jekyll-4.3.2.gem
Fetching addressable-2.8.4.gem
Successfully installed unicode-display_width-2.4.2
Successfully installed terminal-table-3.0.2
Successfully installed safe_yaml-1.0.5
Successfully installed forwardable-extended-2.6.0
Successfully installed pathutil-0.16.2
Successfully installed mercenary-0.4.0
Successfully installed liquid-4.0.4
Successfully installed kramdown-2.4.0
Successfully installed kramdown-parser-gfm-1.1.0
Building native extensions. This could take a while...
Successfully installed ffi-1.15.5
Successfully installed rb-inotify-0.10.1
Successfully installed rb-fsevent-0.11.2
Successfully installed listen-3.8.0
Successfully installed jekyll-watch-2.2.1
Successfully installed google-protobuf-3.23.2-arm64-darwin
Successfully installed sass-embedded-1.62.1-arm64-darwin
Successfully installed jekyll-sass-converter-3.0.0
Successfully installed concurrent-ruby-1.2.2
Successfully installed i18n-1.13.0
Building native extensions. This could take a while...
Successfully installed http_parser.rb-0.8.0
Building native extensions. This could take a while...
Successfully installed eventmachine-1.2.7
Successfully installed em-websocket-0.5.3
Successfully installed colorator-1.1.0
Successfully installed public_suffix-5.0.1
Successfully installed addressable-2.8.4
Successfully installed jekyll-4.3.2
Parsing documentation for unicode-display_width-2.4.2
Installing ri documentation for unicode-display_width-2.4.2
Parsing documentation for terminal-table-3.0.2
Installing ri documentation for terminal-table-3.0.2
Parsing documentation for safe_yaml-1.0.5
Installing ri documentation for safe_yaml-1.0.5
Parsing documentation for forwardable-extended-2.6.0
Installing ri documentation for forwardable-extended-2.6.0
Parsing documentation for pathutil-0.16.2
Installing ri documentation for pathutil-0.16.2
Parsing documentation for mercenary-0.4.0
Installing ri documentation for mercenary-0.4.0
Parsing documentation for liquid-4.0.4
Installing ri documentation for liquid-4.0.4
Parsing documentation for kramdown-2.4.0
Installing ri documentation for kramdown-2.4.0
Parsing documentation for kramdown-parser-gfm-1.1.0
Installing ri documentation for kramdown-parser-gfm-1.1.0
Parsing documentation for ffi-1.15.5
Installing ri documentation for ffi-1.15.5
Parsing documentation for rb-inotify-0.10.1
Installing ri documentation for rb-inotify-0.10.1
Parsing documentation for rb-fsevent-0.11.2
Installing ri documentation for rb-fsevent-0.11.2
Parsing documentation for listen-3.8.0
Installing ri documentation for listen-3.8.0
Parsing documentation for jekyll-watch-2.2.1
Installing ri documentation for jekyll-watch-2.2.1
Parsing documentation for google-protobuf-3.23.2-arm64-darwin
Installing ri documentation for google-protobuf-3.23.2-arm64-darwin
Parsing documentation for sass-embedded-1.62.1-arm64-darwin
Installing ri documentation for sass-embedded-1.62.1-arm64-darwin
Parsing documentation for jekyll-sass-converter-3.0.0
Installing ri documentation for jekyll-sass-converter-3.0.0
Parsing documentation for concurrent-ruby-1.2.2
Installing ri documentation for concurrent-ruby-1.2.2
Parsing documentation for i18n-1.13.0
Installing ri documentation for i18n-1.13.0
Parsing documentation for http_parser.rb-0.8.0
unknown encoding name "chunked\r\n\r\n25" for ext/ruby_http_parser/vendor/http-parser-java/tools/parse_tests.rb, skipping
Installing ri documentation for http_parser.rb-0.8.0
Parsing documentation for eventmachine-1.2.7
Installing ri documentation for eventmachine-1.2.7
Parsing documentation for em-websocket-0.5.3
Installing ri documentation for em-websocket-0.5.3
Parsing documentation for colorator-1.1.0
Installing ri documentation for colorator-1.1.0
Parsing documentation for public_suffix-5.0.1
Installing ri documentation for public_suffix-5.0.1
Parsing documentation for addressable-2.8.4
Installing ri documentation for addressable-2.8.4
Parsing documentation for jekyll-4.3.2
Installing ri documentation for jekyll-4.3.2
Done installing documentation for unicode-display_width, terminal-table, safe_yaml, forwardable-extended, pathutil, mercenary, liquid, kramdown, kramdown-parser-gfm, ffi, rb-inotify, rb-fsevent, listen, jekyll-watch, google-protobuf, sass-embedded, jekyll-sass-converter, concurrent-ruby, i18n, http_parser.rb, eventmachine, em-websocket, colorator, public_suffix, addressable, jekyll after 6 seconds
27 gems installed

> jekyll new manuals
Running bundle install in /Users/tambara/manuals... 
  Bundler: Fetching gem metadata from https://rubygems.org/............
  Bundler: Resolving dependencies...
  Bundler: Using bundler 2.4.13
  Bundler: Using eventmachine 1.2.7
  Bundler: Using http_parser.rb 0.8.0
  Bundler: Using ffi 1.15.5
  Bundler: Using forwardable-extended 2.6.0
  Bundler: Using rexml 3.2.5
  Bundler: Using liquid 4.0.4
  Bundler: Using mercenary 0.4.0
  Bundler: Using unicode-display_width 2.4.2
  Bundler: Using public_suffix 5.0.1
  Bundler: Using colorator 1.1.0
  Bundler: Using addressable 2.8.4
  Bundler: Using em-websocket 0.5.3
  Bundler: Using rb-inotify 0.10.1
  Bundler: Using kramdown 2.4.0
  Bundler: Using concurrent-ruby 1.2.2
  Bundler: Using terminal-table 3.0.2
  Bundler: Using google-protobuf 3.23.2 (arm64-darwin)
  Bundler: Using rb-fsevent 0.11.2
  Bundler: Using rouge 4.1.1
  Bundler: Using safe_yaml 1.0.5
  Bundler: Using webrick 1.8.1
  Bundler: Using pathutil 0.16.2
  Bundler: Using i18n 1.13.0
  Bundler: Using sass-embedded 1.62.1 (arm64-darwin)
  Bundler: Using listen 3.8.0
  Bundler: Using kramdown-parser-gfm 1.1.0
  Bundler: Using jekyll-sass-converter 3.0.0
  Bundler: Using jekyll-watch 2.2.1
  Bundler: Using jekyll 4.3.2
  Bundler: Fetching jekyll-feed 0.17.0
  Bundler: Fetching jekyll-seo-tag 2.8.0
  Bundler: Installing jekyll-feed 0.17.0
  Bundler: Installing jekyll-seo-tag 2.8.0
  Bundler: Fetching minima 2.5.1
  Bundler: Installing minima 2.5.1
  Bundler: Bundle complete! 7 Gemfile dependencies, 33 gems now installed.
  Bundler: Use `bundle info [gemname]` to see where a bundled gem is installed.
New jekyll site installed in /Users/tambara/manuals. 

> cd manuals

> bundle exec jekyll serve
Configuration file: /Users/tambara/manuals/_config.yml
            Source: /Users/tambara/manuals
       Destination: /Users/tambara/manuals/_site
 Incremental build: disabled. Enable with --incremental
      Generating... 
       Jekyll Feed: Generating feed for posts
Deprecation Warning: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.

Recommendation: math.div($spacing-unit, 2) or calc($spacing-unit / 2)

More info and automated migrator: https://sass-lang.com/d/slash-div

   ╷
40 │   margin-bottom: $spacing-unit / 2;
   │                  ^^^^^^^^^^^^^^^^^
   ╵
    ../../../../minima-2.5.1/_sass/minima/_base.scss 40:18  @import
    minima.scss 48:3                                        @import
    /Users/tambara/manuals/assets/main.scss 1:9             root stylesheet
Deprecation Warning: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.

Recommendation: math.div($spacing-unit, 2) or calc($spacing-unit / 2)

More info and automated migrator: https://sass-lang.com/d/slash-div

    ╷
134 │   padding-left: $spacing-unit / 2;
    │                 ^^^^^^^^^^^^^^^^^
    ╵
    ../../../../minima-2.5.1/_sass/minima/_base.scss 134:17  @import
    minima.scss 48:3                                         @import
    /Users/tambara/manuals/assets/main.scss 1:9              root stylesheet
Deprecation Warning: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.

Recommendation: math.div($spacing-unit, 2) or calc($spacing-unit / 2)

More info and automated migrator: https://sass-lang.com/d/slash-div

    ╷
189 │     padding-right: $spacing-unit / 2;
    │                    ^^^^^^^^^^^^^^^^^
    ╵
    ../../../../minima-2.5.1/_sass/minima/_base.scss 189:20  @content
    minima.scss 38:5                                         media-query()
    ../../../../minima-2.5.1/_sass/minima/_base.scss 186:3   @import
    minima.scss 48:3                                         @import
    /Users/tambara/manuals/assets/main.scss 1:9              root stylesheet
Deprecation Warning: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.

Recommendation: math.div($spacing-unit, 2) or calc($spacing-unit / 2)

More info and automated migrator: https://sass-lang.com/d/slash-div

    ╷
190 │     padding-left: $spacing-unit / 2;
    │                   ^^^^^^^^^^^^^^^^^
    ╵
    ../../../../minima-2.5.1/_sass/minima/_base.scss 190:19  @content
    minima.scss 38:5                                         media-query()
    ../../../../minima-2.5.1/_sass/minima/_base.scss 186:3   @import
    minima.scss 48:3                                         @import
    /Users/tambara/manuals/assets/main.scss 1:9              root stylesheet
Deprecation Warning: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.

Recommendation: math.div($spacing-unit, 3) or calc($spacing-unit / 3)

More info and automated migrator: https://sass-lang.com/d/slash-div

    ╷
244 │     padding: ($spacing-unit / 3) ($spacing-unit / 2);
    │               ^^^^^^^^^^^^^^^^^
    ╵
    ../../../../minima-2.5.1/_sass/minima/_base.scss 244:15  @import
    minima.scss 48:3                                         @import
    /Users/tambara/manuals/assets/main.scss 1:9              root stylesheet
Warning: 6 repetitive deprecation warnings omitted.
Run in verbose mode to see all warnings.
                    done in 7.24 seconds.
 Auto-regeneration: enabled for '/Users/tambara/manuals'
    Server address: http://127.0.0.1:4000/
  Server running... press ctrl-c to stop.

なんかいっぱいWarningは出ているのだが、画面は出るのでインストールはこれで良いらしい。

作られたディレクトリの中を見ると、すごくシンプルだ。

> ls -l
total 48
-rw-r--r--@ 1 tambara  staff   419  5 27 21:28 404.html
-rw-r--r--@ 1 tambara  staff  1309  5 27 21:28 Gemfile
-rw-r--r--  1 tambara  staff  2052  5 27 21:29 Gemfile.lock
-rw-r--r--@ 1 tambara  staff  2079  5 27 21:28 _config.yml
drwxr-xr-x  3 tambara  staff    96  5 27 21:28 _posts/
drwxr-xr-x  9 tambara  staff   288  6 22 23:13 _site/
-rw-r--r--@ 1 tambara  staff   539  5 27 21:28 about.markdown
-rw-r--r--@ 1 tambara  staff   175  5 27 21:28 index.markdown

_siteに作られたhtmlファイルが格納される。さっき表示されたページの元ネタはindex.markdownだが、このファイルの中身はこれしかない。

---
# Feel free to add content and custom Front Matter to this file.
# To modify the layout, see https://jekyllrb.com/docs/themes/#overriding-theme-defaults

layout: home
---

このファイルに書いてあるURLをみると、どうやらこういうことらしい。

  • 普通はテンプレートファイルを作って、それを元に表示をする。
  • しかし、今のJekyllはnewした段階でminimaというgemで提供されているデフォルトテーマを使う。これがGemfileに指定されている。
  • 本来は_layoutというディレクトリを作ってそこにテンプレートを入れて作っていくんだけど、出来合のものがgemに入っているので何にもないのに動いているように見える
  • このテーマを使い続けるなら、コンテンツを_postsというディレクトリに置いていけばブログ風のサイトが出来る

なるほど。しかし、作りたいのはblogじゃないんだわ。

というわけで、このドキュメントを読んでいく。

ローカルに久しぶりにtDiaryをインストールしてみる

tdiary-core/INSTALL-rack.md at master · tdiary/tdiary-core · GitHub を読んで、そのままやってみる。

> gem install tdiary
Fetching webrick-1.8.1.gem
Fetching thor-1.2.2.gem
Fetching rack-3.0.7.gem
Fetching mail-2.8.1.gem
Fetching hikidoc-0.1.0.gem
Fetching mini_mime-1.1.2.gem
Fetching emot-0.0.4.gem
Fetching fastimage-2.2.6.gem
Fetching tdiary-5.2.4.gem
Successfully installed webrick-1.8.1
Successfully installed thor-1.2.2
Successfully installed rack-3.0.7
Successfully installed mini_mime-1.1.2
Successfully installed mail-2.8.1
Successfully installed hikidoc-0.1.0
Successfully installed fastimage-2.2.6
Successfully installed emot-0.0.4
Successfully installed tdiary-5.2.4
Parsing documentation for webrick-1.8.1
Installing ri documentation for webrick-1.8.1
Parsing documentation for thor-1.2.2
Installing ri documentation for thor-1.2.2
Parsing documentation for rack-3.0.7
Installing ri documentation for rack-3.0.7
Parsing documentation for mini_mime-1.1.2
Installing ri documentation for mini_mime-1.1.2
Parsing documentation for mail-2.8.1
Installing ri documentation for mail-2.8.1
Parsing documentation for hikidoc-0.1.0
Installing ri documentation for hikidoc-0.1.0
Parsing documentation for fastimage-2.2.6
Installing ri documentation for fastimage-2.2.6
Parsing documentation for emot-0.0.4
Installing ri documentation for emot-0.0.4
Parsing documentation for tdiary-5.2.4
Installing ri documentation for tdiary-5.2.4
Done installing documentation for webrick, thor, rack, mini_mime, mail, hikidoc, fastimage, emot, tdiary after 6 seconds
9 gems installed

しんぷる

> tdiary version
tdiary 5.2.4

大昔のバージョンしか知らないので、CLIがあるのが驚き。

> tdiary new diary
      create  diary
      create  diary/public
      create  diary/misc/plugin
      create  diary/lib/tdiary/filter
      create  diary/lib/tdiary/style
      create  diary/js
      create  diary/theme
      create  diary/README.md
      create  diary/Gemfile
      create  diary/Gemfile.lock
      create  diary/config.ru
      create  diary/tdiary.conf.beginner
      create  diary/tdiary.conf.sample
      create  diary/tdiary.conf.sample-en
      create  diary/doc
      create  diary/doc/HOWTO-authenticate-in-rack.md
      create  diary/doc/HOWTO-make-io.md
      create  diary/doc/HOWTO-make-plugin.md
      create  diary/doc/HOWTO-make-theme.md
      create  diary/doc/HOWTO-testing-tDiary.md
      create  diary/doc/HOWTO-use-plugin.md
      create  diary/doc/HOWTO-write-tDiary.en.md
      create  diary/doc/HOWTO-write-tDiary.md
      create  diary/doc/INSTALL-cgi.md
      create  diary/doc/INSTALL-paas.md
      create  diary/doc/INSTALL-rack.md
      create  diary/doc/INSTALL.md
      create  diary/doc/README.en.md
      create  diary/doc/README.md
      create  diary/doc/UPGRADE.md
      create  diary/doc/doc.css
      create  diary/tdiary.conf
      create  diary/Gemfile.local
[DEPRECATED] `Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env` (called at /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/tdiary-5.2.4/lib/tdiary/cli.rb:23)
         run  bundle install --without test development from "./diary"
[DEPRECATED] The `--without` flag is deprecated because it relies on being remembered across bundler invocations, which bundler will no longer do in future versions. Instead please use `bundle config set --local without 'test development'`, and stop using this flag
Bundler 2.4.13 is running, but your lockfile was generated with 2.3.7. Installing Bundler 2.3.7 and restarting using that version.
Fetching gem metadata from https://rubygems.org/.
Fetching bundler 2.3.7
Installing bundler 2.3.7
[DEPRECATED] The `--without` flag is deprecated because it relies on being remembered across bundler invocations, which bundler will no longer do in future versions. Instead please use `bundle config set --local without 'test development'`, and stop using this flag
Fetching gem metadata from https://rubygems.org/...........
Resolving dependencies...
Using rake 13.0.6
Using bundler 2.3.7
Using rexml 3.2.5
Fetching thor 1.2.1
Using hikidoc 0.1.0
Using mini_mime 1.1.2
Fetching timeout 0.3.0
Fetching rack 3.0.1
Using fastimage 2.2.6
Fetching webrick 1.7.0
Fetching mail 2.7.1
Installing timeout 0.3.0
Fetching net-protocol 0.1.3
Installing thor 1.2.1
Installing webrick 1.7.0
Using emot 0.0.4
Installing net-protocol 0.1.3
Installing rack 3.0.1
Using net-smtp 0.3.3
Installing mail 2.7.1
Fetching rackup 0.2.3
Using tdiary 5.2.4
Installing rackup 0.2.3
Bundle complete! 28 Gemfile dependencies, 16 gems now installed.
Gems in the groups 'test' and 'development' were not installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
         run  bundle exec tdiary htpasswd from "./diary"
Input your username/password
Username: tambara
New password: 
Re-type new password: 
install finished
run `tdiary server` in diary directory to start server

サーバを起動してみる

> bundle exec tdiary server
/Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/rack-3.0.1/lib/rack/file.rb:5: warning: Rack::File is deprecated and will be removed in Rack 3.1
[2023-05-20 09:51:17] INFO  WEBrick 1.7.0
[2023-05-20 09:51:17] INFO  ruby 3.2.2 (2023-03-30) [arm64-darwin22]
[2023-05-20 09:51:17] INFO  WEBrick::HTTPServer#start: pid=12696 port=19292

あがった。localhost:19292にアクセスしてみよう。

Rack::Lint::LintError: uppercase character in header name: Content-Type (Rack::Lint::LintError)
    /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/rack-3.0.1/lib/rack/lint.rb:653:in `block in check_headers'
    /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/rack-3.0.1/lib/rack/lint.rb:637:in `each'
    /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/rack-3.0.1/lib/rack/lint.rb:637:in `check_headers'
    /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/rack-3.0.1/lib/rack/lint.rb:73:in `response'
    /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/rack-3.0.1/lib/rack/lint.rb:35:in `call'
    /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/rack-3.0.1/lib/rack/show_exceptions.rb:27:in `call'
    /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/rack-3.0.1/lib/rack/common_logger.rb:43:in `call'
    /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/rack-3.0.1/lib/rack/content_length.rb:20:in `call'
    /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/rackup-0.2.3/lib/rackup/handler/webrick.rb:94:in `service'
    /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/webrick-1.7.0/lib/webrick/httpserver.rb:140:in `service'
    /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/webrick-1.7.0/lib/webrick/httpserver.rb:96:in `run'
    /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/webrick-1.7.0/lib/webrick/server.rb:310:in `block in start_thread'
127.0.0.1 - - [20/May/2023:09:53:01 +0900] "GET / HTTP/1.1" 500 40600 0.0290
127.0.0.1 - - [20/May/2023:09:53:01 JST] "GET / HTTP/1.1" 500 40600
- -> /

あら?

というわけで、動かない。調べるか・・・

とりあえず、この設定だとマシンの外部からアクセス出来てしまう。ローカルでだけ使いたい。

cli.rbをみると、serverコマンドにオプションを付ければ良さそうだ。

(前略)
        desc "server", "Start tDiary server"
        method_option "rack", type: :string, banner:
            "start server with rack interface (default)"
        method_option "cgi", type: :string, banner:
            "start server with cgi interface"
        method_option "bind", aliases: "b", type: :string, default: "0.0.0.0", banner:
            "bind to the IP"
        method_option "port", aliases: "p", type: :numeric, default: 19292, banner:
            "use PORT"
        method_option "log", aliases: "l", type: :string, banner:
            "File to redirect output"
        def server
(後略)

オプションbらしい。-bの形で指定すればいいのかな?

> bundle exec tdiary server -b localhost
/Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/rack-3.0.1/lib/rack/file.rb:5: warning: Rack::File is deprecated and will be removed in Rack 3.1
[2023-05-20 11:42:10] INFO  WEBrick 1.7.0
[2023-05-20 11:42:10] INFO  ruby 3.2.2 (2023-03-30) [arm64-darwin22]
[2023-05-20 11:42:10] INFO  WEBrick::HTTPServer#start: pid=14501 port=19292

見た目変わらないが、これでLAN上の別のマシンからはアクセス出来なくなったのでOKっぽい。

さて、エラーの原因だけども、

Rack::Lint::LintError: uppercase character in header name: Content-Type (Rack::Lint::LintError)

と言われていて、ググった感じだとRackの3.0.0からレスポンスヘッダは小文字じゃないとダメみたい。HTTP ヘッダの大文字小文字がはどちらでもいいという認識だったけど、最近、変わったのだろうか。

さらに検索してみると、そのもののPRが見つかった。

Rack 3 で動かない箇所を直しました by hsbt · Pull Request #1068 · tdiary/tdiary-core · GitHub

これは5.2.4に含まれている問題みたい。 tDiary-5.2.4 リリース - tDiary.org

にも、動かなかったら5.2.3を使ってくれと書いてある。はーい。

> gem uninstall tdiary
Remove executables:
    tdiary

in addition to the gem? [Yn]  Y
Removing tdiary
Successfully uninstalled tdiary-5.2.4

> gem install tdiary -v 5.2.3
Fetching tdiary-5.2.3.gem
Successfully installed tdiary-5.2.3
Parsing documentation for tdiary-5.2.3
Installing ri documentation for tdiary-5.2.3
Done installing documentation for tdiary after 0 seconds
1 gem installed

今度は~lib/tdiaryで作ることにする。

> tdiary new lib/tdiary
      create  lib/tdiary
      create  lib/tdiary/public
      create  lib/tdiary/misc/plugin
      create  lib/tdiary/lib/tdiary/filter
      create  lib/tdiary/lib/tdiary/style
      create  lib/tdiary/js
      create  lib/tdiary/theme
      create  lib/tdiary/README.md
      create  lib/tdiary/Gemfile
      create  lib/tdiary/Gemfile.lock
      create  lib/tdiary/config.ru
      create  lib/tdiary/tdiary.conf.beginner
      create  lib/tdiary/tdiary.conf.sample
      create  lib/tdiary/tdiary.conf.sample-en
      create  lib/tdiary/doc
      create  lib/tdiary/doc/HOWTO-authenticate-in-rack.md
      create  lib/tdiary/doc/HOWTO-make-io.md
      create  lib/tdiary/doc/HOWTO-make-plugin.md
      create  lib/tdiary/doc/HOWTO-make-theme.md
      create  lib/tdiary/doc/HOWTO-testing-tDiary.md
      create  lib/tdiary/doc/HOWTO-use-plugin.md
      create  lib/tdiary/doc/HOWTO-write-tDiary.en.md
      create  lib/tdiary/doc/HOWTO-write-tDiary.md
      create  lib/tdiary/doc/INSTALL-cgi.md
      create  lib/tdiary/doc/INSTALL-paas.md
      create  lib/tdiary/doc/INSTALL-rack.md
      create  lib/tdiary/doc/INSTALL.md
      create  lib/tdiary/doc/README.en.md
      create  lib/tdiary/doc/README.md
      create  lib/tdiary/doc/UPGRADE.md
      create  lib/tdiary/doc/doc.css
      create  lib/tdiary/tdiary.conf
      create  lib/tdiary/Gemfile.local
[DEPRECATED] `Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env` (called at /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/tdiary-5.2.3/lib/tdiary/cli.rb:23)
         run  bundle install --without test development from "./lib/tdiary"
[DEPRECATED] The `--without` flag is deprecated because it relies on being remembered across bundler invocations, which bundler will no longer do in future versions. Instead please use `bundle config set --local without 'test development'`, and stop using this flag
Fetching gem metadata from https://rubygems.org/...........
Resolving dependencies...
Using rake 13.0.6
Using bundler 2.3.7
Fetching digest 3.1.0
Using thor 1.2.1
Using fastimage 2.2.6
Using hikidoc 0.1.0
Using mini_mime 1.1.2
Using timeout 0.3.0
Using webrick 1.7.0
Using rexml 3.2.5
Fetching rack 2.2.4
Using emot 0.0.4
Using mail 2.7.1
Using net-protocol 0.1.3
Installing digest 3.1.0 with native extensions
Installing rack 2.2.4
Fetching tdiary 5.2.4
Installing tdiary 5.2.4
Fetching net-smtp 0.3.1
Installing net-smtp 0.3.1
Bundle complete! 27 Gemfile dependencies, 16 gems now installed.
Gems in the groups 'test' and 'development' were not installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
         run  bundle exec tdiary htpasswd from "./lib/tdiary"
Input your username/password
Username: tambara
New password: 
Re-type new password: 
install finished
run `tdiary server` in lib/tdiary directory to start server

あ、あれ?tdiary 5.2.4がインストールされちゃった。

> bundle exec tdiary server -b localhost
bundler: failed to load command: tdiary (/Users/tambara/.rbenv/versions/3.2.2/bin/tdiary)
/Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/tdiary-5.2.4/lib/tdiary/cli.rb:129:in `server': uninitialized constant Rackup (NameError)

                ::Rackup::Server.start( opts )
                        ^^^^^^^^
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/thor-1.2.1/lib/thor/command.rb:27:in `run'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/thor-1.2.1/lib/thor/invocation.rb:127:in `invoke_command'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/thor-1.2.1/lib/thor.rb:392:in `dispatch'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/thor-1.2.1/lib/thor/base.rb:485:in `start'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/tdiary-5.2.4/bin/tdiary:7:in `<top (required)>'
    from /Users/tambara/.rbenv/versions/3.2.2/bin/tdiary:25:in `load'
    from /Users/tambara/.rbenv/versions/3.2.2/bin/tdiary:25:in `<top (required)>'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.3.7/lib/bundler/cli/exec.rb:58:in `load'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.3.7/lib/bundler/cli/exec.rb:58:in `kernel_load'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.3.7/lib/bundler/cli/exec.rb:23:in `run'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.3.7/lib/bundler/cli.rb:484:in `exec'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.3.7/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.3.7/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.3.7/lib/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.3.7/lib/bundler/cli.rb:31:in `dispatch'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.3.7/lib/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.3.7/lib/bundler/cli.rb:25:in `start'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.3.7/exe/bundle:48:in `block in <top (required)>'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.3.7/lib/bundler/friendly_errors.rb:103:in `with_friendly_errors'
    from /Users/tambara/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.3.7/exe/bundle:36:in `<top (required)>'
    from /Users/tambara/.rbenv/versions/3.2.2/bin/bundle:25:in `load'
    from /Users/tambara/.rbenv/versions/3.2.2/bin/bundle:25:in `<main>'

案の定動かない。よくわからんけど、Gemfile.lockのtdiaryのバージョンを5.2.3に直してうごかしちゃった(笑)

あと、RDスタイルがないと困ってしまうので、探して入れた。

RubyのLinda実装であるrindaを触ってみる

部門の勉強会でオライリーから出ている「ソフトウェアアーキテクチャの基礎」という本を読んでいる。アーキテクチャパターンランゲージを手に入れることを主眼にしているので、第2部から読んでる。

www.oreilly.co.jp

内容的に同意できないところもあるし、「そのネーミングはどうなのか?」と思うこともしばしばだけども知識の整理にはなるし、何より「うーん、どうなの?」という内容の方が勉強会が盛り上がるというのはあるので、楽しくやっているところ。

で、次回は15章の「スペースベースアーキテクチャ」である。「すぺーす?宇宙?」という感じでまったく聞いたことがない名前なんだけれども、インメモリDBグリッドでデータ共有したたくさんのアプリケーションサーバでリクエスト数の変動幅が大きい(ときどきバーストした大量のリクエストが飛んでくるような)システムを作ろうというようなアーキテクチャパターンのことをそう呼んでいるらしい。まあ、確かに固まった名前がないといえばないような気がする。

しかし、それがなんで「スペースベース」なのかというと、これは以下のように説明されている。

スペースベースアーキテクチャの名前は、タプルスペースの概念に由来する。タプルスペースとは、複数の並列プロセッサーが共有メモリを介して通信する技術だ。

タプルスペースというのは聞いたことがない。調べてみると、Lindaというものが昔、考えられていたらしい。

ja.wikipedia.org

Wikipediaには「プログラミング言語」だと書いてあるが、これは並列プログラミングのモデルの一種のようだ。コルーチンとかアクターとかスレッドとかミューテックスとか、そういうものの仲間な気がする。いや、それらの仲間が「タプルスペース」でタプルスペースの実装をLindaと呼ぶのかもしれない。よくわからない。

よくわからないけども、並列プログラミングを行う上での問題というのは、並列で動作しているプロシージャ同士で共有するリソースの競合をどうやって避けるかということに尽きる。共有しているリソースが何にもなければそれぞれが勝手に動いていればいい。けど、それを並列とはいわないわけで、共有するリソースへのアクセスをどうするかということが問題になる。ロックして他のプロシージャを待たせればいいという考え方もあるし、共有リソースをプロシージャ間で通信に載せてやりとりすればいいという考え方もある。

タプルスペースというのはシンプルなリクエストキューのようなもので、どんなスキーマでも格納できるストレージにputする動作と、ある特定のスキーマだけをgetする動作だけが出来て、リクエスタとコンシューマはスキーマを取り決めておくことでメッセージをやりとり出来るというような仕組み。getする側は欲しい情報がなければブロッキングするので、単純にタプルスペースからgetするよというコードだけを書いておけば、それでリクエストの待ち受け状態に出来るというわけ。

Wikipediaによると、これが提案された1986年頃には注目されたそうだが、90年代には忘れられたらしい。まったく聞いたことがなかった。

で、dRubyの関さんがLindaのRuby実装であるrindaというライブラリを書いていて、大昔からRubyの標準ライブラリに入っていて、Railsの内部でも使われていたりするらしい。まったく知らなかった・・・というか、ここまでくると聞いたことがないわけはない気もするんだけども、関心を持っていないとそんなものである。というわけで、ちょろっと触ってみることにする。

まず、1つ目のターミナルでタプルスペースを作る。

irb(main):001:0> require 'rinda/tuplespace'
=> true
irb(main):002:0> ts = Rinda::TupleSpace.new
=> 
#<Rinda::TupleSpace:0x0000000108141eb0                                                                    
...                                                                                                       
irb(main):003:0> DRb.start_service('druby://localhost:12345',ts)
=> 
#<DRb::DRbServer:0x000000010818e030                                                                       
 @config=                                                                                                 
(途中略)
 @uri="druby://localhost:12345">
irb(main):004:0> 

3行だけである。簡単だ。requireして、タプルスペースを作って、それをdRubyでURLを付けて公開する。それだけ。

では、2つ目のターミナルで、待ち受けをしてみる。

> irb
irb(main):001:0> require 'drb/drb'
=> true
irb(main):002:0> DRb.start_service
=> 
#<DRb::DRbServer:0x0000000106dc7038                                                             
 @config=                                                                                       
(途中略)
 @uri="druby://192.168.0.125:59142">
irb(main):003:0> ts = DRbObject.new_with_uri('druby://localhost:12345')
=> #<DRb::DRbObject:0x00000001067db2c8 @ref=nil, @uri="druby://localhost:12345">        
irb(main):004:0> mes = ts.take([:message, nil])

今度は4行だ。requireして、dRubyを開始して、タプルスペースに接続して、メッセージを取得する。

2行目のDRb.start_serviceはなぜ必要なのかというと、dRubyでやりとりするときに暗黙のオブジェクト公開が行われることがあるからなんだそうだ。なので、オブジェクトを公開しない場合も、おまじないで引数なしのDRb.start_serviceをやっておく。

3行目が典型的なdRubyの使い方で、DRbObject.new_with_uriするとそのURLで公開されているオブジェクトに対するDRbObjectが作られる。そのDRbObjectに対するメソッド呼び出しをすると、それがネットワークを通じて元のオブジェクトへ送られることになる。ありがちなRMI(Remote Method Invocation)だと、そのメソッドの呼び出しのためのIDL(Interface Definition Language)での記述がめんどっちかったりするわけだが、なんせRubyなのでそういうものはなく、いきなりメソッド呼び出しが出来てしまう。

なので、4行目でいきなりDRbObjectであるtsに対してtakeを実行する。こちらのプロセスはたぶんDRbObjectの実体がTapleSpaceであることは知らないまま、takeを向こうに送りつけている。で、takeは引数に渡したものをパターンとしてマッチするものを返す。見つからなければ待ち続ける。nilワイルドカードとして扱われるので、要するに2要素で1要素目に:messageが入っているものが来るのを待ち続ける。 最後の行でプロンプトが戻ってきていないのがポイントね。

では、3つ目のターミナルを開いて、メッセージを送りつけてみよう。

> irb
irb(main):001:0> require 'drb/drb'
=> true
irb(main):002:0> DRb.start_service
=> 
#<DRb::DRbServer:0x000000010134f010
 @config=                
(途中略)
 @uri="druby://192.168.0.125:59454">
irb(main):003:0> ts = DRbObject.new_with_uri('druby://localhost:12345')
=> #<DRb::DRbObject:0x00000001013fd5e8 @ref=nil, @uri="druby://localhost:12345">
irb(main):004:0> ts.write([:message, "hoge"])
=> #<DRb::DRbObject:0x00000001014a4028 @ref=78840, @uri="druby://localhost:12345">
irb(main):005:0> 

さっきとの違いは、takeじゃなくてwriteでメッセージを送っていること。これをwriteした瞬間に2つ目のターミナルに以下が表示されることになる。

irb(main):004:0> mes = ts.take([:message, nil])    ## <== さっきはここで止まってた
=> [:message, "hoge"]
irb(main):005:0> 

めちゃめちゃ簡単だ。

1つのリクエスタと1つのコンシューマしかいないと何がうれしいのかわからないが、これの素敵なところはいくらでもコンシューマを待ち受けさせてよいし、いくらでも同時のプロセスからメッセージを投げ込んでよいということだ。時間がかかるIOを伴う処理(例えば、何かのリストにもとづいてインターネットのいろんな場所から何かを集めてくるとか)を並列化したり、時間のかかる計算をコア数分だけ並列化したりしたいことはちょいちょいあるが、それがものすごく簡単に実行出来るし、まったく同じプログラムでマルチプロセスにもマルチマシンにも出来る。これはとっても便利じゃないか。なんで今まで知らなかったんだろう。覚えておこう。