Mail.appでTwitterに投稿する

2009/11/24 (火)  カテゴリー/AppleScript

 Mail.appで受信したメールの本文をTwitterに投稿するスクリプトを作ってみた。
 最近携帯でTwitterに投稿する際、
「ログインがめんでぇー」
 と生来の面倒臭い病が発病。公式のモバイルページを使っているのですが、
・ブラウザでTwitter.comを開く
・ユーザ名入力
・パスワード入力
 このステップが激しく面倒臭い。
「ちょっと投稿したいだけ」
 って時にブラウザ動かすなんていう、たいそうなことをしたくないわけです。
 海外ではSMSなんかでさくっと投稿できるらしいですが、仮に日本で同様のことができてもSMSの料金払ってまで投稿とかはちょっと考えものですね。
 そこでメールを使って投稿しようと考えてみました。Twitterにメールで投稿するサービスはいくつかあるんですが、せっかくなので自分で手軽にできないかと考えてみることに。
 自分でとなると意外と敷居の高いメール投稿。ここは一つお手軽にMail.appでルールを作成してApplescriptを動かすというなんとも回りくどい方法をとってみました。
 まずは以下のApplescriptを作成
using terms from application "Mail"
on perform mail action with messages theMessages
tell application "Mail"
repeat with eachMessage in theMessages
set login to "ユーザ名:パスワード"
set PostData to content of eachMessage
set status to quoted form of ("status=" & PostData)
set results to do shell script "curl -u " & login & " -d " & status & " http://twitter.com/statuses/update.xml"
end repeat
end tell
end perform mail action with messages
end using terms from

※上記スクリプをproxy利用環境で利用するにはこちらの記事を参考にcurlコマンドを書き換えてください
 これで受信したメールの本文がTwitterに投稿されます。スクリプト中の「ユーザ名:パスワード」の部分は使用されるアカウントの値に設定してください。ここらへん、セキュリティ的には微妙ですがそもそもAPIの実行自体がベーシック認証なんで気にしないことにしましょう。
 さてこのスクリプトができたら今度はMail.appにこのApplescriptを動かすルールを作って適用します。Mail.appのメニューがから「環境設定」を選んでルールタブを開きます。私はこんな感じで設定してみました。
ルール
 Subjectはメールの件名、fromは送信元のメールアドレス。「以下の動作を実行」の部分で先程作成したApplescriptを指定します。さてこの設定の動きです。fromのメールアドレスを携帯電話のアドレスにしておけば、
「携帯電話から送られたメールの件名が"TwitterPost"であればTwitterに投稿する」
 という動きになります。
 これでMail.appの新着受信で受信されたメールにルールが適用されればTwitterに投稿されます。
 とまあここまでやっておきながらこれはこれで常にマックを起動しっぱなしにしておかなければならないので世間のエコな流れに真っ向勝負な感がありますし、スリープになっても動くのかよ? という疑問も有ります。まあ、FC2の広告表示阻止ようのネタとしてはそこそこの内容ですかね??

テーマ : Mac - ジャンル : コンピュータ

Perlでなんちゃってオブジェクト指向2「データへのアクセスを解りやすくする」

2009/10/15 (木)  カテゴリー/Perl

 前回は読み込んだレコードを一つのデータの塊として操作する方法を学びました。処理に利用したデータは以下のようなデータです。

00,A君,13,12,3
01,B君,7,11,7
02,C君,8,4,1
03,D君,3,5,5

「ID,名前,年齢,誕生日(月),誕生日(日)」という並びのデータです。これらを読み込んで一つのデータの塊として捉え「$Menber{$key}[0]」なんていう感じでデータにアクセスしていました。でも、
「えーと、名前は配列の何番目だっけ?。。。あぁ、2番目か、じゃあ$Menber{$key}[1]だな」
 なんていうアクセスの仕方は正直やりにくいですよね。名前が欲しいなら、
「名前くれ」
 って呼び出したい。そこで項目名を直接指定して、それぞれのデータにアクセスする方法を実装してみます。

 前回はIDをキーにしたハッシュの中に配列を入れ込みました。当然配列変数なので配列の要素にアクセスするには何番目の値が欲しいのかを数字で指定しなければなりません。しかし今回は数字ではなく項目名でアクセスしたい。項目名ということは特定のキーワードです。特定のキーでデータを呼び出すということはご存知ハッシュ変数の出番となります。

#!/usr/bin/perl
use utf8; #-ソースがUTF8だという宣言
use Encode;
binmode STDOUT, ":utf8"; #-画面に出力したい文字コード
binmode STDERR, ":utf8"; #-エラー出力に使いたい文字コード
binmode STDIN, ":utf8"; #-標準入力から入ってくる文字コード

#-読み込むデータの項目名を定義しておく。
#-splitしてもいいけど私は地道に書くのが好き
#-ID,名前,年齢,誕生日(月),誕生日(日)
$Koumoku[0] = 'ID';
$Koumoku[1] = '名前';
$Koumoku[2] = '年齢';
$Koumoku[3] = '月';
$Koumoku[4] = '日';

while() {
chomp($_);
my %BODY; #-常に新しい領域を生み出す「my」がポイント
@LINE = split(",",$_);
#-定義した項目名をキーにして分解したフィールドをハッシュに入れる
for ($i=0;$i<@LINE;$i++) {
$BODY{$Koumoku[$i]} = $LINE[$i];
}
$Menber{$BODY{'ID'}} = \%BODY;#-配列のリファレンスを入れる
}

for $key (sort mySort keys %Menber) {
print $Menber{$key}{'ID'} . ':' . $Menber{$key}{'名前'} .'=';
print $Menber{$key}{'月'}.'月'.$Menber{$key}{'日'} .'日生 ' . $Menber{$key}{'年齢'} ."歳\n";
}

sub mySort() {
$Menber{$a}{'年齢'} <=> $Menber{$b}{'年齢'};
}

exit;

__DATA__
00,A君,13,12,3
01,B君,7,11,7
02,C君,8,4,1
03,D君,3,5,5


結果:
03:D君=5月5日生 3歳
01:B君=11月7日生 7歳
02:C君=4月1日生 8歳
00:A君=12月3日生 13歳

 前回のソースでは数字で配列の要素番号を指定していましたが、今回はハッシュ変数に項目名をキーにして入れたので「年齢」や「名前」等の項目名でデータを呼び出しています。ソートのルーチンでも「年齢」という項目名があるおかげで年齢でソートしているということがよくわかります。

 自分で項目名を定義してデータを一つの塊として生み出す。今回読み込んでいる名簿の中には「ID,名前,年齢,誕生日(月),誕生日(日)」という5つの値が存在しているのでソースの中で項目名を事前に準備しています。これから処理しようとしているデータが、

・どのような値を保持しているのかを確認する
・保持している値を格納する受け皿の準備をする

 受け皿の準備と言っても項目名を並べただけですが「この順番でデータが並んでますよ」という簡単な設計図といえます。ソースでは22行目にあるforループが準備した設計図にそってデータを格納している部分です。

 項目名で解りやすくデータをアクセスするには事前に設計図の準備が必要になります。今回は項目名の順番だけを定義する簡単な設計図使いました。次回はこの設計図をもうちょっと使いこなす、そんなソースをご紹介しようと思います。

テーマ : プログラミング - ジャンル : コンピュータ

Perlでなんちゃってオブジェクト指向1「名簿をソートしてみる」

2009/09/30 (水)  カテゴリー/Perl

 私、一応プログラマの端くれなのでオブジェクト指向ってのをそれなりに勉強しております。ということで今まで自分が勉強してきたことでポイントとなるやもしれんという要所要所を備忘録として思いつき次第書いていこうと思います。ただ小難しい話は苦手なので、

「少なくともこういう処理をするにはこうやったほうが楽ちんだよね?」

 というノリで行こうと思います。使う言語はひらくん大好きPerlです。

 今やPerlにおいてもオブジェクト指向プログラミングが主流となっていると思われます。もともとオブジェクト指向なんていうものと縁もゆかりも無かった言語が現在オブジェクト指向プログラミングの手法を確立している。実はその経緯の中に0からオブジェクト指向を学ぶためのマイルストーンが隠れているのではなかろうかっ! では前置きはこんなところで。

 ある名簿をソートする場合を考えてみます。こんなCSVのファイルがあったとしましょう。

00,A君,13,12,3
01,B君,7,11,7
02,C君,8,4,1
03,D君,3,5,5

「ID,名前,年齢,誕生日(月),誕生日(日)」なんていう名簿です。さてこれを年齢順にソートするとしましょう。

「リファレンスなんてしらない、CSVならスプリットして配列に放り込むのだ」

 というベタなPerlで処理するとこんな感じでしょうか?

※サンプルでは外部ファイルではなく「__DATA__」にレコードを記述しています
※「__DATA__」って何?:ソース内にある「__DATA__」以下の行はハンドルを経由して読み込むことができます
※デバッグなんかに便利やねー
#!/usr/bin/perl
use utf8; #-ソースがUTF8だという宣言
use Encode;
binmode STDOUT, ":utf8"; #-画面に出力したい文字コード
binmode STDERR, ":utf8"; #-エラー出力に使いたい文字コード
binmode STDIN, ":utf8"; #-標準入力から入ってくる文字コード

chomp(@DATA = );#-セパレータ(標準では\n)を削除
@DATA = sort mySort @DATA;#-サブルーチンを使ってカスタムソート

#-出力ブロック
for (@DATA) {
@LINE = split(",",$_);
print $LINE[0] . ':' . $LINE[1] .'=';
print $LINE[3].'月'.$LINE[4] .'日生 ' . $LINE[2] ."歳\n";
}

sub mySort() {
my @A = split(',',$a);
my @B = split(',',$b);
$A[2] <=> $B[2];
}

exit;
__DATA__
00,A君,13,12,3
01,B君,7,11,7
02,C君,8,4,1
03,D君,3,5,5

結果:
03:D君=5月5日生 3歳
01:B君=11月7日生 7歳
02:C君=4月1日生 8歳
00:A君=12月3日生 13歳

 まあ処理結果自体はこれでOKです。ただあまり効率的ではないですね。同一レコードに対して何度もsplitを繰り返しているってのが駄目っぽさをアピールしています。どうしてこのようなことになってしまうのでしょうか。

 項目「ID」「名前」「年齢」「月」「日」はそれぞれが一つのレコードとしてまとまっています。仮にそれぞれの項目を「IDテーブル」「名前テーブル」等のように独立した配列にしてしまうと「年齢でソート」なんていう処理をする際に「他の配列も連動するようにソートをしなければいけません」こんな処理は考えただけで面倒くさいじゃないですか。

 そこで上記のソースでは「1つのレコードを一つの文字列として保持」しておくことでレコードとしてのまとまりを保っているわけです。当然レコード内の項目にアクセスしたければ、その都度splitして値を取り出すことになります。

「複数の項目を一つのまとまりとして保持しておきたい」

 今回のような名簿の並べ替えもそうですが、商品毎の売り上げや自分が運営しているWEBサイトの月別アクセス数等、複数の項目を一つのまとまりとして管理する状況は沢山あります。

 まあ前述のソースでも問題ないのですが項目を取り出すたびにsplitするなんてのは面倒ですよね。

「さまざまな項目を一つのまとまりとして保持して管理する方法」

 は、どうすれば実現できるのでしょうか。そんなおいしい処理をする為にはこーんな手法をとります。配列の要素の中に配列を入れてしまうのです。

 今回のレコードには「ID」というユニーク情報がありますので試しにこいつをkeyにしたハッシュ変数を作成します。そうやって作成したハッシュ変数の値にはsplitで分解した各レコードの情報を「配列のまんま」放り込みます。

#!/usr/bin/perl
use utf8; #-ソースがUTF8だという宣言
use Encode;
binmode STDOUT, ":utf8"; #-画面に出力したい文字コード
binmode STDERR, ":utf8"; #-エラー出力に使いたい文字コード
binmode STDIN, ":utf8"; #-標準入力から入ってくる文字コード

while() {
chomp($_);
my @LINE = split(",",$_);#-常に新しい領域を生み出す「my」がポイント
$Menber{$LINE[0]} = \@LINE;#-配列のリファレンスを入れる
}

for $key (sort mySort keys %Menber) {
print $Menber{$key}[0] . ':' . $Menber{$key}[1] .'=';
print $Menber{$key}[3].'月'.$Menber{$key}[4] .'日生 ' . $Menber{$key}[2] ."歳\n";
}

sub mySort() {
$Menber{$a}[2] <=> $Menber{$b}[2];
}

exit;

__DATA__
00,A君,13,12,3
01,B君,7,11,7
02,C君,8,4,1
03,D君,3,5,5

 最初のwhile構文が今回の重要なポイントです。

1 読み込んだ一行をsplitで分解し配列@LINEに入れます。
2 @LINE(正確には@LINEのリファレンス情報)を$Menber{$LINE[0]}に入れます。

 いかがでしょうか? わかりやすく書くとこんな感じです。

$Menber{'00'} = ['00','A君','13','12','3'];

 あたかも$Menber{'00'}という変数の中に配列の構造をそのまま取り込んでいるような処理になっています。
 この構造にアクセスするには$Menber{'00'}を通常の配列変数ととらえて$Menber{'00'}[0]なんて感覚でアクセスできます。
 これでIDというユニークなキーを使って各項目の配列に自由にアクセスできるようになりました。
 ソート用のサブルーチンの中では配列の比較対象である年齢(3番目の項目)を使ってソートし、結果のプリントでは保持してある構造に直接アクセスして値をプリントしています。

 このように「複数の項目を一つの塊にまとめる」という手法を覚えると、データ処理の効率は飛躍的にあがります。

 今回は$Menber{'00'}の中に項目の塊をどーんと放り込んでみました。

・1行目のレコードを読み込んで項目ごとに分解
・分解した項目を一つの塊として変数に入れておく

 こうやって書いてみるとなんでもない処理ですが注目して欲しいのは複数に分裂したレコードの項目を寄せ集めて「一つの塊」にしていることです。

 一つ一つのデータを決められた枠組みのなかに入れて、ぽんぽん新しいデータの塊を生み出す。生み出すなんて言うとなんだかとってもアナログな感じがして楽しいですよねー。

 さて今回はここまで。次回はまだ未定ですが、もうちょっとそれらしくしたオブジェクトプログラミングをご紹介しようと思います。

テーマ : プログラミング - ジャンル : コンピュータ

ターミナルと同階層のFinderウィンドウを即座に開く

2009/09/25 (金)  カテゴリー/OS X Tips

 私はOS Xでよくいろんなスクリプトを組んでいます。

 まあその手の作業ではやっぱりターミナルが大活躍なわけですが今回はOS Xでターミナルを使っている人にちょっと役立つTipsをご紹介いたします。

 ターミナルを開いて作業している時に、

「あ、ちょっとFinder開きたい」

 と思う事があります。当然こんな時は、

「現在ターミナル上で操作しているファイルをFinderで扱いたい」

 わけです。ターミナルと同階層のFinderウィンドウが欲しい。そう、こんな時には「open」を使います。

 このopenコマンドはどんなものかと簡単に言うと、Finderでダブルクリックした時と同じ挙動をターミナル上から実行することができます。

 Finderで特定の階層を表示したい場合は当然フォルダアイコンをダブルクリックしますよね? ということは現在ターミナル上で表示している階層に対してopenコマンドを実行すればいいわけです。現在ターミナル上で表示している階層はピリオド一文字で表すことができます。ですのでターミナルで次のコマンド、

「open .」
※ピリオドが目立たないので大きくしました

 を実行すると現在ターミナル上で表示している階層を即座にFinderで表示することができます。わーちょっと便利。

 ついでにもう一つ、openコマンドを利用したネタ。前述したようにこのopenコマンドはFinderでダブルクリックに相当するので、引数にファイルを指定すると関連アプリケーションで開くことができます。ただスクリプトの処理結果ログなど、まだ関連付けされてないテキストファイルを愛用のテキストエディタで開きたい願望にかられる場合があります。そんな場合はこのopenコマンドにオプションを指定してアプリケーションを指定することができます。例えば私が愛用しているCoteditorでtmp.txtを開きたい場合等は、

「open -a "Coteditor.app" tmp.txt」

 こんな感じ。これを使用すれば仮に他のアプリに関連付けされているファイルであれ、関連付けに関係なく指定したアプリで開くことが可能です。ただ、毎回この指定をするのが面倒なので私の場合「.bashrc」に以下のaliasを追加してます。

「alias copen='open -a "Coteditor.app"'」

 こんな感じ。これでいつでも「copen」という指定で自分が開きたいファイルをCoteditorに渡す事ができます。

 こーんな微妙なネタですが日々の作業では結構遭遇する場面です。

「Finderで新しいウィンドウを開くより open . 」

「open . でFinderを開いてログファイルをD&Dでエディタアイコンに持って行くよりcopen」

 ちょっとした手抜きですが試してみると結構快適ですよ。

テーマ : Mac - ジャンル : コンピュータ

ターミナル起動時に勝手にコマンドが実行される

2009/09/24 (木)  カテゴリー/OS X Tips

 いつからか使っているマックのターミナルを起動すると特定のコマンドが実行されるようになってしまった。
 まあ、特定のコマンドが何かと言えば、
「cd /tmp;ls -v」
 みたいな感じで特定のディレクトリに移動してリストを表示するというもの。実害はないんだけど、精神衛生上よろしくない。なんて言ってもこんな設定した覚えは微塵もないのだ。
 まずはbashの起動時に実行されるファイルを順番にチェックしていく。なにかの実験で設定をしてしまったのかもしれない。しかしながらbashrcもbash_profileも特に問題なし。おかしいなあと思って最後にcom.apple.Terminal.plistをチェック。最初、
「plistなんて面倒だから後回し」
 と思って見てなかったんですがやっぱり原因はこれでした。plistの中に次のキーワード、
「ExecutionString」
 なるものが設定されています。原因はどうやらこいつ。ターミナル起動時に実行されるコマンドを設定する項目。何かのきっかけでこいつが設定されてしまったようだ。ということで以下のコマンドをターミナルで実行。
「defaults delete com.apple.Terminal ExecutionString」
 すばらしーい。新しいシェルを起動しても変なコマンドが実行されなくなったぜい。ちなみにググッた結果わかったのは、ターミナルのファイルメニューにある、
「設定をデフォルトとして使用」
 とういやつを実行するとその時実行していたコマンドまでデフォルトして保存されるらしい。ただ再現させようと試したんだけどうまく行きませんでした。ま、いいや。

テーマ : Mac - ジャンル : コンピュータ


あわせて読みたい