2005-01-12 (Wed)

* getopts.rb は Ruby 1.8.1 より後では非推奨

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [Ruby]

1.8.1 より後の Ruby では getopts は非推奨になった模様。

Rubyリファレンスマニュアル - getopts.rb
http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=geto ...
オプションを解析し、$OPT_xxx に値を設定します。

- 開発版の Ruby 1.9系 で getopts の使用に警告が出る

[ruby-list:40501] getopt
http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-lis ...
これは, 1.9系で発生するのですが...
# メッセージから言うと 1.8.2でもですかね...

emperor% ruby -e "require 'getopts'"
Warning:-e:1: getopts is deprecated after Ruby 1.8.1; use optparse instead

[ruby-list:40502] Re: getopt
http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-lis ...
|emperor% ruby -e "require 'getopts'"
|Warning:-e:1: getopts is deprecated after Ruby 1.8.1; use optparse instead
|
|getopts.rb は非推奨品になったということでしょうか?

そういうことです。

|とはいえ, optparse って随分インターフェイスが変わっていて戸惑ってしま
|うのですが...

とはいえ、グローバル変数を多用したgetoptsを今さら推奨するっ
てのもねえ。

|あと, getoptlong.rb もあると思いますが, それも推薦品ではないってことで
|しょうか?

そうですね。どっちかといえばoptparseを勧めたいって感じです。

2004-11-01 などで書いた「添付ファイル付きメール送信スクリプト」の samail で使ってるのって何だったっけ?

#!/usr/local/bin/ruby

# Copyright (C) 2004 Saito Hiroaki <sonic64@infoseek.jp>
# http://sonic64.com/

require 'kconv'
require 'net/smtp'
require 'getopts'

あ、getopts だ。ダメじゃん。そのうち直そう。samail を書くときに困ったのは、どのモジュールが定番なのかよくわからなかったことだ。文字コード変換にも kconv や nkf とかいくつかあって、何を使うのが良いかを調べきれなかった。とりあえず標準で使えて、機能的に要件を満たしてるなら何でもいいやと思って kconv を使うことにしたんだっけ。

そういえば、2004-12-06 の 「sourceforge.jp にプロジェクトを登録する」で書いた samail を sourceforge に持って行く作業も滞ってるなー。なんとか時間作って作業しなきゃ。

非推奨になったことを Rubyリファレンスマニュアル - getopts.rb http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=geto ... に書いた方が良いと思うけど、どんな体裁で書いたらいいかよくわからないな。個人の wiki じゃなくてリファレンスマニュアルなのでテキトーに直すというのは良くなさそう。正しく整然と書きたい。

Rubyリファレンスマニュアル - 執筆者募集 http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=%BC% ... からリンクが張られてた The RWiki - Manuals' style http://pub.cozmixng.org/~the-rwiki/rw-cgi.rb?cmd=view&na ... には ML などに問い合わせてねとあるので、そのうち投稿してみるか。

2004-11-01 (Mon)

* 添付ファイル付メール送信Rubyスクリプト samail 0.4

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [メール] [Ruby]

2004-10-09 で書いた「添付ファイル付メールを送信する Ruby スクリプト」である samail 0.3 を修正して バージョン 0.4 とした。

- samail 0.4 の修正点

・smtp タイムアウト時のエラーを rescue Exception で捕捉するようにした。
・状況表示メッセージは標準エラー出力に出力するようにした。
・--output - を指定されたときは、SMTP にメールを投げずに標準出力のみに出力するようにした。
・setup メソッド内で初期化した変数を他のメソッドで参照するのはやっぱり違和感があるので setup メソッドを削除。グローバルなんだからいいんだろうけど。

- samail 0.4 で便利になった点

標準出力にメールの中身を出力するようにしたので、ローカルのメール送信コマンドを利用することができるようになった。これにより、samail の簡易な SMTP リトライ機能ではなくローカルの MTA が提供する強力かつ信頼性の高いリトライ機能を利用できる。また、samail はリトライのみでキューイング機能を持たないが、ローカル MTA はキューイング機能を持っていればそれを利用できる。

ローカルの sendmail コマンドに samail の出力を渡す例。
$ samail -v --to "sonic64@infoseek.jp example@example.com" --from sonic64@infoseek.jp --attachment "logo.png /tmp/backup.tar.bz2" |/usr/sbin/sendmail -f sonic64@infoseek.jp -oi "sonic64@infoseek.jp example@example.com"

- samil 0.4 ソース

ライセンスは 2004-10-09 でも書いたとおり、GPL2 と BSD のデュアルライセンス。

#!/usr/local/bin/ruby

# Copyright (C) 2004 Saito Hiroaki <sonic64@infoseek.jp>
# http://sonic64.com/

require 'kconv'
require 'net/smtp'
require 'getopts'

APPLICATION_NAME = 'Landscape Mailsender'
APPLICATION_VERSION = '0.4'
BANNER_STRING = APPLICATION_NAME + ' ' + APPLICATION_VERSION
X_MAILER_WEBSITE = 'http://sonic64.com/2004-11-01.html'

def build_mail_header()
  $mail_content << 'Date: ' + Time::now.strftime("%a, %d %b %Y %X %z") + "\n"
  $mail_content << 'From: ' + $mail_from + "\n"
  $mail_content << 'To: ' + $mail_to.join(', ') + "\n"
  $mail_content << 'Subject: ' + $mail_subject + "\n"
  $mail_content << "MIME-Version: 1.0\n"
  $mail_content << 'Content-Type: multipart/mixed; boundary="' + $boundary  + "\"\n"
  $mail_content << 'X-Mailer: ' + BANNER_STRING + "\n"
  $mail_content << 'X-Mailer-WebSite: ' + X_MAILER_WEBSITE + "\n"
  $mail_content << "\n"
end


def add_attchment(file_name)
  if file_name == '' then
    return
  end

  attachment_file = File.open(file_name).readlines.join('')
  encoded_attachment = [attachment_file].pack('m')
  $mail_content <<  '--' + $boundary + "\n"
  $mail_content << "Content-Type: application/octet-stream;\n"
  $mail_content << ' name="' + File.basename(file_name) + '"' + "\n"
  $mail_content << "Content-Transfer-Encoding: base64\n"
  $mail_content << "Content-Disposition: attachment;\n"
  $mail_content << ' filename="' + File.basename(file_name) + "\"\n\n"
  $mail_content << encoded_attachment + "\n"
end


def send_mail(retry_count)
  begin
    STDERR.puts Time::now.to_s + " Try to connect " + $smtp_server if $OPT_v
    Net::SMTP.start($smtp_server) do |smtp|
      smtp.sendmail($mail_content, $mail_from, $mail_to)
    end
    STDERR.puts Time::now.to_s + ' Send OK' if $OPT_v
  rescue Exception => e
    STDERR.puts Time::now.to_s + ' smtp error: ' + e.message
    if retry_count != 0 then
      retry_count -= 1
      STDERR.puts Time::now.to_s + ' sleep: ' + $smtp_retry_interval_second.to_s + 'sec'
      sleep($smtp_retry_interval_second)
      $smtp_retry_interval_second *= 2
      retry
    else
      STDERR.puts Time::now.to_s + ' abort: Over retry count'
      raise
    end
  end
end


# main
usage_message = "usage: #$0 [-v] --to TO_EMAIL_ADDRESS [--from FROM_EMAIL_ADDRESS] [--smtp SMTP_SERVER] [--attachment ATTACHMENT_FILE] [--output]"
unless getopts('v', 'from:', 'to:', 'subject:', 'attachment:', 'smtp:', 'output:')
  abort usage_message
end
abort "#$0: specifiy --to TO_EMAIL_ADDRESS\n" + usage_message if ! $OPT_to

if $OPT_output == '-' then
  $output2stdout = true
  $smtp_server = ''
elsif $OPT_smtp then
  $output2stdout = false
  $smtp_server = $OPT_smtp
else
  $smtp_server = 'localhost'
end

$mail_from = $OPT_from ? $OPT_from : ENV['USER'] + '@' + ENV['HOSTNAME']
$mail_to = $OPT_to.split(/,\s*|\s+/)
$mail_subject = $OPT_subject ? $OPT_subject : APPLICATION_NAME + ' [' + Time::now.strftime("%a, %d %b %Y %X %z") + ']'

$mail_content = ''
$boundary = 'boundary_string_by_landscape_mailsender'
$attachment_file = $OPT_attachment ? $OPT_attachment.split(/,\s*|\s+/) : []
$smtp_retry = 8
$smtp_retry_interval_second = 30

if $OPT_v then
  STDERR.puts 'To: ' + $mail_to.join(', ')
  STDERR.puts 'From: ' + $mail_from
  STDERR.puts 'Attachment file: ' + $attachment_file.join(", ")
  STDERR.puts 'Subject: ' + $mail_subject
  if $output2stdout then
    STDERR.puts 'Output to STDOUT'
  else
    STDERR.puts 'SMTP Server: ' + $smtp_server
  end
end

build_mail_header()
$mail_content <<  '--' + $boundary + "\n"
$mail_content << "Content-Type: text/plain; charset=iso-2022-jp\n"
$mail_content << "Content-Transfer-Encoding: 7bit\n"
$mail_content << "\n"
$mail_content << "-- \n"
$mail_content << 'Powered by ' + BANNER_STRING + "\n"
$mail_content <<  X_MAILER_WEBSITE + "\n"
$mail_content << "\n"

$attachment_file.each do |file|
  add_attchment(file)
end

$mail_content <<  '--' + $boundary + "--\n"

if $output2stdout then
  puts $mail_content
else
  send_mail($smtp_retry)
end


2004-10-14 (Thu)

* Ruby で全ての例外を rescue (catch) する

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [Ruby]

rescue Exception とすればあらゆる例外を rescue で捕捉できる。

表題の catch は Ruby の 多重ループを抜けるときなどに使う catch のことではなく、「例外を捕捉する」という意味で書いた。

[ruby-list:35487] Re: [ 質問] 例外の補足について
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/ ...
| begin - rescue - end による例外の補足機能では,補足できない例外があ
|るのでしょうか?

rescueに捕捉する例外を指定しないとStandardError(とそのサブク
ラス)を指定したと見なされます。例外の中にはStandardErrorのサ
ブクラスで無いものもありますから(たとえば、1.6ではNameError
はそうではありません)、その場合には捕捉できません。

具体的に例外を指定するか、

  rescue Exception

とするのが対処方法です。Exceptionを指定してあらゆる例外を捕
捉した場合には、思わぬ例外まで捕捉してしまわないように気をつ
けてください。

2004-10-09 で書いた 「添付ファイル付メールを送信する Ruby スクリプト」の samail 0.3 には例外発生時のリトライ機能を付けたのだが、それが機能していない。動作させたときのログを確認すると、Timeout::Error を rescue できていなかった。

C# の try catch や delphi の try exception では rescue Exception の動作がデフォルト。Ruby も同じようなものと思いこんでた。Ruby のリファレンスを読んでおけば良かったな。

2004-10-09 (Sat)

* 添付ファイル付メールを送信する Ruby スクリプト

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [メール] [Ruby]

コマンドラインから添付ファイル付きメールを送信する Ruby スクリプト samail を作成した。Send Attachment MAIL の略で、samail。読み方は「さめいる」または「えすえーめいる」かなあ。

2003-12-12 の「添付ファイル付きメールをコマンドラインから送信」や 2004-07-02 の「添付ファイル付メールを送信する Perl/Rubyスクリプト」 でもいろいろ書いたけど、Ruby 1.8 が使えるなら今回書いたスクリプトの方がカスタマイズはしやすい。

- samail の概要

コマンドラインで動作する、SMTP を利用したメール送信プログラム。
Ruby 1.8 の標準ライブラリしか使っていないため、Ruby さえインストールしてあれば動作する。

- samail の機能

添付ファイルを好きな数だけ指定して送信できる。
To, From, Subject を指定可能。To には複数のアドレスを指定可能。
Cc と Bcc には未対応。
SMTP サーバが必要。ローカルの MDA を呼び出す機能は未実装。
SMTP 失敗時には自動的にリトライする。初期設定では3回までリトライ。

- samail の動作確認環境

ruby 1.8.1 (2003-12-25) [i586-linux]
ruby 1.8.1 (2003-12-25) [i386-cygwin]

- samil のインストール

後述する samail ソースをコピー & ペーストして、samail というファイル名を付けてパスの通ったディレクトリに保存。
ファイルの文字コードは ASCII しか使ってないので何でも良い。改行コードは LF が良い。
chmod 744 などどして、ファイル samail に実行権限を付与。
以上で完了。

- samail の使い方と動作例

以下のようにコマンドラインから必要なオプションを渡す。
to や attachment には複数の値を指定できる。その場合、ダブルクオートかシングルクオートで値をくくり、それぞれの値はカンマかスペースで区切る。

$ samail -v --to "sonic64@infoseek.jp example@example.com" --from sonic64@infoseek.jp --smtp smtp.example.com --attachment "logo.png /tmp/backup.tar.bz2"

-v オプションを指定していると、標準出力に To, From, 添付ファイルのパス, subject, 使用する SMTP サーバ名を表示する。"Try to connect ..." はメール本文の生成が完了し、SMTP サーバに接続しようとした時点で表示する。Send OK は SMTP サーバへの送信を完了したときに表示する。

To: sonic64@infoseek.jp, example@example.com
From: sonic64@infoseek.jp
Attachment file: logo.png, /tmp/backup.tar.bz2
Subject: Landscape Mailsender Sat, 09 Oct 2004 20:35:34 +0900]
SMTP Server: smtp.example.com
Try to connect smtp.example.com
Send OK

samail は X-Mailer などで Landscape Mailsender を名乗る。

- ライセンス

何が良いんだろう? とりあえず GPL2 と BSD のデュアルライセンスにしておけばいいのかな。

- samail ソース

#!/usr/local/bin/ruby

# Copyright (C) 2004 Saito Hiroaki <sonic64@infoseek.jp>
# http://sonic64.com/

require 'kconv'
require 'net/smtp'
require 'getopts'

def setup()
  $APPLICATION_NAME = 'Landscape Mailsender'
  $VERSION = '0.3'
  $BANNER_STRING = $APPLICATION_NAME + ' ' + $VERSION
  $X_MAILER_WEBSITE = "http://sonic64.com/2004-10-09.html"

  $smtp_server = $OPT_smtp? $OPT_smtp : 'localhost'
  $mail_from = $OPT_from ? $OPT_from : ENV['USER'] + '@' + ENV['HOSTNAME']
  $mail_to = $OPT_to.split(/,\s*|\s+/)
  $mail_subject = $OPT_subject ? $OPT_subject : $APPLICATION_NAME + ' [' + Time::now.strftime("%a, %d %b %Y %X %z") + ']'

  $mail_content = ''
  $boundary = 'boundary_string_by_landscape_mail'
  $attachment_file = $OPT_attachment ? $OPT_attachment.split(/,\s*|\s+/) : []
  $smtp_retry = 3

  if ($OPT_v) then
    puts 'To: ' + $mail_to.join(', ')
    puts 'From: ' + $mail_from
    puts 'Attachment file: ' + $attachment_file.join(", ")
    puts 'Subject: ' + $mail_subject
    puts 'SMTP Server: ' + $smtp_server
  end
end


def build_mail_header()
  $mail_content << 'Date: ' + Time::now.strftime("%a, %d %b %Y %X %z") + "\n"
  $mail_content << 'From: ' + $mail_from + "\n"
  $mail_content << 'To: ' + $mail_to.join(', ') + "\n"
  $mail_content << 'Subject: ' + $mail_subject + "\n"
  $mail_content << "MIME-Version: 1.0\n"
  $mail_content << 'Content-Type: multipart/mixed; boundary="' + $boundary  + "\"\n"
  $mail_content << 'X-Mailer: ' + $BANNER_STRING + "\n"
  $mail_content << 'X-Mailer-WebSite: ' + $X_MAILER_WEBSITE + "\n"
  $mail_content << "\n"
end


def add_attchment(file_name)
  if file_name == '' then
    return
  end

  attachment_file = File.open(file_name).readlines.join('')
  encoded_attachment = [attachment_file].pack('m')
  $mail_content <<  '--' + $boundary + "\n"
  $mail_content << "Content-Type: application/octet-stream;\n"
  $mail_content << ' name="' + File.basename(file_name) + '"' + "\n"
  $mail_content << 'Content-Transfer-Encoding: base64' + "\n"
  $mail_content << "Content-Disposition: attachment;\n"
  $mail_content << ' filename="' + File.basename(file_name) + "\"\n\n"
  $mail_content << encoded_attachment + "\n"
end

def send_mail(retry_count)
  begin
    puts "Try to connect " + $smtp_server if $OPT_v
    Net::SMTP.start($smtp_server) do |smtp|
      smtp.sendmail($mail_content, $mail_from, $mail_to)
    end
    puts 'Send OK' if $OPT_v
  rescue
    puts 'smtp error occurred'
    if retry_count  != 0 then
      retry_count  -= 1
      send_mail(retry_count)
    else
      puts 'abort: Over retry count'
      raise
    end
  end
end


# main
unless getopts('v', 'from:', 'to:', 'subject:', 'attachment:', 'smtp:')
  abort "usage: #$0 [-v] --to TO_EMAIL_ADDRESS [--from FROM_EMAIL_ADDRESS] [--smtp SMTP_SERVER] [--attachment ATTACHMENT_FILE]"
end

setup()
build_mail_header()
$mail_content <<  '--' + $boundary + "\n"
$mail_content << "Content-Type: text/plain; charset=iso-2022-jp\n"
$mail_content << "Content-Transfer-Encoding: 7bit\n"
$mail_content << "\n"
$mail_content << "-- \n"
$mail_content << 'Powered by ' + $BANNER_STRING + "\n"
$mail_content <<  $X_MAILER_WEBSITE + "\n"
$mail_content << "\n"

$attachment_file.each do |file|
  add_attchment(file)
end

$mail_content <<  '--' + $boundary + "--\n"
send_mail($smtp_retry)

- 参考にしたもの

TMail
http://www.loveruby.net/ja/prog/tmail.html

vCard ファイルを添付したメールを作る
http://namazu.org/~satoru/attic/vcardmail.rb

SSTP Bottle メール送信クライアント
http://www.tenchi.ne.jp/~yoko/haruna/

- 2004年11月1日追記 2004-11-01 に samail 0.4 について書いた。

2004-07-02 (Fri)

* 添付ファイル付メールを送信する Perl/Rubyスクリプト

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [メール] [Perl] [Ruby]

コマンドラインから添付ファイル付きメールを送信したい。cron で定期的にメール送信するバッチが必要になった。

- 2003-12-12 でも同じ記事を書いたけど

2003-12-12 にも同じ「添付ファイル付きメールをコマンドラインから送信」という記事を書いたが、あれは Linux での話だ。今回は cygwin で同じことをやりたい。本当は前回の記事でも使った mpack を cygwin 環境でコンパイルして使おうと思ったんだけど、コンパイルエラーとなってしまった。

エラーを追求する手間をかけるよりも、今回は他の解決策を探した方が良いと私のゴーストがささやいている。「From の指定」など、mpack には無い機能も使いたいし。というわけで、今回は Perl か Ruby で SMTP と Content-Type: multipart/mixed; を扱うスクリプトを書くことにしよう。

- Perl で添付ファイル付きメールを送信

Perl であれば、すでに添付ファイル付きメール送信スクリプトのサンプルが河馬屋二千年堂のウェブサイトにあったはずなので、それを使えばいい。このサンプルを動かすには、いくつか必要なモジュールがある。その部分だけ引用しておく。

ActivePerlからメールを送る
http://member.nifty.ne.jp/hippo2000/perltips/perlmail.htm
添付ファイル付のメールを送信する + 日本語への対応+HTMLメール
use Net::SMTP;
use MIME::Entity;
use MIME::Words qw (:all);
require 'jcode.pl';

さすがは Perl、全くスクリプトを書かなくてもやりたいことを達成できてしまった。

- RUby で添付ファイル付きメールを送信

Ruby は標準インストールされるライブラリが充実してるから、もしかしたら smtp や base64 を扱うクラス、果ては添付ファイル付きメール送信クラスなんてものまで標準で用意されてるかも。ちょっと期待。

Google で ruby 添付ファイル メール 送信を検索。なんだかあまりヒットしないな。こういう細かい仕事を自動化するスクリプトの需要は結構あると思うんだけどな。検索語が悪いのかも。英語でやってみよう。Google で ruby base64 mail attachment を検索。[ruby-list:30312] composing a mail with a big file attached がヒット。なるほど、Tmail という便利なライブラリがあるんだね。

TMail
http://www.loveruby.net/ja/prog/tmail.html

オフィシャルサイトの説明には「Ruby 用 メール総合ライブラリ」って書いてある。かなり高機能なライブラリのようだ。あ、Tmail の作者は 「Rubyソースコード完全解説」や「Ruby レシピブック」で有名な青木さんだ。

- Tmail のインストール

cygwin でも無事インストールできた。

tar を展開して、
setup.rb config
setup.rb setup
setup.rb install
を実行するだけ。

コンパイルの時にいろいろエラーがでたけど、セットアップスクリプトが ignore するよって言ってるんだから気にしないことにする。

さて、この便利なライブラリ Tmail を使えば、簡単に添付ファイル付きメール送信スクリプトが書けるだろう。でも、やっぱりだれかが同じようなスクリプトを書いているはず。それを探して使うほうが早いだろう。ウェブを探してみると、高林さんが書いた「vCard ファイルを添付したメールを作る」が Tmail を使っている。短いし、これをちょっと修正すればやりたいことは達成できそう。

vCard ファイルを添付したメールを作る
http://namazu.org/~satoru/attic/vcardmail.rb

- スクリプト完成、いざメール送信

高林さんのスクリプトほとんどそのまま。元のスクリプトが GPL2 なので、以下のスクリプトのライセンスも GPL2。

#!/usr/bin/env ruby

require 'kconv'
require 'tmail'
require 'net/smtp'

def generate_filename (vcard)
  /^FN:(.*)/ =~ vcard
  name = $1
  "=?ISO-2022-JP?B?" + (name + '.vcf').tojis.to_a.pack('m').chomp + "?="
end

raise unless ARGV.length == 2
to = ARGV.shift
vcard = File.open(ARGV.shift).readlines.join('')

mail = TMail::Mail.new
mail.to = to
mail.from = 'example@example.com'
mail.subject = "vcard"
mail.date = Time.now
mail.mime_version = '1.0'

message = TMail::Mail.new
message.set_content_type('text', 'plain')
message.transfer_encoding = '7bit'
message.body = "vcard is attached.\n"

filename = 'atch'
encoded_vcard = [vcard].pack('m').chomp.gsub(/.{76}/, "\\1\n")
attachment = TMail::Mail.new
attachment.body = encoded_vcard
attachment.transfer_encoding = 'base64'
attachment.set_content_type('text', 'x-vcard', 'name' => filename)
attachment.set_content_disposition('attachment',
                   'filename' => filename)
mail.parts.push(message)
mail.parts.push(attachment)
mail.write_back

$smtp_server = '10.83.0.38'
Net::SMTP.start($smtp_server) do |smtp|
  smtp.sendmail(mail.encoded, mail.from, to)
end

- 2004年7月7日追記

って、あれ? この記事はもう少し加筆してから公開しようかと思ってたんだけど、いつの間にか公開状態になってる。まあいいや。上記スクリプトも変数名を直したり、複数添付ファイルに対応しようと思ってた。もしかしたら全く動かないかもしれない。そのうち直す予定。

- 2004-10-09 追記

Ruby 1.8 の標準ライブラリだけで動作する添付ファイル付きメール送信スクリプトを 2004-10-09 に書いた。

2004-05-13 (Thu)

* Rubyレシピブック

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [] [Ruby]

Rubyレシピブック 268の技Rubyレシピブック 268の技

青木 峰郎 / 後藤 裕蔵 / 高橋 征義 / まつもと ゆきひろ
発売日: 2004/05


amazon で詳しく見る   bk1で詳しく見る


著者の一人である青木さんの「あおきにっき つっこみつき」に情報があった。
http://i.loveruby.net/d/20040512.html#p02
『Rubyレシピブック』 2800 円で 5 月 28 日配本だそうです。配本つーことは、本屋にはもうちょい後にならぶ?あ、31 日出版となってるな。
とにかくそのあたりです!

Google で Ruby レシピブックを検索してもほとんど情報が無い。amazon や bk1 のデータベースにもまだ登録されていないようだ。たぶん上の紹介リンクも置換前の文字列のままだろう。データが登録されれば表示されるようになるだろうけど。唯一情報があったのが、ソフトバンクパブリッシングのサイト。

SBPストア Rubyレシピブック 268の技
http://store.sbpnet.jp/bm_detail.asp?sku=4797324295
RubyのTipsを満載したレシピ集。Rubyを使いこなすうえでのさまざまなテクニックを幅広く解説。様々な難問を即解決!

現時点では詳細な内容や目次の情報がほとんど無いが、Perl クックブックのようなノウハウ集だと私は想像している。Ruby はあまり慣れていないので、ぜひ手元に置いておきたい。2800円という値段も手頃だし。
Perlクックブック―Perlの鉄人が贈るレシピ集Perlクックブック―Perlの鉄人が贈るレシピ集

トム クリスチャンセン / ネイザン トーキントン / 田和 勝
発売日: 2001/03/23


amazon で詳しく見る   bk1で詳しく見る


- 2004年5月17日追記

あおきにっきつっこみつきに追加情報があった。

『Rubyレシピブック』内容紹介
http://i.loveruby.net/d/20040516.html#p04

2004-04-21 (Wed)

* Ruby 用 Postgres 接続ライブラリのインストール

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [Ruby] [Postgres]

Ruby で DB を扱う必要が出てきたので環境整備。本当を MySQL を使いたいのだが、サーバに MySQL が入っていない。使い慣れた PostgreSQL でもいいかな、と思ったので Postgres 環境を整備。

- Postgres 接続用ライブラリはいずこに?

/usr/local/lib/ruby を探してみたが、postgres 関連のライブラリは無いようだ。
Google で ruby postgres を検索したらヒット。

Postgres(Ruby PostgreSQL 拡張モジュール)
http://www.postgresql.jp/interfaces/ruby/index-ja.html

- インストール

ruby-postgres-0.7.1.tar.gz をダウンロードして、展開。
ruby extconf.rb --with-pgsql-include-dir=/usr/local/pgsql/include --with-pgsql-lib-dir=/usr/local/pgsql/lib
で configure。あとは make して make install でインストール完了。実に簡単。

- ruby から接続できるかテスト

テストテーブルを作成。
$ psql -c 'create table test1 (num int);'

テストデータを100件 INSERT。100 回 psql を呼んでるので遅いけど気にしない。
$ for i in `seq 1 100`; do psql -c "INSERT INTO test1 (num) VALUES ($i);"; done

SELECT 文を投げて、レコードの件数をカウント。この程度ならワンライナーで書いた方が早い。
$ ruby -e 'require "postgres"; conn = PGconn.connect("localhost", 5432, "", "", "hiroaki"); res = conn.exec("select * from test1;"); p res.num_tuples;'
100

よしよし、ばっちり接続できてるね。

- 今回作業した環境

$ ruby -v
ruby 1.8.1 (2003-12-25) [i586-linux]

$ psql -V
psql (PostgreSQL) 7.2.1

2004-03-30 (Tue)

* FileTest::file? にはフルパスを渡す

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [Ruby]

FileTest::file? や同様のメソッドである File.file? にはフルパスを渡すこと。ファイル名だけの場合はカレントディレクトリがパスとして渡される。

以下のコードを /home/hiroaki で実行すると、Dir::foreach は /home/hiroaki/public_html/log にあるファイルを返すが、その後の ファイルテストでは ファイル名しか渡っていないので、カレントディレクトリが指定されたことになり、File.file? 結果はすべて false になる。

$ ruby -v; ruby -e 'target = "/home/hiroaki/public_html/log"; Dir::foreach(target) {|f| if File.file?(f) then p "file: " + f end }'

ruby 1.8.1 (2003-12-25) [i386-cygwin]

こうすれば OK。
$ ruby -v; ruby -e 'target = "/home/hiroaki/public_html/log"; Dir::foreach(target) {|f| if File.file?(target + "/" + f) then p "file: " + f end }'

ruby 1.8.1 (2003-12-25) [i386-cygwin]
"file: .htaccess"
"file: 2002-08-30.html"
"file: 2002-08.html"
"file: 2002-09-02.html"
"file: 2002-09-03.html"
"file: 2002-09-04.html"
"file: 2002-09-10.html"
"file: 2002-09-11.html"

Dir::foreach のサンプルコードを載せてるサイトもいくつか見てみたんだけど、みんな Dir::foreach('.') と書いていたので気づくのが遅れた。

ruby でワンライナーを書くとセミコロンを忘れてエラーになっちゃうことが多いな。perl だったら普段からセミコロンをつけるから忘れないんだけど。

2004-02-21 (Sat)

* api.my.yahoo.com に weblogUpdates.ping すると Wrong content-type エラー

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [RSS] [Ruby]

昨日 2004-02-20 に、api.my.yahoo.com へ更新通知する方法を書いたが、ruby 1.8.1 の XMLRPC 1.2で weblogUpdates.ping を送るとエラーになってしまった。
$ script/update_ping.rb http://api.my.yahoo.com/RPC2
/usr/local/lib/ruby/1.8/xmlrpc/client.rb:543:in `do_rpc': Wrong content-type (RuntimeError)
from /usr/local/lib/ruby/1.8/xmlrpc/client.rb:409:in `call2'
from /usr/local/lib/ruby/1.8/xmlrpc/client.rb:399:in `call'
from script/update_ping.rb:18
update_ping.rb は 2004-02-15 に作ったスクリプト。

何が悪いのかを調べるため、ソースを追いかけてみることにした。/usr/local/lib/ruby/1.8/xmlrpc/client.rb を開く。攻殻機動隊の素子風に言うと「ソースにダイブする」かな。

do_rpc メソッド。538行目付近に例外の発生源があった。
ct = parse_content_type(resp["Content-Type"]).first
if ct != "text/xml"
  if ct == "text/html"
    raise "Wrong content-type: \n#{data}"
  else
    raise "Wrong content-type"
  end
end
resp というのはレスポンスだな。Content-Type レスポンスヘッダの値が text/xml じゃないと例外を発生させてるわけだ。api.my.yahoo.com はどんな Content-Type を返してきてるんだろう? ct を puts で出力させてみる。
text/plain
text/plain か。http://api.my.yahoo.com/rss/ping?u=http://sonic64.com/ を叩いたときと同じだな。

- どう修正しよう?

これって api.my.yahoo.com が悪いのかな。それとも、ruby の XMLRPC が厳格過ぎるのかな。この Content-Type をチェックしている if 文を無効にしてしまえばエラーを回避することはできるが、別のところで破綻しそうな気がする。とりあえず api.my.yahoo.com への更新通知は http://api.my.yahoo.com/rss/ping?u=http://sonic64.com/ に HTTP GET する方法を取ることにしよう。 代替手段もあることだし、XMLRPC のレスポンスは xml じゃないとダメなのか、などの深追いはしないことにする。

追記。その後、例外を rescue してエラーメッセージを標準エラー出力に出力するようにした。これならスクリプトの実行は継続され、weblogUpdates.ping はとりあえず成功するし。というわけでスクリプトは以下のようになった。

#!/usr/bin/env ruby
require 'xmlrpc/client'
require 'uri'

name = "Landscape - エンジニアのメモ"
url  = "http://sonic64.com/"

ping_uri = ARGV.shift
uri = URI.parse(ping_uri)
connection = XMLRPC::Client.new(uri.host, uri.path, uri.port)

result = nil
begin
  result =  connection.call("weblogUpdates.ping", name, url)
  puts "message: " + uri.host + ": " + result["message"]
rescue Exception => e
  puts Time::now.to_s + ' error: ' + ping_uri + ": " + e.message.split("\n")[0];
  puts Time::now.to_s + ' ' + ping_uri + ': weblogUpdates.ping: error'
  exit 1
end

- 余談

今回の記事のタイトルはじつに長くて読みづらい。日本語が7文字しかない。これ以上削れないと思って、「RSS: Ruby: api.my.yahoo.com に weblogUpdates.ping すると Wrong content-type エラー」という長いタイトルにしたんだけど、今考えると Wrong content-type は削ろうと思えば削れるかなあ。「RSS: Ruby: api.my.yahoo.com に weblogUpdates.ping するとエラー」だけでも良かったかも。

2004-02-15 (Sun)

* weblogUpdates.ping で更新を通知するRubyスクリプト

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [Ruby]

RSS やサイトの更新を通知する、weblogUpdates.ping を送ってみることにする。
でも、送り方がわからない。MovableType などであれば簡単に送れるらしいが、使ってない場合はどうしたら良いんだろう? そもそも、どこに ping したら良いかもわからない。そのうえ、この記事を書いてる今現在、何で weblogUpdates.ping を送りたくなったかも忘れてしまった。送りたいと思ったのが今朝。遊びに行って、帰ってきてさあやるぞと取りかかった夜頃にはすべて忘れてしまっている。なんかやる気のない日曜の夜。

まずは Google で weblogUpdates.ping を検索。全体のヒット数は少なめだが、名の売れたサイトがいくつかヒットした。

- どこに weblogUpdates.ping を送るか

hail2u.net - Weblog - weblogUpdates pingを受け付けているサーバー
http://hail2u.net/blog/blog/weblogupdates_ping_servers.html

とりあえず紹介されてた全部のサイトに送ってみることにする。あ、Bullkfeeds は 2003-12-23 に書いた HTTP GET で更新を通知する方法を運用済みなので今回は除外。Myblog japan もユーザ登録が大変そうなので除外。今回送るのは以下の7つ。

Weblogs.Com http://rpc.weblogs.com/RPC2
blo.gs http://ping.blo.gs/
BlogRolling http://rpc.blogrolling.com/pinger/
Technorati http://rpc.technorati.com/rpc/ping
ping.bloggers.jp http://ping.bloggers.jp/rpc/
ココログ http://ping.cocolog-nifty.com/xmlrpc
BlogPeople http://www.blogpeople.net/servlet/weblogUpdates

どこに送るかはこれで決まった。あとは、どうやって送るかだ。

- どうやって送るか

先ほどの Google で weblogUpdates.ping を検索した結果を眺めていると、Perl で ping を送るクライアントの実装例があった。

Weblogs.Com Ping の Perl による実装
http://naoya.dyndns.org/~naoya/mt/archives/000423.html

やったー、コードを書く手間が省けたーと喜んだのもつかの間。module インストール時に以下のエラーが出てうまくいかない。長いけどエラーメッセージなので書いておこう。
  CPAN.pm: Going to build M/MS/MSERGEANT/XML-Parser-2.34.tar.gz

Note (probably harmless): No library found for -lexpat

Expat must be installed prior to building XML::Parser and I can't find
it in the standard library directories. You can download expat from:

http://sourceforge.net/projects/expat/

If expat is installed, but in a non-standard directory, then use the
following options to Makefile.PL:

    EXPATLIBPATH=...  To set the directory in which to find libexpat

    EXPATINCPATH=...  To set the directory in which to find expat.h

For example:

    perl Makefile.PL EXPATLIBPATH=/home/me/lib EXPATINCPATH=/home/me/include

Note that if you build against a shareable library in a non-standard location
you may (on some platforms) also have to set your LD_LIBRARY_PATH environment
variable at run time for perl to find the library.

Running make test
  Make had some problems, maybe interrupted? Won't test
Running make install
  Make had some problems, maybe interrupted? Won't install
Running make for K/KM/KMACLEOD/Frontier-RPC-0.06.tar.gz
  Is already unwrapped into directory /home/aqua/.cpan/build/Frontier-RPC-0.06

  CPAN.pm: Going to build K/KM/KMACLEOD/Frontier-RPC-0.06.tar.gz

cp lib/Frontier/Daemon.pm blib/lib/Frontier/Daemon.pm
cp lib/Frontier/Client.pm blib/lib/Frontier/Client.pm
cp lib/Frontier/RPC2.pm blib/lib/Frontier/RPC2.pm
  /usr/bin/make  -- OK
Running make test
/usr/bin/perl.exe "-Iblib/lib" "-Iblib/arch" test.pl
1..1
Can't locate XML/Parser.pm in @INC (@INC contains: blib/lib blib/arch /usr/lib/perl5/5.8.2/cygwin-thread-multi-64int /usr/lib/perl5/5.8.2 /usr/lib/perl5/site_perl/5.8.2/cygwin-thread-multi-64int /usr/lib/perl5/site_perl/5.8.2 /usr/lib/perl5/site_perl .) at blib/lib/Frontier/RPC2.pm line 14.
BEGIN failed--compilation aborted at blib/lib/Frontier/RPC2.pm line 14.
Compilation failed in require at blib/lib/Frontier/Client.pm line 14.
BEGIN failed--compilation aborted at blib/lib/Frontier/Client.pm line 14.
Compilation failed in require at test.pl line 19.
BEGIN failed--compilation aborted at test.pl line 19.
not ok 1
make: *** [test_dynamic] Error 2
  /usr/bin/make test -- NOT OK
Running make install
  make test had returned bad status, won't install without force

Frontier::Client をインストールしようとしたら XML-Parser に依存していたのでまずは XML-Parser をインストールしようとしたら lexpat というライブラリが無くてビルドができないとのこと。lexpat は SourceForge からダウンロードしてインストールしなければならないらしい。あーもう大変だなあ。perl 以外の方法はないかなあと再び Google で weblogUpdates.ping を検索した結果を見ると、Ruby での実装例があった。やったー。

weblogUpdate の Ruby 実装 : スタンドアローンサーバ版
http://dontstopmusic.no-ip.org/diary/20030911.html#p04

Ruby なら 1.8.1 をインストール済みだし、たいていのライブラリが標準でインストールされるので手間が省けるはず。サンプルを動かしたら問題なく動作したので、ちょっと修正して以下のようにした。もらってきたコードほとんどそのままだけど。

- weblogUpdates.ping を送る Ruby スクリプト

Ruby 1.8.1 + cygwin で動作を確認。

#!/usr/bin/env ruby
require 'xmlrpc/client'
require 'uri'

name = "Landscape - エンジニアのメモ"
url  = "http://sonic64.com/"

ping_uri = ARGV.shift
uri = URI.parse(ping_uri)
connection = XMLRPC::Client.new(uri.host, uri.path, uri.port)
result =  connection.call("weblogUpdates.ping", name, url)
puts "message: " + uri.host + ": " + result["message"]

ping 送信先だけは引数で指定できるようにした。本当はウェブサイト名や url も引数で指定できるようにしようと思ったのだが、cygwin のシェルから2バイト文字列を送るとトラブルの元になりそうだったのでハードコーディングしてしまった。また、ruby スクリプト自体も念のため UTF-8 改行コード LF で保存した。UTF-8 はもしかしたら逆にトラブルの元になるかもしれないが、動かしたら問題なかったのでそのまま使うことにした。

あとはこれを
$ ~/script/update_ping.rb http://rpc.weblogs.com/RPC2
などとして ping するだけだ。

追記。
2004-02-21 に「api.my.yahoo.com に weblogUpdates.ping すると Wrong content-type エラー」という記事を書いた。

2004-02-04 (Wed)

* 続「peeraddr が遅い?」 NetBIOS が悪い?

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [Ruby]

2004-02-03 の 「peeraddr が遅い?」の続き。もはや Ruby とは関係ないんだろうけど、続きということで。
[ruby-list:24947] Re: win32 版でのTCPServer#addr, peeraddr の挙動
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/ ...
後者は,WINSかNetBIOSがらみの問題と推測されます.
たとえば,以下が考えられます.

  o WINSサーバーのアドレスが間違っているかサーバーが落ちている
  o まともなブラウズマスタがいない

"nbtstat -A 存在しないIPアドレス"を実行したときのタイムアウトが
約5秒なので,5秒×2 = 10秒というのは納得できます.
なるほど・・・。では、NetBIOS を無効にしてみよう。

- NetBIOS over TCP/IP を無効にしたら速くなった。

$ time script/mftp.rb -w
["AF_INET", 80, "216.239.57.104", "216.239.57.104"]

real    0m0.564s
user    0m0.160s
sys    0m0.150s

速くなったのはうれしいけど、NetBIOS over TCP/IP を無効にするとファイル共有できなくなっちゃうんじゃなかったっけ? LAN でファイル共有できなくなったら困るし、WINS や NetBIOS って関わりたくないんだけど一応調べておくか。Google で NetBIOS over TCP/IP 無効を検索。うーん、やっぱり無効にするとファイル共有はできなくなっちゃうみたい。ブラウズマスタを立てれば良いのかもしれないけど、とりあえず今はこのままでも良いか。ファイル共有のことはその時考えるとしよう。

2004-02-03 (Tue)

* peeraddr が遅い?

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [Ruby]

Ruby で net/ftp.rb を使った ftp アップローダを書いてみたが、ファイルの転送が始まるまでが異常に遅い。CPU を食いつぶしてるわけでも、ディスクが遅いわけでも、帯域が足りないわけでもない。どうも、コネクションの生成あたりで時間がかかっているようなのだ。

- 環境

OS は Windows2000 SP4。あとは以下の通り。
$ uname -a
CYGWIN_NT-5.0 s 1.5.5(0.94/3/2) (2003-09-20) 16:31 i686 unknown unknown Cygwin

$ ruby -v
ruby 1.8.1 (2003-12-25) [i386-cygwin]

- net/ftp.rb を追跡

printf("%s: %s: %d\n", Time.now - start, __FILE__, __LINE__) をftp アップロードスクリプトの至る所に仕掛け、表示される時間をチェックしていく。
start = Time.now
printf("%s: %s: %d\n", Time.now - start, __FILE__, __LINE__)
何らかの処理
printf("%s: %s: %d\n", Time.now - start, __FILE__, __LINE__)

チェックの結果、net/ftp の putbinaryfile メソッドの呼び出しに時間がかかっていることがわかった。さらに以下のようにして net/ftp.rb のメソッドを追跡していったところ af = (@sock.peeraddr)[0] が遅いことがわかった。
def sendport(host, port)
  start = Time.now
  printf("%s: %s: %d\n", Time.now - start, __FILE__, __LINE__)
  af = (@sock.peeraddr)[0]
  printf("%s: %s: %d\n", Time.now - start, __FILE__, __LINE__)

- Google に聞いてみる

Google で ruby peeraddr 遅い を検索するとヒット。
[ruby-list:24928] Re: win32 版でのTCPServer#addr, peeraddr の挙動
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/ ...
その,i386-mswin32版のRuby 1.4.5を落としてWindows 98で使って
みましたが,まったく問題ありませんでした.

単に名前解決に時間がかかっているだけだと思います.
つまり,ネットワークの環境と設定の問題と考えられます.

telnetで接続した直後にnetstat -aを実行してみて出力がひっかからずに
スムーズに表示されますか?

どこかでひっかかるようなら,表示が遅い行のIPアドレスの逆引きが
うまくいっていないということなので,DNSかWINSかhostsの設定を
確認してみてください.

うーん、WINS なんて使ってないし・・・。ipconfig で確かめてみるか。

$ ipconfig /all

Windows 2000 IP Configuration

        Host Name . . . . . . . . . . . . : s
        Primary DNS Suffix  . . . . . . . :
        Node Type . . . . . . . . . . . . : Hybrid
        IP Routing Enabled. . . . . . . . : No
        WINS Proxy Enabled. . . . . . . . : No
        DNS Suffix Search List. . . . . . : ***.**.jp

Ethernet adapter ローカル エリア接続 2:

        Connection-specific DNS Suffix  . : ***.**.jp
        Description . . . . . . . . . . . : 3Com EtherLink XL 10/100 PCI TX NIC (3C905B-TX)
        Physical Address. . . . . . . . . : 00-**-**-**-**-**
        DHCP Enabled. . . . . . . . . . . : Yes
        Autoconfiguration Enabled . . . . : Yes
        IP Address. . . . . . . . . . . . : 192.168.0.2
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 192.168.0.1
        DHCP Server . . . . . . . . . . . : 192.168.0.1
        DNS Servers . . . . . . . . . . . : ***.**.1.3
        Primary WINS Server . . . . . . . : 192.168.0.200
        Lease Obtained. . . . . . . . . . : 2004年2月3日 1:00:13
        Lease Expires . . . . . . . . . . : 2004年2月4日 1:00:13

・・・? あれ? Primary WINS Server に 192.168.0.200 が指定されてるぞ? これが原因? うーん、プロバイダに問い合わせてみるか・・・。でも、perl だと問題なくて Ruby だと問題あるんだよなあ。私の設定が悪いのかなあ。現象を再現できる最小の ruby のコードと、他の言語で類似のコードを書いて、原因を絞り込んでみよう。

- ruby でのテストコード

#!/usr/local/bin/ruby -l
require 'socket'

sock = TCPSocket.open('www.google.co.jp', '80')
p sock.peeraddr
上記のコードを実行すると、以下のようになる。なんで5秒もかかるんだろう?
$ time script/mftp.rb -w
["AF_INET", 80, "216.239.57.104", "216.239.57.104"]

real    0m5.535s
user    0m0.200s
sys    0m0.130s

ちなみに、
sock = TCPSocket.open('216.239.57.104', '80')
と IP アドレスで指定しても5秒かかる。OS 付属の nslookup だとなぜか一瞬で終わる。

$ time nslookup www.google.co.jp
Server:  dns1.****.**.jp
Address:  ***.**.1.3

Non-authoritative answer:
Name:    www.google.akadns.net
Addresses:  216.239.57.104, 216.239.57.99
Aliases:  www.google.co.jp, www.google.com


real    0m0.545s
user    0m0.010s
sys    0m0.030s

他の言語でも遅いのかを調べるために、perl でテストコードを書いてみた。
#!/usr/bin/perl
use Socket;

my ($host, $port, $ip, $sockaddr, $buf);
$host = 'www.google.co.jp';
$port = 80;

# ソケットの生成
$ip = inet_aton($host) || die "host($host) not found.\n";
$sockaddr = pack_sockaddr_in($port, $ip);
socket(SOCKET, PF_INET, SOCK_STREAM, 0) || die "socket error.\n";

# ソケットの接続
connect(SOCKET, $sockaddr) || die "connect $host $port error.\n";

# 終了処理
close(SOCKET);

やっぱり一瞬で終わる。
$ time script/perlsock.pl

real    0m0.992s
user    0m0.240s
sys    0m0.180s

続きは明日 2004-02-04 にやろう。

2004-01-15 (Thu)

* Rubyマルチスレッドプログラミング 1 ftp uploader

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [Ruby]

今まで ftp でファイルをアップロードするとき、簡単なシェルスクリプトを使っていた。しかし、回線の品質が悪かったりすると、タイムアウトが発生したりすることがある。ファイル数が少ないうちはタイムアウトを待つ時間は大したことはないのだが、数百や数千ファイルを扱うときはタイムアウト待ちの時間は無視できなくなる。シングルスレッドではなく、マルチスレッドで動作させれば待ち時間を少なくすることができる。

シェルスクリプトでもコマンド末尾に & を付けてバックグラウンドで実行すればサーバへの接続を複数持つことはできるが、それでは面白くない。せっかくだから使ったことのない言語で書きたい。以前から Ruby を学びたいと考えていたので、Ruby でコードを書くことにした。Ruby ではスレッドを簡単に扱えるようになっているので、今回の課題にはうってつけだろう。

- 大富豪的プログラミング

以下のサイトを参考に、スレッドを使った ftp クライアントを書いてみた。

チュートリアル: Thread - オブジェクト指向言語Ruby
http://www.ruby-lang.org/ja/20020315.html

逆引きRuby - スレッド
http://www.namaraii.com/rubytips/?%A5%B9%A5%EC%A5%C3%A5%C9#l ...

Ruby 1.8.1 には ftp 用のクラスが標準添付されており、簡単に書くことはできた。ただし正常に動作しない。もちろん、Ruby が悪いのではなく、私のコードが、とくにスレッドの使い方が悪い。

実行するとものすごい勢いでスレッドが生成されていき、それと同時に ftp コネクションも作られていく。ファイルが100個あると、スレッドも100個、ftp コネクションも100個というすさまじいクライアントになってしまった。こんなクライアントでは大富豪が運営するサーバにしか接続できないだろう。とりあえず生成するコネクションの上限を設け、コネクションプールを実装しようとしたが、今度は転送が終わって再利用可能になったはずのコネクションを再利用できなかったりと、問題がたくさんある。どうやら私はまったくスレッドを使いこなせていないようだ。今までシングルスレッドのコードしか書いたことがなかったが、マルチスレッドの概念くらいは理解しているつもりだった。排他制御が要だとか、DB のロックと同じレベルだと思ってたが、甘かったようだ。

- 先人の知恵に頼れ

こうなったらもう本を読んだ方がいい。ちょうど後輩が結城さんのデザインパターン本のマルチスレッド編を持っていたので、借りてきた。

これはいい本だ。私は Java は情報処理の試験で使うために文法だけ覚えただけだが、十分わかる。そもそもスレッドとは何か、というところから始まっているので、Java を知らなくても読んでいける。サポートサイトもあるのでメモしておこう。

『Java言語で学ぶデザインパターン入門 マルチスレッド編』
http://www.hyuki.com/dp/dp2.html

2004-01-01 (Thu)

* cygwin に ruby 1.8.1 をインストール

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [Ruby]

cygwin 環境に ruby 1.8.1 をインストールする。Google で cygwin ruby で検索するとヒット。

Yet another Ruby porter, - RubyをCygwin環境で作る
http://wiki.fdiary.net/yarp/?Ruby%A4%F2Cygwin%B4%C4%B6%AD%A4 ...
Cygwin版Rubyのビルドとインストール
単に

% tar xfvz ruby-1.6.8.tar.gz
% cd ruby-1.6.8
% mkdir BUILD_cygwin; cd BUILD_cygwin
% ../configure --enable-shared && make && make check
% make install
するだけ。

なんだ、cygwin だからいろいろ設定を変えてコンパイルしなければならないのかと思ってたけど、そうでもないんだね。ただ、今回入れようとしてるのは1.8.1だからそこで何かはまるかもしれない。

ruby オフィシャルサイトから ruby 1.8.1 の tar ボールをダウンロード。あとは、上記コマンドをそのままコピ & ペースト。友達に初詣に誘われたので出かけてしまったので、make にどれくらい時間がかかったかはわからない。やっと新年らしい言葉が出てきたな。

さて、初詣から帰ってくると make check に失敗してる。
make: *** No rule to make target `check'.  Stop.
make test ならどうだ。

$ make test
../rubytest.rb:37: warning: Insecure world writable dir /home/aqua, mode 040777
/home/aqua/ruby-1.8.1/sample/test.rb:1643: warning: Insecure world writable dir /home/aqua, mode 040777
/home/aqua/ruby-1.8.1/sample/test.rb:1650: warning: Insecure world writable dir /home/aqua, mode 040777
/home/aqua/ruby-1.8.1/sample/test.rb:1651: warning: Insecure world writable dir /home/aqua, mode 040777
/home/aqua/ruby-1.8.1/sample/test.rb:1658: warning: Insecure world writable dir /home/aqua, mode 040777
/home/aqua/ruby-1.8.1/sample/test.rb:1668: warning: Insecure world writable dir /home/aqua, mode 040777
/home/aqua/ruby-1.8.1/sample/test.rb:1669: warning: Insecure world writable dir /home/aqua, mode 040777
test succeeded

cygwin なのでパーミッションをいい加減な設定にしてたために Insecure world writable dir /home/aqua, mode 040777 という警告が出てるが、マルチユーザの unix システムを使ってる訳じゃないから気にしないでおこう。とりあえずテストは成功。make install して完了。さっきの wiki に 1.8.1 だと make test だよと加筆しておこう。

2003-08-13 (Wed)

* Ruby 1.80 を pro に入れてみる

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [Ruby]

SoftwareDesign で高林さんの pdumpfs の記事を読んだら、
なんだか ruby をインストールしたくなった。

たしか先日 1.80 がリリースされたはず。ここは一発チャレンジだ。
まだ枯れてはいない 1.80 をインストールする。

wget http://www.t.ring.gr.jp/archives/lang/ruby/1.8/ruby-1.8.0.tar.gz
tar zxvf ruby-1.8.0.tar.gz
cd ruby-1.8.0/
./configure && make && make test
su
make install

コンパイルとインストールはとくにトラブル無く進んだ。
ただ、make test の結果が、

test succeeded

の一行だけってのがなんか寂しい気もした。
何のテストしてるのかもよくわからないし。まあいいか。
ということで、インストール完了。

すべての記事の見出し (全1029件)
全カテゴリの一覧と記事の数
カテゴリごとに記事をまとめ読みできます。記事の表題だけを見たい場合は、すべての記事の見出し (カテゴリ別表示) へ。

直近30日分の記事
2007-04-23 (Mon)
2007-03-07 (Wed)
2007-02-27 (Tue)
2007-01-17 (Wed)
2007-01-15 (Mon)
2007-01-14 (Sun)
2007-01-08 (Mon)
2006-12-01 (Fri)
2006-11-22 (Wed)
2006-11-20 (Mon)
2006-11-19 (Sun)
2006-09-30 (Sat)
2006-08-29 (Tue)
2006-08-04 (Fri)
2006-07-27 (Thu)
2006-07-23 (Sun)
2006-07-17 (Mon)
2006-07-10 (Mon)
2006-07-06 (Thu)
2006-07-03 (Mon)
2006-06-29 (Thu)
2006-06-28 (Wed)
2006-06-27 (Tue)
2006-06-25 (Sun)
2006-06-19 (Mon)
2006-06-18 (Sun)
2006-06-15 (Thu)
2006-06-11 (Sun)
2006-06-01 (Thu)
2006-05-30 (Tue)
プロファイル
斎藤 宏明。エンジニアです。宇都宮市に住んでいます。
リンク
RSS
スポンサードリンク
Powered by
さくらインターネット

© 斎藤 宏明 Saito Hiroaki Gmail Address
Landscape - エンジニアのメモ http://sonic64.com/
Landscape はランドスケープと読みます。
ひらがなだと らんどすけーぷ です。