プロが書く美しいコードじゃない、素人の稚拙なコードだからこそ、得られるものだってきっとある…そんな思いでコードを公開しています。どうぞ生暖かく見守ってください。

一連の処理をまとめて別の関数を作成する~functionの作成と結果の受け渡し

[tool1]フォームをシートに書き出しGoogle Apps Script
  • functionって?
  • プロジェクトに新たにスクリプトを追加する
  • 引数・戻り値
  • return

前回、switchを使って一気にアイテムタイプをキャストし、選択肢ありなしや配点設定可能かどうかなどの共通処理ごとに0、1でラベリングしていきました。

ただ、この作業だけでもアイテムタイプが全部で17種類であるため、コードが長くなってしまい、少し見づらくなりました。

そこで今回は、一つの処理をまとめて関数(function)としてくくり、別の場所に置いておいて必要な時に呼び出せる形を作成しようと思います。

この、関数(function)の考え方、苦手でした。。関数同士で変数の受け渡しをするために、持ち出す変数と、持って帰ってくる変数があるのですが、定義の形がイメージしづらいのです。

私自身の頭の整理も兼ねて、なるべくわかりやすい言葉を使って説明してみたいと思います。

まず、ひとくくりにする処理は、swichの部分です。

   //swichによりそれぞれのアイテムにキャスト
    switch (itemType) {
      case itemType.CHECKBOX:
        testPartsItem = itemparts.asCheckboxItem();
        hasChoice = 1;
        hasPoint = 1;
        break;
      case itemType.CHECKBOX_GRID:
        testPartsItem = itemparts.asCheckboxGridItem();
        break;
      case itemType.DATE:
        testPartsItem = itemparts.asDateItem();
        hasPoint = 1;
        break;
      case itemType.DATETIME:
        testPartsItem = itemparts.asDateTimeItem();
        hasPoint = 1;
        break;
      case itemType.DURATION:
        testPartsItem = itemparts.asDurationItem();
        hasPoint = 1;
        break;
      case itemType.GRID:
        testPartsItem = itemparts.asGridItem();
        break;
      case itemType.IMAGE:
        testPartsItem = itemparts.asImageItem();
        break;
      case itemType.LIST:
        testPartsItem = itemparts.asListItem();
        hasChoice = 1;
        hasPoint = 1;
        break;
      case itemType.MULTIPLE_CHOICE:
        testPartsItem = itemparts.asMultipleChoiceItem();
        hasChoice = 1;
        hasPoint = 1;
        break;
      case itemType.PAGE_BREAK:
        testPartsItem = itemparts.asPageBreakItem();
        break;
      case itemType.PARAGRAPH_TEXT:
        testPartsItem = itemparts.asParagraphTextItem();
        hasPoint = 1;
        break;
      case itemType.SCALE:
        testPartsItem = itemparts.asScaleItem();
        hasPoint = 1;
        break;
      case itemType.SECTION_HEADER:
        testPartsItem = itemparts.asSectionHeaderItem();
        break;
      case itemType.TEXT:
        testPartsItem = itemparts.asTextItem();
        hasPoint = 1;
        break;
      case itemType.TIME:
        testPartsItem = itemparts.asTimeItem();
        hasPoint = 1;
        break;
      case itemType.VIDEO:
        testPartsItem = itemparts.asVideoItem();
        break;
    }

この処理を行うためにあらかじめ用意しておかなければならない値は

  • itemType:アイテムタイプの情報(確認用)
  • itemparts:Itemsから取り出した要素(タイプごとに汎用Item→各要素にキャストするため)

の2つの値になります。

そして、この関数の処理を終えたら、持ち帰る値は

  • testPartsItem:各要素にキャストされた変数
  • hasChoice:選択肢の有無
  • hasPoint:配点できるかどうか

の3つになります。

では、早速コードをfunctionの外に移動させて、新たなfunctionとして定義します。

googleスクリプトでは、ひとつのプロジェクトで複数箇所に分けてコードを書くことができます。

ファイルの「+」ボタンを押して「スクリプト」を追加します。

ファイル名はなんでもいいです。わかりやすい名前をつけておきましょう。

スクリプトの中のfunction名を変更します。

function switchItemType(){}

functionの後のカッコ()の中に、よそから持ってくる変数(つまり、このfunction内では定義されていない変数)を必要な数だけ用意します。

中のコードの書き換えが面倒なので、そのまま(itemType,itemparts)とします。

function内で新たに設定される変数の宣言も、このfunction内に移動します。

function switchItemType(itemType,itemparts) {
  let hasChoice = 0;
  let hasPoint = 0;
  let testPartsItem;

あとは、switchでアイテムタイプごとにキャストされたtestPartsItemと、選択肢の有無(hasChoice)、配点設定の有無(hasPoint)の値を持ち帰ります。

処理が終了して元の関数にお土産を手に戻る際には、returnを使用します。

例: return testPartsItem;

ただし、returnで持ち帰ることができるデータ(変数)は1つだけです。そして、returnを使用できるのは1度だけになります。return以降の処理は行われず、直ちに元の関数にもどります。

なので、持ち帰りたい変数が複数ある場合には、それぞれを配列[]の中に入れてまとめて持ち帰ります。

 return [testPartsItem, hasChoice, hasPoint];

さて、これでfunctionの中身は整いました。

あとは元の関数からこの関数(switchItemType)を呼び出します。

このように書きます。

 switchItemTypereturn = switchItemType(itemType, itemparts);

()内に、持っていく関数を入れて、実行結果([testPartsItem, hasChoice, hasPoint])をswitchItemTypereturnに格納します。

実行すると、switchItemTypereturnの中身はこんな感じになりました。

[TextItem, 0.0, 1.0]

あとはそれぞれをもとのように変数に展開すればプログラムの続きを処理できます。

testPartsItem = switchItemTypereturn[0];
hasChoice = switchItemTypereturn[1];
hasPoint = switchItemTypereturn[2];

いかがでしょうか。

もちろん、前回のまま同じfunction内で処理しても問題なしですが、今回はfunctionの構造を理解するためにも、あえて一連の処理を別のfunctionに切り出してみました。

今回修正したコード(メイン)

function myFunction() {

  // フォームを開く
  const form = FormApp.openByUrl(フォームのURL);
  // URLは'https://docs.google.com/fo******/edit'のように''で囲んで入力

  //フォームの要素を配列で取得
  const items = form.getItems();

  //スプレッドシートを開く。
  const spsheet = SpreadsheetApp.openByUrl(シートのURL);
  // URLは'https://docs.google.com/fo******/edit'のように''で囲んで入力
  const sheet = spsheet.getActiveSheet();
  //処理を加えるシートとして、ファイルを開いて最初に表示される(アクティブな)シートを設定

  sheet.clear(); //シートの内容をクリア

  //シートに行を追加し、formタイトル入力
  sheet.appendRow(['フォームタイトル', form.getTitle()]);
  // 項目タイトル行を作成
  sheet.appendRow(['アイテムタイプ', '質問内容']);

  for (let i = 0; i < items.length; i++) {
    //Item数をiと置き換えて、iを0から順番に項目の数だけ1ずつ増やす
    const itemparts = items[i]; //itemという配列のi番目の要素をitempartsとして取り出す。
    const itemType = itemparts.getType(); //取得したitempartsのタイプを確認してitemTypeに保管
    const itemText = itemparts.getTitle();//取得したitempartsの質問内容を確認してitemTextに保管
    let itemSheetinput = [itemType, itemText]; // ↑入力ではなく一旦配列に格納

      ////アイテムタイプ判別とキャストの操作は別function;switchItemTypeに移動

    switchItemTypereturn = switchItemType(itemType, itemparts);

    testPartsItem = switchItemTypereturn[0];
    hasChoice = switchItemTypereturn[1];
    hasPoint = switchItemTypereturn[2];

    Logger.log('testPartsItem'); //ログを確認
    Logger.log(testPartsItem); //ログを確認

    //選択肢取得処理開始
    if (hasChoice == 1) {
      const choices = testPartsItem.getChoices(); //選択肢を取得
      const choicesText = choices.map(x => x.getValue()); //選択肢のテキストを取得
      itemSheetinput = itemSheetinput.concat(choicesText); //アイテムタイプや質問内容の配列と合体
      Logger.log(itemSheetinput); //ログを確認
    }
    sheet.appendRow(itemSheetinput); //まとめてシートの新しい行に入力
  }
}

移動後の別function

function switchItemType(itemType, itemparts) {
  Logger.log('もってきたItemは');
  Logger.log(itemType);
  let hasChoice = 0;
  let hasPoint = 0;
  let testPartsItem;
  //swichによりそれぞれのアイテムにキャスト
  switch (itemType) {
    case itemType.CHECKBOX:
      testPartsItem = itemparts.asCheckboxItem();
      hasChoice = 1;
      hasPoint = 1;
      break;
    case itemType.CHECKBOX_GRID:
      testPartsItem = itemparts.asCheckboxGridItem();
      break;
    case itemType.DATE:
      testPartsItem = itemparts.asDateItem();
      hasPoint = 1;
      break;
    case itemType.DATETIME:
      testPartsItem = itemparts.asDateTimeItem();
      hasPoint = 1;
      break;
    case itemType.DURATION:
      testPartsItem = itemparts.asDurationItem();
      hasPoint = 1;
      break;
    case itemType.GRID:
      testPartsItem = itemparts.asGridItem();
      break;
    case itemType.IMAGE:
      testPartsItem = itemparts.asImageItem();
      break;
    case itemType.LIST:
      testPartsItem = itemparts.asListItem();
      hasChoice = 1;
      hasPoint = 1;
      break;
    case itemType.MULTIPLE_CHOICE:
      testPartsItem = itemparts.asMultipleChoiceItem();
      hasChoice = 1;
      hasPoint = 1;
      break;
    case itemType.PAGE_BREAK:
      testPartsItem = itemparts.asPageBreakItem();
      break;
    case itemType.PARAGRAPH_TEXT:
      testPartsItem = itemparts.asParagraphTextItem();
      hasPoint = 1;
      break;
    case itemType.SCALE:
      testPartsItem = itemparts.asScaleItem();
      break;
    case itemType.SECTION_HEADER:
      testPartsItem = itemparts.asSectionHeaderItem();
      break;
    case itemType.TEXT:
      testPartsItem = itemparts.asTextItem();
      hasPoint = 1;
      break;
    case itemType.TIME:
      testPartsItem = itemparts.asTimeItem();
      hasPoint = 1;
      break;
    case itemType.VIDEO:
      testPartsItem = itemparts.asVideoItem();
      break;
  }
  Logger.log('testPartsItem, hasChoice, hasPointの結果'); //ログを確認
  Logger.log([testPartsItem, hasChoice, hasPoint]);
  return [testPartsItem, hasChoice, hasPoint];
}

だんだんプログラム書いてる感が出てきていますね 笑

このコードにさらに、配点・正解・解説が取得できるように肉付けをしていきたいと思います。

コメント

タイトルとURLをコピーしました