pry 0.10.0.pre2-universal-mingw32

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 (131) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +702 -0
  3. data/LICENSE +25 -0
  4. data/README.md +406 -0
  5. data/bin/pry +16 -0
  6. data/lib/pry.rb +161 -0
  7. data/lib/pry/cli.rb +220 -0
  8. data/lib/pry/code.rb +346 -0
  9. data/lib/pry/code/code_file.rb +103 -0
  10. data/lib/pry/code/code_range.rb +71 -0
  11. data/lib/pry/code/loc.rb +92 -0
  12. data/lib/pry/code_object.rb +172 -0
  13. data/lib/pry/color_printer.rb +55 -0
  14. data/lib/pry/command.rb +692 -0
  15. data/lib/pry/command_set.rb +443 -0
  16. data/lib/pry/commands.rb +6 -0
  17. data/lib/pry/commands/amend_line.rb +99 -0
  18. data/lib/pry/commands/bang.rb +20 -0
  19. data/lib/pry/commands/bang_pry.rb +17 -0
  20. data/lib/pry/commands/cat.rb +62 -0
  21. data/lib/pry/commands/cat/abstract_formatter.rb +27 -0
  22. data/lib/pry/commands/cat/exception_formatter.rb +77 -0
  23. data/lib/pry/commands/cat/file_formatter.rb +67 -0
  24. data/lib/pry/commands/cat/input_expression_formatter.rb +43 -0
  25. data/lib/pry/commands/cd.rb +41 -0
  26. data/lib/pry/commands/change_inspector.rb +27 -0
  27. data/lib/pry/commands/change_prompt.rb +26 -0
  28. data/lib/pry/commands/code_collector.rb +165 -0
  29. data/lib/pry/commands/disable_pry.rb +27 -0
  30. data/lib/pry/commands/disabled_commands.rb +2 -0
  31. data/lib/pry/commands/easter_eggs.rb +112 -0
  32. data/lib/pry/commands/edit.rb +195 -0
  33. data/lib/pry/commands/edit/exception_patcher.rb +25 -0
  34. data/lib/pry/commands/edit/file_and_line_locator.rb +36 -0
  35. data/lib/pry/commands/exit.rb +42 -0
  36. data/lib/pry/commands/exit_all.rb +29 -0
  37. data/lib/pry/commands/exit_program.rb +23 -0
  38. data/lib/pry/commands/find_method.rb +193 -0
  39. data/lib/pry/commands/fix_indent.rb +19 -0
  40. data/lib/pry/commands/gem_cd.rb +26 -0
  41. data/lib/pry/commands/gem_install.rb +32 -0
  42. data/lib/pry/commands/gem_list.rb +33 -0
  43. data/lib/pry/commands/gem_open.rb +29 -0
  44. data/lib/pry/commands/gist.rb +101 -0
  45. data/lib/pry/commands/help.rb +164 -0
  46. data/lib/pry/commands/hist.rb +180 -0
  47. data/lib/pry/commands/import_set.rb +22 -0
  48. data/lib/pry/commands/install_command.rb +53 -0
  49. data/lib/pry/commands/jump_to.rb +29 -0
  50. data/lib/pry/commands/list_inspectors.rb +35 -0
  51. data/lib/pry/commands/list_prompts.rb +35 -0
  52. data/lib/pry/commands/ls.rb +114 -0
  53. data/lib/pry/commands/ls/constants.rb +47 -0
  54. data/lib/pry/commands/ls/formatter.rb +49 -0
  55. data/lib/pry/commands/ls/globals.rb +48 -0
  56. data/lib/pry/commands/ls/grep.rb +21 -0
  57. data/lib/pry/commands/ls/instance_vars.rb +39 -0
  58. data/lib/pry/commands/ls/interrogatable.rb +18 -0
  59. data/lib/pry/commands/ls/jruby_hacks.rb +49 -0
  60. data/lib/pry/commands/ls/local_names.rb +35 -0
  61. data/lib/pry/commands/ls/local_vars.rb +39 -0
  62. data/lib/pry/commands/ls/ls_entity.rb +70 -0
  63. data/lib/pry/commands/ls/methods.rb +57 -0
  64. data/lib/pry/commands/ls/methods_helper.rb +46 -0
  65. data/lib/pry/commands/ls/self_methods.rb +32 -0
  66. data/lib/pry/commands/nesting.rb +25 -0
  67. data/lib/pry/commands/play.rb +103 -0
  68. data/lib/pry/commands/pry_backtrace.rb +25 -0
  69. data/lib/pry/commands/pry_version.rb +17 -0
  70. data/lib/pry/commands/raise_up.rb +32 -0
  71. data/lib/pry/commands/reload_code.rb +62 -0
  72. data/lib/pry/commands/reset.rb +18 -0
  73. data/lib/pry/commands/ri.rb +60 -0
  74. data/lib/pry/commands/save_file.rb +61 -0
  75. data/lib/pry/commands/shell_command.rb +48 -0
  76. data/lib/pry/commands/shell_mode.rb +25 -0
  77. data/lib/pry/commands/show_doc.rb +83 -0
  78. data/lib/pry/commands/show_info.rb +195 -0
  79. data/lib/pry/commands/show_input.rb +17 -0
  80. data/lib/pry/commands/show_source.rb +50 -0
  81. data/lib/pry/commands/simple_prompt.rb +22 -0
  82. data/lib/pry/commands/stat.rb +40 -0
  83. data/lib/pry/commands/switch_to.rb +23 -0
  84. data/lib/pry/commands/toggle_color.rb +24 -0
  85. data/lib/pry/commands/watch_expression.rb +105 -0
  86. data/lib/pry/commands/watch_expression/expression.rb +38 -0
  87. data/lib/pry/commands/whereami.rb +190 -0
  88. data/lib/pry/commands/wtf.rb +57 -0
  89. data/lib/pry/config.rb +24 -0
  90. data/lib/pry/config/behavior.rb +139 -0
  91. data/lib/pry/config/convenience.rb +26 -0
  92. data/lib/pry/config/default.rb +165 -0
  93. data/lib/pry/core_extensions.rb +131 -0
  94. data/lib/pry/editor.rb +133 -0
  95. data/lib/pry/exceptions.rb +77 -0
  96. data/lib/pry/helpers.rb +5 -0
  97. data/lib/pry/helpers/base_helpers.rb +113 -0
  98. data/lib/pry/helpers/command_helpers.rb +156 -0
  99. data/lib/pry/helpers/documentation_helpers.rb +75 -0
  100. data/lib/pry/helpers/options_helpers.rb +27 -0
  101. data/lib/pry/helpers/table.rb +109 -0
  102. data/lib/pry/helpers/text.rb +107 -0
  103. data/lib/pry/history.rb +125 -0
  104. data/lib/pry/history_array.rb +121 -0
  105. data/lib/pry/hooks.rb +230 -0
  106. data/lib/pry/indent.rb +406 -0
  107. data/lib/pry/input_completer.rb +242 -0
  108. data/lib/pry/input_lock.rb +132 -0
  109. data/lib/pry/inspector.rb +27 -0
  110. data/lib/pry/last_exception.rb +61 -0
  111. data/lib/pry/method.rb +546 -0
  112. data/lib/pry/method/disowned.rb +53 -0
  113. data/lib/pry/method/patcher.rb +125 -0
  114. data/lib/pry/method/weird_method_locator.rb +186 -0
  115. data/lib/pry/module_candidate.rb +136 -0
  116. data/lib/pry/object_path.rb +82 -0
  117. data/lib/pry/output.rb +50 -0
  118. data/lib/pry/pager.rb +234 -0
  119. data/lib/pry/plugins.rb +103 -0
  120. data/lib/pry/prompt.rb +26 -0
  121. data/lib/pry/pry_class.rb +375 -0
  122. data/lib/pry/pry_instance.rb +654 -0
  123. data/lib/pry/rbx_path.rb +22 -0
  124. data/lib/pry/repl.rb +202 -0
  125. data/lib/pry/repl_file_loader.rb +74 -0
  126. data/lib/pry/rubygem.rb +82 -0
  127. data/lib/pry/terminal.rb +79 -0
  128. data/lib/pry/test/helper.rb +170 -0
  129. data/lib/pry/version.rb +3 -0
  130. data/lib/pry/wrapped_module.rb +373 -0
  131. metadata +248 -0
@@ -0,0 +1,443 @@
1
+ class Pry
2
+ class NoCommandError < StandardError
3
+ def initialize(match, owner)
4
+ super "Command '#{match}' not found in command set #{owner}"
5
+ end
6
+ end
7
+
8
+ # This class is used to create sets of commands. Commands can be imported from
9
+ # different sets, aliased, removed, etc.
10
+ class CommandSet
11
+ include Enumerable
12
+ include Pry::Helpers::BaseHelpers
13
+ attr_reader :helper_module
14
+
15
+ # @param [Array<Commandset>] imported_sets
16
+ # Sets which will be imported automatically
17
+ # @yield Optional block run to define commands
18
+ def initialize(*imported_sets, &block)
19
+ @commands = {}
20
+ @helper_module = Module.new
21
+ import(*imported_sets)
22
+ instance_eval(&block) if block
23
+ end
24
+
25
+ # Defines a new Pry command.
26
+ # @param [String, Regexp] match The start of invocations of this command.
27
+ # @param [String] description A description of the command.
28
+ # @param [Hash] options The optional configuration parameters.
29
+ # @option options [Boolean] :keep_retval Whether or not to use return value
30
+ # of the block for return of `command` or just to return `nil`
31
+ # (the default).
32
+ # @option options [Array<String>] :requires_gem Whether the command has
33
+ # any gem dependencies, if it does and dependencies not met then
34
+ # command is disabled and a stub proc giving instructions to
35
+ # install command is provided.
36
+ # @option options [Boolean] :interpolate Whether string #{} based
37
+ # interpolation is applied to the command arguments before
38
+ # executing the command. Defaults to true.
39
+ # @option options [String] :listing The listing name of the
40
+ # command. That is the name by which the command is looked up by
41
+ # help and by show-command. Necessary for commands with regex matches.
42
+ # @option options [Boolean] :use_prefix Whether the command uses
43
+ # `Pry.config.command_prefix` prefix (if one is defined). Defaults
44
+ # to true.
45
+ # @option options [Boolean] :shellwords Whether the command's arguments
46
+ # should be split using Shellwords instead of just split on spaces.
47
+ # Defaults to true.
48
+ # @yield The action to perform. The parameters in the block
49
+ # determines the parameters the command will receive. All
50
+ # parameters passed into the block will be strings. Successive
51
+ # command parameters are separated by whitespace at the Pry prompt.
52
+ # @example
53
+ # MyCommands = Pry::CommandSet.new do
54
+ # command "greet", "Greet somebody" do |name|
55
+ # puts "Good afternoon #{name.capitalize}!"
56
+ # end
57
+ # end
58
+ #
59
+ # # From pry:
60
+ # # pry(main)> _pry_.commands = MyCommands
61
+ # # pry(main)> greet john
62
+ # # Good afternoon John!
63
+ # # pry(main)> help greet
64
+ # # Greet somebody
65
+ # @example Regexp command
66
+ # MyCommands = Pry::CommandSet.new do
67
+ # command /number-(\d+)/, "number-N regex command", :listing => "number" do |num, name|
68
+ # puts "hello #{name}, nice number: #{num}"
69
+ # end
70
+ # end
71
+ #
72
+ # # From pry:
73
+ # # pry(main)> _pry_.commands = MyCommands
74
+ # # pry(main)> number-10 john
75
+ # # hello john, nice number: 10
76
+ # # pry(main)> help number
77
+ # # number-N regex command
78
+ def block_command(match, description="No description.", options={}, &block)
79
+ description, options = ["No description.", description] if description.is_a?(Hash)
80
+ options = Pry::Command.default_options(match).merge!(options)
81
+
82
+ @commands[match] = Pry::BlockCommand.subclass(match, description, options, helper_module, &block)
83
+ end
84
+ alias_method :command, :block_command
85
+
86
+ # Defines a new Pry command class.
87
+ #
88
+ # @param [String, Regexp] match The start of invocations of this command.
89
+ # @param [String] description A description of the command.
90
+ # @param [Hash] options The optional configuration parameters, see {#command}
91
+ # @yield The class body's definition.
92
+ #
93
+ # @example
94
+ # Pry::Commands.create_command "echo", "echo's the input", :shellwords => false do
95
+ # def options(opt)
96
+ # opt.banner "Usage: echo [-u | -d] <string to echo>"
97
+ # opt.on :u, :upcase, "ensure the output is all upper-case"
98
+ # opt.on :d, :downcase, "ensure the output is all lower-case"
99
+ # end
100
+ #
101
+ # def process
102
+ # raise Pry::CommandError, "-u and -d makes no sense" if opts.present?(:u) && opts.present?(:d)
103
+ # result = args.join(" ")
104
+ # result.downcase! if opts.present?(:downcase)
105
+ # result.upcase! if opts.present?(:upcase)
106
+ # output.puts result
107
+ # end
108
+ # end
109
+ #
110
+ def create_command(match, description="No description.", options={}, &block)
111
+ description, options = ["No description.", description] if description.is_a?(Hash)
112
+ options = Pry::Command.default_options(match).merge!(options)
113
+
114
+ @commands[match] = Pry::ClassCommand.subclass(match, description, options, helper_module, &block)
115
+ @commands[match].class_eval(&block)
116
+ @commands[match]
117
+ end
118
+
119
+ # Execute a block of code before a command is invoked. The block also
120
+ # gets access to parameters that will be passed to the command and
121
+ # is evaluated in the same context.
122
+ # @param [String, Regexp] search The match or listing of the command.
123
+ # @yield The block to be run before the command.
124
+ # @example Display parameter before invoking command
125
+ # Pry.config.commands.before_command("whereami") do |n|
126
+ # output.puts "parameter passed was #{n}"
127
+ # end
128
+ def before_command(search, &block)
129
+ cmd = find_command_by_match_or_listing(search)
130
+ cmd.hooks[:before].unshift block
131
+ end
132
+
133
+ # Execute a block of code after a command is invoked. The block also
134
+ # gets access to parameters that will be passed to the command and
135
+ # is evaluated in the same context.
136
+ # @param [String, Regexp] search The match or listing of the command.
137
+ # @yield The block to be run after the command.
138
+ # @example Display text 'command complete' after invoking command
139
+ # Pry.config.commands.after_command("whereami") do |n|
140
+ # output.puts "command complete!"
141
+ # end
142
+ def after_command(search, &block)
143
+ cmd = find_command_by_match_or_listing(search)
144
+ cmd.hooks[:after] << block
145
+ end
146
+
147
+ def each(&block)
148
+ @commands.each(&block)
149
+ end
150
+
151
+ # Removes some commands from the set
152
+ # @param [Array<String>] searches the matches or listings of the commands to remove
153
+ def delete(*searches)
154
+ searches.each do |search|
155
+ cmd = find_command_by_match_or_listing(search)
156
+ @commands.delete cmd.match
157
+ end
158
+ end
159
+
160
+ # Imports all the commands from one or more sets.
161
+ # @param [Array<CommandSet>] sets Command sets, all of the commands of which
162
+ # will be imported.
163
+ # @return [Pry::CommandSet] Returns the reciever (a command set).
164
+ def import(*sets)
165
+ sets.each do |set|
166
+ @commands.merge! set.to_hash
167
+ helper_module.send :include, set.helper_module
168
+ end
169
+ self
170
+ end
171
+
172
+ # Imports some commands from a set
173
+ # @param [CommandSet] set Set to import commands from
174
+ # @param [Array<String>] matches Commands to import
175
+ # @return [Pry::CommandSet] Returns the reciever (a command set).
176
+ def import_from(set, *matches)
177
+ helper_module.send :include, set.helper_module
178
+ matches.each do |match|
179
+ cmd = set.find_command_by_match_or_listing(match)
180
+ @commands[cmd.match] = cmd
181
+ end
182
+ self
183
+ end
184
+
185
+ # @param [String, Regexp] match_or_listing The match or listing of a command.
186
+ # of the command to retrieve.
187
+ # @return [Command] The command object matched.
188
+ def find_command_by_match_or_listing(match_or_listing)
189
+ cmd = (@commands[match_or_listing] ||
190
+ Pry::Helpers::BaseHelpers.find_command(match_or_listing, @commands))
191
+ cmd or raise ArgumentError, "Cannot find a command: '#{match_or_listing}'!"
192
+ end
193
+
194
+ # Aliases a command
195
+ # @param [String, Regex] match The match of the alias (can be a regex).
196
+ # @param [String] action The action to be performed (typically
197
+ # another command).
198
+ # @param [Hash] options The optional configuration parameters,
199
+ # accepts the same as the `command` method, but also allows the
200
+ # command description to be passed this way too as `:desc`
201
+ # @example Creating an alias for `ls -M`
202
+ # Pry.config.commands.alias_command "lM", "ls -M"
203
+ # @example Pass explicit description (overriding default).
204
+ # Pry.config.commands.alias_command "lM", "ls -M", :desc => "cutiepie"
205
+ def alias_command(match, action, options={})
206
+ cmd = find_command(action) or fail "Command: `#{action}` not found"
207
+ original_options = cmd.options.dup
208
+
209
+ options = original_options.merge!({
210
+ :desc => "Alias for `#{action}`",
211
+ :listing => match
212
+ }).merge!(options)
213
+
214
+ # ensure default description is used if desc is nil
215
+ desc = options.delete(:desc).to_s
216
+
217
+ c = block_command match, desc, options do |*args|
218
+ run action, *args
219
+ end
220
+
221
+ c.class_eval do
222
+ define_method(:complete) do |input|
223
+ cmd.new(context).complete(input)
224
+ end
225
+ end
226
+
227
+ c.group "Aliases"
228
+
229
+ c
230
+ end
231
+
232
+ # Rename a command. Accepts either match or listing for the search.
233
+ #
234
+ # @param [String, Regexp] new_match The new match for the command.
235
+ # @param [String, Regexp] search The command's current match or listing.
236
+ # @param [Hash] options The optional configuration parameters,
237
+ # accepts the same as the `command` method, but also allows the
238
+ # command description to be passed this way too.
239
+ # @example Renaming the `ls` command and changing its description.
240
+ # Pry.config.commands.rename "dir", "ls", :description => "DOS friendly ls"
241
+ def rename_command(new_match, search, options={})
242
+ cmd = find_command_by_match_or_listing(search)
243
+
244
+ options = {
245
+ :listing => new_match,
246
+ :description => cmd.description
247
+ }.merge!(options)
248
+
249
+ @commands[new_match] = cmd.dup
250
+ @commands[new_match].match = new_match
251
+ @commands[new_match].description = options.delete(:description)
252
+ @commands[new_match].options.merge!(options)
253
+ @commands.delete(cmd.match)
254
+ end
255
+
256
+ def disabled_command(name_of_disabled_command, message, matcher=name_of_disabled_command)
257
+ create_command name_of_disabled_command do
258
+ match matcher
259
+ description ""
260
+
261
+ define_method(:process) do
262
+ output.puts "DISABLED: #{message}"
263
+ end
264
+ end
265
+ end
266
+
267
+ # Sets or gets the description for a command (replacing the old
268
+ # description). Returns current description if no description
269
+ # parameter provided.
270
+ # @param [String, Regexp] search The command match.
271
+ # @param [String?] description (nil) The command description.
272
+ # @example Setting
273
+ # MyCommands = Pry::CommandSet.new do
274
+ # desc "help", "help description"
275
+ # end
276
+ # @example Getting
277
+ # Pry.config.commands.desc "amend-line"
278
+ def desc(search, description=nil)
279
+ cmd = find_command_by_match_or_listing(search)
280
+ return cmd.description if !description
281
+
282
+ cmd.description = description
283
+ end
284
+
285
+ # Defines helpers methods for this command sets.
286
+ # Those helpers are only defined in this command set.
287
+ #
288
+ # @yield A block defining helper methods
289
+ # @example
290
+ # helpers do
291
+ # def hello
292
+ # puts "Hello!"
293
+ # end
294
+ #
295
+ # include OtherModule
296
+ # end
297
+ def helpers(&block)
298
+ helper_module.class_eval(&block)
299
+ end
300
+
301
+
302
+ # @return [Array]
303
+ # The list of commands provided by the command set.
304
+ def list_commands
305
+ @commands.keys
306
+ end
307
+ alias_method :keys, :list_commands
308
+
309
+ def to_hash
310
+ @commands.dup
311
+ end
312
+ alias_method :to_h, :to_hash
313
+
314
+ # Find a command that matches the given line
315
+ # @param [String] pattern The line that might be a command invocation
316
+ # @return [Pry::Command, nil]
317
+ def [](pattern)
318
+ @commands.values.select do |command|
319
+ command.matches?(pattern)
320
+ end.sort_by do |command|
321
+ command.match_score(pattern)
322
+ end.last
323
+ end
324
+ alias_method :find_command, :[]
325
+
326
+ #
327
+ # Re-assign the command found at _pattern_ with _command_.
328
+ #
329
+ # @param [Regexp, String] pattern
330
+ # The command to add or replace(found at _pattern_).
331
+ #
332
+ # @param [Pry::Command] command
333
+ # The command to add.
334
+ #
335
+ # @return [Pry::Command]
336
+ # Returns the new command (matched with "pattern".)
337
+ #
338
+ # @example
339
+ # Pry.config.commands["help"] = MyHelpCommand
340
+ #
341
+ def []=(pattern, command)
342
+ if command.equal?(nil)
343
+ return @commands.delete(pattern)
344
+ end
345
+ unless Class === command && command < Pry::Command
346
+ raise TypeError, "command is not a subclass of Pry::Command"
347
+ end
348
+ bind_command_to_pattern = pattern != command.match
349
+ if bind_command_to_pattern
350
+ command_copy = command.dup
351
+ command_copy.match = pattern
352
+ @commands[pattern] = command_copy
353
+ else
354
+ @commands[pattern] = command
355
+ end
356
+ end
357
+
358
+ #
359
+ # Add a command to set.
360
+ #
361
+ # @param [Command] command
362
+ # a subclass of Pry::Command.
363
+ #
364
+ def add_command(command)
365
+ self[command.match] = command
366
+ end
367
+
368
+ # Find the command that the user might be trying to refer to.
369
+ # @param [String] search The user's search.
370
+ # @return [Pry::Command?]
371
+ def find_command_for_help(search)
372
+ find_command(search) || (begin
373
+ find_command_by_match_or_listing(search)
374
+ rescue ArgumentError
375
+ nil
376
+ end)
377
+ end
378
+
379
+ # Is the given line a command invocation?
380
+ # @param [String] val
381
+ # @return [Boolean]
382
+ def valid_command?(val)
383
+ !!find_command(val)
384
+ end
385
+
386
+ # Process the given line to see whether it needs executing as a command.
387
+ # @param [String] val The line to execute
388
+ # @param [Hash] context The context to execute the commands with
389
+ # @return [CommandSet::Result]
390
+ def process_line(val, context={})
391
+ if command = find_command(val)
392
+ context = context.merge(:command_set => self)
393
+ retval = command.new(context).process_line(val)
394
+ Result.new(true, retval)
395
+ else
396
+ Result.new(false)
397
+ end
398
+ end
399
+
400
+ # @private (used for testing)
401
+ def run_command(context, match, *args)
402
+ command = @commands[match] or raise NoCommandError.new(match, self)
403
+ command.new(context).call_safely(*args)
404
+ end
405
+
406
+ # Generate completions for the user's search.
407
+ # @param [String] search The line to search for
408
+ # @param [Hash] context The context to create the command with
409
+ # @return [Array<String>]
410
+ def complete(search, context={})
411
+ if command = find_command(search)
412
+ command.new(context).complete(search)
413
+ else
414
+ @commands.keys.select do |key|
415
+ String === key && key.start_with?(search)
416
+ end.map{ |key| key + " " }
417
+ end
418
+ end
419
+ end
420
+
421
+ # Wraps the return result of process_commands, indicates if the
422
+ # result IS a command and what kind of command (e.g void)
423
+ class Result
424
+ attr_reader :retval
425
+
426
+ def initialize(is_command, retval = nil)
427
+ @is_command, @retval = is_command, retval
428
+ end
429
+
430
+ # Is the result a command?
431
+ # @return [Boolean]
432
+ def command?
433
+ @is_command
434
+ end
435
+
436
+ # Is the result a command and if it is, is it a void command?
437
+ # (one that does not return a value)
438
+ # @return [Boolean]
439
+ def void_command?
440
+ retval == Command::VOID_VALUE
441
+ end
442
+ end
443
+ end
@@ -0,0 +1,6 @@
1
+ # Default commands used by Pry.
2
+ Pry::Commands = Pry::CommandSet.new
3
+
4
+ Dir[File.expand_path('../commands', __FILE__) << '/*.rb'].each do |file|
5
+ require file
6
+ end
@@ -0,0 +1,99 @@
1
+ class Pry
2
+ class Command::AmendLine < Pry::ClassCommand
3
+ match(/amend-line(?: (-?\d+)(?:\.\.(-?\d+))?)?/)
4
+ group 'Editing'
5
+ description 'Amend a line of input in multi-line mode.'
6
+ command_options :interpolate => false, :listing => 'amend-line'
7
+
8
+ banner <<-'BANNER'
9
+ Amend a line of input in multi-line mode. `amend-line N`, where the N represents
10
+ line to replace. Can also specify a range of lines using `amend-line N..M`
11
+ syntax. Passing "!" as replacement content deletes the line(s) instead.
12
+
13
+ amend-line 1 puts 'new' # replace line 1
14
+ amend-line 1..4 ! # delete lines 1..4
15
+ amend-line 3 >puts 'bye' # insert before line 3
16
+ amend-line puts 'appended' # no line number modifies immediately preceding line
17
+ BANNER
18
+
19
+ def process
20
+ raise CommandError, "No input to amend." if eval_string.empty?
21
+
22
+ eval_string.replace amended_input(eval_string)
23
+ run "fix-indent"
24
+ run "show-input"
25
+ end
26
+
27
+ private
28
+
29
+ # @param [String] string The string to amend.
30
+ # @return [String] A new string with the amendments applied to it.
31
+ def amended_input(string)
32
+ input_array = eval_string.each_line.to_a
33
+
34
+ if arg_string == "!"
35
+ delete_from_array(input_array, line_range)
36
+ elsif arg_string.start_with?(">")
37
+ insert_into_array(input_array, line_range)
38
+ else
39
+ replace_in_array(input_array, line_range)
40
+ end
41
+
42
+ input_array.join
43
+ end
44
+
45
+ def delete_from_array(array, range)
46
+ array.slice!(range)
47
+ end
48
+
49
+ def insert_into_array(array, range)
50
+ insert_slot = Array(range).first
51
+ array.insert(insert_slot, arg_string[1..-1] << "\n")
52
+ end
53
+
54
+ def replace_in_array(array, range)
55
+ array[range] = arg_string + "\n"
56
+ end
57
+
58
+ # @return [Fixnum] The number of lines currently in `eval_string` (the input buffer).
59
+ def line_count
60
+ eval_string.lines.count
61
+ end
62
+
63
+ # Returns the (one-indexed) start and end lines given by the user.
64
+ # The lines in this range will be affected by the `amend-line`.
65
+ # Returns `nil` if no lines were specified by the user.
66
+ # @return [Array<Fixnum>, nil]
67
+ def start_and_end_line_number
68
+ start_line_number, end_line_number = args
69
+ end_line_number ||= start_line_number.to_i
70
+
71
+ [start_line_number.to_i, end_line_number.to_i] if start_line_number
72
+ end
73
+
74
+ # Takes two numbers that are 1-indexed, and returns a range (or
75
+ # number) that is 0-indexed. 1-indexed means the first element is
76
+ # indentified by 1 rather than by 0 (as is the case for Ruby arrays).
77
+ # @param [Fixnum] start_line_number One-indexed number.
78
+ # @param [Fixnum] end_line_number One-indexed number.
79
+ # @return [Range] The zero-indexed range.
80
+ def zero_indexed_range_from_one_indexed_numbers(start_line_number, end_line_number)
81
+ # FIXME: one_index_number is a horrible name for this method
82
+ one_index_number(start_line_number)..one_index_number(end_line_number)
83
+ end
84
+
85
+ # The lines (or line) that will be modified by the `amend-line`.
86
+ # @return [Range, Fixnum] The lines or line.
87
+ def line_range
88
+ start_line_number, end_line_number = start_and_end_line_number
89
+ if start_line_number
90
+ zero_indexed_range_from_one_indexed_numbers(start_line_number,
91
+ end_line_number)
92
+ else
93
+ line_count - 1
94
+ end
95
+ end
96
+ end
97
+
98
+ Pry::Commands.add_command(Pry::Command::AmendLine)
99
+ end