pry 0.9.8.4 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG +26 -0
  3. data/README.markdown +3 -3
  4. data/lib/pry.rb +9 -1
  5. data/lib/pry/code.rb +93 -0
  6. data/lib/pry/command.rb +35 -22
  7. data/lib/pry/command_set.rb +97 -67
  8. data/lib/pry/config.rb +63 -10
  9. data/lib/pry/core_extensions.rb +24 -18
  10. data/lib/pry/default_commands/context.rb +72 -12
  11. data/lib/pry/default_commands/easter_eggs.rb +4 -0
  12. data/lib/pry/default_commands/editing.rb +43 -15
  13. data/lib/pry/default_commands/find_method.rb +171 -0
  14. data/lib/pry/default_commands/hist.rb +10 -6
  15. data/lib/pry/default_commands/introspection.rb +183 -30
  16. data/lib/pry/default_commands/ls.rb +77 -7
  17. data/lib/pry/default_commands/misc.rb +1 -0
  18. data/lib/pry/default_commands/navigating_pry.rb +1 -8
  19. data/lib/pry/helpers/base_helpers.rb +10 -2
  20. data/lib/pry/helpers/command_helpers.rb +23 -40
  21. data/lib/pry/helpers/documentation_helpers.rb +65 -0
  22. data/lib/pry/indent.rb +17 -4
  23. data/lib/pry/method.rb +61 -45
  24. data/lib/pry/pry_class.rb +9 -3
  25. data/lib/pry/pry_instance.rb +99 -65
  26. data/lib/pry/rbx_method.rb +2 -9
  27. data/lib/pry/version.rb +1 -1
  28. data/lib/pry/wrapped_module.rb +236 -1
  29. data/pry.gemspec +5 -5
  30. data/test/helper.rb +22 -0
  31. data/test/test_command.rb +29 -0
  32. data/test/test_command_integration.rb +193 -10
  33. data/test/test_command_set.rb +82 -17
  34. data/test/test_default_commands/test_cd.rb +16 -0
  35. data/test/test_default_commands/test_context.rb +61 -0
  36. data/test/test_default_commands/test_documentation.rb +163 -43
  37. data/test/test_default_commands/test_find_method.rb +42 -0
  38. data/test/test_default_commands/test_input.rb +32 -0
  39. data/test/test_default_commands/test_introspection.rb +50 -197
  40. data/test/test_default_commands/test_ls.rb +22 -0
  41. data/test/test_default_commands/test_show_source.rb +306 -0
  42. data/test/test_pry.rb +3 -3
  43. data/test/test_pry_defaults.rb +21 -0
  44. data/test/test_sticky_locals.rb +81 -1
  45. data/test/test_syntax_checking.rb +7 -6
  46. metadata +22 -14
data/.gitignore CHANGED
@@ -13,3 +13,4 @@ coverage/
13
13
  .rvmrc
14
14
  Gemfile.lock
15
15
  *.swp
16
+ **/*~
data/CHANGELOG CHANGED
@@ -1,3 +1,29 @@
1
+ 18/4/2012 version 0.9.9
2
+
3
+ MAJOR NEW FEATURES
4
+ * lines of input are syntax highlighted upon 'enter' keypress
5
+ * show-source command can now show class/module sourcecode (use -a to see all monkeypatches). Hard dependency on ruby18_source_location gem in MRI 1.8
6
+ * show-doc command can show class/module docs (use -a to see docs for all monkeypatches) Hard dependency on ruby18_source_location gem in MRI 1.8.
7
+ * new `find-method` command, performs a recursive search in a namespace for the existence of methods. Can find methods whose names match a regex or methods which contain provided CODE! This command is like a ruby-aware 'grep', very cool (thanks swarley)
8
+ * pry-coolline now works properly with Pry (https://github.com/pry/pry-coolline)
9
+ * alias_command method now much more powerful, e.g: alias_command "lM", "ls -M"
10
+ * `whereami` is now more intelligent, automatically showing entire sourcecode of current method if current context is a method (thanks robgleeson).
11
+
12
+ remaining items:
13
+ * fixed windows crashing bug when paging
14
+ * lines ending with \ are incomplete (kudos to fowl)
15
+ * `edit-method -n` no longer blocks (thanks misfo)s
16
+ * show instance methods of modules by default in ls
17
+ * docs for REPL defined methods can now be displayed using show-doc
18
+ * autoload ruby18_source_location on mri18, when available (https://github.com/conradirwin/ruby18_source_location)
19
+ * tab completion should work on first line now (historic bug fixed)
20
+ * :quiet => true option added to `Pry.start`, turns off whereami
21
+ * another easter egg added
22
+ * show unloaded constants in yellow for ls
23
+ * improved documentation for Pry.config options
24
+ * improved auto indentation
25
+ * JRuby: heuristics used to clean up 'ls' output (less internal methods polluting output)
26
+
1
27
  6/3/2012 version 0.9.8.4 major bugfix
2
28
  * ~/.pry_history wasnt being created (if it did not exist)! FIXED
3
29
  * `hist --save` saved colors! FIXED
@@ -33,9 +33,9 @@ these include:
33
33
  * Gist integration
34
34
  * Navigation around state (`cd`, `ls` and friends)
35
35
  * Runtime invocation (use Pry as a developer console or debugger)
36
- * Exotic object support (BasicObject ins
37
- * tances, IClasses, ...)
38
- * A Powerful and flexible command system* Ability to view and replay history
36
+ * Exotic object support (BasicObject instances, IClasses, ...)
37
+ * A Powerful and flexible command system
38
+ * Ability to view and replay history
39
39
 
40
40
  * Many convenience commands inspired by IPython, Smalltalk and other advanced REPLs
41
41
  * A wide-range number of [plugins](https://github.com/pry/pry/wiki/Available-plugins) that provide remote sessions, full debugging functionality, and more.
data/lib/pry.rb CHANGED
@@ -9,12 +9,13 @@ require 'pry/hooks'
9
9
  class Pry
10
10
  # The default hooks - display messages when beginning and ending Pry sessions.
11
11
  DEFAULT_HOOKS = Pry::Hooks.new.add_hook(:before_session, :default) do |out, target, _pry_|
12
+ next if _pry_.quiet?
12
13
  # ensure we're actually in a method
13
14
  file = target.eval('__FILE__')
14
15
 
15
16
  # /unknown/ for rbx
16
17
  if file !~ /(\(.*\))|<.*>/ && file !~ /__unknown__/ && file != "" && file != "-e" || file == Pry.eval_path
17
- _pry_.run_command("whereami 5", "", target)
18
+ _pry_.run_command("whereami", "", target)
18
19
  end
19
20
  end
20
21
 
@@ -158,6 +159,13 @@ class Pry
158
159
  end
159
160
  end
160
161
 
162
+ if Pry::Helpers::BaseHelpers.mri_18?
163
+ begin
164
+ require 'ruby18_source_location'
165
+ rescue LoadError
166
+ end
167
+ end
168
+
161
169
  require "method_source"
162
170
  require 'shellwords'
163
171
  require "readline"
@@ -27,6 +27,72 @@ class Pry
27
27
  # object.
28
28
  class Code
29
29
  class << self
30
+
31
+ # Determine if a string of code is a complete Ruby expression.
32
+ # @param [String] code The code to validate.
33
+ # @return [Boolean] Whether or not the code is a complete Ruby expression.
34
+ # @raise [SyntaxError] Any SyntaxError that does not represent incompleteness.
35
+ # @example
36
+ # complete_expression?("class Hello") #=> false
37
+ # complete_expression?("class Hello; end") #=> true
38
+ def complete_expression?(str)
39
+ if defined?(Rubinius::Melbourne19) && RUBY_VERSION =~ /^1\.9/
40
+ Rubinius::Melbourne19.parse_string(str, Pry.eval_path)
41
+ elsif defined?(Rubinius::Melbourne)
42
+ Rubinius::Melbourne.parse_string(str, Pry.eval_path)
43
+ else
44
+ catch(:valid) do
45
+ Helpers::BaseHelpers.silence_warnings do
46
+ eval("BEGIN{throw :valid}\n#{str}", binding, Pry.eval_path)
47
+ end
48
+ end
49
+ end
50
+
51
+ # Assert that a line which ends with a , or \ is incomplete.
52
+ str !~ /[,\\]\s*\z/
53
+ rescue SyntaxError => e
54
+ if incomplete_user_input_exception?(e)
55
+ false
56
+ else
57
+ raise e
58
+ end
59
+ end
60
+
61
+ # Check whether the exception indicates that the user should input more.
62
+ #
63
+ # @param [SyntaxError] the exception object that was raised.
64
+ # @param [Array<String>] The stack frame of the function that executed eval.
65
+ # @return [Boolean]
66
+ #
67
+ def incomplete_user_input_exception?(ex)
68
+ case ex.message
69
+ when /unexpected (\$end|end-of-file|END_OF_FILE)/, # mri, jruby, ironruby
70
+ /unterminated (quoted string|string|regexp) meets end of file/, # "quoted string" is ironruby
71
+ /missing 'end' for/, /: expecting '[})\]]'$/, /can't find string ".*" anywhere before EOF/, /: expecting keyword_end/, /expecting kWHEN/ # rbx
72
+ true
73
+ else
74
+ false
75
+ end
76
+ end
77
+ private :incomplete_user_input_exception?
78
+
79
+ # Retrieve the first complete expression from the passed string.
80
+ #
81
+ # @param [String, Array<String>] str The string (or array of lines) to extract the complete
82
+ # expression from.
83
+ # @return [String, nil] The first complete expression, or `nil` if
84
+ # none found.
85
+ def retrieve_complete_expression_from(str_or_lines)
86
+ lines = str_or_lines.is_a?(Array) ? str_or_lines : str_or_lines.each_line.to_a
87
+
88
+ code = ""
89
+ lines.each do |v|
90
+ code << v
91
+ return code if complete_expression?(code)
92
+ end
93
+ nil
94
+ end
95
+
30
96
  # Instantiate a `Code` object containing code loaded from a file or
31
97
  # Pry's line buffer.
32
98
  #
@@ -63,6 +129,16 @@ class Pry
63
129
  new(meth.source, start_line, meth.source_type)
64
130
  end
65
131
 
132
+ # Attempt to extract the source code for module (or class) `mod`.
133
+ #
134
+ # @param [Module, Class] mod The module (or class) of interest.
135
+ # @return [Code]
136
+ def from_module(mod, start_line=nil)
137
+ mod = Pry::WrappedModule(mod)
138
+ start_line ||= mod.source_line || 1
139
+ new(mod.source, start_line, :ruby)
140
+ end
141
+
66
142
  protected
67
143
  # Guess the CodeRay type of a file from its extension, or nil if
68
144
  # unknown.
@@ -173,6 +249,23 @@ class Pry
173
249
  end
174
250
  end
175
251
 
252
+ # Take `num_lines` from `start_line`, forward or backwards
253
+ #
254
+ # @param [Fixnum] start_line
255
+ # @param [Fixnum] num_lines
256
+ # @return [Code]
257
+ def take_lines(start_line, num_lines)
258
+ if start_line >= 0
259
+ start_idx = @lines.index { |l| l.last >= start_line } || @lines.length
260
+ else
261
+ start_idx = @lines.length + start_line
262
+ end
263
+
264
+ alter do
265
+ @lines = @lines.slice(start_idx, num_lines)
266
+ end
267
+ end
268
+
176
269
  # Remove all lines except for the `lines` up to and excluding `line_num`.
177
270
  #
178
271
  # @param [Fixnum] line_num
@@ -14,10 +14,15 @@ class Pry
14
14
  # Properties of the command itself (as passed as arguments to
15
15
  # {CommandSet#command} or {CommandSet#create_command}).
16
16
  class << self
17
- attr_accessor :block
18
- attr_accessor :name
17
+ attr_writer :block
19
18
  attr_writer :description
20
19
  attr_writer :command_options
20
+ attr_writer :match
21
+
22
+ def match(arg=nil)
23
+ @match = arg if arg
24
+ @match
25
+ end
21
26
 
22
27
  # Define or get the command's description
23
28
  def description(arg=nil)
@@ -40,24 +45,31 @@ class Pry
40
45
  @banner = arg if arg
41
46
  @banner || description
42
47
  end
43
- end
44
48
 
49
+ def block
50
+ @block || instance_method(:process) && instance_method(:process)
51
+ end
52
+ end
45
53
 
46
54
  # Make those properties accessible to instances
47
55
  def name; self.class.name; end
56
+ def match; self.class.match; end
48
57
  def description; self.class.description; end
49
58
  def block; self.class.block; end
50
59
  def command_options; self.class.options; end
51
60
  def command_name; command_options[:listing]; end
52
61
 
53
62
  class << self
63
+ def name
64
+ super.to_s == "" ? "#<class(Pry::Command #{match.inspect})>" : super
65
+ end
54
66
  def inspect
55
- "#<class(Pry::Command #{name.inspect})>"
67
+ name
56
68
  end
57
69
 
58
70
  # Create a new command with the given properties.
59
71
  #
60
- # @param String name the name of the command
72
+ # @param String/Regex match the thing that triggers this command
61
73
  # @param String description the description to appear in {help}
62
74
  # @param Hash options behavioural options (@see {Pry::CommandSet#command})
63
75
  # @param Module helpers a module of helper functions to be included.
@@ -65,10 +77,10 @@ class Pry
65
77
  #
66
78
  # @return Class (a subclass of Pry::Command)
67
79
  #
68
- def subclass(name, description, options, helpers, &block)
80
+ def subclass(match, description, options, helpers, &block)
69
81
  klass = Class.new(self)
70
82
  klass.send(:include, helpers)
71
- klass.name = name
83
+ klass.match = match
72
84
  klass.description = description
73
85
  klass.command_options = options
74
86
  klass.block = block
@@ -115,10 +127,11 @@ class Pry
115
127
  end
116
128
 
117
129
  def command_regex
118
- prefix = convert_to_regex(Pry.config.command_prefix)
130
+ pr = defined?(Pry.config.command_prefix) ? Pry.config.command_prefix : ""
131
+ prefix = convert_to_regex(pr)
119
132
  prefix = "(?:#{prefix})?" unless options[:use_prefix]
120
133
 
121
- /^#{prefix}#{convert_to_regex(name)}(?!\S)/
134
+ /^#{prefix}#{convert_to_regex(match)}(?!\S)/
122
135
  end
123
136
 
124
137
  def convert_to_regex(obj)
@@ -180,7 +193,7 @@ class Pry
180
193
  # @example
181
194
  # run "amend-line", "5", 'puts "hello world"'
182
195
  def run(command_string, *args)
183
- complete_string = "#{command_string} #{args.join(" ")}"
196
+ complete_string = "#{command_string} #{args.join(" ")}".rstrip
184
197
  command_set.process_line(complete_string, context)
185
198
  end
186
199
 
@@ -233,12 +246,12 @@ class Pry
233
246
  # the current scope.
234
247
  # @param [String] command_name_match The name of the colliding command.
235
248
  # @param [Binding] target The current binding context.
236
- def check_for_command_name_collision(command_name_match, arg_string)
237
- collision_type = target.eval("defined?(#{command_name_match})")
249
+ def check_for_command_collision(command_match, arg_string)
250
+ collision_type = target.eval("defined?(#{command_match})")
238
251
  collision_type ||= 'local-variable' if arg_string.match(%r{\A\s*[-+*/%&|^]*=})
239
252
 
240
253
  if collision_type
241
- output.puts "#{Pry::Helpers::Text.bold('WARNING:')} Calling Pry command '#{command_name_match}'," +
254
+ output.puts "#{Pry::Helpers::Text.bold('WARNING:')} Calling Pry command '#{command_match}'," +
242
255
  "which conflicts with a #{collision_type}.\n\n"
243
256
  end
244
257
  rescue Pry::RescuableException
@@ -248,8 +261,8 @@ class Pry
248
261
  #
249
262
  # @param String the line of input
250
263
  # @return [
251
- # String the command name used, or portion of line that matched the command_regex
252
- # String a string of all the arguments (i.e. everything but the name)
264
+ # String the portion of the line that matched with the Command match
265
+ # String a string of all the arguments (i.e. everything but the match)
253
266
  # Array the captures caught by the command_regex
254
267
  # Array args the arguments got by splitting the arg_string
255
268
  # ]
@@ -285,9 +298,9 @@ class Pry
285
298
  # @param String the line to process
286
299
  # @return Object or Command::VOID_VALUE
287
300
  def process_line(line)
288
- command_name, arg_string, captures, args = tokenize(line)
301
+ command_match, arg_string, captures, args = tokenize(line)
289
302
 
290
- check_for_command_name_collision(command_name, arg_string) if Pry.config.collision_warning
303
+ check_for_command_collision(command_match, arg_string) if Pry.config.collision_warning
291
304
 
292
305
  self.arg_string = arg_string
293
306
  self.captures = captures
@@ -310,7 +323,7 @@ class Pry
310
323
  block_init_string = arg_string.slice!(block_index..-1)[1..-1]
311
324
  prime_string = "proc #{block_init_string}\n"
312
325
 
313
- if !_pry_.complete_expression?(prime_string)
326
+ if !Pry::Code.complete_expression?(prime_string)
314
327
  block_string = _pry_.r(target, prime_string)
315
328
  else
316
329
  block_string = prime_string
@@ -335,14 +348,14 @@ class Pry
335
348
  unless dependencies_met?
336
349
  gems_needed = Array(command_options[:requires_gem])
337
350
  gems_not_installed = gems_needed.select { |g| !gem_installed?(g) }
338
- output.puts "\nThe command '#{name}' is #{Helpers::Text.bold("unavailable")} because it requires the following gems to be installed: #{(gems_not_installed.join(", "))}"
351
+ output.puts "\nThe command '#{command_name}' is #{Helpers::Text.bold("unavailable")} because it requires the following gems to be installed: #{(gems_not_installed.join(", "))}"
339
352
  output.puts "-"
340
- output.puts "Type `install-command #{name}` to install the required gems and activate this command."
353
+ output.puts "Type `install-command #{command_name}` to install the required gems and activate this command."
341
354
  return void
342
355
  end
343
356
 
344
357
  if command_options[:argument_required] && args.empty?
345
- raise CommandError, "The command '#{name}' requires an argument."
358
+ raise CommandError, "The command '#{command_name}' requires an argument."
346
359
  end
347
360
 
348
361
  ret = call_with_hooks(*args)
@@ -507,6 +520,6 @@ class Pry
507
520
  # gist_method
508
521
  # end
509
522
  # end
510
- def process; raise CommandError, "command '#{name}' not implemented" end
523
+ def process; raise CommandError, "command '#{command_name}' not implemented" end
511
524
  end
512
525
  end
@@ -1,7 +1,7 @@
1
1
  class Pry
2
2
  class NoCommandError < StandardError
3
- def initialize(name, owner)
4
- super "Command '#{name}' not found in command set #{owner}"
3
+ def initialize(match, owner)
4
+ super "Command '#{match}' not found in command set #{owner}"
5
5
  end
6
6
  end
7
7
 
@@ -27,8 +27,7 @@ class Pry
27
27
  end
28
28
 
29
29
  # Defines a new Pry command.
30
- # @param [String, Regexp] name The name of the command. Can be
31
- # Regexp as well as String.
30
+ # @param [String, Regexp] match The start of invocations of this command.
32
31
  # @param [String] description A description of the command.
33
32
  # @param [Hash] options The optional configuration parameters.
34
33
  # @option options [Boolean] :keep_retval Whether or not to use return value
@@ -43,7 +42,7 @@ class Pry
43
42
  # executing the command. Defaults to true.
44
43
  # @option options [String] :listing The listing name of the
45
44
  # command. That is the name by which the command is looked up by
46
- # help and by show-command. Necessary for regex based commands.
45
+ # help and by show-command. Necessary for commands with regex matches.
47
46
  # @option options [Boolean] :use_prefix Whether the command uses
48
47
  # `Pry.config.command_prefix` prefix (if one is defined). Defaults
49
48
  # to true.
@@ -80,18 +79,17 @@ class Pry
80
79
  # # hello john, nice number: 10
81
80
  # # pry(main)> help number
82
81
  # # number-N regex command
83
- def block_command(name, description="No description.", options={}, &block)
82
+ def block_command(match, description="No description.", options={}, &block)
84
83
  description, options = ["No description.", description] if description.is_a?(Hash)
85
- options = default_options(name).merge!(options)
84
+ options = default_options(match).merge!(options)
86
85
 
87
- commands[name] = Pry::BlockCommand.subclass(name, description, options, helper_module, &block)
86
+ commands[match] = Pry::BlockCommand.subclass(match, description, options, helper_module, &block)
88
87
  end
89
88
  alias_method :command, :block_command
90
89
 
91
90
  # Defines a new Pry command class.
92
91
  #
93
- # @param [String, Regexp] name The name of the command. Can be
94
- # Regexp as well as String.
92
+ # @param [String, Regexp] match The start of invocations of this command.
95
93
  # @param [String] description A description of the command.
96
94
  # @param [Hash] options The optional configuration parameters, see {#command}
97
95
  # @param &Block The class body's definition.
@@ -113,40 +111,40 @@ class Pry
113
111
  # end
114
112
  # end
115
113
  #
116
- def create_command(name, description="No description.", options={}, &block)
114
+ def create_command(match, description="No description.", options={}, &block)
117
115
  description, options = ["No description.", description] if description.is_a?(Hash)
118
- options = default_options(name).merge!(options)
116
+ options = default_options(match).merge!(options)
119
117
 
120
- commands[name] = Pry::ClassCommand.subclass(name, description, options, helper_module, &block)
121
- commands[name].class_eval(&block)
122
- commands[name]
118
+ commands[match] = Pry::ClassCommand.subclass(match, description, options, helper_module, &block)
119
+ commands[match].class_eval(&block)
120
+ commands[match]
123
121
  end
124
122
 
125
123
  # Execute a block of code before a command is invoked. The block also
126
124
  # gets access to parameters that will be passed to the command and
127
125
  # is evaluated in the same context.
128
- # @param [String, Regexp] name The name of the command.
126
+ # @param [String, Regexp] search The match or listing of the command.
129
127
  # @yield The block to be run before the command.
130
128
  # @example Display parameter before invoking command
131
129
  # Pry.commands.before_command("whereami") do |n|
132
130
  # output.puts "parameter passed was #{n}"
133
131
  # end
134
- def before_command(name, &block)
135
- cmd = find_command_by_name_or_listing(name)
132
+ def before_command(search, &block)
133
+ cmd = find_command_by_match_or_listing(search)
136
134
  cmd.hooks[:before].unshift block
137
135
  end
138
136
 
139
137
  # Execute a block of code after a command is invoked. The block also
140
138
  # gets access to parameters that will be passed to the command and
141
139
  # is evaluated in the same context.
142
- # @param [String, Regexp] name The name of the command.
140
+ # @param [String, Regexp] search The match or listing of the command.
143
141
  # @yield The block to be run after the command.
144
142
  # @example Display text 'command complete' after invoking command
145
143
  # Pry.commands.after_command("whereami") do |n|
146
144
  # output.puts "command complete!"
147
145
  # end
148
- def after_command(name, &block)
149
- cmd = find_command_by_name_or_listing(name)
146
+ def after_command(search, &block)
147
+ cmd = find_command_by_match_or_listing(search)
150
148
  cmd.hooks[:after] << block
151
149
  end
152
150
 
@@ -154,91 +152,122 @@ class Pry
154
152
  @commands.each(&block)
155
153
  end
156
154
 
155
+ # Add a given command object to this set.
156
+ # @param Command the subclass of Pry::Command you wish to add.
157
+ def add_command(command)
158
+ commands[command.match] = command
159
+ end
160
+
157
161
  # Removes some commands from the set
158
- # @param [Array<String>] names name of the commands to remove
159
- def delete(*names)
160
- names.each do |name|
161
- cmd = find_command_by_name_or_listing(name)
162
- commands.delete cmd.name
162
+ # @param [Array<String>] searches the matches or listings of the commands to remove
163
+ def delete(*searches)
164
+ searches.each do |search|
165
+ cmd = find_command_by_match_or_listing(search)
166
+ commands.delete cmd.match
163
167
  end
164
168
  end
165
169
 
166
170
  # Imports all the commands from one or more sets.
167
171
  # @param [Array<CommandSet>] sets Command sets, all of the commands of which
168
172
  # will be imported.
173
+ # @return [Pry::CommandSet] Returns the reciever (a command set).
169
174
  def import(*sets)
170
175
  sets.each do |set|
171
176
  commands.merge! set.commands
172
177
  helper_module.send :include, set.helper_module
173
178
  end
179
+ self
174
180
  end
175
181
 
176
182
  # Imports some commands from a set
177
183
  # @param [CommandSet] set Set to import commands from
178
- # @param [Array<String>] names Commands to import
179
- def import_from(set, *names)
184
+ # @param [Array<String>] matches Commands to import
185
+ # @return [Pry::CommandSet] Returns the reciever (a command set).
186
+ def import_from(set, *matches)
180
187
  helper_module.send :include, set.helper_module
181
- names.each do |name|
182
- cmd = set.find_command_by_name_or_listing(name)
183
- commands[cmd.name] = cmd
188
+ matches.each do |match|
189
+ cmd = set.find_command_by_match_or_listing(match)
190
+ commands[cmd.match] = cmd
184
191
  end
192
+ self
185
193
  end
186
194
 
187
- # @param [String, Regexp] name_or_listing The name or listing name
195
+ # @param [String, Regexp] match_or_listing The match or listing of a command.
188
196
  # of the command to retrieve.
189
197
  # @return [Command] The command object matched.
190
- def find_command_by_name_or_listing(name_or_listing)
191
- if commands[name_or_listing]
192
- cmd = commands[name_or_listing]
198
+ def find_command_by_match_or_listing(match_or_listing)
199
+ if commands[match_or_listing]
200
+ cmd = commands[match_or_listing]
193
201
  else
194
- _, cmd = commands.find { |name, command| command.options[:listing] == name_or_listing }
202
+ _, cmd = commands.find { |match, command| command.options[:listing] == match_or_listing }
195
203
  end
196
204
 
197
- raise ArgumentError, "Cannot find a command with name: '#{name_or_listing}'!" if !cmd
205
+ raise ArgumentError, "Cannot find a command: '#{match_or_listing}'!" if !cmd
198
206
  cmd
199
207
  end
200
- protected :find_command_by_name_or_listing
208
+ protected :find_command_by_match_or_listing
201
209
 
202
210
  # Aliases a command
203
- # @param [String] new_name New name of the command.
204
- # @param [String] old_name Old name of the command.
205
- # @param [String, nil] desc New description of the command.
206
- def alias_command(new_name, old_name, desc="")
207
- orig_command = find_command_by_name_or_listing(old_name)
208
- commands[new_name] = orig_command.dup
209
- commands[new_name].name = new_name
210
- commands[new_name].description = desc
211
+ # Note that if `desc` parameter is `nil` then the default
212
+ # description is used.
213
+ # @param [String, Regex] match The match of the alias (can be a regex).
214
+ # @param [String] action The action to be performed (typically
215
+ # another command).
216
+ # @param [Hash] options The optional configuration parameters,
217
+ # accepts the same as the `command` method, but also allows the
218
+ # command description to be passed this way too as `:desc`
219
+ # @example Creating an alias for `ls -M`
220
+ # Pry.config.commands.alias_command "lM", "ls -M"
221
+ # @example Pass explicit description (overriding default).
222
+ # Pry.config.commands.alias_command "lM", "ls -M", :desc => "cutiepie"
223
+ def alias_command(match, action, options={})
224
+ original_options = find_command(action).options.dup
225
+
226
+ options = original_options.merge!({
227
+ :desc => "Alias for `#{action}`",
228
+ :listing => match
229
+ }).merge!(options)
230
+
231
+ # ensure default description is used if desc is nil
232
+ desc = options.delete(:desc).to_s
233
+
234
+ c = block_command match, desc, options do |*args|
235
+ run action, *args
236
+ end
237
+
238
+ c.group "Aliases"
239
+
240
+ c
211
241
  end
212
242
 
213
- # Rename a command. Accepts either actual name or listing name for
214
- # the `old_name`.
215
- # `new_name` must be the actual name of the new command.
216
- # @param [String, Regexp] new_name The new name for the command.
217
- # @param [String, Regexp] old_name The command's current name.
243
+ # Rename a command. Accepts either match or listing for the search.
244
+ #
245
+ # @param [String, Regexp] new_name The new match for the command.
246
+ # @param [String, Regexp] search The command's current match or listing.
218
247
  # @param [Hash] options The optional configuration parameters,
219
248
  # accepts the same as the `command` method, but also allows the
220
249
  # command description to be passed this way too.
221
250
  # @example Renaming the `ls` command and changing its description.
222
251
  # Pry.config.commands.rename "dir", "ls", :description => "DOS friendly ls"
223
- def rename_command(new_name, old_name, options={})
224
- cmd = find_command_by_name_or_listing(old_name)
252
+ def rename_command(new_match, search, options={})
253
+ cmd = find_command_by_match_or_listing(search)
225
254
 
226
255
  options = {
227
- :listing => new_name,
256
+ :listing => new_match,
228
257
  :description => cmd.description
229
258
  }.merge!(options)
230
259
 
231
- commands[new_name] = cmd.dup
232
- commands[new_name].name = new_name
233
- commands[new_name].description = options.delete(:description)
234
- commands[new_name].options.merge!(options)
235
- commands.delete(cmd.name)
260
+ commands[new_match] = cmd.dup
261
+ commands[new_match].match = new_match
262
+ commands[new_match].description = options.delete(:description)
263
+ commands[new_match].options.merge!(options)
264
+ commands.delete(cmd.match)
236
265
  end
237
266
 
238
267
  # Sets or gets the description for a command (replacing the old
239
268
  # description). Returns current description if no description
240
269
  # parameter provided.
241
- # @param [String, Regexp] name The command name.
270
+ # @param [String, Regexp] match The command match.
242
271
  # @param [String] description The command description.
243
272
  # @example Setting
244
273
  # MyCommands = Pry::CommandSet.new do
@@ -246,8 +275,8 @@ class Pry
246
275
  # end
247
276
  # @example Getting
248
277
  # Pry.config.commands.desc "amend-line"
249
- def desc(name, description=nil)
250
- cmd = find_command_by_name_or_listing(name)
278
+ def desc(search, description=nil)
279
+ cmd = find_command_by_match_or_listing(search)
251
280
  return cmd.description if !description
252
281
 
253
282
  cmd.description = description
@@ -282,6 +311,7 @@ class Pry
282
311
  def find_command(val)
283
312
  commands.values.select{ |c| c.matches?(val) }.sort_by{ |c| c.match_score(val) }.last
284
313
  end
314
+ alias_method :[], :find_command
285
315
 
286
316
  # Find the command that the user might be trying to refer to.
287
317
  #
@@ -289,7 +319,7 @@ class Pry
289
319
  # @return [Pry::Command, nil]
290
320
  def find_command_for_help(search)
291
321
  find_command(search) || (begin
292
- find_command_by_name_or_listing(search)
322
+ find_command_by_match_or_listing(search)
293
323
  rescue ArgumentError
294
324
  nil
295
325
  end)
@@ -320,21 +350,21 @@ class Pry
320
350
  end
321
351
 
322
352
  # @nodoc used for testing
323
- def run_command(context, name, *args)
324
- command = commands[name] or raise NoCommandError.new(name, self)
353
+ def run_command(context, match, *args)
354
+ command = commands[match] or raise NoCommandError.new(match, self)
325
355
  command.new(context).call_safely(*args)
326
356
  end
327
357
 
328
358
  private
329
359
 
330
- def default_options(name)
360
+ def default_options(match)
331
361
  {
332
362
  :requires_gem => [],
333
363
  :keep_retval => false,
334
364
  :argument_required => false,
335
365
  :interpolate => true,
336
366
  :shellwords => true,
337
- :listing => name,
367
+ :listing => (String === match ? match : match.inspect),
338
368
  :use_prefix => true,
339
369
  :takes_block => false
340
370
  }