HighLine gem で CLI ツールの入出力を支援します #ruby

## <i class="fa fa-code" style="font-size:1em;"></i> 概要
HighLine gem で CLI ツールの入出力を支援します

## <i class="fa fa-cloud-download" style="font-size:1em;"></i> インストール

~~~bash
$ gem install highline
~~~

## <i class="fa fa-flask" style="font-size:1em;"></i> ask
### サンプルコード: 基本
**メッセージ付で標準入力を促す。**

~~~ruby
require 'highline/import'

answer = ask("Basic no default?  ")
puts answer
answer = ask("Basic with default?  ") { |q| q.default = "yes" }
puts answer
~~~

* 動作確認

~~~bash
% ruby ask_basic.rb
# hoge を入力
Basic no default?  hoge
hoge
# 入力しないとデフォルトが適用される
Basic with default?  |yes|
yes
~~~

### サンプルコード: Validation
メッセージ付で標準入力を促す際に、 **Validation** を行う。

~~~ruby
require 'highline/import'

age = ask("float validation?  ", Float)
print age, "\n"
age =ask("float range validation? (0.5-20.4)  ", Float) { |q| q.in = (0.5)..(20.4) }
print age, "\n"
name_age = ask("RegexpValidation?  (Name[Age])  ") { |q| q.validate = /\A\w+\[\d+\]\Z/ }
print name_age, "\n"
~~~

* 動作確認

~~~bash
% ruby ask_validation.rb

# Float の Validation
float validation?  a
You must enter a valid Float.
?  1
1.0

# Float の 範囲 Validation
float range validation? (0.5-20.4)  0.4
Your answer isn't within the expected range (included in 0.5..20.4).
?  0.5
0.5

# 正規表現の Validation
RegexpValidation?  (Name[Age])  hoge
Your answer isn't valid (must match /\A\w+\[\d+\]\Z/).
?  123
Your answer isn't valid (must match /\A\w+\[\d+\]\Z/).
?  hoge[123]
hoge[123]
~~~

### サンプルコード: Confirm
メッセージ付で標準入力を促す際に、 **入力の確認** を行う。

~~~ruby
require 'highline/import'

hoge = ask("hoge?  ") { |q|q.confirm = true }
print hoge, "\n"
~~~

* 動作確認

~~~bash
% ruby ask_confirm.rb
hoge?  hoge
Are you sure?
Please enter "yes" or "no".
Are you sure?  no
?  hige
Are you sure?  yes
hige
~~~

### サンプルコード: Type Conversion
メッセージ付で標準入力より取得した値を **変換する** 。

~~~ruby
require 'highline/import'

puts "# 入力文字列を日付に変換"
puts "Date"
date = ask("date?  ", Date)
print date, "\n"

puts
puts "# パイプ区切りの入力文字列を配列に変換"
list = ask("Pipe?  (Pipe separate list)  ", -> (e) { e.split('|') })
print list, "\n"

puts
puts "# カンマ区切りの入力文字列を Struct に変換"
Person = Struct.new(:name, :age)
person = ask("Struct?  (Struct)  ", -> (e) {
  attributes = e.split(',')
  Person.new(attributes.first, attributes.last)
})
print person, "\n"
~~~

* 動作確認

~~~bash
% ruby ask_type_conversion.rb
# 入力文字列を日付に変換
Date
date?  a
You must enter a valid Date.
?  20150409
2015-04-09

# パイプ区切りの入力文字列を配列に変換
Pipe?  (Pipe separate list)  hoge|hige|hage
["hoge", "hige", "hage"]

# カンマ区切りの入力文字列を Struct に変換
Struct?  (Struct)  tanaka,213
#<struct Person name="tanaka", age="213">
~~~

### サンプルコード: Hide / Mask
メッセージ付で標準入力より取得した値を **非表示にする・マスクする** 。
※パスワードの設定時などに使用

~~~ruby
require 'highline/import'

puts "# 入力文字列を表示しない"
ret = ask("Enter your password:  ") { |q| q.echo = false }
print ret, "\n"

puts
puts "# 入力文字列を * でマスクする"
ask("Enter your password:  ") { |q| q.echo = "*" }
print ret, "\n"
~~~

* 動作確認

~~~bash
% ruby ask_mask.rb
# 入力文字列を表示しない
Enter your password:
hoge

# 入力文字列を * でマスクする
Enter your password:  ****
hoge
~~~

### サンプルコード: erb
メッセージ付で標準入力のメッセージ内に **erb + ANSIカラーシーケンスを使用する** 。

~~~ruby
require 'highline/import'

ret = ask("Use erb <%= color('red', RED)%>")
print ret, "\n"
~~~

* 動作確認

![ask_erb.png](https://qiita-image-store.s3.amazonaws.com/0/43480/b82cb82b-a73c-1444-7374-f33ecdc5f254.png)

## <i class="fa fa-flask" style="font-size:1em;"></i> agree
yes or no の質問に特化した ask のラッパー。

### サンプルコード
~~~ruby
require 'highline/import'

answer = agree("Are you Japanese? (y)es or (n)o")
puts answer
~~~

* 動作確認

~~~bash
% ruby agree.rb
Are you Japanese? (y)es or (n)o
yes
true
% ruby agree.rb
Are you Japanese? (y)es or (n)o
invalid
Please enter "yes" or "no".
Are you Japanese? (y)es or (n)o
no
false
~~~

## <i class="fa fa-flask" style="font-size:1em;"></i> say
標準出力を行う。

### サンプルコード
~~~ruby
require 'highline/import'

say("saysaysay")
~~~

* 動作確認

~~~bash
% ruby say.rb
saysaysay
~~~

## <i class="fa fa-flask" style="font-size:1em;"></i> choose
複数の選択肢から標準入力を促す。

### サンプルコード
~~~ruby
require 'highline/import'

choose do |menu|
  menu.prompt = "尊敬するソフトウェアエンジニアは誰ですか？  "
  menu.choice("ちょまど") { say("シェルスクリプトマガジン買った？") }
  menu.choice("むぎ") { say("さては社畜教徒だな") }
  menu.choices("Matz", "Larry Wall", "増井雄一郎") { say("いいっすね！") }
end
~~~

* 動作確認

~~~
% ruby choose.rb
1. ちょまど
2. むぎ
3. Matz
4. Larry Wall
5. 増井雄一郎
尊敬するソフトウェアエンジニアは誰ですか？  1
シェルスクリプトマガジン買った？
%
% ruby choose.rb
1. ちょまど
2. むぎ
3. Matz
4. Larry Wall
5. 増井雄一郎
尊敬するソフトウェアエンジニアは誰ですか？  2
さては社畜教徒だな
%
% ruby choose.rb
1. ちょまど
2. むぎ
3. Matz
4. Larry Wall
5. 増井雄一郎
尊敬するソフトウェアエンジニアは誰ですか？  3
いいっすね！
~~~

## <i class="fa fa-flask" style="font-size:1em;"></i> list
### サンプルコード
~~~ruby
require 'prime'
require 'highline/import'

primes = Prime.take(10).map(&:to_s)

# リスト出力
say("<%=list(#{primes})%>")

# インライン出力
say("<%=list(#{primes}, :inline, ' and ')%>")
~~~

* 動作確認

~~~bash
% ruby list.rb
2
3
5
7
11
13
17
19
23
29
2, 3, 5, 7, 11, 13, 17, 19, 23 and 29
~~~

## <i class="fa fa-flask" style="font-size:1em;"></i> indent
インデントしながら標準出力する。

### サンプルコード
~~~ruby
require 'highline/import'

t = HighLine.new(STDIN, STDOUT) 
t.indent_level=0
t.say("1")
t.indent_level=1
t.say("2")
t.indent_level=3
t.say("4")
~~~

* 動作確認

~~~bash
% ruby indent.rb
1
   2
         3
~~~

## <i class="fa fa-flask" style="font-size:1em;"></i> newline
改行。

### サンプルコード
~~~ruby
require 'highline/import'

t = HighLine.new(STDIN, STDOUT) 
t.indent_level=0
t.say("1")
t.newline
t.newline
t.say("2")
~~~

* 動作確認

~~~bash
% ruby newline.rb
1


2
~~~

## :books: 外部資料
* <i class="fa fa-external-link" style="font-size:1em;"></i> [highline GitHub](https://github.com/JEG2/highline)
* <i class="fa fa-external-link" style="font-size:1em;"></i> [highline RubyGems](https://rubygems.org/gems/highline)