diff --git a/lib/pry/commands.rb~ b/lib/pry/commands.rb~ new file mode 100644 index 00000000..b9867217 --- /dev/null +++ b/lib/pry/commands.rb~ @@ -0,0 +1,30 @@ +require "pry/default_commands/misc" +require "pry/default_commands/help" +require "pry/default_commands/gems" +require "pry/default_commands/context" +require "pry/default_commands/commands" +require "pry/default_commands/input_and_output" +require "pry/default_commands/introspection" +require "pry/default_commands/editing" +require "pry/default_commands/navigating_pry" +require "pry/default_commands/easter_eggs" +require "pry/default_commands/find_method" + +require "pry/extended_commands/experimental" + +class Pry + + # Default commands used by Pry. + Commands = Pry::CommandSet.new do + import DefaultCommands::Misc + import DefaultCommands::Help + import DefaultCommands::Gems + import DefaultCommands::Context + import DefaultCommands::NavigatingPry + import DefaultCommands::Editing + import DefaultCommands::InputAndOutput + import DefaultCommands::Introspection + import DefaultCommands::EasterEggs + import DefaultCommands::Commands + end +end diff --git a/lib/pry/default_commands/context.rb b/lib/pry/default_commands/context.rb index c0915e6c..e994ca9f 100644 --- a/lib/pry/default_commands/context.rb +++ b/lib/pry/default_commands/context.rb @@ -1,5 +1,6 @@ require "pry/default_commands/ls" require "pry/default_commands/cd" +require "pry/default_commands/find_method" class Pry module DefaultCommands @@ -7,6 +8,7 @@ class Pry Context = Pry::CommandSet.new do import Ls import Cd + import FindMethod command "whereami", "Show the code context for the session. (whereami shows extra lines of code around the invocation line. Default: 5)" do |num| file, line_num = file_and_line_from_binding(target) diff --git a/lib/pry/default_commands/context.rb~ b/lib/pry/default_commands/context.rb~ new file mode 100644 index 00000000..e994ca9f --- /dev/null +++ b/lib/pry/default_commands/context.rb~ @@ -0,0 +1,115 @@ +require "pry/default_commands/ls" +require "pry/default_commands/cd" +require "pry/default_commands/find_method" + +class Pry + module DefaultCommands + + Context = Pry::CommandSet.new do + import Ls + import Cd + import FindMethod + + command "whereami", "Show the code context for the session. (whereami shows extra lines of code around the invocation line. Default: 5)" do |num| + file, line_num = file_and_line_from_binding(target) + i_num = num ? num.to_i : 5 + + if file != Pry.eval_path && (file =~ /(\(.*\))|<.*>/ || file == "" || file == "-e") + raise CommandError, "Cannot find local context. Did you use binding.pry?" + end + + set_file_and_dir_locals(file) + + method = Pry::Method.from_binding(target) + method_description = method ? " in #{method.name_with_owner}" : "" + output.puts "\n#{text.bold('From:')} #{file} @ line #{line_num}#{method_description}:\n\n" + + code = Pry::Code.from_file(file).around(line_num, i_num) + output.puts code.with_line_numbers.with_marker(line_num) + output.puts + end + + create_command "pry-backtrace", "Show the backtrace for the Pry session." do + banner <<-BANNER + Usage: pry-backtrace [OPTIONS] [--help] + + Show the backtrace for the position in the code where Pry was started. This can be used to + infer the behavior of the program immediately before it entered Pry, just like the backtrace + property of an exception. + + (NOTE: if you are looking for the backtrace of the most recent exception raised, + just type: `_ex_.backtrace` instead, see https://github.com/pry/pry/wiki/Special-Locals) + + e.g: pry-backtrace + BANNER + + def process + output.puts "\n#{text.bold('Backtrace:')}\n--\n" + stagger_output _pry_.backtrace.join("\n") + end + end + + command "reset", "Reset the REPL to a clean state." do + output.puts "Pry reset." + exec "pry" + end + + create_command /wtf([?!]*)/, "Show the backtrace of the most recent exception" do + options :listing => 'wtf?' + + banner <<-BANNER + Show's a few lines of the backtrace of the most recent exception (also available + as _ex_.backtrace). + + If you want to see more lines, add more question marks or exclamation marks: + + e.g. + pry(main)> wtf? + pry(main)> wtf?!???!?!? + + To see the entire backtrace, pass the -v/--verbose flag: + + e.g. + pry(main)> wtf -v + BANNER + + def options(opt) + opt.on(:v, :verbose, "Show the full backtrace.") + end + + def process + raise Pry::CommandError, "No most-recent exception" unless _pry_.last_exception + + output.puts "#{text.bold('Exception:')} #{_pry_.last_exception.class}: #{_pry_.last_exception}\n--" + if opts.verbose? + output.puts Code.new(_pry_.last_exception.backtrace, 0, :text).with_line_numbers.to_s + else + output.puts Code.new(_pry_.last_exception.backtrace.first([captures[0].size, 0.5].max * 10), 0, :text).with_line_numbers.to_s + end + end + end + + # N.B. using a regular expresion here so that "raise-up 'foo'" does the right thing. + create_command /raise-up(!?\b.*)/, :listing => 'raise-up' do + description "Raise an exception out of the current pry instance." + banner <<-BANNER + Raise up, like exit, allows you to quit pry. Instead of returning a value however, it raises an exception. + If you don't provide the exception to be raised, it will use the most recent exception (in pry _ex_). + + e.g. `raise-up "get-me-out-of-here"` is equivalent to: + `raise "get-me-out-of-here" + raise-up` + + When called as raise-up! (with an exclamation mark), this command raises the exception through + any nested prys you have created by "cd"ing into objects. + BANNER + + def process + return stagger_output help if captures[0] =~ /(-h|--help)\b/ + # Handle 'raise-up', 'raise-up "foo"', 'raise-up RuntimeError, 'farble' in a rubyesque manner + target.eval("_pry_.raise_up#{captures[0]}") + end + end + end + end +end diff --git a/lib/pry/default_commands/find_method.rb b/lib/pry/default_commands/find_method.rb new file mode 100644 index 00000000..10812d75 --- /dev/null +++ b/lib/pry/default_commands/find_method.rb @@ -0,0 +1,112 @@ +class Pry + module DefaultCommands + FindMethod = Pry::CommandSet.new do + + + create_command "find-method" do + + group "Context" + + description "Recursively search for a method within a Class/Module or the current namespace. find-method [-n | -c] METHOD [NAMESPACE]" + + def options(opti) + opti.on :n, :name, "Search for a method by name" + opti.on :c, :content, "Search for a method based on content in Regex form" + end + + def process + return if args.size < 1 + pattern = ::Regexp.new args[0] + if args[1] + if args[1].is_a?(Module) + klass = args[1] + else + klass = args[1].class + end + else + to_put = target_self_eval(pattern, opts) + if to_put.flatten == [] + puts "\e[31;1mNo Methods Found\e[0m" + else + puts "\e[32;1;4mMethods Found\e[0m" + puts to_put + end + return + end + if opts.name? + to_put = name_search(pattern, klass) + elsif opts.content? + to_put = content_search(pattern, klass) + else + to_put = name_search(pattern, klass) + end + + if to_put.flatten == [] + puts "\e[31;1mNo Methods Found\e[0m" + else + puts "\e[1;4;32mMethods Found\e[0m" + puts to_put + end + + end + + private + + def puts(item) + output.puts item + end + + def target_self_eval(pattern, opts) + obj = target_self + if opts.name? + return (obj.methods.select {|x| x=~pattern}).map {|x| "(#{obj.to_s})##{x}" } + elsif opts.content? + ret = [] + obj.methods.select do |x| + meth = Pry::Method.new obj.method(x) + if meth.source =~ pattern + ret << "(#{obj.to_s})##{x}: " + (meth.source.split(/\n/).select {|x| x =~ pattern }).join("\n\t") + end + end + return ret + else + return (obj.methods.select {|x| x=~pattern}).map {|x| "(#{obj.to_s})##{x}" } + end + end + + def content_search(pattern, klass, current=[]) + return unless(klass.is_a? Module) + return if current.include? klass + current << klass + meths = [] + (Pry::Method.all_from_class(klass) + Pry::Method.all_from_obj(klass)).uniq.each do |meth| + begin + if meth.source =~ pattern && !meth.alias? + meths << "#{klass}##{meth.name}: " + (meth.source.split(/\n/).select {|x| x =~ pattern }).join("\n\t") + end + rescue Exception + next + end + end + klass.constants.each do |klazz| + meths += ((res = content_search(pattern, klass.const_get(klazz), current)) ? res : []) + end + return meths.flatten + end + + def name_search(regex, klass, current=[]) + return unless(klass.is_a? Module) + return if current.include? klass + current << klass + meths = [] + (Pry::Method.all_from_class(klass) + Pry::Method.all_from_obj(klass)).uniq.each {|x| meths << "#{klass}##{x.name}" if x.name =~ regex } + klass.constants.each do |x| + meths += ((res = name_search(regex, klass.const_get(x), current)) ? res : []) + end + return meths.flatten + end + + end + end + end +end \ No newline at end of file diff --git a/lib/pry/default_commands/find_method.rb~ b/lib/pry/default_commands/find_method.rb~ new file mode 100644 index 00000000..10812d75 --- /dev/null +++ b/lib/pry/default_commands/find_method.rb~ @@ -0,0 +1,112 @@ +class Pry + module DefaultCommands + FindMethod = Pry::CommandSet.new do + + + create_command "find-method" do + + group "Context" + + description "Recursively search for a method within a Class/Module or the current namespace. find-method [-n | -c] METHOD [NAMESPACE]" + + def options(opti) + opti.on :n, :name, "Search for a method by name" + opti.on :c, :content, "Search for a method based on content in Regex form" + end + + def process + return if args.size < 1 + pattern = ::Regexp.new args[0] + if args[1] + if args[1].is_a?(Module) + klass = args[1] + else + klass = args[1].class + end + else + to_put = target_self_eval(pattern, opts) + if to_put.flatten == [] + puts "\e[31;1mNo Methods Found\e[0m" + else + puts "\e[32;1;4mMethods Found\e[0m" + puts to_put + end + return + end + if opts.name? + to_put = name_search(pattern, klass) + elsif opts.content? + to_put = content_search(pattern, klass) + else + to_put = name_search(pattern, klass) + end + + if to_put.flatten == [] + puts "\e[31;1mNo Methods Found\e[0m" + else + puts "\e[1;4;32mMethods Found\e[0m" + puts to_put + end + + end + + private + + def puts(item) + output.puts item + end + + def target_self_eval(pattern, opts) + obj = target_self + if opts.name? + return (obj.methods.select {|x| x=~pattern}).map {|x| "(#{obj.to_s})##{x}" } + elsif opts.content? + ret = [] + obj.methods.select do |x| + meth = Pry::Method.new obj.method(x) + if meth.source =~ pattern + ret << "(#{obj.to_s})##{x}: " + (meth.source.split(/\n/).select {|x| x =~ pattern }).join("\n\t") + end + end + return ret + else + return (obj.methods.select {|x| x=~pattern}).map {|x| "(#{obj.to_s})##{x}" } + end + end + + def content_search(pattern, klass, current=[]) + return unless(klass.is_a? Module) + return if current.include? klass + current << klass + meths = [] + (Pry::Method.all_from_class(klass) + Pry::Method.all_from_obj(klass)).uniq.each do |meth| + begin + if meth.source =~ pattern && !meth.alias? + meths << "#{klass}##{meth.name}: " + (meth.source.split(/\n/).select {|x| x =~ pattern }).join("\n\t") + end + rescue Exception + next + end + end + klass.constants.each do |klazz| + meths += ((res = content_search(pattern, klass.const_get(klazz), current)) ? res : []) + end + return meths.flatten + end + + def name_search(regex, klass, current=[]) + return unless(klass.is_a? Module) + return if current.include? klass + current << klass + meths = [] + (Pry::Method.all_from_class(klass) + Pry::Method.all_from_obj(klass)).uniq.each {|x| meths << "#{klass}##{x.name}" if x.name =~ regex } + klass.constants.each do |x| + meths += ((res = name_search(regex, klass.const_get(x), current)) ? res : []) + end + return meths.flatten + end + + end + end + end +end \ No newline at end of file