Foltia with AppleScript

Foltia animelockerのトラブルシューティング

引数はレコードで:アップルスクリプトチップス

アップルスクリプトの先人たち

アップルスクリプトで私がよく参考にしているのはこの2サイトですかね。 ザリガニさんは最近更新が止まっていますが、古い記事が今でも参考になります。 ググッてヒットしたらまず見に行きますね。おそらく私の記事なんて足下にも及ばないと思うんですわ。

そんな感じでリスペクトしております。 ありがとう先人たち。 ここのサブルーティンハンドラもいくつかはこのサイトから引用しているんじゃないかな・・。

私が気をつけている4つのこと

さて今回から少し私のアップルスクリプトのコードの書き方を解説していきます。 アップルスクリプトの概要とか述べても誰もありがたがらないので、実例を示しながら行ってみましょう。 

私が頭に刻んでいることは下の4つです。コードを書く人はみんな同じこと考えてるんじゃないかな?

  • コードは短ければ短いほどよい
  • 似たコードは一つにまとめろ
  • 未来の拡張性を考慮して書け
  • サブルーティンは単独で動作するように書くべき

引数はレコードで

今回のお題ですね。 レコードというクラスは、{Shinamono:”リンゴ”,price: 1000, categoly:”果物”} みたいな{}で囲まれていて、それぞれのアイテムをカンマで区切り、前半に英数字で記載された属性というんでしょうか? 後半に値が記載されています。一つのレコードに複数の情報を入れることができます。 ほかの言語のArrayや今時だとJsonに近いですかね。 JSONと同じくレコードを入れ子にしておくことも可能です。記載されているアイテムの順番はあまり重要じゃない点がリストとの違いになります。

皆さん必ず使うやつですが、例えばReturn System info とかやって出てくる情報がレコードです。 引数をレコードで定義するメリットは将来の拡張性を維持することができる点にあります。 

引数をどうやって定義するかという例を示してみましょう

例えば引数にStringやIntegerを一つ一つ順番に入れてみて計算してみましょうか?

on TEST1(Shinamono, price, categoly, num)

  set tot to 0

  if Shinamono is "リンゴ" then set tot to tot + (price * num)

  return tot

end TEST1

--return TEST1("リンゴ", 1000, "果物", 10) -->10000

こんな感じで計算されると思います。 これは初心者が作る最も原始的な引数宣言ですかね。 確かに動きますが、再利用しようとすると厳しいハンドラになります。

 

今度は引数にレコードを設定して入力してみます。

set q to {Shinamono:"リンゴ", price:1000, categoly:"果物", num:10}

on TEST2(q)

  set tot to 0

  if q's Shinamono is "リンゴ" then set tot to tot + (((q's price) * (q's num)))

  return tot

end TEST2

 

--return TEST2(q) -->10000

結果は同じですね。 少しだけ本文のメイン文の長さが長い気がします。

前者(TEST1)はまずこのハンドラを書いた直後なら覚えていますが、引数の順番にも意味があり、場所は引数の数も大事になります。 1年前に書いたコードを引用しようとすると、きっと何番目に何が書いてあるのかなんて忘れてしまっているわけで、原典にいちいち戻ってスクリプトを書く必要があります。

拡張する場合

さらに今度は国際化の波に押されて、リンゴの産地を記載する必要が出てきたらどうでしょう? 前者でしたら、TEST1の引数を1個増やしてしまうと、以前どこかで引用していた別のハンドラが、引数が足りませんとエラーを起こしてしまいます。 どこにこのハンドラを引用したのかいちいち全部のスクリプトファイルを確認しますか? 私なんか1000個以上あるのにそんなの無理なんですよね。 じゃあもう一個別にTEST4という別の似たようなハンドラを作成し直したとします。 そうすると似たようなTEST1とTEST4というハンドラができあがります。 その状況であるとき上司から共通のバグを指摘されたら、似たようなハンドラすべてを直すんでしょうか? できたら修正する点は1個にしておきたいですよね。 そういったとき引数をレコードで指定していると変更が簡単になります。 

(*産地が必要になった*)

 

set q to {Shinamono:"リンゴ", price:1000, categoly:"果物", num:10, sanch:"日本"}

on TEST2(q)

  set q to q & {sanchi:"日本"}

  set tot to 0

  if (q's Shinamono is "リンゴ" and q's sanchi is "日本") then set tot to tot + (((q's price) * (q's num)))

  return tot

end TEST2

--return TEST2(q) -->10000

どうでしょうTEST2を変更してしまいます。 以前の別のスクリプトこのハンドラを呼び出した時にはsanchの指定がなかったわけですが、引数に指定がない場合のデフォルト値"日本"であると設定して、本文が実行可能となります。

レコードの結合は左辺が優先される

今回のハンドラの2行目

  set q to q & {sanchi:"日本"}

これはレコードをアンドで結合した場合、同一の属性データーがあった場合、左辺が優先される性質を使っています。 こうやって無指定の場合のデフォルト値を後から指定してハンドラ本文を自由に拡張してゆくことができるわけです。 引数のqにsanchの指定があれば、そちらが優先され、qにsanchの指定がなければ右辺の"日本"が格納されることになります。

なので当初引数なしでもよいかなと思っていても、qを{}で渡せばよいだけですので、q (queryのつもりです)をつけておいた方が後々拡張性するときに便利だということになります。

また初期値をあらかじめ行頭で指定することができるので、短い行数でそのハンドラのバグ取りのための実行テストをすることができる利点があります。 

こうやってレコードを引数で入力することで、ハンドラはちょっとだけ長くなりますが、汎用性がでて、後で引数を変えたり、別の用途に用いたりすることが簡単にできるようになるわけです。