Tbpgr Blog

Organization Development Engineer tbpgr(てぃーびー) のブログ

Ruby | CLI | Make Configration Easy | Using Configuration File with Command Suites

概要

書籍 Build Awesome Command-Line Applications in Ruby2

Make Configration Easy

詳細

Command Suitesのように複数のコマンドを持つ場合、コマンドごとの引数やオプションの設定が必要です。

サンプル仕様

下記記事のサンプルをベースに設定を追加します。

Ruby | CLI | Be Easy to Use | Ruby | CLI | Thorを利用した使いやすいCommand suitインターフェース
http://d.hatena.ne.jp/tbpg/20140526/1401109675

サンプル設定ファイル

---
:commands:
  :firstname:
    'upcase': false
    'downcase': false
  :lastname:
    'upcase': false
    'downcase': false
  :fullname:
    'upcase': false
    'downcase': false
  :age:
    'pretty_print': false

サンプル読み込みデータ

personals.csv

firstname,lastname,age
Kazuo,Tanaka,34
Ken,Sato,54
Ichiro,Suzuki,45

サンプルコード

require 'csv'
require 'thor'
require 'pp'
require 'yaml'

class PersonViewer < Thor
  CONFIG = 'personal.yml'
  package_name "person_viewer"
  VERSION = "0.0.1"
  PERSONALS = './personals.csv'
  UP_OPTIONS = {type: :boolean, aliases: '-u', desc: "文字を大文字にする"}
  DOWN_OPTIONS = {type: :boolean, aliases: '-d', desc: "文字を小文字にする"}
  class_option :help, type: :boolean, aliases: '-h', desc: 'ヘルプを表示します'
  class_option :version, type: :boolean, desc: 'バージョンを表示します'

  desc "firstname", "名前を表示します"
  option 'upcase', UP_OPTIONS
  option 'downcase', DOWN_OPTIONS
  def firstname
    opt = load_option_settings('firstname', options.to_h, 'upcase', 'downcase')
    print opt, "\n"
    read_csv.each do |row|
      row[:firstname] = row[:firstname].upcase if opt['upcase']
      row[:firstname] = row[:firstname].downcase if opt['downcase']
      puts row[:firstname]
    end
  end

  desc "find by firstname [FIRSTNAME]", "find by firstname [FIRSTNAME]"
  def find_by_firstname(text = '')
    target = read_csv.select { |row|row[:firstname] =~ /#{text}/ }
    pp target
  end

  desc "lastname", "名字を表示します"
  option 'upcase', UP_OPTIONS
  option 'downcase', DOWN_OPTIONS
  def lastname
    opt = load_option_settings('lastname', options.to_h, 'upcase', 'downcase')
    print opt, "\n"
    read_csv.each do |row|
      row[:lastname] = row[:lastname].upcase if opt['upcase']
      row[:lastname] = row[:lastname].downcase if opt['downcase']
      puts row[:lastname]
    end
  end

  desc "fullname", "フルネームを表示します"
  option 'upcase', UP_OPTIONS
  option 'downcase', DOWN_OPTIONS
  def fullname
    opt = load_option_settings('fullname', options.to_h, 'upcase', 'downcase')
    print opt, "\n"
    read_csv.each do |row|
      tmp_fullname = "#{row[:firstname]} #{row[:lastname]}"
      tmp_fullname = tmp_fullname.upcase if opt['upcase']
      tmp_fullname = tmp_fullname.downcase if opt['downcase']
      puts tmp_fullname
    end
  end

  desc "age", "年齢を表示します"
  option :pretty_print, {type: :boolean, aliases: '-p', desc: "人間向けの出力フォーマットにする"}
  def age
    opt = load_option_settings('age', options.to_h, 'pretty_print')
    print opt, "\n"
    if opt['pretty_print']
      read_csv.each { |row|puts "#{row[:firstname]} #{row[:lastname]}#{row[:age]}歳です" }
    else
      read_csv.each { |row|puts row[:age] }
    end
  end

  desc 'version', 'バージョンを表示します'
  def version
    puts VERSION
  end

  def self.banner(task, namespace = false, subcommand = true)
      super
  end

  private
    def read_csv
      CSV.table(PERSONALS)
    end

    def load_option_settings(command, opt, *marge_elements)
      options = YAML.load(File.read(CONFIG))
      setting = options[:commands][command]
      marge_elements.each { |elm|setting[elm] ||= opt[elm] unless opt[elm].nil? }
      setting
    end
end
PersonViewer.start(ARGV)

サンプル出力

大文字変換設定有効

personal.yml

---
:commands:
  'firstname':
    'upcase': true
    'downcase': false
  'lastname':
    'upcase': true
    'downcase': false
  'fullname':
    'upcase': true
    'downcase': false
  'age':
    'pretty_print': false

出力

$ ruby personal.rb fir
DL is deprecated, please use Fiddle
{"upcase"=>true, "downcase"=>false}
KAZUO
KEN
ICHIRO
$ ruby personal.rb fir -u
DL is deprecated, please use Fiddle
{"upcase"=>true, "downcase"=>false}
KAZUO
KEN
ICHIRO
$ ruby personal.rb fir -d
DL is deprecated, please use Fiddle
{"upcase"=>true, "downcase"=>true}
kazuo
ken
ichiro
$ ruby personal.rb last
DL is deprecated, please use Fiddle
{"upcase"=>true, "downcase"=>false}
TANAKA
SATO
SUZUKI
$ ruby personal.rb ful
DL is deprecated, please use Fiddle
{"upcase"=>true, "downcase"=>false}
KAZUO TANAKA
KEN SATO
ICHIRO SUZUKI
年齢の pretty print を有効化

personal.yml

---
:commands:
  'firstname':
    'upcase': false
    'downcase': false
  'lastname':
    'upcase': false
    'downcase': false
  'fullname':
    'upcase': false
    'downcase': false
  'age':
    'pretty_print': true

出力

$ ruby personal.rb a
{"pretty_print"=>true}
Kazuo Tanakaは34歳です
Ken Satoは54歳です
Ichiro Suzukiは45歳です

$ ruby personal.rb a -p
{"pretty_print"=>true}
Kazuo Tanakaは34歳です
Ken Satoは54歳です
Ichiro Suzukiは45歳です