GetoptLong
GetoptLong
옵션(options)과 일반 인자(arguments)를 모두 파싱해 주는 클래스예요.
출처: Ruby 3.3 API
본문
GetoptLong 클래스는 프로그램의 옵션과 일반 인자를 모두 파싱해 줘요. GetoptLong을 쓰면 프로그램의 옵션을 정의할 수 있고, 프로그램은 실행된 명령에 포함된 어떤 옵션이든 잡아내서 응답할 수 있어요.
간단한 예시, 파일 simple.rb:
require 'getoptlong'
options = GetoptLong.new(
['--number', '-n', GetoptLong::REQUIRED_ARGUMENT],
['--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT],
['--help', '-h', GetoptLong::NO_ARGUMENT]
)
옵션에 이미 어느 정도 익숙하다면 완전한 예시(full example)로 바로 넘어가도 좋아요.
옵션 (Options)
GetoptLong 옵션은 다음으로 이뤄져요.
- 문자열 옵션 이름(option name).
- 이름에 대한 0개 이상의 문자열 별칭(alias).
- 옵션 타입(option type).
옵션은 싱글턴 메서드 GetoptLong.new를 호출해서 정의할 수 있는데, 이 메서드는 새 GetoptLong 객체를 돌려줘요. 그다음 GetoptLong#each 같은 다른 메서드를 호출해서 옵션을 처리할 수 있어요.
옵션 이름과 별칭 (Option Name and Aliases)
옵션을 정의하는 배열에서 첫 번째 요소는 문자열 옵션 이름이에요. 종종 이름은 두 개의 하이픈으로 시작하는 '긴(long)' 형태를 취하지요.
옵션 이름은 얼마든지 별칭을 가질 수 있는데, 추가 문자열 요소로 정의돼요.
이름과 각 별칭은 반드시 다음 두 형태 중 하나여야 해요.
- 두 하이픈, 그다음 한 글자 이상의 문자.
- 한 하이픈, 그다음 단일 문자.
파일 aliases.rb:
require 'getoptlong'
options = GetoptLong.new(
['--xxx', '-x', '--aaa', '-a', '-p', GetoptLong::NO_ARGUMENT]
)
options.each do |option, argument|
p [option, argument]
end
옵션은 이름이나 그 별칭 중 아무거나로 참조할 수 있어요. 파싱된 옵션은 항상 이름(별칭이 아니라)을 보고해요.
$ ruby aliases.rb -a -p --xxx --aaa -x
출력:
["--xxx", ""]
["--xxx", ""]
["--xxx", ""]
["--xxx", ""]
["--xxx", ""]
옵션은 이름이나 별칭의 축약형(abbreviation)으로도 참조할 수 있는데, 그 축약형이 옵션들 사이에서 유일할 때만 그래요.
파일 abbrev.rb:
require 'getoptlong'
options = GetoptLong.new(
['--xxx', GetoptLong::NO_ARGUMENT],
['--xyz', GetoptLong::NO_ARGUMENT]
)
options.each do |option, argument|
p [option, argument]
end
명령줄:
$ ruby abbrev.rb --xxx --xx --xyz --xy
출력:
["--xxx", ""]
["--xxx", ""]
["--xyz", ""]
["--xyz", ""]
이 명령줄은 GetoptLong::AmbiguousOption을 발생시켜요.
$ ruby abbrev.rb --x
반복 (Repetition)
옵션은 여러 번 참조할 수 있어요.
$ ruby abbrev.rb --xxx --xyz --xxx --xyz
출력:
["--xxx", ""]
["--xyz", ""]
["--xxx", ""]
["--xyz", ""]
남은 옵션을 인자로 취급하기 (Treating Remaining Options as Arguments)
토큰 -- 뒤 어디든 나타나는 옵션처럼 생긴 토큰은 일반 인자로 취급되고, 옵션으로 처리되지 않아요.
$ ruby abbrev.rb --xxx --xyz -- --xxx --xyz
출력:
["--xxx", ""]
["--xyz", ""]
옵션 타입 (Option Types)
각 옵션 정의는 옵션 타입을 포함하는데, 이 타입은 옵션이 인자를 받는지 여부를 결정해요.
파일 types.rb:
require 'getoptlong'
options = GetoptLong.new(
['--xxx', GetoptLong::REQUIRED_ARGUMENT],
['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
['--zzz', GetoptLong::NO_ARGUMENT]
)
options.each do |option, argument|
p [option, argument]
end
옵션 타입은 옵션 인자(반드시 있어야 하는지, 선택인지, 금지인지)에 관한 것이지, 옵션 자체가 필수인지에 관한 게 아니라는 점을 기억하세요.
필수 인자를 가진 옵션 (Option with Required Argument)
GetoptLong::REQUIRED_ARGUMENT 타입의 옵션은 반드시 그 옵션과 연관된 인자가 뒤따라야 해요.
$ ruby types.rb --xxx foo
출력:
["--xxx", "foo"]
옵션이 마지막이 아니라면, 인자는 옵션 바로 뒤에 오는 모든 것이에요(그 인자가 다른 옵션처럼 보여도).
$ ruby types.rb --xxx --yyy
출력:
["--xxx", "--yyy"]
옵션이 마지막이면 예외가 발생해요.
$ ruby types.rb
# Raises GetoptLong::MissingArgument
선택적 인자를 가진 옵션 (Option with Optional Argument)
GetoptLong::OPTIONAL_ARGUMENT 타입의 옵션은 인자가 뒤따를 수 있는데, 주어지면 그 옵션과 연관돼요.
옵션이 마지막이면 인자가 없어요.
$ ruby types.rb --yyy
출력:
["--yyy", ""]
옵션 뒤에 다른 옵션이 오면 인자가 없어요.
$ ruby types.rb --yyy --zzz
출력:
["--yyy", ""]
["--zzz", ""]
그 외에는 옵션 뒤에 인자가 오는데, 그 인자는 그 옵션과 연관돼요.
$ ruby types.rb --yyy foo
출력:
["--yyy", "foo"]
인자가 없는 옵션 (Option with No Argument)
GetoptLong::NO_ARGUMENT 타입의 옵션은 인자를 받지 않아요.
ruby types.rb --zzz foo
출력:
["--zzz", ""]
ARGV
옵션을 블록과 함께 쓰는 each 메서드 또는 get 메서드로 처리할 수 있어요.
처리하는 동안, 발견된 각 옵션은 그 인자가 있으면 인자와 함께 제거돼요. 처리 후 남은 각 요소는 옵션도 아니고 옵션의 인자도 아니에요.
파일 argv.rb:
require 'getoptlong'
options = GetoptLong.new(
['--xxx', GetoptLong::REQUIRED_ARGUMENT],
['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
['--zzz', GetoptLong::NO_ARGUMENT]
)
puts "Original ARGV: #{ARGV}"
options.each do |option, argument|
p [option, argument]
end
puts "Remaining ARGV: #{ARGV}"
명령줄:
$ ruby argv.rb --xxx Foo --yyy Bar Baz --zzz Bat Bam
출력:
Original ARGV: ["--xxx", "Foo", "--yyy", "Bar", "Baz", "--zzz", "Bat", "Bam"]
["--xxx", "Foo"]
["--yyy", "Bar"]
["--zzz", ""]
Remaining ARGV: ["Baz", "Bat", "Bam"]
순서 (Ordering)
옵션을 해석하는 방식을 제어하는 설정은 세 가지가 있어요.
PERMUTEREQUIRE_ORDERRETURN_IN_ORDER
새 GetoptLong 객체의 초기 설정은 환경 변수 POSIXLY_CORRECT가 정의되어 있으면 REQUIRE_ORDER, 그렇지 않으면 PERMUTE예요.
PERMUTE 순서 (PERMUTE Ordering)
PERMUTE 순서에서는 옵션과 옵션이 아닌 다른 인자들이 어떤 순서로든 어떤 혼합으로든 나타날 수 있어요.
파일 permute.rb:
require 'getoptlong'
options = GetoptLong.new(
['--xxx', GetoptLong::REQUIRED_ARGUMENT],
['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
['--zzz', GetoptLong::NO_ARGUMENT]
)
puts "Original ARGV: #{ARGV}"
options.each do |option, argument|
p [option, argument]
end
puts "Remaining ARGV: #{ARGV}"
명령줄:
$ ruby permute.rb Foo --zzz Bar --xxx Baz --yyy Bat Bam --xxx Bag Bah
출력:
Original ARGV: ["Foo", "--zzz", "Bar", "--xxx", "Baz", "--yyy", "Bat", "Bam", "--xxx", "Bag", "Bah"]
["--zzz", ""]
["--xxx", "Baz"]
["--yyy", "Bat"]
["--xxx", "Bag"]
Remaining ARGV: ["Foo", "Bar", "Bam", "Bah"]
REQUIRE_ORDER 순서 (REQUIRE_ORDER Ordering)
REQUIRE_ORDER 순서에서는 모든 옵션이 모든 비옵션 앞에 와요. 즉, 첫 번째 비옵션 단어 뒤의 각 단어는 (하이픈으로 시작해도) 비옵션 단어로 취급돼요.
파일 require_order.rb:
require 'getoptlong'
options = GetoptLong.new(
['--xxx', GetoptLong::REQUIRED_ARGUMENT],
['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
['--zzz', GetoptLong::NO_ARGUMENT]
)
options.ordering = GetoptLong::REQUIRE_ORDER
puts "Original ARGV: #{ARGV}"
options.each do |option, argument|
p [option, argument]
end
puts "Remaining ARGV: #{ARGV}"
명령줄:
$ ruby require_order.rb --xxx Foo Bar --xxx Baz --yyy Bat -zzz
출력:
Original ARGV: ["--xxx", "Foo", "Bar", "--xxx", "Baz", "--yyy", "Bat", "-zzz"]
["--xxx", "Foo"]
Remaining ARGV: ["Bar", "--xxx", "Baz", "--yyy", "Bat", "-zzz"]
RETURN_IN_ORDER 순서 (RETURN_IN_ORDER Ordering)
RETURN_IN_ORDER 순서에서는 모든 단어가 옵션으로 취급돼요. 하이픈(또는 두 개)로 시작하는 단어는 평소처럼 취급되고, 그렇게 시작하지 않는 단어는 이름이 빈 문자열이고 값이 그 단어인 옵션으로 취급돼요.
파일 return_in_order.rb:
require 'getoptlong'
options = GetoptLong.new(
['--xxx', GetoptLong::REQUIRED_ARGUMENT],
['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
['--zzz', GetoptLong::NO_ARGUMENT]
)
options.ordering = GetoptLong::RETURN_IN_ORDER
puts "Original ARGV: #{ARGV}"
options.each do |option, argument|
p [option, argument]
end
puts "Remaining ARGV: #{ARGV}"
명령줄:
$ ruby return_in_order.rb Foo --xxx Bar Baz --zzz Bat Bam
출력:
Original ARGV: ["Foo", "--xxx", "Bar", "Baz", "--zzz", "Bat", "Bam"]
["", "Foo"]
["--xxx", "Bar"]
["", "Baz"]
["--zzz", ""]
["", "Bat"]
["", "Bam"]
Remaining ARGV: []
완전한 예시 (Full Example)
파일 fibonacci.rb:
require 'getoptlong'
options = GetoptLong.new(
['--number', '-n', GetoptLong::REQUIRED_ARGUMENT],
['--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT],
['--help', '-h', GetoptLong::NO_ARGUMENT]
)
def help(status = 0)
puts <<~HELP
Usage:
-n n, --number n:
Compute Fibonacci number for n.
-v [boolean], --verbose [boolean]:
Show intermediate results; default is 'false'.
-h, --help:
Show this help.
HELP
exit(status)
end
def print_fibonacci (number)
return 0 if number == 0
return 1 if number == 1 or number == 2
i = 0
j = 1
(2..number).each do
k = i + j
i = j
j = k
puts j if @verbose
end
puts j unless @verbose
end
options.each do |option, argument|
case option
when '--number'
@number = argument.to_i
when '--verbose'
@verbose = if argument.empty?
true
elsif argument.match(/true/i)
true
elsif argument.match(/false/i)
false
else
puts '--verbose argument must be true or false'
help(255)
end
when '--help'
help
end
end
unless @number
puts 'Option --number is required.'
help(255)
end
print_fibonacci(@number)
명령줄:
$ ruby fibonacci.rb
출력:
Option --number is required.
Usage:
-n n, --number n:
Compute Fibonacci number for n.
-v [boolean], --verbose [boolean]:
Show intermediate results; default is 'false'.
-h, --help:
Show this help.
명령줄:
$ ruby fibonacci.rb --number
GetoptLong::MissingArgument을 발생시켜요.
fibonacci.rb: option `--number' requires an argument
명령줄:
$ ruby fibonacci.rb --number 6
출력:
8
명령줄:
$ ruby fibonacci.rb --number 6 --verbose
출력:
1
2
3
5
8
명령줄:
$ ruby fibonacci.rb --number 6 --verbose yes
출력:
--verbose argument must be true or false
Usage:
-n n, --number n:
Compute Fibonacci number for n.
-v [boolean], --verbose [boolean]:
Show intermediate results; default is 'false'.
-h, --help:
Show this help.
Constants (상수)
ARGUMENT_FLAGS— 인자 플래그.ORDERINGS— 순서 설정들.STATUS_TERMINATEDVERSION— 버전.
Attributes (속성)
error [R]
옵션 처리가 실패했는지 여부를 돌려줘요.
error? [R]
옵션 처리가 실패했는지 여부를 돌려줘요.
ordering [R]
순서(ordering) 설정을 돌려줘요.
quiet [RW]
quiet 모드를 설정하고 주어진 인자를 돌려줘요.
false나nil이면 오류 메시지가$stdout에 쓰여요.- 그 외에는 오류 메시지가 쓰이지 않아요.
quiet? [RW]
quiet 모드를 설정하고 주어진 인자를 돌려줘요.
false나nil이면 오류 메시지가$stdout에 쓰여요.- 그 외에는 오류 메시지가 쓰이지 않아요.
Public Class Methods
new (*arguments)
주어진 인자들에 기반해 새 GetoptLong 객체를 돌려줘요. "옵션 (Options)"을 참고하세요.
예시:
require 'getoptlong'
options = GetoptLong.new(
['--number', '-n', GetoptLong::REQUIRED_ARGUMENT],
['--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT],
['--help', '-h', GetoptLong::NO_ARGUMENT]
)
다음 경우에 예외를 발생시켜요.
arguments중 하나라도 배열이 아닌 경우.- 어떤 옵션 이름이나 별칭이 문자열이 아닌 경우.
- 어떤 옵션 타입이 유효하지 않은 경우.
Public Instance Methods
each () { |option_name, option_argument| ... }
각 옵션과 함께 주어진 블록을 호출해요. 각 옵션은 다음을 담은 2요소 배열이에요.
- 옵션 이름(별칭이 아니라 이름 자체).
- 옵션 값.
예시:
require 'getoptlong'
options = GetoptLong.new(
['--xxx', '-x', GetoptLong::REQUIRED_ARGUMENT],
['--yyy', '-y', GetoptLong::OPTIONAL_ARGUMENT],
['--zzz', '-z',GetoptLong::NO_ARGUMENT]
)
puts "Original ARGV: #{ARGV}"
options.each do |option, argument|
p [option, argument]
end
puts "Remaining ARGV: #{ARGV}"
명령줄:
ruby each.rb -xxx Foo -x Bar --yyy Baz -y Bat --zzz
출력:
Original ARGV: ["-xxx", "Foo", "-x", "Bar", "--yyy", "Baz", "-y", "Bat", "--zzz"]
["--xxx", "xx"]
["--xxx", "Bar"]
["--yyy", "Baz"]
["--yyy", "Bat"]
["--zzz", ""]
Remaining ARGV: ["Foo"]
each_option ()
each와 동일하게 동작하는 메서드예요.
error_message ()
POSIX에서 정의한 형식의 적절한 오류 메시지를 돌려줘요. 오류가 발생하지 않았다면 nil을 돌려줘요.
get ()
다음 옵션을 다음을 담은 2요소 배열로 돌려줘요.
- 옵션 이름(별칭이 아니라 이름 자체).
- 옵션 값.
더 이상 옵션이 없으면 nil을 돌려줘요.
get_option ()
get과 동일하게 동작하는 메서드예요.
ordering= (ordering)
순서를 설정하고 새 순서를 돌려줘요. "순서 (Ordering)"을 참고하세요.
주어진 순서가 PERMUTE이고 환경 변수 POSIXLY_CORRECT가 정의되어 있으면 순서를 REQUIRE_ORDER로 설정하고, 그렇지 않으면 주어진 ordering으로 설정해요.
options = GetoptLong.new
options.ordering == GetoptLong::PERMUTE # => true
options.ordering = GetoptLong::RETURN_IN_ORDER
options.ordering == GetoptLong::RETURN_IN_ORDER # => true
ENV['POSIXLY_CORRECT'] = 'true'
options.ordering = GetoptLong::PERMUTE
options.ordering == GetoptLong::REQUIRE_ORDER # => true
ordering이 유효하지 않으면 예외를 발생시켜요.
set_options (*arguments)
기존 옵션을 arguments가 주는 옵션으로 교체해요. arguments는 ::new의 인자와 같은 형태예요. self를 돌려줘요.
옵션 처리가 이미 시작되었으면 예외를 발생시켜요.
terminate ()
옵션 처리를 종료해요. 처리가 이미 종료되었으면 nil을, 아니면 self를 돌려줘요.
terminated? ()
옵션 처리가 종료되었으면 true, 아니면 false를 돌려줘요.
Protected Instance Methods
set_error (type, message)
오류를 설정해요 (protected 메서드).