アペフチ

雑多にプログラミング、集中力の衰え

OgaのXPathの名前空間サポートの拡充

EPUB ParserというRubyGemを作っている。電子書籍用に使われるEPUBというファイルフォーマットを扱うライブラリーなのだけど、EPUBというのは雑に言って「XHTMLとCSSと画像とメタデータ用XMLファイルをZIPアーカイブした物」なので、内部でXMLを扱う必要がある。

XMLライブラリーは切り替え可能にしていて、今はRuby標準添付のREXMLの他にNokogiriをサポートしている。これに加えてOgaもサポートしたいなあと前々から思っていた。

最近、全然プログラミングを楽しむ時間が取れていなくてあまりにフラストレーションが溜まってしまったので、他にやることもあったのだけど、Ogaに取り組むことにしてしまった。具体的には、Ogaの方のImprove XPath namespace supportというイシューを解決しようというものだ。これができれば、EPUB Parserの方にOgaサポートを追加するのは簡単。

問題の特定や変更箇所は既にイシューページで議論されているので、後残っているのはOgaの構造を理解すること、それから、実際に手を動かしてパッチを書くことだ。ソースコードを眺めたり動かしてみたりしてYorick Peterseさんの提案するAPIを定義することはできたので、後はAPI経由で渡された名前空間エイリアスを使うところを実装すればいい、というところまで進んだ(未コミット)。

Fiddleでlibzip

EPUBというのは「XHTMLとCSSと画像とメタデータ用XMLファイルをZIPアーカイブした物」なので、EPUB ParserではZIPアーカイブを扱う必要がある。これも切り替え可能にしていて、ピュアRubyのArchive::ZipとCのlibzipのバインディングであるZip/Rubyをサポートしている。当然Zip/Rubyの方が速い。のだけど、長いこと開発が止まっているので、何とかしたいなあと思っていた。具体的には、自分でメンテナンスを引き継ぐか、別のlibzipバインディングを作るか、(Rustに興味あるので)RustのZIPクレートをRubyから使えるようにしてみるか(Rutieなどで)。

それとは別にRubyでFFIする時にRuby FFIばっかりが使われてFiddleが見向きもされないのが何だかなあと思っていたので、二番目の「別のlibzipバインディングを作る」をFiddleを使ってやってみようと思った。

とは言え、Cプログラミングが全くの初心者なので、ドキュメント読んだり何とかlibzipのAPIリファレンス見たりしてやってみてるのだけどうまくできてるのか自信がない。特にメモリー管理が適切なのか全然分からん。途中経過がこんな感じ。どうなんでしょう?

require "fiddle/import"

module Libzip
  CREATE = 1
  EXCL = 2
  CHECKCONS = 4
  TRUNCATE = 8
  RDONLY = 16

  module FL
    NOCASE = 1
    NODIR = 2
    COMPRESSED = 4
    UNCHANGED = 8
    RECOMPRESS = 16
    ENCRYPTED = 32
    ENC_GUESS = 0
    ENC_RAW = 64
    ENC_STRICT = 128
    LOCAL = 256
    CENTRAL = 512

    ENC_UTF_8 = 2048
    ENC_CP437 = 4096
    OVERWRITE = 8192
  end

  extend Fiddle::Importer
  dlload "libzip.so", "libzip.so.4"

  typealias "zip_flags_t", "uint64_t"
  typealias "zip_uint16_t", "uint64_t"
  typealias "zip_uint32_t", "uint64_t"
  typealias "zip_uint64_t", "uint64_t"
  typealias "zip_int64_t", "zip_uint64_t"

  extern "zip_t * zip_open(const char *path, int flags, int *errorp)"
  extern "int zip_close(zip_t *archive)"
  extern "zip_int64_t zip_get_num_entries(zip_t *archive, zip_flags_t flags)"
  extern "zip_file_t * zip_fopen_index(zip_t *archive, zip_uint64_t index, zip_flags_t flags)"
  extern "int zip_fclose(zip_file_t *file)"
  extern "void zip_stat_init(zip_stat_t *sb)"
  extern "int zip_stat_index(zip_t *archive, zip_uint64_t index, zip_flags_t flags, zip_stat_t *sb)"

  Stat = struct([
                  "zip_uint64_t valid",
                  "const char *name",
                  "zip_uint64_t index",
                  "zip_uint64_t size",
                  "zip_uint64_t comp_size",
                  # "time_t mtime",
                  "zip_uint32_t crc",
                  "zip_uint16_t comp_method",
                  "zip_uint16_t encryption_method",
                  "zip_uint32_t flags",
                ])
  class Stat
    NAME = 0x0001
    INDEX = 0x0002
    SIZE = 0x0004
    COMP_SIZE = 0x0008
    MTIME = 0x0010
    CRC = 0x0020
    COMP_METHOD = 0x0040
    ENCRYPTION_METHOD = 0x0080
    FLAGS = 0x0100
  end
end

errorp = 0
archive = Libzip.zip_open("book.zip", Libzip::RDONLY, errorp)
pp archive
pp num_entries = Libzip.zip_get_num_entries(archive, Libzip::FL::UNCHANGED)
0.upto num_entries - 1 do |index|
  file = Libzip.zip_fopen_index(archive, index, 0)
  stat = Libzip::Stat.malloc
  Libzip.zip_stat_init stat
  p Libzip.zip_stat_index(archive, index, Libzip::Stat::NAME|Libzip::Stat::SIZE, stat)
  p [index, file, stat.size, stat.name.to_s]
  p Libzip.zip_fclose(file)
end
pp Libzip.zip_close(archive)
pp archive
# pp Libzip.zip_close(archive) # => SEGV

FiddleはRuby標準添付のFFIライブラリーなので、追加gemをインストールする必要がない。おまけにWindowsでも動く。ので基本はこちらがいいんではないかなあ。内部ではFiddleを使いつつ、APIだけRuby FFIと同じにするためのFiddleyというgemもあるので、興味ある人はこれを使って移行を始めてもいいだろう。

Public Outbox

自分のトゥートとかブログポストとかのActivityPubのアクティビティを一か所に集めて、「他人がここを見れば自分のアクティビティが分かる」というようにできたらどうだろう、と考えたりしてた。ActivityPubのoutboxのうちパブリックな物のリスト、とも考えられるので、Public Outboxという名前はどうか。というようなことを考えたりしていた。何で作るのがいいんだろう。Rails?

因みに名前はpublic-inboxのもじり。

集中力の衰え

以前だったら、OgaのXPath名前空間拡充は、ここで手を止めずにもっと進めていたと思うのだけど、今はそれができなくなってしまっている。歳なのかなんなのか、集中力が衰えてしまっているなあと感じる。まずいまずい。

WordPressでGutenbergのブロック追加ができない

ここの「+」の所。

ce78a14fa17a3743411af09f8bf3b57c

これが何故かグレーアウトされたままでブロックが追加できなかった。
「Gutenberg cannot add block」とかでググったら出てくる解決法の、「プロフィール画面で『 ビジュアルリッチエディターを使用しない』のチェックを外す」をしてもだめ。

なんでだろう思いつつ、「Classic Editor」プラグインを入れてみたら、TinyMCEになるわけだけど、なんかHTMLしか入力を受け付けない、WYSIWYGモードにならない。ここで「WordPress wysiwyg not shown」とかでググったら、「WordPressはUAを見てリッチエディターの有効・無効を判定しているので、CloudFrontを使っているとリッチエディターが使えない」ということが分かる(例:Rich Text/Visual/WYSIWYG Editor does not work in WordPress behind cloudfront – dtbaker.net)。
リンク先では functions.php を編集しているけど、CloudFrontでUser-Agentヘッダーをフォワードするように設定して解決。

Gutenberg関連だという思い込みがあって中々解決に至らなかった。CloudFrontは盲点だったなあ。
もうソースコード読むしかないか……という気持ちだったので、そうなってたらまあ、発見できたかも知れないが相当時間か掛かりう。「Classic Editor」を入れる、というのを試して本当によかった。

パソコンの目の前でポッドキャストを聴けない

パソコンの目の前でポッドキャストを聴けない。

ポッドキャストは「ながら聴き」ができていい、という面がある。寝しなに目をつむったまま寝入りながら聞けるとか、通勤中に聞くとか、散歩しながら聞くとか。

でも、パソコン開いてぼーっとしながら聞いてると、いつの間にか別のことを考えていて、聴いてない。慌てて巻き戻す。ということを繰り返していた。なんか、いつの間にか、むしろポッドキャストの内容を切っ掛けにググったりしているのだけど、目の前に記事に集中してしまっている。僕は視覚優位なのかも知れない。