diff --git a/README.markdown b/README.markdown index 55000c65..f8bcfd0f 100644 --- a/README.markdown +++ b/README.markdown @@ -11,6 +11,7 @@ these include: * Source code browsing (including core C source with the pry-doc gem) * Documentation browsing * Live help system +* Open methods in editors (`edit-method Class#method`) * Syntax highlighting * Command shell integration (start editors, run git, and rake from within Pry) * Gist integration @@ -126,16 +127,16 @@ code: # test.rb require 'pry' - + class A def hello() puts "hello world!" end end - + a = A.new - + # start a REPL session binding.pry - + # program resumes here (after pry session) puts "program resumes here." @@ -169,8 +170,8 @@ using the normal `#{}` string interpolation syntax. In the code below we're going to switch to `shell-mode` and edit the `.pryrc` file in the home directory. We'll then cat its contents and reload the file. - - pry(main)> shell-mode + + pry(main)> shell-mode pry main:/home/john/ruby/projects/pry $ .cd ~ pry main:/home/john $ .emacsclient .pryrc pry main:/home/john $ .cat .pryrc @@ -179,7 +180,7 @@ reload the file. end pry main:/home/john $ load ".pryrc" => true - pry main:/home/john $ hello_world + pry main:/home/john $ hello_world hello world! We can also interpolate Ruby code into the shell. In the @@ -189,7 +190,7 @@ current directory and count the number of lines in that file with pry main:/home/john $ .cat #{Dir['*.*'].sample} | wc -l 44 - + ### Code Browsing #### show-method @@ -206,37 +207,37 @@ include line numbers in the output. In the following example we will enter the `Pry` class, list the instance methods beginning with 're' and display the source code for the `rep` method: - + pry(main)> cd Pry pry(Pry):1> ls -M --grep ^re [:re, :readline, :rep, :repl, :repl_epilogue, :repl_prologue, :retrieve_line] pry(Pry):1> show-method rep -l - + From: /home/john/ruby/projects/pry/lib/pry/pry_instance.rb @ line 143: Number of lines: 6 - + 143: def rep(target=TOPLEVEL_BINDING) 144: target = Pry.binding_for(target) 145: result = re(target) - 146: + 146: 147: show_result(result) if should_print? 148: end Note that we can also view C methods (from Ruby Core) using the `pry-doc` gem; we also show off the alternate syntax for `show-method`: - + pry(main)> show-method Array#select - + From: array.c in Ruby Core (C Method): Number of lines: 15 - + static VALUE rb_ary_select(VALUE ary) { VALUE result; long i; - + RETURN_ENUMERATOR(ary, 0, 0); result = rb_ary_new2(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { @@ -259,14 +260,14 @@ commands to do such things as change directory into the directory containing the file, open the file in an editor, display the file using `cat`, and so on. In the following example we wil use Pry to fix a bug in a method: - + pry(main)> greet "john" hello johnhow are you?=> nil pry(main)> show-method greet - + From: /Users/john/ruby/play/bug.rb @ line 2: Number of lines: 4 - + def greet(name) print "hello #{name}" print "how are you?" @@ -278,10 +279,10 @@ In the following example we wil use Pry to fix a bug in a method: how are you? => nil pry(main)> show-method greet - + From: /Users/john/ruby/play/bug.rb @ line 2: Number of lines: 4 - + def greet(name) puts "hello #{name}" puts "how are you?" @@ -317,10 +318,10 @@ documentation for the `try_activate` method: pry(main)> cd Gem pry(Gem):1> show-doc try_activate - + From: /Users/john/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/site_ruby/1.9.1/rubygems.rb @ line 201: Number of lines: 3 - + Try to activate a gem containing path. Returns true if activation succeeded or wasn't needed because it was already activated. Returns false if it can't find the path in a gem. @@ -334,14 +335,14 @@ We can also use `ri` in the normal way: ------------------------------------------------------------------------ Calls _block_ once for each element in _self_, passing that element as a parameter. - + a = [ "a", "b", "c" ] a.each {|x| print x, " -- " } - + produces: - + a -- b -- c -- - + ### History @@ -353,7 +354,7 @@ history can be replayed. In the example below we will enter a few lines in a Pry session and then view history; we will then replay one of those lines: - + pry(main)> hist 0: hist -h 1: ls @@ -362,10 +363,10 @@ then view history; we will then replay one of those lines: 4: x = rand 5: hist pry(main)> hist --replay 3 - + From: io.c in Ruby Core (C Method): Number of lines: 8 - + static VALUE rb_f_puts(int argc, VALUE *argv, VALUE recv) { @@ -374,7 +375,7 @@ then view history; we will then replay one of those lines: } return rb_funcall2(rb_stdout, rb_intern("puts"), argc, argv); } - + In the next example we will replay a range of lines in history. Note that we replay to a point where a class definition is still open and so we can continue to add instance methods to the class: @@ -397,7 +398,7 @@ we can continue to add instance methods to the class: pry(main)> Also note that in the above the line `Hello.new.goodbye_world;` ends -with a semi-colon which causes expression evaluation output to be suppressed. +with a semi-colon which causes expression evaluation output to be suppressed. ### Gist integration @@ -405,13 +406,31 @@ If the `gist` gem is installed then method source or documentation can be gisted `gist-method` command. The `gist-method` command accepts the same two syntaxes as `show-method`. In the example below we will gist the C source code for the `Symbol#to_proc` method to github: - + pry(main)> gist-method Symbol#to_proc https://gist.github.com/5332c38afc46d902ce46 - pry(main)> - -You can see the actual gist generated here: https://gist.github.com/5332c38afc46d902ce46 + pry(main)> +You can see the actual gist generated here: [https://gist.github.com/5332c38afc46d902ce46](https://gist.github.com/5332c38afc46d902ce46) + +### Edit methods + +You can use `edit-method Class#method` or `edit-method my_method` +(if the method is in scope) to open a method for editing directly in +your favorite editor. Pry has knowledge of a few different editors and +will attempt to open the file at the line the method is defined. + +You can set the editor to use by assigning to the `Pry.editor` +accessor. `Pry.editor` will default to `$EDITOR` or failing that will +use `nano` as the backup default. The file that is edited will be +automatically reloaded after exiting the editor - reloading can be +suppressed by passing the `--no-reload` option to `edit-method` + +In the example below we will set our default editor to "emacsclient" +and open the `Pry#repl` method for editing: + + pry(main)> Pry.editor = "emacsclient" + pry(main)> edit-method Pry#repl ### Live Help System @@ -422,6 +441,11 @@ help that can be accessed via typing `command_name --help`. A command will typically say in its description if the `--help` option is avaiable. +### Use Pry as your Rails 3 Console + +This is currently a hack, but follow the gist kindly provided by +MyArtChannel: [https://gist.github.com/941174](https://gist.github.com/941174) + ### Other Features and limitations @@ -471,7 +495,7 @@ invoke any of these methods directly depending on exactly what aspect of the fun limitation in JRuby's regex). * Tab completion is currently a bit broken/limited this will have a major overhaul in a future version. - + ### Syntax Highlighting Syntax highlighting is on by default in Pry. You can toggle it on and @@ -497,7 +521,7 @@ features, see the `examples/` directory. ### Customizing Pry -Pry allows a large degree of customization. +Pry allows a large degree of customization. [Read how to customize Pry here.](http://rdoc.info/github/banister/pry/master/file/wiki/Customizing-pry.md) diff --git a/Rakefile b/Rakefile index 9d4dd528..05aca9e9 100644 --- a/Rakefile +++ b/Rakefile @@ -90,7 +90,7 @@ end desc "build all platform gems at once" -task :gems => [:rmgems, "ruby:gem", "jruby:gem", "mswin32:gem", "mingw32:gem"] +task :gems => [:clean, :rmgems, "ruby:gem", "jruby:gem", "mswin32:gem", "mingw32:gem"] desc "remove all platform gems" task :rmgems => ["ruby:clobber_package"] diff --git a/lib/pry/command_helpers.rb b/lib/pry/command_helpers.rb index fba0618f..c5d383db 100644 --- a/lib/pry/command_helpers.rb +++ b/lib/pry/command_helpers.rb @@ -56,9 +56,28 @@ class Pry end end - def check_for_dynamically_defined_method(meth) + def editor_with_start_line(line_number) + case Pry.editor + when /^[gm]?vi/, /^emacs/, /^nano/, /^pico/, /^gedit/, /^kate/ + "#{Pry.editor} +#{line_number}" + when /^mate/ + "#{Pry.editor} -l#{line_number}" + else + if RUBY_PLATFORM =~ /mswin|mingw/ + Pry.editor + else + "#{Pry.editor} +#{line_number}" + end + end + end + + def is_a_dynamically_defined_method?(meth) file, _ = meth.source_location - if file =~ /(\(.*\))|<.*>/ + !!(file =~ /(\(.*\))|<.*>/) + end + + def check_for_dynamically_defined_method(meth) + if is_a_dynamically_defined_method?(meth) raise "Cannot retrieve source for dynamically defined method." end end diff --git a/lib/pry/commands.rb b/lib/pry/commands.rb index 287ec730..1aafb7bf 100644 --- a/lib/pry/commands.rb +++ b/lib/pry/commands.rb @@ -50,6 +50,57 @@ class Pry Pry.active_instance.input = StringIO.new(actions) end + command "edit-method", "Edit a method. Type `edit-method --help` for more info." do |*args| + target = target() + + opts = Slop.parse!(args) do |opts| + opts.banner %{Usage: edit-method [OPTIONS] [METH] +Edit the method METH in an editor. +Ensure #{bold("Pry.editor")} is set to your editor of choice. +e.g: edit-method hello_method +-- +} + opts.on :M, "instance-methods", "Operate on instance methods." + opts.on :m, :methods, "Operate on methods." + opts.on "no-reload", "Do not automatically reload the method's file after editting." + opts.on :c, :context, "Select object context to run under.", true do |context| + target = Pry.binding_for(target.eval(context)) + end + opts.on :h, :help, "This message." do + output.puts opts + end + end + + next if opts.help? + + meth_name = args.shift + if meth_name + if meth_name =~ /\A([^\.\#]+)[\.\#](.+)\z/ && !opts.context? + context, meth_name = $1, $2 + target = Pry.binding_for(target.eval(context)) + end + else + meth_name = meth_name_from_binding(target) + end + + if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil? + output.puts "Invalid method name: #{meth_name}." + next + end + + next output.puts "Error: No editor set!\nEnsure that #{bold("Pry.editor")} is set to your editor of choice." if !Pry.editor + + if is_a_c_method?(meth) + output.puts "Error: Can't edit a C method." + elsif is_a_dynamically_defined_method?(meth) + output.puts "Error: Can't edit an eval method." + else + file, line = meth.source_location + run ".#{editor_with_start_line(line)}", file + load file if !opts["no-reload"] + end + end + command "exit-program", "End the current program. Aliases: quit-program, !!!" do exit end diff --git a/lib/pry/pry_class.rb b/lib/pry/pry_class.rb index 052739d3..0876db2e 100644 --- a/lib/pry/pry_class.rb +++ b/lib/pry/pry_class.rb @@ -98,6 +98,11 @@ class Pry # Set to true if the pry-doc extension is loaded. # @return [Boolean] attr_accessor :has_pry_doc + + # The default editor to use. Defaults to $EDITOR or nano if + # $EDITOR is not defined. + # @return [String] + attr_accessor :editor end # Load the rc files given in the `Pry::RC_FILES` array. @@ -201,6 +206,14 @@ class Pry end end + def self.default_editor_for_platform + if RUBY_PLATFORM =~ /mswin|mingw/ + ENV['EDITOR'] ? ENV['EDITOR'] : "notepad" + else + ENV['EDITOR'] ? ENV['EDITOR'] : "nano" + end + end + # Set all the configurable options back to their default values def self.reset_defaults @input = Readline @@ -216,6 +229,7 @@ class Pry @should_load_rc = true @rc_loaded = false @cli = false + @editor = default_editor_for_platform end self.reset_defaults diff --git a/lib/pry/version.rb b/lib/pry/version.rb index 04a72e50..b3913cd9 100644 --- a/lib/pry/version.rb +++ b/lib/pry/version.rb @@ -1,3 +1,3 @@ class Pry - VERSION = "0.8.2" + VERSION = "0.8.3" end diff --git a/test/test.rb b/test/test.rb index ecaecede..fa4fd662 100644 --- a/test/test.rb +++ b/test/test.rb @@ -1,8 +1,10 @@ direc = File.dirname(__FILE__) +$LOAD_PATH.unshift "#{direc}/../lib" + require 'rubygems' require 'bacon' -require "#{direc}/../lib/pry" +require "pry" require "#{direc}/test_helper" puts "Ruby Version #{RUBY_VERSION}" @@ -73,7 +75,7 @@ describe Pry do pry_tester.rep(o) str_output.string.should == "" end - + it 'should suppress output if input ends in a ";" (multi-line)' do o = Object.new