チャットプログラムのテスト
とあることがキッカケで、Rubyでシンプルなチャットプログラムを書いてみました。
チャットプログラムのザックリと要件を考えると以下の2点になる。
- 受信したメッセージを適宜表示
- 入力したメッセージを送信
ThreadとSTDIN/STDOUTの相性
要は「受信しつつ、送信」なので、Threadを使ったほうがよさそうな感じ。そこで慣れていないThread関係のテストプログラムを書いてたら、いきなり躓いた。そのコードは次のようなもの。
def recvLoop count = 0 while true p "RECV:#{count}" # とりあえず. count += 1 end end def sendLoop while true p "SEND:"+gets # 入力待ち. end end Thread.start{ recvLoop } sendLoop
上記プログラムのダメなところは、sendLoop内のgetsでコンソール(標準入力)が待ち状態になり、recvLoopからの出力が行えなくなってしまうのです。
ウィンドウアプリなら入出力は別にするだろうし、コンソールアプリでも受信部と送信部を別々のプログラムにして別ウィンドウで処理したら問題ないのですが、このまま引き下がるのも悔しいのでなんとかならないか考えてみた。
「キー入力があったら、getsに遷移する」という方法でなんとかなるかもしれないと思って書いたコードが次のコード。(※参考サイト:小ネタいろいろ - Ruby Tips)
require 'Win32API' $kbhit = Win32API.new( 'msvcrt', '_kbhit', [], 'l') def recvLoop count = 0 while true p "RECV:#{count}" # とりあえず. count += 1 end end def sendLoop while true if $kbhit.call != 0 # キー入力があったら.. p "SEND:"+gets # getsを行う. end end end Thread.start{ recvLoop } sendLoop
これでなんとか、コンソールアプリの問題点もクリアできた。
自分の入力中は受信出来てもすぐに表示できないけど、今回はしょうがないということで目をつむり、以前のサーバクライアントプログラムを参考にしつつ、とりあえず完成させてみた。
ちなみに、TCPServer#acceptのタイミングには注意する必要がある。メインスレッドでやるとそこで処理が止まってしまうので、別スレッドで行うようにした。
チャットテストスクリプトの完成
RUBY-LANG.ORG/JPのコード
何気なくRubyオフィシャルサイトを見ていて、ふとあるコードが書いてあることに気づいた。短いコードなのだが、なかなか面白い、というか、一部分知らないStringメソッドが使われてたので、ちょっと調べてみた。
上記サイトに書かれているコードは次のようなもの。
# Output "I love Ruby" say = "I love Ruby" puts say # Output "I *LOVE* RUBY" say['love'] = "*love*" puts say.upcase # Output "I *love* Ruby" # five times 5.times { puts say }
文字列(String)の部分文字列を[]で指定し、そこに文字列を代入すると文字列の置換が出来るようなのです。なるほどねー。
普通使うであろうメソッドでいうところの String#sub! に相当しているようで、String#gsub! 的には使えないみたい。
say = "I love Ruby, I have a glove." say['love'] = '*love*' puts say #=> "I *love* Ruby, I have a glove" say = "I love Ruby, I have a glove." say.sub!('love', '*love*') puts say #=> "I *love* Ruby, I have a glove" say = "I love Ruby, I have a glove." say.gsub!('love', '*love*') puts say #=> "I *love* Ruby, I have a g*love*"
DynDNSのIPを更新するRubyスクリプト
DynDNS使っています
最近のエントリから察せられるように、VineLinuxを入れたPCで自宅サーバを試しています。そして、ダイナミックDNS対策にDynDNSを使っているのですが、IP割り当てが一定時間ごとに変わる一般プロバイダを通していると、定期的にDynDNSへのIPの登録を変更する必要があります。
それを自動で行ってくれるプログラムがいくつか公開されています。
DynDNS Update Clientを作ってみる
ndyndnsはC言語で書かれていて、またソースが公開されているので、ざっくりと中身の流れは分かっていた。それを頭に入れRubyで書いてみることにしました。
処理の流れは、以下の3ステップ。
- 現在のグローバルIPアドレスを取得
- 以前設定したIPアドレスと比較
- 変化があるか?
- なければ終了
- あれば、それを登録して、そのIPアドレスをメモしておく
グローバルIPを取得する
ルータにアクセスしてグローバルIPを取得する、という方法もあったのですが、解析に手間取りそうで却下。
DynDNSがIPを返してくれるページを設置してくれているのでそれを使うことにしました。
また、VALUE-DOMAINも同様なページを設置しています。
Basic認証を行う
Rubyでページを取得するには、"open-uri"という便利なライブラリがあるのですが、Basic認証を超えて取得する方法が分かりにくかったので以下のページを参考に実装しました。
具体的には以下のような内容になります。
require "open-uri" auth = "Basic "+["#{Username}:#{Password}"].pack("m").chomp hashAuth = { "Authorization" => auth, "User-Agent" => "update_dyndns.rb" } open( "http://need-basic.example.com/", hashAuth )
ハマったポイントは以下の2点。
- packした文字列をchompする
- "User-Agent"を設定しておく(DynDNSにつながるのに必要)
update_dyndns.rb
以上の情報をまとめて書いたコードが以下のものです。
使用するには、コードの冒頭に羅列している"DynDNS_"の定数を定義してから実行してみてください。
(これをcronで5分置き程度に実行するように設定すれば完了です。)
EclipseでRuby
眠くなってきたところで、ふと思い立ち、rubyの開発環境をeclipseにしてみたいなー、と衝動セットアップ。今使っているPCにRubyはインストールしていたのだが、Eclipseをインストールしてなかったので、まずeclipseをインストールするところからメモしておく。
- Eclipse Downloads | The Eclipse Foundation から"Eclipse IDE for Java EE Developers"をダウンロードしてインストール。
- Eclipse 日本語化 | MergeDoc Project から"Pleiades"という日本語化プラグインをダウンロードしてインストール。
- Ruby Development Tool download | SourceForge.net から"Ruby Development Tool"をダウンロードしてインストール。
- Eclipseを立ち上げ、「ウィンドウ」→「設定...」→「Ruby」の中身を設定.
- 新規プロジェクトでRubyを選ぶと、プロジェクトが作成され、適当なファイルを作成し、適当なスクリプトを記述後、F11を押すと、デバッグが始まります.
プレゼントが来た!
Rubyist Magazine 20号のプレゼント企画に応募していたら「Ruby クックブック」が当選しました!
おとといメールが来て、住所とか返信したら、今日届いた。早いなー!
で、届いた荷物がやけに大きいので開けてみたら、こんな感じで、本以外にもいろいろオライリーグッズが入っていた。
トートバッグはJavaScript、マグカップはPerl。という具合に、本以外は、特にRubyと関係ないのがどうにもこうにも。
で、パラパラとめくってみたら、昨日のエントリで書いたPing.pingechoの記事も載っていた!
なんだ、ここにあったのかー。(p.226)
他にも、面白そうな記事がいくつかある。仕事の合間に読み進めてみよう。
- 作者: Lucas Carlson,Leonard Richardson,株式会社クイープ
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2007/04/27
- メディア: 大型本
- 購入: 1人 クリック: 73回
- この商品を含むブログ (55件) を見る
しかーし、佐川のおじさんはそれを読み解き、キチンと届けてくれたのがすばらしい!こういう解決ってやっぱり近所をウロウロして、それっぽい住所をいくつか当たってみたりしてくれたのだろうか。
最近いくつかの宅配業者を使ったときも佐川の対応が一番よかったと思ったのだが、今回の件でさらに佐川のカブが上がりましたよ。ま、他の業者だったら届けられなかった、のかと言えば、そうではないのかもしれないけどね。
(自分が間違えたのかも、と思い確認したけど、やっぱりメールで返信してた住所は正しかった。)
ピンピンPing!
pingをつかって、目的のネットワークサービスが起動しているかどうかを確認したい。
rubyなら何か簡単なライブラリが提供されているんじゃないだろうか、と調べてみたら、ありました!
下記に使い方のサンプルをいくつか載せておきます。
require "Ping" # ローカルホストでテスト. if Ping.pingecho( "localhost", 3, "80" ) p "ローカルホスト(ポート80)がpingを返しました." end # IPアドレス指定. if Ping.pingecho( "127.0.0.1", 3, "80" ) p "ローカルホストのIPアドレスでもOKでした." end # サービス名で指定. if Ping.pingecho( "127.0.0.1", 3, "ftp" ) p "192.168.0.10がftpサービスを起動しています." end
関連エントリ
日本語PDFを作れなかった話
昨日の「PDFJをインストールしてみる」より前に試していたのだが、アップするタイミングを逃していたPDF::Writeモジュールについての調査結果をアップしておく。
経験上、「何が出来て、何が出来なかったか。また、その理由。」というのは「うまくいく理由」よりも、あとで大事になる情報だからね。
PDF::Writerと出会う
まず、Rubyで使えるPDFライブラリを探してみた。こういうのはRubyGemを使うと簡単。
>gem search -r pdf *** REMOTE GEMS *** Bulk updating Gem source index for: http://gems.rubyforge.org jpeg2pdf (0.12) jpeg2pdf is a free program that converts a directory of JPEG files to a PDF file. pdf-labels (1.0.0) Easy label creation in Ruby through PDF::Writer and using templates from gLabels. Contains the library pdf_labels, the Rails engine LabelPageEngine and an example application FileClerk. pdf-toolkit (0.49, 0.5.0) A wrapper around pdftk to allow PDF metadata manipulation pdf-writer (1.1.3, 1.1.2, 1.1.1, 1.1.0, 1.0.1, 1.0.0) A pure Ruby PDF document creation library.
説明文を読むと、pdf-writerが良さそうな気がします。
- http://rubyforge.org/projects/ruby-pdf/
- http://ruby-pdf.rubyforge.org/pdf-writer/index.html
- We retire raa.ruby-lang.org
上記のようにいろいろリンクがありますが、Ruby Gemでインストールすれば、依存ライブラリも適当に返事するだけでインストールしてくれます。
以下のようにタイプします。
>gem install pdf-writer Bulk updating Gem source index for: http://gems.rubyforge.org Install required dependency color-tools? [Yn] Y Install required dependency transaction-simple? [Yn] Y Successfully installed pdf-writer-1.1.3 Successfully installed color-tools-1.3.0 Successfully installed transaction-simple-1.4.0 Installing ri documentation for pdf-writer-1.1.3... Installing ri documentation for color-tools-1.3.0... Installing ri documentation for transaction-simple-1.4.0... Installing RDoc documentation for pdf-writer-1.1.3... Installing RDoc documentation for color-tools-1.3.0... Installing RDoc documentation for transaction-simple-1.4.0... >
以上でインストールは完了。
PDF::Writerを試す
早速使ってみる。
sampleにあるhello.rbを参考にして以下のようなコードを実行してみた。
def initLibs begin require 'pdf/writer' print "Load OK\n" rescue LoadError => le print "Load Error: #{le}\n" exit end end def createPDF pdf = PDF::Writer.new pdf.select_font( "Times-Roman" ) pdf.text( "Hello, Ruby with PDF::Writer",\ :font_size => 72, :justification => :center ) pdf.save_as( "hello.pdf" ) end initLibs createPDF
これで、特に問題なく、hello.pdfが作成されました!おぉ〜、ちょっと感動。
PDF::Writerは日本語に非対応
その後、いろいろソースを試してたら、現在配布されているPDF::Writerでは日本語フォントに対応していないことが判明した。
検索してみたら、日本語フォントパッチと名づけられたものを発見。
しかし、ダウンロードしてdiffファイルを見てみると、ソース内でフォント名をハードコーディングして対応している。それはRyuminとGothicBBBの二つのみ。これでは使えない・・。
ちなみに、こちらの記事が上記パッチ実装までの過程のようです。
PDF::Writerはフォント埋め込みも非対応
もう一つの難点が、フォント埋め込みに非対応、という点。
ちなみにパッチはここにある。
結論
とりあえず今やっている仕事では、日本語で縦書きされたPDFを作りたかったので、使えなさそう。
テキストが英語程度で、グラフィック中心ならかなり使い勝手が良さそうな気がします。
2005年末から2年、全然更新されていないのが残念でならない。せめてフォント埋め込みパッチを正規リポジトリに対応させたりして欲しいところ。
オープンソースなんだからおまえがやれ、と言われそうだけど。
ここでも読んでしっかり勉強しなきゃ、かも。