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

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