Redmine APIをGASで実行して、ガントチャートを同期する(4: claspとTypeScriptを導入する)
こんばんは!株式会社スマレジ、開発部のmasaです。 コロナの影響で、スマレジでもテレワークを導入しておりますが、 皆様の会社はいかがでしょうか?
顔を合わせないで仕事をするのは難しい部分もありますが、 感染拡大防止のため、協力していきましょうー!
というわけで、今回は「お家で一緒にやってみよう」ではありませんが、 GASの開発を本格化するため、claspを導入します。
claspを導入する。
claspはgoogleが提供している、GASをローカルで開発するための認証基盤と命令セットです。 公式GitHub github.com
ローカルで開発するメリットとしては以下のようなものがあります。
- TypeScriptのような、AltJS系を利用できる。
- webpackを用いれば、MVC用途ごとにフォルダを切って整理することができる。(現状、ブラウザの開発環境では階層を作ることができないっぽい)
- Lintを使うことができる。
で、すでに導入方法はいろんなところで説明しています。masaは↓を見て導入しました。 AltJSは学生時代にCoffee Scriptを触って以来、ふれてこなかったので、TypeScriptも勉強の意味で導入しました。
イメージのわきにくい方は、下記の構成イメージをご参照ください。
TypeAcriptでコーディングして、webpackでjsに変換して、claspで認証してソースをサーバにあげるという流れです。
セルの値を相対参照で取得する
さて、環境はできたので、リファクタリングとclaspの動作確認もかねて少しだけ基本部品を作成します。 VBAやGASを触っていてよくあるのが、「シートの構成が変わったから参照するセルの位置がずれた」というやつです。 特にGASでツール化するときは社内の多くの人が使うことが多いので、利用用途に応じてフォーマットもちょいちょい変わりがち。 「フォーマット?考えながら作ってよ。ちょいちょい変えてくれればいいからさー」という要望にすぐに対応できるときとできないときが、 構成によっては発生します。
そういう手戻りを回避するために、いわゆる"A3"とか"B5:C3"のような決め打ちのセル指定ではなく、 「○○からみて、右に3つ、下に2つ」のような相対参照をする機能を考えます。
そして、実際に作成したものがこちら。(3分コーディング?)
まずは、相対参照・絶対参照の値を保持するオブジェクト。
/** * 位置種別クラス * relativeかabsoluteの二値のみ保持する。 * Cellクラスで位置判定をするためのValue object * @class PositionType */ export class PositionType { public position: string; public static readonly RELATIVE: string = "relative"; public static readonly ABSOLUTE: string = "absolute"; constructor(position?: string) { if ( position === PositionType.RELATIVE || position === PositionType.ABSOLUTE ) { this.position = position; } else { this.position = PositionType.ABSOLUTE; } } isRelative() { return this.position === PositionType.RELATIVE; } isAbsolute() { return this.position === PositionType.ABSOLUTE; } }
次にセルの位置情報を持つオブジェクト。 ここに参照区分を持たせる。
import { PositionType } from "./PositionType"; /** * シートのセルの基本クラス * 位置情報として、相対参照と絶対参照を持つ * 相対参照の場合は、相対元となる値が必須. * 相対元の値がシート状で複数回現れる場合は、何番目に現れるのかをindexに指定. * 相対元の値の検索は行ごとに1行目から行う. * @class Cell */ export class Cell { public x: number; public y: number; public positionType: PositionType; public label: string; public index: number; constructor( x: number, y: number, position?: string, label?: string, index?: number ) { this.x = x; this.y = y; this.positionType = new PositionType(position); if (this.positionType.isAbsolute() === true) { this.label = "CAN'T USE"; this.index = -1; } else { if (label === undefined || label.length === 0) { throw new Error( "You must set the label of this value if you want to define the position relatively." ); } else { this.label = label; this.index = index === undefined ? 0 : index; } } } }
でシート一枚を表すクラス(現在作成中)に下記のセルの値を 取得するメソッドを足してあげる。 相対と絶対で参照するセルを分ける。
read(cell: Cell) { if (cell.positionType.isAbsolute()) { return this.dataList[cell.y][cell.x] + cell.index.toString(); } let index = 0; let currentY = 0; let currentX = 0; for (const line of this.dataList) { for (const value of line) { if (value === cell.label) { if (index === cell.index) { return ( this.dataList[currentY + cell.y][currentX + cell.x] + cell.index.toString() ); } index++; } currentX++; } currentX = 0; currentY++; } throw new Error(cell.label + "is not found."); }
とまあこんな感じにしておいて、相対参照を組み合わせてロジックを組めば、少しは変化に強くなっている・・・はず。