2010-04-28 30 views
22

Tôi muốn để có thể sử dụng OptionParser ruby ​​của phân tích tiểu lệnh có dạngSử dụng OptionParser ruby ​​của phân tích tiểu lệnh

COMMAND [GLOBAL FLAGS] [SUB-COMMAND [SUB-COMMAND FLAGS]] 

như:

git branch -a 
gem list foo 

Tôi biết tôi có thể chuyển sang thư viện trình phân tích cú pháp tùy chọn khác (như Trollop), nhưng tôi quan tâm đến việc học cách làm điều này từ bên trong OptionParser, vì tôi muốn tìm hiểu thư viện tốt hơn.

Bất kỳ mẹo nào?

+0

Không có mẹo nào ngoài một đề xuất vẫn mở để chuyển hướng. Theo kinh nghiệm của tôi, 'OptionParser' đã bực bội khi sử dụng vì nhiều lý do, một trong số đó là tài liệu nghèo nàn - do đó, câu hỏi của bạn. William Morgan, tác giả của Trollop, cho thấy không có lòng thương xót trong những lời chỉ trích của ông (ví dụ, xem http://stackoverflow.com/questions/897630/really-cheap-command-line-option-parsing-in-ruby và http://trollop.rubyforge.org). Tôi không thể tranh cãi những gì anh ta nói. – FMc

+1

@FM: Vâng, giống như tác giả của câu hỏi đó, tôi bị mắc kẹt trên một máy tính nhập thư viện là một PITA, vì vậy tôi đang cố gắng làm với libs chuẩn - như 'optparse'. – rampion

Trả lời

35

Đã tìm ra. Tôi cần sử dụng OptionParser#order!. Nó sẽ phân tích tất cả các tùy chọn từ đầu của ARGV cho đến khi nó tìm thấy một tùy chọn (không phải là một đối số tùy chọn), loại bỏ mọi thứ mà nó xử lý từ ARGV và sau đó nó sẽ thoát.

Vì vậy, tôi chỉ cần làm một cái gì đó như:

global = OptionParser.new do |opts| 
    # ... 
end 
subcommands = { 
    'foo' => OptionParser.new do |opts| 
    # ... 
    end, 
    # ... 
    'baz' => OptionParser.new do |opts| 
    # ... 
    end 
} 

global.order! 
subcommands[ARGV.shift].order! 
+2

Để tham khảo, một ví dụ hoàn chỉnh hơn là trong [Gist] này (https://gist.github.com/rkumar/445735). – sschuberth

+0

Điều gì xảy ra nếu 'foo' và' baz' chia sẻ nhiều tùy chọn phổ biến? Làm thế nào để tránh sự lặp lại? –

+0

Fernando Á: đơn giản, chỉ cần trừu tượng các tùy chọn chung cho một phương thức. 'def common_options (&blk) ; OptionParser.new {| opts | opts.on (...); ...; blk.call (opts)}; kết thúc', sau đó gọi phương thức đó với một khối cho các tùy chọn đặc biệt con sau này - 'subcommands = {'foo' => common_options {| opts | ...}, 'baz' => common_options {| opts | ...}, ...}' – rampion

0

Ngoài ra còn có đá quý khác mà bạn có thể nhìn vào như main.

+0

có tài liệu nào không? – rampion

+0

@rampion: Bạn có thể xem các mẫu, ví dụ: http://codeforpeople.com/lib/ruby/main/main-2.8.3/samples/f.rb –

1

Dường như cú pháp OptionParser đã thay đổi một số. Tôi đã phải sử dụng sau đây để các mảng đối số có tất cả các tùy chọn không phân tích cú pháp bởi các đối tượng opts.

begin 
    opts.order!(arguments) 
rescue OptionParser::InvalidOption => io 
    # Prepend the invalid option onto the arguments array 
    arguments = io.recover(arguments) 
rescue => e 
    raise "Argument parsing failed: #{e.to_s()}" 
end 
0

GLI là cách để đi, https://github.com/davetron5000/gli. Đoạn trích từ hướng dẫn:

#!/usr/bin/env ruby 
require 'gli' 
require 'hacer' 

include GLI::App 

program_desc 'A simple todo list' 

flag [:t,:tasklist], :default_value => File.join(ENV['HOME'],'.todolist') 

pre do |global_options,command,options,args| 
    $todo_list = Hacer::Todolist.new(global_options[:tasklist]) 
end 

command :add do |c| 
    c.action do |global_options,options,args| 
    $todo_list.create(args) 
    end 
end 

command :list do |c| 
    c.action do 
    $todo_list.list.each do |todo| 
     printf("%5d - %s\n",todo.todo_id,todo.text) 
    end 
    end 
end 

command :done do |c| 
    c.action do |global_options,options,args| 
    id = args.shift.to_i 
    $todo_list.list.each do |todo| 
     $todo_list.complete(todo) if todo.todo_id == id 
    end 
    end 
end 

exit run(ARGV) 

Bạn có thể tìm hướng dẫn tại http://davetron5000.github.io/gli/.

Các vấn đề liên quan