Googleクラウドサービスを利用して時間指定メール送信システムを作る（その３）

***
＜[前へ](http://qiita.com/matsuhandy/items/ffb717bfb07417c05e4e)＞　＜[次へ](http://qiita.com/matsuhandy/items/0c1bf9e673412dac5135)＞
　プログラムを作る上で，実行結果などをlogとして記録できると楽です。クラスを使ってlogを残せるようにしてみます。
***
#1. プログラムのデバックのためlogファイルを作る
##1.1 クラスを使わない例

* デバッグやエラーを出力するlogファイルを作成。新規，から，Googleドキュメント，を選択し，ドキュメントを新規作成する。

![画像1.png](https://qiita-image-store.s3.amazonaws.com/0/146927/c1cd8b77-382a-775c-eabd-f2e954d7b6ba.png)

* 名前を「log」に変更する。勝手に保存される。

![画像20.png](https://qiita-image-store.s3.amazonaws.com/0/146927/e7a2c8f0-f53e-ba14-9fb1-5e57d194ad84.png)

* ドライブを確認すると，logができている。

![画像1.png](https://qiita-image-store.s3.amazonaws.com/0/146927/07d49506-0073-6d6a-13f6-bc8f1a32d242.png)

* logをダブルクリックすると開く。（閉じた場合は開いておく）
* logに実行ログを書き込んだり，エラーを書き込んだりするので，開発中はlogを開いたままにしておくとよい。
* GASプログラムはフロッピーマークをクリックして自分で保存する。保存し忘れても次回起動時に保存されてないものを復活させるかどうか聞かれるので慌てる必要はない。
* logのファイルIDをコピーし，あとで使用するため，エディタ等に貼り付けておく。

![画像1.png](https://qiita-image-store.s3.amazonaws.com/0/146927/eb01a9e3-cc6a-1e77-bccb-f443ad9863b1.png)

* Google Apps Scriptを新規作成する。

![画像1.png](https://qiita-image-store.s3.amazonaws.com/0/146927/e18bbbbc-1ac0-b2e9-44f0-7ffb6aa4a181.png)

* 名前を nonClassTest に変更し，コード.gsに書かれている4行は全削除。

![画像7.png](https://qiita-image-store.s3.amazonaws.com/0/146927/132e964e-bc50-0e93-4745-3fce67660a95.png)

* 次のプログラムをコピーペーストする。**********の部分は，logのファイルIDに置き換える。

```java:実行ログを残すプログラム，クラスを使ってない
var logID = "**********";//事前にドキュメントを作りIDをしらべておく

function main(){
  var log = DocumentApp.openById(logID);
  //clearDoc(log);//logをクリアしたい場合に有効にする，延々とlogを残す場合は不要
  printDoc(log,"ログ記録を開始\n");
  printDoc(log,"今日の天気は<Weather>です。\n");
  replaceDoc(log, "<Weather>","晴れ");
  var str = "Good Morning";
  words = str.split(' ');
  printDoc(log, words[1]+'\n');
  printDoc(log,"ログ記録を終了\n");
}

//-----------------------デバッグ用の関数群
function clearDoc(doc){//docの中身を全部削除
  var body = doc.getBody();
  body.clear();
}

function printDoc(doc,str){//docにstrを書き込む
  var body = doc.getBody();
  var docText = body.editAsText();
  docText.appendText(str);
}

function replaceDoc(doc,src,dst){//srcをdstにリプレイス
  var body = doc.getBody();
  body.replaceText(src,dst);
}

function saveAndCloseDoc(doc){//使う必要はほぼない
  doc.saveAndClose();
}
```

* 次のようにして，main関数を実行する。実行時には自動保存されるが，実行前にフロッピーディスクマークをクリックして保存する癖を付けると良い。（保存・実行保存し忘れても次回起動時に変更を有効にするかどうか聞かれる）
* 許可・承認を求められた場合は，内容を確認して許可する。

![画像9.png](https://qiita-image-store.s3.amazonaws.com/0/146927/9ee22b5b-1138-b09f-cc06-993c5bd60210.png)

* 実行結果は次の通り。

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/146927/26049e5d-c4c0-2ea4-e9c0-8a924130827b.png)

* 関数replaceDocについては，logを残すだけなら使うことはない。こういうこともできるよ，というサンプル。






##1.2 クラスを使った例

* Google Apps Scriptを新規作成する。
* 名前を classTest に変更し，コード.gsに書かれている4行は全削除。
* 下をコピーペースとして同様に実行すると，同じ実行結果となる。
* **********の部分は，logのファイルIDに置き換える。

```java:実行ログを残すプログラム，クラスを使っている
var logID = "**********";//事前にドキュメントを作りIDをしらべておく

function main(){
  var log = new Doc(logID);
  //log.clear();//logをクリアしたい場合に有効にする，延々とlogを残す場合は不要
  log.print("ログ記録を開始\n");
  log.print("今日の天気は<Weather>です。\n");
  log.replace("<Weather>","晴れ");
  var str = "Good Morning";
  words = str.split(' ');
  log.print(words[1]+'\n');
  log.print("ログ記録を終了\n");
  
  
}

//newでオブジェクト生成時に実行されるコンストラクタ（初期化する関数）
//クラス名は最初の文字を大文字にするのが一般的なルール
Doc = function(id){
  this.ID = id;
  this.doc = DocumentApp.openById(this.ID); 
  this.body = this.doc.getBody();
  this.docText = this.body.editAsText();
}
//メンバ関数（メソッド）は，prototypeでつなげて定義する
//テキストの追加，単にログを追加するなど
Doc.prototype.print = function(str){
  this.docText.appendText(str);
}
//キーワード等をリプレイス
Doc.prototype.replace = function(src,dst){
  this.body.replaceText(src,dst);
}
//中身をクリア
Doc.prototype.clear = function(){
  this.body.clear();
}
//IDを返すメソッド
Doc.prototype.getID = function(){
  return this.ID;
}

//ここから下は参考，作ったけどあまり使いそうもない
/*
Doc.prototype.close = function(){
  this.doc.saveAndClose();
}

Doc.prototype.getDoc = function(){
  return this.doc;
}

Doc.prototype.getBody = function(){
  return this.body;
}

Doc.prototype.getText = function(){
  return this.docText;
}
*/
/*
//参考文献
http://www.yunabe.jp/docs/javascript_class_in_google.html
*/
```

* クラスは，コンストラクタと関数定義でできている。
* `var log = new Doc(logID);`によりDocクラスのインスタンス（オブジェクト）が生成される。
* 生成されると，とりあえずコンストラクタが実行される。

```java:コンストラクタ
Doc = function(id){
  this.ID = id;
  this.doc = DocumentApp.openById(this.ID); 
  this.body = this.doc.getBody();
  this.docText = this.body.editAsText();
}
```

* コンストラクタは，次の形で定義する。引数はあってもなくてもよい。

```java:コンストラクタ定義の形
クラス名 = function(引数){
  ･･･
}
```

* thisはnewで生成された，インスタンスを指す。つまりいつか作られるであろうインスタンスに対して，そのインスタンスが使用する変数を用意するのに，`this.ID`などとしている。thisがあれば，varは不要。
* メソッド（メンバ関数）は，次のように定義する。引数はあってもなくても良い。

```java:メソッド定義の形
クラス名.prototype.関数名 = function(引数){
  ･･･
}
```

* これで，Google Apps Scriptの実行ログが残せるようになった！！
* ちなみに，ドキュメントを二つ作っておいて，次のようにmainの中で簡単に二種類のログを残すこともできる。これでthisの意味が理解しやすい。
* **********，++++++++++は，あらかじめ手動でドキュメントを作成しておき，そのIDに置き換える。
* クラスを利用することで面倒な手続が，カプセル化（ブラックボックス化）されて，mainの中がすっきりする。
* 関数でちまちま書いても良いが，クラスで丁寧に記述するとプログラムの見通しが良くなるし，楽になる。

```java:Docクラス
var log1ID = "**********";
var log2ID = "++++++++++";

function main(){
  var log1 = new Doc(log1ID);
  var log2 = new Doc(log2ID);
  log1.print("log1に書き出し\n");
  log2.print("log2に書き出し\n");
  
}

//////////Docクラスの定義開始（コンストラクタとメンバ関数で構成）
//Docクラスのコンストラクタの記述
Doc = function(id){
  this.ID = id;
  this.doc = DocumentApp.openById(this.ID); 
  this.body = this.doc.getBody();
  this.docText = this.body.editAsText();
}
//Docクラスのメンバ関数の定義開始
//メソッドprintの定義，テキスト追加
Doc.prototype.print = function(str){
  this.docText.appendText(str);
}
//メソッドreplaceの定義，文字列置き換え
Doc.prototype.replace = function(src,dst){
  this.body.replaceText(src,dst);
}
//メソッドclearの定義，全消去
Doc.prototype.clear = function(){
  this.body.clear();
}
//メソッドgetIDの定義，ファイルIDを返す
Doc.prototype.getID = function(){
  return this.ID;
}
//////////Docクラスの定義終了

```

* 実行時やデバック時のログを残すのに便利なDocクラスとしてまとめておく。
* 時間を遅らせて表示したい場合があるので，ウェイト関数を追加。不要な場合は削除して構わない。

```java:デバッグや実行時のログを残すためのクラスDoc
//////////Docクラスの定義開始（コンストラクタとメンバ関数で構成）
//Docクラスのコンストラクタの記述
Doc = function(id){
  this.ID = id;
  this.doc = DocumentApp.openById(this.ID); 
  this.body = this.doc.getBody();
  this.docText = this.body.editAsText();
}
//Docクラスのメンバ関数の定義開始
//メソッドprintの定義，テキスト追加
Doc.prototype.print = function(str){
  this.docText.appendText(str);
}
//メソッドreplaceの定義，文字列置き換え
Doc.prototype.replace = function(src,dst){
  this.body.replaceText(src,dst);
}
//メソッドclearの定義，全消去
Doc.prototype.clear = function(){
  this.body.clear();
}
//メソッドgetIDの定義，ファイルIDを返す
Doc.prototype.getID = function(){
  return this.ID;
}
//指定秒数のウェイト，表示動作を遅らせたい時などに使用
Doc.prototype.waitSec = function(sec){
  var start = new Date().getSeconds();
  while((new Date().getSeconds()-start) < sec);
}
//指定ミリ秒のウェイト，表示動作を遅らせたい時などに使用
Doc.prototype.waitMiliSec = function(msec){
  var start = new Date(); //new Date()は，「1970年1月1日午前0時」からの通算ミリ秒を返す
  while((new Date()-start) < msec);
}
//今現在の日時を表示
Doc.prototype.printTodayNow = function(){
  var now = new Date();
  var year = now.getYear();
  var month = now.getMonth() + 1;
  var day = now.getDate();
  var hour = now.getHours();
  var min = now.getMinutes();
  var sec = now.getSeconds();
  this.docText.appendText(year +'_'+ ("0"+month).slice(-2) +'_'+ ("0"+day).slice(-2) +' '+ 
    ("0"+hour).slice(-2) +'-'+ ("0"+min).slice(-2) +'-'+ ("0"+sec).slice(-2));
}
//////////Docクラスの定義終了
```


***
　せっかくクラスを作ったので，次では，もう少しかっこよくドキュメントを作れるようにします。logを残すだけなら，上のクラスで十分です。ウェイトするメソッドも普通は不要です。
＜[前へ](http://qiita.com/matsuhandy/items/ffb717bfb07417c05e4e)＞　＜[次へ](http://qiita.com/matsuhandy/items/0c1bf9e673412dac5135)＞
***