cft_smartcloud 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG +11 -0
  3. data/README.md +106 -0
  4. data/VERSION +1 -1
  5. data/bin/cft_smartcloud +33 -7
  6. data/bin/smartcloud +33 -7
  7. data/cft_smartcloud.gemspec +84 -20
  8. data/lib/config/config.yml +2 -0
  9. data/lib/curl_client.rb +42 -0
  10. data/lib/rest-client-1.6.6-master/.gitignore +6 -0
  11. data/lib/{rest-client-1.6.3 → rest-client-1.6.6-master}/README.rdoc +10 -1
  12. data/lib/{rest-client-1.6.3 → rest-client-1.6.6-master}/Rakefile +0 -0
  13. data/lib/rest-client-1.6.6-master/VERSION +1 -0
  14. data/lib/{rest-client-1.6.3 → rest-client-1.6.6-master}/bin/restclient +5 -4
  15. data/lib/{rest-client-1.6.3 → rest-client-1.6.6-master}/history.md +22 -0
  16. data/lib/{rest-client-1.6.3 → rest-client-1.6.6-master}/lib/rest-client.rb +0 -0
  17. data/lib/{rest-client-1.6.3 → rest-client-1.6.6-master}/lib/rest_client.rb +0 -0
  18. data/lib/{rest-client-1.6.3 → rest-client-1.6.6-master}/lib/restclient/abstract_response.rb +0 -0
  19. data/lib/{rest-client-1.6.3 → rest-client-1.6.6-master}/lib/restclient/exceptions.rb +0 -0
  20. data/lib/rest-client-1.6.6-master/lib/restclient/net_http_ext.rb +55 -0
  21. data/lib/{rest-client-1.6.3 → rest-client-1.6.6-master}/lib/restclient/payload.rb +17 -2
  22. data/lib/{rest-client-1.6.3 → rest-client-1.6.6-master}/lib/restclient/raw_response.rb +0 -0
  23. data/lib/{rest-client-1.6.3 → rest-client-1.6.6-master}/lib/restclient/request.rb +21 -19
  24. data/lib/{rest-client-1.6.3 → rest-client-1.6.6-master}/lib/restclient/resource.rb +0 -0
  25. data/lib/{rest-client-1.6.3 → rest-client-1.6.6-master}/lib/restclient/response.rb +0 -0
  26. data/lib/{rest-client-1.6.3 → rest-client-1.6.6-master}/lib/restclient.rb +0 -0
  27. data/lib/rest-client-1.6.6-master/rest-client.gemspec +76 -0
  28. data/lib/rest-client-1.6.6-master/spec/abstract_response_spec.rb +85 -0
  29. data/lib/rest-client-1.6.6-master/spec/base.rb +16 -0
  30. data/lib/rest-client-1.6.6-master/spec/exceptions_spec.rb +98 -0
  31. data/lib/rest-client-1.6.6-master/spec/integration/certs/equifax.crt +19 -0
  32. data/lib/rest-client-1.6.6-master/spec/integration/certs/verisign.crt +14 -0
  33. data/lib/rest-client-1.6.6-master/spec/integration/request_spec.rb +25 -0
  34. data/lib/rest-client-1.6.6-master/spec/integration_spec.rb +38 -0
  35. data/lib/rest-client-1.6.6-master/spec/master_shake.jpg +0 -0
  36. data/lib/rest-client-1.6.6-master/spec/payload_spec.rb +234 -0
  37. data/lib/rest-client-1.6.6-master/spec/raw_response_spec.rb +17 -0
  38. data/lib/rest-client-1.6.6-master/spec/request2_spec.rb +40 -0
  39. data/lib/rest-client-1.6.6-master/spec/request_spec.rb +536 -0
  40. data/lib/rest-client-1.6.6-master/spec/resource_spec.rb +134 -0
  41. data/lib/rest-client-1.6.6-master/spec/response_spec.rb +169 -0
  42. data/lib/rest-client-1.6.6-master/spec/restclient_spec.rb +73 -0
  43. data/lib/slop-2.3.1/.gemtest +0 -0
  44. data/lib/slop-2.3.1/.gitignore +6 -0
  45. data/lib/slop-2.3.1/.yardopts +6 -0
  46. data/lib/slop-2.3.1/CHANGES.md +137 -0
  47. data/lib/slop-2.3.1/LICENSE +20 -0
  48. data/lib/slop-2.3.1/README.md +293 -0
  49. data/lib/slop-2.3.1/Rakefile +6 -0
  50. data/lib/slop-2.3.1/lib/slop.rb +1022 -0
  51. data/lib/slop-2.3.1/slop.gemspec +11 -0
  52. data/lib/slop-2.3.1/test/commands_test.rb +151 -0
  53. data/lib/slop-2.3.1/test/helper.rb +13 -0
  54. data/lib/slop-2.3.1/test/option_test.rb +198 -0
  55. data/lib/slop-2.3.1/test/slop_test.rb +574 -0
  56. data/lib/smartcloud.rb +186 -116
  57. data/lib/terminal-table-1.4.4/History.rdoc +53 -0
  58. data/lib/terminal-table-1.4.4/Manifest +24 -0
  59. data/lib/terminal-table-1.4.4/README.rdoc +240 -0
  60. data/lib/terminal-table-1.4.4/Rakefile +15 -0
  61. data/lib/terminal-table-1.4.4/Todo.rdoc +14 -0
  62. data/lib/terminal-table-1.4.4/examples/examples.rb +80 -0
  63. data/lib/terminal-table-1.4.4/lib/terminal-table/cell.rb +88 -0
  64. data/lib/terminal-table-1.4.4/lib/terminal-table/core_ext.rb +8 -0
  65. data/lib/terminal-table-1.4.4/lib/terminal-table/import.rb +4 -0
  66. data/lib/terminal-table-1.4.4/lib/terminal-table/row.rb +48 -0
  67. data/lib/terminal-table-1.4.4/lib/terminal-table/separator.rb +14 -0
  68. data/lib/terminal-table-1.4.4/lib/terminal-table/style.rb +61 -0
  69. data/lib/terminal-table-1.4.4/lib/terminal-table/table.rb +217 -0
  70. data/lib/terminal-table-1.4.4/lib/terminal-table/table_helper.rb +9 -0
  71. data/lib/terminal-table-1.4.4/lib/terminal-table/version.rb +6 -0
  72. data/lib/terminal-table-1.4.4/lib/terminal-table.rb +27 -0
  73. data/lib/terminal-table-1.4.4/spec/cell_spec.rb +54 -0
  74. data/lib/terminal-table-1.4.4/spec/core_ext_spec.rb +18 -0
  75. data/lib/terminal-table-1.4.4/spec/import_spec.rb +11 -0
  76. data/lib/terminal-table-1.4.4/spec/spec.opts +1 -0
  77. data/lib/terminal-table-1.4.4/spec/spec_helper.rb +8 -0
  78. data/lib/terminal-table-1.4.4/spec/table_spec.rb +525 -0
  79. data/lib/terminal-table-1.4.4/tasks/docs.rake +13 -0
  80. data/lib/terminal-table-1.4.4/tasks/gemspec.rake +3 -0
  81. data/lib/terminal-table-1.4.4/tasks/spec.rake +25 -0
  82. data/lib/terminal-table-1.4.4/terminal-table.gemspec +30 -0
  83. data/responses/addresses +26 -0
  84. data/responses/addresses.blank +2 -0
  85. data/responses/instances +74 -0
  86. data/responses/keys +33 -0
  87. data/responses/locations +142 -0
  88. data/responses/offerings_image +3780 -0
  89. data/responses/storage +379 -0
  90. metadata +86 -22
  91. data/README.rdoc +0 -75
  92. data/lib/rest-client-1.6.3/VERSION +0 -1
  93. data/lib/rest-client-1.6.3/lib/restclient/net_http_ext.rb +0 -21
@@ -0,0 +1,1022 @@
1
+ class Slop
2
+ include Enumerable
3
+
4
+ # @return [String] The current version string
5
+ VERSION = '2.3.1'
6
+
7
+ # Slops standard Error class. All exception classes should
8
+ # inherit from this class
9
+ class Error < StandardError; end
10
+
11
+ # Raised when an option expects an argument and none is given
12
+ class MissingArgumentError < Error; end
13
+
14
+ # Raised when an option is required but not given
15
+ class MissingOptionError < Error; end
16
+
17
+ # Raised when an option specifies the `:match` attribute and this
18
+ # options argument does not match this regexp
19
+ class InvalidArgumentError < Error; end
20
+
21
+ # Raised when the `:strict` option is enabled and an unknown
22
+ # or unspecified option is used
23
+ class InvalidOptionError < Error; end
24
+
25
+ # Each option specified in `Slop#opt` creates an instance of this class
26
+ class Option < Struct.new(:short_flag, :long_flag, :description, :tail, :match, :help, :required, :forced, :count)
27
+
28
+ # @param [Slop] slop The Slop object this Option belongs to
29
+ #
30
+ # @param [String, #to_s] short The short flag representing this Option
31
+ # without prefix (ie: `a`)
32
+ #
33
+ # @param [String, #to_s] long The long flag representing this Option
34
+ # without the prefix (ie: `foo`)
35
+ #
36
+ # @param [String] description This options description
37
+ #
38
+ # @param [Boolean] argument True if this option takes an argument
39
+ #
40
+ # @option options [Boolean] :optional
41
+ # * When true, this option takes an optional argument, ie an argument
42
+ # does not **have** to be supplied.
43
+ #
44
+ # @option options [Boolean] :argument
45
+ # * True if this option takes an argument.
46
+ #
47
+ # @option options [Object] :default
48
+ # * The default value for this option when no argument is given
49
+ #
50
+ # @option options [Proc, #call] :callback
51
+ # * The callback object, used instead of passing a block to this option
52
+ #
53
+ # @option options [String, #to_s] :delimiter (',')
54
+ # * A delimiter string when processing this option as a list
55
+ #
56
+ # @option options [Integer] :limit (0)
57
+ # * A limit, used when processing this option as a list
58
+ #
59
+ # @option options [Boolean] :tail (false)
60
+ # * When true, this option will be grouped at the bottom of the help
61
+ # text instead of in order of processing
62
+ #
63
+ # @option options [Regexp] :match
64
+ # * A regular expression this option should match
65
+ #
66
+ # @option options [String, #to_s] :unless
67
+ # * Used by `omit_exec` for omitting execution of this options callback
68
+ # if another option exists
69
+ #
70
+ # @option options [Boolean, String] :help (true)
71
+ # * If this option is a string, it'll be appended to the long flag
72
+ # help text (before the description). When false, no help information
73
+ # will be displayed for this option
74
+ #
75
+ # @option options [Boolean] :required (false)
76
+ # * When true, this option is considered mandatory. That is, when not
77
+ # supplied, Slop will raise a `MissingOptionError`
78
+ def initialize(slop, short, long, description, argument, options, &blk)
79
+ @slop = slop
80
+
81
+ self.short_flag = short
82
+ self.long_flag = long
83
+ self.description = description
84
+
85
+ @argument = argument
86
+ @options = options
87
+
88
+ self.tail = @options[:tail]
89
+ self.match = @options[:match]
90
+ self.help = @options.fetch(:help, true)
91
+ self.required = @options[:required]
92
+
93
+ @delimiter = @options.fetch(:delimiter, ',')
94
+ @limit = @options.fetch(:limit, 0)
95
+ @argument_type = @options[:as].to_s.downcase
96
+ @argument_value = nil
97
+
98
+ self.forced = false
99
+ self.count = 0
100
+
101
+ @callback = blk if block_given?
102
+ @callback ||= @options[:callback]
103
+
104
+ if long_flag && long_flag.size > @slop.longest_flag
105
+ @slop.longest_flag = long_flag.size
106
+ @slop.longest_flag += help.size if help.respond_to?(:to_str)
107
+ end
108
+ end
109
+
110
+ # @return [Boolean] true if this option expects an argument
111
+ def expects_argument?
112
+ @argument || @options[:argument] || @options[:optional] == false
113
+ end
114
+
115
+ # @return [Boolean] true if this option accepts an optional argument
116
+ def accepts_optional_argument?
117
+ @options[:optional]
118
+ end
119
+
120
+ # @return [String] either the long or short flag for this option
121
+ def key
122
+ long_flag || short_flag
123
+ end
124
+
125
+ # Set this options argument value.
126
+ #
127
+ # If this options argument type is expected to be an Array, this
128
+ # method will split the value and concat elements into the original
129
+ # argument value
130
+ #
131
+ # @param [Object] value The value to set this options argument to
132
+ def argument_value=(value)
133
+ if @argument_type == 'array'
134
+ @argument_value ||= []
135
+
136
+ if value.respond_to?(:to_str)
137
+ @argument_value.concat value.split(@delimiter, @limit)
138
+ end
139
+ else
140
+ @argument_value = value
141
+ end
142
+ end
143
+
144
+ # @return [Object] the argument value after it's been cast
145
+ # according to the `:as` option
146
+ def argument_value
147
+ return @argument_value if forced
148
+ # Check for count first to prefer 0 over nil
149
+ return count if @argument_type == 'count'
150
+
151
+ value = @argument_value || @options[:default]
152
+ return if value.nil?
153
+
154
+ case @argument_type
155
+ when 'array'; @argument_value unless !expects_argument?
156
+ when 'range'; value_to_range value unless !expects_argument?
157
+ when 'float'; value.to_s.to_f unless !expects_argument?
158
+ when 'string', 'str'; value.to_s unless !expects_argument?
159
+ when 'symbol', 'sym'; value.to_s.to_sym unless !expects_argument?
160
+ when 'integer', 'int'; value.to_s.to_i unless !expects_argument?
161
+ else
162
+ value
163
+ end
164
+ end
165
+
166
+ # Force an argument value, used when the desired argument value
167
+ # is negative (false or nil)
168
+ #
169
+ # @param [Object] value
170
+ def force_argument_value(value)
171
+ @argument_value = value
172
+ self.forced = true
173
+ end
174
+
175
+ # Execute the block or callback object associated with this Option
176
+ #
177
+ # @param [Object] The object to be sent to `:call`
178
+ def call(obj=nil)
179
+ @callback.call(obj) if @callback.respond_to?(:call)
180
+ end
181
+
182
+ # @param [Array] items The original array of objects passed to `Slop.new`
183
+ # @return [Boolean] true if this options `:unless` argument exists
184
+ # inside *items*
185
+ def omit_exec?(items)
186
+ string = @options[:unless].to_s.sub(/\A--?/, '')
187
+ items.any? { |i| i.to_s.sub(/\A--?/, '') == string }
188
+ end
189
+
190
+ # This option in a nice pretty string, including a short flag, long
191
+ # flag, and description (if they exist).
192
+ #
193
+ # @see Slop#help
194
+ # @return [String]
195
+ def to_s
196
+ out = " "
197
+ out += short_flag ? "-#{short_flag}, " : ' ' * 4
198
+
199
+ if long_flag
200
+ out += "--#{long_flag}"
201
+ if help.respond_to? :to_str
202
+ out += " #{help}"
203
+ size = long_flag.size + help.size + 1
204
+ else
205
+ size = long_flag.size
206
+ end
207
+ diff = @slop.longest_flag - size
208
+ out += " " * (diff + 6)
209
+ else
210
+ out += " " * (@slop.longest_flag + 8)
211
+ end
212
+
213
+ "#{out}#{description}"
214
+ end
215
+
216
+ # @return [String]
217
+ def inspect
218
+ "#<Slop::Option short_flag=#{short_flag.inspect} " +
219
+ "long_flag=#{long_flag.inspect} argument=#{@argument.inspect} " +
220
+ "description=#{description.inspect}>"
221
+ end
222
+
223
+ private
224
+
225
+ def value_to_range(value)
226
+ case value.to_s
227
+ when /\A(-?\d+?)(\.\.\.?|-|,)(-?\d+)\z/
228
+ Range.new($1.to_i, $3.to_i, $2 == '...')
229
+ when /\A-?\d+\z/
230
+ value.to_i
231
+ else
232
+ value
233
+ end
234
+ end
235
+
236
+ end
237
+
238
+ # Used to hold a list of Option objects. This class inherits from Array
239
+ # and overwrites `Array#[]` so we can fetch Option objects via their
240
+ # short or long flags
241
+ class Options < Array
242
+
243
+ # Fetch an Option object. This method overrides Array#[] to provide
244
+ # a nicer interface for fetching options via their short or long flag.
245
+ # The reason we don't use a Hash here is because an option cannot be
246
+ # identified by a single label. Instead this method tests against
247
+ # a short flag first, followed by a long flag. When passing this
248
+ # method an Integer, it will work as an Array usually would, fetching
249
+ # the Slop::Option at this index.
250
+ #
251
+ # @param [Object] flag The short/long flag representing the option
252
+ # @example
253
+ # opts = Slop.parse { on :v, "Verbose mode" }
254
+ # opts.options[:v] #=> Option
255
+ # opts.options[:v].description #=> "Verbose mode"
256
+ # @return [Option] the option assoiated with this flag
257
+ def [](flag)
258
+ if flag.is_a? Integer
259
+ super
260
+ else
261
+ find do |option|
262
+ [option.short_flag, option.long_flag].include? flag.to_s
263
+ end
264
+ end
265
+ end
266
+ end
267
+
268
+ # Parses the items from a CLI format into a friendly object
269
+ #
270
+ # @param [Array] items Items to parse into options.
271
+ # @example Specifying three options to parse:
272
+ # opts = Slops.parse do
273
+ # on :v, :verbose, 'Enable verbose mode'
274
+ # on :n, :name, 'Your name'
275
+ # on :a, :age, 'Your age'
276
+ # end
277
+ # @return [Slop] Returns an instance of Slop
278
+ def self.parse(items=ARGV, options={}, &block)
279
+ initialize_and_parse items, false, options, &block
280
+ end
281
+
282
+ # Identical to {Slop.parse}, but removes parsed options from the
283
+ # original Array
284
+ #
285
+ # @return [Slop] Returns an instance of Slop
286
+ def self.parse!(items=ARGV, options={}, &block)
287
+ initialize_and_parse items, true, options, &block
288
+ end
289
+
290
+ # Build options from an optspec string
291
+ #
292
+ # @param [String] optspec The option spec string
293
+ # @param [Array] options A list of options to forward to Slop.new
294
+ # @return [Slop] A new instance of Slop
295
+ def self.optspec(optspec, *options)
296
+ if optspec[/^--+$/]
297
+ banner, optspec = optspec.split(/^--+$/, 2)
298
+ end
299
+
300
+ lines = optspec.split("\n").reject(&:empty?)
301
+ opts = Slop.new(banner, *options)
302
+
303
+ lines.each do |line|
304
+ opt, description = line.split(' ', 2)
305
+ short, long = opt.split(',').map { |s| s.sub(/\A--?/, '') }
306
+ argument = long && long[/\=$/]
307
+ long.sub!(/\=$/, '') if argument
308
+ opts.on short, long, description, argument
309
+ end
310
+
311
+ opts
312
+ end
313
+
314
+ # @return [Options]
315
+ attr_reader :options
316
+
317
+ # @return [Hash]
318
+ attr_reader :commands
319
+
320
+ # @overload banner=(string)
321
+ # Set the banner
322
+ # @param [String] string The text to set the banner to
323
+ attr_writer :banner
324
+
325
+ # @overload summary=(string)
326
+ # Set the summary
327
+ # @param [String] string The text to set the summary to
328
+ attr_writer :summary
329
+
330
+ # @overload description=(string)
331
+ # Set the description
332
+ # @param [String] string The text to set the description to
333
+ attr_writer :description
334
+
335
+ # @return [Integer] The length of the longest flag slop knows of
336
+ attr_accessor :longest_flag
337
+
338
+ # @return [Array] A list of aliases this command uses
339
+ attr_accessor :aliases
340
+
341
+ # @option opts [Boolean] :help
342
+ # * Automatically add the `help` option
343
+ #
344
+ # @option opts [Boolean] :strict
345
+ # * Raises when a non listed option is found, false by default
346
+ #
347
+ # @option opts [Boolean] :multiple_switches
348
+ # * Allows `-abc` to be processed as the options 'a', 'b', 'c' and will
349
+ # force their argument values to true. By default Slop with parse this
350
+ # as 'a' with the argument 'bc'
351
+ #
352
+ # @option opts [String] :banner
353
+ # * The banner text used for the help
354
+ #
355
+ # @option opts [Proc, #call] :on_empty
356
+ # * Any object that respondes to `call` which is executed when Slop has
357
+ # no items to parse
358
+ #
359
+ # @option opts [IO, #puts] :io ($stderr)
360
+ # * An IO object for writing to when :help => true is used
361
+ #
362
+ # @option opts [Boolean] :exit_on_help (true)
363
+ # * When false and coupled with the :help option, Slop will not exit
364
+ # inside of the `help` option
365
+ #
366
+ # @option opts [Boolean] :ignore_case (false)
367
+ # * Ignore options case
368
+ #
369
+ # @option opts [Proc, #call] :on_noopts
370
+ # * Trigger an event when no options are found
371
+ #
372
+ # @option opts [Boolean] :autocreate (false)
373
+ # * Autocreate options depending on the Array passed to {#parse}
374
+ #
375
+ # @option opts [Boolean] :arguments (false)
376
+ # * Set to true to enable all specified options to accept arguments
377
+ # by default
378
+ #
379
+ # @option opts [Array] :aliases ([])
380
+ # * Primary uses by commands to implement command aliases
381
+ #
382
+ # @option opts [Boolean] :completion (true)
383
+ # * When true, commands will be auto completed. Ie `foobar` will be
384
+ # executed simply when `foo` `fo` or `foob` are used
385
+ #
386
+ # @option options [Boolean] :all_accept_arguments (false)
387
+ # * When true, every option added will take an argument, this saves
388
+ # having to enable it for every option
389
+ def initialize(*opts, &block)
390
+ sloptions = opts.last.is_a?(Hash) ? opts.pop : {}
391
+ sloptions[:banner] = opts.shift if opts[0].respond_to?(:to_str)
392
+ opts.each { |o| sloptions[o] = true }
393
+
394
+ @options = Options.new
395
+ @commands = {}
396
+ @execution_block = nil
397
+
398
+ @longest_flag = 0
399
+ @invalid_options = []
400
+
401
+ @banner = sloptions[:banner]
402
+ @strict = sloptions[:strict]
403
+ @ignore_case = sloptions[:ignore_case]
404
+ @multiple_switches = sloptions.fetch(:multiple_switches, true)
405
+ @autocreate = sloptions[:autocreate]
406
+ @completion = sloptions.fetch(:completion, true)
407
+ @arguments = sloptions[:arguments]
408
+ @on_empty = sloptions[:on_empty]
409
+ @io = sloptions.fetch(:io, $stderr)
410
+ @on_noopts = sloptions[:on_noopts] || sloptions[:on_optionless]
411
+ @sloptions = sloptions
412
+
413
+ if block_given?
414
+ block.arity == 1 ? yield(self) : instance_eval(&block)
415
+ end
416
+
417
+ if sloptions[:help]
418
+ on :h, :help, 'Print this help message', :tail => true do
419
+ @io.puts help
420
+ exit unless sloptions[:exit_on_help] == false
421
+ end
422
+ end
423
+ end
424
+
425
+ # Set or return banner text
426
+ #
427
+ # @param [String] text Displayed banner text
428
+ # @example
429
+ # opts = Slop.parse do
430
+ # banner "Usage - ruby foo.rb [arguments]"
431
+ # end
432
+ # @return [String] The current banner
433
+ def banner(text=nil)
434
+ @banner = text if text
435
+ @banner
436
+ end
437
+
438
+ # Set or return the summary
439
+ #
440
+ # @param [String] text Displayed summary text
441
+ # @example
442
+ # opts = Slop.parse do
443
+ # summary "do stuff with more stuff"
444
+ # end
445
+ # @return [String] The current summary
446
+ def summary(text=nil)
447
+ @summary = text if text
448
+ @summary
449
+ end
450
+
451
+ # Set or return the description
452
+ #
453
+ # @param [String] text Displayed description text
454
+ # @example
455
+ # opts = Slop.parse do
456
+ # description "This command does a lot of stuff with other stuff."
457
+ # end
458
+ # @return [String] The current description
459
+ def description(text=nil)
460
+ @description = text if text
461
+ @description
462
+ end
463
+
464
+ # Parse a list of options, leaving the original Array unchanged
465
+ #
466
+ # @param [Array] items A list of items to parse
467
+ def parse(items=ARGV, &block)
468
+ parse_items items, &block
469
+ end
470
+
471
+ # Parse a list of options, removing parsed options from the original Array
472
+ #
473
+ # @param [Array] items A list of items to parse
474
+ def parse!(items=ARGV, &block)
475
+ parse_items items, true, &block
476
+ end
477
+
478
+ # Enumerable interface
479
+ def each(&block)
480
+ @options.each(&block)
481
+ end
482
+
483
+ # @param [Symbol] key Option symbol
484
+ # @example
485
+ # opts[:name] #=> "Emily"
486
+ # opts.get(:name) #=> "Emily"
487
+ # @return [Object] Returns the value associated with that option. If an
488
+ # option doesn't exist, a command will instead be searched for
489
+ def [](key)
490
+ option = @options[key]
491
+ option ? option.argument_value : @commands[key]
492
+ end
493
+ alias get []
494
+
495
+ # Specify an option with a short or long version, description and type
496
+ #
497
+ # @param [*] args Option configuration.
498
+ # @option args [Symbol, String] :short_flag Short option name.
499
+ # @option args [Symbol, String] :long_flag Full option name.
500
+ # @option args [String] :description Option description for use in Slop#help
501
+ # @option args [Boolean] :argument Specifies whether this option requires
502
+ # an argument
503
+ # @option args [Hash] :options Optional option configurations.
504
+ # @example
505
+ # opts = Slop.parse do
506
+ # on :n, :name, 'Your username', true # Required argument
507
+ # on :a, :age, 'Your age (optional)', :optional => true
508
+ # on :g, :gender, 'Your gender', :optional => false
509
+ # on :V, :verbose, 'Run in verbose mode', :default => true
510
+ # on :P, :people, 'Your friends', true, :as => Array
511
+ # on :h, :help, 'Print this help screen' do
512
+ # puts help
513
+ # end
514
+ # end
515
+ # @return [Slop::Option]
516
+ def option(*args, &block)
517
+ options = args.last.is_a?(Hash) ? args.pop : {}
518
+
519
+ short, long, desc, arg, extras = clean_options(args)
520
+
521
+ options.merge!(extras)
522
+ options[:argument] = true if @sloptions[:all_accept_arguments]
523
+
524
+ option = Option.new(self, short, long, desc, arg, options, &block)
525
+ @options << option
526
+
527
+ option
528
+ end
529
+ alias opt option
530
+ alias on option
531
+
532
+ # Namespace options depending on what command is executed
533
+ #
534
+ # @param [Symbol, String] label
535
+ # @param [Hash] options
536
+ # @example
537
+ # opts = Slop.new do
538
+ # command :create do
539
+ # on :v, :verbose
540
+ # end
541
+ # end
542
+ #
543
+ # # ARGV is `create -v`
544
+ # opts.commands[:create].verbose? #=> true
545
+ # @since 1.5.0
546
+ # @raise [ArgumentError] When this command already exists
547
+ # @return [Slop] a new instance of Slop namespaced to +label+
548
+ def command(label, options={}, &block)
549
+ if @commands.key?(label)
550
+ raise ArgumentError, "command `#{label}` already exists"
551
+ end
552
+
553
+ slop = Slop.new @sloptions.merge(options)
554
+ slop.aliases = Array(options.delete(:aliases) || options.delete(:alias))
555
+ @commands[label] = slop
556
+
557
+ slop.aliases.each { |a| @commands[a] = @commands[label] }
558
+
559
+ if block_given?
560
+ block.arity == 1 ? yield(slop) : slop.instance_eval(&block)
561
+ end
562
+
563
+ slop
564
+ end
565
+
566
+ # Trigger an event when Slop has no values to parse
567
+ #
568
+ # @param [Object, #call] obj The object (which can be anything
569
+ # responding to `call`)
570
+ # @example
571
+ # Slop.parse do
572
+ # on_empty { puts 'No argument given!' }
573
+ # end
574
+ # @since 1.5.0
575
+ def on_empty(obj=nil, &block)
576
+ @on_empty ||= (obj || block)
577
+ end
578
+ alias on_empty= on_empty
579
+
580
+ # Trigger an event when the arguments contain no options
581
+ #
582
+ # @param [Object, #call] obj The object to be triggered (anything
583
+ # responding to `call`)
584
+ # @example
585
+ # Slop.parse do
586
+ # on_noopts { puts 'No options here!' }
587
+ # end
588
+ # @since 1.6.0
589
+ def on_noopts(obj=nil, &block)
590
+ @on_noopts ||= (obj || block)
591
+ end
592
+ alias on_optionless on_noopts
593
+
594
+ # Add an execution block (for commands)
595
+ #
596
+ # @example
597
+ # opts = Slop.new do
598
+ # command :foo do
599
+ # on :v, :verbose
600
+ #
601
+ # execute { |o| p o.verbose? }
602
+ # end
603
+ # end
604
+ # opts.parse %w[foo --verbose] #=> true
605
+ #
606
+ # @param [Array] args The list of arguments to send to this command
607
+ # is invoked
608
+ # @since 1.8.0
609
+ # @yield [Slop] an instance of Slop for this command
610
+ def execute(args=[], &block)
611
+ if block_given?
612
+ @execution_block = block
613
+ elsif @execution_block.respond_to?(:call)
614
+ @execution_block.call(self, args)
615
+ end
616
+ end
617
+
618
+ # Returns the parsed list into a option/value hash
619
+ #
620
+ # @example
621
+ # opts.to_hash #=> { :name => 'Emily' }
622
+ #
623
+ # # strings!
624
+ # opts.to_hash(false) #=> { 'name' => 'Emily' }
625
+ # @return [Hash]
626
+ def to_hash(symbols=true)
627
+ @options.reduce({}) do |hsh, option|
628
+ key = option.key
629
+ key = key.to_sym if symbols
630
+ hsh[key] = option.argument_value
631
+ hsh
632
+ end
633
+ end
634
+ alias to_h to_hash
635
+
636
+ # Return parsed items as a new Class
637
+ #
638
+ # @example
639
+ # opts = Slop.new do
640
+ # on :n, :name, 'Persons name', true
641
+ # on :a, :age, 'Persons age', true, :as => :int
642
+ # on :s, :sex, 'Persons sex m/f', true, :match => /^[mf]$/
643
+ # on :A, :admin, 'Enable admin mode'
644
+ # end
645
+ #
646
+ # opts.parse %w[ --name Lee --age 22 -s m --admin ]
647
+ #
648
+ # person = opts.to_struct("Person")
649
+ # person.class #=> Struct::Person
650
+ # person.name #=> 'Lee'
651
+ # person.age #=> 22
652
+ # person.sex #=> m
653
+ # person.admin #=> true
654
+ #
655
+ # @param [String] name The name of this class
656
+ # @return [Class] The new class, or nil if there are no options
657
+ # @since 2.0.0
658
+ def to_struct(name=nil)
659
+ hash = to_hash
660
+ Struct.new(name, *hash.keys).new(*hash.values) unless hash.empty?
661
+ end
662
+
663
+ # Fetch a list of options which were missing from the parsed list
664
+ #
665
+ # @example
666
+ # opts = Slop.new do
667
+ # on :n, :name, 'Your name', true
668
+ # on :p, :password, 'Your password', true
669
+ # on :A, 'Use auth?'
670
+ # end
671
+ #
672
+ # opts.parse %w[ --name Lee ]
673
+ # opts.missing #=> ['password', 'a']
674
+ #
675
+ # @return [Array] A list of options missing from the parsed string
676
+ # @since 2.1.0
677
+ def missing
678
+ @options.select { |opt| not present?(opt.key) }.map { |opt| opt.key }
679
+ end
680
+
681
+ # Allows you to check whether an option was specified in the parsed list
682
+ #
683
+ # Merely sugar for `present?`
684
+ #
685
+ # @example
686
+ # #== ruby foo.rb -v
687
+ # opts.verbose? #=> true
688
+ # opts.name? #=> false
689
+ # @see Slop#present?
690
+ # @return [Boolean] true if this option is present, false otherwise
691
+ def method_missing(meth, *args, &block)
692
+ super unless meth.to_s[-1, 1] == '?'
693
+ present = present? meth.to_s.chomp('?')
694
+
695
+ (class << self; self; end).instance_eval do
696
+ define_method(meth) { present }
697
+ end
698
+
699
+ present
700
+ end
701
+
702
+ # Check if an option is specified in the parsed list
703
+ #
704
+ # Does the same as Slop#option? but a convenience method for unacceptable
705
+ # method names
706
+ #
707
+ # @param [Object] The object name(s) to check
708
+ # @since 1.5.0
709
+ # @return [Boolean] true if these options are present, false otherwise
710
+ def present?(*option_names)
711
+ option_names.all? { |opt| @options[opt] && @options[opt].count > 0 }
712
+ end
713
+
714
+ # Returns the banner followed by available options listed on the next line
715
+ #
716
+ # @example
717
+ # opts = Slop.parse do
718
+ # banner "Usage - ruby foo.rb [arguments]"
719
+ # on :v, :verbose, "Enable verbose mode"
720
+ # end
721
+ # puts opts
722
+ # @return [String] Help text.
723
+ def to_s
724
+ parts = []
725
+
726
+ parts << banner if banner
727
+ parts << summary if summary
728
+ parts << wrap_and_indent(description, 80, 4) if description
729
+
730
+ if options.size > 0
731
+ parts << "options:"
732
+
733
+ heads = @options.reject(&:tail)
734
+ tails = @options.select(&:tail)
735
+ all = (heads + tails).select(&:help)
736
+
737
+ parts << all.map(&:to_s).join("\n")
738
+ end
739
+
740
+ parts.join("\n\n")
741
+ end
742
+ alias help to_s
743
+
744
+ # @return [String] This Slop object will options and configuration
745
+ # settings revealed
746
+ def inspect
747
+ "#<Slop config_options=#{@sloptions.inspect}\n " +
748
+ options.map(&:inspect).join("\n ") + "\n>"
749
+ end
750
+
751
+ private
752
+
753
+ class << self
754
+ private
755
+
756
+ def initialize_and_parse(items, delete, options, &block)
757
+ if items.is_a?(Hash) && options.empty?
758
+ options = items
759
+ items = ARGV
760
+ end
761
+
762
+ slop = new(options, &block)
763
+ delete ? slop.parse!(items) : slop.parse(items)
764
+ slop
765
+ end
766
+ end
767
+
768
+ # traverse through the list of items sent to parse() or parse!() and
769
+ # attempt to do the following:
770
+ #
771
+ # * Find an option object
772
+ # * Assign an argument to this option
773
+ # * Validate an option and/or argument depending on configuration options
774
+ # * Remove non-parsed items if `delete` is true
775
+ # * Yield any non-options to the block (if one is given)
776
+ def parse_items(items, delete=false, &block)
777
+ if items.empty? and @on_empty.respond_to?(:call)
778
+ @on_empty.call self
779
+ return items
780
+ elsif not items.any? {|i| i.to_s[/\A--?/] } and @on_noopts.respond_to?(:call)
781
+ @on_noopts.call self
782
+ return items
783
+ elsif execute_command(items, delete)
784
+ return items
785
+ end
786
+
787
+ trash = []
788
+ ignore_all = false
789
+
790
+ items.each_with_index do |item, index|
791
+ item = item.to_s
792
+ flag = item.sub(/\A--?/, '')
793
+
794
+ if item == '--'
795
+ trash << index
796
+ ignore_all = true
797
+ end
798
+
799
+ next if ignore_all
800
+ autocreate(flag, index, items) if @autocreate
801
+ option, argument = extract_option(item, flag)
802
+
803
+ if @multiple_switches and item[/\A-[^-]/] and not option
804
+ trash << index
805
+ next
806
+ end
807
+
808
+ if option
809
+ option.count += 1 unless item[/\A--no-/]
810
+ trash << index
811
+ next if option.forced
812
+ option.argument_value = true
813
+
814
+ if option.expects_argument? or option.accepts_optional_argument?
815
+ argument ||= items.at(index + 1)
816
+ trash << index + 1
817
+
818
+ if not option.accepts_optional_argument? and argument =~ /\A--?[a-zA-Z][a-zA-Z0-9_-]*\z/
819
+ raise MissingArgumentError, "'#{option.key}' expects an argument, none given"
820
+ end
821
+
822
+ if argument
823
+ if option.match and not argument.match(option.match)
824
+ raise InvalidArgumentError, "'#{argument}' does not match #{option.match.inspect}"
825
+ end
826
+
827
+ option.argument_value = argument
828
+ option.call option.argument_value unless option.omit_exec?(items)
829
+ else
830
+ option.argument_value = nil
831
+ check_optional_argument!(option, flag)
832
+ end
833
+ else
834
+ option.call unless option.omit_exec?(items)
835
+ end
836
+ else
837
+ @invalid_options << flag if item[/\A--?/] and @strict
838
+ block.call(item) if block_given? and not trash.include?(index)
839
+ end
840
+ end
841
+
842
+ items.reject!.with_index { |o, i| trash.include?(i) } if delete
843
+ raise_if_invalid_options!
844
+ raise_if_missing_required_options!(items)
845
+ items
846
+ end
847
+
848
+ def check_optional_argument!(option, flag)
849
+ if option.accepts_optional_argument?
850
+ option.call
851
+ else
852
+ raise MissingArgumentError, "'#{flag}' expects an argument, none given"
853
+ end
854
+ end
855
+
856
+ def raise_if_invalid_options!
857
+ return if not @strict or @invalid_options.empty?
858
+ message = "Unknown option#{'s' if @invalid_options.size > 1}"
859
+ message << ' -- ' << @invalid_options.map { |o| "'#{o}'" }.join(', ')
860
+ raise InvalidOptionError, message
861
+ end
862
+
863
+ def raise_if_missing_required_options!(items)
864
+ @options.select(&:required).each do |o|
865
+ unless items.select {|i| i[/\A--?/] }.any? {|i| i.to_s.sub(/\A--?/, '') == o.key }
866
+ raise MissingOptionError, "Expected option `#{o.key}` is required"
867
+ end
868
+ end
869
+ end
870
+
871
+ # if multiple_switches is enabled, this method filters through an items
872
+ # characters and attempts to find an Option object for each flag.
873
+ #
874
+ # Raises if a flag expects an argument or strict mode is enabled and a
875
+ # flag was not found
876
+ def enable_multiple_switches(item)
877
+ item[1..-1].each_char do |switch|
878
+ option = @options[switch]
879
+
880
+ if option
881
+ if option.expects_argument?
882
+ raise MissingArgumentError, "'-#{switch}' expects an argument, used in multiple_switch context"
883
+ end
884
+
885
+ option.argument_value = true
886
+ option.count += 1
887
+ else
888
+ raise InvalidOptionError, "Unknown option '-#{switch}'" if @strict
889
+ end
890
+ end
891
+ end
892
+
893
+ def wrap_and_indent(string, width, indentation)
894
+ string.lines.map do |paragraph|
895
+ lines = []
896
+ line = ''
897
+
898
+ paragraph.split(/\s/).each do |word|
899
+ if (line + ' ' + word).length >= width
900
+ lines << line
901
+ line = ''
902
+ end
903
+
904
+ line << (line == '' ? '' : ' ' ) + word
905
+ end
906
+ lines << line
907
+
908
+ lines.map { |l| ' ' * indentation + l }.join("\n")
909
+ end.join("\n")
910
+ end
911
+
912
+ # attempt to extract an option from an argument, this method allows us
913
+ # to parse things like 'foo=bar' and '--no-value' for negative values
914
+ # returns an array of the Option object and an argument if one was found
915
+ def extract_option(item, flag)
916
+ if item[0, 1] == '-'
917
+ option = @options[flag]
918
+ option ||= @options[flag.downcase] if @ignore_case
919
+ end
920
+
921
+ unless option
922
+ case item
923
+ when /\A-[^-]/
924
+ if @multiple_switches
925
+ enable_multiple_switches(item)
926
+ else
927
+ flag, argument = flag.split('', 2)
928
+ option = @options[flag]
929
+ end
930
+ when /\A--([^=]+)=(.+)\z/
931
+ option, argument = @options[$1], $2
932
+ when /\A--no-(.+)\z/
933
+ option = @options[$1]
934
+ option.force_argument_value(false) if option
935
+ end
936
+ end
937
+
938
+ [option, argument]
939
+ end
940
+
941
+ # attempt to execute a command if one exists, returns a positive (tru-ish)
942
+ # result if the command was found and executed. If completion is enabled
943
+ # and a flag is found to be ambiguous, this method prints an error message
944
+ # to the @io object informing the user
945
+ def execute_command(items, delete)
946
+ str = items[0]
947
+
948
+ if str
949
+ command = @commands.keys.find { |c| c.to_s == str.to_s }
950
+
951
+ if @completion and not command
952
+ cmds = @commands.keys.select { |c| c.to_s[0, str.length] == str }
953
+
954
+ if cmds.size > 1
955
+ @io.puts "Command '#{str}' is ambiguous:"
956
+ @io.puts " " + cmds.map(&:to_s).sort.join(', ')
957
+ else
958
+ command = cmds.shift
959
+ end
960
+ end
961
+ end
962
+
963
+ if command
964
+ items.shift
965
+ opts = @commands[command]
966
+ delete ? opts.parse!(items) : opts.parse(items)
967
+ opts.execute(items.reject { |i| i == '--' })
968
+ end
969
+ end
970
+
971
+ # If autocreation is enabled this method simply generates an option
972
+ # and add's it to the existing list of options
973
+ def autocreate(flag, index, items)
974
+ return if present? flag
975
+ short, long = clean_options Array(flag)
976
+ arg = (items[index + 1] && items[index + 1] !~ /\A--?/)
977
+ option = Option.new(self, short, long, nil, arg, {})
978
+ option.count = 1
979
+ @options << option
980
+ end
981
+
982
+ # Clean up arguments sent to `on` and return a list of 5 elements:
983
+ # * short flag (or nil)
984
+ # * long flag (or nil)
985
+ # * description (or nil)
986
+ # * true/false if this option takes an argument or not
987
+ # * extra options (ie: :as, :optional, and :help)
988
+ def clean_options(args)
989
+ options = []
990
+ extras = {}
991
+ extras[:as] = args.find { |c| c.is_a? Class }
992
+ args.delete(extras[:as])
993
+ extras.delete(:as) if extras[:as].nil?
994
+
995
+ short = args.first.to_s.sub(/\A--?/, '')
996
+ if short.size == 1
997
+ options.push short
998
+ args.shift
999
+ else
1000
+ options.push nil
1001
+ end
1002
+
1003
+ long = args.first
1004
+ boolean = [true, false].include? long
1005
+
1006
+ if not boolean and long.to_s =~ /\A(?:--?)?[a-z_-]+\s[A-Z\s\[\]]+\z/
1007
+ arg, help = args.shift.split(/ /, 2)
1008
+ options.push arg.sub(/\A--?/, '')
1009
+ extras[:optional] = help[0, 1] == '[' && help[-1, 1] == ']'
1010
+ extras[:help] = help
1011
+ elsif not boolean and long.to_s =~ /\A(?:--?)?[a-zA-Z][a-zA-Z0-9_-]+\=?\z/
1012
+ extras[:argument] = true if long.to_s[-1, 1] == '='
1013
+ options.push args.shift.to_s.sub(/\A--?/, '').sub(/\=\z/, '')
1014
+ else
1015
+ options.push nil
1016
+ end
1017
+
1018
+ options.push args.first.respond_to?(:to_sym) ? args.shift : nil
1019
+ options.push((@arguments || extras[:argument]) ? true : (args.shift ? true : false))
1020
+ options.push extras
1021
+ end
1022
+ end