0

rvmからrbenvに乗り換えた

rvmで入れた1.9.2でbundler1.3以上が動かないので、入れなおした。
OSはMountainLion


まずmacportsを消す
2.5. Uninstall
pLaTeXのために使っていたけど無くてもなんとかなる気がしたので消した


Homebrewもmacportsとからみ合ってしまっていたので、一旦全部消す
Uninstall Homebrew

rvmも消す

rvm seppuku
sudo rm -rf ~/.rvm
.bashrcとかの設定も消す


App Storeで最新版のXCodeを入れる
Command Line tools for XCodeは必要なし
代わりにXCodeのPreferenceからCommand Line Toolsをインストールする。こっちだと多分XCodeをアップデートしたらアップデートされそうだし。

osx-gcc-installerもインストールする。Rubyのビルドに必要。

それからhomebrewを入れなおす。
ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"

brew doctor
でおかしい所が無いか確認。

brew install openssl readline rbenv ruby-build


1.9.2のextが2.0.0で必要なので先にビルドする。
rbenv install 1.9.2-p320
rbenv global 1.9.2-p320
rbenv rehash
gem update --system
gem install rbenv-rehash bundler
rbenv-rehashを入れておくとgemコマンド毎にrehashしなくてもよくなるそうだ。
ただし、gemコマンドの後にrehashを自動的にやってくれるだけなので、すでに開いてある別のターミナルではrehashする必要がある。
gemは2.0以上、bundlerは1.3以上を入れておく。


Ruby2.0.0もインストールする
rbenv install 2.0.0-p0
rbenv global 2.0.0-p0
rbenv rehash
gem update --system
gem install rbenv-rehash bundler

で、1.9.3や2.0.0でsha1やmd5が動かないので、1.9.2から持ってくる
これしないとbundlerやoauthが動かない。
Ruby2.0.0と1.9.3でSymbol not found: _rb_Digest_SHA1_Finish (LoadError)


こういう面倒くさい手順、Ubuntuだとbuild-essential入れてrvm入れるだけで済んでたのでやっぱりMacは開発環境に向いてないと思った。
最近は1年ごとのOSアップデートに付いて行かないといけないし、入れた直後はgcc消えたりするし、
XCodeのアップデートくる毎におかしくなるし、つらすぎる。

2015年ぐらいにはiOS以外の開発者はMac使ってない気がする。
あと2018年にはgitもオワコンって言われてるはず

0

Ruby2.0.0と1.9.3でSymbol not found: _rb_Digest_SHA1_Finish (LoadError)

macにrbenvで入れたRuby2.0.0や1.9.3でbundlerを使った時にそういうエラーがでて動かなかった


1.9.2でビルドしたsha1.bundleをコピーしてきたら動くようになった。

cp ~/.rbenv/versions/1.9.2-p320/lib/ruby/1.9.1/x86_64-darwin12.3.0/digest/* ~/.rbenv/versions/1.9.3-p392/lib/ruby/1.9.1/x86_64-darwin12.3.0/digest/

cp ~/.rbenv/versions/1.9.2-p320/lib/ruby/1.9.1/x86_64-darwin12.3.0/digest/* ~/.rbenv/versions/2.0.0-p0/lib/ruby/2.0.0/x86_64-darwin12.3.0/digest/

そしたらsha1.bundleだけじゃなくmd5.bundleもエラー出る事に気づいたので、面倒だからdigestの下のバイナリまるごと上書きした。


ubuntuでは問題なし。

0

sinatra/rocketio/clientとem-rocketio-client作った

Sinatra RocketIOのRubyクライアントを作った。
Thread版とEventMachine版がある。
コレを使うとサーバーにwebブラウザ以外からデータを投入したり取得したりできて便利。
ワーカーに作業を任せるのにも使えなくもないかも。


Thread版

sinatra-rocketio gemに付属してる。

Sinatra::RocketIO::Client · shokai/sinatra-rocketio Wiki


例えばhttp://rocketio-chat.herokuapp.com/のCUIクライアントを作る例

#!/usr/bin/env ruby
require 'rubygems'
require 'sinatra/rocketio/client'

io = Sinatra::RocketIO::Client.new('http://rocketio-chat.herokuapp.com').connect

io.on :connect do |session|
puts "#{io.type} connect!! (session_id:#{session})"
end

io.on :chat do |data|
puts "<#{data['name']}> #{data['message']}"
end

io.on :error do |err|
STDERR.puts err
end

io.on :disconnect do
puts "disconnected!!"
end

loop do
line = STDIN.gets.strip
next if line.empty?
io.push :chat, {:message => line, :name => name}
end
Threadなので、最後にloopで止めないとRubyが終了する。


デフォルトでwebsocketを先に試すので、最初からcometを使いたいのならtypeオプションを渡す。
io = Sinatra::RocketIO::Client.new('http://rocketio-chat.herokuapp.com', :type => :comet).connect


仕様

コンストラクタにアプリのURLを渡すと、 /rocketio/settingsというJSONを読みにいってそのアプリでcometとwebsocketが使えるか確認する(RocketIOは設定でcometのみとかできる)

settingsの読み込みに失敗すると10秒ぐらい待ってからまた見に行く。

websocketとcometが両方使えるなら、websocketから接続を試す。接続できなかったらcometを使う。

cometにはHTTParty、websocketにはwebsocket-client-simpleを使っている。
どちらも切断されても自動的に再接続しにいく。


EventMachine版


EM::RocketIO::Client · shokai/sinatra-rocketio Wiki
shokai/em-rocketio-client · GitHub

eventmachine版の方が高速に動作する。
通信にem-http-clientとem-websocket-clientを使っているが、thread版と動作は同じ。


インストール
gem install em-rocketio-client


同様にチャットクライアントを作ってみる

require 'rubygems'
require 'eventmachine'
require 'em-rocketio-client'

url = 'http://rocketio-chat.herokuapp.com'
EM::run do
io = EM::RocketIO::Client.new(url).connect

io.on :* do |event_name, data|
puts "(#{io.type}) #{event_name} - #{data.inspect}"
end

EM::defer do
loop do
line = STDIN.gets.strip
next if line.empty?
io.push :chat, {:message => line, :name => name}
end
end
end

*で全イベントを取得できる。


こっちは下の2つのgemを合体させて実装している。
shokai/em-cometio-client · GitHub
shokai/em-websocketio-client · GitHub

0

websocket-client-simple 作った

eventmachineに依存していないruby用websocketクライアントでまともなのが無いので作った。

shokai/websocket-client-simple · GitHub

既にwebsocket-clientというgemがあるけど、ドラフト0しか実装されていないしpull requestできるリポジトリが無かったので作った。
名前はwebsocket-client2というnode臭がするのと後ろにliteとかsimpleとか付けるperl臭がするのと、わけわからない名前付けるruby臭で迷った。


インストール


gem install websocket-client-simple


使い方


JavaScriptのWebSocketと同じように使える
require 'rubygems'
require 'websocket-client-simple'

ws = WebSocket::Client::Simple.connect 'http://example.com:8888'

ws.on :message do |msg|
puts msg.data
end

ws.on :open do
ws.send 'hello!!!'
end

ws.on :close do |e|
p e
exit 1
end

loop do
ws.send STDIN.gets.strip
end
threadで動くので、最後にloopしておかないとRubyが終了してしまいます


サンプルに、
  • rubyで書いたwebsocketチャットサーバー
  • webブラウザ用チャットクライアント
  • websocket-client-simpleで書いたチャットクライアント
を入れておいた。



websocketのデータのparseにはimanel氏のwebsocketというgemを使った。
とても良くテストなども書かれていてメンテされているので、TCPSocketをそれに食わせるだけでクライアント書けた。

あとちゃんと試してないけど多分
ws.send binary_data, :type => :binary
でバイナリ送信できると思う。

0

Sinatra RocketIOで家のRaspberry PiのArduinoをリアルタイムで見る

RocketIOのサンプルとして、それなりに激しい処理が低スペックマシンで動くかテストするために作った。

http://status.shookai.org

ソースコード
https://github.com/shokai/rocketio-arduino-sample


こういうのが表示されてるはず


物理的な意味ではこうなってる
R0020611


Arduino Firmata on Rubyで、ADコンバータに温度センサと明るさセンサを付けたArduinoを読んで0.3秒毎にSinatra RocketIOでブラウザにpushしている。

5秒毎にCPUとメモリ使用量もpushしてる。
あと新規接続/切断がある度に全クライアントに接続数を通知してる。


60行ぐらいのSinatra40行ぐらいのJavaScriptでできてる。


JavaScript側を抜粋すると、こんな感じでそれぞれイベント待ちしておいて

io.on("arduino", function(data){
$("#temp").text("気温:"+data.temp+"度");
$("#light").text("明るさ:"+data.light);
});

io.on("stat", function(data){
$("#cpu").text("CPU:"+data.cpu+"%");
$("#mem").text("メモリ:"+data.mem+"%");
});

io.on("clients", function(data){
$("#websocket").text("websocket:"+data.websocket);
$("#comet").text("comet:"+data.comet);
});


サーバー側はsinatraの中にArduinoでセンサーを読むEventMachineのタイマーをベタ書き。
io = Sinatra::RocketIO

## Arduino sensors
io.once :start do
begin
arduino = ArduinoFirmata.connect ENV['ARDUINO'], :eventmachine => true
rescue => e
STDERR.puts "#{e.class} - #{e}"
next
end
EM::add_periodic_timer 0.3 do
light = arduino.analog_read 0
$logger.debug "light : #{light}"
temp = arduino.analog_read(1).to_f*5*100/1024
$logger.debug "temperature : #{temp}"
io.push :arduino, :temp => temp, :light => light
end
end
CPUとメモリは同じ要領で、psコマンドの結果をparseして送ってる。


Sinatra側で定期的に行う処理は、 Sinatra::RocketIO.once :start の中で登録すると良いです。
“start”はeventmachineとwebsocketサーバーの準備が整ったら発火するイベント。
onではなくonceなのは1回目だけ呼ばれるという意味。


あと、Arduino Firmataの最近のバージョンからeventmachine用の起動オプションを付けた。
ArduinoFirmata.connect "/dev/tty.usbデバイス名", :eventmachine => true
EM::runの中でこうやって起動するとThreadのかわりにeventmachineで動くようになった。
Sinatraの中で動かすときはこうしないと、タスク切り替えがうまくいかない。