perldocのレンダリング結果をキャッシュして高速に表示するモジュールを作りました

perldocコマンドはPerlを書く人にとっては手放せないツールですが、 割と大きいPodファイル(DBI, perltoc, perlfunc, ...)を表示したり、Pod::Text::Color::Delightを使ってカラーリング表示しようとすると、表示するまで少し待たされるのが気になっていました。

そこで、 perldocで出力したフォーマット結果をキャッシュしておき、次回以降素早く表示するPod::Perldoc::CacheというCPANモジュールを作ってリリースしました。

https://metacpan.org/pod/Pod::Perldoc::Cache

インストール

$ cpanm Pod::Perldoc::Cache

使い方

perldocには-MオプションでPodファイルのフォーマッターを指定することができるので、そこに本モジュールを指定します。 一度目は通常通りの時間がかかりますが、二度目以降はキャッシュを読むようになります。

$ perldoc -MPod::Perldoc::Cache DBI # doesn't use cache
$ perldoc -MPod::Perldoc::Cache DBI # use cache!

また、Pod::Text::Color::Delightなどの他のフォーマッターを同時に使いたい場合は-w parserオプションを使います。

$ perldoc -MPod::Perldoc::Cache -w parser=Pod::Text::Color::Delight DBI

一々こんな長ったらしいコマンド書いていられないので、alias もしくは PERLDOC環境変数でオプションを設定するといいと思います。

$ alias perldoc='perldoc -MPod::Perldoc::Cache -w parser=Pod::Text::Color::Delight'
$ export PERLDOC='-MPod::Perldoc::Cache -w parser=Pod::Text::Color::Delight'

キャッシュ先

キャッシュの保存先はデフォルトで~/.pod_perldoc_cacheというディレクトリになっています。 そんな所に保存したくない!って方はPOD_PERLDOC_CACHE_DIR環境変数に保存先をセットしておけばそこを使ってくれます。

またキャッシュした際のPodの内容はハッシュ値を計算してあるので、元のPodが更新された場合に古いキャッシュは参照しないようになっています。

パフォーマンス

では実際にどれくらいPodの表示速度が速くなるか、実験してみました。 横軸がPodの行数、縦軸が表示までの秒数(小さいほうがベター)です。

f:id:furuyamayuuki:20140427222007p:plain

赤が標準のperldocコマンドで実行した結果、青が本モジュールを使用した結果ですが、 赤がPodの行数に比例して遅くなってる一方、青は行数に関係なく常に高速に表示できていることがわかります。

終わりに

perldocのレンダリング結果をキャッシュするなんて相当ニッチな機能ですが、 体感的にも表示が少し速くなるので、とりあえず設定しておくといいと思います!

機能追加やバグ報告はgithubまでお願いします!

https://github.com/addsict/Pod-Perldoc-Cache

【iOS】ソースコードの編集内容を起動中のアプリにリアルタイムに反映させるiOS Runtime Previewを作りました

ソースコードで編集した内容を起動中のアプリにリアルタイムに反映させるiOS Runtime Previewというツールを作りました。

まるでインタプリタで実行しているかのように動的にアプリの挙動を書き換えることができます。

iOS Runtime Preview from Yuuki Furuyama on Vimeo.

addsict/iOSRuntimePreview

使い方

  1. iOS Runtime PreviewをGitHubからダウンロードします。

    $ git clone https://github.com/addsict/iOSRuntimePreview.git

  2. XcodeiOSアプリを実行します。シミュレータでも実機でもokです。

    img1

  3. デバッグエリアのポーズボタンを押して実行を一時停止します。

    img2

  4. 本ツールのスクリプトpreview.pyをLLDBのセッションにロードします。

    img3

  5. previewコマンドを使用して、リアルタイムに編集したいコードを指定します。これで準備完了です。

    コマンド: preview <プロジェクトディレクトリからのファイルパス>

    img4

  6. 上記で指定したコードを編集すると、起動中のアプリにリアルタイムに反映されます。

仕組み

LLDBのデバッグセッションの裏で対象ファイルの監視スレッドを動かし、アプリ起動以降にファイルに変更があれば前後のdiffを取ります。
diff情報を元に

  • コードが追加された場合
    • 追加されたラインにブレークポイントを張り、そこにヒットしたら追加されたコードをLLDBで評価して実行します。
  • コードが削除された場合
    • 削除されたラインにブレークポイントを張り、そこにヒットしたらPC(プログラムカウンタ)を次の命令のアドレスにセットし、削除されたコードは実行しないようにスキップします。
  • 同一ラインのコードが変更された場合
    • コードの削除とコードの追加が同時に行われたと判断し、上記の2つの処理を行います。

現状の制限

現状リアルタイムに反映できるソースファイルの変更には以下の制限があります。

  • 新しいif文やfor文などの制御構文は実行できません
  • 新しいメソッドを書き足すことはできません
  • 新しい変数宣言は行えません

まとめ

LLDBでコードを評価したりプログラムカウンタを直接いじったりと、けっこう強引な作りとなっています(そのため場合によってはメモリアクセス違反が容易に起こり得ます)が、 UIの微妙な変更や、少しコードをいじって様子を見たい、といった場面で手軽に使えるかなと思います。

不具合報告や機能追加などはこちらまで!

XcodeでiOSアプリの実行時に任意のコードを挿入する

よりアップデートしたツールを作りました

http://addsict.hatenablog.com/entry/2014/02/21/214500

-----------------------------------------------------------------------------

XcodeiOSアプリのデバッグ中に、

「あのコードを追加するの忘れてた!」
「ここに変数のインクリメントが必要だ!」

など、実行後に必要なコードが足りてないことに気付くことありませんか?

そこで、アプリの実行時に任意のObjective-Cコードを実行バイナリに擬似的に追加できるツールを作りました。

addsict/iOSRuntimePreview

iOS Runtime Preview from Yuuki Furuyama on Vimeo.

使い方

  1. ツールをダウンロードします。

    $ git clone https://github.com/addsict/inscode.git

  2. XcodeiOSアプリを実行します。シミュレータでも実機でもokです。

    img1

  3. 任意のタイミングでデバッグエリアのポーズボタンを押して実行を一時停止します。

    img2

  4. 本ツールのスクリプトinscode.pyデバッグエリアからLLDBのセッションにロードします。これで準備完了です。

    img3

  5. inscodeコマンドをデバッグエリアで実行し、挿入したいコードを指定します。挿入されたコードはすぐに有効になります。

    コマンドのフォーマット:
    inscode <ファイル名>:<行番号> '<挿入したいObjective-Cコード>'

    img4

このツールはアプリ自体にプラグインとして組み込む必要がないので、手軽に使えると思います。 是非試してみてください。

アプリのランキングをリアルタイムにGoogle Spreadsheetにレポートする

AppStoreのアプリのランキングをGoogle SpreadsheetにリアルタイムにレポートするGoogle Apps Scriptを書きました。

addsict/AppStoreRankingReport

f:id:furuyamayuuki:20140215130412p:plain

グラフも設定しておけば随時更新されるので、アプリリリース直後におすすめです。 Google Spreadsheetは簡単にメンバーと共有できるので便利ですね。

Mac OS X上でのv8のビルド時のリンクエラー

どのバージョンからかわかりませんが、v8をOS X上でドキュメントに書いてあるようにビルドするとコケます。 具体的には以下のようにビルドすると、

g++ -Iinclude hello_world.cc -o hello_world out/{architecture}/libv8_{base,snapshot}.a -lpthread

リンクで失敗します。

ld: symbol(s) not found for architecture x86_64

これはlibv8_base.alibv8_snapshot.a以外にもlibicudata.a, libicui18n.a, libicuuc.aなどのライブラリが必要だからです。

なのでそれらも全て一緒にビルドすればokです。

g++ -Iinclude hello_world.cc -o hello_world out/{architecture}/*.a -lpthread

もしくはスタティックライブラリのビルド時にi18nsupport=offにしておけば、libv8_base.alibv8_snapshot.aだけで問題なくビルドできます。

make x64.debug -j4 console=readline i18nsupport=off

ハマってしまったので共有。

類似しているGitHub Issue発見ツール Refissue を作りました

GitHubのIssueは便利ですが、複数人で利用しているとどうしても似たようなIssueが登録されてしまうことがあります。 そこで、類似しているIssueを自動的に検出してくれるRefissueというツールを作りました。

https://github.com/addsict/refissue

このツールを動かしておくと、Issueが登録された時に過去のIssueの中から似たようなIssueを探しだし、下の写真のようにコメントとして残してくれます。

img

本当に同一の内容の場合、登録したIssueをcloseするなり、まとめるなりしてIssueの重複を防げますね。

肝心の類似判定ですが、今はIssueのタイトルと本文を形態素解析したものの中からキーワードとなる形態素のみ抽出し、コサイン類似度法でIssue間の類似度を求めています。

類似判定の精度がまだまだイマイチな所はありますが、是非使ってみてください。

git-add, git-commitを使わずにコミットする方法

cf.) Git Internals - Git Objects

  1. blobオブジェクトを作る
  2. treeオブジェクトを作る
  3. commitオブジェクトを作る

blobオブジェクトを作る

$ echo 'hello world' > test
$ git hash-object -w test
# 3b18e512dba79e4c8300dd08aeb37f8e728b8dad

treeオブジェクトを作る

$ printf "100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad\ttest" | git mktree
# 5b873f747ccb268e4491f289eb37fc675ff5825b

もしくは

$ git write-tree
# 5b873f747ccb268e4491f289eb37fc675ff5825b

commitオブジェクトを作る

$ echo "first commit" | git commit-tree 5b873f747ccb268e4491f289eb37fc675ff5825b
# 6684f9fdfbdd60db2ba2851c97aa08aa76ad9487
$ git log 6684f9fdfbdd60db2ba2851c97aa08aa76ad9487