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

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

【#100DaysOfCode】11日目「作りながら学ぶRuby入門」第12章 課題 ~検索機能の追加~

今日やっと、「蔵書管理アプリケーション(テキスト版)」の【検索機能の追加】を終了した。
これでテキスト入力版は完成だっ!

Day 11

・「作りながら学ぶRuby入門」12章 課題

検索機能の追加
point

  • 「登録データと同様に」して、検索条件のインスタンスを作成
  • 検索データを格納しておく変数を用意
  • 検索条件に当てはまるデータを格納するハッシュを作成
    • あとでこれを呼び出して、「これだよっ」と表示
  • 比較結果をフラグに格納
    • 項目数のフラグが立ったら、【検索条件に一致】とみなす
  • 一致したら上記ハッシュを呼ぶ


特に、【フラグの考え方】が最初コード書いたときは抜けてた。
フラグを使えば、「比較結果の判定」も「検索失敗時のループに入る条件」もすんなり書ける。

こういった書き方はC言語っぽいイメージなので、
もっとオブジェクト指向に寄ったうまい書き方ができそう。
以下コード

# 「作りながら学ぶRuby入門」 第12章
# 蔵書管理アプリケーション(テキスト版)に、【検索機能】を追加
require 'date'

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

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

  # Bookinfoクラスのインスタンスの文字列表現を返す
  def to_s
    "#{@title}, #{@author}, #{@page}, #{@pdate}"
  end

  # 蔵書データを書式をつけて出力する操作を追加する
  # 項目の区切り文字を引数に指定することができる
  # 引数を省略した場合は改行を区切り文字にする
  def toFormattedString( sep = "\n" )
    "書籍名: #{@title}#{sep}著者名: #{@author}#{sep}ページ数: #{@page}ページ#{sep}発刊日: #{@pdate}#{sep}"
  end
end

# BookInfoManagerクラスを定義する
class BookInfoManager
  def initialize
    @book_infos = {}
  end

      # 蔵書データをセットアップする
      def setUp
        # 複数冊の蔵書データを登録する
        @book_infos["Ruby2009"] = BookInfo.new(
            "作りながら学ぶRuby入門",
            "久保秋 真",
            418,
            Date.new(2009, 10, 10 )
        )
        @book_infos["Yoko"] = BookInfo.new(
            "プラスチック解体高校 1 新装版 熱い!!",
            "日本橋 ヨヲコ",
            214,
            Date.new(2014, 6, 23)
        )
        @book_infos["Haruki2019"] = BookInfo.new(
            "騎士団長殺し 第1部 顕れるイデア編(上) くっそ面白い〜〜",
            "村上 春樹",
            "不明",
            Date.new( 2019, 3, 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.pdate = 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 searchBookInfos
    # 検索データ1件分のインスタンスを作成する
    book_info = BookInfo.new( "", "", 0, nil )
    # 検索するデータを項目ごとに入力する
    print "\n" 
    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
    if year > 0 && month > 0 && day > 0
      book_info.pdate = Date.new( year, month, day )
    end
            
    # 検索データを格納しておく変数
    search = book_info
    # 該当する蔵書データを格納するハッシュを作る
    match_book = {}
    
    # 蔵書データを1軒ずつ取り出して検索データ(条件)と比較する
    @book_infos.each { |key, info|
      search_flag = 1 # 検索条件と一致しているか
      input_check = 0 # 検索条件が未入力か
      
      if search.title != ""
        search_flag = 0 if search.title =~ /[^"#{info.title}"]/
      else
        input_check += 1
      end
      if search.author != ""
        search_flag = 0 if search.author != info.author
      else
        input_check += 1
      end
      if search.page != 0
        search_flag = 0 if search.page != info.page
      else
        input_check += 1
      end
      if search.pdate != nil
        search_flag = 0 if search.pdate != info.pdate
      else
        input_check += 1
      end
      
      # 比較が全て一致した蔵書データをハッシュに格納する
      # 検索条件が全て未入力の場合は格納しない
      match_book[key] = info if search_flag == 1 && input_check <4
      }
    puts "\n------------------------------"
    if match_book.size > 0
      # 比較が全て一致した蔵書データを表示する 
      match_book.each { |key, info|
        print info.toFormattedString
        puts "\n------------------------------"
      }
    else
      print "条件に一致する蔵書はありません"
      puts "\n------------------------------"
    end 
  end
  
  # 処理の選択と選択後の処理を繰り返す
  def run
    while true
      # 機能選択画面を表示する
      print "
1. 蔵書データの登録
2. 蔵書データの表示
3. 蔵書データの検索
9. 終了
番号を選んでください(1,2,3,9):"
      
      # 文字の入力を待つ
      num = gets.chomp
      case
      when '1' == num
        # 蔵書データの登録
        addBookInfo
      when '2' == num
        # 蔵書データの表示
        listAllBookInfos
      when '3' == num
        # 蔵書データの検索
        searchBookInfos
      when '9' == num
        # アプリケーションの終了
        break;
      else
        # 処理選択待ち画面に戻る
      end
    end
  end

end

# アプリケーションのインスタンスを作る
book_info_manager = BookInfoManager.new

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

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

今日で結構使い回せるようになった感ある。
表示されたとき嬉しいぃ〜〜〜⭐️