Hitsuji_monのブログ~ 村上春樹のあれ ~

文学好きな組み込み系エンジニア

【#100DaysOfCode】Day13 「作りながら学ぶRuby入門」16章

取り組み方を変えたおかげで、今日はスタコラ進んだ。
ファイルアクセスとかやりだすと、「オブジェクト指向的言語」クッソ便利だなあと実感。

指定・修正・更新 がオブジェクトへのアクセスだけで、済むんだもんあ

Day13

「作りながら学ぶRuby入門」16章 CSV形式の取り扱い

蔵書データのファイル保存

  • CSVファイルで保存 (本記事)
  • PStoreでデータベースとして保存 (別)

このようなやり方がある。
本記事では、csvファイルで保存する 場合のコードを書く。



以下コード
読み込みモジュールのみ (単体では動かない)

# csvファイルから蔵書データを読み込む
class BookInfoManager
    def initialize ( filename )
        # 初期化でcsvファイルを指定する
        @csv_fname = filename
        # 蔵書データのハッシュ
        @book_infos = {}
    end

    #(中略)

    # 蔵書データをセットアップする
    def setUp
        # csvファイルを読み込みモードでオープンする
        open(@csv_fname){ |file|
            # ファイルの1行ずつを取り出して、lineに読み込む
            file.each{ |line|
                # lineからchompで改行を除き、splitでカンマ区切りに分割し、
                # 左辺のそれぞれの項目へ多重代入する
                key, title, page, pdate = line.chomp.split(',')

                # strptimeは、文字列からDateクラスのインスタンスを作成するメソッド
                @book_infos[key] =
                    BookInfo.new(title, author, page.to_i,
                        Date.strptime(pdate))
            }   # 1行ずつの処理の終わり
        } #このブロックを抜けると、ファイルを閉じる
    end

    # (以下略)
end


これを用いて、
csv形式で読み込み・書き込みを追加した蔵書管理アプリケーション】
のコードが以下のようになる。

※このコードにcsvファイルの新規作成機能はない

# 「作りながら学ぶRuby入門」 16章
# csvファイル保存版 の蔵書管理アプリケーション

# 【準備】:新規ファイルの作成昨日はないので、
#         予め「空のcsvファイル」を作っておくこと

require 'date'

class BookInfo
    # BookInfoクラスのインスタンスを初期化する
    def initialize (title, author, page, p_date )
        @title = title
        @author = author
        @page = page
        @p_date = p_date
    end

    # 最初に検討する属性に対するアクセサを提供する
    attr_accessor :title, :author, :page, :p_date

    # BookInfoクラスのインスタンスをcsv形式に変換する
    def to_csv(key)
        "#{key},#{@title},#{author},#{page},#{p_date}\n"
    end
    
    # BookInfoクラスのインスタンスの文字列表現を返す
    def to_s
        "#@title, #@author, #@page, #@p_date"
    end
        
    # 蔵書データを書式をつけて出力する
    def toFormattedString( sep = "\n")
        "書籍名: #{@title}#{sep}, 著者名: #{@author}#{sep}, ページ数: #{@page}ページ#{sep}
         発刊日: #{@p_date}#{sep}"
    end
end

# BookInfoManagerクラスを定義する
class BookInfoManager
    def initialize( filename )
        # 初期化でcsvファイルを指定する
        @csv_fname = filename
        # 蔵書データのハッシュ
        @book_infos = {}
    end

    # 蔵書データをセットアップする
    def setUp
        # csvファイルを読み込みモードでオープンする
        open( @csv_fname ){ |file|
            # ファイルの行を1行ずつ取り出して、lineに読み込む
            file.each { |line|

                # lineからchompで改行を除き、splitでカンマ区切りに分割し、
                # 左辺のそれぞれの項目へ、多重代入する
                key, title, author, page, p_date = line.chomp.split(',')
    
                # 蔵書データ1件分のインスタンスを作成して、ハッシュに登録する
                # strptimeは、文字列からDateクラスのインスタンスを作成するメソッド
                @book_infos [key] =
                    BookInfo.new(title, author, page.to_i, Date.strptime(p_date))

            }       # 1行ずつの処理のおわり
        }           # ファイルを閉じている
    end


    # 蔵書データを登録する
    def addBookInfo
        # 蔵書データ1件分のインスタンスを作成する
        book_info = BookInfo.new("", "", 0, Date.new)
        # 登録するデータを項目ごとに入力する
        print "\n";
        print "キー: "
        key = gets.chomp
        print "書籍名: "
        book_info.title = gets.chomp
        print "著者名: "
        book_info.author = gets.chomp
        print "ページ数: "
        book_info.page = gets.chomp.to_i

        print "発行年: "
        year = gets.chomp.to_i      # 数字を整数に変換するメソッド
        print "発行月: "
        month = gets.chomp.to_i
        print "発行日: "
        day = gets.chomp.to_i
        book_info.p_date = Date.new( year, month, day )

        # 作成した蔵書データの1件分をハッシュに登録する
        @book_infos[key] = book_info
    end

    # 蔵書データの一覧を表示する
    def listAllBookInfos
        puts "\n---------------------------"
        @book_infos.each { |key, info|
            print info.toFormattedString
        puts "\n---------------------------"
        }
    end

    # 蔵書データを全件ファイルに書き込んで保存する
    def saveAllBookInfos
        # csvファイルを書き込みモードでオープンする
        open(@csv_fname, 'w'){ |file|
            @book_infos.each{ |key, info|
                file.print( info.to_csv( key ) )
            }   # 1行ずつの処理のおわり
            puts "\nファイルへ保存しました"
        }   # ファイルを閉じている
    end

    # 処理の選択と選択後の処理を繰り返す
    def run
        while true
            # 機能選択画面を表示する
            print "
1. 蔵書データの登録
2. 蔵書データの表示
8. 蔵書データをファイルへ保存
9. 終了
番号を選んでください (1, 2, 8, 9) :"

            # 文字の入力を待つ
            num = gets.chomp
            case
            when '1' == num
                # 蔵書データの登録
                addBookInfo
            when '2' == num
                # 蔵書データの表示
                listAllBookInfos
            when '8' == num
                # 蔵書データをファイルに保存
                saveAllBookInfos
            when '9' == num
                # アプリケーションの終了
                break;
            else
                # 処理選択待ち画面に戻る
            end
        end
    end


end

################### main ################################
# ここからがアプリケーションを動かす本体

# アプリケーションのインスタンスを作る
# 蔵書データのcsvファイルを指定している
book_info_manager = BookInfoManager.new("book_info.csv")

# BookInfoMnager の蔵書データをセットアップする
book_info_manager.setUp

# BookInfoManagerの処理の選択と、選択後の処理を繰り返す
book_info_manager.run

point

csv にデータを渡す時 to_csvメソッドを定義して使い、渡す
csv から データを受け取る時 strptimeメソッドでDateクラスに変換して受け取る