OptionParser 클래스
OptionParser 클래스
명령줄 옵션 분석을 위한 클래스예요. GetoptLong보다 훨씬 진보했으면서도 쓰기 더 쉽고, 더 Ruby스러운 해결책이에요.
출처: Ruby 3.3 API
본문
OptionParser
OptionParser가 처음인가요?
Tutorial을 보세요.
소개 (Introduction)
OptionParser는 명령줄 옵션 분석을 위한 클래스예요. GetoptLong보다 훨씬 진보했으면서도 쓰기 더 쉽고, 더 Ruby스러운 해결책이에요.
기능 (Features)
- 인자 명세와 그걸 처리하는 코드를 같은 곳에 써요.
- 옵션 요약을 출력할 수 있어요. 그 문자열을 따로 유지할 필요가 없죠.
- 선택 인자와 필수 인자를 우아하게 지정할 수 있어요.
- 인자를 지정된 클래스로 자동 변환할 수 있어요.
- 인자를 특정 집합으로 제한할 수 있어요.
이 모든 기능은 아래 예시에서 보여줘요. 전체 문서는 make_switch를 보세요.
최소 예시 (Minimal example)
require 'optparse'
options = {}
OptionParser.new do |parser|
parser.banner = "Usage: example.rb [options]"
parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
options[:verbose] = v
end
end.parse!
p options
p ARGV
도움말 생성 (Generating Help)
OptionParser는 작성한 명령의 도움말을 자동으로 생성하는 데 쓸 수 있어요.
require 'optparse'
Options = Struct.new(:name)
class Parser
def self.parse(options)
args = Options.new("world")
opt_parser = OptionParser.new do |parser|
parser.banner = "Usage: example.rb [options]"
parser.on("-nNAME", "--name=NAME", "Name to say hello to") do |n|
args.name = n
end
parser.on("-h", "--help", "Prints this help") do
puts parser
exit
end
end
opt_parser.parse!(options)
return args
end
end
options = Parser.parse %w[--help]
#=>
# Usage: example.rb [options]
# -n, --name=NAME Name to say hello to
# -h, --help Prints this help
필수 인자 (Required Arguments)
인자를 요구하는 옵션의 경우, 옵션 명세 문자열에 대문자로 된 옵션 이름을 포함할 수 있어요. 옵션이 필수 인자 없이 사용되면 예외가 던져져요.
require 'optparse'
options = {}
OptionParser.new do |parser|
parser.on("-r", "--require LIBRARY",
"Require the LIBRARY before executing your script") do |lib|
puts "You required #{lib}!"
end
end.parse!
사용:
$ ruby optparse-test.rb -r
optparse-test.rb:9:in `<main>': missing argument: -r (OptionParser::MissingArgument)
$ ruby optparse-test.rb -r my-library
You required my-library!
타입 강제 변환 (Type Coercion)
OptionParser는 명령줄 인자를 객체로 강제 변환(coerce)하는 기능을 지원해요.
OptionParser에는 몇 가지 바로 쓸 수 있는 타입 강제 변환이 있어요:
- Date –
Date.parse가 받는 모든 것(optparse/date를 require해야 해요) - DateTime –
DateTime.parse가 받는 모든 것(optparse/date를 require해야 해요) - Time –
Time.httpdate또는Time.parse가 받는 모든 것(optparse/time을 require해야 해요) - URI –
URI.parse가 받는 모든 것(optparse/uri를 require해야 해요) - Shellwords –
Shellwords.shellwords가 받는 모든 것(optparse/shellwords를 require해야 해요) - String – 비어 있지 않은 모든 문자열
- Integer – 모든 정수. 8진수를 변환해요. (예: 124, -3, 040)
- Float – 모든 실수. (예: 10, 3.14, -100E+13)
- Numeric – 모든 정수, 실수 또는 유리수 (1, 3.4, 1/3)
- DecimalInteger –
Integer와 같지만 8진수 형식이 없어요. - OctalInteger –
Integer와 같지만 10진수 형식이 없어요. - DecimalNumeric – 10진 정수 또는 실수.
- TrueClass –
'+, yes, true, -, no, false'를 받아들이고 기본값은true - FalseClass –
TrueClass와 같지만 기본값은false - Array –
,로 구분된 문자열 (예: 1,2,3) - Regexp – 정규표현식. 옵션도 포함해요.
자체 강제 변환을 추가할 수도 있는데, 아래에서 다룰게요.
내장 변환 사용 (Using Built-in Conversions)
예시로 내장 Time 변환을 사용해 볼게요. 다른 내장 변환도 같은 방식으로 동작해요. OptionParser는 인자를 Time으로 파싱하려 시도해요. 성공하면 그 시간이 핸들러 블록에 전달되고, 아니면 예외가 던져져요.
require 'optparse'
require 'optparse/time'
OptionParser.new do |parser|
parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
p time
end
end.parse!
사용:
$ ruby optparse-test.rb -t nonsense
... invalid argument: -t nonsense (OptionParser::InvalidArgument)
$ ruby optparse-test.rb -t 10-11-12
2010-11-12 00:00:00 -0500
$ ruby optparse-test.rb -t 9:30
2014-08-13 09:30:00 -0400
커스텀 변환 만들기 (Creating Custom Conversions)
OptionParser의 accept 메서드로 변환기를 만들 수 있어요. 클래스가 지정될 때마다 호출할 변환 블록을 지정해요. 아래 예시는 on 핸들러가 받기 전에 User 객체를 가져오는 데 써요.
require 'optparse'
User = Struct.new(:id, :name)
def find_user id
not_found = ->{ raise "No User Found for id #{id}" }
[ User.new(1, "Sam"),
User.new(2, "Gandalf") ].find(not_found) do |u|
u.id == id
end
end
op = OptionParser.new
op.accept(User) do |user_id|
find_user user_id.to_i
end
op.on("--user ID", User) do |user|
puts user
end
op.parse!
사용:
$ ruby optparse-test.rb --user 1
#<struct User id=1, name="Sam">
$ ruby optparse-test.rb --user 2
#<struct User id=2, name="Gandalf">
$ ruby optparse-test.rb --user 3
optparse-test.rb:15:in `block in find_user': No User Found for id 3 (RuntimeError)
옵션을 Hash에 저장 (Store options to a Hash)
order, parse 등의 메서드의 into 옵션은 명령줄 옵션을 Hash에 저장해요.
require 'optparse'
options = {}
OptionParser.new do |parser|
parser.on('-a')
parser.on('-b NUM', Integer)
parser.on('-v', '--verbose')
end.parse!(into: options)
p options
사용:
$ ruby optparse-test.rb -a
{:a=>true}
$ ruby optparse-test.rb -a -v
{:a=>true, :verbose=>true}
$ ruby optparse-test.rb -a -b 100
{:a=>true, :b=>100}
완전한 예시 (Complete example)
다음 예시는 완전한 Ruby 프로그램이에요. 직접 실행해 다양한 옵션 지정의 효과를 볼 수 있어요. optparse의 기능을 배우는 가장 좋은 방법일 거예요.
require 'optparse'
require 'optparse/time'
require 'ostruct'
require 'pp'
class OptparseExample
Version = '1.0.0'
CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
class ScriptOptions
attr_accessor :library, :inplace, :encoding, :transfer_type,
:verbose, :extension, :delay, :time, :record_separator,
:list
def initialize
self.library = []
self.inplace = false
self.encoding = "utf8"
self.transfer_type = :auto
self.verbose = false
end
def define_options(parser)
parser.banner = "Usage: example.rb [options]"
parser.separator ""
parser.separator "Specific options:"
# add additional options
perform_inplace_option(parser)
delay_execution_option(parser)
execute_at_time_option(parser)
specify_record_separator_option(parser)
list_example_option(parser)
specify_encoding_option(parser)
optional_option_argument_with_keyword_completion_option(parser)
boolean_verbose_option(parser)
parser.separator ""
parser.separator "Common options:"
# No argument, shows at tail. This will print an options summary.
# Try it and see!
parser.on_tail("-h", "--help", "Show this message") do
puts parser
exit
end
# Another typical switch to print the version.
parser.on_tail("--version", "Show version") do
puts Version
exit
end
end
def perform_inplace_option(parser)
# Specifies an optional option argument
parser.on("-i", "--inplace [EXTENSION]",
"Edit ARGV files in place",
"(make backup if EXTENSION supplied)") do |ext|
self.inplace = true
self.extension = ext || ''
self.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot.
end
end
def delay_execution_option(parser)
# Cast 'delay' argument to a Float.
parser.on("--delay N", Float, "Delay N seconds before executing") do |n|
self.delay = n
end
end
def execute_at_time_option(parser)
# Cast 'time' argument to a Time object.
parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
self.time = time
end
end
def specify_record_separator_option(parser)
# Cast to octal integer.
parser.on("-F", "--irs [OCTAL]", OptionParser::OctalInteger,
"Specify record separator (default \0)") do |rs|
self.record_separator = rs
end
end
def list_example_option(parser)
# List of arguments.
parser.on("--list x,y,z", Array, "Example 'list' of arguments") do |list|
self.list = list
end
end
def specify_encoding_option(parser)
# Keyword completion. We are specifying a specific set of arguments (CODES
# and CODE_ALIASES - notice the latter is a Hash), and the user may provide
# the shortest unambiguous text.
code_list = (CODE_ALIASES.keys + CODES).join(', ')
parser.on("--code CODE", CODES, CODE_ALIASES, "Select encoding",
"(#{code_list})") do |encoding|
self.encoding = encoding
end
end
def optional_option_argument_with_keyword_completion_option(parser)
# Optional '--type' option argument with keyword completion.
parser.on("--type [TYPE]", [:text, :binary, :auto],
"Select transfer type (text, binary, auto)") do |t|
self.transfer_type = t
end
end
def boolean_verbose_option(parser)
# Boolean switch.
parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
self.verbose = v
end
end
end
#
# Return a structure describing the options.
#
def parse(args)
# The options specified on the command line will be collected in
# *options*.
@options = ScriptOptions.new
@args = OptionParser.new do |parser|
@options.define_options(parser)
parser.parse!(args)
end
@options
end
attr_reader :parser, :options
end # class OptparseExample
example = OptparseExample.new
options = example.parse(ARGV)
pp options # example.options
pp ARGV
셸 완성 (Shell Completion)
현대적인 셸(예: bash, zsh 등)에서는 명령줄 옵션에 셸 완성(shell completion)을 쓸 수 있어요.
추가 문서 (Further documentation)
위 예시와 함께 제공되는 Tutorial이면 이 클래스를 쓰는 법을 배우기에 충분해요. 질문이 있으면 bugs.ruby-lang.org에 티켓을 올려 주세요.
상수 (Constants)
- DecimalInteger
Attributes
banner
요약 앞에 오는 헤딩 배너예요.
default_argv
기본적으로 파싱할 문자열들.
program_name
에러 메시지와 기본 배너에 출력될 프로그램 이름. 기본값은 $0이에요.
raise_unknown
알 수 없는 옵션에서 raise할지 여부.
release
릴리스 코드.
require_exact
옵션이 정확히 일치해야 하는지 여부(축약된 긴 옵션을 짧은 옵션으로 제공하는 것을 허용하지 않음).
set_banner
요약 앞에 오는 헤딩 배너예요.
set_program_name
에러 메시지와 기본 배너에 출력될 프로그램 이름. 기본값은 $0이에요.
set_summary_indent
요약의 들여쓰기. String이어야 해요(+ String 메서드가 있거나).
set_summary_width
요약의 옵션 목록 부분 너비. Numeric이어야 해요.
summary_indent
요약의 들여쓰기. String이어야 해요(+ String 메서드가 있거나).
summary_width
요약의 옵션 목록 부분 너비. Numeric이어야 해요.
version
버전.
Public Class Methods
accept (*args, &blk)
accept 참고.
each_const (path, base = ::Object)
상수들을 반복해요.
getopts (*args, symbolize_names: false)
getopts 참고.
inc (arg, default = nil)
arg에 따라 default의 증가된 값을 반환해요.
new (banner = nil, width = 32, indent = ' ' * 4) { |self| ... }
인스턴스를 초기화하고, 블록과 함께 호출되면 자기 자신을 넘겨줘요. banner
reject (*args, &blk)
reject 참고.
search_const (klass, name) { |klass, cname, const| ... }
상수를 탐색해요.
show_version (*pkgs)
버전을 보여 줘요.
terminate (arg = nil)
옵션 파싱을 종료해요.
top ()
옵션 목록의 대상.
with (*args, &block)
새 인스턴스를 초기화하고 인스턴스 문맥에서 선택 블록을 평가해요. 인자 args는 new로 전달되며, 파라미터 설명은 거길 보세요.
이 메서드는 deprecated예요. 동작이 옛 new 메서드와 대응해요.
Public Instance Methods
abort (mesg = $!)
메시지를 출력하고 상태로 종료해요.
accept (*args, &blk)
지정된 클래스 t를 받아들이도록 지시해요. 인자 문자열은 그걸 원하는 클래스로 변환해야 하는 블록에 전달돼요. t
accept(t, pat, &block)
additional_message (typ, opt)
추가 정보를 반환해요.
banner ()
요약 앞에 오는 헤딩 배너.
base ()
on_tail의 대상.
candidate (word)
후보를 구해요.
def_head_option / def_option / def_tail_option
옵션 정의 헬퍼.
define(*params, &block)
주어진 파라미터 params로 옵션을 만들어요. Parameters for New Options 참고.
블록이 주어지면(조건부) 생성된 옵션의 핸들러예요. 명령줄 파싱 중 옵션이 만나지면, 블록은 그 옵션에 주어진 인자(있을 때)와 함께 호출돼요. Option Handlers 참고.
define_by_keywords(options, method, **params)
주어진 파라미터 params로 옵션을 만들어요. Parameters for New Options 참고.
블록이 주어지면(조건부) 생성된 옵션의 핸들러예요. 옵션이 만나지면 주어진 인자와 함께 호출돼요. Option Handlers 참고.
define_head(*params, &block) / define_tail(*params, &block)
주어진 파라미터 params로 옵션을 만들어요. (define과 동일; on_head/on_tail처럼 요약의 머리/꼬리에 추가돼요)
environment (env = File.basename($0, '.*'))
환경변수 env(또는 그 대문자)를 셸처럼 분할해 파싱해요.
env는 기본적으로 프로그램의 basename이에요.
getopts (*args, symbolize_names: false)
getopts.rb용 래퍼 메서드예요.
params = ARGV.getopts("ab:", "foo", "bar:", "zot:Z;zot option")
# params["a"] = true # -a
# params["b"] = "1" # -b1
# params["foo"] = "1" # --foo
# params["bar"] = "x" # --bar x
# params["zot"] = "z" # --zot Z
옵션 symbolize_names(boolean)은 반환되는 Hash 키가 Symbol이어야 하는지 지정해요. 기본값은 false(String 사용)예요.
params = ARGV.getopts("ab:", "foo", "bar:", "zot:Z;zot option", symbolize_names: true)
# params[:a] = true # -a
# params[:b] = "1" # -b1
# params[:foo] = "1" # --foo
# params[:bar] = "x" # --bar x
# params[:zot] = "z" # --zot Z
help ()
옵션 요약 문자열을 반환해요.
inc (*args)
증가된 값을 반환해요.
load (filename = nil, into: nil)
filename처럼 파일에서 옵션을 불러와요. 파일이 없으면 아무것도 하지 않아요. 성공적으로 불러왔는지 반환해요.
filename은 기본적으로 ~/.options 디렉터리에서 확장자 없는 프로그램 basename, 그다음 XDG와 Haiku 표준 위치 아래에서 .options 접미사를 가진 basename이에요.
선택 into 키워드 인자는 parse 메서드에서 받는 것과 정확히 같이 동작해요.
make_switch(params, block = nil)
주어진 파라미터 params로 옵션을 만들어요. Parameters for New Options 참고.
블록이 주어지면(조건부) 생성된 옵션의 핸들러예요. Option Handlers 참고.
new () { |self| ... }
새 List를 푸시해요.
on(*params, &block)
주어진 파라미터 params로 옵션을 만들어요. Parameters for New Options 참고.
블록이 주어지면(조건부) 생성된 옵션의 핸들러예요. Option Handlers 참고.
on_head(*params, &block)
on과 같지만 새 옵션이 요약의 머리에 추가돼요.
on_tail(*params, &block)
on과 같지만 새 옵션이 요약의 꼬리에 추가돼요.
order (*argv, into: nil, &nonopt)
명령줄 인자 argv를 순서대로 파싱해요. 블록이 주어지면 각 비옵션 인자를 넘겨줘요. 선택 into 키워드 인자가 주어지면 파싱된 옵션 값들이 거기에 []= 메서드로 저장돼요(Hash, OpenStruct, 또는 그와 비슷한 객체가 될 수 있어요).
파싱되지 않고 남은 argv의 나머지를 반환해요.
order! (argv = default_argv, into: nil, &nonopt)
order와 같지만 스위치를 파괴적으로 제거해요. 비옵션 인자는 argv에 남아요.
parse (*argv, into: nil)
환경변수 POSIXLY_CORRECT가 설정돼 있으면 명령줄 인자 argv를 순서대로, 그 외에는 permutation 모드로 파싱해요. 선택 into 키워드 인자가 주어지면 파싱된 옵션 값들이 거기에 []= 메서드로 저장돼요.
parse! (argv = default_argv, into: nil)
parse와 같지만 스위치를 파괴적으로 제거해요. 비옵션 인자는 argv에 남아요.
permute (*argv, into: nil)
명령줄 인자 argv를 permutation 모드로 파싱하고 비옵션 인자 목록을 반환해요. 선택 into 키워드 인자가 주어지면 파싱된 옵션 값들이 거기에 저장돼요.
permute! (argv = default_argv, into: nil)
permute와 같지만 스위치를 파괴적으로 제거해요. 비옵션 인자는 argv에 남아요.
program_name ()
에러 메시지와 기본 배너에 출력될 프로그램 이름. 기본값은 $0이에요.
reject (*args, &blk)
지정된 클래스 인자를 거부하도록 지시해요. t
reject(t)
release ()
릴리스 코드.
remove ()
마지막 List를 제거해요.
separator (string)
요약에 구분자를 추가해요.
summarize (to = [], width = @summary_width, max = width - 1, indent = @summary_indent, &blk)
옵션 요약을 to에 넣고 to를 반환해요. 블록이 주어지면 각 줄을 넘겨줘요. to
terminate (arg = nil)
옵션 파싱을 종료해요. 선택 파라미터 arg는 첫 비옵션 인자로 밀어 넣어지는 문자열이에요.
to_a ()
옵션 요약 목록을 반환해요.
to_s ()
문자열 표현을 반환해요.
top ()
on / on_head, accept / reject의 대상.
ver ()
program_name, version, release에서 버전 문자열을 반환해요.
version ()
버전.
warn (mesg = $!)
경고 메시지를 출력해요.