require_relative'byebug.so'require_relative'byebug/version'require_relative'byebug/context'require_relative'byebug/processor'require_relative'byebug/remote'require'stringio'require'linecache19'moduleByebugself.handler=CommandProcessor.new# List of files byebug will ignore while debuggingIGNORED_FILES=Dir[Pathname.new(__FILE__)+"../**/*.rb"].map{|f|File.expand_path(f)}# Default options to Byebug.startDEFAULT_START_SETTINGS={init: true,# Set $0 and save ARGV?post_mortem: false,# post-mortem debugging on uncaught exception?tracing: nil# Byebug.tracing? value. true/false resets}unlessdefined?(DEFAULT_START_SETTINGS)# Configuration file used for startup commands. Default value is .byebugrcINITFILE='.byebugrc'unlessdefined?(INITFILE)class<<selfattr_accessor:last_exceptionByebug.last_exception=nildefsource_reloadObject.send(:remove_const,"SCRIPT_LINES__")ifObject.const_defined?("SCRIPT_LINES__")Object.const_set("SCRIPT_LINES__",{})LineCache::clear_file_cacheend## Get line +line_number+ from file named +filename+.## @return "\n" if there was a problem. Leaking blanks are stripped off.#defline_at(filename,line_number)@@autoreload=nilunlessdefined?(@@autoreload)line=LineCache::getlinefilename,line_number,@@autoreloadreturn"\n"unlesslinereturn"#{line.gsub(/^\s+/,'').chomp}"end## Add a new breakpoint## @param [String] file# @param [Fixnum] line# @param [String] expr#defadd_breakpoint(file,line,expr=nil)breakpoint=Breakpoint.new(file,line,expr)breakpoints<<breakpointbreakpointenddefremove_breakpoint(id)Breakpoint.removebreakpoints,idenddefinterface=(value)handler.interface=valueend## Byebug.start(options) -> bool# Byebug.start(options) { ... } -> obj## If it's called without a block, it returns +true+ unless byebug was# already started.## If a block is given, it starts byebug and yields block. After the block is# executed it stops byebug with Byebug.stop method. Inside the block you# will probably want to have a call to Byebug.byebug. For example:## Byebug.start { byebug; foo } # Stop inside of foo## Also, byebug only allows one invocation of byebug at a time; nested# Byebug.start's have no effect and you can't use this inside byebug itself.## <i>Note that if you want to stop byebug, you must call Byebug.stop as# many times as you called Byebug.start method.</i>## +options+ is a hash used to set various debugging options.# :init - true if you want to save ARGV and some other variables to# make a byebug restart possible. Only the first time :init# is set to true the values will get set. Since ARGV is# saved, you should make sure it hasn't been changed before# the (first) call.# :post_mortem - true if you want to enter post-mortem debugging on an# uncaught exception. Once post-mortem debugging is set, it# can't be unset.#defstart(options={},&block)options=Byebug::DEFAULT_START_SETTINGS.merge(options)ifoptions[:init]Byebug.const_set('ARGV',ARGV.clone)unlessdefined?Byebug::ARGVByebug.const_set('PROG_SCRIPT',$0)unlessdefined?Byebug::PROG_SCRIPTByebug.const_set('INITIAL_DIR',Dir.pwd)unlessdefined?Byebug::INITIAL_DIRendByebug.tracing=options[:tracing]unlessoptions[:tracing].nil?retval=Byebug._start(&block)post_mortemifoptions[:post_mortem]returnretvalend## Runs normal byebug initialization scripts.## Reads and executes the commands from init file (if any) in the current# working directory. This is only done if the current directory is# different from your home directory. Thus, you can have more than one init# file, one generic in your home directory, and another, specific to the# program you are debugging, in the directory where you invoke byebug.#defrun_init_script(out=handler.interface)cwd_script=File.expand_path(File.join(".",INITFILE))run_script(cwd_script,out)ifFile.exists?(cwd_script)home_script=File.expand_path(File.join(ENV['HOME'].to_s,INITFILE))ifFile.exists?(home_script)andcwd_script!=home_scriptrun_script(home_script,out)endend## Runs a script file#defrun_script(file,out=handler.interface,verbose=false)interface=ScriptInterface.new(File.expand_path(file),out)processor=ControlCommandProcessor.new(interface)processor.process_commands(verbose)end## Activates the post-mortem mode. There are two ways of using it:## == Global post-mortem mode# By calling Byebug.post_mortem method without a block, you install an# at_exit hook that intercepts any exception not handled by your script# and enables post-mortem mode.## == Local post-mortem mode## If you know that a particular block of code raises an exception you can# enable post-mortem mode by wrapping this block with Byebug.post_mortem,# e.g.## def offender# raise 'error'# end# Byebug.post_mortem do# ...# offender# ...# enddefpost_mortemifblock_given?old_post_mortem=self.post_mortem?beginself.post_mortem=trueyieldrescueException=>exphandle_post_mortem(exp)raiseensureself.post_mortem=old_post_mortemendelsereturnifself.post_mortem?self.post_mortem=truedebug_at_exitdohandle_post_mortem($!)ifpost_mortem?endendenddefhandle_post_mortem(exp)returnif!exp||!exp.__bb_context||exp.__bb_context.stack_size==0orig_tracing=Byebug.tracing?Byebug.tracing=falseByebug.last_exception=exphandler.at_line(exp.__bb_context,exp.__bb_file,exp.__bb_line)ensureByebug.tracing=orig_tracingendprivate:handle_post_mortemendendclassExceptionattr_reader:__bb_file,:__bb_line,:__bb_binding,:__bb_contextendmoduleKernel## Enters byebug after _steps_into_ line events and _steps_out_ return events# occur. Before entering byebug startup, the init script is read.#defbyebug(steps_into=1,steps_out=2)Byebug.startByebug.run_init_script(StringIO.new)ifByebug.current_context.stack_size>2Byebug.current_context.stop_returnsteps_outifsteps_out>=1endByebug.current_context.step_intosteps_intoifsteps_into>=0endend