Ruby 1.9.0 released?
12/25 23:33 の commit で 1.9.0 は freeze されてリリース……のかな?
Tue Dec 25 23:33:55 2007 Yukihiro Matsumoto <matz@ruby-lang.org> * development version 1.9.0 released.
でも、svn リポジトリ上で tag が作られた様子は無いので、まだなのかも。
あと、Code Golf 用の goruby という実行ファイルがどさくさに紛れて追加されたようだ(ruby-dev:32766 )。
下のようなコードが予め組み込まれた ruby 処理系で、メソッド名を省略できたり h 一文字で "Hello, world!" と表示されたり、なかなかアヤシイ。
class Object def method_missing m, *a, &b r = /^#{m}/ t = (methods + private_methods).sort.find{|e|r=~e} t ? __send__(t, *a, &b) : super end def h(a='H', b='w', c='!') puts "#{a}ello, #{b}orld#{c}" end end
Ruby 1.9 の新機能を調べてみた
1.9.0 のリリースも近いということで、Changes in Ruby 1.9 を参考にしながら Ruby 1.9 trunk (r14828) で遊んでみた。
まあ、ほとんどは上のサイトに書いてあるとおりなんだけど、「おっ」と思った点やその他で気付いた点を以下に列挙。(既に書かれている内容はほぼ省略)
- Changes in Ruby 1.9 のページに書いてあるけど現状に即していない点。
Object#__send__
は、けっきょく可視性に関わらず全てのメソッドを呼べるようになった。(__send
や__send!
は廃止)NameError
は、けっきょくStandardError
のサブクラスに戻った。Hash#each
とHash#each_pair
は同じ動作になった。- 他にもあるかもしれないけど、とりあえず気付いたのは以上。
- RubyGems が標準で組み込まれる
- 機能縮小版が自動的に組み込まれる (gems_prelude.rb)
- コマンドラインで
--disable-gems
を指定すれば回避可能
String
とEncoding
- 文字列リテラルで
"\uHHHH"
と書けるようになった。 $KCODE
は意味をなさなくなった (使おうとすると warning が出る)String#size
で文字数,String#bytesize
でバイト数- 文字列オブジェクトごとに encoding 情報を持っている。(
String#encoding
)- 今のところ有効らしい encoding は ASCII-8BIT, UTF-8, Shift_JIS, EUC-JP, ISO-2022-JP.
(追記: 勘違い)String#ord
は、多バイト文字の場合は Unicode(UCS) が返る(ようだ)。String#force_encoding(encode_name)
で encoding を変更.String#valid_encoding?
でその文字列が正しい encoding なのか(文字列として正しいバイト表現なのか)をチェック。
- 文字列リテラルで
a = "\xE3\x81\x82" # UTF-8 で "あ" p a.encoding #=> <Encoding:ASCII-8BIT> a.force_encoding('UTF-8') p a.encoding #=> <Encoding:UTF-8>
# -*- encoding: UTF-8 -*- p "a".encoding #=> <Encoding:ASCII-8BIT> p "あ".encoding #=> <Encoding:UTF-8>
-
-
encoding:
じゃなくてcoding:
でも同じ動作のようだけど、どちらが正しいんだろう?
- コマンドラインから
--encoding=UTF-8
といった指定も可能。 - ファイルから読む場合は
File.open(filename, 'r:UTF-8')
とか。 (追記: その後のバージョンでは変換してくれるようになった)File.open(filename, 'w:EUC-JP')
とか書くと自動変換してくれるのかと思ったけど、してくれないようだ。Encoding.default_external
って、何の意味があるんだろう。どうやって変更するんだろう。- まだ全貌を掴めてない。
-
- その他
p
の返り値がnil
ではなくなった。(引き数をそのまま返す。引き数なしの場合はnil
)
- 最近の話題
- 単項演算子
!
がメソッド扱いになり、再定義できるようになった。!!object
で true または false に変換する、というイディオムが通用しなくなる(可能性がある)ので、ちょっとだけ気持ち悪い。
- 単項演算子
class A; def !@; "hoge"; end; end p ! A.new #=> "hoge"
!
が再定義できると聞いて、とりあえず皆やるであろうことをやってみた。
class TrueClass def !@; true; end end p !true #=> true
うお、再定義できた! すげえ。
後日追記。
m17n 関連について、もう少しきちんとまとめました。id:macks:20080102
Ruby で DNS Update (RFC 2136)
Ruby を使って RFC 2136 の DNS Update を実行する方法を調べてみた。
標準添付の Resolv::DNS クラスはルックアップの機能しか無いので、Perl の Net::DNS のようなモジュールを探してみたところ、Perl の Net::DNS を移植したという 2 つのライブラリを見付けた。
- Net::DNS (http://rubyforge.org/projects/net-dns/)
- pNet::DNS (http://rubyforge.org/projects/pnet-dns/)
両方比べてみたところ、Net::DNS の方は肝心の update 関連の機能が未実装だったので、今のところ選択肢は pNet::DNS だけのようだ。
pNet::DNS の使い方
まずはインストール。
$ sudo gem install pnet-dns
nsupdate コマンドでの操作を Ruby に置き換えるなら以下のようになる。
$ nsupdate
> server 192.168.1.1
> prereq nxdomain host1.example.com.
> update add host1.example.com. 3600 IN A 192.168.1.2
> send
↑上の操作は、以下↓のようになる。
require 'rubygems'
require 'Net/DNS'
resolver = Net::DNS::Resolver.new(:nameservers => %w(192.168.1.1))
packet = Net::DNS::Update.new_from_values('example.com')
packet.push('prereq', Net::DNS.nxdomain('host1.example.com'))
packet.push('update', Net::DNS.rr_add('host1.example.com 3600 IN A 192.168.1.2'))
resolver.send(packet)
また、TSIG (Transaction Signature) を使ってリクエストの認証を行なうには、Net::DNS::Resolver#send の直前に Net::DNS::Packet#sign_tsig を使用する。
packet.sign_tsig('キーの名前', 'Base64エンコードされた秘密鍵')
resolver.send(packet)
キーの名前や Base64 エンコードされた秘密鍵は、dnssec-keygen コマンドで作った鍵ファイルから取り出して使用する。
なお、pNet::DNS の現時点の最新リリース(0.0.4)には TSIG 関連の機能が動作しないバグがあるので、svn リポジトリから最新版を checkout してくるか、パッチ*1をあてて使用する必要がある。
感想
TSIG の動作修正パッチを作ったのは俺なんだけど、今まで誰も気付かず放置されてたのが不思議なくらいに初歩的なミスばかりで、こういう辺りは圧倒的なユーザー人口と厚みを誇る Perl とは比べものにならないなあ、と思った。
ThinkPad X60s に Debian GNU/Linux 4.0 (etch) をインストール
ThinkPad X60s に Debian GNU/Linux 4.0 (etch) をインストールしてみた。*1
とは言え、基本的なインストールは有線 LAN (e1000) 経由なら特に詰まることもなく、普通に終了。Xorg も i810 ドライバで普通に起動した。
少しだけひねりが必要だったのは、以下の 2 つ。
無線 LAN
私が購入したのは Intel 3945ABG (MIMO 非対応) が搭載されているモデルだったので、non-free/contrib セクションから ipw3945 および関連パッケージをインストール。
$ sudo apt-get install ipw3945-modules-2.6-686 ipw3945d
ipw3945 モジュールをロードして /etc/init.d/ipw3945d を実行したところ、eth2 として認識された。
無線 LAN そのものの設定は、個人的事情により ESS-ID で使い分ける必要があったため、/etc/network/interfaces は以下のようになった。
(中略) mapping eth2 script /root/bin/scan-essid.sh map WLAN1xxxxxx wlan-station1 map WLAN2yyyyyy wlan-station2 iface wlan-station1 inet dhcp wireless-essid WLAN1xxxxxx ... (中略) iface wlan-station2 inet dhcp wireless-essid WLAN2yyyyyy ... (以下略)
また、/root/bin/scan-essid.sh はこんな感じ。
#!/bin/sh -e iface="$1" essid_list=$(iwlist $iface scanning 2>/dev/null | sed -n -e '/^ *ESSID:/ { s/.*:"\(.*\)"/\1/; p }') while read id scheme; do for essid in $essid_list; do if [ "$id" = "$essid" ]; then echo $scheme exit 0 fi done done exit 1
RTC
/sbin/hwclock を実行すると、時刻を読み出せずに `select() to /dev/rtc to wait for clock tick timed out' というエラーメッセージが出力されるという症状に見舞われた。これに加えて、ハードウェア時計を JST にしているため*2、起動時にシステム時計が 9 時間ずれる現象が発生した。
試行錯誤と Google 検索の後、`hwclock --directisa' と実行すれば時計が読めることが判明。ついでに、rtc モジュールを rmmod した場合も大丈夫なことが判明。
結局、/etc/modprobe.d/local に `blacklist rtc' と書いて解決。
ThinkPad X60s DtoD(Disk to Disk) リカバリー領域の移植
ThinkPad X60s を買った。
安かったので HDD 40GB のモデルを購入したんだけど、もちろんそんな容量では話にならないので、さっそく HDD を換装した。
その際 DtoD(Disk to Disk)リカバリー領域を移植したので、その時の記録を残しておこうと思う。なお、本体と換装用ドライブ以外に私が使ったのは以下のもの。
- USB 接続 HDD ケース (2.5" SATA 用)
- Linux マシン1台
- Windows マシン1台
- USB FDD
- リカバリーディスクを起動するのに必要。ネットワークブートが出来るなら memdisk (syslinux に同梱)を使えるので不要かも。
- Debian(etch) の netboot インストーラ
- 試行錯誤の度にネットワークブートするのが面倒だったので、etch をインストールしてしまった。
私がやった手順は以下のとおり。
- ドライブを換装する。元のドライブは USB 接続な HDD ケースに納める。
- 有線 LAN を使ってネットワークブート。適当なディスクレス Linux 環境を起動させる。また、USB に移植元のドライブを接続して認識したことを確認する(dmesg とか /proc/partitions とか)。
- 以後、移植先のディスクを /dev/sda、移植元のディスクを /dev/sdb とする。
- 私はこの時に HDD に Debian GNU/Linux をインストールした。
- " fdisk -l /dev/sdb " などで DtoD 領域のサイズを確認した後、移植先の HDD に適当にパーティションを確保して、dd でパーティション内容を丸ごとコピー。
- 移植先のディスクのジオメトリ情報を記録しておく。
- sfdisk -l /dev/sda
- fdisk -l /dev/sda
- 移植先パーティションのブートレコードを取り出す。(移植先パーティションは /dev/sda2)
- dd if=/dev/sda2 of=/tmp/sda2.bin count=1
- file コマンドなどで、先ほど取り出した中身を確認する。ヘッダ数(heads)、開始セクタ位置(hidden sectors)、セクタ数(sectors)などが実際の値ではなく、移植元のドライブの値になっているはずなので、適当なバイナリエディタ等で修正する。
- 編集するアドレスは、dosfstools のソースの mkdosfs.c の msdos_boot_sector の定義が参考になる。
- バイナリの編集には vim + xxd が便利。
- 成功したかどうかは、セーブして file コマンドで確認。 32 MB) , FAT (32 bit), sectors/FAT 8680, reserved3 0x800000, serial number 0xccdee5ea, label: "SERVICEV001"">*1
- ブートレコードを移植先パーティションに書き戻す。
- dd if=/tmp/sda2.bin of=/dev/sda2
- Lenovo からリカバリー修復ディスケット]をダウンロードし、そこからブートする。
- "replace the current mbr" を選ぶ。
- 後は、マシン起動時に ThinkVantage ボタンを押せば Rescue and Recovery メニューに入れるはずなので、システムのリカバリーを選択して Windows 環境を復旧させれば作業終了。
以上の方法は「私の場合、それで出来た」というだけであって、当然ながらあらゆる保証はしないので、参考にする場合は At your own risk で。それに、たぶんもっと簡単な方法がありそうな気がする。
その他、作業中に気づいた点などは以下のとおり。
- DtoD 領域は、パーティション ID こそ特殊なものの、中身は FAT32。
- とは言え、ブートレコードが特殊らしく、普通に DOS や Windows のブートが可能な FAT32 パーティションを作成し、ファイルをコピーする、という方法ではダメなようだ。
なお、今回の作業にあたって、X40 - ThinkPad X60s/X40/X31 メモ の記述がたいへん参考になったことを申し添えておく。