rubygems-update 3.2.30 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +163 -4
  3. data/CONTRIBUTING.md +40 -10
  4. data/Manifest.txt +28 -5
  5. data/POLICIES.md +22 -8
  6. data/README.md +9 -7
  7. data/UPGRADING.md +5 -81
  8. data/bin/gem +1 -6
  9. data/bundler/CHANGELOG.md +86 -0
  10. data/bundler/exe/bundle +7 -8
  11. data/bundler/lib/bundler/build_metadata.rb +2 -2
  12. data/bundler/lib/bundler/cli/doctor.rb +3 -2
  13. data/bundler/lib/bundler/cli/gem.rb +70 -8
  14. data/bundler/lib/bundler/cli/info.rb +6 -1
  15. data/bundler/lib/bundler/cli/install.rb +2 -0
  16. data/bundler/lib/bundler/cli/update.rb +2 -2
  17. data/bundler/lib/bundler/cli.rb +9 -1
  18. data/bundler/lib/bundler/compact_index_client/updater.rb +0 -5
  19. data/bundler/lib/bundler/definition.rb +66 -120
  20. data/bundler/lib/bundler/dependency.rb +5 -7
  21. data/bundler/lib/bundler/dsl.rb +18 -30
  22. data/bundler/lib/bundler/endpoint_specification.rb +0 -8
  23. data/bundler/lib/bundler/environment_preserver.rb +4 -1
  24. data/bundler/lib/bundler/fetcher/compact_index.rb +9 -4
  25. data/bundler/lib/bundler/fetcher.rb +2 -5
  26. data/bundler/lib/bundler/gem_helper.rb +2 -2
  27. data/bundler/lib/bundler/injector.rb +10 -1
  28. data/bundler/lib/bundler/installer/gem_installer.rb +1 -6
  29. data/bundler/lib/bundler/installer.rb +1 -4
  30. data/bundler/lib/bundler/lazy_specification.rb +17 -1
  31. data/bundler/lib/bundler/lockfile_parser.rb +10 -12
  32. data/bundler/lib/bundler/man/bundle-add.1 +10 -2
  33. data/bundler/lib/bundler/man/bundle-add.1.ronn +7 -1
  34. data/bundler/lib/bundler/man/bundle-binstubs.1 +1 -1
  35. data/bundler/lib/bundler/man/bundle-cache.1 +1 -1
  36. data/bundler/lib/bundler/man/bundle-check.1 +1 -1
  37. data/bundler/lib/bundler/man/bundle-clean.1 +1 -1
  38. data/bundler/lib/bundler/man/bundle-config.1 +5 -5
  39. data/bundler/lib/bundler/man/bundle-config.1.ronn +5 -5
  40. data/bundler/lib/bundler/man/bundle-doctor.1 +1 -1
  41. data/bundler/lib/bundler/man/bundle-exec.1 +1 -1
  42. data/bundler/lib/bundler/man/bundle-gem.1 +14 -1
  43. data/bundler/lib/bundler/man/bundle-gem.1.ronn +16 -0
  44. data/bundler/lib/bundler/man/bundle-info.1 +1 -1
  45. data/bundler/lib/bundler/man/bundle-init.1 +1 -1
  46. data/bundler/lib/bundler/man/bundle-inject.1 +1 -1
  47. data/bundler/lib/bundler/man/bundle-install.1 +2 -2
  48. data/bundler/lib/bundler/man/bundle-install.1.ronn +2 -2
  49. data/bundler/lib/bundler/man/bundle-list.1 +1 -1
  50. data/bundler/lib/bundler/man/bundle-lock.1 +1 -1
  51. data/bundler/lib/bundler/man/bundle-open.1 +1 -1
  52. data/bundler/lib/bundler/man/bundle-outdated.1 +1 -1
  53. data/bundler/lib/bundler/man/bundle-platform.1 +1 -1
  54. data/bundler/lib/bundler/man/bundle-pristine.1 +1 -1
  55. data/bundler/lib/bundler/man/bundle-remove.1 +1 -1
  56. data/bundler/lib/bundler/man/bundle-show.1 +1 -1
  57. data/bundler/lib/bundler/man/bundle-update.1 +2 -2
  58. data/bundler/lib/bundler/man/bundle-update.1.ronn +2 -1
  59. data/bundler/lib/bundler/man/bundle-viz.1 +1 -1
  60. data/bundler/lib/bundler/man/bundle.1 +1 -1
  61. data/bundler/lib/bundler/man/gemfile.5 +28 -2
  62. data/bundler/lib/bundler/man/gemfile.5.ronn +9 -1
  63. data/bundler/lib/bundler/plugin/api/source.rb +1 -0
  64. data/bundler/lib/bundler/plugin/installer.rb +1 -1
  65. data/bundler/lib/bundler/process_lock.rb +1 -1
  66. data/bundler/lib/bundler/psyched_yaml.rb +1 -13
  67. data/bundler/lib/bundler/resolver.rb +34 -31
  68. data/bundler/lib/bundler/rubygems_ext.rb +2 -0
  69. data/bundler/lib/bundler/rubygems_integration.rb +11 -48
  70. data/bundler/lib/bundler/runtime.rb +1 -1
  71. data/bundler/lib/bundler/self_manager.rb +73 -0
  72. data/bundler/lib/bundler/shared_helpers.rb +4 -12
  73. data/bundler/lib/bundler/source/git/git_proxy.rb +7 -4
  74. data/bundler/lib/bundler/source/metadata.rb +1 -1
  75. data/bundler/lib/bundler/source/rubygems.rb +17 -13
  76. data/bundler/lib/bundler/source/rubygems_aggregate.rb +1 -1
  77. data/bundler/lib/bundler/source.rb +1 -1
  78. data/bundler/lib/bundler/source_list.rb +7 -29
  79. data/bundler/lib/bundler/spec_set.rb +1 -1
  80. data/bundler/lib/bundler/templates/Executable.bundler +1 -1
  81. data/bundler/lib/bundler/templates/Gemfile +0 -2
  82. data/bundler/lib/bundler/templates/gems.rb +0 -3
  83. data/bundler/lib/bundler/templates/newgem/Gemfile.tt +5 -2
  84. data/bundler/lib/bundler/templates/newgem/Rakefile.tt +15 -2
  85. data/bundler/lib/bundler/templates/newgem/github/workflows/main.yml.tt +2 -2
  86. data/bundler/lib/bundler/templates/newgem/newgem.gemspec.tt +13 -13
  87. data/bundler/lib/bundler/templates/newgem/sig/newgem.rbs.tt +8 -0
  88. data/bundler/lib/bundler/templates/newgem/standard.yml.tt +2 -0
  89. data/bundler/lib/bundler/templates/newgem/test/minitest/{newgem_test.rb.tt → test_newgem.rb.tt} +1 -1
  90. data/bundler/lib/bundler/ui/shell.rb +1 -1
  91. data/bundler/lib/bundler/vendor/.document +1 -0
  92. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +2 -2
  93. data/bundler/lib/bundler/vendor/tsort/LICENSE.txt +22 -0
  94. data/bundler/lib/bundler/vendor/tsort/lib/tsort.rb +453 -0
  95. data/bundler/lib/bundler/vendor/uri/lib/uri/common.rb +17 -80
  96. data/bundler/lib/bundler/vendor/uri/lib/uri/ftp.rb +0 -1
  97. data/bundler/lib/bundler/vendor/uri/lib/uri/generic.rb +5 -6
  98. data/bundler/lib/bundler/vendor/uri/lib/uri/http.rb +0 -1
  99. data/bundler/lib/bundler/vendor/uri/lib/uri/https.rb +0 -1
  100. data/bundler/lib/bundler/vendor/uri/lib/uri/ldap.rb +1 -1
  101. data/bundler/lib/bundler/vendor/uri/lib/uri/mailto.rb +0 -1
  102. data/bundler/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +1 -14
  103. data/bundler/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +1 -12
  104. data/bundler/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  105. data/bundler/lib/bundler/vendor/uri/lib/uri/ws.rb +84 -0
  106. data/bundler/lib/bundler/vendor/uri/lib/uri/wss.rb +22 -0
  107. data/bundler/lib/bundler/vendor/uri/lib/uri.rb +0 -1
  108. data/bundler/lib/bundler/vendored_tsort.rb +4 -0
  109. data/bundler/lib/bundler/version.rb +1 -1
  110. data/bundler/lib/bundler.rb +9 -3
  111. data/hide_lib_for_update/note.txt +0 -4
  112. data/lib/rubygems/command.rb +4 -4
  113. data/lib/rubygems/command_manager.rb +4 -2
  114. data/lib/rubygems/commands/cert_command.rb +6 -6
  115. data/lib/rubygems/commands/fetch_command.rb +1 -1
  116. data/lib/rubygems/commands/install_command.rb +5 -2
  117. data/lib/rubygems/commands/pristine_command.rb +8 -2
  118. data/lib/rubygems/commands/server_command.rb +14 -77
  119. data/lib/rubygems/commands/setup_command.rb +84 -76
  120. data/lib/rubygems/commands/uninstall_command.rb +1 -1
  121. data/lib/rubygems/commands/update_command.rb +10 -5
  122. data/lib/rubygems/defaults.rb +2 -20
  123. data/lib/rubygems/dependency_list.rb +2 -2
  124. data/lib/rubygems/deprecate.rb +53 -6
  125. data/lib/rubygems/exceptions.rb +27 -1
  126. data/lib/rubygems/ext/builder.rb +11 -8
  127. data/lib/rubygems/ext/cmake_builder.rb +1 -1
  128. data/lib/rubygems/install_update_options.rb +13 -4
  129. data/lib/rubygems/installer.rb +46 -27
  130. data/lib/rubygems/local_remote_options.rb +3 -3
  131. data/lib/rubygems/name_tuple.rb +2 -3
  132. data/lib/rubygems/optparse/.document +1 -0
  133. data/lib/rubygems/optparse/COPYING +56 -0
  134. data/lib/rubygems/optparse/lib/optionparser.rb +2 -0
  135. data/lib/rubygems/optparse/lib/optparse/ac.rb +54 -0
  136. data/lib/rubygems/optparse/lib/optparse/date.rb +18 -0
  137. data/lib/rubygems/optparse/lib/optparse/kwargs.rb +22 -0
  138. data/lib/rubygems/optparse/lib/optparse/shellwords.rb +7 -0
  139. data/lib/rubygems/optparse/lib/optparse/time.rb +11 -0
  140. data/lib/rubygems/optparse/lib/optparse/uri.rb +7 -0
  141. data/lib/rubygems/optparse/lib/optparse/version.rb +71 -0
  142. data/lib/rubygems/optparse/lib/optparse.rb +2230 -0
  143. data/lib/rubygems/optparse.rb +3 -0
  144. data/lib/rubygems/path_support.rb +1 -6
  145. data/lib/rubygems/platform.rb +4 -0
  146. data/lib/rubygems/remote_fetcher.rb +1 -1
  147. data/lib/rubygems/request_set.rb +2 -2
  148. data/lib/rubygems/requirement.rb +1 -1
  149. data/lib/rubygems/resolver/installer_set.rb +1 -1
  150. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb +2 -2
  151. data/lib/rubygems/security.rb +4 -3
  152. data/lib/rubygems/security_option.rb +3 -3
  153. data/lib/rubygems/source.rb +3 -1
  154. data/lib/rubygems/spec_fetcher.rb +1 -1
  155. data/lib/rubygems/specification.rb +46 -46
  156. data/lib/rubygems/text.rb +21 -20
  157. data/lib/rubygems/tsort/.document +1 -0
  158. data/lib/rubygems/tsort/LICENSE.txt +22 -0
  159. data/lib/rubygems/tsort/lib/tsort.rb +454 -0
  160. data/lib/rubygems/tsort.rb +3 -0
  161. data/lib/rubygems/uninstaller.rb +4 -1
  162. data/lib/rubygems/unknown_command_spell_checker.rb +21 -0
  163. data/lib/rubygems/util/licenses.rb +2 -0
  164. data/lib/rubygems/version.rb +2 -0
  165. data/lib/rubygems/version_option.rb +2 -2
  166. data/lib/rubygems.rb +13 -10
  167. data/rubygems-update.gemspec +1 -1
  168. data/setup.rb +1 -6
  169. data/test/rubygems/encrypted_private_key.pem +26 -26
  170. data/test/rubygems/helper.rb +48 -38
  171. data/test/rubygems/test_config.rb +2 -2
  172. data/test/rubygems/test_exit.rb +11 -0
  173. data/test/rubygems/test_gem.rb +46 -41
  174. data/test/rubygems/test_gem_command.rb +1 -1
  175. data/test/rubygems/test_gem_command_manager.rb +28 -2
  176. data/test/rubygems/test_gem_commands_cert_command.rb +8 -8
  177. data/test/rubygems/test_gem_commands_fetch_command.rb +36 -0
  178. data/test/rubygems/test_gem_commands_open_command.rb +1 -1
  179. data/test/rubygems/test_gem_commands_server_command.rb +4 -46
  180. data/test/rubygems/test_gem_commands_setup_command.rb +67 -19
  181. data/test/rubygems/test_gem_commands_signin_command.rb +1 -1
  182. data/test/rubygems/test_gem_commands_uninstall_command.rb +1 -1
  183. data/test/rubygems/test_gem_commands_update_command.rb +2 -2
  184. data/test/rubygems/test_gem_commands_yank_command.rb +1 -1
  185. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +7 -3
  186. data/test/rubygems/test_gem_install_update_options.rb +2 -2
  187. data/test/rubygems/test_gem_installer.rb +37 -5
  188. data/test/rubygems/test_gem_path_support.rb +2 -6
  189. data/test/rubygems/test_gem_remote_fetcher.rb +15 -0
  190. data/test/rubygems/test_gem_request.rb +10 -4
  191. data/test/rubygems/test_gem_requirement.rb +0 -1
  192. data/test/rubygems/test_gem_resolver.rb +7 -7
  193. data/test/rubygems/test_gem_security.rb +1 -1
  194. data/test/rubygems/test_gem_specification.rb +27 -25
  195. data/test/rubygems/test_gem_text.rb +6 -0
  196. data/test/rubygems/test_project_sanity.rb +1 -1
  197. data/test/rubygems/test_require.rb +8 -35
  198. data/test/rubygems/test_rubygems.rb +23 -0
  199. metadata +31 -8
  200. data/bundler/lib/bundler/gemdeps.rb +0 -29
  201. data/lib/rubygems/server.rb +0 -882
  202. data/test/rubygems/bogussources.rb +0 -9
  203. data/test/rubygems/test_gem_server.rb +0 -608
@@ -0,0 +1,2230 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # optparse.rb - command-line option analysis with the Gem::OptionParser class.
4
+ #
5
+ # Author:: Nobu Nakada
6
+ # Documentation:: Nobu Nakada and Gavin Sinclair.
7
+ #
8
+ # See Gem::OptionParser for documentation.
9
+ #
10
+
11
+
12
+ #--
13
+ # == Developer Documentation (not for RDoc output)
14
+ #
15
+ # === Class tree
16
+ #
17
+ # - Gem::OptionParser:: front end
18
+ # - Gem::OptionParser::Switch:: each switches
19
+ # - Gem::OptionParser::List:: options list
20
+ # - Gem::OptionParser::ParseError:: errors on parsing
21
+ # - Gem::OptionParser::AmbiguousOption
22
+ # - Gem::OptionParser::NeedlessArgument
23
+ # - Gem::OptionParser::MissingArgument
24
+ # - Gem::OptionParser::InvalidOption
25
+ # - Gem::OptionParser::InvalidArgument
26
+ # - Gem::OptionParser::AmbiguousArgument
27
+ #
28
+ # === Object relationship diagram
29
+ #
30
+ # +--------------+
31
+ # | Gem::OptionParser |<>-----+
32
+ # +--------------+ | +--------+
33
+ # | ,-| Switch |
34
+ # on_head -------->+---------------+ / +--------+
35
+ # accept/reject -->| List |<|>-
36
+ # | |<|>- +----------+
37
+ # on ------------->+---------------+ `-| argument |
38
+ # : : | class |
39
+ # +---------------+ |==========|
40
+ # on_tail -------->| | |pattern |
41
+ # +---------------+ |----------|
42
+ # Gem::OptionParser.accept ->| DefaultList | |converter |
43
+ # reject |(shared between| +----------+
44
+ # | all instances)|
45
+ # +---------------+
46
+ #
47
+ #++
48
+ #
49
+ # == Gem::OptionParser
50
+ #
51
+ # === New to \Gem::OptionParser?
52
+ #
53
+ # See the {Tutorial}[./doc/optparse/tutorial_rdoc.html].
54
+ #
55
+ # === Introduction
56
+ #
57
+ # Gem::OptionParser is a class for command-line option analysis. It is much more
58
+ # advanced, yet also easier to use, than GetoptLong, and is a more Ruby-oriented
59
+ # solution.
60
+ #
61
+ # === Features
62
+ #
63
+ # 1. The argument specification and the code to handle it are written in the
64
+ # same place.
65
+ # 2. It can output an option summary; you don't need to maintain this string
66
+ # separately.
67
+ # 3. Optional and mandatory arguments are specified very gracefully.
68
+ # 4. Arguments can be automatically converted to a specified class.
69
+ # 5. Arguments can be restricted to a certain set.
70
+ #
71
+ # All of these features are demonstrated in the examples below. See
72
+ # #make_switch for full documentation.
73
+ #
74
+ # === Minimal example
75
+ #
76
+ # require 'rubygems/optparse/lib/optparse'
77
+ #
78
+ # options = {}
79
+ # Gem::OptionParser.new do |parser|
80
+ # parser.banner = "Usage: example.rb [options]"
81
+ #
82
+ # parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
83
+ # options[:verbose] = v
84
+ # end
85
+ # end.parse!
86
+ #
87
+ # p options
88
+ # p ARGV
89
+ #
90
+ # === Generating Help
91
+ #
92
+ # Gem::OptionParser can be used to automatically generate help for the commands you
93
+ # write:
94
+ #
95
+ # require 'rubygems/optparse/lib/optparse'
96
+ #
97
+ # Options = Struct.new(:name)
98
+ #
99
+ # class Parser
100
+ # def self.parse(options)
101
+ # args = Options.new("world")
102
+ #
103
+ # opt_parser = Gem::OptionParser.new do |parser|
104
+ # parser.banner = "Usage: example.rb [options]"
105
+ #
106
+ # parser.on("-nNAME", "--name=NAME", "Name to say hello to") do |n|
107
+ # args.name = n
108
+ # end
109
+ #
110
+ # parser.on("-h", "--help", "Prints this help") do
111
+ # puts parser
112
+ # exit
113
+ # end
114
+ # end
115
+ #
116
+ # opt_parser.parse!(options)
117
+ # return args
118
+ # end
119
+ # end
120
+ # options = Parser.parse %w[--help]
121
+ #
122
+ # #=>
123
+ # # Usage: example.rb [options]
124
+ # # -n, --name=NAME Name to say hello to
125
+ # # -h, --help Prints this help
126
+ #
127
+ # === Required Arguments
128
+ #
129
+ # For options that require an argument, option specification strings may include an
130
+ # option name in all caps. If an option is used without the required argument,
131
+ # an exception will be raised.
132
+ #
133
+ # require 'rubygems/optparse/lib/optparse'
134
+ #
135
+ # options = {}
136
+ # Gem::OptionParser.new do |parser|
137
+ # parser.on("-r", "--require LIBRARY",
138
+ # "Require the LIBRARY before executing your script") do |lib|
139
+ # puts "You required #{lib}!"
140
+ # end
141
+ # end.parse!
142
+ #
143
+ # Used:
144
+ #
145
+ # $ ruby optparse-test.rb -r
146
+ # optparse-test.rb:9:in `<main>': missing argument: -r (Gem::OptionParser::MissingArgument)
147
+ # $ ruby optparse-test.rb -r my-library
148
+ # You required my-library!
149
+ #
150
+ # === Type Coercion
151
+ #
152
+ # Gem::OptionParser supports the ability to coerce command line arguments
153
+ # into objects for us.
154
+ #
155
+ # Gem::OptionParser comes with a few ready-to-use kinds of type
156
+ # coercion. They are:
157
+ #
158
+ # - Date -- Anything accepted by +Date.parse+
159
+ # - DateTime -- Anything accepted by +DateTime.parse+
160
+ # - Time -- Anything accepted by +Time.httpdate+ or +Time.parse+
161
+ # - URI -- Anything accepted by +URI.parse+
162
+ # - Shellwords -- Anything accepted by +Shellwords.shellwords+
163
+ # - String -- Any non-empty string
164
+ # - Integer -- Any integer. Will convert octal. (e.g. 124, -3, 040)
165
+ # - Float -- Any float. (e.g. 10, 3.14, -100E+13)
166
+ # - Numeric -- Any integer, float, or rational (1, 3.4, 1/3)
167
+ # - DecimalInteger -- Like +Integer+, but no octal format.
168
+ # - OctalInteger -- Like +Integer+, but no decimal format.
169
+ # - DecimalNumeric -- Decimal integer or float.
170
+ # - TrueClass -- Accepts '+, yes, true, -, no, false' and
171
+ # defaults as +true+
172
+ # - FalseClass -- Same as +TrueClass+, but defaults to +false+
173
+ # - Array -- Strings separated by ',' (e.g. 1,2,3)
174
+ # - Regexp -- Regular expressions. Also includes options.
175
+ #
176
+ # We can also add our own coercions, which we will cover below.
177
+ #
178
+ # ==== Using Built-in Conversions
179
+ #
180
+ # As an example, the built-in +Time+ conversion is used. The other built-in
181
+ # conversions behave in the same way.
182
+ # Gem::OptionParser will attempt to parse the argument
183
+ # as a +Time+. If it succeeds, that time will be passed to the
184
+ # handler block. Otherwise, an exception will be raised.
185
+ #
186
+ # require 'rubygems/optparse/lib/optparse'
187
+ # require 'rubygems/optparse/lib/optparse/time'
188
+ # Gem::OptionParser.new do |parser|
189
+ # parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
190
+ # p time
191
+ # end
192
+ # end.parse!
193
+ #
194
+ # Used:
195
+ #
196
+ # $ ruby optparse-test.rb -t nonsense
197
+ # ... invalid argument: -t nonsense (Gem::OptionParser::InvalidArgument)
198
+ # $ ruby optparse-test.rb -t 10-11-12
199
+ # 2010-11-12 00:00:00 -0500
200
+ # $ ruby optparse-test.rb -t 9:30
201
+ # 2014-08-13 09:30:00 -0400
202
+ #
203
+ # ==== Creating Custom Conversions
204
+ #
205
+ # The +accept+ method on Gem::OptionParser may be used to create converters.
206
+ # It specifies which conversion block to call whenever a class is specified.
207
+ # The example below uses it to fetch a +User+ object before the +on+ handler receives it.
208
+ #
209
+ # require 'rubygems/optparse/lib/optparse'
210
+ #
211
+ # User = Struct.new(:id, :name)
212
+ #
213
+ # def find_user id
214
+ # not_found = ->{ raise "No User Found for id #{id}" }
215
+ # [ User.new(1, "Sam"),
216
+ # User.new(2, "Gandalf") ].find(not_found) do |u|
217
+ # u.id == id
218
+ # end
219
+ # end
220
+ #
221
+ # op = Gem::OptionParser.new
222
+ # op.accept(User) do |user_id|
223
+ # find_user user_id.to_i
224
+ # end
225
+ #
226
+ # op.on("--user ID", User) do |user|
227
+ # puts user
228
+ # end
229
+ #
230
+ # op.parse!
231
+ #
232
+ # Used:
233
+ #
234
+ # $ ruby optparse-test.rb --user 1
235
+ # #<struct User id=1, name="Sam">
236
+ # $ ruby optparse-test.rb --user 2
237
+ # #<struct User id=2, name="Gandalf">
238
+ # $ ruby optparse-test.rb --user 3
239
+ # optparse-test.rb:15:in `block in find_user': No User Found for id 3 (RuntimeError)
240
+ #
241
+ # === Store options to a Hash
242
+ #
243
+ # The +into+ option of +order+, +parse+ and so on methods stores command line options into a Hash.
244
+ #
245
+ # require 'rubygems/optparse/lib/optparse'
246
+ #
247
+ # options = {}
248
+ # Gem::OptionParser.new do |parser|
249
+ # parser.on('-a')
250
+ # parser.on('-b NUM', Integer)
251
+ # parser.on('-v', '--verbose')
252
+ # end.parse!(into: options)
253
+ #
254
+ # p options
255
+ #
256
+ # Used:
257
+ #
258
+ # $ ruby optparse-test.rb -a
259
+ # {:a=>true}
260
+ # $ ruby optparse-test.rb -a -v
261
+ # {:a=>true, :verbose=>true}
262
+ # $ ruby optparse-test.rb -a -b 100
263
+ # {:a=>true, :b=>100}
264
+ #
265
+ # === Complete example
266
+ #
267
+ # The following example is a complete Ruby program. You can run it and see the
268
+ # effect of specifying various options. This is probably the best way to learn
269
+ # the features of +optparse+.
270
+ #
271
+ # require 'rubygems/optparse/lib/optparse'
272
+ # require 'rubygems/optparse/lib/optparse/time'
273
+ # require 'ostruct'
274
+ # require 'pp'
275
+ #
276
+ # class OptparseExample
277
+ # Version = '1.0.0'
278
+ #
279
+ # CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
280
+ # CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
281
+ #
282
+ # class ScriptOptions
283
+ # attr_accessor :library, :inplace, :encoding, :transfer_type,
284
+ # :verbose, :extension, :delay, :time, :record_separator,
285
+ # :list
286
+ #
287
+ # def initialize
288
+ # self.library = []
289
+ # self.inplace = false
290
+ # self.encoding = "utf8"
291
+ # self.transfer_type = :auto
292
+ # self.verbose = false
293
+ # end
294
+ #
295
+ # def define_options(parser)
296
+ # parser.banner = "Usage: example.rb [options]"
297
+ # parser.separator ""
298
+ # parser.separator "Specific options:"
299
+ #
300
+ # # add additional options
301
+ # perform_inplace_option(parser)
302
+ # delay_execution_option(parser)
303
+ # execute_at_time_option(parser)
304
+ # specify_record_separator_option(parser)
305
+ # list_example_option(parser)
306
+ # specify_encoding_option(parser)
307
+ # optional_option_argument_with_keyword_completion_option(parser)
308
+ # boolean_verbose_option(parser)
309
+ #
310
+ # parser.separator ""
311
+ # parser.separator "Common options:"
312
+ # # No argument, shows at tail. This will print an options summary.
313
+ # # Try it and see!
314
+ # parser.on_tail("-h", "--help", "Show this message") do
315
+ # puts parser
316
+ # exit
317
+ # end
318
+ # # Another typical switch to print the version.
319
+ # parser.on_tail("--version", "Show version") do
320
+ # puts Version
321
+ # exit
322
+ # end
323
+ # end
324
+ #
325
+ # def perform_inplace_option(parser)
326
+ # # Specifies an optional option argument
327
+ # parser.on("-i", "--inplace [EXTENSION]",
328
+ # "Edit ARGV files in place",
329
+ # "(make backup if EXTENSION supplied)") do |ext|
330
+ # self.inplace = true
331
+ # self.extension = ext || ''
332
+ # self.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot.
333
+ # end
334
+ # end
335
+ #
336
+ # def delay_execution_option(parser)
337
+ # # Cast 'delay' argument to a Float.
338
+ # parser.on("--delay N", Float, "Delay N seconds before executing") do |n|
339
+ # self.delay = n
340
+ # end
341
+ # end
342
+ #
343
+ # def execute_at_time_option(parser)
344
+ # # Cast 'time' argument to a Time object.
345
+ # parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
346
+ # self.time = time
347
+ # end
348
+ # end
349
+ #
350
+ # def specify_record_separator_option(parser)
351
+ # # Cast to octal integer.
352
+ # parser.on("-F", "--irs [OCTAL]", Gem::OptionParser::OctalInteger,
353
+ # "Specify record separator (default \\0)") do |rs|
354
+ # self.record_separator = rs
355
+ # end
356
+ # end
357
+ #
358
+ # def list_example_option(parser)
359
+ # # List of arguments.
360
+ # parser.on("--list x,y,z", Array, "Example 'list' of arguments") do |list|
361
+ # self.list = list
362
+ # end
363
+ # end
364
+ #
365
+ # def specify_encoding_option(parser)
366
+ # # Keyword completion. We are specifying a specific set of arguments (CODES
367
+ # # and CODE_ALIASES - notice the latter is a Hash), and the user may provide
368
+ # # the shortest unambiguous text.
369
+ # code_list = (CODE_ALIASES.keys + CODES).join(', ')
370
+ # parser.on("--code CODE", CODES, CODE_ALIASES, "Select encoding",
371
+ # "(#{code_list})") do |encoding|
372
+ # self.encoding = encoding
373
+ # end
374
+ # end
375
+ #
376
+ # def optional_option_argument_with_keyword_completion_option(parser)
377
+ # # Optional '--type' option argument with keyword completion.
378
+ # parser.on("--type [TYPE]", [:text, :binary, :auto],
379
+ # "Select transfer type (text, binary, auto)") do |t|
380
+ # self.transfer_type = t
381
+ # end
382
+ # end
383
+ #
384
+ # def boolean_verbose_option(parser)
385
+ # # Boolean switch.
386
+ # parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
387
+ # self.verbose = v
388
+ # end
389
+ # end
390
+ # end
391
+ #
392
+ # #
393
+ # # Return a structure describing the options.
394
+ # #
395
+ # def parse(args)
396
+ # # The options specified on the command line will be collected in
397
+ # # *options*.
398
+ #
399
+ # @options = ScriptOptions.new
400
+ # @args = Gem::OptionParser.new do |parser|
401
+ # @options.define_options(parser)
402
+ # parser.parse!(args)
403
+ # end
404
+ # @options
405
+ # end
406
+ #
407
+ # attr_reader :parser, :options
408
+ # end # class OptparseExample
409
+ #
410
+ # example = OptparseExample.new
411
+ # options = example.parse(ARGV)
412
+ # pp options # example.options
413
+ # pp ARGV
414
+ #
415
+ # === Shell Completion
416
+ #
417
+ # For modern shells (e.g. bash, zsh, etc.), you can use shell
418
+ # completion for command line options.
419
+ #
420
+ # === Further documentation
421
+ #
422
+ # The above examples, along with the accompanying
423
+ # {Tutorial}[./doc/optparse/tutorial_rdoc.html],
424
+ # should be enough to learn how to use this class.
425
+ # If you have any questions, file a ticket at http://bugs.ruby-lang.org.
426
+ #
427
+ class Gem::OptionParser
428
+ Gem::OptionParser::Version = "0.2.0"
429
+
430
+ # :stopdoc:
431
+ NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
432
+ RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, true].freeze
433
+ OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, false].freeze
434
+ # :startdoc:
435
+
436
+ #
437
+ # Keyword completion module. This allows partial arguments to be specified
438
+ # and resolved against a list of acceptable values.
439
+ #
440
+ module Completion
441
+ def self.regexp(key, icase)
442
+ Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'), icase)
443
+ end
444
+
445
+ def self.candidate(key, icase = false, pat = nil, &block)
446
+ pat ||= Completion.regexp(key, icase)
447
+ candidates = []
448
+ block.call do |k, *v|
449
+ (if Regexp === k
450
+ kn = ""
451
+ k === key
452
+ else
453
+ kn = defined?(k.id2name) ? k.id2name : k
454
+ pat === kn
455
+ end) or next
456
+ v << k if v.empty?
457
+ candidates << [k, v, kn]
458
+ end
459
+ candidates
460
+ end
461
+
462
+ def candidate(key, icase = false, pat = nil)
463
+ Completion.candidate(key, icase, pat, &method(:each))
464
+ end
465
+
466
+ public
467
+ def complete(key, icase = false, pat = nil)
468
+ candidates = candidate(key, icase, pat, &method(:each)).sort_by {|k, v, kn| kn.size}
469
+ if candidates.size == 1
470
+ canon, sw, * = candidates[0]
471
+ elsif candidates.size > 1
472
+ canon, sw, cn = candidates.shift
473
+ candidates.each do |k, v, kn|
474
+ next if sw == v
475
+ if String === cn and String === kn
476
+ if cn.rindex(kn, 0)
477
+ canon, sw, cn = k, v, kn
478
+ next
479
+ elsif kn.rindex(cn, 0)
480
+ next
481
+ end
482
+ end
483
+ throw :ambiguous, key
484
+ end
485
+ end
486
+ if canon
487
+ block_given? or return key, *sw
488
+ yield(key, *sw)
489
+ end
490
+ end
491
+
492
+ def convert(opt = nil, val = nil, *)
493
+ val
494
+ end
495
+ end
496
+
497
+
498
+ #
499
+ # Map from option/keyword string to object with completion.
500
+ #
501
+ class OptionMap < Hash
502
+ include Completion
503
+ end
504
+
505
+
506
+ #
507
+ # Individual switch class. Not important to the user.
508
+ #
509
+ # Defined within Switch are several Switch-derived classes: NoArgument,
510
+ # RequiredArgument, etc.
511
+ #
512
+ class Switch
513
+ attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block
514
+
515
+ #
516
+ # Guesses argument style from +arg+. Returns corresponding
517
+ # Gem::OptionParser::Switch class (OptionalArgument, etc.).
518
+ #
519
+ def self.guess(arg)
520
+ case arg
521
+ when ""
522
+ t = self
523
+ when /\A=?\[/
524
+ t = Switch::OptionalArgument
525
+ when /\A\s+\[/
526
+ t = Switch::PlacedArgument
527
+ else
528
+ t = Switch::RequiredArgument
529
+ end
530
+ self >= t or incompatible_argument_styles(arg, t)
531
+ t
532
+ end
533
+
534
+ def self.incompatible_argument_styles(arg, t)
535
+ raise(ArgumentError, "#{arg}: incompatible argument styles\n #{self}, #{t}",
536
+ ParseError.filter_backtrace(caller(2)))
537
+ end
538
+
539
+ def self.pattern
540
+ NilClass
541
+ end
542
+
543
+ def initialize(pattern = nil, conv = nil,
544
+ short = nil, long = nil, arg = nil,
545
+ desc = ([] if short or long), block = nil, &_block)
546
+ raise if Array === pattern
547
+ block ||= _block
548
+ @pattern, @conv, @short, @long, @arg, @desc, @block =
549
+ pattern, conv, short, long, arg, desc, block
550
+ end
551
+
552
+ #
553
+ # Parses +arg+ and returns rest of +arg+ and matched portion to the
554
+ # argument pattern. Yields when the pattern doesn't match substring.
555
+ #
556
+ def parse_arg(arg) # :nodoc:
557
+ pattern or return nil, [arg]
558
+ unless m = pattern.match(arg)
559
+ yield(InvalidArgument, arg)
560
+ return arg, []
561
+ end
562
+ if String === m
563
+ m = [s = m]
564
+ else
565
+ m = m.to_a
566
+ s = m[0]
567
+ return nil, m unless String === s
568
+ end
569
+ raise InvalidArgument, arg unless arg.rindex(s, 0)
570
+ return nil, m if s.length == arg.length
571
+ yield(InvalidArgument, arg) # didn't match whole arg
572
+ return arg[s.length..-1], m
573
+ end
574
+ private :parse_arg
575
+
576
+ #
577
+ # Parses argument, converts and returns +arg+, +block+ and result of
578
+ # conversion. Yields at semi-error condition instead of raising an
579
+ # exception.
580
+ #
581
+ def conv_arg(arg, val = []) # :nodoc:
582
+ if conv
583
+ val = conv.call(*val)
584
+ else
585
+ val = proc {|v| v}.call(*val)
586
+ end
587
+ return arg, block, val
588
+ end
589
+ private :conv_arg
590
+
591
+ #
592
+ # Produces the summary text. Each line of the summary is yielded to the
593
+ # block (without newline).
594
+ #
595
+ # +sdone+:: Already summarized short style options keyed hash.
596
+ # +ldone+:: Already summarized long style options keyed hash.
597
+ # +width+:: Width of left side (option part). In other words, the right
598
+ # side (description part) starts after +width+ columns.
599
+ # +max+:: Maximum width of left side -> the options are filled within
600
+ # +max+ columns.
601
+ # +indent+:: Prefix string indents all summarized lines.
602
+ #
603
+ def summarize(sdone = {}, ldone = {}, width = 1, max = width - 1, indent = "")
604
+ sopts, lopts = [], [], nil
605
+ @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
606
+ @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
607
+ return if sopts.empty? and lopts.empty? # completely hidden
608
+
609
+ left = [sopts.join(', ')]
610
+ right = desc.dup
611
+
612
+ while s = lopts.shift
613
+ l = left[-1].length + s.length
614
+ l += arg.length if left.size == 1 && arg
615
+ l < max or sopts.empty? or left << +''
616
+ left[-1] << (left[-1].empty? ? ' ' * 4 : ', ') << s
617
+ end
618
+
619
+ if arg
620
+ left[0] << (left[1] ? arg.sub(/\A(\[?)=/, '\1') + ',' : arg)
621
+ end
622
+ mlen = left.collect {|ss| ss.length}.max.to_i
623
+ while mlen > width and l = left.shift
624
+ mlen = left.collect {|ss| ss.length}.max.to_i if l.length == mlen
625
+ if l.length < width and (r = right[0]) and !r.empty?
626
+ l = l.to_s.ljust(width) + ' ' + r
627
+ right.shift
628
+ end
629
+ yield(indent + l)
630
+ end
631
+
632
+ while begin l = left.shift; r = right.shift; l or r end
633
+ l = l.to_s.ljust(width) + ' ' + r if r and !r.empty?
634
+ yield(indent + l)
635
+ end
636
+
637
+ self
638
+ end
639
+
640
+ def add_banner(to) # :nodoc:
641
+ unless @short or @long
642
+ s = desc.join
643
+ to << " [" + s + "]..." unless s.empty?
644
+ end
645
+ to
646
+ end
647
+
648
+ def match_nonswitch?(str) # :nodoc:
649
+ @pattern =~ str unless @short or @long
650
+ end
651
+
652
+ #
653
+ # Main name of the switch.
654
+ #
655
+ def switch_name
656
+ (long.first || short.first).sub(/\A-+(?:\[no-\])?/, '')
657
+ end
658
+
659
+ def compsys(sdone, ldone) # :nodoc:
660
+ sopts, lopts = [], []
661
+ @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
662
+ @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
663
+ return if sopts.empty? and lopts.empty? # completely hidden
664
+
665
+ (sopts+lopts).each do |opt|
666
+ # "(-x -c -r)-l[left justify]"
667
+ if /^--\[no-\](.+)$/ =~ opt
668
+ o = $1
669
+ yield("--#{o}", desc.join(""))
670
+ yield("--no-#{o}", desc.join(""))
671
+ else
672
+ yield("#{opt}", desc.join(""))
673
+ end
674
+ end
675
+ end
676
+
677
+ #
678
+ # Switch that takes no arguments.
679
+ #
680
+ class NoArgument < self
681
+
682
+ #
683
+ # Raises an exception if any arguments given.
684
+ #
685
+ def parse(arg, argv)
686
+ yield(NeedlessArgument, arg) if arg
687
+ conv_arg(arg)
688
+ end
689
+
690
+ def self.incompatible_argument_styles(*)
691
+ end
692
+
693
+ def self.pattern
694
+ Object
695
+ end
696
+ end
697
+
698
+ #
699
+ # Switch that takes an argument.
700
+ #
701
+ class RequiredArgument < self
702
+
703
+ #
704
+ # Raises an exception if argument is not present.
705
+ #
706
+ def parse(arg, argv)
707
+ unless arg
708
+ raise MissingArgument if argv.empty?
709
+ arg = argv.shift
710
+ end
711
+ conv_arg(*parse_arg(arg, &method(:raise)))
712
+ end
713
+ end
714
+
715
+ #
716
+ # Switch that can omit argument.
717
+ #
718
+ class OptionalArgument < self
719
+
720
+ #
721
+ # Parses argument if given, or uses default value.
722
+ #
723
+ def parse(arg, argv, &error)
724
+ if arg
725
+ conv_arg(*parse_arg(arg, &error))
726
+ else
727
+ conv_arg(arg)
728
+ end
729
+ end
730
+ end
731
+
732
+ #
733
+ # Switch that takes an argument, which does not begin with '-'.
734
+ #
735
+ class PlacedArgument < self
736
+
737
+ #
738
+ # Returns nil if argument is not present or begins with '-'.
739
+ #
740
+ def parse(arg, argv, &error)
741
+ if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0]))
742
+ return nil, block, nil
743
+ end
744
+ opt = (val = parse_arg(val, &error))[1]
745
+ val = conv_arg(*val)
746
+ if opt and !arg
747
+ argv.shift
748
+ else
749
+ val[0] = nil
750
+ end
751
+ val
752
+ end
753
+ end
754
+ end
755
+
756
+ #
757
+ # Simple option list providing mapping from short and/or long option
758
+ # string to Gem::OptionParser::Switch and mapping from acceptable argument to
759
+ # matching pattern and converter pair. Also provides summary feature.
760
+ #
761
+ class List
762
+ # Map from acceptable argument types to pattern and converter pairs.
763
+ attr_reader :atype
764
+
765
+ # Map from short style option switches to actual switch objects.
766
+ attr_reader :short
767
+
768
+ # Map from long style option switches to actual switch objects.
769
+ attr_reader :long
770
+
771
+ # List of all switches and summary string.
772
+ attr_reader :list
773
+
774
+ #
775
+ # Just initializes all instance variables.
776
+ #
777
+ def initialize
778
+ @atype = {}
779
+ @short = OptionMap.new
780
+ @long = OptionMap.new
781
+ @list = []
782
+ end
783
+
784
+ #
785
+ # See Gem::OptionParser.accept.
786
+ #
787
+ def accept(t, pat = /.*/m, &block)
788
+ if pat
789
+ pat.respond_to?(:match) or
790
+ raise TypeError, "has no `match'", ParseError.filter_backtrace(caller(2))
791
+ else
792
+ pat = t if t.respond_to?(:match)
793
+ end
794
+ unless block
795
+ block = pat.method(:convert).to_proc if pat.respond_to?(:convert)
796
+ end
797
+ @atype[t] = [pat, block]
798
+ end
799
+
800
+ #
801
+ # See Gem::OptionParser.reject.
802
+ #
803
+ def reject(t)
804
+ @atype.delete(t)
805
+ end
806
+
807
+ #
808
+ # Adds +sw+ according to +sopts+, +lopts+ and +nlopts+.
809
+ #
810
+ # +sw+:: Gem::OptionParser::Switch instance to be added.
811
+ # +sopts+:: Short style option list.
812
+ # +lopts+:: Long style option list.
813
+ # +nlopts+:: Negated long style options list.
814
+ #
815
+ def update(sw, sopts, lopts, nsw = nil, nlopts = nil) # :nodoc:
816
+ sopts.each {|o| @short[o] = sw} if sopts
817
+ lopts.each {|o| @long[o] = sw} if lopts
818
+ nlopts.each {|o| @long[o] = nsw} if nsw and nlopts
819
+ used = @short.invert.update(@long.invert)
820
+ @list.delete_if {|o| Switch === o and !used[o]}
821
+ end
822
+ private :update
823
+
824
+ #
825
+ # Inserts +switch+ at the head of the list, and associates short, long
826
+ # and negated long options. Arguments are:
827
+ #
828
+ # +switch+:: Gem::OptionParser::Switch instance to be inserted.
829
+ # +short_opts+:: List of short style options.
830
+ # +long_opts+:: List of long style options.
831
+ # +nolong_opts+:: List of long style options with "no-" prefix.
832
+ #
833
+ # prepend(switch, short_opts, long_opts, nolong_opts)
834
+ #
835
+ def prepend(*args)
836
+ update(*args)
837
+ @list.unshift(args[0])
838
+ end
839
+
840
+ #
841
+ # Appends +switch+ at the tail of the list, and associates short, long
842
+ # and negated long options. Arguments are:
843
+ #
844
+ # +switch+:: Gem::OptionParser::Switch instance to be inserted.
845
+ # +short_opts+:: List of short style options.
846
+ # +long_opts+:: List of long style options.
847
+ # +nolong_opts+:: List of long style options with "no-" prefix.
848
+ #
849
+ # append(switch, short_opts, long_opts, nolong_opts)
850
+ #
851
+ def append(*args)
852
+ update(*args)
853
+ @list.push(args[0])
854
+ end
855
+
856
+ #
857
+ # Searches +key+ in +id+ list. The result is returned or yielded if a
858
+ # block is given. If it isn't found, nil is returned.
859
+ #
860
+ def search(id, key)
861
+ if list = __send__(id)
862
+ val = list.fetch(key) {return nil}
863
+ block_given? ? yield(val) : val
864
+ end
865
+ end
866
+
867
+ #
868
+ # Searches list +id+ for +opt+ and the optional patterns for completion
869
+ # +pat+. If +icase+ is true, the search is case insensitive. The result
870
+ # is returned or yielded if a block is given. If it isn't found, nil is
871
+ # returned.
872
+ #
873
+ def complete(id, opt, icase = false, *pat, &block)
874
+ __send__(id).complete(opt, icase, *pat, &block)
875
+ end
876
+
877
+ def get_candidates(id)
878
+ yield __send__(id).keys
879
+ end
880
+
881
+ #
882
+ # Iterates over each option, passing the option to the +block+.
883
+ #
884
+ def each_option(&block)
885
+ list.each(&block)
886
+ end
887
+
888
+ #
889
+ # Creates the summary table, passing each line to the +block+ (without
890
+ # newline). The arguments +args+ are passed along to the summarize
891
+ # method which is called on every option.
892
+ #
893
+ def summarize(*args, &block)
894
+ sum = []
895
+ list.reverse_each do |opt|
896
+ if opt.respond_to?(:summarize) # perhaps Gem::OptionParser::Switch
897
+ s = []
898
+ opt.summarize(*args) {|l| s << l}
899
+ sum.concat(s.reverse)
900
+ elsif !opt or opt.empty?
901
+ sum << ""
902
+ elsif opt.respond_to?(:each_line)
903
+ sum.concat([*opt.each_line].reverse)
904
+ else
905
+ sum.concat([*opt.each].reverse)
906
+ end
907
+ end
908
+ sum.reverse_each(&block)
909
+ end
910
+
911
+ def add_banner(to) # :nodoc:
912
+ list.each do |opt|
913
+ if opt.respond_to?(:add_banner)
914
+ opt.add_banner(to)
915
+ end
916
+ end
917
+ to
918
+ end
919
+
920
+ def compsys(*args, &block) # :nodoc:
921
+ list.each do |opt|
922
+ if opt.respond_to?(:compsys)
923
+ opt.compsys(*args, &block)
924
+ end
925
+ end
926
+ end
927
+ end
928
+
929
+ #
930
+ # Hash with completion search feature. See Gem::OptionParser::Completion.
931
+ #
932
+ class CompletingHash < Hash
933
+ include Completion
934
+
935
+ #
936
+ # Completion for hash key.
937
+ #
938
+ def match(key)
939
+ *values = fetch(key) {
940
+ raise AmbiguousArgument, catch(:ambiguous) {return complete(key)}
941
+ }
942
+ return key, *values
943
+ end
944
+ end
945
+
946
+ # :stopdoc:
947
+
948
+ #
949
+ # Enumeration of acceptable argument styles. Possible values are:
950
+ #
951
+ # NO_ARGUMENT:: The switch takes no arguments. (:NONE)
952
+ # REQUIRED_ARGUMENT:: The switch requires an argument. (:REQUIRED)
953
+ # OPTIONAL_ARGUMENT:: The switch requires an optional argument. (:OPTIONAL)
954
+ #
955
+ # Use like --switch=argument (long style) or -Xargument (short style). For
956
+ # short style, only portion matched to argument pattern is treated as
957
+ # argument.
958
+ #
959
+ ArgumentStyle = {}
960
+ NoArgument.each {|el| ArgumentStyle[el] = Switch::NoArgument}
961
+ RequiredArgument.each {|el| ArgumentStyle[el] = Switch::RequiredArgument}
962
+ OptionalArgument.each {|el| ArgumentStyle[el] = Switch::OptionalArgument}
963
+ ArgumentStyle.freeze
964
+
965
+ #
966
+ # Switches common used such as '--', and also provides default
967
+ # argument classes
968
+ #
969
+ DefaultList = List.new
970
+ DefaultList.short['-'] = Switch::NoArgument.new {}
971
+ DefaultList.long[''] = Switch::NoArgument.new {throw :terminate}
972
+
973
+
974
+ COMPSYS_HEADER = <<'XXX' # :nodoc:
975
+
976
+ typeset -A opt_args
977
+ local context state line
978
+
979
+ _arguments -s -S \
980
+ XXX
981
+
982
+ def compsys(to, name = File.basename($0)) # :nodoc:
983
+ to << "#compdef #{name}\n"
984
+ to << COMPSYS_HEADER
985
+ visit(:compsys, {}, {}) {|o, d|
986
+ to << %Q[ "#{o}[#{d.gsub(/[\"\[\]]/, '\\\\\&')}]" \\\n]
987
+ }
988
+ to << " '*:file:_files' && return 0\n"
989
+ end
990
+
991
+ #
992
+ # Default options for ARGV, which never appear in option summary.
993
+ #
994
+ Officious = {}
995
+
996
+ #
997
+ # --help
998
+ # Shows option summary.
999
+ #
1000
+ Officious['help'] = proc do |parser|
1001
+ Switch::NoArgument.new do |arg|
1002
+ puts parser.help
1003
+ exit
1004
+ end
1005
+ end
1006
+
1007
+ #
1008
+ # --*-completion-bash=WORD
1009
+ # Shows candidates for command line completion.
1010
+ #
1011
+ Officious['*-completion-bash'] = proc do |parser|
1012
+ Switch::RequiredArgument.new do |arg|
1013
+ puts parser.candidate(arg)
1014
+ exit
1015
+ end
1016
+ end
1017
+
1018
+ #
1019
+ # --*-completion-zsh[=NAME:FILE]
1020
+ # Creates zsh completion file.
1021
+ #
1022
+ Officious['*-completion-zsh'] = proc do |parser|
1023
+ Switch::OptionalArgument.new do |arg|
1024
+ parser.compsys(STDOUT, arg)
1025
+ exit
1026
+ end
1027
+ end
1028
+
1029
+ #
1030
+ # --version
1031
+ # Shows version string if Version is defined.
1032
+ #
1033
+ Officious['version'] = proc do |parser|
1034
+ Switch::OptionalArgument.new do |pkg|
1035
+ if pkg
1036
+ begin
1037
+ require 'rubygems/optparse/lib/optparse/version'
1038
+ rescue LoadError
1039
+ else
1040
+ show_version(*pkg.split(/,/)) or
1041
+ abort("#{parser.program_name}: no version found in package #{pkg}")
1042
+ exit
1043
+ end
1044
+ end
1045
+ v = parser.ver or abort("#{parser.program_name}: version unknown")
1046
+ puts v
1047
+ exit
1048
+ end
1049
+ end
1050
+
1051
+ # :startdoc:
1052
+
1053
+ #
1054
+ # Class methods
1055
+ #
1056
+
1057
+ #
1058
+ # Initializes a new instance and evaluates the optional block in context
1059
+ # of the instance. Arguments +args+ are passed to #new, see there for
1060
+ # description of parameters.
1061
+ #
1062
+ # This method is *deprecated*, its behavior corresponds to the older #new
1063
+ # method.
1064
+ #
1065
+ def self.with(*args, &block)
1066
+ opts = new(*args)
1067
+ opts.instance_eval(&block)
1068
+ opts
1069
+ end
1070
+
1071
+ #
1072
+ # Returns an incremented value of +default+ according to +arg+.
1073
+ #
1074
+ def self.inc(arg, default = nil)
1075
+ case arg
1076
+ when Integer
1077
+ arg.nonzero?
1078
+ when nil
1079
+ default.to_i + 1
1080
+ end
1081
+ end
1082
+ def inc(*args)
1083
+ self.class.inc(*args)
1084
+ end
1085
+
1086
+ #
1087
+ # Initializes the instance and yields itself if called with a block.
1088
+ #
1089
+ # +banner+:: Banner message.
1090
+ # +width+:: Summary width.
1091
+ # +indent+:: Summary indent.
1092
+ #
1093
+ def initialize(banner = nil, width = 32, indent = ' ' * 4)
1094
+ @stack = [DefaultList, List.new, List.new]
1095
+ @program_name = nil
1096
+ @banner = banner
1097
+ @summary_width = width
1098
+ @summary_indent = indent
1099
+ @default_argv = ARGV
1100
+ @require_exact = false
1101
+ add_officious
1102
+ yield self if block_given?
1103
+ end
1104
+
1105
+ def add_officious # :nodoc:
1106
+ list = base()
1107
+ Officious.each do |opt, block|
1108
+ list.long[opt] ||= block.call(self)
1109
+ end
1110
+ end
1111
+
1112
+ #
1113
+ # Terminates option parsing. Optional parameter +arg+ is a string pushed
1114
+ # back to be the first non-option argument.
1115
+ #
1116
+ def terminate(arg = nil)
1117
+ self.class.terminate(arg)
1118
+ end
1119
+ def self.terminate(arg = nil)
1120
+ throw :terminate, arg
1121
+ end
1122
+
1123
+ @stack = [DefaultList]
1124
+ def self.top() DefaultList end
1125
+
1126
+ #
1127
+ # Directs to accept specified class +t+. The argument string is passed to
1128
+ # the block in which it should be converted to the desired class.
1129
+ #
1130
+ # +t+:: Argument class specifier, any object including Class.
1131
+ # +pat+:: Pattern for argument, defaults to +t+ if it responds to match.
1132
+ #
1133
+ # accept(t, pat, &block)
1134
+ #
1135
+ def accept(*args, &blk) top.accept(*args, &blk) end
1136
+ #
1137
+ # See #accept.
1138
+ #
1139
+ def self.accept(*args, &blk) top.accept(*args, &blk) end
1140
+
1141
+ #
1142
+ # Directs to reject specified class argument.
1143
+ #
1144
+ # +t+:: Argument class specifier, any object including Class.
1145
+ #
1146
+ # reject(t)
1147
+ #
1148
+ def reject(*args, &blk) top.reject(*args, &blk) end
1149
+ #
1150
+ # See #reject.
1151
+ #
1152
+ def self.reject(*args, &blk) top.reject(*args, &blk) end
1153
+
1154
+ #
1155
+ # Instance methods
1156
+ #
1157
+
1158
+ # Heading banner preceding summary.
1159
+ attr_writer :banner
1160
+
1161
+ # Program name to be emitted in error message and default banner,
1162
+ # defaults to $0.
1163
+ attr_writer :program_name
1164
+
1165
+ # Width for option list portion of summary. Must be Numeric.
1166
+ attr_accessor :summary_width
1167
+
1168
+ # Indentation for summary. Must be String (or have + String method).
1169
+ attr_accessor :summary_indent
1170
+
1171
+ # Strings to be parsed in default.
1172
+ attr_accessor :default_argv
1173
+
1174
+ # Whether to require that options match exactly (disallows providing
1175
+ # abbreviated long option as short option).
1176
+ attr_accessor :require_exact
1177
+
1178
+ #
1179
+ # Heading banner preceding summary.
1180
+ #
1181
+ def banner
1182
+ unless @banner
1183
+ @banner = +"Usage: #{program_name} [options]"
1184
+ visit(:add_banner, @banner)
1185
+ end
1186
+ @banner
1187
+ end
1188
+
1189
+ #
1190
+ # Program name to be emitted in error message and default banner, defaults
1191
+ # to $0.
1192
+ #
1193
+ def program_name
1194
+ @program_name || File.basename($0, '.*')
1195
+ end
1196
+
1197
+ # for experimental cascading :-)
1198
+ alias set_banner banner=
1199
+ alias set_program_name program_name=
1200
+ alias set_summary_width summary_width=
1201
+ alias set_summary_indent summary_indent=
1202
+
1203
+ # Version
1204
+ attr_writer :version
1205
+ # Release code
1206
+ attr_writer :release
1207
+
1208
+ #
1209
+ # Version
1210
+ #
1211
+ def version
1212
+ (defined?(@version) && @version) || (defined?(::Version) && ::Version)
1213
+ end
1214
+
1215
+ #
1216
+ # Release code
1217
+ #
1218
+ def release
1219
+ (defined?(@release) && @release) || (defined?(::Release) && ::Release) || (defined?(::RELEASE) && ::RELEASE)
1220
+ end
1221
+
1222
+ #
1223
+ # Returns version string from program_name, version and release.
1224
+ #
1225
+ def ver
1226
+ if v = version
1227
+ str = +"#{program_name} #{[v].join('.')}"
1228
+ str << " (#{v})" if v = release
1229
+ str
1230
+ end
1231
+ end
1232
+
1233
+ def warn(mesg = $!)
1234
+ super("#{program_name}: #{mesg}")
1235
+ end
1236
+
1237
+ def abort(mesg = $!)
1238
+ super("#{program_name}: #{mesg}")
1239
+ end
1240
+
1241
+ #
1242
+ # Subject of #on / #on_head, #accept / #reject
1243
+ #
1244
+ def top
1245
+ @stack[-1]
1246
+ end
1247
+
1248
+ #
1249
+ # Subject of #on_tail.
1250
+ #
1251
+ def base
1252
+ @stack[1]
1253
+ end
1254
+
1255
+ #
1256
+ # Pushes a new List.
1257
+ #
1258
+ def new
1259
+ @stack.push(List.new)
1260
+ if block_given?
1261
+ yield self
1262
+ else
1263
+ self
1264
+ end
1265
+ end
1266
+
1267
+ #
1268
+ # Removes the last List.
1269
+ #
1270
+ def remove
1271
+ @stack.pop
1272
+ end
1273
+
1274
+ #
1275
+ # Puts option summary into +to+ and returns +to+. Yields each line if
1276
+ # a block is given.
1277
+ #
1278
+ # +to+:: Output destination, which must have method <<. Defaults to [].
1279
+ # +width+:: Width of left side, defaults to @summary_width.
1280
+ # +max+:: Maximum length allowed for left side, defaults to +width+ - 1.
1281
+ # +indent+:: Indentation, defaults to @summary_indent.
1282
+ #
1283
+ def summarize(to = [], width = @summary_width, max = width - 1, indent = @summary_indent, &blk)
1284
+ nl = "\n"
1285
+ blk ||= proc {|l| to << (l.index(nl, -1) ? l : l + nl)}
1286
+ visit(:summarize, {}, {}, width, max, indent, &blk)
1287
+ to
1288
+ end
1289
+
1290
+ #
1291
+ # Returns option summary string.
1292
+ #
1293
+ def help; summarize("#{banner}".sub(/\n?\z/, "\n")) end
1294
+ alias to_s help
1295
+
1296
+ #
1297
+ # Returns option summary list.
1298
+ #
1299
+ def to_a; summarize("#{banner}".split(/^/)) end
1300
+
1301
+ #
1302
+ # Checks if an argument is given twice, in which case an ArgumentError is
1303
+ # raised. Called from Gem::OptionParser#switch only.
1304
+ #
1305
+ # +obj+:: New argument.
1306
+ # +prv+:: Previously specified argument.
1307
+ # +msg+:: Exception message.
1308
+ #
1309
+ def notwice(obj, prv, msg) # :nodoc:
1310
+ unless !prv or prv == obj
1311
+ raise(ArgumentError, "argument #{msg} given twice: #{obj}",
1312
+ ParseError.filter_backtrace(caller(2)))
1313
+ end
1314
+ obj
1315
+ end
1316
+ private :notwice
1317
+
1318
+ SPLAT_PROC = proc {|*a| a.length <= 1 ? a.first : a} # :nodoc:
1319
+
1320
+ # :call-seq:
1321
+ # make_switch(params, block = nil)
1322
+ #
1323
+ # :include: ../doc/optparse/creates_option.rdoc
1324
+ #
1325
+ def make_switch(opts, block = nil)
1326
+ short, long, nolong, style, pattern, conv, not_pattern, not_conv, not_style = [], [], []
1327
+ ldesc, sdesc, desc, arg = [], [], []
1328
+ default_style = Switch::NoArgument
1329
+ default_pattern = nil
1330
+ klass = nil
1331
+ q, a = nil
1332
+ has_arg = false
1333
+
1334
+ opts.each do |o|
1335
+ # argument class
1336
+ next if search(:atype, o) do |pat, c|
1337
+ klass = notwice(o, klass, 'type')
1338
+ if not_style and not_style != Switch::NoArgument
1339
+ not_pattern, not_conv = pat, c
1340
+ else
1341
+ default_pattern, conv = pat, c
1342
+ end
1343
+ end
1344
+
1345
+ # directly specified pattern(any object possible to match)
1346
+ if (!(String === o || Symbol === o)) and o.respond_to?(:match)
1347
+ pattern = notwice(o, pattern, 'pattern')
1348
+ if pattern.respond_to?(:convert)
1349
+ conv = pattern.method(:convert).to_proc
1350
+ else
1351
+ conv = SPLAT_PROC
1352
+ end
1353
+ next
1354
+ end
1355
+
1356
+ # anything others
1357
+ case o
1358
+ when Proc, Method
1359
+ block = notwice(o, block, 'block')
1360
+ when Array, Hash
1361
+ case pattern
1362
+ when CompletingHash
1363
+ when nil
1364
+ pattern = CompletingHash.new
1365
+ conv = pattern.method(:convert).to_proc if pattern.respond_to?(:convert)
1366
+ else
1367
+ raise ArgumentError, "argument pattern given twice"
1368
+ end
1369
+ o.each {|pat, *v| pattern[pat] = v.fetch(0) {pat}}
1370
+ when Module
1371
+ raise ArgumentError, "unsupported argument type: #{o}", ParseError.filter_backtrace(caller(4))
1372
+ when *ArgumentStyle.keys
1373
+ style = notwice(ArgumentStyle[o], style, 'style')
1374
+ when /^--no-([^\[\]=\s]*)(.+)?/
1375
+ q, a = $1, $2
1376
+ o = notwice(a ? Object : TrueClass, klass, 'type')
1377
+ not_pattern, not_conv = search(:atype, o) unless not_style
1378
+ not_style = (not_style || default_style).guess(arg = a) if a
1379
+ default_style = Switch::NoArgument
1380
+ default_pattern, conv = search(:atype, FalseClass) unless default_pattern
1381
+ ldesc << "--no-#{q}"
1382
+ (q = q.downcase).tr!('_', '-')
1383
+ long << "no-#{q}"
1384
+ nolong << q
1385
+ when /^--\[no-\]([^\[\]=\s]*)(.+)?/
1386
+ q, a = $1, $2
1387
+ o = notwice(a ? Object : TrueClass, klass, 'type')
1388
+ if a
1389
+ default_style = default_style.guess(arg = a)
1390
+ default_pattern, conv = search(:atype, o) unless default_pattern
1391
+ end
1392
+ ldesc << "--[no-]#{q}"
1393
+ (o = q.downcase).tr!('_', '-')
1394
+ long << o
1395
+ not_pattern, not_conv = search(:atype, FalseClass) unless not_style
1396
+ not_style = Switch::NoArgument
1397
+ nolong << "no-#{o}"
1398
+ when /^--([^\[\]=\s]*)(.+)?/
1399
+ q, a = $1, $2
1400
+ if a
1401
+ o = notwice(NilClass, klass, 'type')
1402
+ default_style = default_style.guess(arg = a)
1403
+ default_pattern, conv = search(:atype, o) unless default_pattern
1404
+ end
1405
+ ldesc << "--#{q}"
1406
+ (o = q.downcase).tr!('_', '-')
1407
+ long << o
1408
+ when /^-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/
1409
+ q, a = $1, $2
1410
+ o = notwice(Object, klass, 'type')
1411
+ if a
1412
+ default_style = default_style.guess(arg = a)
1413
+ default_pattern, conv = search(:atype, o) unless default_pattern
1414
+ else
1415
+ has_arg = true
1416
+ end
1417
+ sdesc << "-#{q}"
1418
+ short << Regexp.new(q)
1419
+ when /^-(.)(.+)?/
1420
+ q, a = $1, $2
1421
+ if a
1422
+ o = notwice(NilClass, klass, 'type')
1423
+ default_style = default_style.guess(arg = a)
1424
+ default_pattern, conv = search(:atype, o) unless default_pattern
1425
+ end
1426
+ sdesc << "-#{q}"
1427
+ short << q
1428
+ when /^=/
1429
+ style = notwice(default_style.guess(arg = o), style, 'style')
1430
+ default_pattern, conv = search(:atype, Object) unless default_pattern
1431
+ else
1432
+ desc.push(o)
1433
+ end
1434
+ end
1435
+
1436
+ default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern
1437
+ if !(short.empty? and long.empty?)
1438
+ if has_arg and default_style == Switch::NoArgument
1439
+ default_style = Switch::RequiredArgument
1440
+ end
1441
+ s = (style || default_style).new(pattern || default_pattern,
1442
+ conv, sdesc, ldesc, arg, desc, block)
1443
+ elsif !block
1444
+ if style or pattern
1445
+ raise ArgumentError, "no switch given", ParseError.filter_backtrace(caller)
1446
+ end
1447
+ s = desc
1448
+ else
1449
+ short << pattern
1450
+ s = (style || default_style).new(pattern,
1451
+ conv, nil, nil, arg, desc, block)
1452
+ end
1453
+ return s, short, long,
1454
+ (not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style),
1455
+ nolong
1456
+ end
1457
+
1458
+ # :call-seq:
1459
+ # define(*params, &block)
1460
+ #
1461
+ # :include: ../doc/optparse/creates_option.rdoc
1462
+ #
1463
+ def define(*opts, &block)
1464
+ top.append(*(sw = make_switch(opts, block)))
1465
+ sw[0]
1466
+ end
1467
+
1468
+ # :call-seq:
1469
+ # on(*params, &block)
1470
+ #
1471
+ # :include: ../doc/optparse/creates_option.rdoc
1472
+ #
1473
+ def on(*opts, &block)
1474
+ define(*opts, &block)
1475
+ self
1476
+ end
1477
+ alias def_option define
1478
+
1479
+ # :call-seq:
1480
+ # define_head(*params, &block)
1481
+ #
1482
+ # :include: ../doc/optparse/creates_option.rdoc
1483
+ #
1484
+ def define_head(*opts, &block)
1485
+ top.prepend(*(sw = make_switch(opts, block)))
1486
+ sw[0]
1487
+ end
1488
+
1489
+ # :call-seq:
1490
+ # on_head(*params, &block)
1491
+ #
1492
+ # :include: ../doc/optparse/creates_option.rdoc
1493
+ #
1494
+ # The new option is added at the head of the summary.
1495
+ #
1496
+ def on_head(*opts, &block)
1497
+ define_head(*opts, &block)
1498
+ self
1499
+ end
1500
+ alias def_head_option define_head
1501
+
1502
+ # :call-seq:
1503
+ # define_tail(*params, &block)
1504
+ #
1505
+ # :include: ../doc/optparse/creates_option.rdoc
1506
+ #
1507
+ def define_tail(*opts, &block)
1508
+ base.append(*(sw = make_switch(opts, block)))
1509
+ sw[0]
1510
+ end
1511
+
1512
+ #
1513
+ # :call-seq:
1514
+ # on_tail(*params, &block)
1515
+ #
1516
+ # :include: ../doc/optparse/creates_option.rdoc
1517
+ #
1518
+ # The new option is added at the tail of the summary.
1519
+ #
1520
+ def on_tail(*opts, &block)
1521
+ define_tail(*opts, &block)
1522
+ self
1523
+ end
1524
+ alias def_tail_option define_tail
1525
+
1526
+ #
1527
+ # Add separator in summary.
1528
+ #
1529
+ def separator(string)
1530
+ top.append(string, nil, nil)
1531
+ end
1532
+
1533
+ #
1534
+ # Parses command line arguments +argv+ in order. When a block is given,
1535
+ # each non-option argument is yielded. When optional +into+ keyword
1536
+ # argument is provided, the parsed option values are stored there via
1537
+ # <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
1538
+ # similar object).
1539
+ #
1540
+ # Returns the rest of +argv+ left unparsed.
1541
+ #
1542
+ def order(*argv, into: nil, &nonopt)
1543
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
1544
+ order!(argv, into: into, &nonopt)
1545
+ end
1546
+
1547
+ #
1548
+ # Same as #order, but removes switches destructively.
1549
+ # Non-option arguments remain in +argv+.
1550
+ #
1551
+ def order!(argv = default_argv, into: nil, &nonopt)
1552
+ setter = ->(name, val) {into[name.to_sym] = val} if into
1553
+ parse_in_order(argv, setter, &nonopt)
1554
+ end
1555
+
1556
+ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
1557
+ opt, arg, val, rest = nil
1558
+ nonopt ||= proc {|a| throw :terminate, a}
1559
+ argv.unshift(arg) if arg = catch(:terminate) {
1560
+ while arg = argv.shift
1561
+ case arg
1562
+ # long option
1563
+ when /\A--([^=]*)(?:=(.*))?/m
1564
+ opt, rest = $1, $2
1565
+ opt.tr!('_', '-')
1566
+ begin
1567
+ sw, = complete(:long, opt, true)
1568
+ if require_exact && !sw.long.include?(arg)
1569
+ raise InvalidOption, arg
1570
+ end
1571
+ rescue ParseError
1572
+ raise $!.set_option(arg, true)
1573
+ end
1574
+ begin
1575
+ opt, cb, val = sw.parse(rest, argv) {|*exc| raise(*exc)}
1576
+ val = cb.call(val) if cb
1577
+ setter.call(sw.switch_name, val) if setter
1578
+ rescue ParseError
1579
+ raise $!.set_option(arg, rest)
1580
+ end
1581
+
1582
+ # short option
1583
+ when /\A-(.)((=).*|.+)?/m
1584
+ eq, rest, opt = $3, $2, $1
1585
+ has_arg, val = eq, rest
1586
+ begin
1587
+ sw, = search(:short, opt)
1588
+ unless sw
1589
+ begin
1590
+ sw, = complete(:short, opt)
1591
+ # short option matched.
1592
+ val = arg.delete_prefix('-')
1593
+ has_arg = true
1594
+ rescue InvalidOption
1595
+ raise if require_exact
1596
+ # if no short options match, try completion with long
1597
+ # options.
1598
+ sw, = complete(:long, opt)
1599
+ eq ||= !rest
1600
+ end
1601
+ end
1602
+ rescue ParseError
1603
+ raise $!.set_option(arg, true)
1604
+ end
1605
+ begin
1606
+ opt, cb, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq}
1607
+ rescue ParseError
1608
+ raise $!.set_option(arg, arg.length > 2)
1609
+ else
1610
+ raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}"
1611
+ end
1612
+ begin
1613
+ argv.unshift(opt) if opt and (!rest or (opt = opt.sub(/\A-*/, '-')) != '-')
1614
+ val = cb.call(val) if cb
1615
+ setter.call(sw.switch_name, val) if setter
1616
+ rescue ParseError
1617
+ raise $!.set_option(arg, arg.length > 2)
1618
+ end
1619
+
1620
+ # non-option argument
1621
+ else
1622
+ catch(:prune) do
1623
+ visit(:each_option) do |sw0|
1624
+ sw = sw0
1625
+ sw.block.call(arg) if Switch === sw and sw.match_nonswitch?(arg)
1626
+ end
1627
+ nonopt.call(arg)
1628
+ end
1629
+ end
1630
+ end
1631
+
1632
+ nil
1633
+ }
1634
+
1635
+ visit(:search, :short, nil) {|sw| sw.block.call(*argv) if !sw.pattern}
1636
+
1637
+ argv
1638
+ end
1639
+ private :parse_in_order
1640
+
1641
+ #
1642
+ # Parses command line arguments +argv+ in permutation mode and returns
1643
+ # list of non-option arguments. When optional +into+ keyword
1644
+ # argument is provided, the parsed option values are stored there via
1645
+ # <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
1646
+ # similar object).
1647
+ #
1648
+ def permute(*argv, into: nil)
1649
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
1650
+ permute!(argv, into: into)
1651
+ end
1652
+
1653
+ #
1654
+ # Same as #permute, but removes switches destructively.
1655
+ # Non-option arguments remain in +argv+.
1656
+ #
1657
+ def permute!(argv = default_argv, into: nil)
1658
+ nonopts = []
1659
+ order!(argv, into: into, &nonopts.method(:<<))
1660
+ argv[0, 0] = nonopts
1661
+ argv
1662
+ end
1663
+
1664
+ #
1665
+ # Parses command line arguments +argv+ in order when environment variable
1666
+ # POSIXLY_CORRECT is set, and in permutation mode otherwise.
1667
+ # When optional +into+ keyword argument is provided, the parsed option
1668
+ # values are stored there via <code>[]=</code> method (so it can be Hash,
1669
+ # or OpenStruct, or other similar object).
1670
+ #
1671
+ def parse(*argv, into: nil)
1672
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
1673
+ parse!(argv, into: into)
1674
+ end
1675
+
1676
+ #
1677
+ # Same as #parse, but removes switches destructively.
1678
+ # Non-option arguments remain in +argv+.
1679
+ #
1680
+ def parse!(argv = default_argv, into: nil)
1681
+ if ENV.include?('POSIXLY_CORRECT')
1682
+ order!(argv, into: into)
1683
+ else
1684
+ permute!(argv, into: into)
1685
+ end
1686
+ end
1687
+
1688
+ #
1689
+ # Wrapper method for getopts.rb.
1690
+ #
1691
+ # params = ARGV.getopts("ab:", "foo", "bar:", "zot:Z;zot option")
1692
+ # # params["a"] = true # -a
1693
+ # # params["b"] = "1" # -b1
1694
+ # # params["foo"] = "1" # --foo
1695
+ # # params["bar"] = "x" # --bar x
1696
+ # # params["zot"] = "z" # --zot Z
1697
+ #
1698
+ def getopts(*args)
1699
+ argv = Array === args.first ? args.shift : default_argv
1700
+ single_options, *long_options = *args
1701
+
1702
+ result = {}
1703
+
1704
+ single_options.scan(/(.)(:)?/) do |opt, val|
1705
+ if val
1706
+ result[opt] = nil
1707
+ define("-#{opt} VAL")
1708
+ else
1709
+ result[opt] = false
1710
+ define("-#{opt}")
1711
+ end
1712
+ end if single_options
1713
+
1714
+ long_options.each do |arg|
1715
+ arg, desc = arg.split(';', 2)
1716
+ opt, val = arg.split(':', 2)
1717
+ if val
1718
+ result[opt] = val.empty? ? nil : val
1719
+ define("--#{opt}=#{result[opt] || "VAL"}", *[desc].compact)
1720
+ else
1721
+ result[opt] = false
1722
+ define("--#{opt}", *[desc].compact)
1723
+ end
1724
+ end
1725
+
1726
+ parse_in_order(argv, result.method(:[]=))
1727
+ result
1728
+ end
1729
+
1730
+ #
1731
+ # See #getopts.
1732
+ #
1733
+ def self.getopts(*args)
1734
+ new.getopts(*args)
1735
+ end
1736
+
1737
+ #
1738
+ # Traverses @stack, sending each element method +id+ with +args+ and
1739
+ # +block+.
1740
+ #
1741
+ def visit(id, *args, &block) # :nodoc:
1742
+ @stack.reverse_each do |el|
1743
+ el.__send__(id, *args, &block)
1744
+ end
1745
+ nil
1746
+ end
1747
+ private :visit
1748
+
1749
+ #
1750
+ # Searches +key+ in @stack for +id+ hash and returns or yields the result.
1751
+ #
1752
+ def search(id, key) # :nodoc:
1753
+ block_given = block_given?
1754
+ visit(:search, id, key) do |k|
1755
+ return block_given ? yield(k) : k
1756
+ end
1757
+ end
1758
+ private :search
1759
+
1760
+ #
1761
+ # Completes shortened long style option switch and returns pair of
1762
+ # canonical switch and switch descriptor Gem::OptionParser::Switch.
1763
+ #
1764
+ # +typ+:: Searching table.
1765
+ # +opt+:: Searching key.
1766
+ # +icase+:: Search case insensitive if true.
1767
+ # +pat+:: Optional pattern for completion.
1768
+ #
1769
+ def complete(typ, opt, icase = false, *pat) # :nodoc:
1770
+ if pat.empty?
1771
+ search(typ, opt) {|sw| return [sw, opt]} # exact match or...
1772
+ end
1773
+ ambiguous = catch(:ambiguous) {
1774
+ visit(:complete, typ, opt, icase, *pat) {|o, *sw| return sw}
1775
+ }
1776
+ exc = ambiguous ? AmbiguousOption : InvalidOption
1777
+ raise exc.new(opt, additional: self.method(:additional_message).curry[typ])
1778
+ end
1779
+ private :complete
1780
+
1781
+ #
1782
+ # Returns additional info.
1783
+ #
1784
+ def additional_message(typ, opt)
1785
+ return unless typ and opt and defined?(DidYouMean::SpellChecker)
1786
+ all_candidates = []
1787
+ visit(:get_candidates, typ) do |candidates|
1788
+ all_candidates.concat(candidates)
1789
+ end
1790
+ all_candidates.select! {|cand| cand.is_a?(String) }
1791
+ checker = DidYouMean::SpellChecker.new(dictionary: all_candidates)
1792
+ suggestions = all_candidates & checker.correct(opt)
1793
+ if DidYouMean.respond_to?(:formatter)
1794
+ DidYouMean.formatter.message_for(suggestions)
1795
+ else
1796
+ "\nDid you mean? #{suggestions.join("\n ")}"
1797
+ end
1798
+ end
1799
+
1800
+ def candidate(word)
1801
+ list = []
1802
+ case word
1803
+ when '-'
1804
+ long = short = true
1805
+ when /\A--/
1806
+ word, arg = word.split(/=/, 2)
1807
+ argpat = Completion.regexp(arg, false) if arg and !arg.empty?
1808
+ long = true
1809
+ when /\A-/
1810
+ short = true
1811
+ end
1812
+ pat = Completion.regexp(word, long)
1813
+ visit(:each_option) do |opt|
1814
+ next unless Switch === opt
1815
+ opts = (long ? opt.long : []) + (short ? opt.short : [])
1816
+ opts = Completion.candidate(word, true, pat, &opts.method(:each)).map(&:first) if pat
1817
+ if /\A=/ =~ opt.arg
1818
+ opts.map! {|sw| sw + "="}
1819
+ if arg and CompletingHash === opt.pattern
1820
+ if opts = opt.pattern.candidate(arg, false, argpat)
1821
+ opts.map!(&:last)
1822
+ end
1823
+ end
1824
+ end
1825
+ list.concat(opts)
1826
+ end
1827
+ list
1828
+ end
1829
+
1830
+ #
1831
+ # Loads options from file names as +filename+. Does nothing when the file
1832
+ # is not present. Returns whether successfully loaded.
1833
+ #
1834
+ # +filename+ defaults to basename of the program without suffix in a
1835
+ # directory ~/.options, then the basename with '.options' suffix
1836
+ # under XDG and Haiku standard places.
1837
+ #
1838
+ def load(filename = nil)
1839
+ unless filename
1840
+ basename = File.basename($0, '.*')
1841
+ return true if load(File.expand_path(basename, '~/.options')) rescue nil
1842
+ basename << ".options"
1843
+ return [
1844
+ # XDG
1845
+ ENV['XDG_CONFIG_HOME'],
1846
+ '~/.config',
1847
+ *ENV['XDG_CONFIG_DIRS']&.split(File::PATH_SEPARATOR),
1848
+
1849
+ # Haiku
1850
+ '~/config/settings',
1851
+ ].any? {|dir|
1852
+ next if !dir or dir.empty?
1853
+ load(File.expand_path(basename, dir)) rescue nil
1854
+ }
1855
+ end
1856
+ begin
1857
+ parse(*IO.readlines(filename).each {|s| s.chomp!})
1858
+ true
1859
+ rescue Errno::ENOENT, Errno::ENOTDIR
1860
+ false
1861
+ end
1862
+ end
1863
+
1864
+ #
1865
+ # Parses environment variable +env+ or its uppercase with splitting like a
1866
+ # shell.
1867
+ #
1868
+ # +env+ defaults to the basename of the program.
1869
+ #
1870
+ def environment(env = File.basename($0, '.*'))
1871
+ env = ENV[env] || ENV[env.upcase] or return
1872
+ require 'shellwords'
1873
+ parse(*Shellwords.shellwords(env))
1874
+ end
1875
+
1876
+ #
1877
+ # Acceptable argument classes
1878
+ #
1879
+
1880
+ #
1881
+ # Any string and no conversion. This is fall-back.
1882
+ #
1883
+ accept(Object) {|s,|s or s.nil?}
1884
+
1885
+ accept(NilClass) {|s,|s}
1886
+
1887
+ #
1888
+ # Any non-empty string, and no conversion.
1889
+ #
1890
+ accept(String, /.+/m) {|s,*|s}
1891
+
1892
+ #
1893
+ # Ruby/C-like integer, octal for 0-7 sequence, binary for 0b, hexadecimal
1894
+ # for 0x, and decimal for others; with optional sign prefix. Converts to
1895
+ # Integer.
1896
+ #
1897
+ decimal = '\d+(?:_\d+)*'
1898
+ binary = 'b[01]+(?:_[01]+)*'
1899
+ hex = 'x[\da-f]+(?:_[\da-f]+)*'
1900
+ octal = "0(?:[0-7]+(?:_[0-7]+)*|#{binary}|#{hex})?"
1901
+ integer = "#{octal}|#{decimal}"
1902
+
1903
+ accept(Integer, %r"\A[-+]?(?:#{integer})\z"io) {|s,|
1904
+ begin
1905
+ Integer(s)
1906
+ rescue ArgumentError
1907
+ raise Gem::OptionParser::InvalidArgument, s
1908
+ end if s
1909
+ }
1910
+
1911
+ #
1912
+ # Float number format, and converts to Float.
1913
+ #
1914
+ float = "(?:#{decimal}(?=(.)?)(?:\\.(?:#{decimal})?)?|\\.#{decimal})(?:E[-+]?#{decimal})?"
1915
+ floatpat = %r"\A[-+]?#{float}\z"io
1916
+ accept(Float, floatpat) {|s,| s.to_f if s}
1917
+
1918
+ #
1919
+ # Generic numeric format, converts to Integer for integer format, Float
1920
+ # for float format, and Rational for rational format.
1921
+ #
1922
+ real = "[-+]?(?:#{octal}|#{float})"
1923
+ accept(Numeric, /\A(#{real})(?:\/(#{real}))?\z/io) {|s, d, f, n,|
1924
+ if n
1925
+ Rational(d, n)
1926
+ elsif f
1927
+ Float(s)
1928
+ else
1929
+ Integer(s)
1930
+ end
1931
+ }
1932
+
1933
+ #
1934
+ # Decimal integer format, to be converted to Integer.
1935
+ #
1936
+ DecimalInteger = /\A[-+]?#{decimal}\z/io
1937
+ accept(DecimalInteger, DecimalInteger) {|s,|
1938
+ begin
1939
+ Integer(s, 10)
1940
+ rescue ArgumentError
1941
+ raise Gem::OptionParser::InvalidArgument, s
1942
+ end if s
1943
+ }
1944
+
1945
+ #
1946
+ # Ruby/C like octal/hexadecimal/binary integer format, to be converted to
1947
+ # Integer.
1948
+ #
1949
+ OctalInteger = /\A[-+]?(?:[0-7]+(?:_[0-7]+)*|0(?:#{binary}|#{hex}))\z/io
1950
+ accept(OctalInteger, OctalInteger) {|s,|
1951
+ begin
1952
+ Integer(s, 8)
1953
+ rescue ArgumentError
1954
+ raise Gem::OptionParser::InvalidArgument, s
1955
+ end if s
1956
+ }
1957
+
1958
+ #
1959
+ # Decimal integer/float number format, to be converted to Integer for
1960
+ # integer format, Float for float format.
1961
+ #
1962
+ DecimalNumeric = floatpat # decimal integer is allowed as float also.
1963
+ accept(DecimalNumeric, floatpat) {|s, f|
1964
+ begin
1965
+ if f
1966
+ Float(s)
1967
+ else
1968
+ Integer(s)
1969
+ end
1970
+ rescue ArgumentError
1971
+ raise Gem::OptionParser::InvalidArgument, s
1972
+ end if s
1973
+ }
1974
+
1975
+ #
1976
+ # Boolean switch, which means whether it is present or not, whether it is
1977
+ # absent or not with prefix no-, or it takes an argument
1978
+ # yes/no/true/false/+/-.
1979
+ #
1980
+ yesno = CompletingHash.new
1981
+ %w[- no false].each {|el| yesno[el] = false}
1982
+ %w[+ yes true].each {|el| yesno[el] = true}
1983
+ yesno['nil'] = false # should be nil?
1984
+ accept(TrueClass, yesno) {|arg, val| val == nil or val}
1985
+ #
1986
+ # Similar to TrueClass, but defaults to false.
1987
+ #
1988
+ accept(FalseClass, yesno) {|arg, val| val != nil and val}
1989
+
1990
+ #
1991
+ # List of strings separated by ",".
1992
+ #
1993
+ accept(Array) do |s, |
1994
+ if s
1995
+ s = s.split(',').collect {|ss| ss unless ss.empty?}
1996
+ end
1997
+ s
1998
+ end
1999
+
2000
+ #
2001
+ # Regular expression with options.
2002
+ #
2003
+ accept(Regexp, %r"\A/((?:\\.|[^\\])*)/([[:alpha:]]+)?\z|.*") do |all, s, o|
2004
+ f = 0
2005
+ if o
2006
+ f |= Regexp::IGNORECASE if /i/ =~ o
2007
+ f |= Regexp::MULTILINE if /m/ =~ o
2008
+ f |= Regexp::EXTENDED if /x/ =~ o
2009
+ k = o.delete("imx")
2010
+ k = nil if k.empty?
2011
+ end
2012
+ Regexp.new(s || all, f, k)
2013
+ end
2014
+
2015
+ #
2016
+ # Exceptions
2017
+ #
2018
+
2019
+ #
2020
+ # Base class of exceptions from Gem::OptionParser.
2021
+ #
2022
+ class ParseError < RuntimeError
2023
+ # Reason which caused the error.
2024
+ Reason = 'parse error'
2025
+
2026
+ def initialize(*args, additional: nil)
2027
+ @additional = additional
2028
+ @arg0, = args
2029
+ @args = args
2030
+ @reason = nil
2031
+ end
2032
+
2033
+ attr_reader :args
2034
+ attr_writer :reason
2035
+ attr_accessor :additional
2036
+
2037
+ #
2038
+ # Pushes back erred argument(s) to +argv+.
2039
+ #
2040
+ def recover(argv)
2041
+ argv[0, 0] = @args
2042
+ argv
2043
+ end
2044
+
2045
+ def self.filter_backtrace(array)
2046
+ unless $DEBUG
2047
+ array.delete_if(&%r"\A#{Regexp.quote(__FILE__)}:"o.method(:=~))
2048
+ end
2049
+ array
2050
+ end
2051
+
2052
+ def set_backtrace(array)
2053
+ super(self.class.filter_backtrace(array))
2054
+ end
2055
+
2056
+ def set_option(opt, eq)
2057
+ if eq
2058
+ @args[0] = opt
2059
+ else
2060
+ @args.unshift(opt)
2061
+ end
2062
+ self
2063
+ end
2064
+
2065
+ #
2066
+ # Returns error reason. Override this for I18N.
2067
+ #
2068
+ def reason
2069
+ @reason || self.class::Reason
2070
+ end
2071
+
2072
+ def inspect
2073
+ "#<#{self.class}: #{args.join(' ')}>"
2074
+ end
2075
+
2076
+ #
2077
+ # Default stringizing method to emit standard error message.
2078
+ #
2079
+ def message
2080
+ "#{reason}: #{args.join(' ')}#{additional[@arg0] if additional}"
2081
+ end
2082
+
2083
+ alias to_s message
2084
+ end
2085
+
2086
+ #
2087
+ # Raises when ambiguously completable string is encountered.
2088
+ #
2089
+ class AmbiguousOption < ParseError
2090
+ const_set(:Reason, 'ambiguous option')
2091
+ end
2092
+
2093
+ #
2094
+ # Raises when there is an argument for a switch which takes no argument.
2095
+ #
2096
+ class NeedlessArgument < ParseError
2097
+ const_set(:Reason, 'needless argument')
2098
+ end
2099
+
2100
+ #
2101
+ # Raises when a switch with mandatory argument has no argument.
2102
+ #
2103
+ class MissingArgument < ParseError
2104
+ const_set(:Reason, 'missing argument')
2105
+ end
2106
+
2107
+ #
2108
+ # Raises when switch is undefined.
2109
+ #
2110
+ class InvalidOption < ParseError
2111
+ const_set(:Reason, 'invalid option')
2112
+ end
2113
+
2114
+ #
2115
+ # Raises when the given argument does not match required format.
2116
+ #
2117
+ class InvalidArgument < ParseError
2118
+ const_set(:Reason, 'invalid argument')
2119
+ end
2120
+
2121
+ #
2122
+ # Raises when the given argument word can't be completed uniquely.
2123
+ #
2124
+ class AmbiguousArgument < InvalidArgument
2125
+ const_set(:Reason, 'ambiguous argument')
2126
+ end
2127
+
2128
+ #
2129
+ # Miscellaneous
2130
+ #
2131
+
2132
+ #
2133
+ # Extends command line arguments array (ARGV) to parse itself.
2134
+ #
2135
+ module Arguable
2136
+
2137
+ #
2138
+ # Sets Gem::OptionParser object, when +opt+ is +false+ or +nil+, methods
2139
+ # Gem::OptionParser::Arguable#options and Gem::OptionParser::Arguable#options= are
2140
+ # undefined. Thus, there is no ways to access the Gem::OptionParser object
2141
+ # via the receiver object.
2142
+ #
2143
+ def options=(opt)
2144
+ unless @optparse = opt
2145
+ class << self
2146
+ undef_method(:options)
2147
+ undef_method(:options=)
2148
+ end
2149
+ end
2150
+ end
2151
+
2152
+ #
2153
+ # Actual Gem::OptionParser object, automatically created if nonexistent.
2154
+ #
2155
+ # If called with a block, yields the Gem::OptionParser object and returns the
2156
+ # result of the block. If an Gem::OptionParser::ParseError exception occurs
2157
+ # in the block, it is rescued, a error message printed to STDERR and
2158
+ # +nil+ returned.
2159
+ #
2160
+ def options
2161
+ @optparse ||= Gem::OptionParser.new
2162
+ @optparse.default_argv = self
2163
+ block_given? or return @optparse
2164
+ begin
2165
+ yield @optparse
2166
+ rescue ParseError
2167
+ @optparse.warn $!
2168
+ nil
2169
+ end
2170
+ end
2171
+
2172
+ #
2173
+ # Parses +self+ destructively in order and returns +self+ containing the
2174
+ # rest arguments left unparsed.
2175
+ #
2176
+ def order!(&blk) options.order!(self, &blk) end
2177
+
2178
+ #
2179
+ # Parses +self+ destructively in permutation mode and returns +self+
2180
+ # containing the rest arguments left unparsed.
2181
+ #
2182
+ def permute!() options.permute!(self) end
2183
+
2184
+ #
2185
+ # Parses +self+ destructively and returns +self+ containing the
2186
+ # rest arguments left unparsed.
2187
+ #
2188
+ def parse!() options.parse!(self) end
2189
+
2190
+ #
2191
+ # Substitution of getopts is possible as follows. Also see
2192
+ # Gem::OptionParser#getopts.
2193
+ #
2194
+ # def getopts(*args)
2195
+ # ($OPT = ARGV.getopts(*args)).each do |opt, val|
2196
+ # eval "$OPT_#{opt.gsub(/[^A-Za-z0-9_]/, '_')} = val"
2197
+ # end
2198
+ # rescue Gem::OptionParser::ParseError
2199
+ # end
2200
+ #
2201
+ def getopts(*args)
2202
+ options.getopts(self, *args)
2203
+ end
2204
+
2205
+ #
2206
+ # Initializes instance variable.
2207
+ #
2208
+ def self.extend_object(obj)
2209
+ super
2210
+ obj.instance_eval {@optparse = nil}
2211
+ end
2212
+ def initialize(*args)
2213
+ super
2214
+ @optparse = nil
2215
+ end
2216
+ end
2217
+
2218
+ #
2219
+ # Acceptable argument classes. Now contains DecimalInteger, OctalInteger
2220
+ # and DecimalNumeric. See Acceptable argument classes (in source code).
2221
+ #
2222
+ module Acceptables
2223
+ const_set(:DecimalInteger, Gem::OptionParser::DecimalInteger)
2224
+ const_set(:OctalInteger, Gem::OptionParser::OctalInteger)
2225
+ const_set(:DecimalNumeric, Gem::OptionParser::DecimalNumeric)
2226
+ end
2227
+ end
2228
+
2229
+ # ARGV is arguable by Gem::OptionParser
2230
+ ARGV.extend(Gem::OptionParser::Arguable)