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


114

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

때로는 명령 줄 옵션을 간단한 스크립트로 매우 저렴하게 해킹하고 싶습니다. 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 줄의 단순화 된 마이크로 옵 파스조차도 암기하는 것은 내가 신경 쓰는 일이 아닙니다.


2
getoptlong에 대한 이의가 궁금 하신가요?
— Mark Carey

그것의 장황함. getoptlog를 사용하면 코드를 구문 분석하는 옵션이 실제로 작업을 수행하는 스크립트 부분보다 긴 경우가 있습니다. 이것은 미적 문제가 아니라 유지 보수 비용 문제입니다.
— cjs

8
모두 - 나는 스크립트 포함 요구 사항을 이해하지 못하는 getoptlong와 optparse루비 후, 해당 시스템에서 작동하는 경우 - 당신은 당신의 스크립트를 배포 할 때 복사 할 필요가 없습니다, 표준 루비 라이브러리에있는 require 'optparse'또는 require 'getoptlong'너무 일 것이다.
— rampion

참조 stackoverflow.com/questions/21357953/... 뿐만 아니라 매춘부에 대한 아래의 윌리엄 모건의 답변을.
— fearless_fool

@CurtSampson 얼마나 많은 사람들이 귀하의 질문에 대답하지 않았는지 믿을 수 없습니다. 어느 쪽이든, 마지막 XD XD 아래 3 개 게시물에 대한 좋은 대답을 얻었다
— OneChillDude

답변:


235

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. 그것은 중요.


39
BTW, +1은 Trollop (이미 여기에서 언급 했음)을 작성했지만 첫 번째 단락을 조금 낮추어도됩니다.
— cjs 09-06-19

33
그는이 경우 불만을 제기 할 권리가 있습니다. 대안을 볼 때 : [1 ] [2 ] [3 ], 기본적으로 단순한 문자열 배열을 처리하는 것이 무엇인지 (실제로는 그렇게하지 마십시오) 왜 그런지 궁금해 할 수 없습니다. 그 모든 팽창에서 무엇을 얻습니까? 이것은 문자열이 "문제가있는"C가 아닙니다. 물론 각자 자신에게. :)
— srcspider 2010-08-22

50
이걸 조금 낮추지 마세요. 의로운 스크 리드 야, 형제.
— William Pietri

7
열 번째 단어를 조금 낮추십시오.
— Andrew Grimm 2011 년

3
Trollop에 +1. 테스트 자동화 시스템에 사용하고 Just Works입니다. 게다가 코드 작성이 너무 쉬워서 가끔 배너의 즐거움을 경험하기 위해 배너를 재정렬합니다.
— kinofrost 2011

76

나는 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}

6
덕분에,이, 특히 설치 / 비 표준 코드 vendoring의 필요에 비해, 모든 표준 lib에 자사을 고려하여 OPS 요청 맞지 않는 볼 수 없습니다
— dolzenko

3
이것은 추가 파일이 필요하지 않다는 점을 제외하면 trollop 버전과 비슷합니다.
— Claudiu

59

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

#!/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}")

3
질문에 답하지만, 트롤 롭은 처리하기가 훨씬 더 쉬운 것 같습니다. 사전 제작 된 휠이 훨씬 더 부드러울 때 휠을 재발 명하는 이유는 무엇입니까?
— Mikey TK

7
미리 만들어진 휠이 더 부드럽 지 않습니다. 요구 사항에주의하면서 질문을주의 깊게 다시 읽으십시오.
— CJS

2
+1 때때로 당신 은 트롤 롭과 같은 다른 의존성을 원하지 않거나 단순히 사용할 수 없기 때문에 바퀴를 재발 명해야합니다 .
— lzap 2014

Trollop은 gem으로 설치할 필요가 없습니다. lib폴더 나 코드 에 파일 하나를 놓아두면 rubygems를 건드리지 않고도 사용할 수 있습니다.
— Overbryd

나를 위해, 나는 변경했다 when /^-/ then usage("Unknown option: #{ARGV[0].inspect}")으로 when /^-/ then usage("Unknown option: #{ARGV.shift.inspect}")또는 무한 사용 루프에 들어갈 것
— 케이시

36

아무도 그것을 언급 등장하지 않으며, 제목이 때문에 않습니다 를 참조 저렴 명령 줄 구문 분석, 왜 그냥 당신을 위해 일을 통역 루비를 보자? -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거나 래퍼 스크립트 등에서 실행해야 할 수 있습니다.


2
감사합니다 :) 그가 지난 2 년 동안이 답변을 기다리지 않았기를 바랍니다.
— DarkHeart 2013

3
나는 정말로 지난 2 년 동안이 대답을 기다리고 있었다. :-) 더 진지하게, 이것은 내가 찾던 일종의 영리한 생각입니다. 경고는 약간 성가 시지만이를 완화 할 방법을 생각할 수 있습니다.
— CJS

@CurtSampson, @CurtSampson, MRI의 깃발은 Perl에서 곧바로 찢어지며 쉘 한 줄에서 무상으로 사용되는 경향이 있습니다. 답변이 여전히 도움이된다면 받아 들일 수 있습니다. :)
— bjjb 2014

1
Linux에서는 shebang에서 여러 인수를 사용할 수 없습니다. / usr / bin / env : 'ruby -s': 해당 파일 또는 디렉토리 없음
— FelipeC

13

짧지 만 사용하기 쉬운 옵션 파서에 대한 이러한 명백한 요구를 충족시키기 위해 마이크로 옵 파스 를 구축했습니다 . 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

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

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


라이브러리 자체가 훌륭 할 것 같습니다. 그러나 optparse1937 줄에 의존하고 요구하기 때문에 줄 수를 Trollop과 비교하는 것이 불명예하지 않습니까 ?
— Telemachus

6
줄 수를 비교 optparse하는 것은 기본 라이브러리 이기 때문에 절대적으로 괜찮습니다 . 즉, 모든 루비 설치와 함께 제공됩니다. Trollop타사 라이브러리이므로 프로젝트에 포함 할 때마다 전체 코드를 가져와야합니다. µ-optparse optparse는 이미 존재 하므로 항상 ~ 70 줄만 필요합니다 .
— Florian Pilz

8

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

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

require 'optiflag'

module Whatever extend OptiFlagSet
  flag "f"
  and_process!
end 

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

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


명확한 질문에 더 잘 맞도록 답변을 자유롭게 편집하십시오.
— CJS

4

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

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

main

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


3

다음과 같이 시도 할 수 있습니다.

if( ARGV.include( '-f' ) )
  file = ARGV[ARGV.indexof( '-f' ) + 1 )]
  ARGV.delete('-f')
  ARGV.delete(file)
end

3

wycats의 Thor 를 고려해 보셨습니까? optparse보다 훨씬 깨끗하다고 ​​생각합니다. 이미 스크립트를 작성했다면 형식을 지정하거나 thor를 위해 리팩토링하는 데 더 많은 작업이 필요할 수 있지만 처리 옵션을 매우 간단하게 만듭니다.

다음은 README의 예제 스 니펫입니다.

class MyApp < Thor                                                # [1]
  map "-L" => :list                                               # [2]

  desc "install APP_NAME", "install one of the available apps"    # [3]
  method_options :force => :boolean, :alias => :optional          # [4]
  def install(name)
    user_alias = options[:alias]
    if options.force?
      # do something
    end
    # ... other code ...
  end

  desc "list [SEARCH]", "list all of the available apps, limited by SEARCH"
  def list(search = "")
    # list everything
  end
end

Thor는 다음과 같은 명령을 자동으로 매핑합니다.

app install myname --force

다음으로 변환됩니다.

MyApp.new.install("myname")
# with {'force' => true} as options hash
  1. Thor에서 상속하여 클래스를 옵션 매퍼로 전환
  2. 유효하지 않은 추가 식별자를 특정 메서드에 매핑합니다. 이 경우 -L을 : list로 변환하십시오.
  3. 바로 아래에 방법을 설명하십시오. 첫 번째 매개 변수는 사용 정보이고 두 번째 매개 변수는 설명입니다.
  4. 추가 옵션을 제공하십시오. 이들은-및-매개 변수에서 마샬링됩니다. 이 경우 --force 및 -f 옵션이 추가됩니다.

많은 하위 명령이있는 단일 바이너리가 자주하는 일이기 때문에 명령 매핑을 좋아합니다. 그래도 '빛'에서 길을 갔지만. 동일한 기능을 표현하는 더 간단한 방법을 찾을 수 있습니까? --help출력물 을 인쇄 할 필요가 없다면 어떻게 합니까? "head myprogram.rb"가 도움말 출력이면 어떻게됩니까?
— cjs

3

제가 가장 좋아하는 빠르고 더러운 옵션 파서가 있습니다.

case ARGV.join
when /-h/
  puts "help message"
  exit
when /-opt1/
  puts "running opt1"
end

옵션은 정규식이므로 "-h"도 "--help"와 일치합니다.

읽기 쉽고 기억하기 쉬우 며 외부 라이브러리가 없으며 최소한의 코드입니다.


네, 그렇습니다. 이것이 문제라면 정규식을 더 추가 할 수 있습니다. 예를 들어/-h(\b|elp)
— EdwardTeach

2

Trollop 은 꽤 저렴합니다.


이것이 바로 < trollop.rubyforge.org >입니다. 나는 정말로 도서관을 찾고 있지 않았지만 오히려 그것을 좋아한다고 생각합니다.
— cjs

사실, 그것은 도서관입니다. 그러나 <800 LOC에서는 매우 무시할 수있는 수준입니다. gitorious.org/trollop/mainline/blobs/master/lib/trollop.rb
— g33kz0r

1
나는 "라이브러리"를 사용하기까지한다면 아마 30-50 줄이 좋을 것이라고 생각했습니다. 그러나 다시 한 번, 코드로 가득 찬 별도의 파일이 있으면 API 디자인이 줄 수보다 더 중요하다고 생각합니다. 그래도 무작위 시스템의 bin 디렉토리에 넣고 싶은 일회성 스크립트에 포함시키고 싶지는 않습니다.
— cjs 09-06-19

1
거꾸로 이해했습니다. 요점은 더 복잡한 배포 전략을 사용하지 않는 것입니다.
— cjs

1
질문을 한 사람의 필요와 의도를 완전히 오해 (또는 무시)하고 있기 때문에 당신은 아주 틀 렸습니다. 질문, 특히 마지막 두 가지 사항을주의 깊게 다시 읽어 보시기 바랍니다.
— cjs

2

gem을 사용하지 않고 키 / 값 명령에 대한 간단한 명령 줄 파서를 원한다면 :

그러나 이것은 항상 키 / 값 쌍이있는 경우 에만 작동합니다.

# example
# script.rb -u username -p mypass

# check if there are even set of params given
if ARGV.count.odd? 
    puts 'invalid number of arguments'
    exit 1
end

# holds key/value pair of cl params {key1 => value1, key2 => valye2, ...}
opts = {} 

(ARGV.count/2).times do |i|
    k,v = ARGV.shift(2)
    opts[k] = v # create k/v pair
end

# set defaults if no params are given
opts['-u'] ||= 'root'

# example use of opts
puts "username:#{opts['-u']} password:#{opts['-p']}"

확인 이 필요하지 않은 경우 다음을 사용할 수 있습니다.

opts = {} 

(ARGV.count/2).times do |i|
    k,v = ARGV.shift(2)
    opts[k] = v # create k/v pair
end

2

다음은 대부분의 스크립트 상단에서 사용하는 코드 스 니펫입니다.

arghash = Hash.new.tap { |h| # Parse ARGV into a hash
    i = -1                      
    ARGV.map{  |s| /(-[a-zA-Z_-])?([^=]+)?(=)?(.+)?/m.match(s).to_a }
     .each{ |(_,a,b,c,d)| h[ a ? "#{a}#{b}#{c}" : (i+=1) ] =
                             (a ? (c ? "#{d}" : true) : "#{b}#{c}#{d}") 
          }
    [[:argc,Proc.new  {|| h.count{|(k,_)| !k.is_a?(String)}}],
     [:switches, Proc.new {|| h.keys.select{|k| k[0] == '-' }}]
    ].each{|(n,p)| h.define_singleton_method(n,&p) }
}

또한 빠르고 더러운 스크립트에 추가 파일이 필요한 것도 싫어합니다. 내 솔루션은 당신이 요구하는 것입니다. 명령 줄을 구문 분석하고 위치 인수를 고정하고 Hash 개체로 전환하는 스크립트의 맨 위에 10 줄의 코드 스 니펫을 붙여 넣습니다 (일반적으로 내가 arghash 라는 개체에 할당 됨). 아래 예제에서 됨).

다음은 구문 분석 할 수있는 명령 줄의 예입니다.

./myexampleprog.rb -s -x=15 --longswitch arg1 --longswitch2=val1 arg2

이런 해시가 될 것입니다.

 { 
   '-s' => true, 
   '-x=' => '15', 
   '--longswitch' => true, 
   '--longswitch2=' => 'val1', 
   0 => 'arg1', 
   1 => 'arg2'
 }

그 외에도 해시에 두 가지 편리한 메서드가 추가되었습니다.

  • argc() 비 스위치 인수의 수를 반환합니다.
  • switches() 존재하는 스위치의 키가 포함 된 배열을 반환합니다.

이것은 다음과 같은 빠르고 더러운 것을 허용한다는 의미입니다.

  • 전달 된 스위치에 관계없이 올바른 수의 위치 인수가 있는지 확인합니다 ( arghash.argc == 2 )
  • 위치 인수 앞에 표시되거나 위치 인수가 산재되어있는 스위치에 관계없이 상대 위치로 위치 인수에 액세스합니다 (예 : arghash[1]항상 두 번째 비 스위치 인수를 가져옴).
  • 명령 줄에서 액세스 할 수있는 "--max = 15"와 같은 값 할당 스위치를 지원 arghash['--max=']하여 예제 명령 줄에서 값 '15'를 생성합니다.
  • 스위치가있는 arghash['-s']경우 true로 평가되고 없을 경우 nil로 평가 되는 매우 간단한 표기법을 사용하여 명령 줄에서 스위치의 존재 여부를 테스트합니다 .
  • 다음과 같은 설정 작업을 사용하여 스위치 또는 스위치의 대안이 있는지 테스트합니다.

    puts USAGETEXT if !(%w(-h --help) & arghash.switches()).empty?

  • 다음과 같은 설정 작업을 사용하여 잘못된 스위치 사용 식별

    puts "Invalid switch found!" if !(arghash.switches - %w(-valid1 -valid2)).empty?

  • Hash.merge()-max = 값이 설정되지 않은 경우 값을 채우고 전달되지 않은 경우 네 번째 위치 인수를 추가하는 아래 예제와 같은 간단한 예를 사용하여 누락 된 인수에 대한 기본값을 지정 하십시오.

    with_defaults = {'-max=' => 20, 3 => 'default.txt'}.merge(arghash)


(주로 정렬을 사용하여 블록 및 제어 구조를 더 명확하게 만드는 코드 서식을 깔끔하게 개선하기 위해 이것을 편집했습니다. 특히 구두점이 이처럼 밀집된 부분에서 중요하다고 생각합니다.하지만 새 서식이 싫다면 부담없이 사용해주세요. 편집을 취소합니다.)
— cjs jul

이것은 세상에서 가장 읽기 쉬운 것은 아니지만 꽤 좋습니다. 또한 인수 "구문"을 변경하면 (여기서는 위치 인수 다음에 옵션을 허용하고를 사용하는 경우를 제외하고 옵션 인수를 허용하지 않음 =) 필요한 코드에 차이를 만들 수 있음을 보여줍니다.
— cjs

다시 포맷 해 주셔서 감사합니다. 읽기는 확실히 모호하며 명확성을 위해 코드 길이를 쉽게 바꿀 수 있습니다. 이제 저는이 코드를 어느 정도 신뢰하므로 보석처럼 취급하고 그것이 무엇을하고 있는지 알아 내려고하지 않습니다 (이제 신뢰를 얻었으므로 명확성은 더 이상 중요하지 않습니다).
— David Foster

1

이것은 받아 들여지는 대답과 매우 유사하지만 간단한 파서ARGV.delete_if 에서 사용 하는 것입니다 . 유일한 차이점은 인수가있는 옵션이 함께 있어야한다는 것입니다 (예 :) .-l=file

def usage
  "usage: #{File.basename($0)}: [-l=<logfile>] [-q] file ..."
end

$quiet = false
$logfile = nil

ARGV.delete_if do |cur|
  next false if cur[0] != '-'
  case cur
  when '-q'
    $quiet = true
  when /^-l=(.+)$/
    $logfile = $1
  else
    $stderr.puts "Unknown option: #{cur}"
    $stderr.puts usage
    exit 1
  end
end

puts "quiet: #{$quiet} logfile: #{$logfile.inspect} args: #{ARGV.inspect}"

0

분명히 @WilliamMorgan과 나는 비슷하다고 생각합니다. 방금 Github에서 OptionParser를 검색 한 후 어제 밤에 Github에 릴리스했습니다. 이제 Trollop과 유사한 라이브러리 (이름은?)입니다. Switches를

몇 가지 차이점이 있지만 철학은 동일합니다. 한 가지 분명한 차이점은 스위치가 OptionParser에 의존한다는 것입니다.


0

Acclaim이라는 자체 옵션 파서 젬을 개발 중 입니다.

git 스타일의 명령 줄 인터페이스를 만들고 각 명령의 기능을 별도의 클래스로 명확하게 분리 할 수 ​​있기를 원했기 때문에 작성했지만 전체 명령 프레임 워크 없이도 사용할 수 있습니다.

(options = []) << Acclaim::Option.new(:verbose, '-v', '--verbose')
values = Acclaim::Option::Parser.new(ARGV, options).parse!
puts 'Verbose.' if values.verbose?

아직 안정적인 릴리스는 없지만 다음과 같은 일부 기능을 이미 구현했습니다.

  • 사용자 정의 옵션 파서
  • 최소 및 옵션을 모두 허용하는 옵션 인수의 유연한 구문 분석
  • 다양한 옵션 스타일 지원
  • 동일한 옵션의 여러 인스턴스에서 교체, 추가 또는 올리기
  • 사용자 정의 옵션 핸들러
  • 사용자 정의 유형 핸들러
  • 공통 표준 라이브러리 클래스에 대해 미리 정의 된 핸들러

명령에 대한 강조가 많으므로 간단한 명령 줄 구문 분석에는 약간 무거울 수 있지만 잘 작동하며 모든 프로젝트에서 사용하고 있습니다. 명령 인터페이스 측면에 관심이 있다면 프로젝트의 GitHub 페이지 에서 자세한 정보와 예제를 확인하십시오.


1
Acclaim을 강력히 추천합니다. 사용하기 쉽고 필요한 모든 옵션이 있습니다.
— bowsersenior jul.

0

명령에 다음과 같이 최대 하나의 작업과 임의의 수의 옵션이 있다고 가정합니다.

cmd.rb
cmd.rb action
cmd.rb action -a -b ...
cmd.rb action -ab ...

유효성 검사없이 구문 분석은 다음과 같을 수 있습니다.

ACTION = ARGV.shift
OPTIONS = ARGV.join.tr('-', '')

if ACTION == '***'
  ...
  if OPTIONS.include? '*'
    ...
  end
  ...
end

0

https://github.com/soveran/clap

other_args = Clap.run ARGV,
  "-s" => lambda { |s| switch = s },
  "-o" => lambda { other = true }

46LOC (1.0.0에서), 외부 옵션 파서에 대한 종속성 없음. 작업을 완료합니다. 아마도 다른 것만 큼 완전한 기능은 아니지만 46LOC입니다.

코드를 확인하면 기본 기술을 매우 쉽게 복제 할 수 있습니다. 외부 라이브러리를 원하지 않는 경우 람다를 할당하고 적절한 수의 인수가 플래그를 따르도록 arity를 ​​사용합니다.

단순한. 싼.


편집 : 합리적인 명령 줄 구문 분석기를 만들기 위해 스크립트에 복사 / 붙여 넣기 할 수 있다고 가정 할 때 기본 개념이 요약되었습니다. 그것은 확실히입니다 하지 싼 파서가 새로운 생각으로 내가 메모리에 커밋 것이 뭔가,하지만 람다 인수에 대응을 사용하여 :

flag = false
option = nil
opts = {
  "--flag" => ->() { flag = true },
  "--option" => ->(v) { option = v }
}

argv = ARGV
args = []

while argv.any?
  item = argv.shift
  flag = opts[item]

  if flag
    raise ArgumentError if argv.size < arity
    flag.call(*argv.shift(arity))
  else
    args << item
  end
end

# ...do stuff...

질문 끝에있는 요점 1을 읽으십시오. 여기에 답변에 필요한 코드를 모두 입력 할 수 없다면 질문에 대한 답변이 아닙니다.
— cjs

좋은 지적! 나는 그 당시 lib가 외부 의존성이 필요하지 않고 작업하고 있던 스크립트에 전체를 복사 / 붙여 넣기 할 수있을만큼 충분히 작다고 생각했지만, 확실히 기억에 남을 깔끔한 한 줄은 아닙니다. 당신의 포인트 # 2를 달성하기 위해. 나는 기본 개념이 참신하고 멋져서 당신의 질문에 조금 더 적절하게 대답하는 삶은 버전을 만들었습니다.
— Ben Alavi

-1

나는 한동안 작업해온 내 자신의 간단한 옵션 파서를 공유 할 것이다. 74 줄의 코드 일 뿐이며 Git의 내부 옵션 파서가 수행하는 작업의 기본을 수행합니다. OptionParser를 영감으로 삼았고 Git도 마찬가지였습니다.

https://gist.github.com/felipec/6772110

다음과 같이 보입니다.

opts = ParseOpt.new
opts.usage = "git foo"

opts.on("b", "bool", help: "Boolean") do |v|
 $bool = v
end

opts.on("s", "string", help: "String") do |v|
 $str = v
end

opts.on("n", "number", help: "Number") do |v|
 $num = v.to_i
end

opts.parse

코드도 확인하지 않았습니다. 파싱 ​​코드를 꺼내는 또 다른 대답을했습니다.
— FelipeC

나는 당신이 그것이 74 줄이라고 말했음을 줄 필요가 없었습니다. 그러나 방금 살펴 봤지만 여전히 요구 사항 2의 첫 번째 문장을 위반합니다. (이 응답은 또한 오프 사이트 링크를 제공하는 대신 답변에 코드를 포함해야한다는 스택 오버플로 규칙을 위반합니다.)
— CJS

-1

EasyOptions 에는 옵션 구문 분석 코드가 전혀 필요하지 않습니다. 도움말 텍스트를 작성하고 요구하고 완료하십시오.

## Options:
##   -i, --interactive  Interactive mode
##   -q, --quiet        Silent mode

require 'easyoptions'
unless EasyOptions.options[:quiet]
    puts 'Interactive mode enabled' if EasyOptions.options[:interactive]
    EasyOptions.arguments.each { |item| puts "Argument: #{item}" }
end

EasyOptions는 require 문이없는 단일 Ruby 파일이며 기억할 구문 분석 코드가 전혀 없습니다. 대신에 충분히 강력하면서도 기억하기 쉬운 삽입 가능한 것을 원하는 것 같습니다.
— Renato Silva
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.