Google App Script 自動化

【GAS】ライブラリ化について

共通処理

Google App Scriptで処理を書いていると、共通した処理が見えてきます。これまで、Gmailで受信した注文情報をGoogleカレンダーに登録してきましたが、Amazon、楽天市場、Google Playの注文情報処理で共通した処理として以下の項目がありました。

  • メールにラベルを付ける処理
  • Googleカレンダーにイベントを新規登録する処理
  • Googleカレンダーに登録済みのイベント化チェックする処理

これらの処理を、毎回コードに記述しても良いのですが、その場合、機能追加やバグ修正を行う場合に複数のスクリプトを修正しなければなりません。修正箇所を局所的にした方がコードのメンテナンス性は高まるので、共通処理をライブラリ化し、各スクリプトから呼び出せるようにすることを考えます。

内部利用関数と公開関数

ライブラリ化の前に、内部利用のみの関数と外部に公開する関数について説明します。

ライブラリを作る際に以下のように外部に公開したくない場合があります。

  • 内部処理のみで利用して外部からアクセスさせたくない
  • ライブラリの使い方を分かりやすくするために内部関数を公開したくない

この場合、以下に示すように関数の最後に「_(アンダーバー)」を付けることによりライブラリ外部からアクセスできなくなります。

function InternalUseOnly_(){
  // 処理
}

Gmail処理用ライブラリ

処理済みのメールにラベルを付けるライブラリを考えます。

付与するラベルが定義されている場合は既存のラベルを利用し、ない場合は新たにラベルを追加します。

このスクリプトの名前を「libCtrlMail」とします。

/*
 * 処理済みとしてスレッドにラベルを付ける
 * 
 * LABELで指定されるラベルが存在しない場合は作成する
 */

// 処理済み後に付けるラベル名(ラベルが存在しなければ自動的に作られる)
var LABEL = '自動処理済';

function putLabel(thread){
  var label = GmailApp.getUserLabelByName(LABEL);
  if(label){
    thread.addLabel(label);
    Logger.log('既存ラベル使用');
  }
  else{
    var newlabel = GmailApp.createLabel(LABEL);
    thread.addLabel(newlabel);
    Logger.log('新規ラベル追加');
  }
}

Googleカレンダー処理用ライブラリ

Googleカレンダーに登録するライブラリも考えます。

カレンダーにイベントを登録する際に必要となる以下の情報が与えられたら登録します。

  • イベントタイトル
  • 開始日時
  • 終了日時
  • 詳細内容
  • 表示色

登録する際に既存のイベントがないかcheckExist_()関数にてチェックします。この関数は内部使用のみで公開する必要がないため、関数名の最後に「_(アンダーバー)」を付けます。

このスクリプトの名前を「libCtrlCalendar」とします。

/*
 * Google Calendarに登録
 */
function registCalendar(calendar, title, startTime, endTime, contents, color){
  if (title && startTime && endTime && contents) {

    // カレンダーに追加
    if(checkExist_(calendar, title, startTime, endTime) == false){
      var options = {
        description : contents
      }
      var event = calendar.createEvent(title, startTime, endTime, options);
      event.setColor(color);
      event.removeAllReminders();   // 利用実績なので通知しない
    }
  }  
}

/*
 * カレンダーに登録済みイベントがあるかチェック
 */
function checkExist_(calendar, registTitle, registStart, registEnd){

  // イベントリスト取得
  var events = calendar.getEvents(registStart, registEnd);
  for(const event of events){
    var title = event.getTitle();
    if(title.indexOf(registTitle) >= 0){
      return true;    // イベント登録済み
    }
  }
  // イベント未登録
  return false;
}

ライブラリの使用方法

libCtrlMailとlibCtrlCalendarを使用するためには以下の手順を踏みます。

  • ライブラリのIDを取得する
  • ライブラリを使うスクリプトに登録する
  • 「ライブラリ名.関数名」でライブラリ関数を利用する

ライブラリのIDを取得する

プロジェクトの設定から、スクリプトIDを取得します。

ライブラリを使うスクリプトに登録する

ライブラリを使用したいスクリプトを開き、左側に表示される「ライブラリ」の「+」をクリックします。

「スクリプID」に追加したいライブラリのスクリプトIDを追加して「検索」ボタンを押します。

追加したいライブラリが表示されたら「追加」ボタンを押します。

ライブラリ関数を呼び出す

「ライブラリ名.関数名」で呼び出せます。

//  Googleカレンダーに登録
libCtrlCalendar.registCalendar(
        calendar, 'Amazon注文', 
        startTime, endTime, contents, CalendarApp.EventColor.GREEN);

// メールに処理済みラベルを付ける
libCtrlMail.putLabel(thread);

Amazon注文内容のカレンダー登録

以下の記事で紹介したAmazon注文内容のカレンダー登録を修正します。

作成したライブラリを使用してコードを見直すと以下のようになります。

/*
 * Amazonの注文内容をGoogle Calendarに登録する
 * 
 * Google Calenderに以下のフォーマットで終日イベントが作成される。
 * 「Amazon注文」
 * 
 * 2021/09/15 Created by N.Sekiya
 * 2021/09/30 modified by N.Sekiya libCtrlMail, libCtrlCalendarを使用するよう修正
 */

// GMail検索文字列(Amazonからの注文確認メール)※未読でラベルなしが条件
var SEARCH_QUERY = 'is:unread -label:' + LABEL + ' from:digital-no-reply@amazon.co.jp subject:amazon.co.jp注文';

// 検索文字列
var FORWARD_MSG = '---------- Forwarded message ---------';

function registOrderInformationToCalendar() {

  // デフォルトカレンダーを取得
  var calendar = CalendarApp.getDefaultCalendar();

  var threads = GmailApp.search(SEARCH_QUERY, 0, 1);
  if (threads.length === 0) {
    Logger.log('メールが見つかりません');
    return;
  }

  for(var k in threads){
    var thread = threads[k]
    var messages = thread.getMessages();
    for (var j in messages){
      var message = messages[j];
      var body = message.getPlainBody();   // HtmlメールからPlain textの本文を取得する
      var startTime = message.getDate();
      var endTime = new Date(startTime.getTime() + 10 * 60000);
      //Logger.log("body=" + body);

      var contents = '';        // 登録内容
      var flgEnd = 0;           // 終了フラグ(0:続ける、1:処理しないで終了する)

      // 注文メールの内容確認
      var rows = body.split("\n");
      for (var i in rows) {
        var row = rows[i];
        if (row.indexOf(FORWARD_MSG) >= 0) {
          flgEnd = 1;
          break;
        } 

        contents = contents + row;
      }

      if(flgEnd){
        continue;
      }

      // Googleカレンダーに登録
      libCtrlCalendar.registCalendar(
        calendar, 'Amazon注文', startTime, endTime, contents, CalendarApp.EventColor.GREEN);

      // 処理済みメールとしてラベルを付ける
      libCtrlMail.putLabel(thread);
    }
  }
}

注文メールの内容処理のみになっているのがわかります。

この部分を楽天市場用、GooglePlay用に変更すればよいのも理解できるかと思います。

上記コードは、libCtrlMailとlibCtrlCalendarを使用することを前提としています。

注意点

ライブラリを使用すると、ライブラリ化しないで一つのスクリプトにすべての関数を実装する場合よりも、処理速度が遅くなります。

処理速度を重視する場合は、一つのスクリプトに全て記述することも必要になることに気を留めておきましょう。

最後に

関谷さんが20代の頃、先輩から言われたことがあります。

たくさん有用なライブラリを作成し、実現したい処理を短時間で実装できるようになることは、プロとして必要な行動だよ。

限られた時間の中で、成果を出すには必要な考え方ですね。

では、今日も良い一日を。

-Google App Script, 自動化
-, , ,