PLAIN-TEXT BASIC, RUN AGAINST DOCUMENTS THAT CANNOT STORE MACROS

マクロを置けない文書を、平文の Basic で動かす。 Office 無しで、文書を動かす。

Microsoft Office は要りません。文書の形式はそのままに、 中身だけを機械で処理します。ソースは平文なので差分が読めます。

道具もこのページも AI が書き、AI が描画して確かめました。 根拠は視覚 QA と確認していないことに書いてあります。

Amount.bas 平文。git に置く
u = oSheet.getCellByPosition(2, i).getValue()
q = oSheet.getCellByPosition(3, i).getValue()
oSheet.getCellByPosition(4, i).setValue(u * q)
total = total + u * q
basrun apply
見積書.xlsx マクロは入らない
1,28040 51,200
340120 40,800
95500 47,500
8,6006 51,600
72080 57,600
合計 248,700
詰まる場所THE CONSTRAINT

たとえば、こういう場面です。

「この見積、金額と合計を入れて今日中にお願いします。
毎月同じ形で来るので、来月からも」

  • 渡されたのは .xlsx。マクロは 1 バイトも入っていない
  • 手元の端末に Microsoft Office が無い
  • 相手の運用は変えられない。形式もそのまま返すのが前提
  • 同じ処理が来月もある。今回かぎりの手作業では終わらない

この依頼は、渡されたファイルが .xlsx だと素直には成立しません。 .xlsx は仕様としてマクロを格納できないからです(マクロは .xlsm 側)。 VBA を書けるかどうかではなく、書いたものの置き場所がないという形で詰まります。 そして逃げ道は 3 つとも、何かを諦めることになります。

形式を変える

.xlsm に変換する。相手の運用を変えることになり、受け入れられないことがある。

値を直接書く

計算結果だけ埋める。再実行できず、式も残らない。次に数字が変われば作り直し。

諦める

手作業に戻す。枚数や月数に比例して時間が増える。来月も同じだけかかる。

3 つとも、技術的な限界ではありません。 できない理由が仕様に書いてあるので、そこで止まりやすいだけです。 止まっているのは 格納 の側であって、実行 の側ではありません。

制約は格納側にあるSTORAGE, NOT EXECUTION

格納できないだけで、実行できないわけではありません。 ソースを実行時に Basic ライブラリへ流し込めば、文書は普通の .xlsx のまま処理できます。

平文のソース src/Amount.bas git diff が読める。真実はここ apply 流し込む Basic ライブラリ MyLib 実行時だけ。終わればもう無い 文書を処理 文書 book.xlsx ソースは埋め込まれない pull ― 文書に埋まってしまったマクロを、平文へ救出する
平文のソース src/Amount.bas git diff が読める。真実はここ apply 流し込む Basic ライブラリ MyLib 実行時だけ。終わればもう無い 文書を処理 文書 book.xlsx ソースは埋め込まれない pull ― 埋まったマクロを平文へ救出
# ソースは平文のまま。文書には一切埋め込まない
python basrun.py apply book.xlsx src MyLib Amount.FillAmounts --backup

# 文書に埋まってしまったマクロを、平文へ救出することもできる
python basrun.py pull rescued Standard --book legacy.ods

回り道した先のほうが、本来の形として優れています。

埋め込みマクロ
✗
ソースの可読性

文書内の XML に埋まる

✗
レビュー

実質できない

✗
対象の形式

マクロを持てる形式のみ

✗
真実の在処

文書

basrun
✓
ソースの可読性

git diff が読める

✓
レビュー

通常のコードレビュー

✓
対象の形式

.xlsx .pptx .docx 共通

✓
真実の在処

ソース(実行時のキャッシュ)

basrun が粗利率を埋めた月次表とグラフ

別の .xlsx ― 粗利率と % 書式は basrun が入れ、グラフと条件付き書式は生成時に。Excel は使っていない

作ったら、見るRENDER, THEN LOOK

文字列が正しいことと、読める状態であることは別です。 「うまくいきました」と表示するコードは、うまくいかなくてもそう表示します。 だから出来上がりを描画し、目で確かめてから完了とします。

値だけなら CSV に落とせば読めます。ですが CSV になった時点で、 結合・列幅・シートの構造は落ちます。座標そのものは数字として残っても、 見え方は残りません。グラフに至っては文字としての姿がないので、 書けているかどうかを読み返しで確かめる方法がありません。

文字として読める描画しないと分からない
セル値・数式・座標結合の見え方、列幅で切れた文字
書式指定した規則その規則が当たった結果の色
グラフ定義(XML)そもそも出ているかどうか

実際に踏みました。グラフの図形に 大きさが書かれておらず、グラフは存在するのに面積がゼロ ―― つまり 見えない状態になっていました。問い合わせれば「グラフ 1 個」と正しく返ります。 存在を確認する方法では、これは見つかりません。原因を 3 回続けて読み違え、 最後は「この描画系はグラフに対応していない」と道具の限界に帰着させました。 3 回とも外れです。描画して初めて、自分の生成物を疑えました。

basrun も、このページも、書いたのは AI です。
そして上の欠陥を見つけたのも、描画して見た AI 自身です。

  • AI は画像を読めます。ですが文書を画像にする経路が無ければ、 読む対象そのものがありません。ライブラリが返すのは値と書式の 指定であって、描画の結果ではないためです
  • そこで soffice で PDF にし、画像にしてから読み返す経路を作りました。 この節の 2 枚も、上の月次表も、そうやって一度見てから載せています
  • このページ自体も同じ手順で作りました。幅を変えて描画し、 見出しの折り返し・図の欠け・地と文字のコントラストを確かめています
basrun が版数を差し替えた作業指示書

.docx ― 版数の差し替えとロット件数の追記を basrun が実行

生成した 3-D 円グラフを描画したもの

.xlsx ― 3-D グラフとテクスチャ。描画しなければ確認できない領域

題が 2 行に折り返す

文字列としては完全に正しい。読み返しでは絶対に出ない欠陥。

暗い面に暗い文字

デザインシステムの色を名前で対応させ、載せる面の役割を落としていた。

下三分の一が空白

横幅で設計して縦の寸法を使っていなかった。数値上は正しい配置。

使い方GETTING STARTED

必要なのは LibreOffice だけです。Microsoft Office は要りません。 Python は LibreOffice に同梱のものを使います(素の Python には uno が無いためです)。

01

Sub を書く

ソースは平文の .bas。文書には一切埋め込まないので、そのまま git に置けます。

02

文書に当てる

実行時にライブラリへ流し込み、処理して保存します。形式は .xlsx のままです。

03

描画して見る

「うまくいきました」の表示ではなく、出来上がりを目で確かめてから完了とします。

' ★ 文書は引数で受ける。ThisComponent に頼らない
Sub FillAmounts(oDoc As Object)
    Dim oSheet As Object
    oSheet = oDoc.Sheets.getByIndex(0)
    ...
End Sub

ThisComponent は使えません。 --headless で非表示に開いた文書は「現在のコンポーネント」ではないためです。 成功したように見えて、何も起きません ― 実測で「読み込んだ / 実行した / 保存した」と全部表示され、セルは 1 つも変わっていませんでした。

# 同期して、当てて、保存する(--backup で元を残す)
python basrun.py apply book.xlsx src MyLib Amount.FillAmounts --backup

起動する LibreOffice は専用プロファイルで隔離します。 利用者が画面で開いている LibreOffice を巻き込まないためです。停止も taskkill ではなく、接続先だけを終了させます。 BASRUN_OFFICE / BASRUN_PROFILE / BASRUN_PORT で上書きできます。

確認していないことWHAT IS NOT VERIFIED

確かめた範囲と、確かめていない範囲を分けて書きます。 聞かれてから答えるのと、先に書いておくのとでは意味が違うためです。

確認していない

  • Windows でしか動かしていません。Linux / macOS のパス解決は書いてありますが未検証です。
  • 巨大な表(数万行規模の性能・メモリ)は試していません。結合セル・複数シートは確認しましたが、スケールは別問題です。
  • 描画に使うのは LibreOffice です。Excel / PowerPoint の描画とは異なります。 実測で、3-D 円グラフのラベル位置が両者で違いました。
  • 同梱している同期ツールは 2017 年公開で以降更新がありません。 現行の LibreOffice で動くことは確認済みですが、将来の互換性は保証できません。

確認した

  • 結合セル・複数シートで動くこと。既存の結合が処理の往復で保たれ、 2 枚目のシートを狙って書け、新しい結合も作れます ― 値だけでなく描画して見た目も確認しました。
  • テスト 22 件(単体 16 / 統合 6)。単独でも、通しでも 22/22 ― 通しで走らせて初めて出た欠陥が 1 件あり、直してあります。 LibreOffice が無い環境では統合分を飛ばします
  • 実行の前後で、利用者の既定プロファイルがバイト単位で不変であること
  • 処理後も vbaProject.bin を含まない、通常の .xlsx であること
  • 結果は生成に使った実装ではなく、別の実装で読み返して確認
  • このページも幅 1280 / 390 / 360 で描画して確認。地と本文のコントラストは 画素を読んで測定(最悪 8.2 : 1)、外部への通信は 0 件
借りているものBUILT ON
obasync 同期を委譲。imacat 作 / Apache-2.0 ― 無改変で同梱しています → open-design 配色と立体。Apache-2.0 ― データだけ取り込み、常駐するものは入れていません →

書き直す理由が無いものは書き直していません。組んで初めて出来ることのほうに時間を使っています。 ―― 文書を開いて中のマクロを平文へ救出する --book は、 どちらの道具にも単体では無かったものです。