[GAS] ライブラリの仕様をまとめてみる

# ライブラリってなに？

> **ライブラリ**（英: library）は、汎用性の高い複数のプログラムを再利用可能な形でひとまとまりにしたものである。ライブラリと呼ぶときは、それ単体ではプログラムとして動作させることはできない、つまり実行ファイルではない場合がある。ライブラリは他のプログラムに何らかの機能を提供するコードの集まりと言える。
> 出典: [Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA)

数学の公式がプログラム（一般的には関数）だとすれば、「三角形の面積」「長方形の面積」「円の面積」のそれぞれを導出する公式（＝プログラム）を「面積を求める公式」としてまとめたものがライブラリです。
ライブラリの中にあるプログラム（区別するため「`機能`」とします）は、それら`機能`を使う複数のプログラムから使うことを前提に作られています。`機能`の中身が単純であればその`機能`自体の価値は薄いですが、複雑になるとその価値は高まります。また、同一ライブラリに存在する複数の`機能`を同時に使う機会が多いほど、そのライブラリ自体の価値が高まります。
そういった理由から、ライブラリの多くは、場面を問わずに使える（汎用性が高い）プログラムを、共通のジャンルをもっているものや需要の重なっているものどうしでまとめたものとなっています。

# GASのライブラリ

GASにもライブラリを実装するメリットがたくさんあり、誰でもライブラリを作れるし、そのIDを知っていれば使えるようになっています。
**なお、ライブラリの作り方や導入手順はこの記事では取り上げず、あくまでもライブラリの仕様のみを取り上げます。ご了承ください。**
本記事でこれ以降「ライブラリ」と記すものはすべて「GASのライブラリ」、「プロジェクト」は「GASプロジェクト」を指します。

## GASライブラリの仕様

### 公開/公開設定

ライブラリ自体には公開設定がありませんが、プロジェクトファイルがGoogle Driveの中にあるので、ライブラリにアクセスできる範囲はプロジェクトファイルの公開設定に依存します。

### バージョン管理

GASプロジェクトには「デプロイ」機能があり、デプロイごとにバージョンが振られます。このバージョン管理はライブラリにも適用されるので、バージョンを指定してライブラリを使用することになります。
また、プロジェクトに対する編集権限を持っているユーザーは、同一のユーザーが作成した別のプロジェクト内で、そのライブラリを「開発モード（HEAD）」として使用できます。別のプロジェクトに更新があるたびに、ライブラリの最新の内容が適用されます。

<img width=12%><img width=76% src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687929/b340b6ff-2c82-477c-adb0-48597d56b363.png">

### ほかのライブラリの使用

普通のプロジェクト同様、ライブラリとしてデプロイしているプロジェクトでも、ほかのライブラリを使うことができます。この場合、呼び出し元でもそのライブラリを登録するという必要はありません。

### 環境変数もどき

GASのプロジェクトは、環境変数に似ている`PropertiesService`を使用することができます。
この`PropertiesService`には数種類のスコープがあり、以下のとおりです。

<img width=12%><img width=76% src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687929/ef85a686-8bcc-192b-ca47-1d19419bfac1.png">

ライブラリで使用できるのは`ScriptProperty`と`UserProperty`です。ドキュメントのアドオンとして使わない限り、`DocumentProperty`にはアクセスできません。

## 細かな仕様

### ライブラリに含まれない要素

非常に複雑なので、図にしました。
赤の要素はライブラリに含まれず、緑の要素はライブラリに含まれます。

<img width=12%><img width=76% src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687929/33a733c3-f399-4fa2-4f7e-e10384ab897a.png">


### スコープ

ひとつのプロジェクトに複数のスクリプトファイルが存在する場合でも、グローバルスコープはプロジェクト単位になっています。

### その他

呼び出す側でのライブラリのふるまいは、以下のようになります。

+ 呼び出す側のプロジェクト内でライブラリを参照する際に使用する名前を設定できます。<br>ここでは`ライブラリ名前空間`と呼ぶことにします。
+ ライブラリを登録していると、スクリプトの中に自動的に`ライブラリ名前空間`と同じ名前を持ったオブジェクトがグローバルスコープで変数として代入されます。<br>トリッキーなのは、このオブジェクト自体には**中身がない**ことです。これによって、ライブラリが使用しているライブラリを間接的に参照する方法がデフォルトでは存在しないようになっています。<br>
しかし、ライブラリ側に `globalThis` （グローバルオブジェクト自身）を返す関数を用意することで、間接的にほかのライブラリを参照できるようになります。また、プライベートな関数もグローバルスコープに属していると参照できてしまいます。

```js:ライブラリ.gs
var myVariable = "val";

function libFunction() {
  return myVariable;
}

function myPrivateFunction_() {
  return "this should be private";
}

function getGlobalThis() {
  return globalThis;
}
```

```js:呼び出し元.gs
// ライブラリ名: MyLibrary を ライブラリ名前空間 MyLib として登録
function myFunction() {
  console.log(MyLib);
  // {}

  console.log(MyLib.libFunction());
  // "val"

  console.log(MyLib.getGlobalThis());
  /*
  {
    a: "val",
    myPrivateFunction_: [Function: myPrivateFunction_],
    getGlobalThis: [Function: getGlobalThis]
  }
  */

  console.log(MyLib.getGlobalThis().myPrivateFunction_());
  // "this should be private"
}
```

# さいごに

訂正や、追記事項などありましたらコメントにて共有していただけると幸いです。