ちょっと気分をかえてみたくなり、今後の投稿はBloggerにしてみます。
http://blog.bagend.info/取りはしたものの、あまり有効に使えていなかった独自ドメインも使ってみました。
#けど、Google先生のご機嫌が悪いようなのでドメインを取り直しました。gooからFC2に移ったときと同様、過去の記事を遡って引っ越しとかはせず、向こうには今後の投稿だけ載ることになります。
また、ブログのテーマを変えたり、使い分けたりするということでもないので、今後も引き続きよろしくお願いします。
#最近、アニメやコミックの記事が書けてないhttp://code.google.com/googleapps/appsscript/ 使ってみてのまとめ。もう他の人がとっくに書いているだろうけど。
これは何?
GoogleがWebから使わせてくれるプログラム開発&実行環境。略称GAS。
GoogleにWebアクセスさえ出来れば、手元のPCに何もなくても使えるというのがウリです。
何が出来るの?
EXCELのVBA(マクロ)にあたるものと考えるのがふさわしいと思います。
Googleドキュメントのスプレッドシート(表計算)の中で、オリジナルのワークシート関数を作ったり、データを加工したり。
スプレッドシートの中のデータだけでなく、カレンダーやアドレス帳、メールなどGoogleの他のデータを読み書きできるのがウリ。
Googleの外のサイトへのアクセスも出来るので、テレビの番組表のデータを拾って一覧表にまとめるようなこともできるはず。
どうやって作るの?
Googleドキュメントのスプレッドシートにスクリプトエディタというメニューがあって、ここから作成します。
どうやって実行するの?
スクリプトエディタから直接実行するほか、スプレッドシートを開いたときに実行させる、メニューから実行させる、タイマーで何分おきに実行させる、データが編集されたら実行させる、などいろいろ。
スプレッドシートから作成した後、独立したサービスとして実行させることもできます。自分じゃ試してないですが。
どのような知識が必要?
文法はJavaScriptのそれに則っています。基本的な書き方は知っておく必要があるでしょう。
EXCEL等のVBAを使った経験があれば習得が早いと思います。が、未経験者がわざわざ回り道するほどでもないです。FileSystemObject等、後から新しい要素が盛り込まれてきているVBAよりGASのほうがスッキリ書けます。
カレンダーやアドレス帳などGoogleのデータを扱うなら、言語リファレンスを読む前にそのアプリをちょっとは使ってみてください。GASの言語リファレンスはほんとうに言語の部分しか説明していないので。
GUIの部品はGoogleWebToolkitのそれに準じています。イメージをビジュアルで見せてくれるギャラリーなどもWebToolkitにはあるので、まずはそちらを見てイメージをつかむのがいいと思います。
以上のいずれも、勉強し出すとキリがないです。自分のやりたいことと見合う範囲で。
コツ、あるいは注意点
文法こそJavaScriptですが、Googleのサーバ上で動作する点に注意が必要です。秒単位でのカウントダウンなど、画面をガシガシ書き換えるような処理には全く向いてません。画面を書き換える裏で通信も発生しています。その代わりに自分のマシンが非力だからといって処理速度が落ちることはないはず。もちろん、通信の速度が遅ければ別です。
上記の理由で、処理の進行表示などを細かくやるのは難しいです。GUIの取扱もまだまだ面倒ということもあり、自分はSpreadSheet.toast()メソッドを処理n件おきに発行することにしました。タイトル(太字)とメッセージの両方を設定できて、何秒間表示させるかのコントロールもできて助かりました。
Googleの中でのやりとりだから、Googleのデータの扱いも速いだろうと期待してましたが、現状それほどでもありません。スプレッドシートのセルを1個1個読み書きなどすると目に見えて、というより信じられないほど遅くなります。範囲指定で配列に一括で取り込むような工夫が必要です。こういう工夫はVBAでも必要なので、経験した人もいるといるでしょう。
オリジナルのワークシート関数を作れて、それを表中に埋め込めるのが大きな魅力です。が、外部サイトへのアクセスを伴う処理など、制限されているものもあります。セル1つ1つにそんな処理を入れられたら大変なことになるので当然ですね。開いたときにデータを取り込んで、それを使い回すみたいな回避策を検討する必要があるでしょう。
日付・時刻を扱うスクリプトにはタイムゾーンを設定しないと面白いことになります。Googleカレンダーの終日の予定などのように設定しても拾いきれない問題もあります。(これはGoogleカレンダーの情報の持ち方の問題なので…)
カレンダー、アドレス帳など、他のサービスへのアクセスにあたってはAPIの呼び出し回数制限があります。現状、何回までという基準も明示されておらず、GoogleAppEngineのように課金して制限を緩めてもらうみたいなこともまだできないようです。
困ったこと、要望など
バージョン管理システムがなく、サポートフォーラムでも要望として挙げられています。過去の履歴は一応たどれるのですが。
VBA同様、手軽さがウリということもあるので、業務用システムとして本格的な構成管理が求められる環境で使うには独自の工夫や根回しが必要だと思います。
ゴミ収集日カレンダーの作成ツール。
結局、日付がズレる問題は泥臭くクリアした。
あと、毎週○曜日の収集がある、燃やせるごみ、資源ごみはカレンダーを作成しないようにし、隔週あるいは月の第二○曜日みたいな予定に対象を絞った。APIの呼出し回数が多いとGoogle様が機嫌を損ねるし、その割りに予定を可視化するメリットが薄かったので。あまり多くの予定が並ぶと見た目にウザいというのも多少はある。
あとはユーザーインターフェースだ。
- Googleスプレッドシートのメニューから実行できるようにする。
- カレンダー作成、削除の進行表示のパネルを表示する。
ちなみにメニューはこんな感じに追加。

やってみたあと、あまりうまくなかったなと思ったのが次の点。
- 2.の作業から取りかかったのだが、1.からやったほうが良かった。実行するときにスプレッドシートが画面上一番手前に表示されていないと、せっかく作った進行表示パネルが表示されないみたいなのだ。メニューがないとスクリプトエディタ等、他の機能から呼び出すことになるので、せっかく作った画面を見ることができない。
- 進行表示は、何個中の何番目を処理中、1/29が2/29、3/29…みたいに刻々と変わっていく感じのシンプルなものにした。
…のだけど、実行しても全然表示が更新されていかない。Spreadsheet.show()でいちいち再表示させないといけないのか。また、一般的なJavaScriptと違い、GoogleAppsScriptはサーバー側で動く。そのため、画面の再表示に関してもいちいちネットワーク通信が発生するはず。しょうがないので、10個に1回の画面更新とかで勘弁してやる。
今でもまだうまくいってないのが次の点。
- GUIビルダで作ったパネルが、イマイチ不格好だ。サイズが正しく反映されてないか、使い方を間違っている気がする。
- 処理が終わって、UIInstance.close()してもパネルが消えてくれず、居座り続ける。
とりあえず今回の用に間に合うところまではいったけど、UIの作り方、使い方はもうちょっといろいろ試してみないと分らないなぁ。
日付がズレる件。
以下をチェックした。
(1) Googleスプレッドシートのタイムゾーン設定
(2) Googleカレンダーのタイムゾーン設定
(3) 作成する「ごみ収集カレンダー」のタイムゾーン設定
(4) GoogleAppsScriptエディタのタイムゾーン設定(!)
今回の場合は、まず(4)が抜けてた。
スプレッドシートとカレンダーの橋渡しをする機能にもタイムゾーン設定をしなければいけなかった。デフォルトのタイムゾーンは太平洋時間だったので、その分、時刻がズレて解釈される。
で、(4)を修整して再実行したものの、前ほど酷くはないがやはり日付がズレる。
テスト用のスクリプトを作ってみたのだけど、予定に開始終了時刻を設定せず、「終日の予定」とするとタイムゾーンの考慮が丸々抜け落ちるみたい。
(4)まで踏まえた上で、改めてググレカス先生にお伺いを立ててみたら、Google自身のヘルプフォーラム内で昨年から話題になっててガイジン達があーでもない、こーでもないとやっていた。(しかも、まだ収束してないっぽい)
今すぐナントカする必要に迫られている人は涙を呑んで、自分の居住地に合わせて、日付をプラス1したり、マイナス1したりしているみたい。
泥臭いけど、しょうがないよね。
追記 まず、何をもって「終日」とするかがワールドワイドなサービスでは難しいよね。予定を立てた国では感覚的に一日がかりでも、その後飛行機に乗って外国行っちゃえば、現地時間では深夜から翌朝にかけての予定になるかもしれないし。
function test() {
// TimeZone of CalendarApp
Logger.log('CalendarApp.TimeZone : ' + CalendarApp.getTimeZone());
// TimeZone of Default Calendar
var testCalendar = CalendarApp.getDefaultCalendar();
Logger.log('Deafult Calendar.TimeZone : ' + testCalendar.getTimeZone());
// Add New Event
testCalendar.createEvent('dummy', new Date('2011/06/20 0:00'), new Date('2011/06/20 01:00'));
// Add New All Day Event
testCalendar.createAllDayEvent('dummy-all-1', new Date('2011/06/20'));
// Add New All Day Event(with Time)
testCalendar.createAllDayEvent('dummy-all-2', new Date('2011/06/20 0:00'));
// Add New Event and set All Day
testCalendar.createEvent('dummy-all-3', new Date('2011/06/20 0:00'), new Date('2011/06/20 01:00'))
.setAllDayDate(new Date('2011/06/20 0:00'));
var testEvents = testCalendar.getEvents(new Date('2011/06/18'), new Date('2011/06/22'));
for (var e in testEvents) {
Logger.log('New Event ' + testEvents[e].getTitle() + ':' + testEvents[e].getStartTime() + '-' + testEvents[e].getEndTime());
}
}
-- log ---
CalendarApp.TimeZone : Asia/Tokyo
Deafult Calendar.TimeZone : Asia/Tokyo
New Event dummy-all-3:Sun Jun 19 2011 09:00:00 GMT+0900 (JST)-Mon Jun 20 2011 09:00:00 GMT+0900 (JST)
New Event dummy-all-2:Sun Jun 19 2011 09:00:00 GMT+0900 (JST)-Mon Jun 20 2011 09:00:00 GMT+0900 (JST)
New Event dummy-all-1:Sun Jun 19 2011 09:00:00 GMT+0900 (JST)-Mon Jun 20 2011 09:00:00 GMT+0900 (JST)
New Event dummy:Mon Jun 20 2011 00:00:00 GMT+0900 (JST)-Mon Jun 20 2011 01:00:00 GMT+0900 (JST)
ゴミの収集日を忘れて、出し忘れたゴミが台所の一角、いや三角くらいに積み上がっている今日この頃。
毎週決まった曜日に収集される燃やせるゴミなどはともかく、隔週とか月2回とかいうサイクルが設定されているものって、ついつい忘れがちじゃないですか?ウチの町田とペットボトルなどがそう。
収集日の通知サービスとかないかなぁ。…はい、あります。
ゴミ収集日お知らせサービス53cal(ゴミカレ) http://www.53cal.jp/ しかし、ウチの町のデータは登録されておらず、自分は利用できない。うーん、どうしよう。
いっそ、自分で作るか。Googleカレンダー「ごみ収集日」。
一度は手作業で作成してみた。「繰り返しの予定」で楽に作れそうだと思ったのだ。
が、一見規則正しく見えて、正月、GWなどで繰り返しがズレることがままあり。収集日にペットボトルを運んでみたら空振りみたいなことを何度かやった。
毎年設定される年度予定にちゃんと合わせないと使い物にならんなあ、と。
「繰り返しの予定」機能に頼らず、一年365日分の予定を手作業で作成するのは無茶だ。
考えたのは、Googleドキュメント上に作った日付データから、カレンダーを生成する方法。

このようなデータから。

このようなカレンダーを作るのだ。
GoogleAppsScriptという、MicrosoftOfficeでいうVBAみたいなスクリプティング環境をGoogle自身が提供している。それを利用してゴミの種類と日付をもとに予定をカレンダーに作り込んでいくのである。
GoogleのヘルプとJavaScriptの参考書等を見ながら、それっぽい
スクリプトを書いてみた。
(試行用に作ったものなので、品質については勘弁)
マジ遅い。これ実行すると、たまにヘンな落ち方するから気をつけて。というか実行しないでね。
あと、カレンダー上に生成された予定の日付がズレている。
遅いのは、セルの値をループ回しながらいちいち問い合わせているのと、カレンダーのイベントを1個1個追加しているのが理由だと思う。
前者はセル単位でなく、シートのデータを範囲指定でいっぺんに持ってくればいいはず。
後者はGoogleAppsScript単独では厳しいみたい。もしかしたら、XMLとかJSONデータを作成してバッチ反映みたいな迂回が必要かも。う〜ん、なるべくGoogleAppsScriptで完結させたかったんだけどなぁ。
カレンダーの日付のズレについては、Google各サービス間のタイムゾーン設定が整合しているか確認しないと。ワールドワイドなサービスではままある話。
あと、実行が遅いなら遅いなりに進行表示を設けないと。ということはGUIも作らなきゃだ。
…と、色々検討、試行しているウチに今度はAPIの呼び出し回数の制限に引っかかった。とほ〜。