[ruby] Ruby에서 매우 저렴한 명령 줄 옵션 구문 분석

편집 : 제발, 제발 , 제발 회신하기 전에이 게시물의 하단에 나와있는 두 가지 요구 사항을 참조하십시오. 사람들은 요구 사항을 분명히 충족하지 못하는 새로운 보석과 라이브러리 등을 계속 게시합니다.

때로는 명령 줄 옵션을 간단한 스크립트로 매우 저렴하게 해킹하고 싶습니다. getopts, 구문 분석 또는 이와 유사한 것을 처리하지 않고이를 수행하는 재미있는 방법은 다음과 같습니다.

...
$quiet       = ARGV.delete('-d')
$interactive = ARGV.delete('-i')
...
# Deal with ARGV as usual here, maybe using ARGF or whatever.

myprog -i foo bar -q” 에서와 같이 옵션이 아닌 명령 줄 매개 변수를 허용하기 때문에 일반적인 Unix 옵션 구문은 아니지만 그와 함께 살 수 있습니다. (Subversion 개발자와 같은 일부 사람들은 이것을 선호합니다. 때로는 저도 그렇습니다.)

그냥 존재하거나없는 옵션은 위의 것보다 훨씬 간단하게 구현할 수 없습니다. (하나의 할당, 하나의 함수 호출, 하나의 부작용) ” -f filename ” 과 같이 매개 변수를 사용하는 옵션을 처리하는 똑같이 간단한 방법이 있습니까?

편집하다:

Trollop의 저자가 라이브러리가 “하나의 [800 줄] 파일에 적합”하다고 언급 할 때까지 명확하지 않았기 때문에 이전에 언급하지 않은 한 가지 요점은 내가 깨끗한 것만을 찾고 있다는 것입니다. 구문이지만 다음과 같은 특성을 가진 기술에 사용됩니다.

  1. 코드 전체를 스크립트 파일에 포함 할 수 있으므로 (실제 스크립트 자체를 압도하지 않고 몇 줄에 불과할 수 있음) bin표준 Ruby 1.8을 사용하는 모든 시스템 의 디렉터리에 단일 파일을 드롭 할 수 있습니다. . [5-7] 설치 및 사용. require 문이없는 Ruby 스크립트를 작성할 수없고 몇 가지 옵션을 구문 분석하는 코드가 12 줄 정도 미만인 경우이 요구 사항이 실패합니다.

  2. 코드는 작고 단순해서 다른 곳에서 잘라내어 붙여 넣는 대신 트릭을 수행 할 코드를 직접 입력 할 수있을만큼 충분히 기억할 수 있습니다. 인터넷에 액세스 할 수없는 방화벽 서버의 콘솔에있는 상황을 생각해보십시오. 클라이언트가 사용할 수있는 빠른 스크립트를 함께 사용하려고합니다. 나는 당신에 대해 잘 모르지만 (위의 요구 사항에 실패하는 것 외에도) 45 줄의 단순화 된 마이크로 옵 파스조차도 암기하는 것은 내가 신경 쓰는 일이 아닙니다.



답변

Trollop 의 저자로서 저는 사람들이 옵션 파서에서 합리적이라고 생각하는 것을 믿을 수 없습니다. 진지하게. 그것은 마음을 깜짝 놀라게합니다.

옵션을 구문 분석하기 위해 다른 모듈을 확장하는 모듈을 만들어야하는 이유는 무엇입니까? 왜 어떤 것을 서브 클래 싱해야합니까? 명령 줄을 구문 분석하기 위해 “프레임 워크”를 구독해야하는 이유는 무엇입니까?

위의 Trollop 버전은 다음과 같습니다.

opts = Trollop::options do
  opt :quiet, "Use minimal output", :short => 'q'
  opt :interactive, "Be interactive"
  opt :filename, "File to process", :type => String
end

그리고 그게 다야. opts지금 키가있는 해시 :quiet, :interactive:filename. 원하는대로 할 수 있습니다. 그리고 화면 너비에 맞게 형식이 지정된 아름다운 도움말 페이지, 자동 짧은 인수 이름, 유형 검사 등 필요한 모든 것을 얻을 수 있습니다.

하나의 파일이므로 공식적인 종속성을 원하지 않는 경우 lib / 디렉토리에 놓을 수 있습니다. 픽업하기 쉬운 최소한의 DSL이 있습니다.

옵션 인원 당 LOC. 그것은 중요.


답변

나는 require 'getopts'주로 다음과 같은 굉장함 때문에에 대한 당신의 싫어함을 공유합니다 OptionParser.

% cat temp.rb
require 'optparse'
OptionParser.new do |o|
  o.on('-d') { |b| $quiet = b }
  o.on('-i') { |b| $interactive = b }
  o.on('-f FILENAME') { |filename| $filename = filename }
  o.on('-h') { puts o; exit }
  o.parse!
end
p :quiet => $quiet, :interactive => $interactive, :filename => $filename
% ruby temp.rb
{:interactive=>nil, :filename=>nil, :quiet=>nil}
% ruby temp.rb -h
Usage: temp [options]
    -d
    -i
    -f FILENAME
    -h
% ruby temp.rb -d
{:interactive=>nil, :filename=>nil, :quiet=>true}
% ruby temp.rb -i
{:interactive=>true, :filename=>nil, :quiet=>nil}
% ruby temp.rb -di
{:interactive=>true, :filename=>nil, :quiet=>true}
% ruby temp.rb -dif apelad
{:interactive=>true, :filename=>"apelad", :quiet=>true}
% ruby temp.rb -f apelad -i
{:interactive=>true, :filename=>"apelad", :quiet=>nil}


답변

일반적으로 사용하는 표준 기술은 다음과 같습니다.

#!/usr/bin/env ruby

def usage(s)
    $stderr.puts(s)
    $stderr.puts("Usage: #{File.basename($0)}: [-l <logfile] [-q] file ...")
    exit(2)
end

$quiet   = false
$logfile = nil

loop { case ARGV[0]
    when '-q' then  ARGV.shift; $quiet = true
    when '-l' then  ARGV.shift; $logfile = ARGV.shift
    when /^-/ then  usage("Unknown option: #{ARGV[0].inspect}")
    else break
end; }

# Program carries on here.
puts("quiet: #{$quiet} logfile: #{$logfile.inspect} args: #{ARGV.inspect}")


답변

아무도 그것을 언급 등장하지 않으며, 제목이 때문에 않습니다 를 참조 저렴 명령 줄 구문 분석, 왜 그냥 당신을 위해 일을 통역 루비를 보자? -s스위치 를 전달하면 (예 : shebang에서) 단일 문자 전역 변수에 할당 된 더럽고 간단한 스위치가 무료로 제공됩니다. 이 스위치를 사용한 예는 다음과 같습니다.

#!/usr/bin/env ruby -s
puts "#$0: Quiet=#$q Interactive=#$i, ARGV=#{ARGV.inspect}"

그리고 여기에 그것을 저장 ./test하고 chmod 할 때 출력이 있습니다 +x.

$ ./test
./test: Quiet= Interactive=, ARGV=[]
$ ./test -q foo
./test: Quiet=true Interactive=, ARGV=["foo"]
$ ./test -q -i foo bar baz
./test: Quiet=true Interactive=true, ARGV=["foo", "bar", "baz"]
$ ./test -q=very foo
./test: Quiet=very Interactive=, ARGV=["foo"]

자세한 내용은 ruby -h을 참조하십시오.

한다 이수록 저렴로합니다. 와 같은 스위치를 시도하면 NameError가 발생 -:하므로 거기에 몇 가지 유효성 검사가 있습니다. 물론, non-switch 인수 후에는 어떤 스위치도 가질 수 없지만, 뭔가 멋진 것이 필요하다면, 최소한 OptionParser를 사용해야합니다. 사실,이 기술에 대해 저를 짜증나게하는 유일한 점은 설정되지 않은 전역 변수에 액세스 할 때 경고 (활성화 한 경우)가 표시되지만 여전히 거짓이므로 일회용 도구 및 빠른 스크립트.

Ruby에서 정말 저렴한 명령 줄 옵션 구문 분석을 수행하는 방법 “의 주석에서 FelipeC가 지적한 한 가지주의 사항은 쉘이 3- 토큰 shebang을 지원하지 않을 수 있다는 것입니다. /usr/bin/env ruby -w루비의 실제 경로 (예 🙂 로 바꾸 /usr/local/bin/ruby -w거나 래퍼 스크립트 등에서 실행해야 할 수 있습니다.


답변

짧지 만 사용하기 쉬운 옵션 파서에 대한 이러한 명백한 요구를 충족시키기 위해 마이크로파스 를 구축했습니다 . Trollop과 유사한 구문을 가지고 있으며 70 줄이 짧습니다. 유효성 검사가 필요하지 않고 빈 줄없이 할 수있는 경우 45 줄로 줄일 수 있습니다. 정확히 당신이 찾고 있던 것 같아요.

간단한 예 :

options = Parser.new do |p|
  p.version = "fancy script version 1.0"
  p.option :verbose, "turn on verbose mode"
  p.option :number_of_chairs, "defines how many chairs are in the classroom", :default => 1
  p.option :room_number, "select room number", :default => 2, :value_in_set => [1,2,3,4]
end.process!

와 스크립트를 호출 -h하거나하는 것은 --help인쇄됩니다

Usage: micro-optparse-example [options]
    -v, --[no-]verbose               turn on verbose mode
    -n, --number-of-chairs 1         defines how many chairs are in the classroom
    -r, --room-number 2              select room number
    -h, --help                       Show this message
    -V, --version                    Print version

입력이 기본값과 동일한 유형인지 확인하고, 짧고 긴 접근자를 생성하고, 유효하지 않은 인수가 주어지면 설명 오류 메시지를 인쇄합니다.

내가 가진 문제에 대해 각 옵션 파서 를 사용하여 여러 옵션 파서비교했습니다 . 이 예와 요약을 사용하여 유익한 결정을 내릴 수 있습니다. 목록에 더 많은 구현을 자유롭게 추가하십시오. 🙂


답변

optparse를 피하고 싶은 이유를 완전히 이해합니다. 너무 많이 얻을 수 있습니다. 그러나 라이브러리로 제공되지만 단일 gem 설치를 가치있게 만들 수있을만큼 간단한 몇 가지 훨씬 “가벼운”솔루션 (OptParse에 비해)이 있습니다.

예를 들어, 이 OptiFlag 예제를 확인하십시오 . 처리를 위해 몇 줄만하면됩니다. 귀하의 사례에 맞게 약간 잘린 예 :

require 'optiflag'

module Whatever extend OptiFlagSet
  flag "f"
  and_process!
end

ARGV.flags.f # => .. whatever ..

있습니다 사용자 정의 예제의 톤도 . 더 쉬운 다른 것을 사용했던 것을 기억하지만 지금은 나를 피했지만 내가 찾으면 여기에 다시 와서 여기에 주석을 추가합니다.


답변

이것이 제가 정말 정말 값싼 인수에 사용하는 것입니다.

def main
  ARGV.each { |a| eval a }
end

main

그래서 실행 programname foo bar하면 foo를 호출 한 다음 bar를 호출합니다. 일회용 스크립트에 편리합니다.