はじめに
GASの大部分の処理はスプレッドシート関連、すなわち
- スプレッドシートにある以下のような情報を取得する
- 従業員情報
- グーグルフォームの情報
- 売上情報
- スプレッドシートにある情報を編集する
- 従業員情報を修正したり
- 従業員情報にグーグルフォームの情報を追加したり
だと思います。スプレッドシートをデータベースとして使うイメージですね。
高頻度で触る処理になるので、以下のようなルールを設けてみたらうまくいきました。
- シートの情報は連想配列でまとめる
- シートの情報をとるときは基本共通処理を使う
- シートの情報をとったときはクラスに格納する
です。
ルール1 シートの情報は連想配列でまとめる
sheet.gs
const SHEET = {
member : {
name : '従業員情報',
row : {
// 実際にデータが何行目からあるかを定義しています。共通処理の中でここの情報を取得しています。
data : 2,
},
column : {
// 何列目になんの情報があるかを定義してます。後ほどクラスに設定するときに使います。
id : 1,
name : 2,
status : 3,
},
},
form : {
name : 'フォーム',
row : {
data : 2,
},
column : {
time : 1,
id : 2,
text : 3,
},
},
};
ルール2 シートの情報をとるときは基本共通処理を使う
sheet.gs
// シートからの情報を取得する処理(見出しを省く)
function getSheetData(sheetConfig, spreadSheetId){
let data = getSheetDataFull(sheetConfig, spreadSheetId);
[...Array(sheetConfig.row.data - 1)].forEach(_ => data.shift());
return data;
}
// シートからの情報を取得する処理(見出しを省かず、シートの情報全体をとる)
function getSheetDataFull(sheetConfig, spreadSheetId){
const ss = (spreadSheetId !== undefined)
? SpreadsheetApp.openById(spreadSheetId)
: SpreadsheetApp.getActive();
const sheet = ss.getSheetByName(sheetConfig.name);
return ss.getSheetByName(sheetConfig.name).getDataRange().getValues();
}
// 1つのセルに対して情報を設定
function setText(sheetConfig, row, column, text){
setList(sheetConfig, row, column, [[text]]);
}
// 複数のセルに対して情報を設定
function setList(sheetConfig, row, column, list){
if(!list.length) return;
const sheet = SpreadsheetApp.getActive().getSheetByName(sheetConfig.name);
sheet.getRange(row, column, list.length, list[0].length).setValues(list);
}
// シート全体を更新
function refreshSheet(sheetName, list, startColumn, startRow){
if(!list[0].length) return;
const sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
startRow = startRow ? startRow : 2;
startColumn = startColumn ? startColumn : 1;
sheet.getRange(startRow, startColumn, sheet.getLastRow(), list[0].length).clear();
sheet.getRange(startRow, startColumn, list.length, list[0].length).setValues(list);
}
// シートに情報を追加(見出しの下の行から足す)
function addSheet(sheetConfig, column, list){
if(!list.length) return;
const sheet = SpreadsheetApp.getActive().getSheetByName(sheetConfig.name);
sheet.insertRows(sheetConfig.row.data, list.length);
sheet.getRange(sheetConfig.row.data, column, list.length, list[0].length).setValues(list);
}
// シートに情報を追加(シートの最後の行から足す)
function addSheetLastRow(sheetConfig, list, column){
if(!list.length) return;
const sheet = SpreadsheetApp.getActive().getSheetByName(sheetConfig.name);
sheet.getRange(
sheet.getLastRow() + 1,
column !== undefined ? column : 1,
list.length,
list[0].length
).setValues(list);
}
ルール3 シートの情報をとったときはクラスに格納する
取得するところ
sheet.gs
function getMemberList(){
return getSheetData(SHEET.member).map(row => new Member(row));
}
クラスを定義しているところ
class/Member.gs
class Member{
constructor(row){
this.id = row[SHEET.member.column.id - 1];
this.name = row[SHEET.member.column.name - 1];
this.status = row[SHEET.member.column.status - 1];
}
isValid(){
return this.id !== ''
&& this.name !== ''
&& this.status !== '';
}
getHonorificName(){
return `${this.name} 様`;
}
}
効果
上のようなルールを設けることで
- 列が変わったときにも対応が容易になった
- PGやコードレビューがしやすくなった
などの恩恵がありました。
フレームワーク化もしてみたいなぁと思いつつ一旦こんな運用をしています。