オルタナティブ・ブログ > Cathedral Break in Action >

エンタープライズ(企業)向けのオープンソースとか育児とかについて考えていきます。

Google ドライブ上に事前投句システムを作ってみた

»

こんにちは。もう10月ですね。みなさん俳句作ってますか? 作ってますね?

作ってるならわかりますね? 5・7・5の間に空白開けたりしてないですよね? それだけは守ってくださいね! 

ああああ、待ってください。俳句作らなくてもこの記事には意味ありますから。もうすこし読んで!

はい、そんなわけで、今回は、ぼくが参加している句会で、Googleのサービスだけで句会のためのアプリケーションを作ってみて、けっこううまくいっちゃったのでそのことをシェアしようかと思います。

ああああ、待ってください。句会に出なくてももうちょっと読んで!

句会とは

さて、とはいえ、まず句会についてお話ししておく必要があります。句会では、参加者はお題に沿って俳句を作ってきます(当日その場で作る場合もありますが、今回は事前に作ってきます)。お題は「この季語をいれなさい」とか「この言葉を入れなさい」とか、これを兼題と言います。

で、一般的には、句会は会場に集まった参加者が作ってきた俳句を、匿名の形にしてリスト化するところからはじまります。具体的には短冊に一句ずつ無記名で書いたものを集め、そのままだと筆跡で作者が分かってしまうので、それをさらに参加者全員で分担して、清記用紙に転記します。これで、転記者の筆跡になるので、各俳句は作者が分からなくなります。

_thumb3

俳句だけのリストが作られて、はじめてどの句が良いとかどの句がひどいとか好き勝手に話ができるようになります。あくまでも句に対してモノをいうのであって作者が分からなくなることの意味がここにあります。このへんの話も面白いんですが、今回のシステムと関係ないので省略します。

事前投句システムとは

さて、今回作ったのはこの、あらかじめ作ってきた俳句を集約してリストにする仕組みです。短冊に書いたものを集めて転記するのは時間がかかります。土日にやるような句会であれば、そういった時間がとれるのですが、我々は平日、仕事終わりに飲み屋で句会をやろうとしており、その時間がもったいなかった。そこで、俳句をあらかじめネット上で集めて、リストを印刷できるところまで持ってきておけばだいぶ時間が省略できると思ったんですね。

ただ、まとめ人が集約するような仕組みではその人には作者が分かってしまいますから、匿名という部分が担保できません。そこで、システムに集約を任せるような仕組みが必要だった、ということです。簡単に言えば、Webフォームを作って、そこに俳句を書き込んでもらい、〆切りまでに集まった俳句をランダムな並びにしてリスト化、印刷しておけばよいのです。

事前投句システムの仕組み

まずは、投句の仕組みから。これは Google のフォームを使いました。Google ドライブで、「フォームを新規作成」します。

Google--_thumb1[1]

項目として投句者名(あとで集計するときに使う)、お題1への投句、お題2への投句……といった単純なものを作成します。「回答者の送信後に回答の編集を許可」というところにチェックを入れておくと、一回投稿した俳句を〆切りまでであれば何回でも直せます。

さて、Google のフォームでは回答は自動的にスプレッドシートに回答をためることが出来ます(回答、といっているのが今回は俳句の投稿内容になるわけです)ただこれだけでは、誰が書いたかもの分かってしまいますから、この後の「匿名にする」「ランダムな並びにする」「リスト化する」を自動化する必要があります。

スクリプトを書く

スクリプトを使います。フォームを編集する画面から、ツール-スクリプトマネージャという機能を呼び出します。

Google----_thumb3

ここで次のようなスクリプトを書きました。

function main() {
  var form = FormApp.getActiveForm();
  var responses = form.getResponses();
  var haiku;
  var haikus = new Array();
  for (var i = 0; i < responses.length; i++) {
    var response = responses[i];
    var itemResponses = response.getItemResponses();
    for (var j = 2; j < itemResponses.length-1; j++) {
      var itemResponse = itemResponses[j];
        haiku = itemResponse.getResponse();
        haikus.push(haiku);
     }
    Logger.log(response.getEditResponseUrl());
  }
 
  rHaikus = shuffle(haikus);
  Logger.log(rHaikus);
 
  var sheetName = "選句評"
  var spreadSheetId = form.getDestinationId();
  var spreadSheet = SpreadsheetApp.openById(spreadSheetId);
  var oldSheet = spreadSheet.getSheetByName(sheetName);
  if (oldSheet != null) {
     spreadSheet.deleteSheet(oldSheet);
  }
  var sheet = spreadSheet.insertSheet(sheetName);
  sheet.getRange(1, 1).setValue("選句表");
 
  for (var k = 0; k < rHaikus.length; k++) {
    sheet.getRange(k + 3, 1).setValue(rHaikus.length - k);
    sheet.getRange(k + 3, 2).setValue(rHaikus[k]);
  }
 
  var sheetName2 = "投句リスト"
  var oldSheet2 = spreadSheet.getSheetByName(sheetName2);
  if (oldSheet2 != null) {
     spreadSheet.deleteSheet(oldSheet2);
  }
  var sheet2 = spreadSheet.insertSheet(sheetName2);
  sheet2.getRange(1, 1).setValue("投句リスト");
 
  for (var k = 0; k < rHaikus.length; k++) {
    sheet2.getRange(k + 1, 1).setValue(rHaikus.length - k);
    sheet2.getRange(k + 1, 2).setValue(rHaikus[k]);

  } 
}

function shuffle(arr) {
    var i = arr.length;
    while(i){
        var j = Math.floor(Math.random()*i);
        var tmp = arr[--i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    return arr;
}

function sendConfirmMail() {
  var form = FormApp.getActiveForm();
  var responses = form.getResponses();
 
  //最後のレスポンスを取る
  var response = responses[responses.length-1];
  var itemResponses = response.getItemResponses();
 
  var subject = "投句完了メール";
  var to = itemResponses[0].getResponse();
 
  var body = "以下の内容で投句されました。\n\n";
  for (var j = 0; j < itemResponses.length; j++) {
    var itemResponse = itemResponses[j];
   
    var questionItem = itemResponse.getItem();
    var title = questionItem.getTitle();
    body += title;
    body += "\n";
   
    var answer = itemResponse.getResponse();
    body += answer;
    body += "\n\n";
    if(title == "確認メールの送付先"){
      to = answer
    }
  }

  body += "投句修正URL\n";
  var editUrl = response.getEditResponseUrl();
  body += editUrl;

 var options = {};
  options.replyTo = "****@gmail.com";
 
  if(to){
    MailApp.sendEmail(to, subject, body, options);
  }
}

スクリプトの解説

そんなに難しい内容じゃありませんので、細かい説明はしませんが、簡単に。Googleドライブでフォームを作ると、規定では投稿されたデータは下記のようにスプレッドシートに転記されていきます。

Google--_thumb1

この図でいうとD列E列が投句された俳句です。スクリプトで明示的にmainファンクションを呼ぶと、投句された俳句がリスト化し、ランダムな並びにして、違うシートに転記されます。

なお、投句があるとユーザが投句を修正できるよう確認メールを送っています。sendConfirmMailがそのファンクションです。これをやるにはトリガーを使います。リソースから、現在のプロジェクトのトリガーを選択します。

_thumb

イベントを追加して「フォームから」「フォーム送信時」にsendConfirmMailが呼ばれるように設定します。

_thumb1

このメール送るのは、投句システムそのものとは関係ない仕組みですが、いろいろ便利です。デフォルトだとユーザは回答直後の画面で修正URLが見られるのですが、ブラウザを閉じてしまうとそれがわからなくなってしまうんですよね。なのでメールで通知するようにしました。コードが汚くてすいません。

足りないところ

これで投句リストができました。本来はこれをそのまま印刷してもっていきたいところなのですが、俳句は縦書きのリストにするひつようがあり、そこだけがどうしてもうまくできません。なのでダサいんですが、Excelで落として加工して印刷することにしました。Googleさんが縦書きに対応してくれれば、印刷用データのみになるのになー

あと、もう一つ足りないところで、このあと進化させたいなと思っているのは、フォーム自体を生成するメタフォームですね。現在はお題とかを決めた後、フォームを手で作成する必要があります。しかし、このフォーム、1番目の入力欄がメールアドレスで、2番目がお題1で、3番目がお題2で、というふうに定型化されています(お題の数だけが不定です)。なので、今回のお題はこれとこれとこれ、と入力することで、投稿フォーム自体が自動的に生成され、そのURLが通知されるようにできるのがベストですよね。

現状だと、上記スクリプトも投句フォームごとにコピーする必要があるのでフォームごとに微妙に手直ししちゃったりして最新版がちゃんと管理できてないです。フォームを生成するためのメタフォームが出来れば、メタフォームのみにスクリプトを所属させておけば、管理も簡単になると思います。

まとめ

Googleドライブはスゴイ!

これにつきます(あれ、これって「ドライブ」がスゴイ!でいいのかな? これらのサービスをまとめる名称がよく分かってませんが)。これくらい単純な動的Webサービスであればあっというまにできてしまいますね。JavaScriptは書いたことがなくても言語が1つ出来ればべつに難しくはありません。UI=フォーム、データベース=スプレッドシート、という考え方で、ロジックをスクリプトとして書けばすみます。上記のしくみもトータル数時間で作れてしまいました。

また仕組みが洗練されたらこちらで紹介したいと思います。

Comment(0)