Sinatra(というかRack)で複数の同名パラメータを受け取る

はじめに

Sinatra

  http://localhost:4567/?foo=123&foo=456&foo=789

って感じで複数の同名パラメータを送ったら

require 'sinatra'
get '/' do
  params[:foo] #=> 789
end

のように、最後の1つしか取ってくれませんでしたf**k!
そんなわけで、全部取り出すにはどうすればいいのか調べてみました。

環境

結論から言うと

そもそもSinatra(というよりRack)では、複数の同名パラメータを受け取る場合は

  http://localhost:4567/?foo[]=123&foo[]=456&foo[]=789

のように、キーの後ろに [] をつけるのが正解のようです。
こうすると、

require 'sinatra'
get '/' do
  params[:foo] #=> ["123", "456", "789"]
end

のように、値を配列で取り出すことができます。このあたりはたぶんRailsでも一緒です。

そんなのヤダヤダ、という場合は?

  http://localhost:4567/?foo=123&foo=456&foo=789

という形式でパラメータが渡された場合でも同様の動作にするには、

Rack::Utils.parse_query(qs, d = nil)

でパラメータの文字列(上記でいうと foo=123&foo=567&foo=789)をバラしてやればOKです。


パラメータの文字列は、

  • GETの場合:
@env['rack.request.query_string']
  • POSTの場合:
@env['rack.request.form_vars']

に格納されています。
というわけで、

require 'sinatra'
# http://localhost:4567/?foo=123&foo=456&foo=789 でアクセス

get '/' do
  # GETのときは @env['rack.request.query_string']
  hoge = Rack::Utils.parse_query(@env['rack.request.query_string'])
  hoge['foo'] #=> ["123", "456", "789"]
end

post '/' do
  # POSTのときは @env['rack.request.form_vars']
  hoge = Rack::Utils.parse_query(@env['rack.request.form_vars'])
  hoge['foo'] #=> ["123", "456", "789"]
end

のようにすれば、キーの後ろに [] が無い場合でも複数の同名パラメータを扱えます。
ただし、この場合は

  http://localhost:4567/?foo[]=123&foo[]=456&foo[]=789

のように指定されると、キー名が 'foo[]' と解釈されます。

require 'sinatra'
# http://localhost:4567/?foo[]=123&foo[]=456&foo[]=789 でアクセス

get '/' do
  hoge = Rack::Utils.parse_query(@env['rack.request.query_string'])
  hoge['foo'] #=> nil
  hoge['foo[]'] #=> ["123", "456", "789"]
end

まとめ

  • Sinatra(というかRack)で複数の同名パラメータを使うときは ?foo[]=1&foo[]=2 みたいにキーの後ろに [] をつける
  • Rack::Utils.parse_queryでパラメータの文字列を自前でバラせば ?foo=1&foo=2 みたいなのも扱える

続・CI超入門〜Jenkinsのススメ2 CI導入の壁を越えろ〜 に行ってきました。

はじめに

2月22日に行われた「続・CI超入門 〜 Jenkinsのススメ2 CI導入の壁を越えろ 〜」に行ってきました。

Jenkinsの導入 (CloudBees, Inc. 川口 耕介さん)

CIやJenkinsを導入するにあたってのお話でした。
デモで出てきたTest Driveを使えば、手軽にJenkinsを試せそうです。

継続的インテグレーション(CI)の発想
  • ビルドを頻繁に実行しよう
  • テストを頻繁に実行しよう
  • 問題が発生したらときすぐに発見できるようにしよう
CIとは
  • 命綱
  • 火災報知機
    • 問題があったらすぐにわかる
    • 普段ちゃんと動いていることが前提(「警報鳴ってるけど、いつものことだからいいよ」って感じになってしまう)。問題が見つかったらすぐに直すことが必要。
CIするのにあるとよいもの
  • バージョン管理システム
    • 誰の変更で壊れたのかわかるようにするため
  • 自動化されたビルドスクリプト
    • ビルドがない言語の場合は品質検査で代用
  • 自動化されたテストスクリプト
デモ
  • ジョブを作る
    • 新規ジョブ作成 > ジョブ名を入れて選ぶ(フリースタイルがおすすめ)
    • ジョブとは?
      • 基本的にはソフトウェアのビルドを模している
      • ビルドするのにどんな条件・ツールなのかがわかるのも利点の1つ。ログを見るのを手助けする役割もある。
      • テストを実行して失敗すると、どのコミットのせいなのか、とかそのときのエラーメッセージ、スタックトレースも表示される

Jenkins + EC2で分散ビルド (Sky株式会社 玉川 竜司さん)

ビルドは負荷の変動が激しい作業のため、Amazon EC2上で動かしてしまおうというお話でした。

Amazon EC2でJenkinsを動かす話
  • ビルドは負荷の変動が激しい(リリース前は高負荷、とか)
  • Amazon EC2ならピークにあわせてハードウェアを用意しなくていい!!
    • EC2で勝手にスレーブを動的に増減してくれる
    • 1時間ごとの従量課金
  • セキュリティは大丈夫?→Amazon Virtual Private Cloud(VPC)やDirect Connectで対応
EC2 Pluginで高負荷時にスレーブを自動的に起動
  • EC2 Pluginを使えば、EC2のインスタンスを自動的に起動・終了してくれる
  • 注意点
    • 設定はちょっと引っかかるかも
    • UbuntuのAMIをベースにするとうまくいった
    • 64bitインスタンスは今のところ使えない

LT(1): Startup Jenkins! 〜CIから始めないJenkins入門〜 (@kanu_さん)

JenkinsはCIだけでなく、高機能なcronとしても使えるというお話でした。その発想はなかった!
紹介されていたTracLightningを使えば導入も非常に簡単にできそうです。

CIできてないとJenkinsに入門できない?→否!
  • 高機能cronとして使える
  • Windowsのタスクがイケてない→そうだ、Jenkinsを使おう!
    • スケジュールとかログとかの管理も楽だし実行結果とかもWeb UIから見れる。処理が終わったらメール送信も可能。
TrachLightningを使えば5分で導入完了
  • JenkinsやらTracやら必要なものがひと通り揃っている
  • Jenkinsのビルドサンプルもたくさん付属

LT(2): <すいませんタイトル忘れました> (@cactusmanさん)

Jenkinsをどうやって社内に導入するか、というお話でした。
様々な工夫がありましたが、最終手段は「会社を変える」だそうですw

構想編
  • コストをかけない
    • ダメならすぐ撤退
  • 何がしたいかを決めておく
    • テストがしたいのか、常にリリースできる状態を保ちたいのか
サーバ編
  • 空いているサーバを確保
  • どっかに寄生
  • 上司を説得するには実際に動くものを見せるのが効果的
    • グラフとか。マネージャの人はそういうの大好きなので。
ビルド編
  • ビルドスクリプトは書きましょう
  • 静的解析ツールを動かすのに使うのもアリ
通知編
  • まずは自分だけ
    • いきなり失敗してるのがみんなに通知されると、何事か!?となるので
  • 安定してきたらみんなが見る場所へ

まとめ

Jenkinsを簡単に試せるTest DriveやTracLightningのことを知ることができたり、Jenkinsを定期実行ジョブや静的解析ツールを動かすために使うというアイディアなど、いろいろ学ぶことができました。
そんなわけで、早速Jenkinsをインストールしていろいろ試してみようと思います。

*1:手元のUbuntu11.10ではファイルを右クリックして「別のアプリで開く」→「IcedTea Java 6 Web Start」で実行できました

logstudy01 & mailerstudy02に行ってきました

rsyslog入門 @ttkzw さん

syslogの概要や問題点、rsyslogの特長や設定方法などを解説していただきました。

syslogとは
  • カーネルやアプリケーションから通知されたイベントメッセージをログファイルに記録する仕組み
  • 問題点
    • デバイスとsyslogサーバとの通信にはUDPを使用しているため、信頼性がない→ログメッセージの取りこぼし、送信元の詐称の可能性がある
    • 暗号化できない
    • 自分でログローテートできない
    • fsyncするのでディスクIOが非効率
  • syslogのログ取りこぼしの原因は2つ
    • UPDでの通信のため、パケットの取りこぼしがある
    • CPUの負荷が高い場合は受け取ったメッセージを処理できず、メッセージが消えてしまう
代替のsyslogデーモン
  • syslog-ng: syslogと設定ファイルの互換性がない
  • rsyslog: syslogと設定ファイルの互換性がある程度維持されてる, 最近のLinuxでよく使われてる
rsyslogとは
  • syslogのフォーク
  • rsyslogの r は reliable で、メッセージ転送の信頼性を表している
  • TCPとかRELPとかRFC3195とかで通信することでメッセージ転送の信頼性が向上
  • 転送先のサーバがダウンしてる場合でも、rsyslogはメッセージをキューイングして再送してくれる(syslogはキューイングしない)
  • プラグインモジュールによる機能拡張が可能
rsyslogのバージョン
  • ver.4, 5, 6があって、5と6は開発が続いている
  • 後方互換モード(rsyslog -c0 で起動)は ver.6 でなくなったので、使いたい場合はver.5を使用
rsyslogのモジュールとか設定とかの話
  • モジュール特有のディレクティブはそのモジュールのロード後に書く
  • rsyslogの公式Webドキュメントに説明がないディレクティブが半分ぐらいあるので、名前から判断してくださいw
  • rsyslogのセレクタ拡張機能
    • [facility].=[severity] でseverityに一致するもの
    • [facility].!=[severity] で一致しないものを指定
  • アウトプットモジュールのomudpspoofは偽装した送信アドレスでUDPでメッセージを送信する。転送するときに元のアドレスで送りたいときに使うらしい。

メール暗号化入門 -アリスとボブの恋の行方- @ttkzw さん

一般的な暗号方式や暗号通信で使用されるプロトコルなどについて、解説していただきました。
2セッション続けて@ttkzwさんが担当されていました。なんという@ttkzwさん無双w

暗号技術
  • メールの脅威:盗聴、否認、改ざん、詐称→脅威への対策として暗号技術を利用
  • ほとんどはセッション鍵(一定時間だけ有効な鍵)を使って暗号化。セッション鍵を公開鍵方式で渡して、あとは共通鍵方式でやりとりする。
  • PGPは信頼の輪:友達の友達はみんな友達
  • 公開鍵暗号では鍵配送が問題となる(暗号化は常に鍵配送との戦い)
    • 対策として公開鍵証明書を使用
    • 認証局自身の証明書を証明する仕組みが公開鍵基盤(PKI)
    • ルート認証局ルート証明書はOSやソフトウェアにバンドルして配布
SSL/TLS
  • SSL/TLS: インターネット上の安全な通信を提供するプロトコル
    • TCP/IP通信に対して透過的に使える
    • ダウングレード攻撃の影響を受けるため、SSL2.0は無効にしなきゃダメ
  • SMTPS: SMTPSSL/TLSで暗号化するプロトコル
    • TCP 465番ポートを慣習的に使ってるけどIANAに正式に登録されていない(慣習的に使ってる)
    • メーラからSMTPサーバへのメール送信時のみで使われてて、SMTPサーバ同士のやりとりでは使えない
メール特有の話
  • SMTP,POP3,IMAPのセッション中にSTARTTLSコマンドでTLS通信に切り替える
    • POP3だとなぜか短縮されてて STLS になってる
  • SMTPサーバと接続確認するには
    • SMTPS: openssl s_client -connect localhost:465
    • STARTTLS: openssl s_client -connect localhost:587 -starttls smtp
  • IMAPサーバとの接続確認
    • IMAPS: openssl s_client -connect ホスト名:993
    • STARTTLS: openssl s_client -connect ホスト名:143 -starttls imap
  • POP3サーバとの接続確認
    • POP3S: openssl s_client -connect ホスト名:995
    • STARTTLS: openssl s_client -connect ホスト名:110 -starttls pop3
  • STARTTLS以外はメール特有のものはない。SSL/TLSTCP/IP通信に対して透過的に使える。

logと監視の微妙な関係 〜こんなlogはイヤだ〜 @qryuuさん

logstudyの第1回として、ログの出力方法が悪いせいでうまくログがとれないケースの実例(主にZabbix)を紹介していただきました。

資料↓
https://docs.google.com/presentation/pub?id=1wGLr5am-N4WfeXiGculVxZFdw140w18nbnkIPtmJ4W4

  • イベントビューワでは日本語のメッセージなのにZabbixで収集してみたら英語になってる!?
    • そもそもメッセージのDLLが作成されていないとか、Windows2008で追加されたWidowsイベントログ6.0を使っていると、APIの互換性が無いためZabbixで取れないとか…
  • ログローテーションすると文字化けする!?
    • ローテーションした瞬間に圧縮されてしまったため。1世代前までは圧縮しないようにして解決。
  • logが変なところで改行される!?
    • Zabbixはファイルエンドを改行として扱うため、メッセージを途中でフラッシュするとそこで改行されてしまう。途中でフラッシュしちゃダメ
  • logが遅れて出力される!?
    • syslogの仕様。-mark-オプションをつけるかrsyslogを使う

まとめ

そんなわけで、logstudy01 & mailerstudy02に行ってきました。

第5回 Ruby/OpenCV進捗報告

はじめに

気がついたら2012年になってましたが、Ruby/OpenCVもじわじわと進化を続けております。

進捗

開発リポジトリが移動しました!

GitHubでOrganizationアカウントを作って、メインのリポジトリをそっちに移してみました。
そんなわけで、今後のメインリポジトリ

ruby-opencv/ruby-opencv - GitHub

になります。

ser1zw/ruby-opencv - GitHub のほうは機能追加とかするときの作業用に使う予定です。

Windows(mingw32, mswin32)に対応しました!

ようやくWindowsでも動くようになりました。
と言ってもまだバイナリ配布はしてないので、自前でのビルドが必要です。


前提条件
OpenCVのインストールが必要です。
OpenCV2.3.1の入手、ダウンロード、インストール、環境設定 | イメージングソリューションなどを参考にインストールしてください。dllのパスの設定も忘れずに!
なお、以降の説明では、OpenCVが C:\path\to\opencvdir にインストールされているものとします。


mswin32の場合
mswin32の場合はVisual C++ (Express EditionでOK)を入れて、Visual Studioコマンドプロンプトから下記のコマンドを実行します。

$ git clone git://github.com/ruby-opencv/ruby-opencv.git  # またはGitHubからzipファイルをダウンロードして展開
$ cd ruby-opencv
$ ruby extconf.rb --with-opencv-dir=C:\path\to\opencvdir\bin\install  # 自分でビルドしたOpenCVを使う場合(バイナリ版を使う場合は下記参照)
$ nmake
$ nmake install

バイナリ配布されているOpenCVをそのまま使う場合は、includeフォルダが C:\path\to\opencvdir\build\include 、libフォルダが C:\path\to\opencvdir\build\x86\vc10\lib となるので、extconf.rb のオプションを

$ ruby extconf.rb --with-opencv-include=C:\path\to\opencvdir\build\include --with-opencv-lib=C:\path\to\opencvdir\build\x86\vc10\lib

みたいな感じにしてください。


mingw32の場合
mingw32の場合はMinGWのgcc, g++, MSYSを入れて*1、MSYSのコンソールから下記のコマンドを実行します。

$ git clone git://github.com/ruby-opencv/ruby-opencv.git  # またはGitHubからzipファイルをダウンロードして展開
$ cd ruby-opencv
$ ruby extconf.rb --with-opencv-dir=/C/path/to/opencvdir/install  # 自分でビルドしたOpenCVを使う場合
$ make
$ make install

mswin32と同様、バイナリ配布されているOpenCVを使う場合は、

$ ruby extconf.rb --with-opencv-include=/C/path/to/opencvdir/build/include --with-opencv-lib=/C/path/to/opencvdir/build/x86/mingw/lib

みたいな感じで指定してください。

ffcallが不要になりました!

これで余計な依存ライブラリがなくなり、インストールがちょっとだけ楽になりました。やったね!

今後の展開

とりあえず

  • gem install hogehoge でインストールできるようにしたい
    • rubygems.orgで公開?
    • Windows用はバイナリも配布したい
  • 全文検索機能付きのリファレンスを作りたい
    • るりまサーチ的なやつ
  • C++版の機能を追加したい
    • DescriptorMatcherとか

みたいなことを考えてます。他にもこんな機能ほしい!とかありましたらお知らせください。

デモ

cvAdaptiveThresholdのラッパーを追加したので、そのサンプルコード的なやつを書いてみます。
環境は

です。

# -*- encoding: utf-8 -*-
require 'opencv'
include OpenCV

img = IplImage.load('Lenna.jpg', CV_LOAD_IMAGE_GRAYSCALE)

# CvMat#adaptive_threshold(max_value, options = nil)
#   max_value (Integer) - 最大値
#   options (Hash) - オプションパラメータ
#     :adaptive_method - 使用するアルゴリズム (:mean_c または :gaussian_c)
#     :threshold_type - しきい値処理の種類 (:binary または :binary_inv)
#     :block_size - しきい値を計算するときのブロックサイズ
#     :param1 - 各手法で使うパラメータ
result1 = img.adaptive_threshold(255, :block_size => 25)
result2 = img.adaptive_threshold(128, :adaptive_method => :gaussian_c, :threshold_type => :binary_inv, :block_size => 5, :param1 => 10)

GUI::Window.new('original').show img
GUI::Window.new('mean_c').show result1
GUI::Window.new('gaussian_c').show result2
GUI::wait_key
GUI::Window.destroy_all

結果はこんな感じ。いい感じにしきい値処理がされています。

f:id:ser1zw:20120216003049p:image

まとめ

そんなわけで、第5回Ruby/OpenCV進捗報告でした。

リポジトリはこちら

ruby-opencv/ruby-opencv - GitHub

人柱、Pull Request、ご要望、バグ報告等は大歓迎です!

*1:インストーラからC Compiler, C++ Compiler, MSYS Basic System, MinGW Developer Toolkitあたりを入れておけば大丈夫なはず http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/

xyzzyのフィルタコマンドであっと言う間に仕事を終わらせる

(インスパイア元: Emacs のキーボードマクロであっと言う間に仕事を終わらせる (フェンリル | デベロッパーズブログ))


こんにちは。お仕事PCをEmacsキーバインドにして周りから冷たい目で見られる担当のser1zwです。

今日はみんな大好きなxyzzyでテキストファイルを処理するときに役立つフィルタコマンドを紹介します。

どんな時に役に立つの?

ふだんの暮らしの中で、CSVのような行を中心としたテキストデータを扱う機会がよくあると思います。たとえば、1行に3つデータがあるCSVで、いちばん左のデータだけを削除したい場合、どうするでしょうか?

たとえばこんなファイルです。

abcd,ef,ghi
jk,lmno,pqr
stu,vwx,yz0
...(2000行くらい続く)

これを次のようにしたいわけです。

ef,ghi
lmno,pqr
vwx,yz0
...(2000行くらい続く)

手作業で1つひとつ心をこめて編集するとか、見なかったことにするとかいろいろと選択肢はありますが、ここではあえて、xyzzyと適当なプログラミング言語さえわかっていればできてしまうxyzzyのフィルタコマンドを使ってみましょう。

フィルタコマンドとは

フィルタコマンドは、xyzzyのバッファ内またはリージョンの内容を標準入力につなげて、任意のコマンドを実行し、その出力結果に置き換えることができる機能です。
バッファ内すべてを対象としたい場合は filter-buffer (C-x #) を、リージョンのみを対象としたい場合は filter-region (C-x |) を実行します。
任意のコマンドとしてPerlやRubyなどのワンライナーを実行することで、割と何でもできます。

何をするか決める

今回のような作業をフィルタコマンドで行う手順は次のようになります。

  1. ある行を目的どおり処理するワンライナーを書く(今回はRubyで)
  2. すべての行に適用する

では、1行目を例にどんな処理が必要か考えてみましょう。

abcd,ef,ghi

この行から、次のように1つめのデータを削除したいわけです。

ef,ghi

Rubyistなら考える前に手が動きますね。

print 'abcd,ef,ghi'.split(',')[1..-1].join(',') #=> ef,ghi

これをxyzzyのバッファで実行すればよさそうですね。

さっそく実行してみる

心の準備はいいでしょうか?

では、C-x # で filter-buffer コマンドを実行してみましょう。実行するとカーソルがミニバッファに移動します。ここに書かれたコマンドに対して、バッファの内容が標準入力から渡され、実行されます。

f:id:ser1zw:20120118030933p:image

実行するコマンドはこんな感じにしてみます。

ruby -ne "print $_.split(',')[1..-1].join(',')"

Rubyの-e オプションを設定すると、ファイルではなくコマンドラインから渡されたスクリプトを実行します。

-n オプションを設定すると、プログラム全体が

while gets
  ...
end

で囲まれているように動作します*1Rubyのオプションの詳しい話はこのへんとかを見てください。

標準入力の内容は、組み込み変数 $_*2 を使って取り出しています。

Rubyに -n オプションを指定して実行するため、 $_ にバッファの内容が1行ずつ入ってきます。そこで、 $_ に対して1行ごとに実行したい処理を適用すればOK、というわけです。

ためしてみる

C-x # を実行してミニバッファに書いたコマンドは、そのままEnterキーを押せば実行できます。さっそく適当なバッファで試してみましょう。

f:id:ser1zw:20120118034541p:image

うまくいきましたか? うまくいかない場合は、もう一度ワンライナーを見直してみましょう。C-x # を再度実行し、C-p (上キーでもOK)を押すと、実行したコマンドの履歴が見れますので、よーく見て直してください。

選択したリージョンのみに適用!

うまくいったら、今度は選択したリージョンのみで実行するようにしてみます。ここでわざわざ新しくバッファを作って必要な部分だけコピペして filter-buffer!!というのはちょっと野暮なのでやめておきましょう。

まずは適用したい行をすべてリージョン指定(選択)します。そして、おもむろに C-x | を押し、先ほどと同じようにコマンドを書きます。

f:id:ser1zw:20120118030935p:image

さぁ、いかがですか?コマンドが選択したリージョンのみに適用されているはずです。ちなみに、C-x | は filter-region というコマンドを呼び出しています。

こうして、1行ずつ手でやっていたら気の遠くなるような作業も一撃で済んでしまうわけです。

まとめ

今回実行したワンライナーはかなり単純なものですが、使う言語でできることなら大概何でもできてしまうので、かなりいろんな場面で使えます。 再利用性など考えず、その場で必要なワンライナーを書いて、使ったら、あとは忘れてしまって構いません。どうせ履歴見れるし。

最近使ったワンライナーとしては、「ずらーっと書かれたデータからSQLを生成する」「ログファイルから必要な列だけ抜き出し、ちょっとだけ加工する」などが役に立ちました。「単純作業だけど、スクリプトを書けば一瞬で終わる。むしろ書かせろ。」という時はxyzzyのフィルタコマンドでさくっと仕事を終わらせて、まわりのみんなにドヤ顔をご披露ください。


参考: xyzzyでプログラミング/空行、行末空白などの削除

あわせて読みたい: Emacs のキーボードマクロであっと言う間に仕事を終わらせる (フェンリル | デベロッパーズブログ)

*1:場合によっては -p オプションにしてもいいかもしれません。この辺はお好みで。

*2:最後に gets または readline で読み込んだ文字列が入っています http://www.ruby-lang.org/ja/old-man/html/_C1C8A4DFB9FEA4DFCAD1BFF4.html

オープンソースのAndroid用USBテザリングアプリ「AziLink」をMacで使う

はじめに

MacBook Airを外で使っていると、外でネットが使いたくなるものです。しかし、外で必ずしもWiFiが使えるわけではないのが現実。
そこで手持ちのAndroid端末でUSBテザリング!となるわけですが、有名どころのアプリだとWindows専用だったりhttpsが有料版でしかできなかったりして*1微妙な気持ちに。
そんな折、無料でWindows/Mac/Linux対応でhttpsも使えるオープンソースAndroid用USBテザリングアプリ AziLink を見つけたので、Macにインストールしてみました。

環境

  • Mac OSX 10.7.2 (Lion)
  • IS06 (Android 2.2.1)

インストール

1. Android端末をMacに接続し、USBデバッグと野良アプリインストールができるようにする
Android端末をMacにUSB接続し、Android端末側で

  • 設定→システム→アプリケーション→提供元不明のアプリ にチェックを入れる
  • 設定→システム→アプリケーション→開発→USBデバッグ にチェックを入れる

を行います。上記はIS06の場合ですが、他の端末だとちょっと違うかもしれないので、適当に探してください。
このあとAndroid端末にソフトウェアのインストールなどを行うので、接続したまま置いておきます。

なお、MacならAndroid用USBドライバは不要ですが、Linuxでやる場合はudevファイルを作成、WindowsならOEMのドライバのインストールが必要らしいです。


2. Tunnelblickのダウンロードとインストール
Mac用のOpenVPNクライアントであるTunnelblickをインストールします。
どうやら安定版の3.1.7はLionで使えないようなので、Beta版のTunnelblick 3.2beta36をダウンロードします。dmgファイルをダブルクリックしてインストーラを起動し、そのまま進めていけばOKです。
起動するとVPNの設定ファイルをどうするかとか聞いてきますが、放っときます。


3. TunTapのインストール
OpenVPNで使う仮想ネットワークカーネルドライバTunTapをインストールします。

http://sourceforge.net/projects/tuntaposx/files/tuntap/ から最新版(今回は tuntap_20111101.tar.gz)をダウンロードして展開し、中にある tuntap_20111101.pkg を起動してインストーラを進めていけばOKです。
インストールが完了したら、マシンの再起動をします。


4. Android SDKのインストール
Android SDKに含まれるadbが必要*2なので、インストールします。
http://developer.android.com/sdk/index.html からMac用(今回はandroid-sdk_r16-macosx.zip)をダウンロードし、適当なところに展開しておきます。
展開すると android-sdk-macosx みたいな名前のフォルダになるので、

$ cd android-sdk-macosx/tools
$ ./android

でAndroid SDK Managerを起動し、Android SDK Platform-toolsを選択してインストールします。
f:id:ser1zw:20111215042342p:image
android-sdk-macosx/platform-tools/ に adb というファイルがあればOKです。
adbはAziLinkを実行する際にも使うので、パスを通しておきましょう。


5. AziLinkのインストール
https://code.google.com/p/azilink/downloads/list から 最新版の.apkファイル(今回はazilink-2.0.2.apk) をダウンロードします。
そして4.でインストールしたadbを使用し、下記のコマンドでAndroid端末にインストールします。

$ adb install azilink-2.0.2.apk



6. Mac OSX Lionでの起動用シェルスクリプトのダウンロード
Tethering OS X Lion to Android - Bryce Boeで紹介されている https://gist.github.com/1302227 をダウンロードし、実行権限をつけて適当な場所に保存しておきます。

$ wget https://gist.github.com/raw/1302227/d2e23c6754017f865cb742667ce73852661a0e64/tether.sh
$ chmod +x tether.sh


以上でインストールは終了です。超めんどくさいですね!!

USBテザリングする

1. Android端末をMacにUSB接続する
普通に接続します


2. Android端末側でAziLinkを起動し、「Service active」にチェックを入れる
Statusが「Waiting for connection」になっていればOKです。


3. Macで起動用シェルスクリプトを実行する
「インストール」の6.で保存したシェルスクリプトを実行します。保存した場所でターミナルから

$ ./tether.sh

とかやればOKです。
このとき、adbにパスが通っていないとシェルスクリプトが実行できないので、事前にパスを通しておきましょう。

USBテザリングを終了するには、3.のシェルスクリプトをCtrl+Cで止めればOKです。

使い勝手はどうなのよ?

無料なのにプロトコルの制限が無いため、使い勝手はかなりいいです。
速度はスピードテスト | USENの回線速度測定で計測したところ、2.5Mbpsぐらい出てました。
普通にTwitterしたりGmail見たりするには十分かと思います。

まとめ

オープンソースAndroid用USBテザリングアプリであるAziLinkをIS06にインストールし、MacでUSBテザリングしてみました。今回はMacでやっていますが、AziLinkはWindowsとLinuxにも対応しているようなので、そちらでも試してみたいところです。
インストールは超めんどくさいですが使い勝手は非常にいいので、ぜひ使ってみてください。

*1:つまりTwitterGmailも使えない

*2:AziLinkのFull downloadに含まれるadbはWindows用のみ

Rubyの拡張ライブラリを作ってみよう!

はじめに

Ruby Advent Calendar jp: 2011 : ATNDの17日目の記事です。昨日は@yoppiblogさんのSeleniumの自動テストをCI環境(Jenkins)で快適に実施するでした。


Rubyを使ってて
遅い…ここだけ超遅い…
とか
あのライブラリが使いたい!でもRuby用のライブラリじゃないし…
みたいなこと、ありますよね?
そんなとき、Rubyの拡張ライブラリで解決できるかもしれません。


Rubyの拡張ライブラリは、普通のライブラリと異なりC(とかC++とかその他の言語とか)で作成します。そのため、Rubyで直接書くよりも高速に処理できたり、Cのインタフェースが用意されているライブラリをRubyから呼びだしたりすることができます。すばらしい!
そんなわけで、拡張ライブラリの作り方をざっくり説明したいと思います。

用意するもの

最小限のRuby拡張ライブラリ

Rubyの拡張ライブラリを作成してから使うまでの流れは、

  1. Cでコードを書く
  2. Makefileを生成するためにextconf.rbを書く
  3. Makefileを生成して make && make install する
  4. 使う

みたいな感じです。


1. Cでコードを書く
foo というライブラリを作ることにしましょう。
まず適当にディレクトリを作って

$ mkdir foo
$ cd foo

こんな感じのコードを書きます。

/* foo.c */
#include <stdio.h>

/* require 'foo' とやると、Init_foo() が呼ばれる */
void Init_foo()
{
  puts("Init_fooですよー");
}

拡張ライブラリでは、

require 'ライブラリ名'

をやると

Init_(ライブラリ名)

が呼び出されます。普通はここでクラスやメソッドの定義などをやります。


2. Makefileを生成するためにextconf.rbを書く
Makefileを生成するためのスクリプトをRubyで書きます。下記のようなファイルをextconf.rbという名前で作成しましょう。

require 'mkmf'
create_makefile('foo')

mkmfをrequireして create_makefile(ライブラリ名) とするだけで、とりあえずMakefileを生成できます。


3. Makefileを生成して make && make install する
extconf.rb を普通に実行すればMakefileが生成されるので、普通に make && make install すればOKです。

$ ruby extconf.rb 
creating Makefile
$ make
compiling foo.c
linking shared-object foo.so
$ make install
/usr/bin/install -c -m 0755 foo.so /path/to/ruby-1.9.3-p0/lib/ruby/site_ruby/1.9.1/i686-linux
installing default foo libraries


4. 使う
普通にrequireするだけ。他のライブラリと全く同じです。

$ irb
ruby-1.9.3-p0 :001 > require 'foo'
Init_fooですよー
 => true 
ruby-1.9.3-p0 :002 > 

クラスとメソッドを定義する

クラス、メソッドを定義するには、それぞれrb_define_class()、rb_define_method()を使います。

/*
  name: クラス名
  super: 親クラス
  戻り値: 定義したクラス
*/
VALUE rb_define_class(const char *name, VALUE super);
/*
  klass: メソッドを定義するクラス
  name: メソッド名
  func: メソッド実行時に呼び出されるCの関数
  argc: メソッドの引数の数
  戻り値: なし
*/
void rb_define_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc);

VALUE型は、Rubyのオブジェクトを指すポインタです。引数や戻り値でRubyのオブジェクトをやりとりする際は、このVALUE型を使います。


また、privateメソッドを定義するrb_define_private_methodもあります。initializeメソッドを定義するときにはこっちを使いましょう。

/*
  klass: メソッドを定義するクラス
  name: メソッド名
  func: メソッド実行時に呼び出されるCの関数
  argc: メソッドの引数の数
  戻り値: なし
*/
void rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc);


では、さっきのfoo.cをこんな感じに変えて、FooクラスとFoo#addメソッドを定義してみます。

/* foo.c */
#include <stdio.h>
#include <ruby.h>

VALUE cFoo; /* Fooクラス */

/* self はメソッドの呼び出し元オブジェクト */
VALUE bar_func(VALUE self)
{
  puts("Foo#barですよー");
  return self;
}

void Init_foo()
{
  /* Fooクラスを定義 */
  cFoo = rb_define_class("Foo", rb_cObject);
  
  /*
    Fooクラスに引数0個のbarメソッドを定義
    barメソッドが呼ばれると、bar_funcが実行される
  */
  rb_define_method(cFoo, "bar", RUBY_METHOD_FUNC(bar_func), 0);
}


こんな感じで実行します。ちゃんと bar_func が呼ばれてますね。

$ ruby extconf.rb && make && make install
$ irb
ruby-1.9.3-p0 :001 > require 'foo'
 => true 
ruby-1.9.3-p0 :002 > foo = Foo.new
 => #<Foo:0x88f0d60> 
ruby-1.9.3-p0 :003 > foo.bar
Foo#barですよー
 => #<Foo:0x88f0d60> 
ruby-1.9.3-p0 :004 > 

Rubyの値とCの値を変換する

実際の拡張ライブラリでは、Rubyの値とCの値との変換が必要になります。
よく使うのはこのへんです。

関数名 用途
int NUM2INT(VALUE x) Rubyの数値をCのint型に変換
double NUM2DBL(VALUE x) Rubyの数値をCのdouble型に変換
char* StringValuePtr(VALUE str) Rubyの文字列をCのchar*に変換
VALUE INT2NUM(int x) Cのint型をRubyの数値に変換
VALUE DBL2NUM(double x) Cのdouble型をRubyの数値に変換
VALUE rb_str_new2(const char* ptr) Cのchar*型をRubyの文字列に変換


こんな感じで使います。

#include <stdio.h>
#include <ruby.h>

VALUE cFoo;

VALUE bar_func(VALUE self, VALUE i_val, VALUE d_val, VALUE s_val)
{
  /* Rubyの値をCの値に変換して */
  int i = NUM2INT(i_val);
  double d = NUM2DBL(d_val);
  char* s = StringValuePtr(s_val);

  /* なんか処理して */
  double x = i + d;
  printf("[%s : %d + %lf = %lf]\n", s, i, d, x);

  /* Cの値をRubyの値に変換して返す */
  return DBL2NUM(x);
}

void Init_foo()
{
  cFoo = rb_define_class("Foo", rb_cObject);

  /* Foo#barは引数を3つ取るように変更 */
  rb_define_method(cFoo, "bar", RUBY_METHOD_FUNC(bar_func), 3);
}


Foo#barに引数を3つ与えて実行してみましょう。

$ ruby extconf.rb && make && make install
$ irb                                    
ruby-1.9.3-p0 :001 > require 'foo'
 => true 
ruby-1.9.3-p0 :002 > foo = Foo.new
 => #<Foo:0x9441ea8> 
ruby-1.9.3-p0 :003 > foo.bar(1, 2.2, 'foobar')
[foobar : 1 + 2.200000 = 3.200000]
 => 3.2 

どうやらちゃんと動いてます。やったね!

さらに調べるには

まとめ

Rubyの拡張ライブラリの作り方をざっくり紹介しました。これでボトルネックもCで書かれたライブラリも怖くないはず!
もうすこし書きたいところではありますが、時間もアレなのでこのへんで。
明日は18日目、@sakairyotaさんです。