pry 0.12.2-java → 0.13.0-java

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 (158) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +110 -1
  3. data/LICENSE +1 -1
  4. data/README.md +331 -269
  5. data/bin/pry +5 -0
  6. data/lib/pry.rb +133 -119
  7. data/lib/pry/basic_object.rb +8 -4
  8. data/lib/pry/block_command.rb +22 -0
  9. data/lib/pry/class_command.rb +194 -0
  10. data/lib/pry/cli.rb +40 -31
  11. data/lib/pry/code.rb +39 -27
  12. data/lib/pry/code/code_file.rb +28 -24
  13. data/lib/pry/code/code_range.rb +4 -2
  14. data/lib/pry/code/loc.rb +15 -8
  15. data/lib/pry/code_object.rb +40 -38
  16. data/lib/pry/color_printer.rb +47 -46
  17. data/lib/pry/command.rb +166 -369
  18. data/lib/pry/command_set.rb +76 -73
  19. data/lib/pry/command_state.rb +31 -0
  20. data/lib/pry/commands/amend_line.rb +86 -81
  21. data/lib/pry/commands/bang.rb +18 -14
  22. data/lib/pry/commands/bang_pry.rb +15 -11
  23. data/lib/pry/commands/cat.rb +61 -54
  24. data/lib/pry/commands/cat/abstract_formatter.rb +23 -18
  25. data/lib/pry/commands/cat/exception_formatter.rb +71 -60
  26. data/lib/pry/commands/cat/file_formatter.rb +55 -49
  27. data/lib/pry/commands/cat/input_expression_formatter.rb +35 -30
  28. data/lib/pry/commands/cd.rb +40 -35
  29. data/lib/pry/commands/change_inspector.rb +29 -22
  30. data/lib/pry/commands/change_prompt.rb +44 -39
  31. data/lib/pry/commands/clear_screen.rb +16 -10
  32. data/lib/pry/commands/code_collector.rb +148 -133
  33. data/lib/pry/commands/disable_pry.rb +23 -19
  34. data/lib/pry/commands/easter_eggs.rb +19 -30
  35. data/lib/pry/commands/edit.rb +184 -161
  36. data/lib/pry/commands/edit/exception_patcher.rb +21 -17
  37. data/lib/pry/commands/edit/file_and_line_locator.rb +34 -23
  38. data/lib/pry/commands/exit.rb +39 -35
  39. data/lib/pry/commands/exit_all.rb +24 -20
  40. data/lib/pry/commands/exit_program.rb +20 -16
  41. data/lib/pry/commands/find_method.rb +168 -160
  42. data/lib/pry/commands/fix_indent.rb +16 -12
  43. data/lib/pry/commands/help.rb +140 -133
  44. data/lib/pry/commands/hist.rb +151 -150
  45. data/lib/pry/commands/import_set.rb +20 -16
  46. data/lib/pry/commands/jump_to.rb +25 -21
  47. data/lib/pry/commands/list_inspectors.rb +35 -28
  48. data/lib/pry/commands/ls.rb +124 -102
  49. data/lib/pry/commands/ls/constants.rb +59 -42
  50. data/lib/pry/commands/ls/formatter.rb +50 -46
  51. data/lib/pry/commands/ls/globals.rb +38 -34
  52. data/lib/pry/commands/ls/grep.rb +17 -13
  53. data/lib/pry/commands/ls/instance_vars.rb +29 -27
  54. data/lib/pry/commands/ls/interrogatable.rb +18 -12
  55. data/lib/pry/commands/ls/jruby_hacks.rb +47 -41
  56. data/lib/pry/commands/ls/local_names.rb +26 -22
  57. data/lib/pry/commands/ls/local_vars.rb +38 -28
  58. data/lib/pry/commands/ls/ls_entity.rb +47 -51
  59. data/lib/pry/commands/ls/methods.rb +44 -43
  60. data/lib/pry/commands/ls/methods_helper.rb +46 -42
  61. data/lib/pry/commands/ls/self_methods.rb +23 -22
  62. data/lib/pry/commands/nesting.rb +21 -17
  63. data/lib/pry/commands/play.rb +93 -82
  64. data/lib/pry/commands/pry_backtrace.rb +24 -17
  65. data/lib/pry/commands/pry_version.rb +15 -11
  66. data/lib/pry/commands/raise_up.rb +27 -22
  67. data/lib/pry/commands/reload_code.rb +60 -48
  68. data/lib/pry/commands/reset.rb +16 -12
  69. data/lib/pry/commands/ri.rb +55 -45
  70. data/lib/pry/commands/save_file.rb +45 -43
  71. data/lib/pry/commands/shell_command.rb +51 -51
  72. data/lib/pry/commands/shell_mode.rb +21 -17
  73. data/lib/pry/commands/show_doc.rb +81 -68
  74. data/lib/pry/commands/show_info.rb +189 -171
  75. data/lib/pry/commands/show_input.rb +16 -11
  76. data/lib/pry/commands/show_source.rb +109 -45
  77. data/lib/pry/commands/stat.rb +35 -31
  78. data/lib/pry/commands/switch_to.rb +21 -15
  79. data/lib/pry/commands/toggle_color.rb +20 -16
  80. data/lib/pry/commands/watch_expression.rb +89 -86
  81. data/lib/pry/commands/watch_expression/expression.rb +32 -27
  82. data/lib/pry/commands/whereami.rb +156 -148
  83. data/lib/pry/commands/wtf.rb +75 -50
  84. data/lib/pry/config.rb +311 -25
  85. data/lib/pry/config/attributable.rb +22 -0
  86. data/lib/pry/config/lazy_value.rb +29 -0
  87. data/lib/pry/config/memoized_value.rb +34 -0
  88. data/lib/pry/config/value.rb +24 -0
  89. data/lib/pry/control_d_handler.rb +28 -0
  90. data/lib/pry/core_extensions.rb +9 -7
  91. data/lib/pry/editor.rb +48 -21
  92. data/lib/pry/env.rb +18 -0
  93. data/lib/pry/exception_handler.rb +43 -0
  94. data/lib/pry/exceptions.rb +13 -16
  95. data/lib/pry/forwardable.rb +5 -1
  96. data/lib/pry/helpers.rb +2 -0
  97. data/lib/pry/helpers/base_helpers.rb +68 -197
  98. data/lib/pry/helpers/command_helpers.rb +50 -61
  99. data/lib/pry/helpers/documentation_helpers.rb +20 -13
  100. data/lib/pry/helpers/options_helpers.rb +14 -7
  101. data/lib/pry/helpers/platform.rb +7 -5
  102. data/lib/pry/helpers/table.rb +33 -26
  103. data/lib/pry/helpers/text.rb +17 -14
  104. data/lib/pry/history.rb +48 -56
  105. data/lib/pry/hooks.rb +21 -12
  106. data/lib/pry/indent.rb +54 -50
  107. data/lib/pry/input_completer.rb +248 -230
  108. data/lib/pry/input_lock.rb +8 -9
  109. data/lib/pry/inspector.rb +36 -24
  110. data/lib/pry/last_exception.rb +45 -45
  111. data/lib/pry/method.rb +141 -94
  112. data/lib/pry/method/disowned.rb +16 -4
  113. data/lib/pry/method/patcher.rb +12 -3
  114. data/lib/pry/method/weird_method_locator.rb +68 -44
  115. data/lib/pry/object_path.rb +33 -25
  116. data/lib/pry/output.rb +121 -35
  117. data/lib/pry/pager.rb +41 -42
  118. data/lib/pry/plugins.rb +25 -8
  119. data/lib/pry/prompt.rb +123 -54
  120. data/lib/pry/pry_class.rb +61 -98
  121. data/lib/pry/pry_instance.rb +217 -215
  122. data/lib/pry/repl.rb +18 -22
  123. data/lib/pry/repl_file_loader.rb +27 -21
  124. data/lib/pry/ring.rb +11 -6
  125. data/lib/pry/slop.rb +574 -563
  126. data/lib/pry/slop/commands.rb +164 -169
  127. data/lib/pry/slop/option.rb +172 -168
  128. data/lib/pry/syntax_highlighter.rb +26 -0
  129. data/lib/pry/system_command_handler.rb +17 -0
  130. data/lib/pry/testable.rb +59 -61
  131. data/lib/pry/testable/evalable.rb +21 -12
  132. data/lib/pry/testable/mockable.rb +18 -10
  133. data/lib/pry/testable/pry_tester.rb +71 -56
  134. data/lib/pry/testable/utility.rb +29 -21
  135. data/lib/pry/testable/variables.rb +49 -43
  136. data/lib/pry/version.rb +3 -1
  137. data/lib/pry/warning.rb +27 -0
  138. data/lib/pry/wrapped_module.rb +51 -42
  139. data/lib/pry/wrapped_module/candidate.rb +21 -14
  140. metadata +31 -30
  141. data/lib/pry/commands.rb +0 -6
  142. data/lib/pry/commands/disabled_commands.rb +0 -2
  143. data/lib/pry/commands/gem_cd.rb +0 -26
  144. data/lib/pry/commands/gem_install.rb +0 -32
  145. data/lib/pry/commands/gem_list.rb +0 -33
  146. data/lib/pry/commands/gem_open.rb +0 -29
  147. data/lib/pry/commands/gem_readme.rb +0 -25
  148. data/lib/pry/commands/gem_search.rb +0 -40
  149. data/lib/pry/commands/gem_stats.rb +0 -83
  150. data/lib/pry/commands/gist.rb +0 -102
  151. data/lib/pry/commands/install_command.rb +0 -54
  152. data/lib/pry/config/behavior.rb +0 -255
  153. data/lib/pry/config/convenience.rb +0 -28
  154. data/lib/pry/config/default.rb +0 -159
  155. data/lib/pry/config/memoization.rb +0 -48
  156. data/lib/pry/platform.rb +0 -91
  157. data/lib/pry/rubygem.rb +0 -84
  158. data/lib/pry/terminal.rb +0 -91
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Pry
2
4
  class REPL
3
5
  extend Pry::Forwardable
@@ -19,13 +21,11 @@ class Pry
19
21
  # @option options [Object] :target The initial target of the session.
20
22
  def initialize(pry, options = {})
21
23
  @pry = pry
22
- @indent = Pry::Indent.new
24
+ @indent = Pry::Indent.new(pry)
23
25
 
24
26
  @readline_output = nil
25
27
 
26
- if options[:target]
27
- @pry.push_binding options[:target]
28
- end
28
+ @pry.push_binding options[:target] if options[:target]
29
29
  end
30
30
 
31
31
  # Start the read-eval-print loop.
@@ -47,10 +47,10 @@ class Pry
47
47
  def prologue
48
48
  pry.exec_hook :before_session, pry.output, pry.current_binding, pry
49
49
 
50
+ return unless pry.config.correct_indent
51
+
50
52
  # Clear the line before starting Pry. This fixes issue #566.
51
- if pry.config.correct_indent
52
- Kernel.print(Helpers::Platform.windows_ansi? ? "\e[0F" : "\e[0G")
53
- end
53
+ output.print(Helpers::Platform.windows_ansi? ? "\e[0F" : "\e[0G")
54
54
  end
55
55
 
56
56
  # The actual read-eval-print loop.
@@ -98,13 +98,15 @@ class Pry
98
98
  val = read_line("#{current_prompt}#{indentation}")
99
99
 
100
100
  # Return nil for EOF, :no_more_input for error, or :control_c for <Ctrl-C>
101
- return val unless String === val
101
+ return val unless val.is_a?(String)
102
102
 
103
103
  if pry.config.auto_indent
104
104
  original_val = "#{indentation}#{val}"
105
105
  indented_val = @indent.indent(val)
106
106
 
107
- if output.tty? && pry.config.correct_indent && Pry::Helpers::BaseHelpers.use_ansi_codes?
107
+ if output.tty? &&
108
+ pry.config.correct_indent &&
109
+ Pry::Helpers::BaseHelpers.use_ansi_codes?
108
110
  output.print @indent.correct_indentation(
109
111
  current_prompt,
110
112
  indented_val,
@@ -130,7 +132,7 @@ class Pry
130
132
  yield
131
133
  rescue EOFError
132
134
  pry.config.input = Pry.config.input
133
- if !should_retry
135
+ unless should_retry
134
136
  output.puts "Error: Pry ran out of things to read from! " \
135
137
  "Attempting to break out of REPL."
136
138
  return :no_more_input
@@ -151,9 +153,7 @@ class Pry
151
153
  puts "Error: #{e.message}"
152
154
  output.puts e.backtrace
153
155
  exception_count += 1
154
- if exception_count < 5
155
- retry
156
- end
156
+ retry if exception_count < 5
157
157
  puts "FATAL: Pry failed to get user input using `#{input}`."
158
158
  puts "To fix this you may be able to pass input and output file " \
159
159
  "descriptors to pry directly. e.g."
@@ -185,12 +185,10 @@ class Pry
185
185
  input_readline(current_prompt, false) # false since we'll add it manually
186
186
  elsif coolline_available?
187
187
  input_readline(current_prompt)
188
+ elsif input.method(:readline).arity == 1
189
+ input_readline(current_prompt)
188
190
  else
189
- if input.method(:readline).arity == 1
190
- input_readline(current_prompt)
191
- else
192
- input_readline
193
- end
191
+ input_readline
194
192
  end
195
193
  end
196
194
  end
@@ -227,9 +225,7 @@ class Pry
227
225
  def set_readline_output
228
226
  return if @readline_output
229
227
 
230
- if piping?
231
- @readline_output = (Readline.output = Pry.config.output)
232
- end
228
+ @readline_output = (Readline.output = Pry.config.output) if piping?
233
229
  end
234
230
 
235
231
  # Calculates correct overhang for current line. Supports vi Readline
@@ -247,7 +243,7 @@ class Pry
247
243
  # rb-readline doesn't support this method:
248
244
  # https://github.com/ConnorAtherton/rb-readline/issues/152
249
245
  if Readline.vi_editing_mode?
250
- overhang += current_prompt.length - indented_val.length
246
+ overhang = output.width - current_prompt.size - indented_val.size
251
247
  end
252
248
  rescue NotImplementedError
253
249
  # VI editing mode is unsupported on JRuby.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Pry
2
4
  # A class to manage the loading of files through the REPL loop.
3
5
  # This is an interesting trick as it processes your file as if it
@@ -12,7 +14,7 @@ class Pry
12
14
  class REPLFileLoader
13
15
  def initialize(file_name)
14
16
  full_name = File.expand_path(file_name)
15
- raise RuntimeError, "No such file: #{full_name}" if !File.exist?(full_name)
17
+ raise "No such file: #{full_name}" unless File.exist?(full_name)
16
18
 
17
19
  define_additional_commands
18
20
  @content = File.read(full_name)
@@ -20,34 +22,36 @@ class Pry
20
22
 
21
23
  # Switch to interactive mode, i.e take input from the user
22
24
  # and use the regular print and exception handlers.
23
- # @param [Pry] _pry_ the Pry instance to make interactive.
24
- def interactive_mode(_pry_)
25
- _pry_.config.input = Pry.config.input
26
- _pry_.config.print = Pry.config.print
27
- _pry_.config.exception_handler = Pry.config.exception_handler
28
- Pry::REPL.new(_pry_).start
25
+ # @param [Pry] pry_instance the Pry instance to make interactive.
26
+ def interactive_mode(pry_instance)
27
+ pry_instance.config.input = Pry.config.input
28
+ pry_instance.config.print = Pry.config.print
29
+ pry_instance.config.exception_handler = Pry.config.exception_handler
30
+ Pry::REPL.new(pry_instance).start
29
31
  end
30
32
 
31
33
  # Switch to non-interactive mode. Essentially
32
34
  # this means there is no result output
33
35
  # and that the session becomes interactive when an exception is encountered.
34
- # @param [Pry] _pry_ the Pry instance to make non-interactive.
35
- def non_interactive_mode(_pry_, content)
36
- _pry_.print = proc {}
37
- _pry_.exception_handler = proc do |o, e, _p_|
38
- _p_.run_command "cat --ex"
36
+ # @param [Pry] pry_instance the Pry instance to make non-interactive.
37
+ def non_interactive_mode(pry_instance, content)
38
+ pry_instance.print = proc {}
39
+ pry_instance.exception_handler = proc do |o, _e, p|
40
+ p.run_command "cat --ex"
39
41
  o.puts "...exception encountered, going interactive!"
40
- interactive_mode(_pry_)
42
+ interactive_mode(pry_instance)
41
43
  end
42
44
 
43
45
  content.lines.each do |line|
44
- break unless _pry_.eval line, generated: true
46
+ break unless pry_instance.eval line, generated: true
45
47
  end
46
48
 
47
- unless _pry_.eval_string.empty?
48
- _pry_.output.puts "#{_pry_.eval_string}...exception encountered, going interactive!"
49
- interactive_mode(_pry_)
50
- end
49
+ return if pry_instance.eval_string.empty?
50
+
51
+ pry_instance.output.puts(
52
+ "#{pry_instance.eval_string}...exception encountered, going interactive!"
53
+ )
54
+ interactive_mode(pry_instance)
51
55
  end
52
56
 
53
57
  # Define a few extra commands useful for flipping back & forth
@@ -56,11 +60,13 @@ class Pry
56
60
  s = self
57
61
 
58
62
  Pry::Commands.command "make-interactive", "Make the session interactive" do
59
- s.interactive_mode(_pry_)
63
+ s.interactive_mode(pry_instance)
60
64
  end
61
65
 
62
- Pry::Commands.command "load-file", "Load another file through the repl" do |file_name|
63
- s.non_interactive_mode(_pry_, File.read(File.expand_path(file_name)))
66
+ Pry::Commands.command(
67
+ "load-file", "Load another file through the repl"
68
+ ) do |file_name|
69
+ s.non_interactive_mode(pry_instance, File.read(File.expand_path(file_name)))
64
70
  end
65
71
  end
66
72
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Pry
2
4
  # A ring is a thread-safe fixed-capacity array to which you can only add
3
5
  # elements. Older entries are overwritten as you add new elements, so that the
@@ -57,10 +59,7 @@ class Pry
57
59
  return @buffer[(count + index) % max_size] if index.is_a?(Integer)
58
60
  return @buffer[index] if count <= max_size
59
61
 
60
- # Swap parts of array when the array turns page and starts overwriting
61
- # from the beginning, then apply the range.
62
- last_part = @buffer.slice([index.end, max_size - 1].min, count % max_size)
63
- (last_part + (@buffer - last_part))[index]
62
+ transpose_buffer_tail[index]
64
63
  end
65
64
  end
66
65
 
@@ -68,8 +67,7 @@ class Pry
68
67
  def to_a
69
68
  return @buffer.dup if count <= max_size
70
69
 
71
- last_part = @buffer.slice(count % max_size, @buffer.size)
72
- last_part + (@buffer - last_part)
70
+ transpose_buffer_tail
73
71
  end
74
72
 
75
73
  # Clear the buffer and reset count.
@@ -80,5 +78,12 @@ class Pry
80
78
  @count = 0
81
79
  end
82
80
  end
81
+
82
+ private
83
+
84
+ def transpose_buffer_tail
85
+ tail = @buffer.slice(count % max_size, @buffer.size)
86
+ tail.concat @buffer.slice(0, count % max_size)
87
+ end
83
88
  end
84
89
  end
@@ -1,661 +1,672 @@
1
- class Pry::Slop
2
- require_relative 'slop/option'
3
- require_relative 'slop/commands'
4
- include Enumerable
5
- VERSION = '3.4.0'
6
-
7
- # The main Error class, all Exception classes inherit from this class.
8
- class Error < StandardError; end
9
-
10
- # Raised when an option argument is expected but none are given.
11
- class MissingArgumentError < Error; end
12
-
13
- # Raised when an option is expected/required but not present.
14
- class MissingOptionError < Error; end
15
-
16
- # Raised when an argument does not match its intended match constraint.
17
- class InvalidArgumentError < Error; end
18
-
19
- # Raised when an invalid option is found and the strict flag is enabled.
20
- class InvalidOptionError < Error; end
21
-
22
- # Raised when an invalid command is found and the strict flag is enabled.
23
- class InvalidCommandError < Error; end
24
-
25
- # Returns a default Hash of configuration options this Slop instance uses.
26
- DEFAULT_OPTIONS = {
27
- strict: false,
28
- help: false,
29
- banner: nil,
30
- ignore_case: false,
31
- autocreate: false,
32
- arguments: false,
33
- optional_arguments: false,
34
- multiple_switches: true,
35
- longest_flag: 0
36
- }
37
-
38
- class << self
39
- # items - The Array of items to extract options from (default: ARGV).
40
- # config - The Hash of configuration options to send to Slop.new().
41
- # block - An optional block used to add options.
42
- #
43
- # Examples:
44
- #
45
- # Slop.parse(ARGV, :help => true) do
46
- # on '-n', '--name', 'Your username', :argument => true
47
- # end
1
+ # frozen_string_literal: true
2
+
3
+ class Pry
4
+ # rubocop:disable Metrics/ClassLength
5
+ class Slop
6
+ require_relative 'slop/option'
7
+ require_relative 'slop/commands'
8
+ include Enumerable
9
+ VERSION = '3.4.0'.freeze
10
+
11
+ # The main Error class, all Exception classes inherit from this class.
12
+ class Error < StandardError; end
13
+
14
+ # Raised when an option argument is expected but none are given.
15
+ class MissingArgumentError < Error; end
16
+
17
+ # Raised when an option is expected/required but not present.
18
+ class MissingOptionError < Error; end
19
+
20
+ # Raised when an argument does not match its intended match constraint.
21
+ class InvalidArgumentError < Error; end
22
+
23
+ # Raised when an invalid option is found and the strict flag is enabled.
24
+ class InvalidOptionError < Error; end
25
+
26
+ # Raised when an invalid command is found and the strict flag is enabled.
27
+ class InvalidCommandError < Error; end
28
+
29
+ # Returns a default Hash of configuration options this Slop instance uses.
30
+ DEFAULT_OPTIONS = {
31
+ strict: false,
32
+ help: false,
33
+ banner: nil,
34
+ ignore_case: false,
35
+ autocreate: false,
36
+ arguments: false,
37
+ optional_arguments: false,
38
+ multiple_switches: true,
39
+ longest_flag: 0
40
+ }.freeze
41
+
42
+ class << self
43
+ # items - The Array of items to extract options from (default: ARGV).
44
+ # config - The Hash of configuration options to send to Slop.new().
45
+ # block - An optional block used to add options.
46
+ #
47
+ # Examples:
48
+ #
49
+ # Slop.parse(ARGV, :help => true) do
50
+ # on '-n', '--name', 'Your username', :argument => true
51
+ # end
52
+ #
53
+ # Returns a new instance of Slop.
54
+ def parse(items = ARGV, config = {}, &block)
55
+ parse! items.dup, config, &block
56
+ end
57
+
58
+ # items - The Array of items to extract options from (default: ARGV).
59
+ # config - The Hash of configuration options to send to Slop.new().
60
+ # block - An optional block used to add options.
61
+ #
62
+ # Returns a new instance of Slop.
63
+ def parse!(items = ARGV, config = {}, &block)
64
+ if items.is_a?(Hash) && config.empty?
65
+ config = items
66
+ items = ARGV
67
+ end
68
+ slop = Pry::Slop.new config, &block
69
+ slop.parse! items
70
+ slop
71
+ end
72
+
73
+ # Build a Slop object from a option specification.
74
+ #
75
+ # This allows you to design your options via a simple String rather
76
+ # than programatically. Do note though that with this method, you're
77
+ # unable to pass any advanced options to the on() method when creating
78
+ # options.
79
+ #
80
+ # string - The optspec String
81
+ # config - A Hash of configuration options to pass to Slop.new
82
+ #
83
+ # Examples:
84
+ #
85
+ # opts = Slop.optspec(<<-SPEC)
86
+ # ruby foo.rb [options]
87
+ # ---
88
+ # n,name= Your name
89
+ # a,age= Your age
90
+ # A,auth Sign in with auth
91
+ # p,passcode= Your secret pass code
92
+ # SPEC
93
+ #
94
+ # opts.fetch_option(:name).description #=> "Your name"
95
+ #
96
+ # Returns a new instance of Slop.
97
+ def optspec(string, config = {})
98
+ config[:banner], optspec = string.split(/^--+$/, 2) if string[/^--+$/]
99
+ lines = optspec.split("\n").reject(&:empty?)
100
+ opts = Slop.new(config)
101
+
102
+ lines.each do |line|
103
+ opt, description = line.split(' ', 2)
104
+ short, long = opt.split(',').map { |s| s.sub(/\A--?/, '') }
105
+ opt = opts.on(short, long, description)
106
+
107
+ if long && long.end_with?('=')
108
+ long.sub!(/\=$/, '')
109
+ opt.config[:argument] = true
110
+ end
111
+ end
112
+
113
+ opts
114
+ end
115
+ end
116
+
117
+ # The Hash of configuration options for this Slop instance.
118
+ attr_reader :config
119
+
120
+ # The Array of Slop::Option objects tied to this Slop instance.
121
+ attr_reader :options
122
+
123
+ # Create a new instance of Slop and optionally build options via a block.
48
124
  #
49
- # Returns a new instance of Slop.
50
- def parse(items = ARGV, config = {}, &block)
51
- parse! items.dup, config, &block
125
+ # config - A Hash of configuration options.
126
+ # block - An optional block used to specify options.
127
+ def initialize(config = {}, &block)
128
+ @config = DEFAULT_OPTIONS.merge(config)
129
+ @options = []
130
+ @commands = {}
131
+ @trash = []
132
+ @triggered_options = []
133
+ @unknown_options = []
134
+ @callbacks = {}
135
+ @separators = {}
136
+ @runner = nil
137
+
138
+ if block_given?
139
+ block.arity == 1 ? yield(self) : instance_eval(&block)
140
+ end
141
+
142
+ return unless config[:help]
143
+
144
+ on('-h', '--help', 'Display this help message.', tail: true) do
145
+ warn help
146
+ end
52
147
  end
53
148
 
54
- # items - The Array of items to extract options from (default: ARGV).
55
- # config - The Hash of configuration options to send to Slop.new().
56
- # block - An optional block used to add options.
149
+ # Is strict mode enabled?
57
150
  #
58
- # Returns a new instance of Slop.
59
- def parse!(items = ARGV, config = {}, &block)
60
- config, items = items, ARGV if items.is_a?(Hash) && config.empty?
61
- slop = Pry::Slop.new config, &block
62
- slop.parse! items
63
- slop
151
+ # Returns true if strict mode is enabled, false otherwise.
152
+ def strict?
153
+ config[:strict]
64
154
  end
65
155
 
66
- # Build a Slop object from a option specification.
156
+ # Set the banner.
67
157
  #
68
- # This allows you to design your options via a simple String rather
69
- # than programatically. Do note though that with this method, you're
70
- # unable to pass any advanced options to the on() method when creating
71
- # options.
158
+ # banner - The String to set the banner.
159
+ def banner=(banner)
160
+ config[:banner] = banner
161
+ end
162
+
163
+ # Get or set the banner.
72
164
  #
73
- # string - The optspec String
74
- # config - A Hash of configuration options to pass to Slop.new
165
+ # banner - The String to set the banner.
75
166
  #
76
- # Examples:
77
- #
78
- # opts = Slop.optspec(<<-SPEC)
79
- # ruby foo.rb [options]
80
- # ---
81
- # n,name= Your name
82
- # a,age= Your age
83
- # A,auth Sign in with auth
84
- # p,passcode= Your secret pass code
85
- # SPEC
86
- #
87
- # opts.fetch_option(:name).description #=> "Your name"
88
- #
89
- # Returns a new instance of Slop.
90
- def optspec(string, config = {})
91
- config[:banner], optspec = string.split(/^--+$/, 2) if string[/^--+$/]
92
- lines = optspec.split("\n").reject(&:empty?)
93
- opts = Slop.new(config)
94
-
95
- lines.each do |line|
96
- opt, description = line.split(' ', 2)
97
- short, long = opt.split(',').map { |s| s.sub(/\A--?/, '') }
98
- opt = opts.on(short, long, description)
99
-
100
- if long && long.end_with?('=')
101
- long.sub!(/\=$/, '')
102
- opt.config[:argument] = true
103
- end
104
- end
105
-
106
- opts
167
+ # Returns the banner String.
168
+ def banner(banner = nil)
169
+ config[:banner] = banner if banner
170
+ config[:banner]
107
171
  end
108
- end
109
-
110
- # The Hash of configuration options for this Slop instance.
111
- attr_reader :config
112
172
 
113
- # The Array of Slop::Option objects tied to this Slop instance.
114
- attr_reader :options
173
+ # Set the description (used for commands).
174
+ #
175
+ # desc - The String to set the description.
176
+ def description=(desc)
177
+ config[:description] = desc
178
+ end
115
179
 
116
- # Create a new instance of Slop and optionally build options via a block.
117
- #
118
- # config - A Hash of configuration options.
119
- # block - An optional block used to specify options.
120
- def initialize(config = {}, &block)
121
- @config = DEFAULT_OPTIONS.merge(config)
122
- @options = []
123
- @commands = {}
124
- @trash = []
125
- @triggered_options = []
126
- @unknown_options = []
127
- @callbacks = {}
128
- @separators = {}
129
- @runner = nil
180
+ # Get or set the description (used for commands).
181
+ #
182
+ # desc - The String to set the description.
183
+ #
184
+ # Returns the description String.
185
+ def description(desc = nil)
186
+ config[:description] = desc if desc
187
+ config[:description]
188
+ end
130
189
 
131
- if block_given?
132
- block.arity == 1 ? yield(self) : instance_eval(&block)
190
+ # Add a new command.
191
+ #
192
+ # command - The Symbol or String used to identify this command.
193
+ # options - A Hash of configuration options (see Slop::new)
194
+ #
195
+ # Returns a new instance of Slop mapped to this command.
196
+ def command(command, options = {}, &block)
197
+ @commands[command.to_s] = Pry::Slop.new(options, &block)
133
198
  end
134
199
 
135
- if config[:help]
136
- on('-h', '--help', 'Display this help message.', tail: true) do
137
- $stderr.puts help
138
- end
200
+ # Parse a list of items, executing and gathering options along the way.
201
+ #
202
+ # items - The Array of items to extract options from (default: ARGV).
203
+ # block - An optional block which when used will yield non options.
204
+ #
205
+ # Returns an Array of original items.
206
+ def parse(items = ARGV, &block)
207
+ parse! items.dup, &block
208
+ items
139
209
  end
140
- end
141
210
 
142
- # Is strict mode enabled?
143
- #
144
- # Returns true if strict mode is enabled, false otherwise.
145
- def strict?
146
- config[:strict]
147
- end
211
+ # Parse a list of items, executing and gathering options along the way.
212
+ # unlike parse() this method will remove any options and option arguments
213
+ # from the original Array.
214
+ #
215
+ # items - The Array of items to extract options from (default: ARGV).
216
+ # block - An optional block which when used will yield non options.
217
+ #
218
+ # Returns an Array of original items with options removed.
219
+ def parse!(items = ARGV, &block)
220
+ if items.empty? && @callbacks[:empty]
221
+ @callbacks[:empty].each { |cb| cb.call(self) }
222
+ return items
223
+ end
148
224
 
149
- # Set the banner.
150
- #
151
- # banner - The String to set the banner.
152
- def banner=(banner)
153
- config[:banner] = banner
154
- end
225
+ if (cmd = @commands[items[0]])
226
+ return cmd.parse! items[1..-1]
227
+ end
155
228
 
156
- # Get or set the banner.
157
- #
158
- # banner - The String to set the banner.
159
- #
160
- # Returns the banner String.
161
- def banner(banner = nil)
162
- config[:banner] = banner if banner
163
- config[:banner]
164
- end
229
+ items.each_with_index do |item, index|
230
+ @trash << index && break if item == '--'
231
+ autocreate(items, index) if config[:autocreate]
232
+ process_item(items, index, &block) unless @trash.include?(index)
233
+ end
234
+ items.reject!.with_index { |_item, index| @trash.include?(index) }
165
235
 
166
- # Set the description (used for commands).
167
- #
168
- # desc - The String to set the description.
169
- def description=(desc)
170
- config[:description] = desc
171
- end
236
+ missing_options = options.select { |opt| opt.required? && opt.count < 1 }
237
+ if missing_options.any?
238
+ raise MissingOptionError,
239
+ "Missing required option(s): #{missing_options.map(&:key).join(', ')}"
240
+ end
172
241
 
173
- # Get or set the description (used for commands).
174
- #
175
- # desc - The String to set the description.
176
- #
177
- # Returns the description String.
178
- def description(desc = nil)
179
- config[:description] = desc if desc
180
- config[:description]
181
- end
242
+ if @unknown_options.any?
243
+ raise InvalidOptionError, "Unknown options #{@unknown_options.join(', ')}"
244
+ end
182
245
 
183
- # Add a new command.
184
- #
185
- # command - The Symbol or String used to identify this command.
186
- # options - A Hash of configuration options (see Slop::new)
187
- #
188
- # Returns a new instance of Slop mapped to this command.
189
- def command(command, options = {}, &block)
190
- @commands[command.to_s] = Pry::Slop.new(options, &block)
191
- end
246
+ if @triggered_options.empty? && @callbacks[:no_options]
247
+ @callbacks[:no_options].each { |cb| cb.call(self) }
248
+ end
192
249
 
193
- # Parse a list of items, executing and gathering options along the way.
194
- #
195
- # items - The Array of items to extract options from (default: ARGV).
196
- # block - An optional block which when used will yield non options.
197
- #
198
- # Returns an Array of original items.
199
- def parse(items = ARGV, &block)
200
- parse! items.dup, &block
201
- items
202
- end
250
+ @runner.call(self, items) if @runner.respond_to?(:call)
203
251
 
204
- # Parse a list of items, executing and gathering options along the way.
205
- # unlike parse() this method will remove any options and option arguments
206
- # from the original Array.
207
- #
208
- # items - The Array of items to extract options from (default: ARGV).
209
- # block - An optional block which when used will yield non options.
210
- #
211
- # Returns an Array of original items with options removed.
212
- def parse!(items = ARGV, &block)
213
- if items.empty? && @callbacks[:empty]
214
- @callbacks[:empty].each { |cb| cb.call(self) }
215
- return items
252
+ items
216
253
  end
217
254
 
218
- if (cmd = @commands[items[0]])
219
- return cmd.parse! items[1..-1]
255
+ # Add an Option.
256
+ #
257
+ # objects - An Array with an optional Hash as the last element.
258
+ #
259
+ # Examples:
260
+ #
261
+ # on '-u', '--username=', 'Your username'
262
+ # on :v, :verbose, 'Enable verbose mode'
263
+ #
264
+ # Returns the created instance of Slop::Option.
265
+ def on(*objects, &block)
266
+ option = build_option(objects, &block)
267
+ options << option
268
+ option
220
269
  end
270
+ alias option on
271
+ alias opt on
221
272
 
222
- items.each_with_index do |item, index|
223
- @trash << index && break if item == '--'
224
- autocreate(items, index) if config[:autocreate]
225
- process_item(items, index, &block) unless @trash.include?(index)
273
+ # Fetch an options argument value.
274
+ #
275
+ # key - The Symbol or String option short or long flag.
276
+ #
277
+ # Returns the Object value for this option, or nil.
278
+ def [](key)
279
+ option = fetch_option(key)
280
+ option.value if option
226
281
  end
227
- items.reject!.with_index { |item, index| @trash.include?(index) }
282
+ alias get []
228
283
 
229
- missing_options = options.select { |opt| opt.required? && opt.count < 1 }
230
- if missing_options.any?
231
- raise MissingOptionError,
232
- "Missing required option(s): #{missing_options.map(&:key).join(', ')}"
284
+ # Returns a new Hash with option flags as keys and option values as values.
285
+ #
286
+ # include_commands - If true, merge options from all sub-commands.
287
+ def to_hash(include_commands = false)
288
+ hash = Hash[options.map { |opt| [opt.key.to_sym, opt.value] }]
289
+ if include_commands
290
+ @commands.each { |cmd, opts| hash.merge!(cmd.to_sym => opts.to_hash) }
291
+ end
292
+ hash
233
293
  end
294
+ alias to_h to_hash
234
295
 
235
- if @unknown_options.any?
236
- raise InvalidOptionError, "Unknown options #{@unknown_options.join(', ')}"
296
+ # Enumerable interface. Yields each Slop::Option.
297
+ def each(&block)
298
+ options.each(&block)
237
299
  end
238
300
 
239
- if @triggered_options.empty? && @callbacks[:no_options]
240
- @callbacks[:no_options].each { |cb| cb.call(self) }
301
+ # Specify code to be executed when these options are parsed.
302
+ #
303
+ # callable - An object responding to a call method.
304
+ #
305
+ # yields - The instance of Slop parsing these options
306
+ # An Array of unparsed arguments
307
+ #
308
+ # Example:
309
+ #
310
+ # Slop.parse do
311
+ # on :v, :verbose
312
+ #
313
+ # run do |opts, args|
314
+ # puts "Arguments: #{args.inspect}" if opts.verbose?
315
+ # end
316
+ # end
317
+ def run(callable = nil, &block)
318
+ @runner = callable || block
319
+ return if @runner.respond_to?(:call)
320
+
321
+ raise ArgumentError, "You must specify a callable object or a block to #run"
241
322
  end
242
323
 
243
- @runner.call(self, items) if @runner.respond_to?(:call)
324
+ # Check for an options presence.
325
+ #
326
+ # Examples:
327
+ #
328
+ # opts.parse %w( --foo )
329
+ # opts.present?(:foo) #=> true
330
+ # opts.present?(:bar) #=> false
331
+ #
332
+ # Returns true if all of the keys are present in the parsed arguments.
333
+ def present?(*keys)
334
+ keys.all? { |key| (opt = fetch_option(key)) && opt.count > 0 }
335
+ end
244
336
 
245
- items
246
- end
337
+ # Override this method so we can check if an option? method exists.
338
+ #
339
+ # Returns true if this option key exists in our list of options.
340
+ def respond_to_missing?(method_name, include_all = false)
341
+ options.any? { |o| o.key == method_name.to_s.chop } || super
342
+ end
247
343
 
248
- # Add an Option.
249
- #
250
- # objects - An Array with an optional Hash as the last element.
251
- #
252
- # Examples:
253
- #
254
- # on '-u', '--username=', 'Your username'
255
- # on :v, :verbose, 'Enable verbose mode'
256
- #
257
- # Returns the created instance of Slop::Option.
258
- def on(*objects, &block)
259
- option = build_option(objects, &block)
260
- options << option
261
- option
262
- end
263
- alias option on
264
- alias opt on
265
-
266
- # Fetch an options argument value.
267
- #
268
- # key - The Symbol or String option short or long flag.
269
- #
270
- # Returns the Object value for this option, or nil.
271
- def [](key)
272
- option = fetch_option(key)
273
- option.value if option
274
- end
275
- alias get []
344
+ # Fetch a list of options which were missing from the parsed list.
345
+ #
346
+ # Examples:
347
+ #
348
+ # opts = Slop.new do
349
+ # on :n, :name=
350
+ # on :p, :password=
351
+ # end
352
+ #
353
+ # opts.parse %w[ --name Lee ]
354
+ # opts.missing #=> ['password']
355
+ #
356
+ # Returns an Array of Strings representing missing options.
357
+ def missing
358
+ (options - @triggered_options).map(&:key)
359
+ end
276
360
 
277
- # Returns a new Hash with option flags as keys and option values as values.
278
- #
279
- # include_commands - If true, merge options from all sub-commands.
280
- def to_hash(include_commands = false)
281
- hash = Hash[options.map { |opt| [opt.key.to_sym, opt.value] }]
282
- if include_commands
283
- @commands.each { |cmd, opts| hash.merge!(cmd.to_sym => opts.to_hash) }
361
+ # Fetch a Slop::Option object.
362
+ #
363
+ # key - The Symbol or String option key.
364
+ #
365
+ # Examples:
366
+ #
367
+ # opts.on(:foo, 'Something fooey', :argument => :optional)
368
+ # opt = opts.fetch_option(:foo)
369
+ # opt.class #=> Slop::Option
370
+ # opt.accepts_optional_argument? #=> true
371
+ #
372
+ # Returns an Option or nil if none were found.
373
+ def fetch_option(key)
374
+ options.find { |option| [option.long, option.short].include?(clean(key)) }
284
375
  end
285
- hash
286
- end
287
- alias to_h to_hash
288
376
 
289
- # Enumerable interface. Yields each Slop::Option.
290
- def each(&block)
291
- options.each(&block)
292
- end
377
+ # Fetch a Slop object associated with this command.
378
+ #
379
+ # command - The String or Symbol name of the command.
380
+ #
381
+ # Examples:
382
+ #
383
+ # opts.command :foo do
384
+ # on :v, :verbose, 'Enable verbose mode'
385
+ # end
386
+ #
387
+ # # ruby run.rb foo -v
388
+ # opts.fetch_command(:foo).verbose? #=> true
389
+ def fetch_command(command)
390
+ @commands[command.to_s]
391
+ end
293
392
 
294
- # Specify code to be executed when these options are parsed.
295
- #
296
- # callable - An object responding to a call method.
297
- #
298
- # yields - The instance of Slop parsing these options
299
- # An Array of unparsed arguments
300
- #
301
- # Example:
302
- #
303
- # Slop.parse do
304
- # on :v, :verbose
305
- #
306
- # run do |opts, args|
307
- # puts "Arguments: #{args.inspect}" if opts.verbose?
308
- # end
309
- # end
310
- def run(callable = nil, &block)
311
- @runner = callable || block
312
- unless @runner.respond_to?(:call)
313
- raise ArgumentError, "You must specify a callable object or a block to #run"
393
+ # Add a callback.
394
+ #
395
+ # label - The Symbol identifier to attach this callback.
396
+ #
397
+ # Returns nothing.
398
+ def add_callback(label, &block)
399
+ (@callbacks[label] ||= []) << block
314
400
  end
315
- end
316
401
 
317
- # Check for an options presence.
318
- #
319
- # Examples:
320
- #
321
- # opts.parse %w( --foo )
322
- # opts.present?(:foo) #=> true
323
- # opts.present?(:bar) #=> false
324
- #
325
- # Returns true if all of the keys are present in the parsed arguments.
326
- def present?(*keys)
327
- keys.all? { |key| (opt = fetch_option(key)) && opt.count > 0 }
328
- end
402
+ # Add string separators between options.
403
+ #
404
+ # text - The String text to print.
405
+ def separator(text)
406
+ if @separators[options.size]
407
+ @separators[options.size] << "\n#{text}"
408
+ else
409
+ @separators[options.size] = text
410
+ end
411
+ end
329
412
 
330
- # Override this method so we can check if an option? method exists.
331
- #
332
- # Returns true if this option key exists in our list of options.
333
- def respond_to_missing?(method_name, include_all = false)
334
- options.any? { |o| o.key == method_name.to_s.chop } || super
335
- end
413
+ # Print a handy Slop help string.
414
+ #
415
+ # Returns the banner followed by available option help strings.
416
+ def to_s
417
+ heads = options.reject(&:tail?)
418
+ tails = (options - heads)
419
+ opts = (heads + tails).select(&:help).map(&:to_s)
420
+ optstr = opts.each_with_index.map do |o, i|
421
+ (str = @separators[i + 1]) ? [o, str].join("\n") : o
422
+ end.join("\n")
423
+
424
+ if @commands.any?
425
+ optstr << "\n" unless optstr.empty?
426
+ optstr << "\nAvailable commands:\n\n"
427
+ optstr << commands_to_help
428
+ optstr << "\n\nSee `<command> --help` for more information on a specific command."
429
+ end
336
430
 
337
- # Fetch a list of options which were missing from the parsed list.
338
- #
339
- # Examples:
340
- #
341
- # opts = Slop.new do
342
- # on :n, :name=
343
- # on :p, :password=
344
- # end
345
- #
346
- # opts.parse %w[ --name Lee ]
347
- # opts.missing #=> ['password']
348
- #
349
- # Returns an Array of Strings representing missing options.
350
- def missing
351
- (options - @triggered_options).map(&:key)
352
- end
431
+ banner = config[:banner]
432
+ banner ||= "Usage: #{File.basename($PROGRAM_NAME, '.*')}" \
433
+ "#{' [command]' if @commands.any?} [options]"
434
+ if banner
435
+ "#{banner}\n#{@separators[0] ? "#{@separators[0]}\n" : ''}#{optstr}"
436
+ else
437
+ optstr
438
+ end
439
+ end
440
+ alias help to_s
353
441
 
354
- # Fetch a Slop::Option object.
355
- #
356
- # key - The Symbol or String option key.
357
- #
358
- # Examples:
359
- #
360
- # opts.on(:foo, 'Something fooey', :argument => :optional)
361
- # opt = opts.fetch_option(:foo)
362
- # opt.class #=> Slop::Option
363
- # opt.accepts_optional_argument? #=> true
364
- #
365
- # Returns an Option or nil if none were found.
366
- def fetch_option(key)
367
- options.find { |option| [option.long, option.short].include?(clean(key)) }
368
- end
442
+ private
369
443
 
370
- # Fetch a Slop object associated with this command.
371
- #
372
- # command - The String or Symbol name of the command.
373
- #
374
- # Examples:
375
- #
376
- # opts.command :foo do
377
- # on :v, :verbose, 'Enable verbose mode'
378
- # end
379
- #
380
- # # ruby run.rb foo -v
381
- # opts.fetch_command(:foo).verbose? #=> true
382
- def fetch_command(command)
383
- @commands[command.to_s]
384
- end
444
+ # Convenience method for present?(:option).
445
+ #
446
+ # Examples:
447
+ #
448
+ # opts.parse %( --verbose )
449
+ # opts.verbose? #=> true
450
+ # opts.other? #=> false
451
+ #
452
+ # Returns true if this option is present. If this method does not end
453
+ # with a ? character it will instead call super().
454
+ def method_missing(method, *args, &block)
455
+ meth = method.to_s
456
+ if meth.end_with?('?')
457
+ meth = meth.chop
458
+ present?(meth) || present?(meth.tr('_', '-'))
459
+ else
460
+ super
461
+ end
462
+ end
385
463
 
386
- # Add a callback.
387
- #
388
- # label - The Symbol identifier to attach this callback.
389
- #
390
- # Returns nothing.
391
- def add_callback(label, &block)
392
- (@callbacks[label] ||= []) << block
393
- end
464
+ # Process a list item, figure out if it's an option, execute any
465
+ # callbacks, assign any option arguments, and do some sanity checks.
466
+ #
467
+ # items - The Array of items to process.
468
+ # index - The current Integer index of the item we want to process.
469
+ # block - An optional block which when passed will yield non options.
470
+ #
471
+ # Returns nothing.
472
+ def process_item(items, index, &block)
473
+ return unless (item = items[index])
394
474
 
395
- # Add string separators between options.
396
- #
397
- # text - The String text to print.
398
- def separator(text)
399
- if @separators[options.size]
400
- @separators[options.size] << "\n#{text}"
401
- else
402
- @separators[options.size] = text
403
- end
404
- end
475
+ option, argument = extract_option(item) if item.start_with?('-')
405
476
 
406
- # Print a handy Slop help string.
407
- #
408
- # Returns the banner followed by available option help strings.
409
- def to_s
410
- heads = options.reject(&:tail?)
411
- tails = (options - heads)
412
- opts = (heads + tails).select(&:help).map(&:to_s)
413
- optstr = opts.each_with_index.map { |o, i|
414
- (str = @separators[i + 1]) ? [o, str].join("\n") : o
415
- }.join("\n")
416
-
417
- if @commands.any?
418
- optstr << "\n" if !optstr.empty?
419
- optstr << "\nAvailable commands:\n\n"
420
- optstr << commands_to_help
421
- optstr << "\n\nSee `<command> --help` for more information on a specific command."
422
- end
423
-
424
- banner = config[:banner]
425
- banner = "Usage: #{File.basename($0, '.*')}#{' [command]' if @commands.any?} [options]" if banner.nil?
426
- if banner
427
- "#{banner}\n#{@separators[0] ? "#{@separators[0]}\n" : ''}#{optstr}"
428
- else
429
- optstr
430
- end
431
- end
432
- alias help to_s
433
-
434
- private
435
-
436
- # Convenience method for present?(:option).
437
- #
438
- # Examples:
439
- #
440
- # opts.parse %( --verbose )
441
- # opts.verbose? #=> true
442
- # opts.other? #=> false
443
- #
444
- # Returns true if this option is present. If this method does not end
445
- # with a ? character it will instead call super().
446
- def method_missing(method, *args, &block)
447
- meth = method.to_s
448
- if meth.end_with?('?')
449
- meth.chop!
450
- present?(meth) || present?(meth.gsub('_', '-'))
451
- else
452
- super
453
- end
454
- end
477
+ if option
478
+ option.count += 1 unless item.start_with?('--no-')
479
+ option.count += 1 if option.key[0, 3] == "no-"
480
+ @trash << index
481
+ @triggered_options << option
455
482
 
456
- # Process a list item, figure out if it's an option, execute any
457
- # callbacks, assign any option arguments, and do some sanity checks.
458
- #
459
- # items - The Array of items to process.
460
- # index - The current Integer index of the item we want to process.
461
- # block - An optional block which when passed will yield non options.
462
- #
463
- # Returns nothing.
464
- def process_item(items, index, &block)
465
- return unless (item = items[index])
466
-
467
- option, argument = extract_option(item) if item.start_with?('-')
468
-
469
- if option
470
- option.count += 1 unless item.start_with?('--no-')
471
- option.count += 1 if option.key[0, 3] == "no-"
472
- @trash << index
473
- @triggered_options << option
474
-
475
- if option.expects_argument?
476
- argument ||= items.at(index + 1)
477
-
478
- if !argument || argument =~ /\A--?[a-zA-Z][a-zA-Z0-9_-]*\z/
479
- raise MissingArgumentError, "#{option.key} expects an argument"
480
- end
483
+ if option.expects_argument?
484
+ argument ||= items.at(index + 1)
481
485
 
482
- execute_option(option, argument, index, item)
483
- elsif option.accepts_optional_argument?
484
- argument ||= items.at(index + 1)
486
+ if !argument || argument =~ /\A--?[a-zA-Z][a-zA-Z0-9_-]*\z/
487
+ raise MissingArgumentError, "#{option.key} expects an argument"
488
+ end
485
489
 
486
- if argument && argument =~ /\A([^\-?]|-\d)+/
487
490
  execute_option(option, argument, index, item)
491
+ elsif option.accepts_optional_argument?
492
+ argument ||= items.at(index + 1)
493
+
494
+ if argument && argument =~ /\A([^\-?]|-\d)+/
495
+ execute_option(option, argument, index, item)
496
+ else
497
+ option.call(nil)
498
+ end
499
+ elsif config[:multiple_switches] && argument
500
+ execute_multiple_switches(option, argument, index)
488
501
  else
502
+ option.value = option.count > 0
489
503
  option.call(nil)
490
504
  end
491
- elsif config[:multiple_switches] && argument
492
- execute_multiple_switches(option, argument, index)
493
505
  else
494
- option.value = option.count > 0
495
- option.call(nil)
506
+ @unknown_options << item if strict? && item =~ /\A--?/
507
+ yield(item) if block && !@trash.include?(index)
496
508
  end
497
- else
498
- @unknown_options << item if strict? && item =~ /\A--?/
499
- block.call(item) if block && !@trash.include?(index)
500
509
  end
501
- end
502
510
 
503
- # Execute an option, firing off callbacks and assigning arguments.
504
- #
505
- # option - The Slop::Option object found by #process_item.
506
- # argument - The argument Object to assign to this option.
507
- # index - The current Integer index of the object we're processing.
508
- # item - The optional String item we're processing.
509
- #
510
- # Returns nothing.
511
- def execute_option(option, argument, index, item = nil)
512
- if !option
513
- if config[:multiple_switches] && strict?
514
- raise InvalidOptionError, "Unknown option -#{item}"
511
+ # Execute an option, firing off callbacks and assigning arguments.
512
+ #
513
+ # option - The Slop::Option object found by #process_item.
514
+ # argument - The argument Object to assign to this option.
515
+ # index - The current Integer index of the object we're processing.
516
+ # item - The optional String item we're processing.
517
+ #
518
+ # Returns nothing.
519
+ def execute_option(option, argument, index, item = nil)
520
+ unless option
521
+ if config[:multiple_switches] && strict?
522
+ raise InvalidOptionError, "Unknown option -#{item}"
523
+ end
524
+
525
+ return
515
526
  end
516
527
 
517
- return
518
- end
528
+ if argument
529
+ unless item && item.end_with?("=#{argument}")
530
+ @trash << index + 1 unless option.argument_in_value
531
+ end
532
+ option.value = argument
533
+ else
534
+ option.value = option.count > 0
535
+ end
519
536
 
520
- if argument
521
- unless item && item.end_with?("=#{argument}")
522
- @trash << index + 1 unless option.argument_in_value
537
+ if option.match? && !argument.match(option.config[:match])
538
+ raise InvalidArgumentError, "#{argument} is an invalid argument"
523
539
  end
524
- option.value = argument
525
- else
526
- option.value = option.count > 0
527
- end
528
540
 
529
- if option.match? && !argument.match(option.config[:match])
530
- raise InvalidArgumentError, "#{argument} is an invalid argument"
541
+ option.call(option.value)
531
542
  end
532
543
 
533
- option.call(option.value)
534
- end
535
-
536
- # Execute a `-abc` type option where a, b and c are all options. This
537
- # method is only executed if the multiple_switches argument is true.
538
- #
539
- # option - The first Option object.
540
- # argument - The argument to this option. (Split into multiple Options).
541
- # index - The index of the current item being processed.
542
- #
543
- # Returns nothing.
544
- def execute_multiple_switches(option, argument, index)
545
- execute_option(option, nil, index)
546
- argument.split('').each do |key|
547
- next unless (opt = fetch_option(key))
548
-
549
- opt.count += 1
550
- execute_option(opt, nil, index, key)
544
+ # Execute a `-abc` type option where a, b and c are all options. This
545
+ # method is only executed if the multiple_switches argument is true.
546
+ #
547
+ # option - The first Option object.
548
+ # argument - The argument to this option. (Split into multiple Options).
549
+ # index - The index of the current item being processed.
550
+ #
551
+ # Returns nothing.
552
+ def execute_multiple_switches(option, argument, index)
553
+ execute_option(option, nil, index)
554
+ argument.split('').each do |key|
555
+ next unless (opt = fetch_option(key))
556
+
557
+ opt.count += 1
558
+ execute_option(opt, nil, index, key)
559
+ end
551
560
  end
552
- end
553
561
 
554
- # Extract an option from a flag.
555
- #
556
- # flag - The flag key used to extract an option.
557
- #
558
- # Returns an Array of [option, argument].
559
- def extract_option(flag)
560
- option = fetch_option(flag)
561
- option ||= fetch_option(flag.downcase) if config[:ignore_case]
562
- option ||= fetch_option(flag.gsub(/([^-])-/, '\1_'))
563
-
564
- unless option
565
- case flag
566
- when /\A--?([^=]+)=(.+)\z/, /\A-([a-zA-Z])(.+)\z/, /\A--no-(.+)\z/
567
- option, argument = fetch_option($1), ($2 || false)
568
- option.argument_in_value = true if option
562
+ # Extract an option from a flag.
563
+ #
564
+ # flag - The flag key used to extract an option.
565
+ #
566
+ # Returns an Array of [option, argument].
567
+ def extract_option(flag)
568
+ option = fetch_option(flag)
569
+ option ||= fetch_option(flag.downcase) if config[:ignore_case]
570
+ option ||= fetch_option(flag.gsub(/([^-])-/, '\1_'))
571
+
572
+ unless option
573
+ case flag
574
+ when /\A--?([^=]+)=(.+)\z/, /\A-([a-zA-Z])(.+)\z/, /\A--no-(.+)\z/
575
+ option = fetch_option(Regexp.last_match(1))
576
+ argument = Regexp.last_match(2) || false
577
+ option.argument_in_value = true if option
578
+ end
569
579
  end
580
+
581
+ [option, argument]
570
582
  end
571
583
 
572
- [option, argument]
573
- end
584
+ # Autocreate an option on the fly. See the :autocreate Slop config option.
585
+ #
586
+ # items - The Array of items we're parsing.
587
+ # index - The current Integer index for the item we're processing.
588
+ #
589
+ # Returns nothing.
590
+ def autocreate(items, index)
591
+ flag = items[index]
592
+ return if fetch_option(flag) || @trash.include?(index)
574
593
 
575
- # Autocreate an option on the fly. See the :autocreate Slop config option.
576
- #
577
- # items - The Array of items we're parsing.
578
- # index - The current Integer index for the item we're processing.
579
- #
580
- # Returns nothing.
581
- def autocreate(items, index)
582
- flag = items[index]
583
- if !fetch_option(flag) && !@trash.include?(index)
584
594
  option = build_option(Array(flag))
585
595
  argument = items[index + 1]
586
596
  option.config[:argument] = (argument && argument !~ /\A--?/)
587
597
  option.config[:autocreated] = true
588
598
  options << option
589
599
  end
590
- end
591
-
592
- # Build an option from a list of objects.
593
- #
594
- # objects - An Array of objects used to build this option.
595
- #
596
- # Returns a new instance of Slop::Option.
597
- def build_option(objects, &block)
598
- config = {}
599
- config[:argument] = true if @config[:arguments]
600
- config[:optional_argument] = true if @config[:optional_arguments]
601
-
602
- if objects.last.is_a?(Hash)
603
- config.merge!(objects.last)
604
- objects.pop
605
- end
606
- short = extract_short_flag(objects, config)
607
- long = extract_long_flag(objects, config)
608
- desc = objects[0].respond_to?(:to_str) ? objects.shift : nil
609
-
610
- Option.new(self, short, long, desc, config, &block)
611
- end
612
600
 
613
- # Extract the short flag from an item.
614
- #
615
- # objects - The Array of objects passed from #build_option.
616
- # config - The Hash of configuration options built in #build_option.
617
- def extract_short_flag(objects, config)
618
- flag = clean(objects.first)
601
+ # Build an option from a list of objects.
602
+ #
603
+ # objects - An Array of objects used to build this option.
604
+ #
605
+ # Returns a new instance of Slop::Option.
606
+ def build_option(objects, &block)
607
+ config = {}
608
+ config[:argument] = true if @config[:arguments]
609
+ config[:optional_argument] = true if @config[:optional_arguments]
610
+
611
+ if objects.last.is_a?(Hash)
612
+ config.merge!(objects.last)
613
+ objects.pop
614
+ end
615
+ short = extract_short_flag(objects, config)
616
+ long = extract_long_flag(objects, config)
617
+ desc = objects[0].respond_to?(:to_str) ? objects.shift : nil
619
618
 
620
- if flag.size == 2 && flag.end_with?('=')
621
- config[:argument] ||= true
622
- flag.chop!
619
+ Option.new(self, short, long, desc, config, &block)
623
620
  end
624
621
 
625
- if flag.size == 1
622
+ # Extract the short flag from an item.
623
+ #
624
+ # objects - The Array of objects passed from #build_option.
625
+ # config - The Hash of configuration options built in #build_option.
626
+ def extract_short_flag(objects, config)
627
+ flag = clean(objects.first)
628
+
629
+ if flag.size == 2 && flag.end_with?('=')
630
+ config[:argument] ||= true
631
+ flag.chop!
632
+ end
633
+
634
+ return unless flag.size == 1
635
+
626
636
  objects.shift
627
637
  flag
628
638
  end
629
- end
630
639
 
631
- # Extract the long flag from an item.
632
- #
633
- # objects - The Array of objects passed from #build_option.
634
- # config - The Hash of configuration options built in #build_option.
635
- def extract_long_flag(objects, config)
636
- flag = objects.first.to_s
637
- if flag =~ /\A(?:--?)?[a-zA-Z][a-zA-Z0-9_-]+\=?\??\z/
640
+ # Extract the long flag from an item.
641
+ #
642
+ # objects - The Array of objects passed from #build_option.
643
+ # config - The Hash of configuration options built in #build_option.
644
+ def extract_long_flag(objects, config)
645
+ flag = objects.first.to_s
646
+ return unless flag =~ /\A(?:--?)?[a-zA-Z][a-zA-Z0-9_-]+\=?\??\z/
647
+
638
648
  config[:argument] ||= true if flag.end_with?('=')
639
649
  config[:optional_argument] = true if flag.end_with?('=?')
640
650
  objects.shift
641
651
  clean(flag).sub(/\=\??\z/, '')
642
652
  end
643
- end
644
653
 
645
- # Remove any leading -- characters from a string.
646
- #
647
- # object - The Object we want to cast to a String and clean.
648
- #
649
- # Returns the newly cleaned String with leading -- characters removed.
650
- def clean(object)
651
- object.to_s.sub(/\A--?/, '')
652
- end
654
+ # Remove any leading -- characters from a string.
655
+ #
656
+ # object - The Object we want to cast to a String and clean.
657
+ #
658
+ # Returns the newly cleaned String with leading -- characters removed.
659
+ def clean(object)
660
+ object.to_s.sub(/\A--?/, '')
661
+ end
653
662
 
654
- def commands_to_help
655
- padding = 0
656
- @commands.each { |c, _| padding = c.size if c.size > padding }
657
- @commands.map do |cmd, opts|
658
- " #{cmd}#{' ' * (padding - cmd.size)} #{opts.description}"
659
- end.join("\n")
663
+ def commands_to_help
664
+ padding = 0
665
+ @commands.each { |c, _| padding = c.size if c.size > padding }
666
+ @commands.map do |cmd, opts|
667
+ " #{cmd}#{' ' * (padding - cmd.size)} #{opts.description}"
668
+ end.join("\n")
669
+ end
660
670
  end
671
+ # rubocop:enable Metrics/ClassLength
661
672
  end