Twitterアクセス クラス
Twitterからタイムラインを取得するコードは前回説明したものをTwitterクラスとしてまとめました。また、Twitterにつぶやきをポストするメソッドも追加しました。
- basic-auth-tokenには前回の記事を参照し、自分のログイン、パスワードを設定してください。
- タイムラインを取得する time-lineメソッドではGUIの都合もあり、リストから配列に変換しています。このようにNuにはリストから配列、配列からリストに変換するメソッドが用意されています。
- つぶやきメソッド post-tweet: はAPIを呼び出しているだけです。APIの詳細はCocoa APIリファレンスを参照してください。
(set basic-auth-token "XXXXXXXXXXXXXXXXX") (set twitter-time-line-url "http://twitter.com/statuses/friends_timeline.xml?count=100") (set twitter-update-url "http://twitter.com/statuses/update.xml") (function string-list-from-xml (xml path) (map (do (e) (e stringValue)) ((xml nodesForXPath:path error:nil) list))) (function twitter-timeline-xml () (let (http-req (NSMutableURLRequest requestWithURL:(NSURL URLWithString:twitter-time-line-url))) (http-req setHTTPMethod:"GET") (http-req setValue:"Basic #{basic-auth-token}" forHTTPHeaderField:"Authorization") ((NSXMLDocument alloc) initWithData:(NSURLConnection sendSynchronousRequest:http-req returningResponse:nil error:nil) options:0 error:nil))) (function twitter-timeline () (let (xml (twitter-timeline-xml)) (zip3 (string-list-from-xml xml "/statuses/status/user/screen_name") (string-list-from-xml xml "/statuses/status/text") (string-list-from-xml xml "/statuses/status/user/profile_image_url")))) (class Twitter is NSObject (+ time-lines is ((twitter-timeline) array)) (+ post-tweet: message is (let (http-req (NSMutableURLRequest requestWithURL:(NSURL URLWithString:twitter-update-url))) (http-req setHTTPMethod:"POST") (http-req setValue:"Basic #{basic-auth-token}" forHTTPHeaderField:"Authorization") (http-req setHTTPBody:("status=#{(message stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding)}" dataUsingEncoding:NSASCIIStringEncoding)) (NSURLConnection sendSynchronousRequest:http-req returningResponse:nil error:nil))) )
今回は汎用的なLisp関数を別ファイルにしました。これも前回説明したものです。
(function caar (e) (car (car e))) (function cadr (e) (car (cdr e))) (function cdar (e) (cdr (car e))) (function cddr (e) (cdr (cdr e))) (function cadar (e) (car (cdr (car e)))) (function null (x) (== x ())) (function zip3 (l1 l2 l3) (cond ((null l1) ()) (else (cons (list (car l1) (car l2) (car l3)) (zip3 (cdr l1) (cdr l2) (cdr l3)))))) (function map (f l) (cond ((null l) nil) (else (cons (f (car l)) (map f (cdr l)) )))) (function tl-name (e) (car e)) (function tl-text (e) (car (cdr e))) (function tl-icon (e) (car (cdr (cdr e))))
GUIハンドリング
GUIとのやり取りを行う main.nu コードです。最初の (load "...") でNuやCocoaのクラス、そして上で説明したクラスを読み込んでいます。最後の3行がGUIとやり取りするApplicationDelegateクラスを生成し、実行する定型処理です。
ApplicationDelegateクラスではインスタンス変数を3つ定義していますが、最初の tableView と textField は画面のタイムライン表示用 NSTableView、つぶやき入力用の NSTextField らと、InterfaceBuilderで対応付けされています。timeLines はタイムラインの保持用変数です。
以下のメソッドは各イベント等で呼び出されるメソッドで、pushRefreshButton:・pushPostButton: はそれぞれRefresh・Postボタンが押された時に呼び出されるようにInterfaceBuilderで対応付けされています。
各メソッドを解説すると、
- awakeFromNib はGUI定義が読み込まれた後で呼び出されます、ここではテーブルに画像を表示するために列の要素を NSImageCell に入れ替えています。
- applicationDidFinishLaunching: は画面が表示された後に呼び出されます、こではタイムラインを取得し timeLinesインスタンス変数に代入し、テーブルを再表示しています。
- pushRefreshButton: はrefreshボタンが押された時に呼び出されます、上と同様にタイムラインを取得・表示しています。
- pushPostButton: はpostボタンが押された時に呼び出されます、つぶやきを textField から取得し post-tweet: を呼び出しています。
- numberOfRowsInTableView: はテーブル表示時に呼び出されます。このメソッドはテーブルに表示するデータの件数を戻します。
- tableView: objectValueForTableColumn: row: もテーブル表示時に呼び出されます、このメソッドはテーブルに表示するデータを戻します。引数には列情報 aTableColumn と行インデックス rowIndex が渡ってくるので対応する表要素のデータを戻します。アイコンの表示はタイムラインに含まれる画像URLを使って、initWithContentsOfURL:メソッドを使い画像データを取得しています。
- applicationShouldTerminateAfterLastWindowClosed: は画面のクローズボタンを押した際にアプリが終了するようにするおまじないです。
(load "Nu:nu") (load "Nu:cocoa") (load "Nu:menu") (load "functions") (load "twitter") (class ApplicationDelegate is NSObject (ivar (id) tableView (id) textField (id) timeLines) (- (void) awakeFromNib is (let (theColumn (@tableView tableColumnWithIdentifier:"icon")) (theColumn setDataCell:((NSImageCell alloc) initImageCell:nil)))) (- (void) applicationDidFinishLaunching:(id) sender is (set @timeLines (Twitter time-lines)) (@tableView reloadData) ) (- (void) pushRefreshButton:(id) sender is (set @timeLines (Twitter time-lines)) (@tableView reloadData) ) (- (void) pushPostButton:(id) sender is (Twitter post-tweet:(@textField stringValue))) (- (int) numberOfRowsInTableView:(id) aTableView is (@timeLines count)) (- (id) tableView:(id) aTableView objectValueForTableColumn:(id) aTableColumn row:(int) rowIndex is (case (aTableColumn identifier) ("icon" ((NSImage alloc) initWithContentsOfURL: (NSURL URLWithString:(tl-icon (@timeLines objectAtIndex:rowIndex))))) ("name" (tl-name (@timeLines objectAtIndex:rowIndex))) ("text" (tl-text (@timeLines objectAtIndex:rowIndex))) (else ""))) (- (BOOL) applicationShouldTerminateAfterLastWindowClosed:(id) theApplication is YES) ) ((NSApplication sharedApplication) setDelegate:(set delegate ((ApplicationDelegate alloc) init))) ((NSApplication sharedApplication) activateIgnoringOtherApps:YES) (NSApplicationMain 0 nil)
まとめ
今回はNuでMacのGUIアプリを作ってみました。速度がそれほど必要でないGUIアプリを作る際にはLispの俊敏なプログラミングが活かせるのではないかと思います。
また、Objective-Cの中にあるC言語と [...] のオブジェクト指向部分のギャップに比べ、同じ () を使っているNuはオブジェクト指向部分とうまく調和していてコードが読みやすい気がします、このへんもS式の良さでしょうか。
今回のコードはここからダウンロードできますので、ぜひ皆さんもNuに挑戦してみてください。