pry 0.8.4pre1 → 0.9.0pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.gitignore +1 -0
  2. data/README.markdown +1 -1
  3. data/Rakefile +11 -5
  4. data/TODO +28 -2
  5. data/bin/pry +5 -9
  6. data/examples/example_basic.rb +2 -4
  7. data/examples/example_command_override.rb +2 -5
  8. data/examples/example_commands.rb +1 -4
  9. data/examples/example_hooks.rb +2 -5
  10. data/examples/example_image_edit.rb +4 -8
  11. data/examples/example_input.rb +1 -4
  12. data/examples/example_input2.rb +1 -4
  13. data/examples/example_output.rb +1 -4
  14. data/examples/example_print.rb +2 -5
  15. data/examples/example_prompt.rb +2 -5
  16. data/examples/helper.rb +6 -0
  17. data/lib/pry.rb +61 -4
  18. data/lib/pry/command_context.rb +10 -9
  19. data/lib/pry/command_processor.rb +29 -68
  20. data/lib/pry/command_set.rb +79 -28
  21. data/lib/pry/commands.rb +10 -121
  22. data/lib/pry/completion.rb +30 -29
  23. data/lib/pry/config.rb +93 -0
  24. data/lib/pry/default_commands/basic.rb +37 -0
  25. data/lib/pry/default_commands/context.rb +15 -15
  26. data/lib/pry/default_commands/documentation.rb +49 -48
  27. data/lib/pry/default_commands/easter_eggs.rb +1 -20
  28. data/lib/pry/default_commands/gems.rb +32 -41
  29. data/lib/pry/default_commands/input.rb +95 -19
  30. data/lib/pry/default_commands/introspection.rb +54 -60
  31. data/lib/pry/default_commands/ls.rb +2 -2
  32. data/lib/pry/default_commands/shell.rb +29 -39
  33. data/lib/pry/extended_commands/experimental.rb +48 -0
  34. data/lib/pry/extended_commands/user_command_api.rb +22 -0
  35. data/lib/pry/helpers.rb +1 -0
  36. data/lib/pry/helpers/base_helpers.rb +9 -106
  37. data/lib/pry/helpers/command_helpers.rb +96 -59
  38. data/lib/pry/helpers/text.rb +83 -0
  39. data/lib/pry/plugins.rb +79 -0
  40. data/lib/pry/pry_class.rb +96 -111
  41. data/lib/pry/pry_instance.rb +87 -55
  42. data/lib/pry/version.rb +1 -1
  43. data/test/helper.rb +56 -7
  44. data/test/test_command_processor.rb +99 -0
  45. data/test/{test_commandset.rb → test_command_set.rb} +18 -12
  46. data/test/test_default_commands.rb +59 -0
  47. data/test/test_default_commands/test_context.rb +64 -0
  48. data/test/test_default_commands/test_documentation.rb +31 -0
  49. data/test/test_default_commands/test_input.rb +157 -0
  50. data/test/test_default_commands/test_introspection.rb +146 -0
  51. data/test/test_pry.rb +430 -313
  52. metadata +25 -9
  53. data/lib/pry/hooks.rb +0 -17
  54. data/lib/pry/print.rb +0 -16
  55. data/lib/pry/prompts.rb +0 -31
@@ -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
@@ -1,3 +1,4 @@
1
+ require "pry/default_commands/basic"
1
2
  require "pry/default_commands/documentation"
2
3
  require "pry/default_commands/gems"
3
4
  require "pry/default_commands/context"
@@ -6,135 +7,23 @@ require "pry/default_commands/shell"
6
7
  require "pry/default_commands/introspection"
7
8
  require "pry/default_commands/easter_eggs"
8
9
 
10
+ require "pry/extended_commands/user_command_api"
11
+ require "pry/extended_commands/experimental"
12
+
9
13
  class Pry
10
14
 
11
15
  # Default commands used by Pry.
12
- Commands = Pry::CommandSet.new :default do
16
+ Commands = Pry::CommandSet.new do
17
+ import DefaultCommands::Basic
13
18
  import DefaultCommands::Documentation
14
19
  import DefaultCommands::Gems
15
20
  import DefaultCommands::Context
16
- import DefaultCommands::Input, DefaultCommands::Shell
21
+ import DefaultCommands::Input
22
+ import DefaultCommands::Shell
17
23
  import DefaultCommands::Introspection
18
24
  import DefaultCommands::EasterEggs
19
25
 
20
- Helpers::CommandHelpers.try_to_load_pry_doc
21
-
22
- command "toggle-color", "Toggle syntax highlighting." do
23
- Pry.color = !Pry.color
24
- output.puts "Syntax highlighting #{Pry.color ? "on" : "off"}"
25
- end
26
-
27
- command "simple-prompt", "Toggle the simple prompt." do
28
- case Pry.active_instance.prompt
29
- when Pry::SIMPLE_PROMPT
30
- Pry.active_instance.prompt = Pry::DEFAULT_PROMPT
31
- else
32
- Pry.active_instance.prompt = Pry::SIMPLE_PROMPT
33
- end
34
- end
35
-
36
- command "status", "Show status information." do
37
- nesting = opts[:nesting]
38
-
39
- output.puts "Status:"
40
- output.puts "--"
41
- output.puts "Receiver: #{Pry.view_clip(target.eval('self'))}"
42
- output.puts "Nesting level: #{nesting.level}"
43
- output.puts "Pry version: #{Pry::VERSION}"
44
- output.puts "Ruby version: #{RUBY_VERSION}"
45
-
46
- mn = meth_name_from_binding(target)
47
- output.puts "Current method: #{mn ? mn : "N/A"}"
48
- output.puts "Pry instance: #{Pry.active_instance}"
49
- output.puts "Last result: #{Pry.view(Pry.last_result)}"
50
- end
51
-
52
-
53
- command "req", "Requires gem(s). No need for quotes! (If the gem isn't installed, it will ask if you want to install it.)" do |*gems|
54
- gems = gems.join(' ').gsub(',', '').split(/\s+/)
55
- gems.each do |gem|
56
- begin
57
- if require gem
58
- output.puts "#{bright_yellow(gem)} loaded"
59
- else
60
- output.puts "#{bright_white(gem)} already loaded"
61
- end
62
-
63
- rescue LoadError => e
64
-
65
- if gem_installed? gem
66
- output.puts e.inspect
67
- else
68
- output.puts "#{bright_red(gem)} not found"
69
- if prompt("Install the gem?") == "y"
70
- run "gem-install", gem
71
- end
72
- end
73
-
74
- end # rescue
75
- end # gems.each
76
- end
77
-
78
- command "version", "Show Pry version." do
79
- output.puts "Pry version: #{Pry::VERSION} on Ruby #{RUBY_VERSION}."
80
- end
26
+ # Helpers::CommandHelpers.try_to_load_pry_doc
81
27
 
82
-
83
- command "lls", "List local files using 'ls'" do |*args|
84
- cmd = ".ls"
85
- run cmd, *args
86
- end
87
-
88
- command "lcd", "Change the current (working) directory" do |*args|
89
- run ".cd", *args
90
- end
91
-
92
-
93
- command "eval-file", "Eval a Ruby script. Type `eval-file --help` for more info." do |*args|
94
- options = {}
95
- target = target()
96
- file_name = nil
97
-
98
- OptionParser.new do |opts|
99
- opts.banner = %{Usage: eval-file [OPTIONS] FILE
100
- Eval a Ruby script at top-level or in the specified context. Defaults to top-level.
101
- e.g: eval-file -c self "hello.rb"
102
- --
103
- }
104
- opts.on("-c", "--context CONTEXT", "Eval the script in the specified context.") do |context|
105
- options[:c] = true
106
- target = Pry.binding_for(target.eval(context))
107
- end
108
-
109
- opts.on_tail("-h", "--help", "This message.") do
110
- output.puts opts
111
- options[:h] = true
112
- end
113
- end.order(args) do |v|
114
- file_name = v
115
- end
116
-
117
- next if options[:h]
118
-
119
- if !file_name
120
- output.puts "You need to specify a file name. Type `eval-file --help` for help"
121
- next
122
- end
123
-
124
- old_constants = Object.constants
125
- if options[:c]
126
- target_self = target.eval('self')
127
- target.eval(File.read(File.expand_path(file_name)))
128
- output.puts "--\nEval'd '#{file_name}' in the `#{target_self}` context."
129
- else
130
- TOPLEVEL_BINDING.eval(File.read(File.expand_path(file_name)))
131
- output.puts "--\nEval'd '#{file_name}' at top-level."
132
- end
133
- set_file_and_dir_locals(file_name)
134
-
135
- new_constants = Object.constants - old_constants
136
- output.puts "Brought in the following top-level constants: #{new_constants.inspect}" if !new_constants.empty?
137
- end
138
-
139
- end
28
+ end
140
29
  end
@@ -14,28 +14,29 @@ class Pry
14
14
  Readline.completion_append_character = nil
15
15
 
16
16
  ReservedWords = [
17
- "BEGIN", "END",
18
- "alias", "and",
19
- "begin", "break",
20
- "case", "class",
21
- "def", "defined", "do",
22
- "else", "elsif", "end", "ensure",
23
- "false", "for",
24
- "if", "in",
25
- "module",
26
- "next", "nil", "not",
27
- "or",
28
- "redo", "rescue", "retry", "return",
29
- "self", "super",
30
- "then", "true",
31
- "undef", "unless", "until",
32
- "when", "while",
33
- "yield",
34
- ]
35
-
36
- Operators = ["%", "&", "*", "**", "+", "-", "/",
37
- "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
38
- "[]", "[]=", "^", "!", "!=", "!~"]
17
+ "BEGIN", "END",
18
+ "alias", "and",
19
+ "begin", "break",
20
+ "case", "class",
21
+ "def", "defined", "do",
22
+ "else", "elsif", "end", "ensure",
23
+ "false", "for",
24
+ "if", "in",
25
+ "module",
26
+ "next", "nil", "not",
27
+ "or",
28
+ "redo", "rescue", "retry", "return",
29
+ "self", "super",
30
+ "then", "true",
31
+ "undef", "unless", "until",
32
+ "when", "while",
33
+ "yield" ]
34
+
35
+ Operators = [
36
+ "%", "&", "*", "**", "+", "-", "/",
37
+ "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
38
+ "[]", "[]=", "^", "!", "!=", "!~"
39
+ ]
39
40
 
40
41
  # Return a new completion proc for use by Readline.
41
42
  # @param [Binding] target The current binding context.
@@ -188,13 +189,13 @@ class Pry
188
189
 
189
190
  def self.select_message(receiver, message, candidates)
190
191
  candidates.grep(/^#{message}/).collect do |e|
191
- case e
192
- when /^[a-zA-Z_]/
193
- receiver + "." + e
194
- when /^[0-9]/
195
- when *Operators
196
- #receiver + " " + e
197
- end
192
+ case e
193
+ when /^[a-zA-Z_]/
194
+ receiver + "." + e
195
+ when /^[0-9]/
196
+ when *Operators
197
+ #receiver + " " + e
198
+ end
198
199
  end
199
200
  end
200
201
  end
@@ -0,0 +1,93 @@
1
+ require 'ostruct'
2
+
3
+ class Pry
4
+ class Config < OpenStruct
5
+
6
+ # Get/Set the object to use for input by default by all Pry instances.
7
+ # @return [#readline] The object to use for input by default by all
8
+ # Pry instances.
9
+ attr_accessor :input
10
+
11
+ # Get/Set the object to use for output by default by all Pry instances.
12
+ # @return [#puts] The object to use for output by default by all
13
+ # Pry instances.
14
+ attr_accessor :output
15
+
16
+ # Get/Set the object to use for commands by default by all Pry instances.
17
+ # @return [Pry::CommandBase] The object to use for commands by default by all
18
+ # Pry instances.
19
+ attr_accessor :commands
20
+
21
+ # Get/Set the Proc to use for printing by default by all Pry
22
+ # instances.
23
+ # This is the 'print' component of the REPL.
24
+ # @return [Proc] The Proc to use for printing by default by all
25
+ # Pry instances.
26
+ attr_accessor :print
27
+
28
+ # @return [Proc] The Proc to use for printing exceptions by default by all
29
+ # Pry instances.
30
+ attr_accessor :exception_handler
31
+
32
+ # Get/Set the Hash that defines Pry hooks used by default by all Pry
33
+ # instances.
34
+ # @return [Hash] The hooks used by default by all Pry instances.
35
+ # @example
36
+ # Pry.hooks :before_session => proc { puts "hello" },
37
+ # :after_session => proc { puts "goodbye" }
38
+ attr_accessor :hooks
39
+
40
+ # Get the array of Procs to be used for the prompts by default by
41
+ # all Pry instances.
42
+ # @return [Array<Proc>] The array of Procs to be used for the
43
+ # prompts by default by all Pry instances.
44
+ attr_accessor :prompt
45
+
46
+ # The default editor to use. Defaults to $EDITOR or nano if
47
+ # $EDITOR is not defined.
48
+ # If `editor` is a String then that string is used as the shell
49
+ # command to invoke the editor. If `editor` is callable (e.g a
50
+ # Proc) then `file` and `line` are passed in as parameters and the
51
+ # return value of that callable invocation is used as the exact
52
+ # shell command to invoke the editor.
53
+ # @example String
54
+ # Pry.editor = "emacsclient"
55
+ # @example Callable
56
+ # Pry.editor = proc { |file, line| "emacsclient #{file} +#{line}" }
57
+ # @return [String, #call]
58
+ attr_accessor :editor
59
+
60
+ # @return [Boolean] Toggle Pry color on and off.
61
+ attr_accessor :color
62
+
63
+ # @return [Boolean] Toggle paging on and off.
64
+ attr_accessor :pager
65
+
66
+ # Determines whether the rc file (~/.pryrc) should be loaded.
67
+ # @return [Boolean]
68
+ attr_accessor :should_load_rc
69
+
70
+ # Determines whether plugins should be loaded.
71
+ # @return [Boolean]
72
+ attr_accessor :should_load_plugins
73
+
74
+ # Config option for history.
75
+ # sub-options include hist.file, hist.load, and hist.save
76
+ # hist.file is the file to save/load history too, e.g
77
+ # Pry.config.history.file = "~/.pry_history".
78
+ # hist.load is a boolean that determines whether history will be
79
+ # loaded from hist.file at session start.
80
+ # hist.save is a boolean that determines whether history will be
81
+ # saved to hist.file at session end.
82
+ # @return [OpenStruct]
83
+ attr_accessor :history
84
+
85
+ # Config option for plugins:
86
+ # sub-options include:
87
+ # `plugins.enabled` (Boolean) to toggle the loading of plugins on and off wholesale. (defaults to true)
88
+ # `plugins.strict_loading` (Boolean) which toggles whether referring to a non-existent plugin should raise an exception (defaults to `false`)
89
+ # @return [OpenStruct]
90
+ attr_accessor :plugins
91
+ end
92
+ end
93
+