ぼっちupcamp #upcamp に参加しようと思ったのですが、 諸事情により行けなくなったので、一人で何か作ってました。 Ruby の 処理系の動作の改良(改悪)をしていました。 Ruby は git clone https://github.com/ruby/ruby.git で落としたものを使いました。 Thread#join で タイムアウトしたときに例外を発生させる Thread#joinは、 スレッド self の実行が終了するまで、カレントスレッドを停止させるメソッドです。 limit を指定して、limit 秒過ぎても自身が終了しない場合、nil を返します。 今回は、limit 秒を過ぎてタイムアウトした場合、 例外Timeout を発生させるように改造しました。 正直、自分でもネタをミスった感がありますが、 すこしはタイムアウトした場合の処理が楽に書けるようになる気がします。 従来のRubyの Thread#join でタイムアウトを処理する まず、従来のRubyの Thread#join でタイムアウトを処理する場合のコード例を示します。 Thread#joinの返り値が nilのときにタイムアウトしたと分かるので、 このように書けると思います。 begin t = Thread.start { # 1秒で終わらない処理 while true 1 end } isTimeout = (t.join(1) == nil) rescue ThreadError puts "theread error" ensure puts "timeout error" if isTimeout t.kill end # => "timeout error" 改造したRubyの Thread#join でタイムアウトを処理する 今回の改造によって、次のようにRubyのコードをスッキリさせることができます。

Read more


RubyってSubversionで開発してるというイメージしか無かったのですが、GitHubでも最新のソースコードをCloneできました。

git clone https://github.com/ruby/ruby.git

公式にリポジトリガイドなるページがあるので、最新のRubyのソースコードを読んでみたい人は参考にしたらいいと思います。

レポジトリガイド

Read more


はじめに Rubyの初心者にありがちなことだと思うが、 変数を代入した時や関数を呼び出した時に、値渡しであるか参照渡しであるか混乱すると思う。 私もよくわからずにかつては混乱した。 次のページを見つけてようやく頭の整理がついた。 Rubyのメソッドの引数は値渡しで、Rubyの変数は全てオブジェクトを指し示すポインタに似た何かだと考えればよいのだ。 引数の参照渡し(変数渡し)なのか単なるオブジェクトへの参照なのか、それが問題 なるほどわかりやすい。 Rubyのメソッドの引数は値渡し Rubyの変数は全てオブジェクトを指し示すポインタに似た何か Rubyの変数はラベル Cにおける変数は箱だと例えられるが、Rubyにおける変数はラベルと例えられることがある。 Cの変数では、メモリ上の箱に値がそのまま入っている。代入をすれば、箱が複製される。 一方、Rubyではメモリ上の箱のどこかに値が入っており、変数はラベル(箱への参照)を持っているだけにすぎない。 変数を代入すると、メモリ上のデータはそのままに、ラベルだけがコピーされるのである。 破壊的操作で意図しない変更が起きる例 次の例のようにbにaを代入した後、aに破壊的変更をすると、bの値まで変わってしまう。 なぜならば、aとbは同じラベルを持っているので、同じ箱を共有した状態にあるからだ。

破壊的操作でbに意図しない変更が起こる例 [1] pry(main)> a = "abc" => "abc" [2] pry(main)> b = a => "abc" [3] pry(main)> a.reverse! => "cba" [4] pry(main)> b => "cba" 回避方法1 bの値を変えたくなければ、破壊的操作をしなければ良い。

a = a.reverseとすれば、インスタンス"cba"が作られ、aにそのラベルが入る。

破壊的操作をしなければbは変わらない [1] pry(main)> a = "abc" => "abc" [2] pry(main)> b = a => "abc" [3] pry(main)> a = a.

Read more


WEBrickを使って、RubyCGIをローカル上でプレビューする方法を紹介します。前にTwinCalを作った時にこの方法を覚えました。

ApacheはC言語で書かれていているためにパフォーマンスが良いので本番環境ではApacheを採用しましたが、 ローカルでテスト用に使うにはWEBrickでちょろっとサーバを立てるのが良いですよね、そうしましょう。

テスト環境(ローカル) :WEBrick

本番環境(サーバ) :Apache

あとは、rsyncとかでファイルを同期できるようにしたら完璧。

1. Rubyのパスを本番環境とテスト環境で統一する

Rubyのパスを本番環境とテスト環境で統一するために、 /usr/bin/rubyのシンボリックリンクをrvmなどで入れたRubyに置き換えます。

mv /usr/bin/ruby /usr/bin/ruby-original
ln -s /Users/gam0022/.rvm/rubies/ruby-1.9.3-p194/bin/ruby /usr/bin/ruby

本番環境とテスト環境の両方で行います。

当然ですが、RubyのCGIではこのパスを1行目に指定します。

2. WEBrickを使う

WEBrickについて簡単に説明すると、RubyでWEBサーバを立てるためのライブラリです。 これをrequireすることで、10行くらいのコードを書くだけで簡易WEBサーバが完成します。

私の場合、次のようなpreview.rbを書きました。 WEBrickで.rbをAddHandlerする方法がなかなかわからなくて苦労しました。

require 'webrick'
include WEBrick

module WEBrick::HTTPServlet
  FileHandler.add_handler('rb', CGIHandler)
end

s = HTTPServer.new(
  :Port => 3000,
  :DocumentRoot => File.join(Dir.pwd),
  :DirectoryIndex => ['index.rb']
)
trap("INT") { s.shutdown }
s.start

このpreview.rbを公開したいディレクトリに設置し、 ターミナルでruby preview.rbをすれば、ブラウザでlocalhost:3000にアクセスすることで、 簡単にローカル上でCGIをテストすることができます。

おまけ: WEBrickでRequestURITooLargeが発生したときの対処方法

ApacheではURIの上限が大きいので、かなり長いURIを発行しても問題がないのですが、WEBrickでは2083byteの制限があるので、 CGIで長いURIを発行すると、RequestURITooLargeというエラーになってしまうことがあります。

これは、WEBrickのソースコードを書き換えることで対処できます。

私の環境では、/usr/local/rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/webrick/httprequest.rbのL293に、 MAX_URI_LENGTHという定数があったので、これを書き換えることで対処できました。

291     private
292 
293     MAX_URI_LENGTH = 20830#2083 # :nodoc:
294 
295     def read_request_line(socket)

RubyでWebrick利用時にRequestURITooLargeエラー発生時の対処

Read more


Rubyで何かWebアプリを作ってみたかったので、 Twinsに登録した時間割をGoogleカレンダーやiCalにインポートするWebサービス「TwinCal」を作ってみました。

TwinCal

筑波大学生以外にも分かるように説明すると、筑波大学にはTwinsという履修の登録をするWebのシステムがあり、 Twinsでは時間割をCSV出力する機能があるので、そのCSVをiCalender形式に変換して、 GoogleカレンダーやiCalにインポートをサポートするWebアプリを作りました。

来年、Twinsが改修されるらしいので、半年後には使えなくなると思います。

バイトでPHPを使ってWebアプリを開発した経験はありましたが、個人でWebアプリを作ったのは初めてでした。

気を使ったこととして、ビューの部分はerb(railsでも使われているアレ)を使い、MVCを意識して作りました。

最近流行りのbootstrapやjQueryなどを使ったのですが、この2つを使ったのは正解でした。 これらのおかげでロジック部分に集中することができ、かなりサクサク作業することができました。

このアプリを作ろうと思い立ったのは12日で、14日には公開できるような状態になりました。

あまり使ってくれている人はいないようですが、bootstrapとhtml5で遊べたことだけでもよい経験となりました。

今回のことで学んだテクニックがいくつかあるので、後ほど記事にしたいです。

Read more


Ruby 1.9を使ってアスキーコードを取得する方法です。 次のように、bytesメソッドを使えばいいです。

# Ruby1.9
"ABC".bytes.to_a # => [65, 66, 67] 

なお、上記のコードはRuby1.8では動きません。

Ruby1.8でアスキーコードが欲しい場合、[]で取得できますが、 あまりこの動作は美しくないですよね。

# Ruby1.8
?A # => 65
"A"[0] # => 65

Read more


ServersMan@VPS(Ubuntu)でRubyのCGIを実行するまでのメモです。

apache2をインストールする

apt-getかaptitudeでインストールすればいいと思います。

sudo aptitude install apache2   

AddHandlerを設定する

/etc/apache2/mods-enabled/mime.confにAddHandlerを設定します。

#AddHandler cgi-script .cgiという行があるので、 見つけてコメントアウトを解除して、次のように書き換えればいいと思います。

AddHandler cgi-script .cgi .rb

Options +ExecCGIを設定する

/etc/apache2/sites-available/defaultでOptions +ExecCGIを設定します。

<Directory /var/www/html/>
    #Options Indexes FollowSymLinks MultiViews 
    Options Indexes FollowSymLinks MultiViews ExecCGI
    AllowOverride None
    Order allow,deny
    allow from all
</Directory>

apache2を再起動する

上の2つのファイルを編集したら、apacheを再起動して設定を反映させます。

sudo /etc/init.d/apache2 restart    

Ruby CGIのパーミッションを755にする

cd /var/www/html
chmod 755 test.rb

これでたぶん動くようになります。

ね?簡単でしょ?

うまくいかないときは

/var/log/apache2/error.logのエラーメッセージを見ましょう。

Read more