「ゲームっぽい何かを作りながらRubyを勉強する」シリーズ、第2回は入出力ファイルの保存先についてです。
前回、セーブデータを保存する簡単なプログラムを書いてtest-unitで実行するということを試してみました。
実際に動いてファイルが出力されたのは良いのですが、そのままではファイルの出力先がプログラムの実行時のカレントディレクトリ、という残念な感じでした。
今回は、そのファイルの出力先問題を解決すべく、出力ファイルはすべてプロジェクト直下のdata
ディレクトりに保存されるようプログラムを修正してみます。
シリーズ一覧
- ゲームっぽい何かを作りながらRubyを勉強する その1 〜ディレクトリ構成とかtest-unitとかRakeとか〜
- ゲームっぽい何かを作りながらRubyを勉強する その2 〜ファイル保存〜
本文
まず、常にdata
ディレクトリにファイルを保存するためにはどのような要素が必要かを考えてみます。
- プログラム実行時のカレントディレクトリを取得する
- カレントディレクトリと
data
ディレクトリ名、ファイル名を連結する。
これだけですね。
では一つずつ見ていきます。
プログラム実行時のカレントディレクトリを取得する
まず、このプロジェクトの実行は必ずプロジェクト直下と決めておきます。
これによって、プログラム実行時のカレントディレクトリを固定し、そのパスをプログラム中で取得することで、どのプログラムファイルから実行されても同じ場所にファイルを保存できるようにします。
プログラム中でカレントディレクトリを取得するには以下のメソッドを使います。
Dir.pwd
念のため、このメソッドで実際に取得できる文字列がどのようなものか、irb
を使って確認します。
$ pwd
/usr/local/workdir/ruby/mygame
$ irb
irb(main):001:0>p Dir.pwd
"/usr/local/workdir/ruby/mygame"
=> "/usr/local/workdir/ruby/mygame"
Bashでpwd
コマンドを実行した時と同じ文字列が取得できますね。
参考
Ruby 2.3.0 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Dirクラス
カレントディレクトリとdata
ディレクトリ名、ファイル名を連結する。
さて、Dir.pwd
でカレントディレクトリが取得できたら、あとはdata
とファイル名を連結していくだけなのですが、この時以下のように単純に+
で連結するのはイケていないです。
Dir.pwd + '/data/' + file_name
パスを区切るための/
がそれぞれの変数についているのかどうか、そもそも区切り文字は/
でいいのか(Windowsでは¥
)など、いろいろと考慮しなければならない点が出てくるからです。考慮しなければならない、ということは懸念点も増え、実装量も増え、バグが生まれる原因になってしまいます。
こんな時、JavaのPaths
クラスのように、大体の言語は「ファイルパスを組み立てる」ためのAPIが用意されています。RubyではPathname
というクラスが使えます。
というわけで、先ほどの例をPathname
を使って書き直したのがこちらです。
Pathname.new(Dir.pwd).join(DATA_DIR, file_name).to_s
/
も区切り文字も全く使わず、配列だけでパスをすべて表せていますね。これなら環境依存のバグも少なそうです。
参考
Ruby 2.3.0 リファレンスマニュアル > ライブラリ一覧 > pathnameライブラリ > Pathnameクラス
結果
以上で、「セーブファイルは常にdata
ディレクトリ内に保存する」という仕組みを実現することができました。
修正後のsave_manager.rb
は以下になります。
require 'pathname'
module MyGame
# module for managing game data
module SaveManager
DATA_DIR = 'data'
# save given data into given file at data/
def self.save(file_name, data)
File.open(Pathname.new(Dir.pwd).join(DATA_DIR, file_name).to_s, 'w') do |f|
f.puts(data)
end
end
end
end
まとめ
今回はファイル入出力時のパス指定について調べてみました。
言語に関係なく、ファイルの入出力は実行環境によって結果が変わらないようにするのが重要かと思います。文字列の加算でも動いてしまいますが、マシンのOSが違う可能性のある他の人の環境でもちゃんと動くことを意識することで、より安定したプログラムになるのではないかと思います。
なお、この記事は、以下の時点までの変更を元に書いています。