pry 0.10.0.pre2-universal-mswin32

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