@@ -1148,6 +1148,7 @@ def initialize(banner = nil, width = 32, indent = ' ' * 4)
11481148 @summary_indent = indent
11491149 @default_argv = ARGV
11501150 @require_exact = false
1151+ @subparsers = nil
11511152 add_officious
11521153 yield self if block_given?
11531154 end
@@ -1170,6 +1171,12 @@ def self.terminate(arg = nil)
11701171 throw :terminate , arg
11711172 end
11721173
1174+ def subparser ( name , *rest , &block )
1175+ parser = self . class . new ( *rest )
1176+ ( @subparsers ||= CompletingHash . new ) [ name ] = [ parser , block ]
1177+ parser
1178+ end
1179+
11731180 @stack = [ DefaultList ]
11741181 def self . top ( ) DefaultList end
11751182
@@ -1622,12 +1629,17 @@ def order(*argv, into: nil, &nonopt)
16221629 # Non-option arguments remain in +argv+.
16231630 #
16241631 def order! ( argv = default_argv , into : nil , &nonopt )
1625- setter = -> ( name , val ) { into [ name . to_sym ] = val } if into
1632+ setter = into . extend ( SymSetter ) . method ( :sym_set ) if into
16261633 parse_in_order ( argv , setter , &nonopt )
16271634 end
16281635
1636+ module SymSetter
1637+ def sym_set ( name , val )
1638+ self [ name . to_sym ] = val
1639+ end
1640+ end
16291641 def parse_in_order ( argv = default_argv , setter = nil , &nonopt ) # :nodoc:
1630- opt , arg , val , rest = nil
1642+ opt , arg , val , rest , sub = nil
16311643 nonopt ||= proc { |a | throw :terminate , a }
16321644 argv . unshift ( arg ) if arg = catch ( :terminate ) {
16331645 while arg = argv . shift
@@ -1692,6 +1704,17 @@ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
16921704
16931705 # non-option argument
16941706 else
1707+ # sub-command
1708+ if ( key , ( sub , block ) = @subparsers &.complete ( arg ) )
1709+ block . call if block
1710+ if setter
1711+ into = setter . receiver . class . new . extend ( SymSetter )
1712+ setter . call ( key , into )
1713+ setter = into . method ( :sym_set )
1714+ end
1715+ return sub . parse_in_order ( argv , setter , &nonopt )
1716+ end
1717+
16951718 catch ( :prune ) do
16961719 visit ( :each_option ) do |sw0 |
16971720 sw = sw0
@@ -1709,7 +1732,7 @@ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
17091732
17101733 argv
17111734 end
1712- private :parse_in_order
1735+ protected :parse_in_order
17131736
17141737 #
17151738 # Parses command line arguments +argv+ in permutation mode and returns
@@ -1728,6 +1751,9 @@ def permute(*argv, into: nil)
17281751 # Non-option arguments remain in +argv+.
17291752 #
17301753 def permute! ( argv = default_argv , into : nil )
1754+ if @subparsers
1755+ raise "cannot parse in permutation mode with subparsers"
1756+ end
17311757 nonopts = [ ]
17321758 order! ( argv , into : into , &nonopts . method ( :<< ) )
17331759 argv [ 0 , 0 ] = nonopts
@@ -1751,7 +1777,7 @@ def parse(*argv, into: nil)
17511777 # Non-option arguments remain in +argv+.
17521778 #
17531779 def parse! ( argv = default_argv , into : nil )
1754- if ENV . include? ( 'POSIXLY_CORRECT' )
1780+ if @subparsers or ENV . include? ( 'POSIXLY_CORRECT' )
17551781 order! ( argv , into : into )
17561782 else
17571783 permute! ( argv , into : into )
0 commit comments