Ruby の "Hello, world!"

院試が終わってから Yugui 著 『初めての Ruby』 (ISBN: 978-4-87311-367-8) を読んで Ruby の勉強をしてたんですが、ようやく本日読了しました! そんなわけで Ruby について初心者ながらにちょこちょこ書いてみようと思います。

とりあえず今日は標準入出力やらエンコーディングやらについて。

標準入出力

標準入力を表すオブジェクトは、組み込み変数 $stdin に格納されています。 その初期値は STDIN です。 同様に、標準出力について $stdoutSTDOUT標準エラー出力について $stderrSTDERR があります。 STDIN、STDOUT、STDERR は IO クラスに属するオブジェクトです。

$stdout や $stdin のメソッドを使用して標準出力へ出力したり、標準入力から読み込んだりすることができます。 $stderr はエラーメッセージの出力に使用されます。

# 出力
$stdout << "C++ 的な表記法" << "\n"
$stdout.write( "write メソッドを使用\n" )
# gets メソッドを使用して標準入力から読み込み
str = $stdin.gets()
# 入力された値を表示
$stdout << str

また、組み込み関数 putsprintp などは $stdout の write メソッドを呼び出して、標準出力に文字列を出力します。 同様に組み込み関数 gets は $stdin の gets メソッドを呼び出し、標準入力から文字列を得ます。 一般的には $stdout や $stdin を直接操作するのではなく、puts や gets などの組み込み関数を用い、標準入出力を間接的に使用することが多いようです。

ソースコードエンコーディング (マジックコメント)

Ruby 1.9 では文字列をバイト列としてではなく 「文字の列」 として扱えるようになりました。 例えば String オブジェクトの length メソッドは 「バイト数」 ではなく 「文字数」 を返します。 また、String オブジェクトは文字列のエンコーディングを知っています。

そのため、ソースコード内の文字列のエンコーディングが何であるかを Ruby 処理系に教えてやる必要があります。 そのための方法としてマジックコメントが使用されます。 次のようなコメント文をソースコード冒頭 (Shebang があるならその次の行) に書きます。

# -*- coding: utf-8 -*-
上の例の場合、Ruby 処理系はソースコード内の文字列のエンコーディングUTF-8 だとみなして処理します。 以下のように書いても良いです。
# vim:fileencoding=UTF-8

外部エンコーディングと内部エンコーディング

Ruby 1.9 では、IO クラスが外部とデータのやり取りする際に文字エンコーディングを考慮するようになりました。 これは Perl IO レイヤと似ています。

「外部エンコーディング」 というものを指定しておけば、IO クラスが外部に文字列データを出力する際に 「外部エンコーディング」 で指定されたエンコーディングに変換して出力します。 外部からデータを受け取る際も同様で、受け取ったバイト列を 「外部エンコーディング」 で指定されているエンコードされた文字列だと解釈します。

また 「内部エンコーディング」 というものもあります。 内部エンコーディングが指定されていない場合は、外部から読み込んだデータは 「外部エンコーディング」 で指定されたエンコーディングの文字列として Ruby の内部に持ち込まれます。 しかし、「内部エンコーディング」 が指定されていれば、そのエンコーディングに自動的に変換されます。

組み込み定数 STDOUT なども IO オブジェクトなので、外部エンコーディングや内部エンコーディングを指定することができます。 ソースコードUTF-8 で書いているのに、システムのエンコーディングShift_JIS だったりすると、そのままでは文字化けしてしまいます。 そのような問題を起こさないために STDOUT の外部エンコーディングをシステムのエンコーディングにしておくと良いでしょう。 外部エンコーディングおよび内部エンコーディングの指定には IO#set_encoding メソッドを使用します。

# 外部エンコーディングをシステムのエンコーディングに, 内部エンコーディングを UTF-8 に変更
STDOUT.set_encoding( Encoding.locale_charmap, "UTF-8" )

サンプルコード

というわけで今日の内容をまとめたサンプルコード。

#! /usr/bin/ruby1.9
# -*- coding: utf-8 -*- # ソースコードのエンコーディング指定

# 標準入出力の外部エンコーディングをシステムのエンコーディングに変更
# 内部エンコーディングを UTF-8 に変更
STDIN .set_encoding( Encoding.locale_charmap, "UTF-8" )
STDOUT.set_encoding( Encoding.locale_charmap, "UTF-8" )
STDERR.set_encoding( Encoding.locale_charmap, "UTF-8" )

# 引数の文字列を標準出力に出力し, 改行する
puts "Hello, world!"
# 引数の文字列を標準出力に出力する
print "何か入力してください: "
# 標準入力から文字列を得て変数 str に代入する
str = gets().chomp() # gets で標準入力から文字列を得て, chomp で改行コードを削除
# 入力された文字列とそのエンコーディング (UTF-8) を表示
print "入力された文字列: ", str, ", エンコーディング: ", str.encoding, "\n"