Sinatra(というかRack)で複数の同名パラメータを受け取る
はじめに
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導入の壁を越えろ 〜」に行ってきました。
- 日時: 2012/2/22 19:00-21:00
- 場所: 株式会社 豆蔵 トレーニングルーム
- ハッシュタグ: #jenkins_night
- こくちーず: http://kokucheese.com/event/index/18660/
- Togetter: http://togetter.com/li/262267
- Ustream: http://www.ustream.tv/recorded/20618625
Jenkinsの導入 (CloudBees, Inc. 川口 耕介さん)
CIやJenkinsを導入するにあたってのお話でした。
デモで出てきたTest Driveを使えば、手軽にJenkinsを試せそうです。
継続的インテグレーション(CI)の発想
- ビルドを頻繁に実行しよう
- テストを頻繁に実行しよう
- 問題が発生したらときすぐに発見できるようにしよう
CIとは
- 命綱
- 常にチェックできるので、リファクタリングなどをやるリスクが取れる
- 火災報知機
- 問題があったらすぐにわかる
- 普段ちゃんと動いていることが前提(「警報鳴ってるけど、いつものことだからいいよ」って感じになってしまう)。問題が見つかったらすぐに直すことが必要。
CIするのにあるとよいもの
- バージョン管理システム
- 誰の変更で壊れたのかわかるようにするため
- 自動化されたビルドスクリプト
- ビルドがない言語の場合は品質検査で代用
- 自動化されたテストスクリプト
デモ
- Java Web StartでJenkinsを手軽に実行できる「Test Drive」
- https://wiki.jenkins-ci.org/display/JENKINS/Meet+Jenkins の「Test Drive」の「Launch」ボタンをクリック
- ダウンロードした jenkins.jnlp ファイルをJava Web Startで実行*1
- http://localhost:8080/ にアクセスするとダッシュボードが表示される
- ジョブを作る
- 新規ジョブ作成 > ジョブ名を入れて選ぶ(フリースタイルがおすすめ)
- ジョブとは?
- 基本的にはソフトウェアのビルドを模している
- ビルドするのにどんな条件・ツールなのかがわかるのも利点の1つ。ログを見るのを手助けする役割もある。
- テストを実行して失敗すると、どのコミットのせいなのか、とかそのときのエラーメッセージ、スタックトレースも表示される
Jenkins + EC2で分散ビルド (Sky株式会社 玉川 竜司さん)
ビルドは負荷の変動が激しい作業のため、Amazon EC2上で動かしてしまおうというお話でした。
Amazon EC2でJenkinsを動かす話
- ビルドは負荷の変動が激しい(リリース前は高負荷、とか)
- Amazon EC2ならピークにあわせてハードウェアを用意しなくていい!!
- EC2で勝手にスレーブを動的に増減してくれる
- 1時間ごとの従量課金
- セキュリティは大丈夫?→Amazon Virtual Private Cloud(VPC)やDirect Connectで対応
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をインストールしていろいろ試してみようと思います。
logstudy01 & mailerstudy02に行ってきました
はじめに
2月18日に行われたlog何でも勉強会とメールサーバ勉強会の合同勉強会、logstudy01 & mailerstudy02に行ってきました。
- 日時: 2012/2/18 14:30-18:30
- 場所: フューチャーアーキテクト株式会社
- ハッシュタグ: #mailerstudy #logstudy
- Zusaar: logstudy01 & mailerstudy02 本編 on Zusaar
- Togetter: logstudy01 & mailerstudy02 本編 #logstudy #mailerstudy - Togetter
- Ustream:
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を使用
メール暗号化入門 -アリスとボブの恋の行方- @ttkzw さん
一般的な暗号方式や暗号通信で使用されるプロトコルなどについて、解説していただきました。
2セッション続けて@ttkzwさんが担当されていました。なんという@ttkzwさん無双w
暗号技術
メール特有の話
- SMTP,POP3,IMAPのセッション中にSTARTTLSコマンドでTLS通信に切り替える
- POP3だとなぜか短縮されてて STLS になってる
- 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/TLSはTCP/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
結果はこんな感じ。いい感じにしきい値処理がされています。
まとめ
そんなわけで、第5回Ruby/OpenCV進捗報告でした。
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行目を例にどんな処理が必要か考えてみましょう。
abcd,ef,ghi
この行から、次のように1つめのデータを削除したいわけです。
ef,ghi
Rubyistなら考える前に手が動きますね。
print 'abcd,ef,ghi'.split(',')[1..-1].join(',') #=> ef,ghi
これをxyzzyのバッファで実行すればよさそうですね。
さっそく実行してみる
心の準備はいいでしょうか?
では、C-x # で filter-buffer コマンドを実行してみましょう。実行するとカーソルがミニバッファに移動します。ここに書かれたコマンドに対して、バッファの内容が標準入力から渡され、実行されます。
実行するコマンドはこんな感じにしてみます。
ruby -ne "print $_.split(',')[1..-1].join(',')"
Rubyの-e オプションを設定すると、ファイルではなくコマンドラインから渡されたスクリプトを実行します。
-n オプションを設定すると、プログラム全体が
while gets ... end
で囲まれているように動作します*1。Rubyのオプションの詳しい話はこのへんとかを見てください。
標準入力の内容は、組み込み変数 $_*2 を使って取り出しています。
Rubyに -n オプションを指定して実行するため、 $_ にバッファの内容が1行ずつ入ってきます。そこで、 $_ に対して1行ごとに実行したい処理を適用すればOK、というわけです。
ためしてみる
C-x # を実行してミニバッファに書いたコマンドは、そのままEnterキーを押せば実行できます。さっそく適当なバッファで試してみましょう。
うまくいきましたか? うまくいかない場合は、もう一度ワンライナーを見直してみましょう。C-x # を再度実行し、C-p (上キーでもOK)を押すと、実行したコマンドの履歴が見れますので、よーく見て直してください。
選択したリージョンのみに適用!
うまくいったら、今度は選択したリージョンのみで実行するようにしてみます。ここでわざわざ新しくバッファを作って必要な部分だけコピペして filter-buffer!!というのはちょっと野暮なのでやめておきましょう。
まずは適用したい行をすべてリージョン指定(選択)します。そして、おもむろに C-x | を押し、先ほどと同じようにコマンドを書きます。
さぁ、いかがですか?コマンドが選択したリージョンのみに適用されているはずです。ちなみに、C-x | は filter-region というコマンドを呼び出しています。
こうして、1行ずつ手でやっていたら気の遠くなるような作業も一撃で済んでしまうわけです。
まとめ
今回実行したワンライナーはかなり単純なものですが、使う言語でできることなら大概何でもできてしまうので、かなりいろんな場面で使えます。 再利用性など考えず、その場で必要なワンライナーを書いて、使ったら、あとは忘れてしまって構いません。どうせ履歴見れるし。
最近使ったワンライナーとしては、「ずらーっと書かれたデータからSQLを生成する」「ログファイルから必要な列だけ抜き出し、ちょっとだけ加工する」などが役に立ちました。「単純作業だけど、スクリプトを書けば一瞬で終わる。むしろ書かせろ。」という時はxyzzyのフィルタコマンドでさくっと仕事を終わらせて、まわりのみんなにドヤ顔をご披露ください。
参考: xyzzyでプログラミング/空行、行末空白などの削除
あわせて読みたい: Emacs のキーボードマクロであっと言う間に仕事を終わらせる (フェンリル | デベロッパーズブログ)
オープンソースの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を選択してインストールします。
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にも対応しているようなので、そちらでも試してみたいところです。
インストールは超めんどくさいですが使い勝手は非常にいいので、ぜひ使ってみてください。
参考
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でコードを書く
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
どうやらちゃんと動いてます。やったね!
さらに調べるには
- LoveRubyNet Wiki: RubyExtensionProgrammingGuide
- 今回触れなかったRuby内部のデータ構造や、データをGCから守る方法など、重要なポイントが書かれています。必読です。
- Ruby 1.9.3 リファレンスマニュアル > 関数一覧
- こんなのやるにはどうすればいいの?という場合はこちら。説明が無いものもありますが、その場合はソースコード見て下さい。
- README.EXT.ja
- Rubyのソースコード
- やっぱり一時情報は大事です。
まとめ
Rubyの拡張ライブラリの作り方をざっくり紹介しました。これでボトルネックもCで書かれたライブラリも怖くないはず!
もうすこし書きたいところではありますが、時間もアレなのでこのへんで。
明日は18日目、@sakairyotaさんです。