Tbpgr Blog

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

Ruby | CLI | Have a Clear Concise Purpose | サブセットを持つコマンド

概要

書籍 Build Awesome Command-Line Applications in Ruby2

Have a Clear Concise Purposee | サブセットを持つコマンド

サブセットを持つコマンド例:仕様

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

Personの関連情報を出力するコマンド群を作成する。
Personの情報は persons.txt にcsv形式で保存されている。

firstname,lastname,age
kazuo,tanaka,34
ken,sato,54
ichiro,suzuki,45

Personの情報を取得し、
姓を出力する
名を出力する
姓名を出力する
年齢を出力する
コマンドを作成します。

サブセットを持つコマンド例:コード(修正前)

各コマンドをバラバラに作成してしまった悪い例。
類似処理をバラバラに実装しているためWETな実装になっている。

personal-firstname.rb

require 'csv'

table = CSV.table('./personals.csv')
table.each { |row|puts row[:lastname] }

personal-lastname.rb

require 'csv'

table = CSV.table('./personals.csv')
table.each { |row|puts row[:lastname] }

personal-fullname.rb

require 'csv'

table = CSV.table('./personals.csv')
table.each { |row|puts "#{row[:firstname]} #{row[:lastname]}" }

personal-age.rb

require 'csv'

table = CSV.table('./personals.csv')
table.each { |row|puts row[:age] }

出力

$ ruby personal-firstname.rb
tanaka
sato
suzuki
$ ruby personal-lastname.rb
tanaka
sato
suzuki
$ ruby personal-fullname.rb
kazuo tanaka
ken sato
ichiro suzuki
$ ruby personal-age.rb
34
54
45

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

各コマンドを1箇所にまとめて共通化し、DRYな実装に。
各コマンドはサブコマンドとして実装。

personal.rb

require 'csv'

PERSONALS = './personals.csv'

if ARGV.size == 0
  command = 'firstname'
else
  command = ARGV.shift
end

table = CSV.table(PERSONALS)
case command
when 'firstname'
  table.each { |row|puts row[:firstname] }
when 'lastname'
  table.each { |row|puts row[:lastname] }
when 'fullname'
  table.each { |row|puts "#{row[:firstname]} #{row[:lastname]}" }
when 'age'
  table.each { |row|puts row[:age] }
else
  fail "invalid sub command #{command}"
  exit false
end

出力

$ ruby personal.rb firstname
kazuo
ken
ichiro
$ ruby personal.rb lastname
tanaka
sato
suzuki
$ ruby personal.rb fullname
kazuo tanaka
ken sato
ichiro suzuki
$ ruby personal.rb age
34
54
45