定食屋おろポン

おろしポン酢と青ネギはかけ放題です

基礎から真面目にRubyを勉強する-文字列, 入出力編-

Rubyの開発環境を整えるために一日かけてEmacsを鍛えました。ふひひ。
Ruby関係だと auto-complete, rsense, anything-rurimaあたりを入れました。
引き続きamazon:初めてのRuby4,5章

文字列

さて。Ruby1.9では

puts "hogehoge".length #=> 8
puts "ほげほげ".length #=> 4

と日本語もいい感じに使えるし、あとは「ひたすら使って、リファレンスを読んで、体で覚えろ」って感じですよね。インスタンスメソッドもかなり多いし。メソッドはリファレンスを読めば事足りるので特に書くこともない。

バッククォート文字列

コマンド実行の出力から文字列リテラルを構成できるのね。
これは便利そう。

ruby_version = `ruby -v`
puts ruby_version #=> ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin11.2.0]
puts RUBY_VERSION #=> 1.9.2

ls grep findあたりと組み合わせるとよさそう。
コマンド実行に関しては
exec(command)
system(command)
あたりも見ておかねば。

コマンドライン引数

サンプルコードがシンプルで気に入ったので引用

初めてのRuby 初版 p85
例 5-1

expression = ARGV.join(' + ')
total = ARGV.inject(0){|subtotal, arg| subtotal + arg.to_i}
puts "#{expression} = #{total}"

コマンドラインで渡した引数の総和を出力するプログラムを書きなさい、と言われてこれが1分で書けるくらいになりたい。

# 実行
$ ruby sum.rb 2 3 4

# 出力
2 + 3 + 4 = 9

3行のプログラムだが、流れを追ってみる。
まず、配列ARGVに渡された引数が入る。ARGV[0]にファイル名等が入ったりはしない。渡された引数はARGV[0]から順に格納される。

  • 1行目

Array#join(sep) は配列の要素を、文字列sepを間に挟んで連結するメソッド。
join(sep = $,) -> String
空の配列にjoinを呼び出すとnilが返って来ます。$,は区切り文字が入っている特殊変数で、デフォルト値はnilです。

  • 2行目

Enumerable#inject(init){|result, item| ... } は、たたみこみ演算と呼ばれるものらしい。
要するに、すべての要素に対してひたすら足しあわせたりかけ合わせたり、という演算をしたい時に使うってことだろうな。多分な。
inject(init = self.first) {|result, item| ... } -> object
initがresultの初期値。initが省略されると、渡される最初の要素(self.first)がresultの初期値になる。要素数が0だとnilを返す。
今回はsubtotalに初期値0が与えられ、subtotalにARGVの要素を足しあわせていくことになる。
ARGVには文字列の配列が入っているので、要素にはto_iが呼ばれている、と。

  • 3行目

出力。
なお、今回のサンプルコードを引数なしで実行すると、expressionがnil, totalが0となり、出力は" = 0"となる。
数字以外の引数(例えばa, b, c)を渡すと、arg.to_iで0が返ってくるため、出力は"a + b + c = 0"となる。
ココらへんを厳しくチェックしたいなら、引数の数と中身のチェックを追加すればいい。

if ARGV.count == 0 then error = "no arg" end
expression = ARGV.join(' + ')
total = ARGV.inject(0) do |subtotal, arg|
	if arg !~ /^-?\d+$/ then error = "invalid arg: #{arg}" end
	subtotal + arg.to_i
end
if error then
	puts error
else
	puts "#{expression} = #{total}"
end

試しに書いてみた。例外の発生は6章で扱うので後回し。
ついでに世界のナベアツプログラム(コレ)も書いたった。

(1..ARGV[0].to_i).each do |i|
	if (i % 3 == 0 || i.to_s =~ /3/) then
		puts "アホ\a"
	else
		puts i
	end
	sleep 1
end
puts "オモロー"

正規表現使わずにちゃんと計算したほうが早いんだろうけど、このシンプルさが好きです。

ファイル

ファイルの読み込み等はrubyがよしなにやってくれます。
あとはIO#each_lineなりIO#each_charなりIO#readなりで好きなように料理する、と。あら簡単。
これは使いながら覚えないとなあ。
あと、メソッドがIOクラスとFileクラスのどっちで実装されてるのかわからんから調べるのめんどくさいね。慣れだね。