pry 0.8.4pre1-i386-mswin32 → 0.9.0-i386-mswin32

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 (60) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG +25 -6
  3. data/README.markdown +11 -4
  4. data/Rakefile +15 -19
  5. data/TODO +28 -2
  6. data/bin/pry +28 -11
  7. data/examples/example_basic.rb +2 -4
  8. data/examples/example_command_override.rb +2 -5
  9. data/examples/example_commands.rb +1 -4
  10. data/examples/example_hooks.rb +2 -5
  11. data/examples/example_image_edit.rb +4 -8
  12. data/examples/example_input.rb +1 -4
  13. data/examples/example_input2.rb +1 -4
  14. data/examples/example_output.rb +1 -4
  15. data/examples/example_print.rb +2 -5
  16. data/examples/example_prompt.rb +2 -5
  17. data/examples/helper.rb +6 -0
  18. data/lib/pry.rb +59 -3
  19. data/lib/pry/command_context.rb +10 -9
  20. data/lib/pry/command_processor.rb +51 -73
  21. data/lib/pry/command_set.rb +79 -28
  22. data/lib/pry/commands.rb +9 -123
  23. data/lib/pry/completion.rb +30 -29
  24. data/lib/pry/config.rb +100 -0
  25. data/lib/pry/default_commands/basic.rb +37 -0
  26. data/lib/pry/default_commands/context.rb +16 -15
  27. data/lib/pry/default_commands/documentation.rb +73 -54
  28. data/lib/pry/default_commands/easter_eggs.rb +1 -20
  29. data/lib/pry/default_commands/gems.rb +31 -40
  30. data/lib/pry/default_commands/input.rb +223 -15
  31. data/lib/pry/default_commands/introspection.rb +108 -73
  32. data/lib/pry/default_commands/ls.rb +25 -11
  33. data/lib/pry/default_commands/shell.rb +29 -39
  34. data/lib/pry/extended_commands/experimental.rb +17 -0
  35. data/lib/pry/extended_commands/user_command_api.rb +22 -0
  36. data/lib/pry/helpers.rb +1 -0
  37. data/lib/pry/helpers/base_helpers.rb +15 -104
  38. data/lib/pry/helpers/command_helpers.rb +96 -59
  39. data/lib/pry/helpers/text.rb +83 -0
  40. data/lib/pry/history_array.rb +105 -0
  41. data/lib/pry/plugins.rb +79 -0
  42. data/lib/pry/pry_class.rb +102 -114
  43. data/lib/pry/pry_instance.rb +123 -55
  44. data/lib/pry/version.rb +1 -1
  45. data/pry.gemspec +45 -0
  46. data/test/helper.rb +57 -7
  47. data/test/test_command_processor.rb +205 -0
  48. data/test/{test_commandset.rb → test_command_set.rb} +18 -12
  49. data/test/test_default_commands.rb +59 -0
  50. data/test/test_default_commands/test_context.rb +64 -0
  51. data/test/test_default_commands/test_documentation.rb +31 -0
  52. data/test/test_default_commands/test_gems.rb +14 -0
  53. data/test/test_default_commands/test_input.rb +327 -0
  54. data/test/test_default_commands/test_introspection.rb +155 -0
  55. data/test/test_history_array.rb +65 -0
  56. data/test/test_pry.rb +548 -313
  57. metadata +48 -15
  58. data/lib/pry/hooks.rb +0 -17
  59. data/lib/pry/print.rb +0 -16
  60. data/lib/pry/prompts.rb +0 -31
@@ -4,25 +4,26 @@ class Pry
4
4
  class CommandContext
5
5
  attr_accessor :output
6
6
  attr_accessor :target
7
+ attr_accessor :captures
8
+ attr_accessor :eval_string
9
+ attr_accessor :arg_string
7
10
  attr_accessor :opts
8
11
  attr_accessor :command_set
9
12
  attr_accessor :command_processor
10
13
 
11
- def run(name, *args)
12
- if name.start_with? "."
13
- cmd = name[1..-1]
14
- command_processor.
15
- execute_system_command([name, Shellwords.join(args)].join(' '),
16
- target)
17
- else
18
- command_set.run_command(self, name, *args)
19
- end
14
+ def run(command_string, *args)
15
+ complete_string = "#{command_string} #{args.join(" ")}"
16
+ command_processor.process_commands(complete_string, eval_string, target)
20
17
  end
21
18
 
22
19
  def commands
23
20
  command_set.commands
24
21
  end
25
22
 
23
+ def text
24
+ Pry::Helpers::Text
25
+ end
26
+
26
27
  include Pry::Helpers::BaseHelpers
27
28
  include Pry::Helpers::CommandHelpers
28
29
  end
@@ -2,9 +2,6 @@ require 'forwardable'
2
2
 
3
3
  class Pry
4
4
  class CommandProcessor
5
- SYSTEM_COMMAND_DELIMITER = "."
6
- SYSTEM_COMMAND_REGEX = /^#{Regexp.escape(SYSTEM_COMMAND_DELIMITER)}(.*)/
7
-
8
5
  extend Forwardable
9
6
 
10
7
  attr_accessor :pry_instance
@@ -15,32 +12,31 @@ class Pry
15
12
 
16
13
  def_delegators :@pry_instance, :commands, :nesting, :output
17
14
 
18
- # Is the string a command valid?
15
+ # Is the string a valid command?
19
16
  # @param [String] val The string passed in from the Pry prompt.
17
+ # @param [Binding] target The context where the string should be
18
+ # interpolated in.
20
19
  # @return [Boolean] Whether the string is a valid command.
21
- def valid_command?(val)
22
- system_command?(val) || pry_command?(val)
23
- end
24
-
25
- # Is the string a valid system command?
26
- # @param [String] val The string passed in from the Pry prompt.
27
- # @return [Boolean] Whether the string is a valid system command.
28
- def system_command?(val)
29
- !!(SYSTEM_COMMAND_REGEX =~ val)
20
+ def valid_command?(val, target=binding)
21
+ !!(command_matched(val, target)[0])
30
22
  end
31
23
 
32
- # Is the string a valid pry command?
33
- # A Pry command is a command that is not a system command.
34
- # @param [String] val The string passed in from the Pry prompt.
35
- # @return [Boolean] Whether the string is a valid Pry command.
36
- def pry_command?(val)
37
- !!command_matched(val).first
24
+ # Convert the object to a form that can be interpolated into a
25
+ # Regexp cleanly.
26
+ # @return [String] The string to interpolate into a Regexp
27
+ def convert_to_regex(obj)
28
+ case obj
29
+ when String
30
+ Regexp.escape(obj)
31
+ else
32
+ obj
33
+ end
38
34
  end
39
35
 
40
36
  # Revaluate the string (str) and perform interpolation.
41
37
  # @param [String] str The string to reevaluate with interpolation.
42
38
  # @param [Binding] target The context where the string should be
43
- # reevaluated in.
39
+ # interpolated in.
44
40
  # @return [String] The reevaluated string with interpolations
45
41
  # applied (if any).
46
42
  def interpolate_string(str, target)
@@ -49,52 +45,34 @@ class Pry
49
45
  target.eval(dumped_str)
50
46
  end
51
47
 
52
- # Execute a given system command.
53
- # The commands first have interpolation applied against the
54
- # `target` context.
55
- # All system command are forwarded to a shell. Note that the `cd`
56
- # command is special-cased and is converted internallly to a `Dir.chdir`
57
- # @param [String] val The system command to execute.
58
- # @param [Binding] target The context in which to perform string interpolation.
59
- def execute_system_command(val, target)
60
- SYSTEM_COMMAND_REGEX =~ val
61
- cmd = interpolate_string($1, target)
62
-
63
- if cmd =~ /^cd\s+(.+)/i
64
- begin
65
- @@cd_history ||= []
66
- if $1 == "-"
67
- dest = @@cd_history.pop || Dir.pwd
68
- else
69
- dest = File.expand_path($1)
70
- end
71
-
72
- @@cd_history << Dir.pwd
73
- Dir.chdir(dest)
74
- rescue Errno::ENOENT
75
- output.puts "No such directory: #{dest}"
76
- end
77
- else
78
- if !system(cmd)
79
- output.puts "Error: there was a problem executing system command: #{cmd}"
80
- end
81
- end
82
-
83
- # Tick, tock, im getting rid of this shit soon.
84
- val.replace("")
85
- end
86
-
87
48
  # Determine whether a Pry command was matched and return command data
88
49
  # and argument string.
89
50
  # This method should not need to be invoked directly.
90
51
  # @param [String] val The line of input.
52
+ # @param [Binding] target The binding to perform string
53
+ # interpolation against.
91
54
  # @return [Array] The command data and arg string pair
92
- def command_matched(val)
93
- _, cmd_data = commands.commands.find do |name, cmd_data|
94
- /^#{Regexp.escape(name)}(?!\S)(?:\s+(.+))?/ =~ val
55
+ def command_matched(val, target)
56
+ _, cmd_data = commands.commands.find do |name, data|
57
+
58
+ command_regex = /^#{convert_to_regex(name)}(?!\S)/
59
+
60
+ if data.options[:interpolate]
61
+ # If interpolation fails then the command cannot be matched,
62
+ # so early exit.
63
+ begin
64
+ interp_val = interpolate_string(val, target)
65
+ rescue NameError
66
+ next
67
+ end
68
+
69
+ val.replace interp_val if command_regex =~ interp_val
70
+ else
71
+ command_regex =~ val
72
+ end
95
73
  end
96
74
 
97
- [cmd_data, $1]
75
+ [cmd_data, (Regexp.last_match ? Regexp.last_match.captures : nil), (Regexp.last_match ? Regexp.last_match.end(0) : nil)]
98
76
  end
99
77
 
100
78
  # Process Pry commands. Pry commands are not Ruby methods and are evaluated
@@ -107,30 +85,27 @@ class Pry
107
85
  # multi-line input.
108
86
  # @param [Binding] target The receiver of the commands.
109
87
  def process_commands(val, eval_string, target)
110
- def val.clear() replace("") end
111
- def eval_string.clear() replace("") end
112
-
113
- if system_command?(val)
114
- execute_system_command(val, target)
115
- return
116
- end
117
88
 
118
89
  # no command was matched, so return to caller
119
- return if !pry_command?(val)
90
+ command, captures, pos = command_matched(val, target)
91
+ return if !command
92
+ arg_string = val[pos..-1]
120
93
 
121
- val.replace interpolate_string(val, target)
122
- command, args_string = command_matched(val)
94
+ # remove the one leading space if it exists
95
+ arg_string.slice!(0) if arg_string.start_with?(" ")
123
96
 
124
- args = args_string ? Shellwords.shellwords(args_string) : []
97
+ args = arg_string ? Shellwords.shellwords(arg_string) : []
125
98
 
126
99
  options = {
127
100
  :val => val,
101
+ :arg_string => arg_string,
128
102
  :eval_string => eval_string,
129
103
  :nesting => nesting,
130
- :commands => commands.commands
104
+ :commands => commands.commands,
105
+ :captures => captures
131
106
  }
132
107
 
133
- execute_command(target, command.name, options, *args)
108
+ execute_command(target, command.name, options, *(captures + args))
134
109
  end
135
110
 
136
111
  # Execute a Pry command.
@@ -146,6 +121,9 @@ class Pry
146
121
  context.opts = options
147
122
  context.target = target
148
123
  context.output = output
124
+ context.captures = options[:captures]
125
+ context.eval_string = options[:eval_string]
126
+ context.arg_string = options[:arg_string]
149
127
  context.command_set = commands
150
128
 
151
129
  context.command_processor = self
@@ -153,7 +131,7 @@ class Pry
153
131
  ret = commands.run_command(context, command, *args)
154
132
 
155
133
  # Tick, tock, im getting rid of this shit soon.
156
- options[:val].clear
134
+ options[:val].replace("")
157
135
 
158
136
  ret
159
137
  end
@@ -5,7 +5,7 @@ class Pry
5
5
  end
6
6
  end
7
7
 
8
- # This class used to create sets of commands. Commands can be impoted from
8
+ # This class is used to create sets of commands. Commands can be imported from
9
9
  # different sets, aliased, removed, etc.
10
10
  class CommandSet
11
11
  class Command < Struct.new(:name, :description, :options, :block)
@@ -26,23 +26,21 @@ class Pry
26
26
  args
27
27
  when 1, 0
28
28
  # Keep 1.8 happy
29
- args.values_at *0..(arity - 1)
29
+ args.values_at 0..(arity - 1)
30
30
  end
31
31
  end
32
32
  end
33
33
 
34
+ include Enumerable
34
35
  include Pry::Helpers::BaseHelpers
35
36
 
36
37
  attr_reader :commands
37
- attr_reader :name
38
38
  attr_reader :helper_module
39
39
 
40
- # @param [Symbol] name Name of the command set
41
40
  # @param [Array<CommandSet>] imported_sets Sets which will be imported
42
41
  # automatically
43
42
  # @yield Optional block run to define commands
44
- def initialize(name, *imported_sets, &block)
45
- @name = name
43
+ def initialize(*imported_sets, &block)
46
44
  @commands = {}
47
45
  @helper_module = Module.new
48
46
 
@@ -53,19 +51,29 @@ class Pry
53
51
  end
54
52
 
55
53
  # Defines a new Pry command.
56
- # @param [String, Array] names The name of the command (or array of
57
- # command name aliases).
54
+ # @param [String, Regexp] name The name of the command. Can be
55
+ # Regexp as well as String.
58
56
  # @param [String] description A description of the command.
59
57
  # @param [Hash] options The optional configuration parameters.
60
58
  # @option options [Boolean] :keep_retval Whether or not to use return value
61
59
  # of the block for return of `command` or just to return `nil`
62
60
  # (the default).
61
+ # @option options [Array<String>] :requires_gem Whether the command has
62
+ # any gem dependencies, if it does and dependencies not met then
63
+ # command is disabled and a stub proc giving instructions to
64
+ # install command is provided.
65
+ # @option options [Boolean] :interpolate Whether string #{} based
66
+ # interpolation is applied to the command arguments before
67
+ # executing the command. Defaults to true.
68
+ # @option options [String] :listing The listing name of the
69
+ # command. That is the name by which the command is looked up by
70
+ # help and by show-command. Necessary for regex based commands.
63
71
  # @yield The action to perform. The parameters in the block
64
72
  # determines the parameters the command will receive. All
65
73
  # parameters passed into the block will be strings. Successive
66
74
  # command parameters are separated by whitespace at the Pry prompt.
67
75
  # @example
68
- # MyCommands = Pry::CommandSet.new :mine do
76
+ # MyCommands = Pry::CommandSet.new do
69
77
  # command "greet", "Greet somebody" do |name|
70
78
  # puts "Good afternoon #{name.capitalize}!"
71
79
  # end
@@ -77,25 +85,45 @@ class Pry
77
85
  # # Good afternoon John!
78
86
  # # pry(main)> help greet
79
87
  # # Greet somebody
80
- def command(names, description="No description.", options={}, &block)
81
- first_name = Array(names).first
88
+ # @example Regexp command
89
+ # MyCommands = Pry::CommandSet.new do
90
+ # command /number-(\d+)/, "number-N regex command", :listing => "number" do |num, name|
91
+ # puts "hello #{name}, nice number: #{num}"
92
+ # end
93
+ # end
94
+ #
95
+ # # From pry:
96
+ # # pry(main)> _pry_.commands = MyCommands
97
+ # # pry(main)> number-10 john
98
+ # # hello john, nice number: 10
99
+ # # pry(main)> help number
100
+ # # number-N regex command
101
+ def command(name, description="No description.", options={}, &block)
82
102
 
83
- options = {:requires_gem => []}.merge(options)
103
+ options = {
104
+ :requires_gem => [],
105
+ :keep_retval => false,
106
+ :argument_required => false,
107
+ :interpolate => true,
108
+ :listing => name
109
+ }.merge!(options)
84
110
 
85
111
  unless command_dependencies_met? options
86
112
  gems_needed = Array(options[:requires_gem])
87
113
  gems_not_installed = gems_needed.select { |g| !gem_installed?(g) }
88
114
 
89
115
  options[:stub_info] = proc do
90
- output.puts "\n#{first_name} requires the following gems to be installed: #{(gems_needed.join(", "))}"
91
- output.puts "Command not available due to dependency on gems: `#{gems_not_installed.join(", ")}` not being met."
92
- output.puts "Type `install #{first_name}` to install the required gems and activate this command."
116
+ output.puts "\nThe command '#{name}' is #{Helpers::Text.bold("unavailable")} because it requires the following gems to be installed: #{(gems_not_installed.join(", "))}"
117
+ output.puts "-"
118
+ output.puts "Type `install #{name}` to install the required gems and activate this command."
93
119
  end
94
120
  end
95
121
 
96
- Array(names).each do |name|
97
- commands[name] = Command.new(name, description, options, block)
98
- end
122
+ commands[name] = Command.new(name, description, options, block)
123
+ end
124
+
125
+ def each &block
126
+ @commands.each(&block)
99
127
  end
100
128
 
101
129
  # Removes some commands from the set
@@ -125,7 +153,7 @@ class Pry
125
153
  # Aliases a command
126
154
  # @param [String] new_name New name of the command.
127
155
  # @param [String] old_name Old name of the command.
128
- # @pasam [String, nil] desc New description of the command.
156
+ # @param [String, nil] desc New description of the command.
129
157
  def alias_command(new_name, old_name, desc = nil)
130
158
  commands[new_name] = commands[old_name].dup
131
159
  commands[new_name].name = new_name
@@ -140,12 +168,17 @@ class Pry
140
168
  # @raise [NoCommandError] If the command is not defined in this set
141
169
  def run_command(context, name, *args)
142
170
  context.extend helper_module
171
+ command = commands[name]
143
172
 
144
- if command = commands[name]
145
- command.call(context, *args)
146
- else
173
+ if command.nil?
147
174
  raise NoCommandError.new(name, self)
148
175
  end
176
+
177
+ if command.options[:argument_required] && args.empty?
178
+ puts "The command '#{command.name}' requires an argument."
179
+ else
180
+ command.call context, *args
181
+ end
149
182
  end
150
183
 
151
184
  # Sets the description for a command (replacing the old
@@ -153,7 +186,7 @@ class Pry
153
186
  # @param [String] name The command name.
154
187
  # @param [String] description The command description.
155
188
  # @example
156
- # MyCommands = Pry::CommandSet.new :test do
189
+ # MyCommands = Pry::CommandSet.new do
157
190
  # desc "help", "help description"
158
191
  # end
159
192
  def desc(name, description)
@@ -176,8 +209,15 @@ class Pry
176
209
  helper_module.class_eval(&block)
177
210
  end
178
211
 
212
+
213
+ # @return [Array] The list of commands provided by the command set.
214
+ def list_commands
215
+ commands.keys
216
+ end
217
+
179
218
  private
180
219
  def define_default_commands
220
+
181
221
  command "help", "This menu." do |cmd|
182
222
  if !cmd
183
223
  output.puts
@@ -185,13 +225,13 @@ class Pry
185
225
 
186
226
  commands.each do |key, command|
187
227
  if command.description && !command.description.empty?
188
- help_text << "#{key}".ljust(18) + command.description + "\n"
228
+ help_text << "#{command.options[:listing]}".ljust(18) + command.description + "\n"
189
229
  end
190
230
  end
191
231
 
192
232
  stagger_output(help_text)
193
233
  else
194
- if command = commands[cmd]
234
+ if command = find_command(cmd)
195
235
  output.puts command.description
196
236
  else
197
237
  output.puts "No info for command: #{cmd}"
@@ -200,7 +240,8 @@ class Pry
200
240
  end
201
241
 
202
242
  command "install", "Install a disabled command." do |name|
203
- stub_info = commands[name].options[:stub_info]
243
+ command = find_command(name)
244
+ stub_info = command.options[:stub_info]
204
245
 
205
246
  if !stub_info
206
247
  output.puts "Not a command stub. Nothing to do."
@@ -208,7 +249,7 @@ class Pry
208
249
  end
209
250
 
210
251
  output.puts "Attempting to install `#{name}` command..."
211
- gems_to_install = Array(commands[name].options[:requires_gem])
252
+ gems_to_install = Array(command.options[:requires_gem])
212
253
 
213
254
  gem_install_failed = false
214
255
  gems_to_install.each do |g|
@@ -226,7 +267,17 @@ class Pry
226
267
  next if gem_install_failed
227
268
 
228
269
  Gem.refresh
229
- commands[name].options.delete :stub_info
270
+ gems_to_install.each do |g|
271
+ begin
272
+ require g
273
+ rescue LoadError
274
+ output.puts "Required Gem: `#{g}` installed but not found?!. Aborting command installation."
275
+ gem_install_failed = true
276
+ end
277
+ end
278
+ next if gem_install_failed
279
+
280
+ command.options.delete :stub_info
230
281
  output.puts "Installation of `#{name}` successful! Type `help #{name}` for information"
231
282
  end
232
283
  end