見出し画像

ポンコツ・キャンプ-シンプルなコマンド入力プログラム

世間では電子帳簿保存法の対応が迫られ、当社でも対応せねばと巷のアプリを検討することになりました。案外、使い易そうなアプリもあったのですが、全てサブスクリプション。。。毎年、永久に金をむしり取られる仕組みのようです。数年後、データが溜った後に料金の改定があったらどうなるのでしょう?悲惨な結果しか待っていないような気がします。

仕方なく自作することにしました。
幸いにも中々良いものが出来ました。
現在、稼働中です。
DOS画面上で、コマンド入力で動くソフトです。
Rubyで作ったら、とてもすっきりと仕上がりましたので、コマンドラインで駆動する部分を抜き出して、アップします。
ベテランの方からすれば、あっそ。ぐらいの物ですので、初心者向けの内容だと思って下さい。

3つのファイルで構成されています。
単純な作りになっていますが、意外に使い出があります。


main.rb

# frozen_string_literal: true

require_relative 'command_parser'
require_relative 'commander'

# -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# -+-+-+ Main routine                 -+-+-+
# -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

commander = Commander.new
parser    = CommandParser.new(commander)

until parser.exit_command?
  print "\n\ninput command => "
  parser.parse(gets.chomp)
end

command_parser.rb

# frozen_string_literal: true

class CommandParser
  def initialize(commander)
    @commander = commander
    @command = nil
  end

  def parse(demand)
    command, _, options = demand.strip.partition(' ')
    @command = command.empty? ? Commander::ENTER : command.downcase.to_sym
    options = options.split(',').map(&:strip)

    return print "\nunknow command: #{@command}" if @commander.incorrect?(@command)

    @commander.method(@command).call(options)
  end

  def exit_command?
    @commander.exit_command?(@command)
  end
end

commander.rb

# frozen_string_literal: true

class Commander
  ENTER = :enter

  def initialize
    @help_message = [
      "\n --- exit          - 保存して、終了",
      "\n --- quit          - 終了",
      "\n --- save          - 保存",
      "\n",
      "\n --- help          - help表示",
      "\n --- <enter>       - nextと同じ",
      "\n",
      "\n --- top           - 最初のページを表示する",
      "\n --- bottom        - 最後のページを表示する",
      "\n --- next [n]      - 次のページを表示するか、nページ先のページを表示",
      "\n --- previous [n]  - 前のページを表示するか、nページ前のページを表示",
      "\n --- page n        - ページn番を表示する",
      "\n",
      "\n --- select [kind], [price], [customer], [since date], [before date]",
      "\n                   - 表示を絞り込む",
      "\n                     kind: 文書の種類",
      "\n                     price: 価格",
      "\n                     customer: 顧客名",
      "\n                     since date: yyyy-mm-dd以降",
      "\n                     before date: yyyy-mm-dd以前"
    ]
    @command_list = nil
  end

  def command_list
    @command_list ||= @help_message.map { |line| /--- <*([a-z_]+)>* /.match(line).to_a[1] }
                                   .compact
                                   .map(&:to_sym)
  end
  private :command_list

  def exit_command?(command)
    command_list[0, 2].include?(command)
  end

  def incorrect?(command)
    !command_list.include?(command)
  end

  def exit(_)
    p 'exit'
  end

  def quit(_)
    p 'quit'
  end

  def save(_)
    p 'save'
  end

  def help(_)
    print @help_message.join
  end

  def enter(_)
    self.next('1')
  end

  def top(_)
    page('1')
  end

  def bottom(_)
    p 'bottom'
    p '何等かの方法で、max_page_sizeを取得して、page(max_page_size)で飛ばす'
  end

  def next(n)
    n, = n
    p 'next'
    p n
  end

  def previous(n)
    n, = n
    p 'previous'
    p n
  end

  def page(n)
    p 'page'
    n, = n
    p n
  end

  def select(options)
    kind, price, customer, since_date, before_date = options
    p 'select'
    p kind
    p price
    p customer
    p since_date
    p before_date
  end
end

簡単な説明

main.rb
... 終了コマンドが発行されるまで、コマンドを実行しながら、
グルグル回り続けさせています。

:exit, :quitに出会うまで、回り続けます。

command_parser.rb
... 入力されたコマンドを解析して、Commanderに投げています。

parseメソッド内で、commandとoptionsに分離しています。commandは、シンボル化し、optionsは、配列に分解しています。 @command.command_listに無いcommandはタイポとして表示されます。 チェックを通過したら、@commanderにメッセージを送ります。 @commander.method(@command).call(options)のお蔭で、膨大なcase文を 管理しなくても良くなるのでこの表記は便利だと思われます。

commander.rb
... 個々のコマンドを実行します。

@help_messageは、他の記述の仕方もあるのでしょうが、個人的な好みで 配列に納めています。@command_listは、全てのコマンドのリストです。
@help_messageからコマンドを抽出して、commanderをCommandParserに送っています。これによって、コマンドの管理はCommnanderのメソッドと@help_message内の記述のみになり、コマンド拡張などの場合のメンテナンスの軽減を図っています。

実行

3つのファイルを同じディレクトリにいれて、ruby main.rbで動きます。
まずは、helpとタイプしてみましょう。
登録してあるコマンドを色々試してみたり、間違ったコマンドも試してみて下さい。

ではでは。


この記事が気に入ったらサポートをしてみませんか?