この記事は N・S高等学校 Advent Calendar 2021 の 7日目の記事です。
わたしは学校法人角川ドワンゴ学園でプログラミング講師をしている @ohataken です。以前は Ruby や JavaScript を使って Web アプリ開発をしていました。業務としての開発はしていませんが、学校運営の一環として Google Classroom や Slack の API を日常的に扱っています。
概要
Google Apps Script で以下のような createCsv
関数と appendRow
関数を作って、小さいドメイン固有言語 (DSL) だと思うことにして利用しています。Google Apps Script において Google スプレッドシートへの書き込みは頻出パターンなので、その書き方にルールを作ることで可読性、保守性が高まります。
function createCsv(callback) {
const csv = [];
callback(csv);
return csv;
}
function appendRow(csv, callback) {
const row = [];
callback(row);
csv.push(row);
}
解説
Google Apps Script において、 Google スプレッドシートへの書き込みはかなりの頻出パターンだと思います。スプレッドシートに書き込むためのデータは2次元配列なので、この2次元配列を作ることもまた頻出パターンです。 createCsv
関数と appendRow
関数は、2次元配列をつくるためのものです。
function createCsv(callback) {
const csv = [];
callback(csv);
return csv;
}
function appendRow(csv, callback) {
const row = [];
callback(row);
csv.push(row);
}
ここでは CSV は単に2次元配列のことを指しています。
使い方 (1)
まずはリテラルで。
const obj = createCsv((csv) => {
appendRow(csv, (row) => {
row.push("名前");
row.push("年齢");
});
appendRow(csv, (row) => {
row.push("アリス");
row.push("16");
});
appendRow(csv, (row) => {
row.push("ボブ");
row.push("14");
});
appendRow(csv, (row) => {
row.push("キャロル");
row.push("11");
});
appendRow(csv, (row) => {
row.push("デイヴ");
row.push("19");
});
});
コールバックを使って書くことで、 const
や let
などのローカル変数の宣言なしに書くことができてスッキリします。同じことですが、自然にスコープを狭く狭く持とうとする書き方になります。また、コールバック関数のインデントが2次元配列の「行があって、その中に列がある」という構造に対応していて、理解しやすいです。値をひとつ入れる度に1行使うようにするので、コードが横ではなく縦に伸びていくのも読みやすさに一役買っています。
使い方 (2)
例題として百マス計算でも。
const obj = createCsv((csv) => {
for (let i = 1; i < 10; ++i) {
appendRow(csv, (row) => {
for (let j = 1; j < 10; ++i) {
row.push(i * j);
}
});
}
});
この例はさほど読みやすいとも思いませんが、前の例と同じ方法で書くことができる、ということがわかってもらえれば。
使い方 (3)
これは実際のコードに近いパターンで、 Google ドライブの特定のフォルダ内のファイルを列挙するものです。
前述のとおり、スプレッドシートへの書き込みは Google Apps Script の頻出パターンと思われますが、もっと言い切ってしまうと、 DriveApp.getFolderById
や Folder.getFiles
などの Google Apps Script にある API から得たデータを整形して2次元配列を作る パターンこそ頻出だと思います。
const folder = DriveApp.getFolderById("THIS_IS_ID_OF_A_GOOGLE_DRIVE_FOLDER");
const iter = folder.getFiles();
const csvObject = createCsv((csv) => {
appendRow(csv, (row) => {
row.push("ID");
row.push("Name");
row.push("URL");
});
while (iter.hasNext()) {
const file = iter.next();
appendRow(csv, (row) => {
row.push(file.getId());
row.push(file.getName());
row.push(file.getUrl());
});
}
});
こうすることで、データを取得するときと、2次元配列の形に整形するときを明確に区別することができ、数日後または数週間後の自分にもやさしい書き方になります。
まとめ
頻出パターンである2次元配列の作成をイディオムにできました。本当にちょっとした関数なので、あたらしく Google Apps Script を書き始めるときは既存のプロジェクトからいつもコピーして使っていくことができます。
Google Apps Script は、技術的な興味や価値はともかく、業務上はとても価値があるツールなので、書き捨てのスクリプトのままにせず、動き続ける生きたものにするための工夫は、やはり重要だと思います。今回の方法はそれを実現するものになっていると思っています。