@@ -1149,6 +1149,7 @@ def initialize(banner = nil, width = 32, indent = ' ' * 4)
1149
1149
@default_argv = ARGV
1150
1150
@require_exact = false
1151
1151
@raise_unknown = true
1152
+ @subparsers = nil
1152
1153
add_officious
1153
1154
yield self if block_given?
1154
1155
end
@@ -1171,6 +1172,12 @@ def self.terminate(arg = nil)
1171
1172
throw :terminate , arg
1172
1173
end
1173
1174
1175
+ def subparser ( name , *rest , &block )
1176
+ parser = self . class . new ( *rest )
1177
+ ( @subparsers ||= CompletingHash . new ) [ name ] = [ parser , block ]
1178
+ parser
1179
+ end
1180
+
1174
1181
@stack = [ DefaultList ]
1175
1182
def self . top ( ) DefaultList end
1176
1183
@@ -1626,12 +1633,18 @@ def order(*argv, into: nil, &nonopt)
1626
1633
# Non-option arguments remain in +argv+.
1627
1634
#
1628
1635
def order! ( argv = default_argv , into : nil , &nonopt )
1629
- setter = -> ( name , val ) { into [ name . to_sym ] = val } if into
1636
+ setter = into . extend ( SymSetter ) . method ( :sym_set ) if into
1630
1637
parse_in_order ( argv , setter , &nonopt )
1631
1638
end
1632
1639
1640
+ module SymSetter
1641
+ def sym_set ( name , val )
1642
+ self [ name . to_sym ] = val
1643
+ end
1644
+ end
1645
+
1633
1646
def parse_in_order ( argv = default_argv , setter = nil , &nonopt ) # :nodoc:
1634
- opt , arg , val , rest = nil
1647
+ opt , arg , val , rest , sub = nil
1635
1648
nonopt ||= proc { |a | throw :terminate , a }
1636
1649
argv . unshift ( arg ) if arg = catch ( :terminate ) {
1637
1650
while arg = argv . shift
@@ -1699,6 +1712,17 @@ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
1699
1712
1700
1713
# non-option argument
1701
1714
else
1715
+ # sub-command
1716
+ if ( key , ( sub , block ) = @subparsers &.complete ( arg ) )
1717
+ block . call if block
1718
+ if setter
1719
+ into = setter . receiver . class . new . extend ( SymSetter )
1720
+ setter . call ( key , into )
1721
+ setter = into . method ( :sym_set )
1722
+ end
1723
+ return sub . parse_in_order ( argv , setter , &nonopt )
1724
+ end
1725
+
1702
1726
catch ( :prune ) do
1703
1727
visit ( :each_option ) do |sw0 |
1704
1728
sw = sw0
@@ -1716,7 +1740,7 @@ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
1716
1740
1717
1741
argv
1718
1742
end
1719
- private :parse_in_order
1743
+ protected :parse_in_order
1720
1744
1721
1745
#
1722
1746
# Parses command line arguments +argv+ in permutation mode and returns
@@ -1735,6 +1759,9 @@ def permute(*argv, into: nil)
1735
1759
# Non-option arguments remain in +argv+.
1736
1760
#
1737
1761
def permute! ( argv = default_argv , into : nil )
1762
+ if @subparsers
1763
+ raise "cannot parse in permutation mode with subparsers"
1764
+ end
1738
1765
nonopts = [ ]
1739
1766
order! ( argv , into : into , &nonopts . method ( :<< ) )
1740
1767
argv [ 0 , 0 ] = nonopts
@@ -1758,7 +1785,7 @@ def parse(*argv, into: nil)
1758
1785
# Non-option arguments remain in +argv+.
1759
1786
#
1760
1787
def parse! ( argv = default_argv , into : nil )
1761
- if ENV . include? ( 'POSIXLY_CORRECT' )
1788
+ if @subparsers or ENV . include? ( 'POSIXLY_CORRECT' )
1762
1789
order! ( argv , into : into )
1763
1790
else
1764
1791
permute! ( argv , into : into )
0 commit comments