いまさらGASに入門したのでまとめてみた

## はじめに
その場凌ぎでGASを使っていませんか？
これは自分のことなんですが、少しでもGASを理解しようと入門したのでまとめます。
ざっくり理解するときに役立てばと思います！

以下の書籍を大いに参考にしています。世間的には「GAS本」と呼ばれているようです。ぜひ購入しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/e73179b8-3f84-f65d-208b-f8c17b5ae89c.png)
[詳解！ Google Apps Script完全入門 第2版 ～GoogleアプリケーションとGoogle Workspaceの最新プログラミングガイド～ | 高橋宣成 | 工学 | Kindleストア | Amazon](https://www.amazon.co.jp/dp/B08SQMBNR7/ref=sspa_dk_detail_0?psc=1&pd_rd_i=B08SQMBNR7p13NParams&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUEzUkpXVENFRlFZREFFJmVuY3J5cHRlZElkPUEwNjMzMzg4MlUwV1M0SzIwNVgyVyZlbmNyeXB0ZWRBZElkPUExVzlPTzNQM05FU0FRJndpZGdldE5hbWU9c3BfZGV0YWlsJmFjdGlvbj1jbGlja1JlZGlyZWN0JmRvTm90TG9nQ2xpY2s9dHJ1ZQ==)

## 想定読者
- GASを少し理解したい方

## GAS(Google Apps Script)とは
Google Apps Scriptは、Googleが提供しているプログラミング言語です。
スプレッドシートやGmail、Googleカレンダーなど、Goolgeが提供しているサービスをプログラムで操作することが出来ます。
GASを利用することにで、普段は手動で行っている作業を自動化することが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/65aef641-d7c7-a02e-dcc3-e6a435c116e1.png)
GASはJavaScriptをベースとして作られており、V8ランタイムがサポートされているためJavaScriptの比較的新しい構文も利用できます。

## クイックスタート
さっそくGASを始めていきましょう。
Googleアカウントを取得している前提で進めていくので、取得していない方はアカウントの取得から行ってください。

### スクリプトエディタを開く
まず、スプレッドシートの作成を行い編集画面に遷移します。
次に、「ツール」→「スクリプトエディタ」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/29cc38e2-9831-1308-0526-2468d0356bde.png)
すると、スクリプトエディタが起動し、プロジェクトが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/28c11c87-162c-b118-f647-957207992740.png)

### スクリプトを編集する
スクリプトを編集していきます。今回は、Hello Worldのメッセージボックスが出る処理を記述します。

```javascript
 function myFunction() {
   Browser.msgBox('Hello World');
 }
```

### スクリプトを実行する
スクリプトを実行していきましょう。メニューバーの「実行」を選択します。
GASでは関数ごとに実行できます。今回は関数が1つなので特に気にする必要は無いですが、複数の関数があるときは実行ボタンの右側で実行する関数を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/ed69e589-3913-5979-debb-2ffa423337a1.png)
初回の実行では承認メッセージが出てきますが、「権限を確認」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/2de0d870-4953-df80-8a28-a609540135f1.png)
次の画面ではアカウントを選択します。
このアプリは確認されていませんという画面では、左下の「詳細」→「無題なプロジェクト(安心ではないページ)に移動」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/9e63f452-094a-3a48-1076-5faff5f63a66.png)
アクセスのリクエストを許可します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/be6e464d-cb90-c36b-33a5-889d4569479b.png)
これで実行されるので、スプレッドシートにメッセージボックスが出ているはずです！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/aa1d448f-80a6-2854-6f83-8b3fe0efc654.png)

## スプレッドシートを操作してみる
次に、GASを使ってスプレッドシートを操作していきます。
実際にスクリプトを動かす前に、Spreadsheetサービスの主なクラスを紹介します。

|  クラス  |  説明  |
| ---- | ---- |
|   SpreadsheetApp  |  スプレッドシートを操作するときに最初に利用するクラス  |
|  Spreadsheet  |  スプレッドシートを操作するためのクラス  |
|  Sheet  |  シートを操作するためのクラス  |
|  Range  |  セル範囲を操作するためのクラス  |

これらのクラスは、SpreadsheetApp→Spreadsheet→Sheet→Rangeのように階層構造になっています。
画面に対応させると以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/69675d0a-87cf-2b3c-025d-277e23b5ef68.png)
**今回はスプレッドシートを例に説明していますが、他のサービスで利用するクラスも基本的に階層構造になっています。**

### データの取得と更新
シートのデータを取得、書き込みをしていきます。
以下のデータを例に、ハードカバーを雑誌に変更しようと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/8c911e78-bc03-6975-c011-67097ed4a105.png)
コードは以下の通りです。

```javascript
function myFunction() {
   // 各オブジェクトの取得
   const ss = SpreadsheetApp.getActiveSpreadsheet();
   const sheet = ss.getSheetByName('シート1');
   const range = sheet.getRange('A2:D4');
   
   // データの取得
   values = range.getValues();
   console.log(values);
 
   // データの変更
   values[2][0] = '雑誌'
   values[2][1] = 1000;
   values[2][3] = values[2][1] * values[2][2];
 
   // データの更新
   range.setValues(values);
}
```

実行結果は以下のとおりです。ハードカバーが雑誌に変わっており、値段も変更されていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/e5bfe60d-525f-78cb-d006-98a8d626e4be.png)

```terminal
 22:29:05	お知らせ	実行開始
 22:29:05	情報	[ [ 'コミック', 400, 3, 1200 ],
   [ '文庫本', 600, 10, 6000 ],
   [ '雑誌', 1000, 2, 2000 ] ]
 22:29:05	お知らせ	実行完了
```
以下、細かく説明します。

#### 各オブジェクトの取得
先程、「クラスはSpreadsheetApp→Spreadsheet→Sheet→Rangeのように階層構造になっています。」と説明しました。
そこが以下の処理です。SpreadsheetAppクラスを利用してSpreadsheetクラスのオブジェクトを取得し、、、と辿っていくの基本になります。

```javascript
    const ss = SpreadsheetApp.getActiveSpreadsheet(); // Spreadsheetの取得
    const sheet = ss.getSheetByName('シート1'); // sheetの取得
    const range = sheet.getRange('A2:D4'); // rangeの取得
```

今回は、Spreadsheetに関しては`getActiveSpreadsheet()`を使用してアクティブなシート(スクリプトに紐付けられているSpreadsheet)の取得を行いましたが、URLで取得したり、IDで取得することも出来ます。

```javascript
  // URLで取得
  const url = 'https://docs.google.com/spreadsheets/d/xxxxxxxx/edit#gid=0';
  const ssByUrl = SpreadsheetApp.openByUrl(url);
  // idで取得
  const id = 'xxxxxxxx';
  const ssById = SpreadsheetApp.openById(id);
  console.log(ssById.getName());
```
Sheet等の他のオブジェクトも同様に、様々な手段で取得することが出来ます。

また、Rangeの取得に関してはアドレスを使用しましたが、`getDataRange()`を利用することでシート上のデータ範囲を自動で取得出来ます。
これを利用することで、データの行数や列数が変化する場合にも対応が出来ます。

```javascript
 function myFunction2() {
   // 変更前のデータの取得
   const ss = SpreadsheetApp.getActiveSpreadsheet();
   const sheet = ss.getSheetByName('シート1');
   const range = sheet.getDataRange();
   values = range.getValues();
   console.log(values);
 }
```

```terminal
 22:33:25	お知らせ	実行開始
 22:33:25	情報	[ [ '商品名', '単価', '個数', '合計' ],
   [ 'コミック', 400, 3, 1200 ],
   [ '文庫本', 600, 10, 6000 ],
   [ 'ハードカバー', 1500, 2, 3000 ] ]
 22:33:25	お知らせ	実行完了
```

#### データの取得
`getValues()`によって二次元配列でデータを取得できます。

```javascript
values = range.getValues();
```

#### データの更新
`setValues(values)`によって二次元配列でデータを更新出来ます。

```javascript
range.setValues(values);
```

## トリガー
GASには特定のイベントで関数を実行するトリガー機能が存在します。
GASのトリガーは、大きく分けて2種類に分けれます。

|  種類  |  説明  |
| ---- | ---- |
|   シンプルトリガー  |  決められた関数名とイベントで発火する  |
|  インストーラブルトリガー  |  画面からトリガーを設定し、条件を満たしたときに発火する  |
それぞれ例を交えながら説明します。

### シンプルトリガー
シンプルトリガーとは、決められ関数名とイベントで発火するトリガーです。
例えば、`onOpen` 関数を作成すると、関数を設定したスプレッドシート等を開いたタイミングで関数が発火します。

```javascript
 function onOpen() {
    Browser.msgBox('Open');
 }
```

上記の関数を設定すると、スプレッドシートを開いたタイミングでメッセージボックスが出力されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/e25764a9-628a-50d8-e3e7-50bb2d0896cd.png)
「編集した時に」発火するトリガーもありますで、Googleフォームの回答をスプレッドシートの記述、それをトリガーに回答内容をslackに飛ばすことも実現できるかと思います。

他にもシンプルトリガーは色々あるので、気になる方は以下のドキュメントを御覧ください。
[Simple Triggers  |  Apps Script  |  Google Developers](https://developers.google.com/apps-script/guides/triggers)

### インストーラブルトリガー
インストーラブルトリガーは、画面から条件を設定します。
例えば、時間主導型タイマーが挙げられます。
設定するには、サイドバーの「トリガー」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/bc9a3032-f48f-428b-23d7-544542f7ae81.png)
次に、右下の「トリガーの追加」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/bfbe5943-7afa-bb47-0ee2-12865f6e80fc.png)
画面上でトリガーを追加することが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/5f75efb3-5661-f513-bffd-ca1f75365da3.png)

他にもシンプルトリガーは色々ありますが、気になる方は以下のドキュメントを御覧ください。
[Installable Triggers  |  Apps Script  |  Google Developers](https://developers.google.com/apps-script/guides/triggers/installable)

## スタンドアロンスクリプトとコンテナバインドスクリプト
GASのスクリプトは大きく2つに分けられます。

|  種類  |  説明  |
| ---- | ---- |
|  コンテナバインドスクリプト  |  スプレッドシートやドキュメントなどの親ファイル(コンテナ)と紐づくスクリプト  |
|  スタンドアロンスクリプト  |  単体で独立しているスクリプト  |

### コンテナバインドスクリプト
コンテナバインドスクリプトとは、スプレッドシートやドキュメントなどの親ファイル(コンテナ)と紐づくスクリプトです。
これまで使ってきたものはこちらになります。
コンテナバインドスクリプトを使うと、getActiveSpreadsheetのようなアクティブなオブジェクトを取得するメソッド等、紐付いたファイルに対するメソッドを実行することが出来ます。

### スタンドアロンスクリプト
スタンドアロンスクリプトとは、コンテナと紐付けず単体で存在するスクリプトです。
Google翻訳を単体で利用するときなど、コンテナと紐付けを行わない時に使用します。

作成はドライブから行います。「新規」→「その他」→「Google Apps Script」と選択していくことで作成出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/b5caafaa-a329-9736-71e8-0c88883efb89.png)

### 結局どちらを使うべきか
コンテナバインドスクリプトをメインに使っていき、コンテナバインドが使いづらい状況でスタンドアロンスクリプトを使っていくのが良さそうです。

## その他のTips
その他自分が知られて良かったと感じるTipsです。今回は概要に留めます。

### SpreadsheetAppクラスから直接Sheetを取得する
これはもはや本編に加えたかった内容なんですが、、、
一段飛び越えてSpreadsheetAppクラスからアクティブなSheetを取得するメソッドも存在します。

```javascript
const sheet = SpreadsheetApp.getActiveSheet();
```
ただし、シートは複数存在する可能性があるので、シートが1つしか無いとき等、確実に目当てのシートがアクティブになっているときに利用するのが無難です。

### コードのバージョン管理について
コードをGitHubで管理したくなると思いますが、その時の選択肢としては2つ挙げられます。

#### 1. [Google Apps Script GitHub アシスタント](https://chrome.google.com/webstore/detail/google-apps-script-github/lfjcgcmkmjjlieihflfhjopckgpelofo?hl=ja)
 
スクリプトエディタの上にボタンが作成され、GitHubへの操作が行えるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217116/eeba7637-7272-725c-2583-a480c606b626.png)

#### 2. [clasp](https://github.com/google/clasp)
ローカルで開発を行い、`clasp push`等のコマンドを利用することでスクリプトエディタにコードをpush出来ます。
そのためローカルでは好きなエディタを使うことが出来ますし、いつもと同じようにGitHubを利用することが出来ます。(個人的にはこちらが好みです。)

使い方に関しては以下の記事が非常にわかりやすかったです。
[GAS のGoogle謹製CLIツール clasp - Qiita](https://qiita.com/HeRo/items/4e65dcc82783b2766c03)

## 最後に
今回の学習を通してGASで出来ることを把握出来たので、これから課題にぶつかった時に「GASの〜〜機能を使えば実現できそうだな」と考えられそうです。(もちろん本当にGASを使うべき場面かは考えていく必要はありますが)