diff --git a/.gitignore b/.gitignore
index 413493d..c6a664f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,7 @@ ext/ruby_debug/ruby_debug.c
ext/ruby_debug/ruby_debug.h
Gemfile.lock
+
+.ruby-version
+.ruby-gemset
+
diff --git a/Guardfile b/Guardfile
new file mode 100644
index 0000000..96b19a7
--- /dev/null
+++ b/Guardfile
@@ -0,0 +1,9 @@
+# A sample Guardfile
+# More info at https://github.com/guard/guard#readme
+
+guard :minitest do
+ # with Minitest::Unit
+ watch(%r{^test/(.*)\/?(.*)_test\.rb})
+ watch(%r{^lib/(.*/)?([^/]+)\.rb}) { 'test' }
+ watch(%r{^test/test_helper\.rb}) { 'test' }
+end
diff --git a/README.md b/README.md
index 708f2e9..eb5b383 100644
--- a/README.md
+++ b/README.md
@@ -112,6 +112,8 @@ Please report them [on github](http://github.com/cldwalker/debugger/issues).
[See here](http://tagaholic.me/contributing.html) for contribution policies.
Let's keep this working for the ruby community!
+* After forking the repo, run `rake compile` before running `rake test`.
+
## Related projects
* [debugger-completion](https://github.com/cldwalker/debugger-completion) - autocompletion for
diff --git a/Rakefile b/Rakefile
index b742ed1..4730642 100644
--- a/Rakefile
+++ b/Rakefile
@@ -10,7 +10,7 @@ SO_NAME = "ruby_debug.so"
desc "Run new MiniTest tests."
task :test do
Rake::TestTask.new(:test) do |t|
- t.test_files = FileList["test/*_test.rb"]
+ t.test_files = FileList["test/**/*_test.rb"]
t.verbose = true
end
end
diff --git a/bin/rdebug b/bin/rdebug
index bd99d85..267908e 100755
--- a/bin/rdebug
+++ b/bin/rdebug
@@ -25,7 +25,7 @@
# --cport options
#
#--cport=port::
-# Use port port for access to debugger control.
+# Use port port for access to debugger control. Default 8990
#
#-d | --debug::
# Set $DEBUG true.
@@ -55,7 +55,7 @@
# Do not stop when script is loaded.
#
#-p | --port=PORT::
-# Host name used for remote debugging.
+# Host name used for remote debugging. Default 8989
#
#-r | --requirescript::
# Require the library, before executing your script.
@@ -105,6 +105,7 @@
require 'optparse'
require 'ostruct'
require 'debugger'
+require_relative '../lib/debugger/runner/rdebug_option_parser'
def debug_program(options)
# Make sure Ruby script syntax checks okay.
@@ -143,140 +144,6 @@ def whence_file(prog_script)
return prog_script
end
-options = OpenStruct.new(
- 'annotate' => Debugger.annotate,
- 'client' => false,
- 'control' => true,
- 'cport' => Debugger::PORT + 1,
- 'host' => nil,
- 'quit' => true,
- 'no_rewrite_program' => false,
- 'stop' => true,
- 'nx' => false,
- 'port' => Debugger::PORT,
- 'restart_script' => nil,
- 'script' => nil,
- 'server' => false,
- 'tracing' => false,
- 'verbose_long' => false,
- 'wait' => false
-)
-
-def process_options(options)
- program = File.basename($0)
- opts = OptionParser.new do |opts|
- opts.banner = < --
-EOB
- opts.separator ""
- opts.separator "Options:"
- opts.on("-A", "--annotate LEVEL", Integer, "Set annotation level") do
- |annotate|
- Debugger.annotate = annotate
- end
- opts.on("-c", "--client", "Connect to remote debugger") do
- options.client = true
- end
- opts.on("--cport PORT", Integer, "Port used for control commands") do
- |cport|
- options.cport = cport
- end
- opts.on("-d", "--debug", "Set $DEBUG=true") {$DEBUG = true}
- opts.on("--emacs LEVEL", Integer,
- "Activates full Emacs support at annotation level LEVEL") do
- |level|
- Debugger.annotate = level.to_i
- ENV['EMACS'] = '1'
- ENV['COLUMNS'] = '120' if ENV['COLUMNS'].to_i < 120
- options.control = false
- options.quit = false
- end
- opts.on('--emacs-basic', 'Activates basic Emacs mode') do
- ENV['EMACS'] = '1'
- end
- opts.on('-h', '--host HOST', 'Host name used for remote debugging') do
- |host|
- options.host = host
- end
- opts.on('-I', '--include PATH', String, 'Add PATH to $LOAD_PATH') do |path|
- $LOAD_PATH.unshift(path)
- end
- opts.on('--no-control', 'Do not automatically start control thread') do
- options.control = false
- end
- opts.on('--no-quit', 'Do not quit when script finishes') do
- options.quit = false
- end
- opts.on('--no-rewrite-program',
- 'Do not set $0 to the program being debugged') do
- options.no_rewrite_program = true
- end
- opts.on('--no-stop', 'Do not stop when script is loaded') do
- options.stop = false
- end
- opts.on('-nx', 'Not run debugger initialization files (e.g. .rdebugrc') do
- options.nx = true
- end
- opts.on('-p', '--port PORT', Integer, 'Port used for remote debugging') do
- |port|
- options.port = port
- end
- opts.on('-r', '--require SCRIPT', String,
- 'Require the library, before executing your script') do |name|
- if name == 'debug'
- puts "debugger is not compatible with Ruby's 'debug' library. This option is ignored."
- else
- require name
- end
- end
- opts.on('--restart-script FILE', String,
- 'Name of the script file to run. Erased after read') do
- |restart_script|
- options.restart_script = restart_script
- unless File.exists?(options.restart_script)
- puts "Script file '#{options.restart_script}' is not found"
- exit
- end
- end
- opts.on('--script FILE', String, 'Name of the script file to run') do
- |script|
- options.script = script
- unless File.exists?(options.script)
- puts "Script file '#{options.script}' is not found"
- exit
- end
- end
- opts.on('-s', '--server', 'Listen for remote connections') do
- options.server = true
- end
- opts.on('-w', '--wait', 'Wait for a client connection, implies -s option') do
- options.wait = true
- end
- opts.on('-x', '--trace', 'Turn on line tracing') {options.tracing = true}
- opts.separator ''
- opts.separator 'Common options:'
- opts.on_tail('--help', 'Show this message') do
- puts opts
- exit
- end
- opts.on_tail('--version',
- 'Print the version') do
- puts "debugger #{Debugger::VERSION}"
- exit
- end
- opts.on('--verbose', 'Turn on verbose mode') do
- $VERBOSE = true
- options.verbose_long = true
- end
- opts.on_tail('-v',
- 'Print version number, then turn on verbose mode') do
- puts "debugger #{Debugger::VERSION}"
- $VERBOSE = true
- end
- end
- return opts
-end
# What file is used for debugger startup commands.
unless defined?(OPTS_INITFILE)
@@ -297,21 +164,21 @@ begin
rescue
end
-opts = process_options(options)
+if not defined? Debugger::ARGV
+ Debugger::ARGV = ARGV.clone
+end
+rdebug_path = File.expand_path($0)
+if RUBY_PLATFORM =~ /mswin/
+ rdebug_path += '.cmd' unless rdebug_path =~ /\.cmd$/i
+end
+Debugger::RDEBUG_SCRIPT = rdebug_path
+Debugger::RDEBUG_FILE = __FILE__
+Debugger::INITIAL_DIR = Dir.pwd
+
begin
- if not defined? Debugger::ARGV
- Debugger::ARGV = ARGV.clone
- end
- rdebug_path = File.expand_path($0)
- if RUBY_PLATFORM =~ /mswin/
- rdebug_path += '.cmd' unless rdebug_path =~ /\.cmd$/i
- end
- Debugger::RDEBUG_SCRIPT = rdebug_path
- Debugger::RDEBUG_FILE = __FILE__
- Debugger::INITIAL_DIR = Dir.pwd
- opts.parse! ARGV
+ options = RdebugOptionParser.instance.parse ARGV
rescue StandardError => e
- puts opts
+ puts RdebugOptionParser.instance
puts
puts e.message
exit(-1)
@@ -322,7 +189,8 @@ if options.client
else
if ARGV.empty?
exit if $VERBOSE and not options.verbose_long
- puts opts
+ # Print the possible options and exit
+ puts RdebugOptionParser.instance
puts
puts 'Must specify a script to run'
exit(-1)
diff --git a/debugger.gemspec b/debugger.gemspec
index 766ac20..babe131 100644
--- a/debugger.gemspec
+++ b/debugger.gemspec
@@ -26,5 +26,6 @@ handling, bindings for stack frames among other things.
s.add_development_dependency 'rake-compiler', '~> 0.8.0'
s.add_development_dependency 'minitest', '~> 2.12.1'
s.add_development_dependency 'mocha', '~> 0.13.0'
+ s.add_development_dependency 'guard-minitest'
s.license = "BSD"
end
diff --git a/lib/debugger/runner/rdebug_option_parser.rb b/lib/debugger/runner/rdebug_option_parser.rb
new file mode 100644
index 0000000..fa18da5
--- /dev/null
+++ b/lib/debugger/runner/rdebug_option_parser.rb
@@ -0,0 +1,175 @@
+require 'optparse'
+require 'ostruct'
+require 'singleton'
+
+# Singleton parser class for Rdebug options
+#
+# Usage:
+#
+# RdebugOptionParser.instance.parse arguments
+#
+# Returns an OpenStruct with attributes built from (in order of priority)
+# 1. arguments passed to parse()
+# 2. default_options
+class RdebugOptionParser
+ include Singleton
+
+ # arguments - an array of strings, the same format as ARGV
+ def parse arguments
+ begin
+ @option_parser.parse! arguments
+ rescue StandardError => e
+ puts @option_parser
+ puts
+ puts e.message
+ exit(-1)
+ end
+
+ @options
+ end
+
+ def initialize
+ @options = default_options
+
+ program = File.basename($0)
+ @option_parser = OptionParser.new do |parser|
+ parser.banner = < --
+EOB
+ parser.separator ""
+ parser.separator "Options:"
+ parser.on("-A", "--annotate LEVEL", Integer,
+ "Set annotation level") do |annotate|
+ Debugger.annotate = annotate
+ end
+ parser.on("-c", "--client", "Connect to remote debugger") do
+ @options.client = true
+ end
+ parser.on("--cport PORT", Integer, "Port used for control commands. Default 8990") do
+ |cport|
+ @options.cport = cport
+ end
+ parser.on("-d", "--debug", "Set $DEBUG=true") {$DEBUG = true}
+ parser.on("--emacs LEVEL", Integer,
+ "Activates full Emacs support at annotation level LEVEL") do
+ |level|
+ Debugger.annotate = level.to_i
+ ENV['EMACS'] = '1'
+ ENV['COLUMNS'] = '120' if ENV['COLUMNS'].to_i < 120
+ @options.control = false
+ @options.quit = false
+ end
+ parser.on('--emacs-basic', 'Activates basic Emacs mode') do
+ ENV['EMACS'] = '1'
+ end
+ parser.on('-h', '--host HOST', 'Host name used for remote debugging') do
+ |host|
+ @options.host = host
+ end
+ parser.on('-I', '--include PATH', String, 'Add PATH to $LOAD_PATH') do |path|
+ $LOAD_PATH.unshift(path)
+ end
+ parser.on('--no-control', 'Do not automatically start control thread') do
+ @options.control = false
+ end
+ parser.on('--no-quit', 'Do not quit when script finishes') do
+ @options.quit = false
+ end
+ parser.on('--no-rewrite-program',
+ 'Do not set $0 to the program being debugged') do
+ @options.no_rewrite_program = true
+ end
+ parser.on('--no-stop', 'Do not stop when script is loaded') do
+ @options.stop = false
+ end
+ parser.on('-nx', 'Not run debugger initialization files (e.g. .rdebugrc') do
+ @options.nx = true
+ end
+ parser.on('-p', '--port PORT', Integer, 'Port used for remote debugging. Default 8989') do
+ |port|
+ @options.port = port
+ end
+ parser.on('-r', '--require SCRIPT', String,
+ 'Require the library, before executing your script') do |name|
+ if name == 'debug'
+ puts "debugger is not compatible with Ruby's 'debug' library. This option is ignored."
+ else
+ require name
+ end
+ end
+ parser.on('--restart-script FILE', String,
+ 'Name of the script file to run. Erased after read') do
+ |restart_script|
+ @options.restart_script = restart_script
+ unless File.exists?(@options.restart_script)
+ puts "Script file '#{@options.restart_script}' is not found"
+ exit
+ end
+ end
+ parser.on('--script FILE', String, 'Name of the script file to run') do
+ |script|
+ @options.script = script
+ unless File.exists?(@options.script)
+ puts "Script file '#{@options.script}' is not found"
+ exit
+ end
+ end
+ parser.on('-s', '--server', 'Listen for remote connections') do
+ @options.server = true
+ end
+ parser.on('-w', '--wait', 'Wait for a client connection, implies -s option') do
+ @options.wait = true
+ end
+ parser.on('-x', '--trace', 'Turn on line tracing') {@options.tracing = true}
+ parser.separator ''
+ parser.separator 'Common options:'
+ parser.on_tail('--help', 'Show this message') do
+ puts parser
+ exit
+ end
+ parser.on_tail('--version',
+ 'Print the version') do
+ puts "debugger #{Debugger::VERSION}"
+ exit
+ end
+ parser.on('--verbose', 'Turn on verbose mode') do
+ $VERBOSE = true
+ @options.verbose_long = true
+ end
+ parser.on_tail('-v',
+ 'Print version number, then turn on verbose mode') do
+ puts "debugger #{Debugger::VERSION}"
+ $VERBOSE = true
+ end
+ end
+ end
+
+ # Delegate to_s to @option_parser, which returns an option summary string
+ def to_s
+ @option_parser.to_s
+ end
+
+ private
+
+ def default_options
+ OpenStruct.new(
+ 'annotate' => Debugger.annotate,
+ 'client' => false,
+ 'control' => true,
+ 'cport' => Debugger::PORT + 1,
+ 'host' => nil,
+ 'quit' => true,
+ 'no_rewrite_program' => false,
+ 'stop' => true,
+ 'nx' => false,
+ 'port' => Debugger::PORT,
+ 'restart_script' => nil,
+ 'script' => nil,
+ 'server' => false,
+ 'tracing' => false,
+ 'verbose_long' => false,
+ 'wait' => false
+ )
+ end
+end
diff --git a/man/rdebug.1 b/man/rdebug.1
index 4c9d03f..0384aed 100644
--- a/man/rdebug.1
+++ b/man/rdebug.1
@@ -159,7 +159,7 @@ Connect to a remote debugger. Used with another rdebug invocation using \-\-serv
See also \-\-host and \-\-cport options
.TP
.B \-\-cport=PORT
-Port used for control commands.
+Port used for control commands. Default 8990
.TP
.B \-d | \-\-debug
Set $DEBUG true.
@@ -189,7 +189,7 @@ Do not automatically start control thread.
Do not stop when script is loaded.
.TP
.B \-p | \-\-port=PORT
-Host name used for remote debugging.
+Host name used for remote debugging. Default 8989
.TP
.B \-r | \-\-require SCRIPT
Require the library, before executing your script.
diff --git a/test/new/printers/plain_test.rb b/test/new/printers/plain_test.rb
index 4fb6a63..6580163 100644
--- a/test/new/printers/plain_test.rb
+++ b/test/new/printers/plain_test.rb
@@ -1,4 +1,4 @@
-require_relative '../test_helper'
+require_relative '../../test_helper'
describe "Printers::Plain" do
include PrinterHelpers
diff --git a/test/rdebug/rdebug_option_parser_test.rb b/test/rdebug/rdebug_option_parser_test.rb
new file mode 100644
index 0000000..075b001
--- /dev/null
+++ b/test/rdebug/rdebug_option_parser_test.rb
@@ -0,0 +1,283 @@
+require_relative '../test_helper'
+require_relative '../../lib/debugger/runner/rdebug_option_parser'
+require 'minitest/autorun'
+require 'mocha/setup'
+
+describe RdebugOptionParser do
+ before do
+ # Hack to re-initialize a Singleton class and clear its state
+ Singleton.__init__(RdebugOptionParser)
+ end
+
+ it "returns an option summary" do
+ RdebugOptionParser.instance.to_s.wont_be_empty
+ end
+
+ describe "annotation arguments" do
+ it "parses the long form" do
+ Debugger.expects(:annotate=).with(3)
+ call_rdebug_parse_with_arguments ["--annotate=3"]
+ end
+
+ it "parses the short form" do
+ Debugger.expects(:annotate=).with(3)
+ call_rdebug_parse_with_arguments ["-A", "3"]
+ end
+ end
+
+ describe "client mode arguments" do
+ it "parses the long form" do
+ result = call_rdebug_parse_with_arguments ["--client"]
+ result.client.must_equal true
+ end
+
+ it "parses the short form" do
+ result = call_rdebug_parse_with_arguments ["-c"]
+ result.client.must_equal true
+ end
+ end
+
+ it "parses a control port argument and sets a value in the returned OpenStruct" do
+ result = call_rdebug_parse_with_arguments ["--cport=3000"]
+ result.cport.must_equal 3000
+ end
+
+ describe "debug arguments" do
+ before { @old_debug_setting = $DEBUG }
+ after { $DEBUG = @old_debug_setting }
+ it "parses the long form" do
+ $DEBUG = false
+ call_rdebug_parse_with_arguments ["--debug"]
+ $DEBUG.must_equal true
+ end
+
+ it "parses the short form" do
+ $DEBUG = false
+ call_rdebug_parse_with_arguments ["-d"]
+ $DEBUG.must_equal true
+ end
+ end
+
+ describe "emacs arguments" do
+ it "parses an emacs option with custom annotation level" do
+ Debugger.expects(:annotate=).with(5)
+ ENV.expects(:[]=).with('EMACS', '1')
+
+ # Mock column width less than 120
+ ENV.expects(:[]).with('COLUMNS').returns(110)
+ ENV.expects(:[]=).with('COLUMNS', '120')
+
+ result = call_rdebug_parse_with_arguments ['--emacs=5']
+ result.control.must_equal false
+ result.quit.must_equal false
+ end
+
+ it "parses an emacs basic argument" do
+ ENV.expects(:[]=).with('EMACS', '1')
+
+ call_rdebug_parse_with_arguments ['--emacs-basic']
+ end
+ end
+
+ describe "host arguments" do
+ it "parses the short form" do
+ result = call_rdebug_parse_with_arguments ['-h', '5000']
+ result.host.must_equal '5000'
+ end
+
+ it "parses the long form" do
+ result = call_rdebug_parse_with_arguments ['--host=5000']
+ result.host.must_equal '5000'
+ end
+ end
+
+ describe "include arguments" do
+ before { $LOAD_PATH.expects(:unshift).with('./') }
+ it "parses the long form" do
+ call_rdebug_parse_with_arguments ['--include=./']
+ end
+
+ it "parses the short form" do
+ call_rdebug_parse_with_arguments ['-I', './']
+ end
+ end
+
+ it "parses a no-control-thread argument and sets a boolean in the returned OpenStruct" do
+ result = call_rdebug_parse_with_arguments ['--no-control']
+ result.control.must_equal false
+ end
+
+ it "parses a no-quit argument and sets a boolean in the returned OpenStruct" do
+ result = call_rdebug_parse_with_arguments ['--no-quit']
+ result.quit.must_equal false
+ end
+
+ it "parses a no-rewrite-program argument and sets a boolean in returned OpenStruct" do
+ result = call_rdebug_parse_with_arguments ['--no-rewrite-program']
+ result.no_rewrite_program.must_equal true
+ end
+
+ it "parses a no-stop argument and sets a boolean in returned OpenStruct" do
+ result = call_rdebug_parse_with_arguments ['--no-stop']
+ result.stop.must_equal false
+ end
+
+ it "parses a skip init files argument and sets a boolean in returned OpenStruct" do
+ result = call_rdebug_parse_with_arguments ['-nx']
+ result.nx.must_equal true
+ end
+
+ it "parses a port argument and sets a user-provided value in the returned OpenStruct" do
+ result = call_rdebug_parse_with_arguments ['-p', '5000']
+ result.port.must_equal 5000
+ end
+
+ describe "require arguments" do
+ it "parses the long form" do
+ RdebugOptionParser.instance.expects(:require).with('foo').returns(true)
+ call_rdebug_parse_with_arguments ["--require=foo"]
+ end
+
+ it "parses the short form" do
+ RdebugOptionParser.instance.expects(:require).with('foo').returns(true)
+ call_rdebug_parse_with_arguments ["-r", "foo"]
+ end
+ end
+
+ describe "restart-script" do
+ it "sets the filename in the returned OpenStruct" do
+ result = call_rdebug_parse_with_arguments ['--restart-script=./']
+ result.restart_script.must_equal './'
+ end
+
+ it "checks for the existence of a file and prints an error message if it doesn't exist" do
+ out, err = capture_io do
+ assert_raises(SystemExit) do
+ RdebugOptionParser.instance.parse ['--restart-script=./non_existent_file']
+ end
+ end
+
+ out.must_match /is not found/
+ end
+ end
+
+ describe "script" do
+ it "sets the filename in the returned OpenStruct" do
+ result = call_rdebug_parse_with_arguments ['--script=./']
+ result.script.must_equal './'
+ end
+
+ it "checks for the existence of a file and prints an error message if it doesn't exist" do
+ out, err = capture_io do
+ assert_raises(SystemExit) do
+ RdebugOptionParser.instance.parse ['--script=./non_existent_file']
+ end
+ end
+
+ out.must_match /is not found/
+ end
+ end
+
+ describe "server mode arguments" do
+ it "parses the long form" do
+ result = call_rdebug_parse_with_arguments ["--server"]
+ result.server.must_equal true
+ end
+
+ it "parses the short form" do
+ result = call_rdebug_parse_with_arguments ["-s"]
+ result.server.must_equal true
+ end
+ end
+
+ describe "wait mode arguments" do
+ it "parses the long form" do
+ result = call_rdebug_parse_with_arguments ["--wait"]
+ result.wait.must_equal true
+ end
+
+ it "parses the short form" do
+ result = call_rdebug_parse_with_arguments ["-w"]
+ result.wait.must_equal true
+ end
+ end
+
+ describe "trace arguments" do
+ after { @result.tracing.must_equal true }
+
+ it "parses the long version and sets a boolean on the returned OpenStruct" do
+ @result = call_rdebug_parse_with_arguments ["-x"]
+ end
+
+ it "parses the short version and sets a boolean on the returned OpenStruct" do
+ @result = call_rdebug_parse_with_arguments ["--trace"]
+ end
+ end
+
+ describe "help argument" do
+
+ it "prints the command line options" do
+ out,err = capture_io do
+ call_rdebug_parse_with_arguments ['--help']
+ end
+
+ out.must_include "Usage:"
+ end
+ end
+
+ it 'parses a version argument' do
+ out, err = capture_io do
+ assert_raises(SystemExit) do
+ RdebugOptionParser.instance.parse ['--version']
+ end
+ end
+
+ out.must_include Debugger::VERSION
+ end
+
+ describe 'verbose options' do
+ before do
+ # preserve $VERBOSE setting so that this test doesn't make other tests
+ # noisy
+ @verbose_before = $VERBOSE
+ end
+
+ after do
+ $VERBOSE = @verbose_before
+ end
+
+ it 'parses a verbose argument' do
+ options = RdebugOptionParser.instance.parse ['--verbose']
+
+ options.verbose_long.must_equal true
+ $VERBOSE.must_equal true
+ end
+
+ it 'parses a verbose/version argument and prints a message' do
+ out, err = capture_io do
+ options = RdebugOptionParser.instance.parse ['-v']
+
+ $VERBOSE.must_equal true
+ end
+
+ out.must_include Debugger::VERSION
+ end
+ end
+
+ it "to_s returns the command line options when run without arguments" do
+ output = RdebugOptionParser.instance.to_s
+
+ output.must_include "Usage:"
+ output.must_include "[options] -- "
+ output.must_include "-A, --annotate LEVEL Set annotation level"
+ end
+
+ private
+ def call_rdebug_parse_with_arguments arguments
+ begin
+ RdebugOptionParser.instance.parse arguments
+ # RdebugOptionParser catches all StandardErrors and calls exit(-1)
+ rescue SystemExit
+ end
+ end
+end