2010-11-25
TitaniumのコードをGUIなしでエディタからすばやくbuildする
最近ちまたではTitaniumが話題ですね。はてなの技術勉強会で紹介されたのをきっかけに少しいじってみています。
Titanium開発では、通常Titanium DeveloperというGUIアプリケーションを使ってコードをbuildします。開発中は、どうしてもTitanium Developerとエディタとの行き来が必要で、なかなか不便です。
そこで、Titaniumのコードをvimなどのエディタから一発で、すばやくbuildできるようになるスクリプトを書いてみました。ついでにXCodeもTitanium Developerも(GUIの部分は)起動しなくてよくなります。
使い方
https://gist.github.com/715378 を Titaniumのプロジェクトの直下に置いて、
$ perl build.pl
のように実行します。すると9090番ポートでbuild用HTTPサーバが立ち上がります。
エディタからこのbuildサーバの/runにHTTPリクエストを送るとビルドが実行されます。vimの場合は以下のようしておくと良いです。
nnoremap <unique> <silent> <Leader>ti :call system('curl http://localhost:9090/run &')<CR>
これでvimで,tiとするだけでbuildがはじまります。 Titaniumのプロジェクト内のファイルがコンパイルされ、シミュレータが起動します。キーボードから手を離さずにすばやくbuildできて便利!
buildが実行されるとbuildサーバでは以下のようにTitaniumのログが表示されます。
> perl build.pl starting server at localhost:9090 at build.pl line 38. [INFO] One moment, building ... [TRACE] app property, ti.android.debug : false [INFO] Titanium SDK version: 1.4.2 [INFO] iPhone Device family: None [INFO] iPhone SDK version: 4.0 ...
どうしてこうなってるか
build.plのソースコードを見てもらえればわかるのですが、以下のようにすれば、GUIなしでビルドが実行できます。
$ "/Library/Application Support/Titanium/mobilesdk/osx/1.4.2/iphone/builder.py" run /path/to/TiProject
このコマンドは大変便利なのですが、vimとかのエディタから直接実行すると、工夫してもログが見れなかったり、エディタがこのスクリプトにブロックされてしまったりするので、あまりうまくありません。
なので、要求に応じてbuildをするだけのサーバを作って、そこにメッセージを送ることでエディタからのbuildを実現してます。AnyEventべんりー
2010-11-22
unite.vim の source をお好きなスクリプト言語で書ける unite-script
11月20日に開催されたKansai.pmのLTでunite-scriptについて発表しました。
unite-scriptはunite.vim の sourceをお好きなスクリプト言語で書くためのsourceです。リポジトリはこちら。
Kansai.pmのLTで発表した資料も公開しておきます。
以下ちょっとくわしく。
unite.vim
unite.vim は最近もりあがりを見せてきた vim のプラグインです。候補の一覧からアイテムを選択しアクションを実行するための汎用的な仕組みを持っています。基本的には、ファイラやバッファセレクタとして利用できます。加えて、一覧して表示するデータ(source)を自分で定義することができるのが特徴です。Emacsのanything.elのようですね。
利用できるsourceとしては以下のようなものがあります。
- file ファイルの一覧
- file_mru 最近開いたファイルの一覧
- buffer 現在開いているバッファの一覧
- help ヘルプの一覧
- outline ソースコードを解析した結果の一覧
詳しくは、ドキュメントを参考にしてください。
unite-script
unite.vim のsourceを自分で定義すると好みの情報を一覧して選択できるようになるので便利です。しかし、sourceは通常vimスクリプトをつかって定義する必要があります。普段から使わないvimスクリプトをsourceを作るために覚えるのはたいへんです。
sourceを普段使っている言語で作成できれば便利です。そこで、Perlをはじめとしたスクリプト言語によってsourceを書くことが可能になるunite-scriptを作りました。
unite-scriptの利用例
unite-scriptを利用するには、unite-script が読み込める形式の文字列を出力するスクリプトを作成する必要あります。ここでは、vimからはてなブックマークのhotentryを出力するbookmarks.plを用いて説明します。
bookmarks.pl の実装は非常に単純です。フィードを読み込んで一行ごとに出力していきます。この時、各行は
一覧に表示するタイトル\tvimで実行するコマンド
の用になっています。具体的なスクリプトは以下のようになります。
use strict; use warnings; use XML::Feed; use URI; use Perl6::Say; use Cache::File; use URI::Fetch; my $target = 'http://b.hatena.ne.jp/hotentry.rss'; my $cache = Cache::File->new( cache_root => '/tmp/cache' ); my $res = URI::Fetch->fetch( $target, Cache => $cache ) or die URI::Fetch->errstr; my $feed = XML::Feed->parse(\($res->content)); for my $entry ($feed->entries) { say sprintf("%s\tcall system('open %s')", $entry->title, $entry->link); }
このスクリプトを実行すると以下のよう出力されます。
> perl bookmarks.pl
C言語すら知らなかった私が2ヶ月でiPhoneアプリをリリースするまでにやった事。 | Last Day. jp call system('open http://www.lastday.jp/2010/11/22/objective-c')
漢字も使える手書き風の日本語フォントのまとめ | コリス call system('open http://coliss.com/articles/freebies/freebies-handwriting-japanese-font.html')
webデザインのセンスを磨く『○○系のwebデザインまとめ』の総まとめ*ホームページを作る人のネタ帳 call system('open http://e0166.blog89.fc2.com/blog-entry-817.html')
苦しんで覚えるC言語 call system('open http://9cguide.appspot.com/')
このスクリプトをunite-scriptから呼び出すには次のようにします。
:Unite script:perl:/path/to/bookmarks.pl
これで、一つsourceが完成しました。これをvimから呼び出すと次のようになります。
記事の名前を選んでEnterを押すとブラウザが起動して記事をみることができます。
このほかにもunite-scriptのリポジトリのexamplesディレクトリにいくつかの例を含めました。
- bookmarks.pl はてなブックマークの人気エントリの一覧、ブラウザで表示
- gmail.pl Gmailの受信箱のメール一覧、ブラウザで表示
- twitter_user.pl miyagawaさんのツイートを一覧、ブラウザで表示
- itunes.pl 現在再生しているプレイリストの曲を一覧、再生
個人的にはitunes.plがコーディング中にすばやく選曲するのにとても便利でお気に入りです。こんなかんじです。絞り込みもできて便利。ただし、実装のほとんどがAppleScriptなのでMacのひとしか使えません。
まとめ
unite.vim のsourceをお好きなスクリプト言語で作成できる、unite-scriptについて説明しました。vimスクリプトに馴染みがない人も簡単にsourceを定義することができて便利です。
一方、実際に各行のコマンド部分にはvimスクリプトを書く必要があるため、複雑なことをするためには結局vimスクリプトを学ぶ必要があります。また、スクリプトの出力結果を利用するという仕組み上、unite.vimのもつ便利な機能(項目ごとに複数のアクションを定義したり)が利用できなくなっています。
このような制限のため、高機能なsourceはつくりにくいものの、vimスクリプトビギナーにとってはちょっとした便利sourceを作りたい時にはやはり便利です。
僕自身もvimスクリプトは初心者なのでつたない感じになっていますが、よければ使って、おもしろいsourceをつくってみてください。
2010-10-17
YAPC::Asia で 「ページャ実装マニアックス」という題目で発表してきました
YAPC::Asia 2010に参加して LT で発表しました。ページャ実装マニアックスという題目で、はてなにおけるページャ実装について紹介しました。
スライド内で大量のページャ実装を紹介していますが、もちろんまったく別の実装ということはないです。いくつかの共通クラスを継承してカスタマイズしたものを使っています。
スライド内でもいってるようで、単にページャといってもさまざまな要素がからんでいます。これを踏まえてページャをうまく抽象化できる実装が考えられると良いですね。
2010-07-11
ScalaでWebM形式の動画再生
それなりにたいへんそうで勉強になるかと思い、ScalaでWebM形式の動画を再生するコードを書いてみた。やりたくなったから、やっただけなので特に有用性とかはないです。
WebMのデコーダを準備する
Javaで、WebM形式の動画を扱うには gstreamer-java が使える。
gstramer-java はネイティブのgstreamerを呼びだすのでインストールする。また、gstreamerがWebM形式の動画をデコードできるように、デコーダもインストールしておく。
WebMデコーダのインストール
WebMのデコーダ(libvpx)のソースコードをcloneしてビルド/インストール。
$ git clone git://review.webmproject.org/libvpx.git $ cd libvpx $ ./configure $ make $ sudo make install # とりあえず/usr/local にいれておく
gstreamerのインストール
MacPortsからインストール。GNOME系のライブラリ/各種コーデックに依存しているためか、とても時間がかかる。
$ sudo port install gstreamer gst-plugins-base gst-plugins-bad gst-plugins-good
Scalaでgstreamerを呼び出すコードを書く
gstreamer-javaのサンプルコードをScalaに翻訳する。
import java.io.File;
import scala.swing._;
import org.gstreamer.Gst;
import org.gstreamer.State;
import org.gstreamer.elements.PlayBin;
import org.gstreamer.swing.VideoComponent;
object VideoPlayer {
def main(args : Array[String]) {
val gstArgs = Gst.init("VideoPlayer", args)
val playBin = new PlayBin("VideoPlayer")
playBin.setInputFile(new File(gstArgs(0)))
Swing.onEDT {
val videoComponent = new VideoComponent;
playBin.setVideoSink(videoComponent.getElement)
val panel = new BorderPanel {
add(Component.wrap(videoComponent), BorderPanel.Position.Center)
}
val frame = new MainFrame {
title = "VideoPlayer"
preferredSize = new Dimension(640, 480)
contents = panel
open
}
playBin.setState(State.PLAYING)
}
Gst.main
playBin.setState(State.NULL)
}
}
もとのコードよりもSwingまわりはscalaっぽくなっていてきれいですね。newしながらコンストラクタ拡張しつつ初期化コードを走らせているのが Scalaっぽい? scala.swingの使い方がよくわかんなかったので適当です。
コンパイル
gstreamer-java-1.4.jarとjna.jarをダウンロードして適当なところにおいておく(うちはlibディレクトリを作っておいてる) 。あと、コンパイル時にはjnaにライブラリの場所を教えてあげる。あと、Scala2.8じゃないとうごかなさそうです。
$ scalac -Djna.library.path=/opt/local/lib/ -cp .:lib/gstreamer-java-1.4.jar:lib/jna.jar VideoPlayer.scala
実行
$ scala -Djna.library.path=/opt/local/lib/ -cp .:lib/gstreamer-java-1.4.jar:lib/jna.jar VideoPlayer ~/Desktop/k-on_op.webm
再生できました!!
WebM形式の動画は YouTube からとってくるのが便利ですね。
メモ
- Java系で動画再生とか大変そうに思っていたけどライブラリがそろっていて簡単。Scalaでも余裕でつかえる
- gstreamer/gstreamer-javaが汎用的に使えて便利 (WebMにもプラグインで対応)
- ただしネイティブにコンパイルされたライブラリに依存してる
- ScalaでJavaのライブラリを呼び出すコードを書くとあまりJavaとかわらなくなって、Scalaの書きやすさを享受できなくなる
- scala.swingではなくて、javax.swingを使うとだいぶJavaっぽくなってしまう (new Runnable() {} とかいるし)
- JavaのライブラリのScalaラッパが増えれば、もっとScalaが書きやすくなりそう
- Scalaのソースコード内のライブラリのコードはScalaの勉強するのにたいへんよい
- Scalaのソースコード内の src/swing とか
- Scalaの開発環境整えたいです
今回のようにただ再生するだけだと、さすがにしょうもないので、今度は、Actorを使ってWebインターフェースからプレイヤーをコントロールとかやりたいですね。
2010-05-30
御当地訪問を支援するAndroidアプリ Gotouchi をつくりました
昨今では、アニメやコミック、ゲームの御当地を訪問することが流行しているようですね。気になって、日本にどのくらいの御当地があるのかを調べて、Google マップ上にプロットしてみました。*1
うわぁ…。このように日本全国津々浦々どこにいっても何かしらの御当地にブチ当たるという具合です。このような状況では、自分の家の近くや旅の行く先々のもたくさんのアニメやコミックの御当地が存在しているはずです。
そんな御当地が近くにあるかを簡単に確認できれば便利です。そこで Androidアプリ Gotouchi を作ってみました。
Gotouchiを起動すると、現在位置を測定し、近くにどの作品の御当地があるかを一覧表示してくれます。
ためしに、滋賀県にある、うちの家でためしてみると、滋賀県大津市のちはやふるの御当地が最寄のようです。全然知りませんでした… ちはやふるはまだ読んだことがないので、今度読んで御当地を訪問してみたいと思います。
一覧から作品のタイトルをタッチすると、御当地訪問をするのに参考になりそうなWebサイトを検索して表示することができます。出先で急に御当地訪問がしたくなっても、安心です。
精度はGoogle先生の検索に依存しますが、だいたいどなたかがまとめてくださったページに簡単にたどりつけます。
こんな感じの御当地訪問アプリを作ってみました。ソースコードとアプリケーションパッケージをgithubで公開していますので、興味のある方はぜひ使ってみてください。
御当地の情報は、 地域別リスト[関東] - info - 舞台探訪アーカイブ を使わせていただいています。大変充実していて参考になりました。
技術的なメモ
今回の実装の技術的なメモです。
GeoHashの利用
ある位置とある位置が近くにあるかを判定する計算量を抑えるために、GeoHashを使ってみました。位置情報をGeoHashで表現すると、特定の範囲内にあれば先頭の文字列が一致するので、文字列比較だけで、近傍判定ができます。例えば、以下の二つは先頭3文字が一致しているため、それなりに近くにあることがわかります。
- 滋賀県大津市: xn0x5qy61b
- 京都府宇治市: xn0rdxn7mb
文字列の一致量で精度が調整できたりもできます。緯度経度を文字列で表すGeoHash - @masuidrive blog がたいへん参考になりました。
位置情報インデックスの作成
今回の実装では事前に位置情報と作品名のペアをJSON形式で保存しておき利用しています。事前にGeoHashを計算してインデックスに含めて、Androidアプリ側での計算を抑えています。ただし、100KBくらいのデータがメモリに乗っかるのが玉にキズです。
JSONではなく、MessagePackを利用したり、重複情報がなくなるように工夫すればもう少しメモリ効率が良くなりそうです。
Androidでの位置情報取得
Androidで位置情報を取得する際には、GPSの情報やネットワークの情報を使うことができました。ただ、GPSでの位置情報取得は遅いので、
- 起動時にはネットワークから取得
- メニューから再取得を実行した際には、GPSから取得
のようにしています。Androidはこの位置情報のプロバイダを選択する際に何を優先するのかを選択できるので、実際には以下のようなコードを使っています。
private void setLocationManager(boolean fine) {
if (mLocationManager == null) { return; }
showLoadingDialog();
Criteria criteria = new Criteria();
if (fine) { criteria.setAccuracy(Criteria.ACCURACY_FINE); } // 精度を優先するか?
mProvider = mLocationManager.getBestProvider(criteria, true);
// 省略
}
*1: 地域別リスト[関東] - info - 舞台探訪アーカイブ を参考にさせていただきました。








