Skip to content

subcommand parser #41

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
[WIP] subcommand parser
  • Loading branch information
nobu committed Dec 22, 2022
commit 99af0a050a8da2d5cdd5b024de096d576de69b3a
35 changes: 31 additions & 4 deletions lib/optparse.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,7 @@ def initialize(banner = nil, width = 32, indent = ' ' * 4)
@default_argv = ARGV
@require_exact = false
@raise_unknown = true
@subparsers = nil
add_officious
yield self if block_given?
end
Expand All @@ -1171,6 +1172,12 @@ def self.terminate(arg = nil)
throw :terminate, arg
end

def subparser(name, *rest, &block)
parser = self.class.new(*rest)
(@subparsers ||= CompletingHash.new)[name] = [parser, block]
parser
end

@stack = [DefaultList]
def self.top() DefaultList end

Expand Down Expand Up @@ -1626,12 +1633,18 @@ def order(*argv, into: nil, &nonopt)
# Non-option arguments remain in +argv+.
#
def order!(argv = default_argv, into: nil, &nonopt)
setter = ->(name, val) {into[name.to_sym] = val} if into
setter = into.extend(SymSetter).method(:sym_set) if into
parse_in_order(argv, setter, &nonopt)
end

module SymSetter
def sym_set(name, val)
self[name.to_sym] = val
end
end

def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
opt, arg, val, rest = nil
opt, arg, val, rest, sub = nil
nonopt ||= proc {|a| throw :terminate, a}
argv.unshift(arg) if arg = catch(:terminate) {
while arg = argv.shift
Expand Down Expand Up @@ -1699,6 +1712,17 @@ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:

# non-option argument
else
# sub-command
if (key, (sub, block) = @subparsers&.complete(arg))
block.call if block
if setter
into = setter.receiver.class.new.extend(SymSetter)
setter.call(key, into)
setter = into.method(:sym_set)
end
return sub.parse_in_order(argv, setter, &nonopt)
end

catch(:prune) do
visit(:each_option) do |sw0|
sw = sw0
Expand All @@ -1716,7 +1740,7 @@ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:

argv
end
private :parse_in_order
protected :parse_in_order

#
# Parses command line arguments +argv+ in permutation mode and returns
Expand All @@ -1735,6 +1759,9 @@ def permute(*argv, into: nil)
# Non-option arguments remain in +argv+.
#
def permute!(argv = default_argv, into: nil)
if @subparsers
raise "cannot parse in permutation mode with subparsers"
end
nonopts = []
order!(argv, into: into, &nonopts.method(:<<))
argv[0, 0] = nonopts
Expand All @@ -1758,7 +1785,7 @@ def parse(*argv, into: nil)
# Non-option arguments remain in +argv+.
#
def parse!(argv = default_argv, into: nil)
if ENV.include?('POSIXLY_CORRECT')
if @subparsers or ENV.include?('POSIXLY_CORRECT')
order!(argv, into: into)
else
permute!(argv, into: into)
Expand Down
23 changes: 23 additions & 0 deletions sample/optparse/subcommand.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#! /usr/bin/ruby
# contributed by Minero Aoki.

require 'optparse'

opts = {}
parser = OptionParser.new
parser.on('-i') { opts["i"] = true }
parser.on('-o') { puts["o"] = true }

parser.subparser('add') {opts[:add] = {}}
.on('-i') { opts[:add]["i"] = true }
parser.subparser('del') {opts[:del] = {}}.then do |sub|
sub.on('-i') { opts[:del]["i"] = true }
end
parser.subparser('list') {opts[:list] = {}}.then do |sub|
sub.on('-iN', Integer) {|i| opts[:list]["i"] = i }
end

h = {}
p parser.parse!(ARGV, into: h)
p h
p opts
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy