cft_smartcloud 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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