Tbpgr Blog

Ruby プログラマ tbpgr(てぃーびー) のブログ

Ruby | CLI | Have a Clear Concise Purpose | 単一目的のシンプルなケースへの変更例

概要

書籍 Build Awesome Command-Line Applications in Ruby2

Have a Clear Concise Purposee | 単一目的のシンプルなケースへの変更例

ツールの単純化例:仕様

※書籍に載っていたものとは全く別のものです。
同じような内容を自分独自の仕様で考えました。

RSpec, RuboCopを実行して両方とも実行成功ならfigletで
「Success」
失敗なら
「Fail in app_name」
と表示します。

ツールの単純化例:コード(修正前)

特に工夫もせず実装した場合。
このままだと、他のコマンドでも利用したい場合に不便です。

require "English"

`rspec`
puts $CHILD_STATUS.to_i
unless $CHILD_STATUS.to_i == 0
  system('figlet Fail in rspec')
  exit
end

`rubocop lib`
unless $CHILD_STATUS.to_i == 0
  system('figlet Fail in rubocop')
  exit
end

system('figlet Success')

ツールの単純化例:コード(修正後)

ツールの単純化例:出力

成功時

$ ruby 1_before.rb
 ____
/ ___| _   _  ___ ___ ___  ___ ___
\___ \| | | |/ __/ __/ _ \/ __/ __|
 ___) | |_| | (_| (_|  __/\__ \__ \
|____/ \__,_|\___\___\___||___/___/

RSpec失敗時

$ ruby 1_before.rb
 _____     _ _   _
|  ___|_ _(_) | (_)_ __    _ __ ___ _ __   ___  ___
| |_ / _` | | | | | '_ \  | '__/ __| '_ \ / _ \/ __|
|  _| (_| | | | | | | | | | |  \__ \ |_) |  __/ (__
|_|  \__,_|_|_| |_|_| |_| |_|  |___/ .__/ \___|\___|
                                   |_|

RuboCop失敗時

$ ruby 1_before.rb
 _____     _ _   _                    _
|  ___|_ _(_) | (_)_ __    _ __ _   _| |__   ___   ___ ___  _ __
| |_ / _` | | | | | '_ \  | '__| | | | '_ \ / _ \ / __/ _ \| '_ \
|  _| (_| | | | | | | | | | |  | |_| | |_) | (_) | (_| (_) | |_) |
|_|  \__,_|_|_| |_|_| |_| |_|   \__,_|_.__/ \___/ \___\___/| .__/
                                                           |_|

ツールの単純化例:コード(修正後)

問題をより抽象化して
コマンド群を実行し、何かエラーがあればfigletで「Fail in app_name」と出力し、
全て成功ならfigletで「Success」と出力するツール
と考えます。

明確で簡単な目的になりました。

require 'English'
require 'open3'

class BulkCommandExecutor
  def initialize
    @commands = ARGV
    check_commands
  end

  def execute
    execute_each_command
    system('figlet Success')
  end

  private
  def check_commands
    fail ArgumentError, 'you must give arguments' if @commands.size == 0
    @commands.each do |command|
      fail ArgumentError, "not exist command '#{command}'" unless command_exists?(command)
    end
  end

  def command_exists?(command)
    out, err, status = Open3.capture3("which #{command}")
    status == 0
  end

  def execute_each_command
    @commands.each do |command|
      unless $CHILD_STATUS.to_i == 0
        system("figlet Fail in #{command}")
        exit
      end
    end
  end
end

begin
  bce = BulkCommandExecutor.new
  bce.execute
rescue => e
  puts e
  exit false
end

ツールの単純化例:出力

成功時、RSpec、Rubocopそれぞれのエラー時の出力は修正前と同じ
新たに引数チェックを追加したのでそのケースを確認

引数無し

$ ruby 1_after.rb
you must give arguments

存在しないコマンドを呼び出し

$ ruby 1_after.rb rspec rubocop_invalid
not exist command 'rubocop_invalid'