[DRE-commits] [pry] 04/08: Refresh patch: import upstream rspec
Youhei SASAKI
uwabami-guest at moszumanska.debian.org
Tue Aug 12 11:11:08 UTC 2014
This is an automated email from the git hooks/post-receive script.
uwabami-guest pushed a commit to branch master
in repository pry.
commit 371700f1a1fa5b5ea92e25879d81344b6a8e10f9
Author: Youhei SASAKI <uwabami at gfd-dennou.org>
Date: Tue Aug 12 19:53:16 2014 +0900
Refresh patch: import upstream rspec
Signed-off-by: Youhei SASAKI <uwabami at gfd-dennou.org>
---
.../patches/0001-Import-upstream-rspec-files.patch | 12420 +++++++++++++++++++
...2-Modify-upstream-spec-for-Debian-Package.patch | 37 +
debian/patches/fix_spelling.patch | 15 -
debian/patches/series | 3 +-
4 files changed, 12459 insertions(+), 16 deletions(-)
diff --git a/debian/patches/0001-Import-upstream-rspec-files.patch b/debian/patches/0001-Import-upstream-rspec-files.patch
new file mode 100644
index 0000000..9bb0737
--- /dev/null
+++ b/debian/patches/0001-Import-upstream-rspec-files.patch
@@ -0,0 +1,12420 @@
+From: Youhei SASAKI <uwabami at gfd-dennou.org>
+Date: Tue, 12 Aug 2014 19:36:30 +0900
+Subject: Import upstream rspec files
+
+Signed-off-by: Youhei SASAKI <uwabami at gfd-dennou.org>
+---
+ spec/Procfile | 3 +
+ spec/cli_spec.rb | 88 ++++
+ spec/code_object_spec.rb | 283 ++++++++++
+ spec/code_spec.rb | 256 +++++++++
+ spec/command_helpers_spec.rb | 29 ++
+ spec/command_integration_spec.rb | 564 ++++++++++++++++++++
+ spec/command_set_spec.rb | 676 ++++++++++++++++++++++++
+ spec/command_spec.rb | 819 +++++++++++++++++++++++++++++
+ spec/commands/amend_line_spec.rb | 247 +++++++++
+ spec/commands/bang_spec.rb | 24 +
+ spec/commands/cat/file_formatter_spec.rb | 83 +++
+ spec/commands/cat_spec.rb | 164 ++++++
+ spec/commands/cd_spec.rb | 259 ++++++++++
+ spec/commands/disable_pry_spec.rb | 25 +
+ spec/commands/edit_spec.rb | 768 +++++++++++++++++++++++++++
+ spec/commands/exit_all_spec.rb | 27 +
+ spec/commands/exit_program_spec.rb | 19 +
+ spec/commands/exit_spec.rb | 28 +
+ spec/commands/find_method_spec.rb | 63 +++
+ spec/commands/gem_list_spec.rb | 25 +
+ spec/commands/gist_spec.rb | 32 ++
+ spec/commands/help_spec.rb | 56 ++
+ spec/commands/hist_spec.rb | 204 ++++++++
+ spec/commands/jump_to_spec.rb | 15 +
+ spec/commands/ls_spec.rb | 246 +++++++++
+ spec/commands/play_spec.rb | 182 +++++++
+ spec/commands/raise_up_spec.rb | 56 ++
+ spec/commands/reload_code_spec.rb | 21 +
+ spec/commands/save_file_spec.rb | 177 +++++++
+ spec/commands/shell_command_spec.rb | 63 +++
+ spec/commands/show_doc_spec.rb | 573 +++++++++++++++++++++
+ spec/commands/show_input_spec.rb | 17 +
+ spec/commands/show_source_spec.rb | 829 ++++++++++++++++++++++++++++++
+ spec/commands/watch_expression_spec.rb | 119 +++++
+ spec/commands/whereami_spec.rb | 237 +++++++++
+ spec/completion_spec.rb | 214 ++++++++
+ spec/config_spec.rb | 189 +++++++
+ spec/control_d_handler_spec.rb | 62 +++
+ spec/documentation_helper_spec.rb | 68 +++
+ spec/editor_spec.rb | 68 +++
+ spec/exception_whitelist_spec.rb | 21 +
+ spec/fixtures/candidate_helper1.rb | 11 +
+ spec/fixtures/candidate_helper2.rb | 8 +
+ spec/fixtures/cat_load_path | 0
+ spec/fixtures/cat_load_path.rb | 0
+ spec/fixtures/example.erb | 5 +
+ spec/fixtures/example_nesting.rb | 33 ++
+ spec/fixtures/pry_history | 3 +
+ spec/fixtures/show_source_doc_examples.rb | 22 +
+ spec/fixtures/slinky.rb | 0
+ spec/fixtures/slinky/stinky.rb | 0
+ spec/fixtures/testlinkrc | 1 +
+ spec/fixtures/testrc | 2 +
+ spec/fixtures/testrcbad | 2 +
+ spec/fixtures/whereami_helper.rb | 6 +
+ spec/helper.rb | 34 ++
+ spec/helpers/table_spec.rb | 105 ++++
+ spec/history_array_spec.rb | 71 +++
+ spec/history_spec.rb | 154 ++++++
+ spec/hooks_spec.rb | 475 +++++++++++++++++
+ spec/indent_spec.rb | 301 +++++++++++
+ spec/method/patcher_spec.rb | 34 ++
+ spec/method_spec.rb | 507 ++++++++++++++++++
+ spec/pager_spec.rb | 66 +++
+ spec/prompt_spec.rb | 61 +++
+ spec/pry_defaults_spec.rb | 428 +++++++++++++++
+ spec/pry_output_spec.rb | 117 +++++
+ spec/pry_repl_spec.rb | 102 ++++
+ spec/pry_spec.rb | 414 +++++++++++++++
+ spec/pryrc_spec.rb | 97 ++++
+ spec/regression/readline_spec.rb | 39 ++
+ spec/run_command_spec.rb | 23 +
+ spec/spec_helpers/bacon.rb | 86 ++++
+ spec/spec_helpers/mock_pry.rb | 44 ++
+ spec/spec_helpers/repl_tester.rb | 112 ++++
+ spec/sticky_locals_spec.rb | 180 +++++++
+ spec/syntax_checking_spec.rb | 81 +++
+ spec/wrapped_module_spec.rb | 276 ++++++++++
+ 78 files changed, 11799 insertions(+)
+ create mode 100644 spec/Procfile
+ create mode 100644 spec/cli_spec.rb
+ create mode 100644 spec/code_object_spec.rb
+ create mode 100644 spec/code_spec.rb
+ create mode 100644 spec/command_helpers_spec.rb
+ create mode 100644 spec/command_integration_spec.rb
+ create mode 100644 spec/command_set_spec.rb
+ create mode 100644 spec/command_spec.rb
+ create mode 100644 spec/commands/amend_line_spec.rb
+ create mode 100644 spec/commands/bang_spec.rb
+ create mode 100644 spec/commands/cat/file_formatter_spec.rb
+ create mode 100644 spec/commands/cat_spec.rb
+ create mode 100644 spec/commands/cd_spec.rb
+ create mode 100644 spec/commands/disable_pry_spec.rb
+ create mode 100644 spec/commands/edit_spec.rb
+ create mode 100644 spec/commands/exit_all_spec.rb
+ create mode 100644 spec/commands/exit_program_spec.rb
+ create mode 100644 spec/commands/exit_spec.rb
+ create mode 100644 spec/commands/find_method_spec.rb
+ create mode 100644 spec/commands/gem_list_spec.rb
+ create mode 100644 spec/commands/gist_spec.rb
+ create mode 100644 spec/commands/help_spec.rb
+ create mode 100644 spec/commands/hist_spec.rb
+ create mode 100644 spec/commands/jump_to_spec.rb
+ create mode 100644 spec/commands/ls_spec.rb
+ create mode 100644 spec/commands/play_spec.rb
+ create mode 100644 spec/commands/raise_up_spec.rb
+ create mode 100644 spec/commands/reload_code_spec.rb
+ create mode 100644 spec/commands/save_file_spec.rb
+ create mode 100644 spec/commands/shell_command_spec.rb
+ create mode 100644 spec/commands/show_doc_spec.rb
+ create mode 100644 spec/commands/show_input_spec.rb
+ create mode 100644 spec/commands/show_source_spec.rb
+ create mode 100644 spec/commands/watch_expression_spec.rb
+ create mode 100644 spec/commands/whereami_spec.rb
+ create mode 100644 spec/completion_spec.rb
+ create mode 100644 spec/config_spec.rb
+ create mode 100644 spec/control_d_handler_spec.rb
+ create mode 100644 spec/documentation_helper_spec.rb
+ create mode 100644 spec/editor_spec.rb
+ create mode 100644 spec/exception_whitelist_spec.rb
+ create mode 100644 spec/fixtures/candidate_helper1.rb
+ create mode 100644 spec/fixtures/candidate_helper2.rb
+ create mode 100644 spec/fixtures/cat_load_path
+ create mode 100644 spec/fixtures/cat_load_path.rb
+ create mode 100644 spec/fixtures/example.erb
+ create mode 100644 spec/fixtures/example_nesting.rb
+ create mode 100644 spec/fixtures/pry_history
+ create mode 100644 spec/fixtures/show_source_doc_examples.rb
+ create mode 100644 spec/fixtures/slinky.rb
+ create mode 100644 spec/fixtures/slinky/stinky.rb
+ create mode 120000 spec/fixtures/testlinkrc
+ create mode 100644 spec/fixtures/testrc
+ create mode 100644 spec/fixtures/testrcbad
+ create mode 100644 spec/fixtures/whereami_helper.rb
+ create mode 100644 spec/helper.rb
+ create mode 100644 spec/helpers/table_spec.rb
+ create mode 100644 spec/history_array_spec.rb
+ create mode 100644 spec/history_spec.rb
+ create mode 100644 spec/hooks_spec.rb
+ create mode 100644 spec/indent_spec.rb
+ create mode 100644 spec/method/patcher_spec.rb
+ create mode 100644 spec/method_spec.rb
+ create mode 100644 spec/pager_spec.rb
+ create mode 100644 spec/prompt_spec.rb
+ create mode 100644 spec/pry_defaults_spec.rb
+ create mode 100644 spec/pry_output_spec.rb
+ create mode 100644 spec/pry_repl_spec.rb
+ create mode 100644 spec/pry_spec.rb
+ create mode 100644 spec/pryrc_spec.rb
+ create mode 100644 spec/regression/readline_spec.rb
+ create mode 100644 spec/run_command_spec.rb
+ create mode 100644 spec/spec_helpers/bacon.rb
+ create mode 100644 spec/spec_helpers/mock_pry.rb
+ create mode 100644 spec/spec_helpers/repl_tester.rb
+ create mode 100644 spec/sticky_locals_spec.rb
+ create mode 100644 spec/syntax_checking_spec.rb
+ create mode 100644 spec/wrapped_module_spec.rb
+
+diff --git a/spec/Procfile b/spec/Procfile
+new file mode 100644
+index 0000000..d0fec32
+--- /dev/null
++++ b/spec/Procfile
+@@ -0,0 +1,3 @@
++# Run this with:
++# gem install foreman && foreman start -f spec/Procfile
++pryhere: sh -c '(cd ..; rake pry)'
+diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb
+new file mode 100644
+index 0000000..0f6f88c
+--- /dev/null
++++ b/spec/cli_spec.rb
+@@ -0,0 +1,88 @@
++require_relative 'helper'
++
++describe Pry::Hooks do
++ before do
++ Pry::CLI.reset
++ end
++
++ describe "parsing options" do
++ it 'should raise if no options defined' do
++ lambda { Pry::CLI.parse_options(["--nothing"]) }.should.raise Pry::CLI::NoOptionsError
++ end
++
++ it "should remove args from ARGV by default" do
++ ARGV << '-v'
++ Pry::CLI.add_options do
++ on :v, "Display the Pry version" do
++ # irrelevant
++ end
++ end.parse_options
++ ARGV.include?('-v').should == false
++ end
++ end
++
++ describe "adding options" do
++ it "should be able to add an option" do
++ run = false
++
++ Pry::CLI.add_options do
++ on :optiontest, "A test option" do
++ run = true
++ end
++ end.parse_options(["--optiontest"])
++
++ run.should == true
++ end
++
++ it "should be able to add multiple options" do
++ run = false
++ run2 = false
++
++ Pry::CLI.add_options do
++ on :optiontest, "A test option" do
++ run = true
++ end
++ end.add_options do
++ on :optiontest2, "Another test option" do
++ run2 = true
++ end
++ end.parse_options(["--optiontest", "--optiontest2"])
++
++ run.should.be.true
++ run2.should.be.true
++ end
++
++ end
++
++ describe "processing options" do
++ it "should be able to process an option" do
++ run = false
++
++ Pry::CLI.add_options do
++ on :optiontest, "A test option"
++ end.add_option_processor do |opts|
++ run = true if opts.present?(:optiontest)
++ end.parse_options(["--optiontest"])
++
++ run.should == true
++ end
++
++ it "should be able to process multiple options" do
++ run = false
++ run2 = false
++
++ Pry::CLI.add_options do
++ on :optiontest, "A test option"
++ on :optiontest2, "Another test option"
++ end.add_option_processor do |opts|
++ run = true if opts.present?(:optiontest)
++ end.add_option_processor do |opts|
++ run2 = true if opts.present?(:optiontest2)
++ end.parse_options(["--optiontest", "--optiontest2"])
++
++ run.should == true
++ run2.should == true
++ end
++
++ end
++end
+diff --git a/spec/code_object_spec.rb b/spec/code_object_spec.rb
+new file mode 100644
+index 0000000..2184c98
+--- /dev/null
++++ b/spec/code_object_spec.rb
+@@ -0,0 +1,283 @@
++require_relative 'helper'
++
++describe Pry::CodeObject do
++ describe "basic lookups" do
++ before do
++ @obj = Object.new
++ def @obj.ziggy
++ "a flight of scarlet pigeons thunders round my thoughts"
++ end
++
++ class ClassyWassy
++ def piggy
++ binding
++ end
++ end
++
++ @p = Pry.new
++ @p.binding_stack = [binding]
++ end
++
++ after do
++ Object.remove_const(:ClassyWassy)
++ end
++
++ it 'should lookup methods' do
++ m = Pry::CodeObject.lookup("@obj.ziggy", @p)
++ m.is_a?(Pry::Method).should == true
++ m.name.to_sym.should == :ziggy
++ end
++
++ it 'should lookup modules' do
++ m = Pry::CodeObject.lookup("ClassyWassy", @p)
++ m.is_a?(Pry::WrappedModule).should == true
++ m.source.should =~ /piggy/
++ end
++
++ it 'should lookup procs' do
++ my_proc = proc { :hello }
++ @p.binding_stack = [binding]
++ m = Pry::CodeObject.lookup("my_proc", @p)
++ m.is_a?(Pry::Method).should == true
++ m.source.should =~ /hello/
++ end
++
++ describe 'commands lookup' do
++ before do
++ @p = Pry.new
++ @p.binding_stack = [binding]
++ end
++
++ it 'should return command class' do
++ @p.commands.command "jeremy-jones" do
++ "lobster"
++ end
++ m = Pry::CodeObject.lookup("jeremy-jones", @p)
++ (m <= Pry::Command).should == true
++ m.source.should =~ /lobster/
++ end
++
++ describe "class commands" do
++ before do
++ class LobsterLady < Pry::ClassCommand
++ match "lobster-lady"
++ description "nada."
++ def process
++ "lobster"
++ end
++ end
++ end
++
++ after do
++ Object.remove_const(:LobsterLady)
++ end
++
++ it 'should return Pry::ClassCommand class when looking up class command' do
++ Pry.config.commands.add_command(LobsterLady)
++ m = Pry::CodeObject.lookup("lobster-lady", @p)
++ (m <= Pry::ClassCommand).should == true
++ m.source.should =~ /class LobsterLady/
++ Pry.config.commands.delete("lobster-lady")
++ end
++
++ it 'should return Pry::WrappedModule when looking up command class directly (as a class, not as a command)' do
++ Pry.config.commands.add_command(LobsterLady)
++ m = Pry::CodeObject.lookup("LobsterLady", @p)
++ m.is_a?(Pry::WrappedModule).should == true
++ m.source.should =~ /class LobsterLady/
++ Pry.config.commands.delete("lobster-lady")
++ end
++ end
++
++ it 'looks up commands by :listing name as well' do
++ @p.commands.command /jeremy-.*/, "", :listing => "jeremy-baby" do
++ "lobster"
++ end
++ m = Pry::CodeObject.lookup("jeremy-baby", @p)
++ (m <= Pry::Command).should == true
++ m.source.should =~ /lobster/
++ end
++
++ it 'finds nothing when passing nil as the first argument' do
++ Pry::CodeObject.lookup(nil, @p).should == nil
++ end
++
++ end
++
++ it 'should lookup instance methods defined on classes accessed via local variable' do
++ o = Class.new do
++ def princess_bubblegum
++ "mathematic!"
++ end
++ end
++
++ @p.binding_stack = [binding]
++ m = Pry::CodeObject.lookup("o#princess_bubblegum", @p)
++ m.is_a?(Pry::Method).should == true
++ m.source.should =~ /mathematic!/
++ end
++
++ it 'should lookup class methods defined on classes accessed via local variable' do
++ o = Class.new do
++ def self.finn
++ "4 realzies"
++ end
++ end
++ @p.binding_stack = [binding]
++ m = Pry::CodeObject.lookup("o.finn", @p)
++ m.is_a?(Pry::Method).should == true
++ m.source.should =~ /4 realzies/
++ end
++
++ it 'should lookup the class of an object (when given a variable)' do
++ moddy = ClassyWassy.new
++ @p.binding_stack = [binding]
++ m = Pry::CodeObject.lookup("moddy", @p)
++ m.is_a?(Pry::WrappedModule).should == true
++ m.source.should =~ /piggy/
++ end
++
++ describe "inferring object from binding when lookup str is empty/nil" do
++ before do
++ @b1 = Pry.binding_for(ClassyWassy)
++ @b2 = Pry.binding_for(ClassyWassy.new)
++ end
++
++ describe "infer module objects" do
++ it 'should infer module object when binding self is a module' do
++ ["", nil].each do |v|
++ @p.binding_stack = [@b1]
++ m = Pry::CodeObject.lookup(v, @p)
++ m.is_a?(Pry::WrappedModule).should == true
++ m.name.should =~ /ClassyWassy/
++ end
++ end
++
++ it 'should infer module object when binding self is an instance' do
++ ["", nil].each do |v|
++ @p.binding_stack = [@b2]
++ m = Pry::CodeObject.lookup(v, @p)
++ m.is_a?(Pry::WrappedModule).should == true
++ m.name.should =~ /ClassyWassy/
++ end
++ end
++ end
++
++ describe "infer method objects" do
++ it 'should infer method object from binding when inside method context' do
++ b = ClassyWassy.new.piggy
++
++ ["", nil].each do |v|
++ @p.binding_stack = [b]
++ m = Pry::CodeObject.lookup(v, @p)
++ m.is_a?(Pry::Method).should == true
++ m.name.should =~ /piggy/
++ end
++ end
++ end
++ end
++ end
++
++ describe "lookups with :super" do
++ before do
++ class MyClassyWassy; end
++ class CuteSubclass < MyClassyWassy; end
++ @p = Pry.new
++ @p.binding_stack = [binding]
++ end
++
++ after do
++ Object.remove_const(:MyClassyWassy)
++ Object.remove_const(:CuteSubclass)
++ end
++
++ it 'should lookup original class with :super => 0' do
++ m = Pry::CodeObject.lookup("CuteSubclass", @p, :super => 0)
++ m.is_a?(Pry::WrappedModule).should == true
++ m.wrapped.should == CuteSubclass
++ end
++
++ it 'should lookup immediate super class with :super => 1' do
++ m = Pry::CodeObject.lookup("CuteSubclass", @p, :super => 1)
++ m.is_a?(Pry::WrappedModule).should == true
++ m.wrapped.should == MyClassyWassy
++ end
++
++ it 'should ignore :super parameter for commands' do
++ p = Pry.new
++ p.commands.command "jeremy-jones" do
++ "lobster"
++ end
++ p.binding_stack = [binding]
++ m = Pry::CodeObject.lookup("jeremy-jones", p, :super => 10)
++ m.source.should =~ /lobster/
++ end
++ end
++
++ describe "precedence" do
++ before do
++ class ClassyWassy
++ class Puff
++ def tiggy
++ end
++ end
++
++ def Puff
++ end
++
++ def piggy
++ end
++ end
++
++ Object.class_eval do
++ def ClassyWassy
++ :ducky
++ end
++ end
++
++ @p = Pry.new
++ @p.binding_stack = [binding]
++ end
++
++ after do
++ Object.remove_const(:ClassyWassy)
++ Object.remove_method(:ClassyWassy)
++ end
++
++ it 'should look up classes before methods (at top-level)' do
++ m = Pry::CodeObject.lookup("ClassyWassy", @p)
++ m.is_a?(Pry::WrappedModule).should == true
++ m.source.should =~ /piggy/
++ end
++
++ it 'should look up methods before classes when ending in () (at top-level)' do
++ m = Pry::CodeObject.lookup("ClassyWassy()", @p)
++ m.is_a?(Pry::Method).should == true
++ m.source.should =~ /ducky/
++ end
++
++ it 'should look up classes before methods when namespaced' do
++ m = Pry::CodeObject.lookup("ClassyWassy::Puff", @p)
++ m.is_a?(Pry::WrappedModule).should == true
++ m.source.should =~ /tiggy/
++ end
++
++ it 'should look up locals before methods' do
++ b = Pry.binding_for(ClassyWassy)
++ b.eval("piggy = Puff.new")
++ @p.binding_stack = [b]
++ o = Pry::CodeObject.lookup("piggy", @p)
++ o.is_a?(Pry::WrappedModule).should == true
++ end
++
++ # actually locals are never looked up (via co.default_lookup) when they're classes, it
++ # just falls through to co.method_or_class
++ it 'should look up classes before locals' do
++ c = ClassyWassy
++ @p.binding_stack = [binding]
++ o = Pry::CodeObject.lookup("c", @p)
++ o.is_a?(Pry::WrappedModule).should == true
++ o.wrapped.should == ClassyWassy
++ end
++ end
++end
+diff --git a/spec/code_spec.rb b/spec/code_spec.rb
+new file mode 100644
+index 0000000..d9fad6d
+--- /dev/null
++++ b/spec/code_spec.rb
+@@ -0,0 +1,256 @@
++require_relative 'helper'
++
++describe Pry::Code do
++ describe '.from_file' do
++ should 'read lines from a file on disk' do
++ Pry::Code.from_file('lib/pry.rb').length.should > 0
++ end
++
++ should 'read lines from Pry\'s line buffer' do
++ pry_eval ':hay_guys'
++ Pry::Code.from_file('(pry)').grep(/:hay_guys/).length.should == 1
++ end
++
++ should 'default to unknown' do
++ temp_file('') do |f|
++ Pry::Code.from_file(f.path).code_type.should == :unknown
++ end
++ end
++
++ should 'check the extension' do
++ temp_file('.c') do |f|
++ Pry::Code.from_file(f.path).code_type.should == :c
++ end
++ end
++
++ should 'raise an error if the file doesn\'t exist' do
++ proc do
++ Pry::Code.from_file('/knalkjsdnalsd/alkjdlkq')
++ end.should.raise(MethodSource::SourceNotFoundError)
++ end
++
++ should 'check for files relative to origin pwd' do
++ Dir.chdir('spec') do |f|
++ Pry::Code.from_file('spec/' + File.basename(__FILE__)).code_type.should == :ruby
++ end
++ end
++
++ should 'check for Ruby files relative to origin pwd with `.rb` omitted' do
++ Dir.chdir('spec') do |f|
++ Pry::Code.from_file('spec/' + File.basename(__FILE__, '.*')).code_type.should == :ruby
++ end
++ end
++
++ should 'find files that are relative to the current working directory' do
++ Dir.chdir('spec') do |f|
++ Pry::Code.from_file(File.basename(__FILE__)).code_type.should == :ruby
++ end
++ end
++
++ describe 'find Ruby files relative to $LOAD_PATH' do
++ before do
++ $LOAD_PATH << 'spec/fixtures'
++ end
++
++ after do
++ $LOAD_PATH.delete 'spec/fixtures'
++ end
++
++ it 'finds files with `.rb` extension' do
++ Pry::Code.from_file('slinky.rb').code_type.should == :ruby
++ end
++
++ it 'finds files with `.rb` omitted' do
++ Pry::Code.from_file('slinky').code_type.should == :ruby
++ end
++
++ it 'finds files in a relative directory with `.rb` extension' do
++ Pry::Code.from_file('../helper.rb').code_type.should == :ruby
++ end
++
++ it 'finds files in a relative directory with `.rb` omitted' do
++ Pry::Code.from_file('../helper').code_type.should == :ruby
++ end
++
++ it "doesn't confuse files with the same name, but without an extension" do
++ Pry::Code.from_file('cat_load_path').code_type.should == :unknown
++ end
++
++ it "doesn't confuse files with the same name, but with an extension" do
++ Pry::Code.from_file('cat_load_path.rb').code_type.should == :ruby
++ end
++ end
++ end
++
++ describe '.from_method' do
++ should 'read lines from a method\'s definition' do
++ m = Pry::Method.from_obj(Pry, :load_history)
++ Pry::Code.from_method(m).length.should > 0
++ end
++ end
++
++ describe '#initialize' do
++ before do
++ @str = Pry::Helpers::CommandHelpers.unindent <<-CODE
++ def hay
++ :guys
++ end
++ CODE
++
++ @array = ['def hay', ' :guys', 'end']
++ end
++
++ should 'break a string into lines' do
++ Pry::Code.new(@str).length.should == 3
++ end
++
++ should 'accept an array' do
++ Pry::Code.new(@array).length.should == 3
++ end
++
++ it 'an array or string should produce an equivalent object' do
++ Pry::Code.new(@str).should == Pry::Code.new(@array)
++ end
++ end
++
++ describe 'filters and formatters' do
++ def raw(str)
++ Pry::Helpers::Text.strip_color(str)
++ end
++ before do
++ @code = Pry::Code(Pry::Helpers::CommandHelpers.unindent <<-STR)
++ class MyProgram
++ def self.main
++ puts 'Hello, world!'
++ end
++ end
++ STR
++ end
++
++ describe 'filters' do
++ describe '#between' do
++ should 'work with an inclusive range' do
++ @code = @code.between(1..3)
++ @code.length.should == 3
++ raw(@code).should =~ /\Aclass MyProgram/
++ raw(@code).should =~ /world!'\Z/
++ end
++
++ should 'default to an inclusive range' do
++ @code = @code.between(3, 5)
++ @code.length.should == 3
++ end
++
++ should 'work with an exclusive range' do
++ @code = @code.between(2...4)
++ @code.length.should == 2
++ raw(@code).should =~ /\A def self/
++ raw(@code).should =~ /world!'\Z/
++ end
++
++ should 'use real line numbers for positive indices' do
++ @code = @code.after(3, 3)
++ @code = @code.between(4, 4)
++ @code.length.should == 1
++ raw(@code).should =~ /\A end\Z/
++ end
++ end
++
++ describe '#before' do
++ should 'work' do
++ @code = @code.before(3, 1)
++ raw(@code).should =~ /\A def self\.main\Z/
++ end
++ end
++
++ describe '#around' do
++ should 'work' do
++ @code = @code.around(3, 1)
++ @code.length.should == 3
++ raw(@code).should =~ /\A def self/
++ raw(@code).should =~ / end\Z/
++ end
++ end
++
++ describe '#after' do
++ should 'work' do
++ @code = @code.after(3, 1)
++ raw(@code).should =~ /\A end\Z/
++ end
++ end
++
++ describe '#grep' do
++ should 'work' do
++ @code = @code.grep(/end/)
++ @code.length.should == 2
++ end
++ end
++ end
++
++ describe 'formatters' do
++ describe '#with_line_numbers' do
++ should 'show line numbers' do
++ @code = @code.with_line_numbers
++ @code.should =~ /1:/
++ end
++
++ should 'disable line numbers when falsy' do
++ @code = @code.with_line_numbers
++ @code = @code.with_line_numbers(false)
++ @code.should.not =~ /1:/
++ end
++ end
++
++ describe '#with_marker' do
++ should 'show a marker in the right place' do
++ @code = @code.with_marker(2)
++ raw(@code).should =~ /^ => def self/
++ end
++
++ should 'disable the marker when falsy' do
++ @code = @code.with_marker(2)
++ @code = @code.with_marker(false)
++ raw(@code).should =~ /^ def self/
++ end
++ end
++
++ describe '#with_indentation' do
++ should 'indent the text' do
++ @code = @code.with_indentation(2)
++ raw(@code).should =~ /^ def self/
++ end
++
++ should 'disable the indentation when falsy' do
++ @code = @code.with_indentation(2)
++ @code = @code.with_indentation(false)
++ raw(@code).should =~ /^ def self/
++ end
++ end
++ end
++
++ describe 'composition' do
++ describe 'grep and with_line_numbers' do
++ should 'work' do
++ @code = @code.grep(/end/).with_line_numbers
++ raw(@code).should =~ /\A4: end/
++ raw(@code).should =~ /5: end\Z/
++ end
++ end
++
++ describe 'grep and before and with_line_numbers' do
++ should 'work' do
++ @code = @code.grep(/e/).before(5, 5).with_line_numbers
++ raw(@code).should =~ /\A2: def self.main\n3:/
++ raw(@code).should =~ /4: end\Z/
++ end
++ end
++
++ describe 'before and after' do
++ should 'work' do
++ @code = @code.before(4, 2).after(2)
++ raw(@code).should == " puts 'Hello, world!'\n"
++ end
++ end
++ end
++ end
++end
+diff --git a/spec/command_helpers_spec.rb b/spec/command_helpers_spec.rb
+new file mode 100644
+index 0000000..2cbee84
+--- /dev/null
++++ b/spec/command_helpers_spec.rb
+@@ -0,0 +1,29 @@
++require_relative 'helper'
++
++describe Pry::Helpers::CommandHelpers do
++ before do
++ @helper = Pry::Helpers::CommandHelpers
++ end
++
++ describe "unindent" do
++ it "should remove the same prefix from all lines" do
++ @helper.unindent(" one\n two\n").should == "one\ntwo\n"
++ end
++
++ it "should not be phased by empty lines" do
++ @helper.unindent(" one\n\n two\n").should == "one\n\ntwo\n"
++ end
++
++ it "should only remove a common prefix" do
++ @helper.unindent(" one\n two\n").should == " one\ntwo\n"
++ end
++
++ it "should also remove tabs if present" do
++ @helper.unindent("\tone\n\ttwo\n").should == "one\ntwo\n"
++ end
++
++ it "should ignore lines starting with --" do
++ @helper.unindent(" one\n--\n two\n").should == "one\n--\ntwo\n"
++ end
++ end
++end
+diff --git a/spec/command_integration_spec.rb b/spec/command_integration_spec.rb
+new file mode 100644
+index 0000000..d8707fa
+--- /dev/null
++++ b/spec/command_integration_spec.rb
+@@ -0,0 +1,564 @@
++require_relative 'helper'
++
++
++describe "commands" do
++ before do
++ @str_output = StringIO.new
++ @o = Object.new
++
++ # Shortcuts. They save a lot of typing.
++ @bs1 = "Pad.bs1 = _pry_.binding_stack.dup"
++ @bs2 = "Pad.bs2 = _pry_.binding_stack.dup"
++ @bs3 = "Pad.bs3 = _pry_.binding_stack.dup"
++
++ @self = "Pad.self = self"
++
++ @command_tester = Pry::CommandSet.new do
++ command "command1", "command 1 test" do
++ output.puts "command1"
++ end
++
++ command "command2", "command 2 test" do |arg|
++ output.puts arg
++ end
++ end
++
++ Pad.bong = "bong"
++ end
++
++ after do
++ Pad.clear
++ Pry.reset_defaults
++ end
++
++ describe "alias_command" do
++ it 'should make an aliasd command behave like its original' do
++ set = Pry::CommandSet.new do
++ command "test-command" do
++ output.puts "testing 1, 2, 3"
++ end
++ alias_command "test-alias", "test-command"
++ end
++
++ pry_tester(:commands => set).tap do |t|
++ t.eval('test-command').should == t.eval('test-alias')
++ end
++ end
++
++ it 'should pass on arguments to original' do
++ set = Pry::CommandSet.new do
++ command "test-command" do |*args|
++ output.puts "testing #{args.join(' ')}"
++ end
++ alias_command "test-alias", "test-command"
++ end
++
++ t = pry_tester(:commands => set)
++
++ t.process_command "test-alias hello baby duck"
++ t.last_output.should =~ /testing hello baby duck/
++ end
++
++ it 'should pass option arguments to original' do
++ set = Pry::CommandSet.new do
++ import Pry::Commands
++ alias_command "test-alias", "ls"
++ end
++
++ obj = Class.new { @x = 10 }
++ t = pry_tester(obj, :commands => set)
++
++ t.process_command "test-alias -i"
++ t.last_output.should =~ /@x/
++ end
++
++ it 'should pass option arguments to original with additional parameters' do
++ set = Pry::CommandSet.new do
++ import Pry::Commands
++ alias_command "test-alias", "ls -M"
++ end
++
++ obj = Class.new { @x = Class.new { define_method(:plymouth) {} } }
++ t = pry_tester(obj, :commands => set)
++ t.process_command "test-alias @x"
++ t.last_output.should =~ /plymouth/
++ end
++
++ it 'should be able to alias a regex command' do
++ set = Pry::CommandSet.new do
++ command /du.k/ do
++ output.puts "ducky"
++ end
++ alias_command "test-alias", "duck"
++ end
++
++ t = pry_tester(:commands => set)
++ t.process_command "test-alias"
++ t.last_output.should =~ /ducky/
++ end
++
++ it 'should be able to make the alias a regex' do
++ set = Pry::CommandSet.new do
++ command /du.k/ do
++ output.puts "ducky"
++ end
++ alias_command /test-ali.s/, "duck"
++ end
++
++ redirect_pry_io(InputTester.new("test-alias"), out1 = StringIO.new) do
++ Pry.start self, :commands => set
++ end
++
++ out1.string.should =~ /ducky/
++ end
++ end
++
++ describe "Pry::Command#run" do
++ it 'should allow running of commands with following whitespace' do
++ set = Pry::CommandSet.new do
++ import Pry::Commands
++ command "test-run" do
++ run "cd / "
++ end
++ end
++
++ redirect_pry_io(InputTester.new("cd 1/2/3/4/5/6", @bs1, "test-run",
++ @self, @bs2, "exit-all")) do
++ Pry.start(@o, :commands => set)
++ end
++
++ Pad.bs1.size.should == 7
++ Pad.self.should == @o
++ Pad.bs2.size.should == 1
++ end
++
++ it 'should allow running of cd command when contained in a single string' do
++ set = Pry::CommandSet.new do
++ import Pry::Commands
++ command "test-run" do
++ run "cd /"
++ end
++ end
++ redirect_pry_io(InputTester.new("cd 1/2/3/4/5/6", @bs1, "test-run",
++ @self, @bs2, "exit-all")) do
++ Pry.start(@o, :commands => set)
++ end
++
++ Pad.bs1.size.should == 7
++ Pad.self.should == @o
++ Pad.bs2.size.should == 1
++ end
++
++ it 'should allow running of cd command when split into array' do
++ set = Pry::CommandSet.new do
++ import Pry::Commands
++ command "test-run" do
++ run "cd", "/"
++ end
++ end
++ redirect_pry_io(InputTester.new("cd 1/2/3/4/5/6", @bs1, "test-run",
++ @self, @bs2, "exit-all")) do
++ Pry.start(@o, :commands => set)
++ end
++
++ Pad.bs1.size.should == 7
++ Pad.self.should == @o
++ Pad.bs2.size.should == 1
++ end
++
++ it 'should run a command from within a command' do
++ klass = Pry::CommandSet.new do
++ command "v" do
++ output.puts "v command"
++ end
++
++ command "run_v" do
++ run "v"
++ end
++ end
++
++ pry_tester(:commands => klass).eval('run_v').should =~ /v command/
++ end
++
++ it 'should run a regex command from within a command' do
++ klass = Pry::CommandSet.new do
++ command /v(.*)?/ do |arg|
++ output.puts "v #{arg}"
++ end
++
++ command "run_v" do
++ run "vbaby"
++ end
++ end
++
++ pry_tester(:commands => klass).eval('run_v').should =~ /v baby/
++ end
++
++ it 'should run a command from within a command with arguments' do
++ klass = Pry::CommandSet.new do
++ command /v(\w+)/ do |arg1, arg2|
++ output.puts "v #{arg1} #{arg2}"
++ end
++
++ command "run_v_explicit_parameter" do
++ run "vbaby", "param"
++ end
++
++ command "run_v_embedded_parameter" do
++ run "vbaby param"
++ end
++ end
++
++ ["run_v_explicit_parameter", "run_v_embedded_parameter"].each do |cmd|
++ pry_tester(:commands => klass).eval(cmd).should =~ /v baby param/
++ end
++ end
++ end
++
++ describe "Pry#run_command" do
++ it 'should run a command that modifies the passed in eval_string' do
++ p = Pry.new(:output => @str_output)
++ p.eval "def hello\npeter pan\n"
++ p.run_command "amend-line !"
++ p.eval_string.should =~ /def hello/
++ p.eval_string.should.not =~ /peter pan/
++ end
++
++ it 'should run a command in the context of a session' do
++ pry_tester(Object.new).tap do |t|
++ t.eval "@session_ivar = 10", "_pry_.run_command('ls')"
++ t.last_output.should =~ /@session_ivar/
++ end
++ end
++ end
++
++ it 'should interpolate ruby code into commands' do
++ set = Pry::CommandSet.new do
++ command "hello", "", :keep_retval => true do |arg|
++ arg
++ end
++ end
++
++ pry_tester(:commands => set).eval('hello #{Pad.bong}').should =~ /bong/
++ end
++
++ # bug fix for https://github.com/pry/pry/issues/170
++ it 'should not choke on complex string interpolation when checking if ruby code is a command' do
++ redirect_pry_io(InputTester.new('/#{Regexp.escape(File.expand_path("."))}/'), @str_output) do
++ pry
++ end
++
++ @str_output.string.should.not =~ /SyntaxError/
++ end
++
++ it 'should NOT interpolate ruby code into commands if :interpolate => false' do
++ set = Pry::CommandSet.new do
++ command "hello", "", :keep_retval => true, :interpolate => false do |arg|
++ arg
++ end
++ end
++
++ pry_tester(:commands => set).eval('hello #{Pad.bong}').
++ should =~ /Pad\.bong/
++ end
++
++ it 'should NOT try to interpolate pure ruby code (no commands) ' do
++ # These should raise RuntimeError instead of NameError
++ proc {
++ pry_eval 'raise \'#{aggy}\''
++ }.should.raise(RuntimeError)
++
++ proc {
++ pry_eval 'raise #{aggy}'
++ }.should.raise(RuntimeError)
++
++ pry_eval('format \'#{my_var}\'').should == "\#{my_var}"
++ end
++
++ it 'should create a command with a space in its name zzz' do
++ set = Pry::CommandSet.new do
++ command "hello baby", "" do
++ output.puts "hello baby command"
++ end
++ end
++
++ pry_tester(:commands => set).eval('hello baby').
++ should =~ /hello baby command/
++ end
++
++ it 'should create a command with a space in its name and pass an argument' do
++ set = Pry::CommandSet.new do
++ command "hello baby", "" do |arg|
++ output.puts "hello baby command #{arg}"
++ end
++ end
++
++ pry_tester(:commands => set).eval('hello baby john').
++ should =~ /hello baby command john/
++ end
++
++ it 'should create a regex command and be able to invoke it' do
++ set = Pry::CommandSet.new do
++ command /hello(.)/, "" do
++ c = captures.first
++ output.puts "hello#{c}"
++ end
++ end
++
++ pry_tester(:commands => set).eval('hello1').should =~ /hello1/
++ end
++
++ it 'should create a regex command and pass captures into the args list before regular arguments' do
++ set = Pry::CommandSet.new do
++ command /hello(.)/, "" do |c1, a1|
++ output.puts "hello #{c1} #{a1}"
++ end
++ end
++
++ pry_tester(:commands => set).eval('hello1 baby').should =~ /hello 1 baby/
++ end
++
++ it 'should create a regex command and interpolate the captures' do
++ set = Pry::CommandSet.new do
++ command /hello (.*)/, "" do |c1|
++ output.puts "hello #{c1}"
++ end
++ end
++
++ bong = "bong"
++ pry_tester(binding, :commands => set).eval('hello #{bong}').
++ should =~ /hello bong/
++ end
++
++ it 'should create a regex command and arg_string should be interpolated' do
++ set = Pry::CommandSet.new do
++ command /hello(\w+)/, "" do |c1, a1, a2, a3|
++ output.puts "hello #{c1} #{a1} #{a2} #{a3}"
++ end
++ end
++
++ bing = 'bing'
++ bong = 'bong'
++ bang = 'bang'
++
++ pry_tester(binding, :commands => set).
++ eval('hellojohn #{bing} #{bong} #{bang}').
++ should =~ /hello john bing bong bang/
++ end
++
++ it 'if a regex capture is missing it should be nil' do
++ set = Pry::CommandSet.new do
++ command /hello(.)?/, "" do |c1, a1|
++ output.puts "hello #{c1.inspect} #{a1}"
++ end
++ end
++
++ pry_tester(:commands => set).eval('hello baby').should =~ /hello nil baby/
++ end
++
++ it 'should create a command in a nested context and that command should be accessible from the parent' do
++ pry_tester(Object.new).eval(*(<<-RUBY.split("\n"))).should =~ /instance variables:\s+ at x/m
++ @x = nil
++ cd 7
++ _pry_.commands.instance_eval { command('bing') { |arg| run arg } }
++ cd ..
++ bing ls
++ RUBY
++ end
++
++ it 'should define a command that keeps its return value' do
++ klass = Pry::CommandSet.new do
++ command "hello", "", :keep_retval => true do
++ :kept_hello
++ end
++ end
++
++ t = pry_tester(:commands => klass)
++ t.eval("hello\n")
++ t.last_command_result.should == :kept_hello
++ end
++
++ it 'should define a command that does NOT keep its return value' do
++ klass = Pry::CommandSet.new do
++ command "hello", "", :keep_retval => false do
++ :kept_hello
++ end
++ end
++
++ t = pry_tester(:commands => klass)
++ t.eval("hello\n").should == ''
++ t.last_command_result.should == Pry::Command::VOID_VALUE
++ end
++
++ it 'should define a command that keeps its return value even when nil' do
++ klass = Pry::CommandSet.new do
++ command "hello", "", :keep_retval => true do
++ nil
++ end
++ end
++
++ t = pry_tester(:commands => klass)
++ t.eval("hello\n")
++ t.last_command_result.should == nil
++ end
++
++ it 'should define a command that keeps its return value but does not return when value is void' do
++ klass = Pry::CommandSet.new do
++ command "hello", "", :keep_retval => true do
++ void
++ end
++ end
++
++ pry_tester(:commands => klass).eval("hello\n").empty?.should == true
++ end
++
++ it 'a command (with :keep_retval => false) that replaces eval_string with a valid expression should not have the expression value suppressed' do
++ klass = Pry::CommandSet.new do
++ command "hello", "" do
++ eval_string.replace("6")
++ end
++ end
++
++ output = StringIO.new
++
++ redirect_pry_io(InputTester.new('def yo', 'hello'), output) do
++ Pry.start self, :commands => klass
++ end
++
++ output.string.should =~ /6/
++ end
++
++ it 'a command (with :keep_retval => true) that replaces eval_string with a valid expression should overwrite the eval_string with the return value' do
++ klass = Pry::CommandSet.new do
++ command "hello", "", :keep_retval => true do
++ eval_string.replace("6")
++ 7
++ end
++ end
++
++ pry_tester(:commands => klass).eval("def yo\nhello\n").should == 7
++ end
++
++ it 'a command that return a value in a multi-line expression should clear the expression and return the value' do
++ klass = Pry::CommandSet.new do
++ command "hello", "", :keep_retval => true do
++ 5
++ end
++ end
++
++ pry_tester(:commands => klass).eval("def yo\nhello\n").should == 5
++ end
++
++ it 'should set the commands default, and the default should be overridable' do
++ klass = Pry::CommandSet.new do
++ command "hello" do
++ output.puts "hello world"
++ end
++ end
++
++ other_klass = Pry::CommandSet.new do
++ command "goodbye", "" do
++ output.puts "goodbye world"
++ end
++ end
++
++ Pry.config.commands = klass
++ pry_tester.eval("hello").should == "hello world\n"
++ pry_tester(:commands => other_klass).eval("goodbye").should == "goodbye world\n"
++ end
++
++ it 'should inherit commands from Pry::Commands' do
++ klass = Pry::CommandSet.new Pry::Commands do
++ command "v" do
++ end
++ end
++
++ klass.to_hash.include?("nesting").should == true
++ klass.to_hash.include?("jump-to").should == true
++ klass.to_hash.include?("cd").should == true
++ klass.to_hash.include?("v").should == true
++ end
++
++ it 'should change description of a command using desc' do
++ klass = Pry::CommandSet.new do
++ import Pry::Commands
++ end
++ orig = klass["help"].description
++ klass.instance_eval do
++ desc "help", "blah"
++ end
++ commands = klass.to_hash
++ commands["help"].description.should.not == orig
++ commands["help"].description.should == "blah"
++ end
++
++ it 'should enable an inherited method to access opts and output and target, due to instance_exec' do
++ klass = Pry::CommandSet.new do
++ command "v" do
++ output.puts "#{target.eval('self')}"
++ end
++ end
++
++ child_klass = Pry::CommandSet.new klass do
++ end
++
++ mock_pry(Pry.binding_for('john'), "v", :print => proc {}, :commands => child_klass,
++ :output => @str_output)
++
++ @str_output.string.should == "john\n"
++ end
++
++ it 'should import commands from another command object' do
++ klass = Pry::CommandSet.new do
++ import_from Pry::Commands, "ls", "jump-to"
++ end
++
++ klass.to_hash.include?("ls").should == true
++ klass.to_hash.include?("jump-to").should == true
++ end
++
++ it 'should delete some inherited commands when using delete method' do
++ klass = Pry::CommandSet.new Pry::Commands do
++ command "v" do
++ end
++
++ delete "show-doc", "show-method"
++ delete "ls"
++ end
++
++ commands = klass.to_hash
++ commands.include?("nesting").should == true
++ commands.include?("jump-to").should == true
++ commands.include?("cd").should == true
++ commands.include?("v").should == true
++ commands.include?("show-doc").should == false
++ commands.include?("show-method").should == false
++ commands.include?("ls").should == false
++ end
++
++ it 'should override some inherited commands' do
++ klass = Pry::CommandSet.new Pry::Commands do
++ command "jump-to" do
++ output.puts "jump-to the music"
++ end
++
++ command "help" do
++ output.puts "help to the music"
++ end
++ end
++
++ t = pry_tester(:commands => klass)
++ t.eval('jump-to').should == "jump-to the music\n"
++ t.eval('help').should == "help to the music\n"
++ end
++
++ it 'should run a command with no parameter' do
++ pry_tester(:commands => @command_tester).eval('command1').
++ should == "command1\n"
++ end
++
++ it 'should run a command with one parameter' do
++ pry_tester(:commands => @command_tester).eval('command2 horsey').
++ should == "horsey\n"
++ end
++end
+diff --git a/spec/command_set_spec.rb b/spec/command_set_spec.rb
+new file mode 100644
+index 0000000..8e7eee3
+--- /dev/null
++++ b/spec/command_set_spec.rb
+@@ -0,0 +1,676 @@
++require_relative 'helper'
++
++describe Pry::CommandSet do
++ before do
++ @set = Pry::CommandSet.new do
++ import Pry::Commands
++ end
++
++ @ctx = {
++ :target => binding,
++ :command_set => @set,
++ :pry_instance => Pry.new(output: StringIO.new)
++ }
++ end
++
++ describe "[]=" do
++ it "removes a command from the command set" do
++ @set["help"].should.not == nil
++ @set["help"] = nil
++ @set["help"].should == nil
++ lambda { @set.run_command(TOPLEVEL_BINDING, "help") }.should.raise Pry::NoCommandError
++ end
++
++ it "replaces a command" do
++ old_help = @set["help"]
++ @set["help"] = @set["pry-version"]
++ @set["help"].should.not == old_help
++ end
++
++ it "rebinds the command with key" do
++ @set["help-1"] = @set["help"]
++ @set["help-1"].match.should == "help-1"
++ end
++
++ it "raises a TypeError when command is not a subclass of Pry::Command" do
++ lambda { @set["help"] = "hello" }.should.raise TypeError
++ end
++ end
++
++ it 'should call the block used for the command when it is called' do
++ run = false
++ @set.command 'foo' do
++ run = true
++ end
++
++ @set.run_command @ctx, 'foo'
++ run.should == true
++ end
++
++ it 'should pass arguments of the command to the block' do
++ @set.command 'foo' do |*args|
++ args.should == [1, 2, 3]
++ end
++
++ @set.run_command @ctx, 'foo', 1, 2, 3
++ end
++
++ it 'should use the first argument as context' do
++ ctx = @ctx
++
++ @set.command 'foo' do
++ self.context.should == ctx
++ end
++
++ @set.run_command @ctx, 'foo'
++ end
++
++ it 'should raise an error when calling an undefined command' do
++ @set.command('foo') {}
++ lambda {
++ @set.run_command @ctx, 'bar'
++ }.should.raise(Pry::NoCommandError)
++ end
++
++ it 'should be able to remove its own commands' do
++ @set.command('foo') {}
++ @set.delete 'foo'
++
++ lambda {
++ @set.run_command @ctx, 'foo'
++ }.should.raise(Pry::NoCommandError)
++ end
++
++ it 'should be able to remove its own commands, by listing name' do
++ @set.command(/^foo1/, 'desc', :listing => 'foo') {}
++ @set.delete 'foo'
++
++ lambda {
++ @set.run_command @ctx, /^foo1/
++ }.should.raise(Pry::NoCommandError)
++ end
++
++ it 'should be able to import some commands from other sets' do
++ run = false
++
++ other_set = Pry::CommandSet.new do
++ command('foo') { run = true }
++ command('bar') {}
++ end
++
++ @set.import_from(other_set, 'foo')
++
++ @set.run_command @ctx, 'foo'
++ run.should == true
++
++ lambda {
++ @set.run_command @ctx, 'bar'
++ }.should.raise(Pry::NoCommandError)
++ end
++
++ it 'should return command set after import' do
++ run = false
++
++ other_set = Pry::CommandSet.new do
++ command('foo') { run = true }
++ command('bar') {}
++ end
++
++ @set.import(other_set).should == @set
++ end
++
++ it 'should return command set after import_from' do
++ run = false
++
++ other_set = Pry::CommandSet.new do
++ command('foo') { run = true }
++ command('bar') {}
++ end
++
++ @set.import_from(other_set, 'foo').should == @set
++ end
++
++ it 'should be able to import some commands from other sets using listing name' do
++ run = false
++
++ other_set = Pry::CommandSet.new do
++ command(/^foo1/, 'desc', :listing => 'foo') { run = true }
++ end
++
++ @set.import_from(other_set, 'foo')
++
++ @set.run_command @ctx, /^foo1/
++ run.should == true
++ end
++
++ it 'should be able to import a whole set' do
++ run = []
++
++ other_set = Pry::CommandSet.new do
++ command('foo') { run << true }
++ command('bar') { run << true }
++ end
++
++ @set.import other_set
++
++ @set.run_command @ctx, 'foo'
++ @set.run_command @ctx, 'bar'
++ run.should == [true, true]
++ end
++
++ it 'should be able to import sets at creation' do
++ run = false
++ @set.command('foo') { run = true }
++
++ Pry::CommandSet.new(@set).run_command @ctx, 'foo'
++ run.should == true
++ end
++
++ it 'should set the descriptions of commands' do
++ @set.command('foo', 'some stuff') {}
++ @set['foo'].description.should == 'some stuff'
++ end
++
++ describe "aliases" do
++ it 'should be able to alias command' do
++ run = false
++ @set.command('foo', 'stuff') { run = true }
++
++ @set.alias_command 'bar', 'foo'
++ @set['bar'].match.should == 'bar'
++ @set['bar'].description.should == 'Alias for `foo`'
++
++ @set.run_command @ctx, 'bar'
++ run.should == true
++ end
++
++ it "should be able to alias command with command_prefix" do
++ run = false
++
++ begin
++ @set.command('owl', 'stuff') { run = true }
++ @set.alias_command 'owlet', 'owl'
++
++ Pry.config.command_prefix = '%'
++ @set['%owlet'].match.should == 'owlet'
++ @set['%owlet'].description.should == 'Alias for `owl`'
++
++ @set.run_command @ctx, 'owlet'
++ run.should == true
++ ensure
++ Pry.config.command_prefix = ''
++ end
++ end
++
++ it 'should inherit options from original command' do
++ run = false
++ @set.command('foo', 'stuff', :shellwords => true, :interpolate => false) { run = true }
++
++ @set.alias_command 'bar', 'foo'
++ @set['bar'].options[:shellwords].should == @set['foo'].options[:shellwords]
++ @set['bar'].options[:interpolate].should == @set['foo'].options[:interpolate]
++
++ # however some options should not be inherited
++ @set['bar'].options[:listing].should.not == @set['foo'].options[:listing]
++ @set['bar'].options[:listing].should == "bar"
++ end
++
++ it 'should be able to specify alias\'s description when aliasing' do
++ run = false
++ @set.command('foo', 'stuff') { run = true }
++
++ @set.alias_command 'bar', 'foo', :desc => "tobina"
++ @set['bar'].match.should == 'bar'
++ @set['bar'].description.should == "tobina"
++
++ @set.run_command @ctx, 'bar'
++ run.should == true
++ end
++
++ it "should be able to alias a command by its invocation line" do
++ run = false
++ @set.command(/^foo1/, 'stuff', :listing => 'foo') { run = true }
++
++ @set.alias_command 'bar', 'foo1'
++ @set['bar'].match.should == 'bar'
++ @set['bar'].description.should == 'Alias for `foo1`'
++
++ @set.run_command @ctx, 'bar'
++ run.should == true
++ end
++
++ it "should be able to specify options when creating alias" do
++ run = false
++ @set.command(/^foo1/, 'stuff', :listing => 'foo') { run = true }
++
++ @set.alias_command /^b.r/, 'foo1', :listing => "bar"
++ @set.to_hash[/^b.r/].options[:listing].should == "bar"
++ end
++
++ it "should set description to default if description parameter is nil" do
++ run = false
++ @set.command(/^foo1/, 'stuff', :listing => 'foo') { run = true }
++
++ @set.alias_command "bar", 'foo1'
++ @set["bar"].description.should == "Alias for `foo1`"
++ end
++ end
++
++ it 'should be able to change the descriptions of commands' do
++ @set.command('foo', 'bar') {}
++ @set.desc 'foo', 'baz'
++
++ @set['foo'].description.should == 'baz'
++ end
++
++ it 'should get the descriptions of commands' do
++ @set.command('foo', 'bar') {}
++ @set.desc('foo').should == 'bar'
++ end
++
++ it 'should get the descriptions of commands, by listing' do
++ @set.command(/^foo1/, 'bar', :listing => 'foo') {}
++ @set.desc('foo').should == 'bar'
++ end
++
++ it 'should return Pry::Command::VOID_VALUE for commands by default' do
++ @set.command('foo') { 3 }
++ @set.run_command(@ctx, 'foo').should == Pry::Command::VOID_VALUE
++ end
++
++ it 'should be able to keep return values' do
++ @set.command('foo', '', :keep_retval => true) { 3 }
++ @set.run_command(@ctx, 'foo').should == 3
++ end
++
++ it 'should be able to keep return values, even if return value is nil' do
++ @set.command('foo', '', :keep_retval => true) { nil }
++ @set.run_command(@ctx, 'foo').should == nil
++ end
++
++ it 'should be able to have its own helpers' do
++ @set.command('foo') do
++ should.respond_to :my_helper
++ end
++
++ @set.helpers do
++ def my_helper; end
++ end
++
++ @set.run_command(@ctx, 'foo')
++ Pry::Command.subclass('foo', '', {}, Module.new).new({:target => binding}).should.not.respond_to :my_helper
++ end
++
++ it 'should not recreate a new helper module when helpers is called' do
++ @set.command('foo') do
++ should.respond_to :my_helper
++ should.respond_to :my_other_helper
++ end
++
++ @set.helpers do
++ def my_helper; end
++ end
++
++ @set.helpers do
++ def my_other_helper; end
++ end
++
++ @set.run_command(@ctx, 'foo')
++ end
++
++ it 'should import helpers from imported sets' do
++ imported_set = Pry::CommandSet.new do
++ helpers do
++ def imported_helper_method; end
++ end
++ end
++
++ @set.import imported_set
++ @set.command('foo') { should.respond_to :imported_helper_method }
++ @set.run_command(@ctx, 'foo')
++ end
++
++ it 'should import helpers even if only some commands are imported' do
++ imported_set = Pry::CommandSet.new do
++ helpers do
++ def imported_helper_method; end
++ end
++
++ command('bar') {}
++ end
++
++ @set.import_from imported_set, 'bar'
++ @set.command('foo') { should.respond_to :imported_helper_method }
++ @set.run_command(@ctx, 'foo')
++ end
++
++ it 'should provide a :listing for a command that defaults to its name' do
++ @set.command 'foo', "" do;end
++ @set['foo'].options[:listing].should == 'foo'
++ end
++
++ it 'should provide a :listing for a command that differs from its name' do
++ @set.command 'foo', "", :listing => 'bar' do;end
++ @set['foo'].options[:listing].should == 'bar'
++ end
++
++ it "should provide a 'help' command" do
++ @ctx[:command_set] = @set
++ @ctx[:output] = StringIO.new
++
++ lambda {
++ @set.run_command(@ctx, 'help')
++ }.should.not.raise
++ end
++
++
++ describe "renaming a command" do
++ it 'should be able to rename and run a command' do
++ run = false
++ @set.command('foo') { run = true }
++ @set.rename_command('bar', 'foo')
++ @set.run_command(@ctx, 'bar')
++ run.should == true
++ end
++
++ it 'should accept listing name when renaming a command' do
++ run = false
++ @set.command('foo', "", :listing => 'love') { run = true }
++ @set.rename_command('bar', 'love')
++ @set.run_command(@ctx, 'bar')
++ run.should == true
++ end
++
++ it 'should raise exception trying to rename non-existent command' do
++ lambda { @set.rename_command('bar', 'foo') }.should.raise ArgumentError
++ end
++
++ it 'should make old command name inaccessible' do
++ @set.command('foo') { }
++ @set.rename_command('bar', 'foo')
++ lambda { @set.run_command(@ctx, 'foo') }.should.raise Pry::NoCommandError
++ end
++
++ it 'should be able to pass in options when renaming command' do
++ desc = "hello"
++ listing = "bing"
++ @set.command('foo') { }
++ @set.rename_command('bar', 'foo', :description => desc, :listing => listing, :keep_retval => true)
++ @set['bar'].description.should == desc
++ @set['bar'].options[:listing].should == listing
++ @set['bar'].options[:keep_retval].should == true
++ end
++ end
++
++ describe "command decorators - before_command and after_command" do
++ describe "before_command" do
++ it 'should be called before the original command' do
++ foo = []
++ @set.command('foo') { foo << 1 }
++ @set.before_command('foo') { foo << 2 }
++ @set.run_command(@ctx, 'foo')
++
++ foo.should == [2, 1]
++ end
++
++ it 'should be called before the original command, using listing name' do
++ foo = []
++ @set.command(/^foo1/, '', :listing => 'foo') { foo << 1 }
++ @set.before_command('foo') { foo << 2 }
++ @set.run_command(@ctx, /^foo1/)
++
++ foo.should == [2, 1]
++ end
++
++ it 'should share the context with the original command' do
++ @ctx[:target] = "test target string".__binding__
++ before_val = nil
++ orig_val = nil
++ @set.command('foo') { orig_val = target }
++ @set.before_command('foo') { before_val = target }
++ @set.run_command(@ctx, 'foo')
++
++ before_val.should == @ctx[:target]
++ orig_val.should == @ctx[:target]
++ end
++
++ it 'should work when applied multiple times' do
++ foo = []
++ @set.command('foo') { foo << 1 }
++ @set.before_command('foo') { foo << 2 }
++ @set.before_command('foo') { foo << 3 }
++ @set.before_command('foo') { foo << 4 }
++ @set.run_command(@ctx, 'foo')
++
++ foo.should == [4, 3, 2, 1]
++ end
++
++ end
++
++ describe "after_command" do
++ it 'should be called after the original command' do
++ foo = []
++ @set.command('foo') { foo << 1 }
++ @set.after_command('foo') { foo << 2 }
++ @set.run_command(@ctx, 'foo')
++
++ foo.should == [1, 2]
++ end
++
++ it 'should be called after the original command, using listing name' do
++ foo = []
++ @set.command(/^foo1/, '', :listing => 'foo') { foo << 1 }
++ @set.after_command('foo') { foo << 2 }
++ @set.run_command(@ctx, /^foo1/)
++
++ foo.should == [1, 2]
++ end
++
++ it 'should share the context with the original command' do
++ @ctx[:target] = "test target string".__binding__
++ after_val = nil
++ orig_val = nil
++ @set.command('foo') { orig_val = target }
++ @set.after_command('foo') { after_val = target }
++ @set.run_command(@ctx, 'foo')
++
++ after_val.should == @ctx[:target]
++ orig_val.should == @ctx[:target]
++ end
++
++ it 'should determine the return value for the command' do
++ @set.command('foo', 'bar', :keep_retval => true) { 1 }
++ @set.after_command('foo') { 2 }
++ @set.run_command(@ctx, 'foo').should == 2
++ end
++
++ it 'should work when applied multiple times' do
++ foo = []
++ @set.command('foo') { foo << 1 }
++ @set.after_command('foo') { foo << 2 }
++ @set.after_command('foo') { foo << 3 }
++ @set.after_command('foo') { foo << 4 }
++ @set.run_command(@ctx, 'foo')
++
++ foo.should == [1, 2, 3, 4]
++ end
++ end
++
++ describe "before_command and after_command" do
++ it 'should work when combining both before_command and after_command' do
++ foo = []
++ @set.command('foo') { foo << 1 }
++ @set.after_command('foo') { foo << 2 }
++ @set.before_command('foo') { foo << 3 }
++ @set.run_command(@ctx, 'foo')
++
++ foo.should == [3, 1, 2]
++ end
++
++ end
++
++ end
++
++ describe 'find_command' do
++ it 'should find commands with the right string' do
++ cmd = @set.command('rincewind'){ }
++ @set.find_command('rincewind').should == cmd
++ end
++
++ it 'should not find commands with spaces before' do
++ cmd = @set.command('luggage'){ }
++ @set.find_command(' luggage').should == nil
++ end
++
++ it 'should find commands with arguments after' do
++ cmd = @set.command('vetinari'){ }
++ @set.find_command('vetinari --knock 3').should == cmd
++ end
++
++ it 'should find commands with names containing spaces' do
++ cmd = @set.command('nobby nobbs'){ }
++ @set.find_command('nobby nobbs --steal petty-cash').should == cmd
++ end
++
++ it 'should find command defined by regex' do
++ cmd = @set.command(/(capt|captain) vimes/i){ }
++ @set.find_command('Capt Vimes').should == cmd
++ end
++
++ it 'should find commands defined by regex with arguments' do
++ cmd = @set.command(/(cpl|corporal) Carrot/i){ }
++ @set.find_command('cpl carrot --write-home').should == cmd
++ end
++
++ it 'should not find commands by listing' do
++ cmd = @set.command(/werewol(f|ve)s?/, 'only once a month', :listing => "angua"){ }
++ @set.find_command('angua').should == nil
++ end
++
++ it 'should not find commands without command_prefix' do
++ begin
++ Pry.config.command_prefix = '%'
++ cmd = @set.command('detritus'){ }
++ @set.find_command('detritus').should == nil
++ ensure
++ Pry.config.command_prefix = ''
++ end
++ end
++
++ it "should find commands that don't use the prefix" do
++ begin
++ Pry.config.command_prefix = '%'
++ cmd = @set.command('colon', 'Sergeant Fred', :use_prefix => false){ }
++ @set.find_command('colon').should == cmd
++ ensure
++ Pry.config.command_prefix = ''
++ end
++ end
++
++ it "should find the command that has the longest match" do
++ cmd = @set.command(/\.(.*)/){ }
++ cmd2 = @set.command(/\.\|\|(.*)/){ }
++ @set.find_command('.||').should == cmd2
++ end
++
++ it "should find the command that has the longest name" do
++ cmd = @set.command(/\.(.*)/){ }
++ cmd2 = @set.command('.||'){ }
++ @set.find_command('.||').should == cmd2
++ end
++ end
++
++ describe '.valid_command?' do
++ it 'should be true for commands that can be found' do
++ cmd = @set.command('archchancellor')
++ @set.valid_command?('archchancellor of_the?(:University)').should == true
++ end
++
++ it 'should be false for commands that can\'' do
++ @set.valid_command?('def monkey(ape)').should == false
++ end
++
++ it 'should not cause argument interpolation' do
++ cmd = @set.command('hello')
++ lambda {
++ @set.valid_command?('hello #{raise "futz"}')
++ }.should.not.raise
++ end
++ end
++
++ describe '.process_line' do
++
++ it 'should return Result.new(false) if there is no matching command' do
++ result = @set.process_line('1 + 42')
++ result.command?.should == false
++ result.void_command?.should == false
++ result.retval.should == nil
++ end
++
++ it 'should return Result.new(true, VOID) if the command is not keep_retval' do
++ @set.create_command('mrs-cake') do
++ def process; 42; end
++ end
++
++ result = @set.process_line('mrs-cake')
++ result.command?.should == true
++ result.void_command?.should == true
++ result.retval.should == Pry::Command::VOID_VALUE
++ end
++
++ it 'should return Result.new(true, retval) if the command is keep_retval' do
++ @set.create_command('magrat', 'the maiden', :keep_retval => true) do
++ def process; 42; end
++ end
++
++ result = @set.process_line('magrat')
++ result.command?.should == true
++ result.void_command?.should == false
++ result.retval.should == 42
++ end
++
++ it 'should pass through context' do
++ ctx = {
++ :eval_string => "bloomers",
++ :pry_instance => Object.new,
++ :output => StringIO.new,
++ :target => binding
++ }
++ @set.create_command('agnes') do
++ define_method(:process) do
++ eval_string.should == ctx[:eval_string]
++ output.should == ctx[:output]
++ target.should == ctx[:target]
++ _pry_.should == ctx[:pry_instance]
++ end
++ end
++
++ @set.process_line('agnes', ctx)
++ end
++
++ it 'should add command_set to context' do
++ set = @set
++ @set.create_command(/nann+y ogg+/) do
++ define_method(:process) do
++ command_set.should == set
++ end
++ end
++
++ @set.process_line('nannnnnny oggggg')
++ end
++ end
++
++ if defined?(Bond)
++ describe '.complete' do
++ it "should list all command names" do
++ @set.create_command('susan'){ }
++ @set.complete('sus').should.include 'susan '
++ end
++
++ it "should delegate to commands" do
++ @set.create_command('susan'){ def complete(search); ['--foo']; end }
++ @set.complete('susan ').should == ['--foo']
++ end
++ end
++ end
++end
+diff --git a/spec/command_spec.rb b/spec/command_spec.rb
+new file mode 100644
+index 0000000..f493f14
+--- /dev/null
++++ b/spec/command_spec.rb
+@@ -0,0 +1,819 @@
++require_relative 'helper'
++
++describe "Pry::Command" do
++
++ before do
++ @set = Pry::CommandSet.new
++ @set.import Pry::Commands
++ end
++
++ describe 'call_safely' do
++
++ it 'should display a message if gems are missing' do
++ cmd = @set.create_command "ford-prefect", "From a planet near Beetlegeuse", :requires_gem => %w(ghijkl) do
++ #
++ end
++
++ mock_command(cmd, %w(hello world)).output.should =~ /install-command ford-prefect/
++ end
++
++ it 'should abort early if arguments are required' do
++ cmd = @set.create_command 'arthur-dent', "Doesn't understand Thursdays", :argument_required => true do
++ #
++ end
++
++ lambda {
++ mock_command(cmd, %w())
++ }.should.raise(Pry::CommandError)
++ end
++
++ it 'should return VOID without keep_retval' do
++ cmd = @set.create_command 'zaphod-beeblebrox', "Likes pan-Galactic Gargle Blasters" do
++ def process
++ 3
++ end
++ end
++
++ mock_command(cmd).return.should == Pry::Command::VOID_VALUE
++ end
++
++ it 'should return the return value with keep_retval' do
++ cmd = @set.create_command 'tricia-mcmillian', "a.k.a Trillian", :keep_retval => true do
++ def process
++ 5
++ end
++ end
++
++ mock_command(cmd).return.should == 5
++ end
++
++ it 'should call hooks in the right order' do
++ cmd = @set.create_command 'marvin', "Pained by the diodes in his left side" do
++ def process
++ output.puts 3 + args[0].to_i
++ end
++ end
++
++ @set.before_command 'marvin' do |i|
++ output.puts 2 + i.to_i
++ end
++ @set.before_command 'marvin' do |i|
++ output.puts 1 + i.to_i
++ end
++
++ @set.after_command 'marvin' do |i|
++ output.puts 4 + i.to_i
++ end
++
++ @set.after_command 'marvin' do |i|
++ output.puts 5 + i.to_i
++ end
++
++ mock_command(cmd, %w(2)).output.should == "3\n4\n5\n6\n7\n"
++ end
++
++ # TODO: This strikes me as rather silly...
++ it 'should return the value from the last hook with keep_retval' do
++ cmd = @set.create_command 'slartibartfast', "Designs Fjords", :keep_retval => true do
++ def process
++ 22
++ end
++ end
++
++ @set.after_command 'slartibartfast' do
++ 10
++ end
++
++ mock_command(cmd).return.should == 10
++ end
++ end
++
++ describe 'help' do
++ it 'should default to the description for blocky commands' do
++ @set.command 'oolon-colluphid', "Raving Atheist" do
++ #
++ end
++
++ mock_command(@set['help'], %w(oolon-colluphid), :command_set => @set).output.should =~ /Raving Atheist/
++ end
++
++ it 'should use slop to generate the help for classy commands' do
++ @set.create_command 'eddie', "The ship-board computer" do
++ def options(opt)
++ opt.banner "Over-cheerful, and makes a ticking noise."
++ end
++ end
++
++ mock_command(@set['help'], %w(eddie), :command_set => @set).output.should =~ /Over-cheerful/
++ end
++
++ it 'should provide --help for classy commands' do
++ cmd = @set.create_command 'agrajag', "Killed many times by Arthur" do
++ def options(opt)
++ opt.on :r, :retaliate, "Try to get Arthur back"
++ end
++ end
++
++ mock_command(cmd, %w(--help)).output.should =~ /--retaliate/
++ end
++
++ it 'should provide a -h for classy commands' do
++ cmd = @set.create_command 'zarniwoop', "On an intergalactic cruise, in his office." do
++ def options(opt)
++ opt.on :e, :escape, "Help zaphod escape the Total Perspective Vortex"
++ end
++ end
++
++ mock_command(cmd, %w(--help)).output.should =~ /Total Perspective Vortex/
++ end
++
++ it 'should use the banner provided' do
++ cmd = @set.create_command 'deep-thought', "The second-best computer ever" do
++ banner <<-BANNER
++ Who's merest operational parameters, I am not worthy to compute.
++ BANNER
++ end
++
++ mock_command(cmd, %w(--help)).output.should =~ /Who\'s merest/
++ end
++ end
++
++ describe 'context' do
++ context = {
++ :target => binding,
++ :output => StringIO.new,
++ :eval_string => "eval-string",
++ :command_set => @set,
++ :pry_instance => Pry.new
++ }
++
++ it 'should capture lots of stuff from the hash passed to new before setup' do
++ cmd = @set.create_command 'fenchurch', "Floats slightly off the ground" do
++ define_method(:setup) do
++ self.context.should == context
++ target.should == context[:target]
++ target_self.should == context[:target].eval('self')
++ output.should == context[:output]
++ end
++
++ define_method(:process) do
++ eval_string.should == "eval-string"
++ command_set.should == @set
++ _pry_.should == context[:pry_instance]
++ end
++ end
++
++ cmd.new(context).call
++ end
++ end
++
++ describe 'classy api' do
++
++ it 'should call setup, then subcommands, then options, then process' do
++ cmd = @set.create_command 'rooster', "Has a tasty towel" do
++ def setup
++ output.puts "setup"
++ end
++
++ def subcommands(cmd)
++ output.puts "subcommands"
++ end
++
++ def options(opt)
++ output.puts "options"
++ end
++
++ def process
++ output.puts "process"
++ end
++ end
++
++ mock_command(cmd).output.should == "setup\nsubcommands\noptions\nprocess\n"
++ end
++
++ it 'should raise a command error if process is not overridden' do
++ cmd = @set.create_command 'jeltz', "Commander of a Vogon constructor fleet" do
++ def proccces
++ #
++ end
++ end
++
++ lambda {
++ mock_command(cmd)
++ }.should.raise(Pry::CommandError)
++ end
++
++ it 'should work if neither options, nor setup is overridden' do
++ cmd = @set.create_command 'wowbagger', "Immortal, insulting.", :keep_retval => true do
++ def process
++ 5
++ end
++ end
++
++ mock_command(cmd).return.should == 5
++ end
++
++ it 'should provide opts and args as provided by slop' do
++ cmd = @set.create_command 'lintilla', "One of 800,000,000 clones" do
++ def options(opt)
++ opt.on :f, :four, "A numeric four", :as => Integer, :optional_argument => true
++ end
++
++ def process
++ args.should == ['four']
++ opts[:f].should == 4
++ end
++ end
++
++ mock_command(cmd, %w(--four 4 four))
++ end
++
++ it 'should allow overriding options after definition' do
++ cmd = @set.create_command /number-(one|two)/, "Lieutenants of the Golgafrinchan Captain", :shellwords => false do
++
++ command_options :listing => 'number-one'
++ end
++
++ cmd.command_options[:shellwords].should == false
++ cmd.command_options[:listing].should == 'number-one'
++ end
++
++ it "should create subcommands" do
++ cmd = @set.create_command 'mum', 'Your mum' do
++ def subcommands(cmd)
++ cmd.command :yell
++ end
++
++ def process
++ opts.fetch_command(:blahblah).should == nil
++ opts.fetch_command(:yell).present?.should == true
++ end
++ end
++
++ mock_command(cmd, ['yell'])
++ end
++
++ it "should create subcommand options" do
++ cmd = @set.create_command 'mum', 'Your mum' do
++ def subcommands(cmd)
++ cmd.command :yell do
++ on :p, :person
++ end
++ end
++
++ def process
++ args.should == ['papa']
++ opts.fetch_command(:yell).present?.should == true
++ opts.fetch_command(:yell).person?.should == true
++ end
++ end
++
++ mock_command(cmd, %w|yell --person papa|)
++ end
++
++ it "should accept top-level arguments" do
++ cmd = @set.create_command 'mum', 'Your mum' do
++ def subcommands(cmd)
++ cmd.on :yell
++ end
++
++ def process
++ args.should == ['yell', 'papa', 'sonny', 'daughter']
++ end
++ end
++
++ mock_command(cmd, %w|yell papa sonny daughter|)
++ end
++
++ describe "explicit classes" do
++ before do
++ @x = Class.new(Pry::ClassCommand) do
++ options :baby => :pig
++ match /goat/
++ description "waaaninngggiiigygygygygy"
++ end
++ end
++
++ it 'subclasses should inherit options, match and description from superclass' do
++ k = Class.new(@x)
++ k.options.should == @x.options
++ k.match.should == @x.match
++ k.description.should == @x.description
++ end
++ end
++ end
++
++ describe 'tokenize' do
++ it 'should interpolate string with #{} in them' do
++ cmd = @set.command 'random-dent' do |*args|
++ args.should == ["3", "8"]
++ end
++
++ foo = 5
++
++ cmd.new(:target => binding).process_line 'random-dent #{1 + 2} #{3 + foo}'
++ end
++
++ it 'should not fail if interpolation is not needed and target is not set' do
++ cmd = @set.command 'the-book' do |*args|
++ args.should == ['--help']
++ end
++
++ cmd.new.process_line 'the-book --help'
++ end
++
++ it 'should not interpolate commands with :interpolate => false' do
++ cmd = @set.command 'thor', 'norse god', :interpolate => false do |*args|
++ args.should == ['%(#{foo})']
++ end
++
++ cmd.new.process_line 'thor %(#{foo})'
++ end
++
++ it 'should use shell-words to split strings' do
++ cmd = @set.command 'eccentrica' do |*args|
++ args.should == ['gallumbits', 'eroticon', '6']
++ end
++
++ cmd.new.process_line %(eccentrica "gallumbits" 'erot''icon' 6)
++ end
++
++ it 'should split on spaces if shellwords is not used' do
++ cmd = @set.command 'bugblatter-beast', 'would eat its grandmother', :shellwords => false do |*args|
++ args.should == ['"of', 'traal"']
++ end
++
++ cmd.new.process_line %(bugblatter-beast "of traal")
++ end
++
++ it 'should add captures to arguments for regex commands' do
++ cmd = @set.command /perfectly (normal)( beast)?/i do |*args|
++ args.should == ['Normal', ' Beast', '(honest!)']
++ end
++
++ cmd.new.process_line %(Perfectly Normal Beast (honest!))
++ end
++ end
++
++ describe 'process_line' do
++ it 'should check for command name collisions if configured' do
++ old = Pry.config.collision_warning
++ Pry.config.collision_warning = true
++
++ cmd = @set.command 'frankie' do
++
++ end
++
++ frankie = 'boyle'
++ output = StringIO.new
++ cmd.new(:target => binding, :output => output).process_line %(frankie mouse)
++
++ output.string.should =~ /command .* conflicts/
++
++ Pry.config.collision_warning = old
++ end
++
++ it 'should spot collision warnings on assignment if configured' do
++ old = Pry.config.collision_warning
++ Pry.config.collision_warning = true
++
++ cmd = @set.command 'frankie' do
++
++ end
++
++ output = StringIO.new
++ cmd.new(:target => binding, :output => output).process_line %(frankie = mouse)
++
++ output.string.should =~ /command .* conflicts/
++
++ Pry.config.collision_warning = old
++ end
++
++ it "should set the commands' arg_string and captures" do
++
++ cmd = @set.command /benj(ie|ei)/ do |*args|
++ self.arg_string.should == "mouse"
++ self.captures.should == ['ie']
++ args.should == ['ie', 'mouse']
++ end
++
++ cmd.new.process_line %(benjie mouse)
++ end
++
++ it "should raise an error if the line doesn't match the command" do
++ cmd = @set.command 'grunthos', 'the flatulent'
++
++ lambda {
++ cmd.new.process_line %(grumpos)
++ }.should.raise(Pry::CommandError)
++ end
++ end
++
++ describe "block parameters" do
++ before do
++ @context = Object.new
++ @set.command "walking-spanish", "down the hall", :takes_block => true do
++ PryTestHelpers.inject_var(:@x, command_block.call, target)
++ end
++ @set.import Pry::Commands
++
++ @t = pry_tester(@context, :commands => @set)
++ end
++
++ it 'should accept multiline blocks' do
++ @t.eval <<-EOS
++ walking-spanish | do
++ :jesus
++ end
++ EOS
++
++ @context.instance_variable_get(:@x).should == :jesus
++ end
++
++ it 'should accept normal parameters along with block' do
++ @set.block_command "walking-spanish",
++ "litella's been screeching for a blind pig.",
++ :takes_block => true do |x, y|
++ PryTestHelpers.inject_var(:@x, x, target)
++ PryTestHelpers.inject_var(:@y, y, target)
++ PryTestHelpers.inject_var(:@block_var, command_block.call, target)
++ end
++
++ @t.eval 'walking-spanish john carl| { :jesus }'
++
++ @context.instance_variable_get(:@x).should == "john"
++ @context.instance_variable_get(:@y).should == "carl"
++ @context.instance_variable_get(:@block_var).should == :jesus
++ end
++
++ describe "single line blocks" do
++ it 'should accept blocks with do ; end' do
++ @t.eval 'walking-spanish | do ; :jesus; end'
++ @context.instance_variable_get(:@x).should == :jesus
++ end
++
++ it 'should accept blocks with do; end' do
++ @t.eval 'walking-spanish | do; :jesus; end'
++ @context.instance_variable_get(:@x).should == :jesus
++ end
++
++ it 'should accept blocks with { }' do
++ @t.eval 'walking-spanish | { :jesus }'
++ @context.instance_variable_get(:@x).should == :jesus
++ end
++ end
++
++ describe "block-related content removed from arguments" do
++
++ describe "arg_string" do
++ it 'should remove block-related content from arg_string (with one normal arg)' do
++ @set.block_command "walking-spanish", "down the hall", :takes_block => true do |x, y|
++ PryTestHelpers.inject_var(:@arg_string, arg_string, target)
++ PryTestHelpers.inject_var(:@x, x, target)
++ end
++
++ @t.eval 'walking-spanish john| { :jesus }'
++
++ @context.instance_variable_get(:@arg_string).should == @context.instance_variable_get(:@x)
++ end
++
++ it 'should remove block-related content from arg_string (with no normal args)' do
++ @set.block_command "walking-spanish", "down the hall", :takes_block => true do
++ PryTestHelpers.inject_var(:@arg_string, arg_string, target)
++ end
++
++ @t.eval 'walking-spanish | { :jesus }'
++
++ @context.instance_variable_get(:@arg_string).should == ""
++ end
++
++ it 'should NOT remove block-related content from arg_string when :takes_block => false' do
++ block_string = "| { :jesus }"
++ @set.block_command "walking-spanish", "homemade special", :takes_block => false do
++ PryTestHelpers.inject_var(:@arg_string, arg_string, target)
++ end
++
++ @t.eval "walking-spanish #{block_string}"
++
++ @context.instance_variable_get(:@arg_string).should == block_string
++ end
++ end
++
++ describe "args" do
++ describe "block_command" do
++ it "should remove block-related content from arguments" do
++ @set.block_command "walking-spanish", "glass is full of sand", :takes_block => true do |x, y|
++ PryTestHelpers.inject_var(:@x, x, target)
++ PryTestHelpers.inject_var(:@y, y, target)
++ end
++
++ @t.eval 'walking-spanish | { :jesus }'
++
++ @context.instance_variable_get(:@x).should == nil
++ @context.instance_variable_get(:@y).should == nil
++ end
++
++ it "should NOT remove block-related content from arguments if :takes_block => false" do
++ @set.block_command "walking-spanish", "litella screeching for a blind pig", :takes_block => false do |x, y|
++ PryTestHelpers.inject_var(:@x, x, target)
++ PryTestHelpers.inject_var(:@y, y, target)
++ end
++
++ @t.eval 'walking-spanish | { :jesus }'
++
++ @context.instance_variable_get(:@x).should == "|"
++ @context.instance_variable_get(:@y).should == "{"
++ end
++ end
++
++ describe "create_command" do
++ it "should remove block-related content from arguments" do
++ @set.create_command "walking-spanish", "punk sanders carved one out of wood", :takes_block => true do
++ def process(x, y)
++ PryTestHelpers.inject_var(:@x, x, target)
++ PryTestHelpers.inject_var(:@y, y, target)
++ end
++ end
++
++ @t.eval 'walking-spanish | { :jesus }'
++
++ @context.instance_variable_get(:@x).should == nil
++ @context.instance_variable_get(:@y).should == nil
++ end
++
++ it "should NOT remove block-related content from arguments if :takes_block => false" do
++ @set.create_command "walking-spanish", "down the hall", :takes_block => false do
++ def process(x, y)
++ PryTestHelpers.inject_var(:@x, x, target)
++ PryTestHelpers.inject_var(:@y, y, target)
++ end
++ end
++
++ @t.eval 'walking-spanish | { :jesus }'
++
++ @context.instance_variable_get(:@x).should == "|"
++ @context.instance_variable_get(:@y).should == "{"
++ end
++ end
++ end
++ end
++
++ describe "blocks can take parameters" do
++ describe "{} style blocks" do
++ it 'should accept multiple parameters' do
++ @set.block_command "walking-spanish", "down the hall", :takes_block => true do
++ PryTestHelpers.inject_var(:@x, command_block.call(1, 2), target)
++ end
++
++ @t.eval 'walking-spanish | { |x, y| [x, y] }'
++
++ @context.instance_variable_get(:@x).should == [1, 2]
++ end
++ end
++
++ describe "do/end style blocks" do
++ it 'should accept multiple parameters' do
++ @set.create_command "walking-spanish", "litella", :takes_block => true do
++ def process
++ PryTestHelpers.inject_var(:@x, command_block.call(1, 2), target)
++ end
++ end
++
++ @t.eval <<-EOS
++ walking-spanish | do |x, y|
++ [x, y]
++ end
++ EOS
++
++ @context.instance_variable_get(:@x).should == [1, 2]
++ end
++ end
++ end
++
++ describe "closure behaviour" do
++ it 'should close over locals in the definition context' do
++ @t.eval 'var = :hello', 'walking-spanish | { var }'
++ @context.instance_variable_get(:@x).should == :hello
++ end
++ end
++
++ describe "exposing block parameter" do
++ describe "block_command" do
++ it "should expose block in command_block method" do
++ @set.block_command "walking-spanish", "glass full of sand", :takes_block => true do
++ PryTestHelpers.inject_var(:@x, command_block.call, target)
++ end
++
++ @t.eval 'walking-spanish | { :jesus }'
++
++ @context.instance_variable_get(:@x).should == :jesus
++ end
++ end
++
++ describe "create_command" do
++ it "should NOT expose &block in create_command's process method" do
++ @set.create_command "walking-spanish", "down the hall", :takes_block => true do
++ def process(&block)
++ block.call
++ end
++ end
++ @out = StringIO.new
++
++ proc {
++ @t.eval 'walking-spanish | { :jesus }'
++ }.should.raise(NoMethodError)
++ end
++
++ it "should expose block in command_block method" do
++ @set.create_command "walking-spanish", "homemade special", :takes_block => true do
++ def process
++ PryTestHelpers.inject_var(:@x, command_block.call, target)
++ end
++ end
++
++ @t.eval 'walking-spanish | { :jesus }'
++
++ @context.instance_variable_get(:@x).should == :jesus
++ end
++ end
++ end
++ end
++
++ describe "a command made with a custom sub-class" do
++
++ before do
++ class MyTestCommand < Pry::ClassCommand
++ match /my-*test/
++ description 'So just how many sound technicians does it take to' \
++ 'change a lightbulb? 1? 2? 3? 1-2-3? Testing?'
++ options :shellwords => false, :listing => 'my-test'
++
++ def process
++ output.puts command_name * 2
++ end
++ end
++
++ Pry.config.commands.add_command MyTestCommand
++ end
++
++ after do
++ Pry.config.commands.delete 'my-test'
++ end
++
++ it "allows creation of custom subclasses of Pry::Command" do
++ pry_eval('my---test').should =~ /my-testmy-test/
++ end
++
++ it "shows the source of the process method" do
++ pry_eval('show-source my-test').should =~ /output.puts command_name/
++ end
++
++ describe "command options hash" do
++ it "is always present" do
++ options_hash = {
++ :requires_gem => [],
++ :keep_retval => false,
++ :argument_required => false,
++ :interpolate => true,
++ :shellwords => false,
++ :listing => 'my-test',
++ :use_prefix => true,
++ :takes_block => false
++ }
++ MyTestCommand.options.should == options_hash
++ end
++
++ describe ":listing option" do
++ it "defaults to :match if not set explicitly" do
++ class HappyNewYear < Pry::ClassCommand
++ match 'happy-new-year'
++ description 'Happy New Year 2013'
++ end
++ Pry.config.commands.add_command HappyNewYear
++
++ HappyNewYear.options[:listing].should == 'happy-new-year'
++
++ Pry.config.commands.delete 'happy-new-year'
++ end
++
++ it "can be set explicitly" do
++ class MerryChristmas < Pry::ClassCommand
++ match 'merry-christmas'
++ description 'Merry Christmas!'
++ command_options :listing => 'happy-holidays'
++ end
++ Pry.config.commands.add_command MerryChristmas
++
++ MerryChristmas.options[:listing].should == 'happy-holidays'
++
++ Pry.config.commands.delete 'merry-christmas'
++ end
++
++ it "equals to :match option's inspect, if :match is Regexp" do
++ class CoolWinter < Pry::ClassCommand
++ match /.*winter/
++ description 'Is winter cool or cool?'
++ end
++ Pry.config.commands.add_command CoolWinter
++
++ CoolWinter.options[:listing].should == '/.*winter/'
++
++ Pry.config.commands.delete /.*winter/
++ end
++ end
++ end
++
++ end
++
++ describe "commands can save state" do
++ before do
++ @set = Pry::CommandSet.new do
++ create_command "litella", "desc" do
++ def process
++ state.my_state ||= 0
++ state.my_state += 1
++ end
++ end
++
++ create_command "sanders", "desc" do
++ def process
++ state.my_state = "wood"
++ end
++ end
++
++ create_command /[Hh]ello-world/, "desc" do
++ def process
++ state.my_state ||= 0
++ state.my_state += 2
++ end
++ end
++
++ end.import Pry::Commands
++
++ @t = pry_tester(:commands => @set)
++ end
++
++ it 'should save state for the command on the Pry#command_state hash' do
++ @t.eval 'litella'
++ @t.pry.command_state["litella"].my_state.should == 1
++ end
++
++ it 'should ensure state is maintained between multiple invocations of command' do
++ @t.eval 'litella'
++ @t.eval 'litella'
++ @t.pry.command_state["litella"].my_state.should == 2
++ end
++
++ it 'should ensure state with same name stored seperately for each command' do
++ @t.eval 'litella', 'sanders'
++
++ @t.pry.command_state["litella"].my_state.should == 1
++ @t.pry.command_state["sanders"].my_state.should =="wood"
++ end
++
++ it 'should ensure state is properly saved for regex commands' do
++ @t.eval 'hello-world', 'Hello-world'
++ @t.pry.command_state[/[Hh]ello-world/].my_state.should == 4
++ end
++ end
++
++ if defined?(Bond)
++ describe 'complete' do
++ it 'should return the arguments that are defined' do
++ @set.create_command "torrid" do
++ def options(opt)
++ opt.on :test
++ opt.on :lest
++ opt.on :pests
++ end
++ end
++
++ @set.complete('torrid ').should.include('--test ')
++ end
++ end
++ end
++
++ describe 'group' do
++ before do
++ @set.import(
++ Pry::CommandSet.new do
++ create_command("magic") { group("Not for a public use") }
++ end
++ )
++ end
++
++ it 'should be correct for default commands' do
++ @set["help"].group.should == "Help"
++ end
++
++ it 'should not change once it is initialized' do
++ @set["magic"].group("-==CD COMMAND==-")
++ @set["magic"].group.should == "Not for a public use"
++ end
++
++ it 'should not disappear after the call without parameters' do
++ @set["magic"].group
++ @set["magic"].group.should == "Not for a public use"
++ end
++ end
++end
+diff --git a/spec/commands/amend_line_spec.rb b/spec/commands/amend_line_spec.rb
+new file mode 100644
+index 0000000..7e16645
+--- /dev/null
++++ b/spec/commands/amend_line_spec.rb
+@@ -0,0 +1,247 @@
++require_relative '../helper'
++
++describe "amend-line" do
++ before do
++ @t = pry_tester
++ end
++
++ it 'should amend the last line of input when no line number specified' do
++ @t.push *unindent(<<-STR).split("\n")
++ def hello
++ puts :bing
++ STR
++
++ @t.process_command 'amend-line puts :blah'
++
++ @t.eval_string.should == unindent(<<-STR)
++ def hello
++ puts :blah
++ STR
++ end
++
++ it 'should amend the specified line of input when line number given' do
++ @t.push *unindent(<<-STR).split("\n")
++ def hello
++ puts :bing
++ puts :bang
++ STR
++
++ @t.process_command 'amend-line 1 def goodbye'
++
++ @t.eval_string.should == unindent(<<-STR)
++ def goodbye
++ puts :bing
++ puts :bang
++ STR
++ end
++
++ it 'should amend the first line of input when 0 given as line number' do
++ @t.push *unindent(<<-STR).split("\n")
++ def hello
++ puts :bing
++ puts :bang
++ STR
++
++ @t.process_command 'amend-line 0 def goodbye'
++
++ @t.eval_string.should == unindent(<<-STR)
++ def goodbye
++ puts :bing
++ puts :bang
++ STR
++ end
++
++ it 'should amend a specified line when negative number given' do
++ @t.push *unindent(<<-STR).split("\n")
++ def hello
++ puts :bing
++ puts :bang
++ STR
++
++ @t.process_command 'amend-line -1 puts :bink'
++
++ @t.eval_string.should == unindent(<<-STR)
++ def hello
++ puts :bing
++ puts :bink
++ STR
++
++ @t.process_command 'amend-line -2 puts :bink'
++
++ @t.eval_string.should == unindent(<<-STR)
++ def hello
++ puts :bink
++ puts :bink
++ STR
++ end
++
++ it 'should amend a range of lines of input when negative numbers given' do
++ @t.push *unindent(<<-STR).split("\n")
++ def hello
++ puts :bing
++ puts :bang
++ puts :boat
++ STR
++
++ @t.process_command 'amend-line -3..-2 puts :bink'
++
++ @t.eval_string.should == unindent(<<-STR)
++ def hello
++ puts :bink
++ puts :boat
++ STR
++ end
++
++ it 'should correctly amend the specified line with interpolated text' do
++ @t.push *unindent(<<-STR).split("\n")
++ def hello
++ puts :bing
++ puts :bang
++ STR
++
++ @t.process_command 'amend-line puts "#{goodbye}"'
++
++ @t.eval_string.should == unindent(<<-'STR')
++ def hello
++ puts :bing
++ puts "#{goodbye}"
++ STR
++ end
++
++ it 'should display error if nothing to amend' do
++ error = nil
++
++ begin
++ @t.process_command 'amend-line'
++ rescue Pry::CommandError => e
++ error = e
++ end
++
++ error.should.not.be.nil
++ error.message.should =~ /No input to amend/
++ end
++
++ it 'should correctly amend the specified range of lines' do
++ @t.push *unindent(<<-STR).split("\n")
++ def hello
++ puts :bing
++ puts :bang
++ puts :heart
++ STR
++
++ @t.process_command 'amend-line 2..3 puts :bong'
++
++ @t.eval_string.should == unindent(<<-STR)
++ def hello
++ puts :bong
++ puts :heart
++ STR
++ end
++
++ it 'should correctly delete a specific line using the ! for content' do
++ @t.push *unindent(<<-STR).split("\n")
++ def hello
++ puts :bing
++ puts :bang
++ puts :boast
++ puts :heart
++ STR
++
++ @t.process_command 'amend-line 3 !'
++
++ @t.eval_string.should == unindent(<<-STR)
++ def hello
++ puts :bing
++ puts :boast
++ puts :heart
++ STR
++ end
++
++ it 'should correctly delete a range of lines using the ! for content' do
++ @t.push *unindent(<<-STR).split("\n")
++ def hello
++ puts :bing
++ puts :bang
++ puts :boast
++ puts :heart
++ STR
++
++ @t.process_command 'amend-line 2..4 !'
++
++ @t.eval_string.should == unindent(<<-STR)
++ def hello
++ puts :heart
++ STR
++ end
++
++ it 'should correctly delete the previous line using the ! for content' do
++ @t.push *unindent(<<-STR).split("\n")
++ def hello
++ puts :bing
++ puts :bang
++ puts :boast
++ puts :heart
++ STR
++
++ @t.process_command 'amend-line !'
++
++ @t.eval_string.should == unindent(<<-STR)
++ def hello
++ puts :bing
++ puts :bang
++ puts :boast
++ STR
++ end
++
++ it 'should amend the specified range of lines, with numbers < 0 in range' do
++ @t.push *unindent(<<-STR).split("\n")
++ def hello
++ puts :bing
++ puts :bang
++ puts :boast
++ puts :heart
++ STR
++
++ @t.process_command 'amend-line 2..-2 puts :bong'
++
++ @t.eval_string.should == unindent(<<-STR)
++ def hello
++ puts :bong
++ puts :heart
++ STR
++ end
++
++ it 'should correctly insert a line before a specified line using >' do
++ @t.push *unindent(<<-STR).split("\n")
++ def hello
++ puts :bing
++ puts :bang
++ STR
++
++ @t.process_command 'amend-line 2 > puts :inserted'
++
++ @t.eval_string.should == unindent(<<-STR)
++ def hello
++ puts :inserted
++ puts :bing
++ puts :bang
++ STR
++ end
++
++ it 'should ignore second value of range with > syntax' do
++ @t.push *unindent(<<-STR).split("\n")
++ def hello
++ puts :bing
++ puts :bang
++ STR
++
++ @t.process_command 'amend-line 2..21 > puts :inserted'
++
++ @t.eval_string.should == unindent(<<-STR)
++ def hello
++ puts :inserted
++ puts :bing
++ puts :bang
++ STR
++ end
++end
+diff --git a/spec/commands/bang_spec.rb b/spec/commands/bang_spec.rb
+new file mode 100644
+index 0000000..3e8d2c0
+--- /dev/null
++++ b/spec/commands/bang_spec.rb
+@@ -0,0 +1,24 @@
++require_relative '../helper'
++
++describe "!" do
++ before do
++ @t = pry_tester
++ end
++
++ it 'should correctly clear the input buffer ' do
++ @t.push unindent(<<-STR)
++ def hello
++ puts :bing
++ STR
++
++ @t.process_command '!'
++ @t.last_output.should =~ /Input buffer cleared!/
++ @t.eval_string.should == ''
++ end
++
++ it 'should not clear the input buffer for negation' do
++ @t.push '! false'
++ @t.last_output.should =~ /true/
++ @t.eval_string.should == ''
++ end
++end
+diff --git a/spec/commands/cat/file_formatter_spec.rb b/spec/commands/cat/file_formatter_spec.rb
+new file mode 100644
+index 0000000..9d76475
+--- /dev/null
++++ b/spec/commands/cat/file_formatter_spec.rb
+@@ -0,0 +1,83 @@
++require_relative '../../helper'
++
++describe Pry::Command::Cat::FileFormatter do
++ describe "#file_and_line" do
++ before do
++ @p = Pry.new
++ @opt = Slop.new
++ Pry::Code.stubs(:from_file)
++ end
++
++ after do
++ Pry::Code.unstub(:from_file)
++ end
++
++ describe "windows filesystem" do
++ it "should parse '/'style absolute path without line_num" do
++ file_with_embedded_line = "C:/Ruby193/pry_instance.rb"
++ ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt)
++ file_name, line_num = ff.file_and_line
++ file_name.should == "C:/Ruby193/pry_instance.rb"
++ line_num.should == nil
++ end
++
++ it "should parse '/'style absolute path with line_num" do
++ file_with_embedded_line = "C:/Ruby193/pry_instance.rb:2"
++ ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt)
++ file_name, line_num = ff.file_and_line
++ file_name.should == "C:/Ruby193/pry_instance.rb"
++ line_num.should == 2
++ end
++
++ it "should parse '\\'style absolute path without line_num" do
++ file_with_embedded_line = "C:\\Ruby193\\pry_instance.rb"
++ ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt)
++ file_name, line_num = ff.file_and_line
++ file_name.should == "C:\\Ruby193\\pry_instance.rb"
++ line_num.should == nil
++ end
++
++ it "should parse '\\'style absolute path with line_num" do
++ file_with_embedded_line = "C:\\Ruby193\\pry_instance.rb:2"
++ ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt)
++ file_name, line_num = ff.file_and_line
++ file_name.should == "C:\\Ruby193\\pry_instance.rb"
++ line_num.should == 2
++ end
++ end
++
++ describe "UNIX-like filesystem" do
++ it "should parse absolute path without line_num" do
++ file_with_embedded_line = "/Ruby193/pry_instance.rb"
++ ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt)
++ file_name, line_num = ff.file_and_line
++ file_name.should == "/Ruby193/pry_instance.rb"
++ line_num.should == nil
++ end
++
++ it "should parse absolute path with line_num" do
++ file_with_embedded_line = "/Ruby193/pry_instance.rb:2"
++ ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt)
++ file_name, line_num = ff.file_and_line
++ file_name.should == "/Ruby193/pry_instance.rb"
++ line_num.should == 2
++ end
++ end
++
++ it "should parse relative path without line_num" do
++ file_with_embedded_line = "pry_instance.rb"
++ ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt)
++ file_name, line_num = ff.file_and_line
++ file_name.should == "pry_instance.rb"
++ line_num.should == nil
++ end
++
++ it "should parse relative path with line_num" do
++ file_with_embedded_line = "pry_instance.rb:2"
++ ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt)
++ file_name, line_num = ff.file_and_line
++ file_name.should == "pry_instance.rb"
++ line_num.should == 2
++ end
++ end
++end
+diff --git a/spec/commands/cat_spec.rb b/spec/commands/cat_spec.rb
+new file mode 100644
+index 0000000..26b69b7
+--- /dev/null
++++ b/spec/commands/cat_spec.rb
+@@ -0,0 +1,164 @@
++require_relative '../helper'
++
++describe "cat" do
++ before do
++ @str_output = StringIO.new
++
++ @t = pry_tester do
++ def insert_nil_input
++ @pry.update_input_history(nil)
++ end
++
++ def last_exception=(e)
++ @pry.last_exception = e
++ end
++ end
++ end
++
++ describe "on receiving a file that does not exist" do
++ it 'should display an error message' do
++ proc {
++ @t.eval 'cat supercalifragilicious66'
++ }.should.raise(StandardError).message.should =~ /Cannot open/
++ end
++ end
++
++ describe "with --in" do
++ it 'should display the last few expressions with indices' do
++ @t.eval('10', '20', 'cat --in').should == unindent(<<-STR)
++ 1:
++ 10
++ 2:
++ 20
++ STR
++ end
++ end
++
++ describe "with --in 1" do
++ it 'should display the first expression with no index' do
++ @t.eval('10', '20', 'cat --in 1').should == "10\n"
++ end
++ end
++
++ describe "with --in -1" do
++ it 'should display the last expression with no index' do
++ @t.eval('10', '20', 'cat --in -1').should == "20\n"
++ end
++ end
++
++ describe "with --in 1..2" do
++ it 'should display the given range with indices, omitting nils' do
++ @t.eval '10'
++ @t.insert_nil_input # normally happens when a command is executed
++ @t.eval ':hello'
++
++ @t.eval('cat --in 1..3').should == unindent(<<-EOS)
++ 1:
++ 10
++ 3:
++ :hello
++ EOS
++ end
++ end
++
++ # this doesnt work so well on rbx due to differences in backtrace
++ # so we currently skip rbx until we figure out a workaround
++ describe "with --ex" do
++ before do
++ @o = Object.new
++
++ # this is to test exception code (cat --ex)
++ def @o.broken_method
++ this method is broken
++ end
++ end
++
++ if !Pry::Helpers::BaseHelpers.rbx?
++ it 'cat --ex should display repl code that generated exception' do
++ @t.eval unindent(<<-EOS)
++ begin
++ this raises error
++ rescue => e
++ _pry_.last_exception = e
++ end
++ EOS
++ @t.eval('cat --ex').should =~ /\d+:(\s*) this raises error/
++ end
++
++ it 'cat --ex should correctly display code that generated exception' do
++ begin
++ @o.broken_method
++ rescue => e
++ @t.last_exception = e
++ end
++ @t.eval('cat --ex').should =~ /this method is broken/
++ end
++ end
++ end
++
++ describe "with --ex N" do
++ it 'should cat first level of backtrace when --ex used with no argument ' do
++ temp_file do |f|
++ f << "bt number 1"
++ f.flush
++ @t.last_exception = mock_exception("#{f.path}:1", 'x', 'x')
++ @t.eval('cat --ex').should =~ /bt number 1/
++ end
++ end
++
++ it 'should cat first level of backtrace when --ex 0 used ' do
++ temp_file do |f|
++ f << "bt number 1"
++ f.flush
++ @t.last_exception = mock_exception("#{f.path}:1", 'x', 'x')
++ @t.eval('cat --ex 0').should =~ /bt number 1/
++ end
++ end
++
++ it 'should cat second level of backtrace when --ex 1 used ' do
++ temp_file do |f|
++ f << "bt number 2"
++ f.flush
++ @t.last_exception = mock_exception('x', "#{f.path}:1", 'x')
++ @t.eval('cat --ex 1').should =~ /bt number 2/
++ end
++ end
++
++ it 'should cat third level of backtrace when --ex 2 used' do
++ temp_file do |f|
++ f << "bt number 3"
++ f.flush
++ @t.last_exception = mock_exception('x', 'x', "#{f.path}:1")
++ @t.eval('cat --ex 2').should =~ /bt number 3/
++ end
++ end
++
++ it 'should show error when backtrace level out of bounds' do
++ @t.last_exception = mock_exception('x', 'x', 'x')
++ proc {
++ @t.eval('cat --ex 3')
++ }.should.raise(Pry::CommandError).message.should =~ /out of bounds/
++ end
++
++ it 'each successive cat --ex should show the next level of backtrace, and going past the final level should return to the first' do
++ temp_files = []
++ 3.times do |i|
++ temp_files << Tempfile.new(['pry', '.rb'])
++ temp_files.last << "bt number #{i}"
++ temp_files.last.flush
++ end
++
++ @t.last_exception = mock_exception(*temp_files.map { |f| "#{f.path}:1" })
++
++ 3.times do |i|
++ @t.eval('cat --ex').should =~ /bt number #{i}/
++ end
++
++ @t.eval('cat --ex').should =~ /bt number 0/
++
++ temp_files.each do |file|
++ file.close(true)
++ end
++ end
++ end
++end
+diff --git a/spec/commands/cd_spec.rb b/spec/commands/cd_spec.rb
+new file mode 100644
+index 0000000..ddc3595
+--- /dev/null
++++ b/spec/commands/cd_spec.rb
+@@ -0,0 +1,259 @@
++require_relative '../helper'
++
++describe 'cd' do
++ before do
++ @o, @obj = Object.new, Object.new
++ @obj.instance_variable_set(:@x, 66)
++ @obj.instance_variable_set(:@y, 79)
++ @o.instance_variable_set(:@obj, @obj)
++
++ @t = pry_tester(@o) do
++ def assert_binding_stack(other)
++ binding_stack.map { |b| b.eval('self') }.should == other
++ end
++
++ def binding_stack
++ pry.binding_stack.dup
++ end
++
++ def command_state
++ pry.command_state["cd"]
++ end
++
++ def old_stack
++ pry.command_state['cd'].old_stack.dup
++ end
++ end
++ end
++
++ describe 'state' do
++ it 'should not to be set up in fresh instance' do
++ @t.command_state.should.be.nil
++ end
++ end
++
++ describe 'old stack toggling with `cd -`' do
++ describe 'in fresh pry instance' do
++ it 'should not toggle when there is no old stack' do
++ 2.times do
++ @t.eval 'cd -'
++ @t.assert_binding_stack [@o]
++ end
++ end
++ end
++
++ describe 'when an error was raised' do
++ it 'should not toggle and should keep correct stacks' do
++ proc {
++ @t.eval 'cd %'
++ }.should.raise(Pry::CommandError)
++
++ @t.old_stack.should == []
++ @t.assert_binding_stack [@o]
++
++ @t.eval 'cd -'
++ @t.old_stack.should == []
++ @t.assert_binding_stack [@o]
++ end
++ end
++
++ describe 'when using simple cd syntax' do
++ it 'should toggle' do
++ @t.eval 'cd :mon_dogg', 'cd -'
++ @t.assert_binding_stack [@o]
++
++ @t.eval 'cd -'
++ @t.assert_binding_stack [@o, :mon_dogg]
++ end
++ end
++
++ describe "when using complex cd syntax" do
++ it 'should toggle with a complex path (simple case)' do
++ @t.eval 'cd 1/2/3', 'cd -'
++ @t.assert_binding_stack [@o]
++
++ @t.eval 'cd -'
++ @t.assert_binding_stack [@o, 1, 2, 3]
++ end
++
++ it 'should toggle with a complex path (more complex case)' do
++ @t.eval 'cd 1/2/3', 'cd ../4', 'cd -'
++ @t.assert_binding_stack [@o, 1, 2, 3]
++
++ @t.eval 'cd -'
++ @t.assert_binding_stack [@o, 1, 2, 4]
++ end
++ end
++
++ describe 'series of cd calls' do
++ it 'should toggle with fuzzy `cd -` calls' do
++ @t.eval 'cd :mon_dogg', 'cd -', 'cd 42', 'cd -'
++ @t.assert_binding_stack [@o]
++
++ @t.eval 'cd -'
++ @t.assert_binding_stack [@o, 42]
++ end
++ end
++
++ describe 'when using cd ..' do
++ it 'should toggle with a simple path' do
++ @t.eval 'cd :john_dogg', 'cd ..'
++ @t.assert_binding_stack [@o]
++
++ @t.eval 'cd -'
++ @t.assert_binding_stack [@o, :john_dogg]
++ end
++
++ it 'should toggle with a complex path' do
++ @t.eval 'cd 1/2/3/../4', 'cd -'
++ @t.assert_binding_stack [@o]
++
++ @t.eval 'cd -'
++ @t.assert_binding_stack [@o, 1, 2, 4]
++ end
++ end
++
++ describe 'when using cd ::' do
++ it 'should toggle' do
++ @t.eval 'cd ::', 'cd -'
++ @t.assert_binding_stack [@o]
++
++ @t.eval 'cd -'
++ @t.assert_binding_stack [@o, TOPLEVEL_BINDING.eval('self')]
++ end
++ end
++
++ describe 'when using cd /' do
++ it 'should toggle' do
++ @t.eval 'cd /', 'cd -'
++ @t.assert_binding_stack [@o]
++
++ @t.eval 'cd :john_dogg', 'cd /', 'cd -'
++ @t.assert_binding_stack [@o, :john_dogg]
++ end
++ end
++
++ describe 'when using ^D (Control-D) key press' do
++ it 'should keep correct old binding' do
++ @t.eval 'cd :john_dogg', 'cd :mon_dogg', 'cd :kyr_dogg',
++ 'Pry::DEFAULT_CONTROL_D_HANDLER.call("", _pry_)'
++ @t.assert_binding_stack [@o, :john_dogg, :mon_dogg]
++
++ @t.eval 'cd -'
++ @t.assert_binding_stack [@o, :john_dogg, :mon_dogg, :kyr_dogg]
++
++ @t.eval 'cd -'
++ @t.assert_binding_stack [@o, :john_dogg, :mon_dogg]
++ end
++ end
++ end
++
++ it 'should cd into simple input' do
++ @t.eval 'cd :mon_ouie'
++ @t.eval('self').should == :mon_ouie
++ end
++
++ it 'should break out of session with cd ..' do
++ @t.eval 'cd :outer', 'cd :inner'
++ @t.eval('self').should == :inner
++
++ @t.eval 'cd ..'
++ @t.eval('self').should == :outer
++ end
++
++ it "should not leave the REPL session when given 'cd ..'" do
++ @t.eval 'cd ..'
++ @t.eval('self').should == @o
++ end
++
++ it 'should break out to outer-most session with cd /' do
++ @t.eval 'cd :inner'
++ @t.eval('self').should == :inner
++
++ @t.eval 'cd 5'
++ @t.eval('self').should == 5
++
++ @t.eval 'cd /'
++ @t.eval('self').should == @o
++ end
++
++ it 'should break out to outer-most session with just cd (no args)' do
++ @t.eval 'cd :inner'
++ @t.eval('self').should == :inner
++
++ @t.eval 'cd 5'
++ @t.eval('self').should == 5
++
++ @t.eval 'cd'
++ @t.eval('self').should == @o
++ end
++
++ it 'should cd into an object and its ivar using cd obj/@ivar syntax' do
++ @t.eval 'cd @obj/@x'
++ @t.assert_binding_stack [@o, @obj, 66]
++ end
++
++ it 'should cd into an object and its ivar using cd obj/@ivar/ syntax (note following /)' do
++ @t.eval 'cd @obj/@x/'
++ @t.assert_binding_stack [@o, @obj, 66]
++ end
++
++ it 'should cd into previous object and its local using cd ../local syntax' do
++ @t.eval 'cd @obj', 'local = :local', 'cd @x', 'cd ../local'
++ @t.assert_binding_stack [@o, @obj, :local]
++ end
++
++ it 'should cd into an object and its ivar and back again using cd obj/@ivar/.. syntax' do
++ @t.eval 'cd @obj/@x/..'
++ @t.assert_binding_stack [@o, @obj]
++ end
++
++ it 'should cd into an object and its ivar and back and then into another ivar using cd obj/@ivar/../@y syntax' do
++ @t.eval 'cd @obj/@x/../@y'
++ @t.assert_binding_stack [@o, @obj, 79]
++ end
++
++ it 'should cd back to top-level and then into another ivar using cd /@ivar/ syntax' do
++ @t.eval '@z = 20', 'cd @obj/@x/', 'cd /@z'
++ @t.assert_binding_stack [@o, 20]
++ end
++
++ it 'should start a session on TOPLEVEL_BINDING with cd ::' do
++ @t.eval 'cd ::'
++ @t.eval('self').should == TOPLEVEL_BINDING.eval('self')
++ end
++
++ it 'should cd into complex input (with spaces)' do
++ def @o.hello(x, y, z)
++ :mon_ouie
++ end
++
++ @t.eval 'cd hello 1, 2, 3'
++ @t.eval('self').should == :mon_ouie
++ end
++
++ it 'should not cd into complex input when it encounters an exception' do
++ proc {
++ @t.eval 'cd 1/2/swoop_a_doop/3'
++ }.should.raise(Pry::CommandError)
++
++ @t.assert_binding_stack [@o]
++ end
++
++ it 'can cd into an expression containing a string with slashes in it' do
++ @t.eval 'cd ["http://google.com"]'
++ @t.eval('self').should == ["http://google.com"]
++ end
++
++ it 'can cd into an expression with division in it' do
++ @t.eval 'cd (10/2)/even?'
++ @t.eval('self').should == false
++ end
++
++ # Regression test for ticket #516.
++ it 'should be able to cd into the Object BasicObject' do
++ proc {
++ @t.eval 'cd BasicObject.new'
++ }.should.not.raise
++ end
++end
+diff --git a/spec/commands/disable_pry_spec.rb b/spec/commands/disable_pry_spec.rb
+new file mode 100644
+index 0000000..534f063
+--- /dev/null
++++ b/spec/commands/disable_pry_spec.rb
+@@ -0,0 +1,25 @@
++require_relative '../helper'
++
++describe "disable-pry" do
++ before do
++ @t = pry_tester
++ end
++
++ after do
++ ENV.delete 'DISABLE_PRY'
++ end
++
++ it 'should quit the current session' do
++ lambda{
++ @t.process_command 'disable-pry'
++ }.should.throw(:breakout)
++ end
++
++ it "should set DISABLE_PRY" do
++ ENV['DISABLE_PRY'].should == nil
++ lambda{
++ @t.process_command 'disable-pry'
++ }.should.throw(:breakout)
++ ENV['DISABLE_PRY'].should == 'true'
++ end
++end
+diff --git a/spec/commands/edit_spec.rb b/spec/commands/edit_spec.rb
+new file mode 100644
+index 0000000..b3b43ae
+--- /dev/null
++++ b/spec/commands/edit_spec.rb
+@@ -0,0 +1,768 @@
++require 'pathname'
++require_relative '../helper'
++
++describe "edit" do
++ before do
++ @old_editor = Pry.config.editor
++ @file = @line = @contents = nil
++ Pry.config.editor = lambda do |file, line|
++ @file = file; @line = line; @contents = File.read(@file)
++ nil
++ end
++ end
++
++ after do
++ Pry.config.editor = @old_editor
++ end
++
++ describe "with FILE" do
++
++ before do
++ # OS-specific tempdir name. For GNU/Linux it's "tmp", for Windows it's
++ # something "Temp".
++ @tf_dir =
++ if Pry::Helpers::BaseHelpers.mri_19?
++ Pathname.new(Dir::Tmpname.tmpdir)
++ else
++ Pathname.new(Dir.tmpdir)
++ end
++
++ @tf_path = File.expand_path(File.join(@tf_dir.to_s, 'bar.rb'))
++ FileUtils.touch(@tf_path)
++ end
++
++ after do
++ FileUtils.rm(@tf_path) if File.exists?(@tf_path)
++ end
++
++ it "should not allow patching any known kind of file" do
++ ["file.rb", "file.c", "file.py", "file.yml", "file.gemspec",
++ "/tmp/file", "\\\\Temp\\\\file"].each do |file|
++ proc {
++ pry_eval "edit -p #{file}"
++ }.should.raise(NotImplementedError).
++ message.should =~ /Cannot yet patch false objects!/
++ end
++ end
++
++ it "should invoke Pry.config.editor with absolutified filenames" do
++ pry_eval 'edit lib/pry.rb'
++ @file.should == File.expand_path('lib/pry.rb')
++
++ pry_eval "edit #@tf_path"
++ @file.should == @tf_path
++ end
++
++ it "should guess the line number from a colon" do
++ pry_eval 'edit lib/pry.rb:10'
++ @line.should == 10
++ end
++
++ it "should use the line number from -l" do
++ pry_eval 'edit -l 10 lib/pry.rb'
++ @line.should == 10
++ end
++
++ it "should not delete the file!" do
++ pry_eval 'edit Rakefile'
++ File.exist?(@file).should == true
++ end
++
++ it "works with files that contain blanks in their names" do
++ tf_path = File.join(File.dirname(@tf_path), 'swoop and doop.rb')
++ FileUtils.touch(tf_path)
++ pry_eval "edit #{ tf_path }"
++ @file.should == tf_path
++ FileUtils.rm(tf_path)
++ end
++
++ if respond_to?(:require_relative, true)
++ it "should work with require relative" do
++ Pry.config.editor = lambda { |file, line|
++ File.open(file, 'w'){ |f| f << 'require_relative "baz.rb"' }
++ File.open(file.gsub('bar.rb', 'baz.rb'), 'w'){ |f| f << "Pad.required = true; FileUtils.rm(__FILE__)" }
++
++ if defined?(Rubinius::Compiler)
++ File.unlink Rubinius::Compiler.compiled_name file
++ end
++ nil
++ }
++ pry_eval "edit #@tf_path"
++ Pad.required.should == true
++ end
++ end
++
++ describe do
++ before do
++ Pad.counter = 0
++ Pry.config.editor = lambda { |file, line|
++ File.open(file, 'w') { |f| f << "Pad.counter = Pad.counter + 1" }
++ nil
++ }
++ end
++
++ it "should reload the file if it is a ruby file" do
++ temp_file do |tf|
++ counter = Pad.counter
++ path = tf.path
++
++ pry_eval "edit #{path}"
++
++ Pad.counter.should == counter + 1
++ end
++ end
++
++ it "should not reload the file if it is not a ruby file" do
++ temp_file('.py') do |tf|
++ counter = Pad.counter
++ path = tf.path
++
++ pry_eval "edit #{path}"
++
++ Pad.counter.should == counter
++ end
++ end
++
++ it "should not reload a ruby file if -n is given" do
++ temp_file do |tf|
++ counter = Pad.counter
++ path = tf.path
++
++ Pad.counter.should == counter
++ end
++ end
++
++ it "should reload a non-ruby file if -r is given" do
++ temp_file('.pryrc') do |tf|
++ counter = Pad.counter
++ path = tf.path
++
++ pry_eval "edit -r #{path}"
++
++ Pad.counter.should == counter + 1
++ end
++ end
++ end
++
++ describe do
++ before do
++ @reloading = nil
++ Pry.config.editor = lambda do |file, line, reloading|
++ @file = file; @line = line; @reloading = reloading
++ nil
++ end
++ end
++
++ it "should pass the editor a reloading arg" do
++ pry_eval 'edit lib/pry.rb'
++ @reloading.should == true
++ pry_eval 'edit -n lib/pry.rb'
++ @reloading.should == false
++ end
++ end
++ end
++
++ describe "with --ex" do
++ before do
++ @t = pry_tester do
++ def last_exception=(exception)
++ @pry.last_exception = exception
++ end
++ def last_exception; @pry.last_exception; end
++ end
++ end
++
++ describe "with a real file" do
++ before do
++ @tf = Tempfile.new(["pry", ".rb"])
++ @path = @tf.path
++ @tf << "1\n2\nraise RuntimeError"
++ @tf.flush
++
++ begin
++ load @path
++ rescue RuntimeError => e
++ @t.last_exception = e
++ end
++ end
++
++ after do
++ @tf.close(true)
++ File.unlink("#{@path}c") if File.exists?("#{@path}c") #rbx
++ end
++
++ it "should reload the file" do
++ Pry.config.editor = lambda {|file, line|
++ File.open(file, 'w'){|f| f << "FOO = 'BAR'" }
++ if defined?(Rubinius::Compiler)
++ File.unlink Rubinius::Compiler.compiled_name file
++ end
++ nil
++ }
++
++ defined?(FOO).should.be.nil
++
++ @t.eval 'edit --ex'
++
++ FOO.should == 'BAR'
++ end
++
++ # regression test (this used to edit the current method instead
++ # of the exception)
++ it 'edits the exception even when in a patched method context' do
++ source_location = nil
++ Pry.config.editor = lambda {|file, line|
++ source_location = [file, line]
++ nil
++ }
++
++ Pad.le = @t.last_exception
++ redirect_pry_io(InputTester.new("def broken_method", "binding.pry", "end",
++ "broken_method",
++ "_pry_.last_exception = Pad.le",
++ "edit --ex -n", "exit-all", "exit-all")) do
++ Object.new.pry
++ end
++
++ source_location.should == [@path, 3]
++ Pad.clear
++ end
++
++ it "should not reload the file if -n is passed" do
++ Pry.config.editor = lambda {|file, line|
++ File.open(file, 'w'){|f| f << "FOO2 = 'BAZ'" }
++ nil
++ }
++
++ defined?(FOO2).should.be.nil
++
++ @t.eval 'edit -n --ex'
++
++ defined?(FOO2).should.be.nil
++ end
++
++ describe "with --patch" do
++ # Original source code must be untouched.
++ it "should apply changes only in memory (monkey patching)" do
++ Pry.config.editor = lambda {|file, line|
++ File.open(file, 'w'){|f| f << "FOO3 = 'PIYO'" }
++ @patched_def = File.open(file, 'r').read
++ nil
++ }
++
++ defined?(FOO3).should.be.nil
++
++ @t.eval 'edit --ex --patch'
++
++ FOO3.should == 'PIYO'
++
++ @tf.rewind
++ @tf.read.should == "1\n2\nraise RuntimeError"
++ @patched_def.should == "FOO3 = 'PIYO'"
++ end
++ end
++ end
++
++ describe "with --ex NUM" do
++ before do
++ Pry.config.editor = proc do |file, line|
++ @__ex_file__ = file
++ @__ex_line__ = line
++ nil
++ end
++
++ @t.last_exception = mock_exception('a:1', 'b:2', 'c:3')
++ end
++
++ it 'should start on first level of backtrace with just --ex' do
++ @t.eval 'edit -n --ex'
++ @__ex_file__.should == "a"
++ @__ex_line__.should == 1
++ end
++
++ it 'should start editor on first level of backtrace with --ex 0' do
++ @t.eval 'edit -n --ex 0'
++ @__ex_file__.should == "a"
++ @__ex_line__.should == 1
++ end
++
++ it 'should start editor on second level of backtrace with --ex 1' do
++ @t.eval 'edit -n --ex 1'
++ @__ex_file__.should == "b"
++ @__ex_line__.should == 2
++ end
++
++ it 'should start editor on third level of backtrace with --ex 2' do
++ @t.eval 'edit -n --ex 2'
++ @__ex_file__.should == "c"
++ @__ex_line__.should == 3
++ end
++
++ it 'should display error message when backtrace level is invalid' do
++ proc {
++ @t.eval 'edit -n --ex 4'
++ }.should.raise(Pry::CommandError)
++ end
++ end
++ end
++
++ describe "without FILE" do
++ before do
++ @t = pry_tester
++ end
++
++ it "should edit the current expression if it's incomplete" do
++ @t.push 'def a'
++ @t.process_command 'edit'
++ @contents.should == "def a\n"
++ end
++
++ it "should edit the previous expression if the current is empty" do
++ @t.eval 'def a; 2; end', 'edit'
++ @contents.should == "def a; 2; end\n"
++ end
++
++ it "should use a blank file if -t is specified" do
++ @t.eval 'def a; 5; end', 'edit -t'
++ @contents.should == "\n"
++ end
++
++ it "should use a blank file if -t given, even during an expression" do
++ @t.push 'def a;'
++ @t.process_command 'edit -t'
++ @contents.should == "\n"
++ end
++
++ it "should position the cursor at the end of the expression" do
++ @t.eval "def a; 2;\nend"
++ @t.process_command 'edit'
++ @line.should == 2
++ end
++
++ it "should evaluate the expression" do
++ Pry.config.editor = lambda {|file, line|
++ File.open(file, 'w'){|f| f << "'FOO'\n" }
++ nil
++ }
++ @t.process_command 'edit'
++ @t.eval_string.should == "'FOO'\n"
++ end
++
++ it "should ignore -n for tempfiles" do
++ Pry.config.editor = lambda {|file, line|
++ File.open(file, 'w'){|f| f << "'FOO'\n" }
++ nil
++ }
++ @t.process_command "edit -n"
++ @t.eval_string.should == "'FOO'\n"
++ end
++
++ it "should not evaluate a file with -n" do
++ Pry.config.editor = lambda {|file, line|
++ File.open(file, 'w'){|f| f << "'FOO'\n" }
++ nil
++ }
++ begin
++ @t.process_command 'edit -n spec/fixtures/foo.rb'
++ File.read("spec/fixtures/foo.rb").should == "'FOO'\n"
++ @t.eval_string.should == ''
++ ensure
++ FileUtils.rm "spec/fixtures/foo.rb"
++ end
++ end
++ end
++
++ describe "with --in" do
++ it "should edit the nth line of _in_" do
++ pry_eval '10', '11', 'edit --in -2'
++ @contents.should == "10\n"
++ end
++
++ it "should edit the last line if no argument is given" do
++ pry_eval '10', '11', 'edit --in'
++ @contents.should == "11\n"
++ end
++
++ it "should edit a range of lines if a range is given" do
++ pry_eval "10", "11", "edit -i 1,2"
++ @contents.should == "10\n11\n"
++ end
++
++ it "should edit a multi-line expression as it occupies one line of _in_" do
++ pry_eval "class Fixnum\n def invert; -self; end\nend", "edit -i 1"
++ @contents.should == "class Fixnum\n def invert; -self; end\nend\n"
++ end
++
++ it "should not work with a filename" do
++ proc {
++ pry_eval 'edit ruby.rb -i'
++ }.should.raise(Pry::CommandError).
++ message.should =~ /Only one of --ex, --temp, --in, --method and FILE/
++ end
++
++ it "should not work with nonsense" do
++ proc {
++ pry_eval 'edit --in three'
++ }.should.raise(Pry::CommandError).
++ message.should =~ /Not a valid range: three/
++ end
++ end
++
++ describe "old edit-method tests now migrated to edit" do
++ describe "on a method defined in a file" do
++ before do
++ @tempfile = (Tempfile.new(['pry', '.rb']))
++ @tempfile.puts <<-EOS
++ module A
++ def a
++ :yup
++ end
++
++ def b
++ :kinda
++ end
++ end
++
++ class X
++ include A
++
++ def self.x
++ :double_yup
++ end
++
++ def x
++ :nope
++ end
++
++ def b
++ super
++ end
++ alias c b
++
++ def y?
++ :because
++ end
++
++ class B
++ G = :nawt
++
++ def foo
++ :possibly
++ G
++ end
++ end
++ end
++ EOS
++ @tempfile.flush
++ load @tempfile.path
++
++ @tempfile_path = @tempfile.path
++ end
++
++ after do
++ @tempfile.close(true)
++ end
++
++ describe 'without -p' do
++ before do
++ @file = @line = @contents = nil
++ Pry.config.editor = lambda do |file, line|
++ @file = file; @line = line
++ nil
++ end
++ end
++
++ it "should correctly find a class method" do
++ pry_eval 'edit X.x'
++
++ @file.should == @tempfile_path
++ @line.should == 14
++
++ end
++
++ it "should correctly find an instance method" do
++ pry_eval 'edit X#x'
++ @file.should == @tempfile_path
++ @line.should == 18
++ end
++
++ it "should correctly find a method on an instance" do
++ pry_eval 'x = X.new', 'edit x.x'
++ @file.should == @tempfile_path
++ @line.should == 18
++ end
++
++ it "should correctly find a method from a module" do
++ pry_eval 'edit X#a'
++ @file.should == @tempfile_path
++ @line.should == 2
++ end
++
++ it "should correctly find an aliased method" do
++ pry_eval 'edit X#c'
++ @file.should == @tempfile_path
++ @line.should == 22
++ end
++ end
++
++ describe 'with -p' do
++ before do
++ Pry.config.editor = lambda do |file, line|
++ lines = File.read(file).lines.to_a
++ lines[1] = ":maybe\n"
++ File.open(file, 'w') do |f|
++ f.write(lines.join)
++ end
++ @patched_def = String(lines[1]).chomp
++ nil
++ end
++ end
++
++ it "should successfully replace a class method" do
++ pry_eval 'edit -p X.x'
++
++ class << X
++ X.method(:x).owner.should == self
++ end
++ X.method(:x).receiver.should == X
++ X.x.should == :maybe
++ end
++
++ it "should successfully replace an instance method" do
++ pry_eval 'edit -p X#x'
++
++ X.instance_method(:x).owner.should == X
++ X.new.x.should == :maybe
++ end
++
++ it "should successfully replace a method on an instance" do
++ pry_eval 'instance = X.new', 'edit -p instance.x'
++
++ instance = X.new
++ instance.method(:x).owner.should == X
++ instance.x.should == :maybe
++ end
++
++ it "should successfully replace a method from a module" do
++ pry_eval 'edit -p X#a'
++
++ X.instance_method(:a).owner.should == A
++ X.new.a.should == :maybe
++ end
++
++ it "should successfully replace a method with a question mark" do
++ pry_eval 'edit -p X#y?'
++
++ X.instance_method(:y?).owner.should == X
++ X.new.y?.should == :maybe
++ end
++
++ it "should preserve module nesting" do
++ pry_eval 'edit -p X::B#foo'
++
++ X::B.instance_method(:foo).owner.should == X::B
++ X::B.new.foo.should == :nawt
++ end
++
++ describe "monkey-patching" do
++ before do
++ @edit = 'edit --patch ' # A shortcut.
++ end
++
++ # @param [Integer] lineno
++ # @return [String] the stripped line from the tempfile at +lineno+
++ def stripped_line_at(lineno)
++ @tempfile.rewind
++ @tempfile.lines.to_a[lineno].strip
++ end
++
++ # Applies the monkey patch for +method+ with help of evaluation of
++ # +eval_strs+. The idea is to capture the initial line number (before
++ # the monkey patch), because it gets overwritten by the line number from
++ # the monkey patch. And our goal is to check that the original
++ # definition hasn't changed.
++ # @param [UnboundMethod] method
++ # @param [Array<String>] eval_strs
++ # @return [Array<String] the lines with definitions of the same line
++ # before monkey patching and after (normally, they should be equal)
++ def apply_monkey_patch(method, *eval_strs)
++ _, lineno = method.source_location
++ definition_before = stripped_line_at(lineno)
++
++ pry_eval(*eval_strs)
++
++ definition_after = stripped_line_at(lineno)
++
++ [definition_before, definition_after]
++ end
++
++ it "should work for a class method" do
++ def_before, def_after =
++ apply_monkey_patch(X.method(:x), "#@edit X.x")
++
++ def_before.should == ':double_yup'
++ def_after.should == ':double_yup'
++ @patched_def.should == ':maybe'
++ end
++
++ it "should work for an instance method" do
++ def_before, def_after =
++ apply_monkey_patch(X.instance_method(:x), "#@edit X#x")
++
++ def_before.should == ':nope'
++ def_after.should == ':nope'
++ @patched_def.should == ':maybe'
++ end
++
++ it "should work for a method on an instance" do
++ def_before, def_after =
++ apply_monkey_patch(X.instance_method(:x), 'instance = X.new', "#@edit instance.x")
++
++ def_before.should == ':nope'
++ def_after.should == ':nope'
++ @patched_def.should == ':maybe'
++ end
++
++ it "should work for a method from a module" do
++ def_before, def_after =
++ apply_monkey_patch(X.instance_method(:a), "#@edit X#a")
++
++ def_before.should == ':yup'
++ def_after.should == ':yup'
++ @patched_def.should == ':maybe'
++ end
++
++ it "should work for a method with a question mark" do
++ def_before, def_after =
++ apply_monkey_patch(X.instance_method(:y?), "#@edit X#y?")
++
++ def_before.should == ':because'
++ def_after.should == ':because'
++ @patched_def.should == ':maybe'
++ end
++
++ it "should work with nesting" do
++ def_before, def_after =
++ apply_monkey_patch(X::B.instance_method(:foo), "#@edit X::B#foo")
++
++ def_before.should == ':possibly'
++ def_after.should == ':possibly'
++ @patched_def.should == ':maybe'
++ end
++ end
++ end
++
++ describe 'on an aliased method' do
++ before do
++ Pry.config.editor = lambda do |file, line|
++ lines = File.read(file).lines.to_a
++ lines[1] = '"#{super}aa".to_sym' + "\n"
++ File.open(file, 'w') do |f|
++ f.write(lines.join)
++ end
++ nil
++ end
++ end
++
++ it "should change the alias, but not the original, without breaking super" do
++
++ $x = :bebe
++ pry_eval 'edit -p X#c'
++
++
++ Pry::Method.from_str("X#c").alias?.should == true
++
++ X.new.b.should == :kinda
++ X.new.c.should == :kindaaa
++ $x = nil
++ end
++ end
++
++ describe 'with three-arg editor' do
++ before do
++ @file = @line = @reloading = nil
++ Pry.config.editor = lambda do |file, line, reloading|
++ @file = file; @line = line; @reloading = reloading
++ nil
++ end
++ end
++
++ it "should pass the editor a reloading arg" do
++ pry_eval 'edit X.x'
++ @reloading.should == true
++ pry_eval 'edit -n X.x'
++ @reloading.should == false
++ end
++ end
++ end
++ end
++
++ describe "--method flag" do
++ before do
++ @t = pry_tester
++ class BinkyWink
++ eval %{
++ def tits_macgee
++ binding
++ end
++ }
++
++ def tots_macgee
++ :jeremy_jones
++ binding
++ end
++ end
++ end
++
++ after do
++ Object.remove_const(:BinkyWink)
++ end
++
++ it 'should edit method context' do
++ Pry.config.editor = lambda do |file, line|
++ [file, line].should == BinkyWink.instance_method(:tots_macgee).source_location
++ nil
++ end
++
++ t = pry_tester(BinkyWink.new.tots_macgee)
++ t.process_command "edit -m -n"
++ end
++
++ it 'errors when cannot find method context' do
++ Pry.config.editor = lambda do |file, line|
++ [file, line].should == BinkyWink.instance_method(:tits_macgee).source_location
++ nil
++ end
++
++ t = pry_tester(BinkyWink.new.tits_macgee)
++ lambda { t.process_command "edit -m -n" }.should.
++ raise(Pry::CommandError).message.should.match(/Cannot find a file for/)
++ end
++
++ it 'errors when a filename arg is passed with --method' do
++ lambda { @t.process_command "edit -m Pry#repl" }.should.
++ raise(Pry::CommandError).message.should.match(/Only one of/)
++ end
++ end
++
++ describe "pretty error messages" do
++ before do
++ @t = pry_tester
++ class TrinkyDink
++ eval %{
++ def claudia_linklater
++ end
++ }
++ end
++ end
++
++ after do
++ Object.remove_const(:TrinkyDink)
++ end
++
++ it 'should display a nice error message when cannot open a file' do
++ lambda { @t.process_command "edit TrinkyDink#claudia_linklater" }.should.
++ raise(Pry::CommandError).message.should.match(/Cannot find a file for/)
++ end
++ end
++end
+diff --git a/spec/commands/exit_all_spec.rb b/spec/commands/exit_all_spec.rb
+new file mode 100644
+index 0000000..7a771c9
+--- /dev/null
++++ b/spec/commands/exit_all_spec.rb
+@@ -0,0 +1,27 @@
++require_relative '../helper'
++
++describe "exit-all" do
++ before { @pry = Pry.new }
++
++ it "should break out of the repl and return nil" do
++ @pry.eval("exit-all").should.be.false
++ @pry.exit_value.should.be.nil
++ end
++
++ it "should break out of the repl wth a user specified value" do
++ @pry.eval("exit-all 'message'").should.be.false
++ @pry.exit_value.should == "message"
++ end
++
++ it "should break out of the repl even if multiple bindings still on stack" do
++ ["cd 1", "cd 2"].each { |line| @pry.eval(line).should.be.true }
++ @pry.eval("exit-all 'message'").should.be.false
++ @pry.exit_value.should == "message"
++ end
++
++ it "should have empty binding_stack after breaking out of the repl" do
++ ["cd 1", "cd 2"].each { |line| @pry.eval(line).should.be.true }
++ @pry.eval("exit-all").should.be.false
++ @pry.binding_stack.should.be.empty
++ end
++end
+diff --git a/spec/commands/exit_program_spec.rb b/spec/commands/exit_program_spec.rb
+new file mode 100644
+index 0000000..b80cc7e
+--- /dev/null
++++ b/spec/commands/exit_program_spec.rb
+@@ -0,0 +1,19 @@
++require_relative '../helper'
++
++describe "exit-program" do
++ it 'should raise SystemExit' do
++ proc {
++ pry_eval('exit-program')
++ }.should.raise SystemExit
++ end
++
++ it 'should exit the program with the provided value' do
++ begin
++ pry_eval 'exit-program 66'
++ rescue SystemExit => e
++ e.status.should == 66
++ else
++ raise "Failed to raise SystemExit"
++ end
++ end
++end
+diff --git a/spec/commands/exit_spec.rb b/spec/commands/exit_spec.rb
+new file mode 100644
+index 0000000..8cd7587
+--- /dev/null
++++ b/spec/commands/exit_spec.rb
+@@ -0,0 +1,28 @@
++require_relative '../helper'
++
++describe "exit" do
++ before { @pry = Pry.new(:target => :outer, :output => StringIO.new) }
++
++ it "should pop a binding" do
++ @pry.eval "cd :inner"
++ @pry.evaluate_ruby("self").should == :inner
++ @pry.eval "exit"
++ @pry.evaluate_ruby("self").should == :outer
++ end
++
++ it "should break out of the repl when binding_stack has only one binding" do
++ @pry.eval("exit").should.be.false
++ @pry.exit_value.should.be.nil
++ end
++
++ it "should break out of the repl and return user-given value" do
++ @pry.eval("exit :john").should.be.false
++ @pry.exit_value.should == :john
++ end
++
++ it "should break out of the repl even after an exception" do
++ @pry.eval "exit = 42"
++ @pry.output.string.should =~ /^SyntaxError/
++ @pry.eval("exit").should.be.false
++ end
++end
+diff --git a/spec/commands/find_method_spec.rb b/spec/commands/find_method_spec.rb
+new file mode 100644
+index 0000000..a00e8b9
+--- /dev/null
++++ b/spec/commands/find_method_spec.rb
+@@ -0,0 +1,63 @@
++require_relative '../helper'
++
++MyKlass = Class.new do
++ def hello
++ "timothy"
++ end
++ def goodbye
++ "jenny"
++ end
++ def tea_tim?
++ "timothy"
++ end
++ def tea_time?
++ "polly"
++ end
++end
++
++describe "find-method" do
++ describe "find matching methods by name regex (-n option)" do
++ it "should find a method by regex" do
++ pry_eval("find-method hell MyKlass").should =~
++ /MyKlass.*?hello/m
++ end
++
++ it "should NOT match a method that does not match the regex" do
++ pry_eval("find-method hell MyKlass").should.not =~
++ /MyKlass.*?goodbye/m
++ end
++ end
++
++ describe "find matching methods by content regex (-c option)" do
++ it "should find a method by regex" do
++ pry_eval("find-method -c timothy MyKlass").should =~
++ /MyKlass.*?hello/m
++ end
++
++ it "should NOT match a method that does not match the regex" do
++ pry_eval("find-method timothy MyKlass").should.not =~
++ /MyKlass.*?goodbye/m
++ end
++ end
++
++ it "should work with badly behaved constants" do
++ MyKlass::X = Object.new
++ def (MyKlass::X).hash
++ raise "mooo"
++ end
++
++ pry_eval("find-method -c timothy MyKlass").should =~
++ /MyKlass.*?hello/m
++ end
++
++ it "should escape regexes correctly" do
++ good = /tea_time\?/
++ bad = /tea_tim\?/
++ pry_eval('find-method tea_time? MyKlass').should =~ good
++ pry_eval('find-method tea_time? MyKlass').should =~ good
++ pry_eval('find-method tea_time\? MyKlass').should.not =~ bad
++ pry_eval('find-method tea_time\? MyKlass').should =~ good
++ end
++end
++
++Object.remove_const(:MyKlass)
+diff --git a/spec/commands/gem_list_spec.rb b/spec/commands/gem_list_spec.rb
+new file mode 100644
+index 0000000..cef5c74
+--- /dev/null
++++ b/spec/commands/gem_list_spec.rb
+@@ -0,0 +1,25 @@
++require_relative '../helper'
++
++describe "gem-list" do
++ it 'should not raise when invoked' do
++ proc {
++ pry_eval(self, 'gem-list')
++ }.should.not.raise
++ end
++
++ it 'should work arglessly' do
++ list = pry_eval('gem-list')
++ list.should =~ /slop \(/
++ list.should =~ /bacon \(/
++ end
++
++ it 'should find arg' do
++ prylist = pry_eval('gem-list slop')
++ prylist.should =~ /slop \(/
++ prylist.should.not =~ /bacon/
++ end
++
++ it 'should return non-results as silence' do
++ pry_eval('gem-list aoeuoueouaou').should.empty?
++ end
++end
+diff --git a/spec/commands/gist_spec.rb b/spec/commands/gist_spec.rb
+new file mode 100644
+index 0000000..dc29ba7
+--- /dev/null
++++ b/spec/commands/gist_spec.rb
+@@ -0,0 +1,32 @@
++# These tests are out of date.
++# THey need to be updated for the new 'gist' API, but im too sleepy to
++# do that now.
++
++require_relative '../helper'
++
++describe 'gist' do
++ it 'has a dependency on the jist gem' do
++ Pry::Command::Gist.command_options[:requires_gem].should == "gist"
++ end
++
++ before do
++ Pad.gist_calls = {}
++ end
++
++ # In absence of normal mocking, just monkeysmash these with no undoing after.
++ module ::Gist
++ class << self
++ def login!; Pad.gist_calls[:login!] = true end
++ def gist(*args)
++ Pad.gist_calls[:gist_args] = args
++ {'html_url' => 'http://gist.blahblah'}
++ end
++ def copy(content); Pad.gist_calls[:copy_args] = content end
++ end
++ end
++
++ it 'nominally logs in' do
++ pry_eval 'gist --login'
++ Pad.gist_calls[:login!].should.not.be.nil
++ end
++end
+diff --git a/spec/commands/help_spec.rb b/spec/commands/help_spec.rb
+new file mode 100644
+index 0000000..d6876c9
+--- /dev/null
++++ b/spec/commands/help_spec.rb
+@@ -0,0 +1,56 @@
++require_relative '../helper'
++
++describe "help" do
++ before do
++ @oldset = Pry.config.commands
++ @set = Pry.config.commands = Pry::CommandSet.new do
++ import Pry::Commands
++ end
++ end
++
++ after do
++ Pry.config.commands = @oldset
++ end
++
++ it 'should display help for a specific command' do
++ pry_eval('help ls').should =~ /Usage: ls/
++ end
++
++ it 'should display help for a regex command with a "listing"' do
++ @set.command /bar(.*)/, "Test listing", :listing => "foo" do; end
++ pry_eval('help foo').should =~ /Test listing/
++ end
++
++ it 'should display help for a command with a spaces in its name' do
++ @set.command "cmd with spaces", "desc of a cmd with spaces" do; end
++ pry_eval('help "cmd with spaces"').should =~ /desc of a cmd with spaces/
++ end
++
++ it 'should display help for all commands with a description' do
++ @set.command /bar(.*)/, "Test listing", :listing => "foo" do; end
++ @set.command "b", "description for b", :listing => "foo" do; end
++ @set.command "c" do;end
++ @set.command "d", "" do;end
++
++ output = pry_eval('help')
++ output.should =~ /Test listing/
++ output.should =~ /Description for b/
++ output.should =~ /No description/
++ end
++
++ it "should sort the output of the 'help' command" do
++ @set.command 'faa', "Fooerizes" do; end
++ @set.command 'gaa', "Gooerizes" do; end
++ @set.command 'maa', "Mooerizes" do; end
++ @set.command 'baa', "Booerizes" do; end
++
++ doc = pry_eval('help')
++
++ order = [doc.index("baa"),
++ doc.index("faa"),
++ doc.index("gaa"),
++ doc.index("maa")]
++
++ order.should == order.sort
++ end
++end
+diff --git a/spec/commands/hist_spec.rb b/spec/commands/hist_spec.rb
+new file mode 100644
+index 0000000..3b444eb
+--- /dev/null
++++ b/spec/commands/hist_spec.rb
+@@ -0,0 +1,204 @@
++require_relative '../helper'
++
++describe "hist" do
++ before do
++ Pry.history.clear
++ @hist = Pry.history
++
++ @str_output = StringIO.new
++ @t = pry_tester :history => @hist do
++ # For looking at what hist pushes into the input stack. The implementation
++ # of this helper will definitely have to change at some point.
++ def next_input
++ @pry.input.string
++ end
++ end
++ end
++
++ it 'should replay history correctly (single item)' do
++ o = Object.new
++ @hist.push "@x = 10"
++ @hist.push "@y = 20"
++ @hist.push "@z = 30"
++
++ @t.push_binding o
++ @t.eval 'hist --replay -1'
++
++ o.instance_variable_get(:@z).should == 30
++ end
++
++ it 'should replay a range of history correctly (range of items)' do
++ o = Object.new
++ @hist.push "@x = 10"
++ @hist.push "@y = 20"
++
++ @t.push_binding o
++ @t.eval 'hist --replay 0..2'
++ @t.eval('[@x, @y]').should == [10, 20]
++ end
++
++ # this is to prevent a regression where input redirection is
++ # replaced by just appending to `eval_string`
++ it 'should replay a range of history correctly (range of commands)' do
++ o = Object.new
++ @hist.push "cd 1"
++ @hist.push "cd 2"
++
++ @t.eval("hist --replay 0..2")
++ stack = @t.eval("Pad.stack = _pry_.binding_stack.dup")
++ stack.map{ |b| b.eval("self") }.should == [TOPLEVEL_BINDING.eval("self"), 1, 2]
++ end
++
++ it 'should grep for correct lines in history' do
++ @hist.push "abby"
++ @hist.push "box"
++ @hist.push "button"
++ @hist.push "pepper"
++ @hist.push "orange"
++ @hist.push "grape"
++ @hist.push "def blah 1"
++ @hist.push "def boink 2"
++ @hist.push "place holder"
++
++ @t.eval('hist --grep o').should =~ /\d:.*?box\n\d:.*?button\n\d:.*?orange/
++
++ # test more than one word in a regex match (def blah)
++ @t.eval('hist --grep def blah').should =~ /def blah 1/
++
++ # test more than one word with leading white space in a regex match (def boink)
++ @t.eval('hist --grep def boink').should =~ /def boink 2/
++ end
++
++ it 'should return last N lines in history with --tail switch' do
++ ("a".."z").each do |v|
++ @hist.push v
++ end
++
++ out = @t.eval 'hist --tail 3'
++ out.each_line.count.should == 3
++ out.should =~ /x\n\d+:.*y\n\d+:.*z/
++ end
++
++ it "should start from beginning if tail number is longer than history" do
++ @hist.push 'Hyacinth'
++ out = @t.eval 'hist --tail'
++ out.should =~ /Hyacinth/
++ end
++
++ it 'should apply --tail after --grep' do
++ @hist.push "print 1"
++ @hist.push "print 2"
++ @hist.push "puts 3"
++ @hist.push "print 4"
++ @hist.push "puts 5"
++
++ out = @t.eval 'hist --tail 2 --grep print'
++ out.each_line.count.should == 2
++ out.should =~ /\d:.*?print 2\n\d:.*?print 4/
++ end
++
++ it 'should apply --head after --grep' do
++ @hist.push "puts 1"
++ @hist.push "print 2"
++ @hist.push "puts 3"
++ @hist.push "print 4"
++ @hist.push "print 5"
++
++ out = @t.eval 'hist --head 2 --grep print'
++ out.each_line.count.should == 2
++ out.should =~ /\d:.*?print 2\n\d:.*?print 4/
++ end
++
++ # strangeness in this test is due to bug in Readline::HISTORY not
++ # always registering first line of input
++ it 'should return first N lines in history with --head switch' do
++ ("a".."z").each do |v|
++ @hist.push v
++ end
++
++ out = @t.eval 'hist --head 4'
++ out.each_line.count.should == 4
++ out.should =~ /a\n\d+:.*b\n\d+:.*c/
++ end
++
++ # strangeness in this test is due to bug in Readline::HISTORY not
++ # always registering first line of input
++ it 'should show lines between lines A and B with the --show switch' do
++ ("a".."z").each do |v|
++ @hist.push v
++ end
++
++ out = @t.eval 'hist --show 1..4'
++ out.each_line.count.should == 4
++ out.should =~ /b\n\d+:.*c\n\d+:.*d/
++ end
++
++ it "should store a call with `--replay` flag" do
++ @t.eval ":banzai"
++ @t.eval "hist --replay 1"
++ @t.eval("hist").should =~ /hist --replay 1/
++ end
++
++ it "should not contain lines produced by `--replay` flag" do
++ @t.eval ":banzai"
++ @t.eval ":geronimo"
++ @t.eval ":huzzah"
++ @t.eval("hist --replay 1..3")
++
++ output = @t.eval("hist")
++ output.should == "1: :banzai\n2: :geronimo\n3: :huzzah\n4: hist --replay 1..3\n"
++ end
++
++ it "should raise CommandError when index of `--replay` points out to another `hist --replay`" do
++ @t.eval ":banzai"
++ @t.eval "hist --replay 1"
++ lambda do
++ @t.eval "hist --replay 2"
++ end.should.raise(Pry::CommandError, /Replay index 4 points out to another replay call: `hist --replay 1`/)
++ end
++
++ it "should disallow execution of `--replay <i>` when CommandError raised" do
++ @t.eval "a = 0"
++ @t.eval "a += 1"
++ @t.eval "hist --replay 2"
++ lambda{
++ @t.eval "hist --replay 3"
++ }.should.raise(Pry::CommandError)
++ @t.eval("a").should == 2
++ @t.eval("hist").lines.to_a.size.should == 5
++ end
++
++ it "excludes Pry commands from the history with `-e` switch" do
++ @hist.push('a = 20')
++ @hist.push('ls')
++ pry_eval('hist -e').should == "1: a = 20\n"
++ end
++
++ describe "sessions" do
++ before do
++ @old_file = Pry.config.history.file
++ Pry.config.history.file = File.expand_path('spec/fixtures/pry_history')
++ @hist.load
++ end
++
++ after do
++ Pry.config.history.file = @old_file
++ end
++
++ it "displays history only for current session" do
++ @hist.push('hello')
++ @hist.push('world')
++
++ @t.eval('hist').should =~ /1:\shello\n2:\sworld/
++ end
++
++ it "displays all history (including the current sesion) with `--all` switch" do
++ @hist.push('goodbye')
++ @hist.push('world')
++
++ output = @t.eval('hist --all')
++ output.should =~ /1:\s:athos\n2:\s:porthos\n3:\s:aramis\n/
++ output.should =~ /4:\sgoodbye\n5:\sworld/
++ end
++ end
++end
+diff --git a/spec/commands/jump_to_spec.rb b/spec/commands/jump_to_spec.rb
+new file mode 100644
+index 0000000..d6958cf
+--- /dev/null
++++ b/spec/commands/jump_to_spec.rb
+@@ -0,0 +1,15 @@
++require_relative '../helper'
++
++describe "jump-to" do
++ it 'should jump to the proper binding index in the stack' do
++ pry_eval('cd 1', 'cd 2', 'jump-to 1', 'self').should == 1
++ end
++
++ it 'should print error when trying to jump to a non-existent binding index' do
++ pry_eval("cd 1", "cd 2", "jump-to 100").should =~ /Invalid nest level/
++ end
++
++ it 'should print error when trying to jump to the same binding index' do
++ pry_eval("cd 1", "cd 2", "jump-to 2").should =~ /Already/
++ end
++end
+diff --git a/spec/commands/ls_spec.rb b/spec/commands/ls_spec.rb
+new file mode 100644
+index 0000000..d03479c
+--- /dev/null
++++ b/spec/commands/ls_spec.rb
+@@ -0,0 +1,246 @@
++require_relative '../helper'
++
++describe "ls" do
++ describe "below ceiling" do
++ it "should stop before Object by default" do
++ pry_eval("cd Class.new{ def goo; end }.new", "ls").should.not =~ /Object/
++ pry_eval("cd Class.new{ def goo; end }", "ls -M").should.not =~ /Object/
++ end
++
++ it "should include object if -v is given" do
++ pry_eval("cd Class.new{ def goo; end }.new", "ls -m -v").should =~ /Object/
++ pry_eval("cd Class.new{ def goo; end }", "ls -vM").should =~ /Object/
++ end
++
++ it "should include super-classes by default" do
++ pry_eval(
++ "cd Class.new(Class.new{ def goo; end; public :goo }).new",
++ "ls").should =~ /goo/
++
++ pry_eval(
++ "cd Class.new(Class.new{ def goo; end; public :goo })",
++ "ls -M").should =~ /goo/
++ end
++
++ it "should not include super-classes when -q is given" do
++ pry_eval("cd Class.new(Class.new{ def goo; end }).new", "ls -q").should.not =~ /goo/
++ pry_eval("cd Class.new(Class.new{ def goo; end })", "ls -M -q").should.not =~ /goo/
++ end
++ end
++
++ describe "help" do
++ it 'should show help with -h' do
++ pry_eval("ls -h").should =~ /Usage: ls/
++ end
++ end
++
++ describe "BasicObject" do
++ it "should work on BasicObject" do
++ pry_eval("ls BasicObject.new").should =~ /BasicObject#methods:.*__send__/m
++ end
++
++ it "should work on subclasses of BasicObject" do
++ pry_eval(
++ "class LessBasic < BasicObject; def jaroussky; 5; end; end",
++ "ls LessBasic.new"
++ ).should =~ /LessBasic#methods:.*jaroussky/m
++ end
++ end
++
++ describe "immediates" do
++ it "should work on Fixnum" do
++ pry_eval("ls 5").should =~ /Fixnum#methods:.*modulo/m
++ end
++ end
++
++ describe "methods" do
++ it "should show public methods by default" do
++ output = pry_eval("ls Class.new{ def goo; end; public :goo }.new")
++ output.should =~ /methods: goo/
++ end
++
++ it "should not show protected/private by default" do
++ pry_eval("ls -M Class.new{ def goo; end; private :goo }").should.not =~ /goo/
++ pry_eval("ls Class.new{ def goo; end; protected :goo }.new").should.not =~ /goo/
++ end
++
++ it "should show public methods with -p" do
++ pry_eval("ls -p Class.new{ def goo; end }.new").should =~ /methods: goo/
++ end
++
++ it "should show protected/private methods with -p" do
++ pry_eval("ls -pM Class.new{ def goo; end; protected :goo }").should =~ /methods: goo/
++ pry_eval("ls -p Class.new{ def goo; end; private :goo }.new").should =~ /methods: goo/
++ end
++
++ it "should work for objects with an overridden method method" do
++ require 'net/http'
++ # This doesn't actually touch the network, promise!
++ pry_eval("ls Net::HTTP::Get.new('localhost')").should =~ /Net::HTTPGenericRequest#methods/
++ end
++
++ it "should work for objects which instance_variables returns array of symbol but there is no Symbol#downcase" do
++ test_case = "class Object; alias :fg :instance_variables; def instance_variables; fg.map(&:to_sym); end end;"
++ normalize = "class Object; def instance_variables; fg; end end;"
++
++ test = lambda do
++ begin
++ pry_eval(test_case, "class GeFromulate2; @flurb=1.3; end", "cd GeFromulate2", "ls")
++ pry_eval(normalize)
++ rescue
++ pry_eval(normalize)
++ raise
++ end
++ end
++
++ test.should.not.raise
++ end
++
++ it "should show error message when instance is given with -M option" do
++ error = lambda{ pry_eval("ls -M String.new") }.should.raise(Pry::CommandError)
++ error.message.should.match(/-M only makes sense with a Module or a Class/)
++ end
++
++
++ # see: https://travis-ci.org/pry/pry/jobs/5071918
++ unless Pry::Helpers::BaseHelpers.rbx?
++ it "should handle classes that (pathologically) define .ancestors" do
++ output = pry_eval("ls Class.new{ def self.ancestors; end; def hihi; end }")
++ output.should =~ /hihi/
++ end
++ end
++ end
++
++ describe 'with -l' do
++ it 'should find locals and sort by descending size' do
++ result = pry_eval("aa = 'asdf'; bb = 'xyz'", 'ls -l')
++ result.should.not =~ /=>/
++ result.should.not =~ /0x\d{5}/
++ result.should =~ /asdf.*xyz/m
++ end
++ it 'should not list pry noise' do
++ pry_eval('ls -l').should.not =~ /_(?:dir|file|ex|pry|out|in)_/
++ end
++ end
++
++ describe "when inside Modules" do
++ it "should still work" do
++ pry_eval(
++ "cd Module.new{ def foobie; end; public :foobie }",
++ "ls -M").should =~ /foobie/
++ end
++
++ it "should work for ivars" do
++ pry_eval(
++ "module StigmaT1sm; def foobie; @@gharble = 456; end; end",
++ "Object.new.tap{ |o| o.extend(StigmaT1sm) }.foobie",
++ "cd StigmaT1sm",
++ "ls -i").should =~ /@@gharble/
++ end
++
++ it "should include instance methods by default" do
++ output = pry_eval(
++ "ls Module.new{ def shinanagarns; 4; end; public :shinanagarns }")
++ output.should =~ /shinanagarns/
++ end
++
++ it "should behave normally when invoked on Module itself" do
++ pry_eval("ls Module").should.not =~ /Pry/
++ end
++ end
++
++ describe "constants" do
++ it "works on top-level" do
++ toplevel_consts = pry_eval('ls -c')
++ [/RUBY_PLATFORM/, /ARGF/, /STDOUT/].each do |const|
++ toplevel_consts.should =~ const
++ end
++ end
++
++ it "should show constants defined on the current module" do
++ pry_eval("class TempFoo1; BARGHL = 1; end", "ls TempFoo1").should =~ /BARGHL/
++ end
++
++ it "should not show constants defined on parent modules by default" do
++ pry_eval("class TempFoo2; LHGRAB = 1; end; class TempFoo3 < TempFoo2; BARGHL = 1; end", "ls TempFoo3").should.not =~ /LHGRAB/
++ end
++
++ it "should show constants defined on ancestors with -v" do
++ pry_eval("class TempFoo4; LHGRAB = 1; end; class TempFoo5 < TempFoo4; BARGHL = 1; end", "ls -v TempFoo5").should =~ /LHGRAB/
++ end
++
++ it "should not autoload constants!" do
++ autoload :McflurgleTheThird, "/tmp/this-file-d000esnat-exist.rb"
++ lambda{ pry_eval("ls -c") }.should.not.raise
++ end
++
++ it "should show constants for an object's class regardless of mixins" do
++ pry_eval(
++ "cd Pry.new",
++ "extend Module.new",
++ "ls -c"
++ ).should.match(/Method/)
++ end
++ end
++
++ describe "grep" do
++ it "should reduce the number of outputted things" do
++ pry_eval("ls -c Object").should =~ /ArgumentError/
++ pry_eval("ls -c Object --grep Run").should.not =~ /ArgumentError/
++ end
++
++ it "should still output matching things" do
++ pry_eval("ls -c Object --grep Run").should =~ /RuntimeError/
++ end
++ end
++
++ describe "when no arguments given" do
++ describe "when at the top-level" do
++ # rubinius has a bug that means local_variables of "main" aren't reported inside eval()
++ unless Pry::Helpers::BaseHelpers.rbx?
++ it "should show local variables" do
++ pry_eval("ls").should =~ /_pry_/
++ pry_eval("arbitrar = 1", "ls").should =~ /arbitrar/
++ end
++ end
++ end
++
++ describe "when in a class" do
++ it "should show constants" do
++ pry_eval("class GeFromulate1; FOOTIFICATE=1.3; end", "cd GeFromulate1", "ls").should =~ /FOOTIFICATE/
++ end
++
++ it "should show class variables" do
++ pry_eval("class GeFromulate2; @@flurb=1.3; end", "cd GeFromulate2", "ls").should =~ /@@flurb/
++ end
++
++ it "should show methods" do
++ pry_eval("class GeFromulate3; def self.mooflight; end ; end", "cd GeFromulate3", "ls").should =~ /mooflight/
++ end
++ end
++
++ describe "when in an object" do
++ it "should show methods" do
++ pry_eval("cd Class.new{ def self.fooerise; end; self }", "ls").should =~ /fooerise/
++ end
++
++ it "should show instance variables" do
++ pry_eval("cd Class.new", "@alphooent = 1", "ls").should =~ /@alphooent/
++ end
++ end
++ end
++
++ if Pry::Helpers::BaseHelpers.jruby?
++ describe 'on java objects' do
++ it 'should omit java-esque aliases by default' do
++ pry_eval('ls java.lang.Thread.current_thread').should =~ /\bthread_group\b/
++ pry_eval('ls java.lang.Thread.current_thread').should.not =~ /\bgetThreadGroup\b/
++ end
++
++ it 'should include java-esque aliases if requested' do
++ pry_eval('ls java.lang.Thread.current_thread -J').should =~ /\bthread_group\b/
++ pry_eval('ls java.lang.Thread.current_thread -J').should =~ /\bgetThreadGroup\b/
++ end
++ end
++ end
++end
+diff --git a/spec/commands/play_spec.rb b/spec/commands/play_spec.rb
+new file mode 100644
+index 0000000..ed75922
+--- /dev/null
++++ b/spec/commands/play_spec.rb
+@@ -0,0 +1,182 @@
++# This command needs a TONNE more tests for it, but i can't figure out
++# how to do them yet, and i really want to release. Sorry. Someone
++# come along and do a better job.
++
++require_relative '../helper'
++
++describe "play" do
++ before do
++ @o = Object.new
++ @t = pry_tester(@o)
++ end
++
++ describe "with an argument" do
++
++ # can't think of a f*cking way to test this!!
++ describe "implied file" do
++ # it 'should play from the file associated with the current binding' do
++ # # require 'fixtures/play_helper'
++ # end
++
++
++ # describe "integer" do
++ # it "should process one line from _pry_.last_file" do
++ # @t.process_command 'play --lines 1', @eval_str
++ # @eval_str.should =~ /bing = :bing\n/
++ # end
++ # end
++
++ # describe "range" do
++ # it "should process multiple lines at once from _pry_.last_file" do
++ # @t.process_command 'play --lines 1..3', @eval_str
++ # [/bing = :bing\n/, /bang = :bang\n/, /bong = :bong\n/].each { |str|
++ # @eval_str.should =~ str
++ # }
++ # end
++ end
++ end
++
++ describe "playing a file" do
++ it 'should play a file' do
++ @t.process_command 'play spec/fixtures/whereami_helper.rb'
++ @t.eval_string.should == unindent(<<-STR)
++ class Cor
++ def a; end
++ def b; end
++ def c; end
++ def d; end
++ end
++ STR
++ end
++
++
++ it 'should output file contents with print option' do
++ @t.process_command 'play --print spec/fixtures/whereami_helper.rb'
++ @t.last_output.should == unindent(<<-STR)
++ 1: class Cor
++ 2: def a; end
++ 3: def b; end
++ 4: def c; end
++ 5: def d; end
++ 6: end
++ STR
++ end
++ end
++
++ describe "whatever" do
++ before do
++ def @o.test_method
++ :test_method_content
++ end
++ end
++
++ it 'should play documentation with the -d switch' do
++ # @v = 10
++ # @y = 20
++ def @o.test_method
++ :test_method_content
++ end
++
++ @t.process_command 'play -d test_method'
++ @t.eval_string.should == unindent(<<-STR)
++ @v = 10
++ @y = 20
++ STR
++ end
++
++ it 'should restrict -d switch with --lines' do
++ # @x = 0
++ # @v = 10
++ # @y = 20
++ # @z = 30
++ def @o.test_method
++ :test_method_content
++ end
++
++ @t.process_command 'play -d test_method --lines 2..3'
++ @t.eval_string.should == unindent(<<-STR)
++ @v = 10
++ @y = 20
++ STR
++ end
++
++ it 'has pretty error messages when -d cant find object' do
++ lambda { @t.process_command "play -d sdfsdf" }.should.raise(Pry::CommandError).message.should.match(/Cannot locate/)
++ end
++
++ it 'should play a method (a single line)' do
++ @t.process_command 'play test_method --lines 2'
++ @t.eval_string.should == ":test_method_content\n"
++ end
++
++ it 'should properly reindent lines' do
++ def @o.test_method
++ 'hello world'
++ end
++
++ @t.process_command 'play test_method --lines 2'
++ @t.eval_string.should == "'hello world'\n"
++ end
++
++ it 'should APPEND to the input buffer when playing a method line, not replace it' do
++ @t.eval_string = unindent(<<-STR)
++ def another_test_method
++ STR
++
++ @t.process_command 'play test_method --lines 2'
++
++ @t.eval_string.should == unindent(<<-STR)
++ def another_test_method
++ :test_method_content
++ STR
++ end
++
++ it 'should play a method (multiple lines)' do
++ def @o.test_method
++ @var0 = 10
++ @var1 = 20
++ @var2 = 30
++ @var3 = 40
++ end
++
++ @t.process_command 'play test_method --lines 3..4'
++ @t.eval_string.should == unindent(<<-STR, 0)
++ @var1 = 20
++ @var2 = 30
++ STR
++ end
++
++ describe "play -i" do
++ it 'should play multi-ranged input expressions' do
++ a = b = c = d = e = 0
++ redirect_pry_io(InputTester.new('a += 1', 'b += 1',
++ 'c += 1', 'd += 1', 'e += 1',
++ "play -i 1..3"), StringIO.new) do
++ binding.pry
++ end
++
++ [a, b, c].all? { |v| v.should == 2 }
++ d.should == 1
++ end
++ end
++
++ describe "play -e" do
++ it 'should run an expression from given line number' do
++ def @o.test_method
++ @s = [
++ 1,2,3,
++ 4,5,6
++ ]
++ end
++
++ @t.process_command 'play test_method -e 2'
++ @t.eval_string.should == unindent(<<-STR, 0)
++ @s = [
++ 1,2,3,
++ 4,5,6
++ ]
++ STR
++ end
++ end
++ end
++end
+diff --git a/spec/commands/raise_up_spec.rb b/spec/commands/raise_up_spec.rb
+new file mode 100644
+index 0000000..bc45164
+--- /dev/null
++++ b/spec/commands/raise_up_spec.rb
+@@ -0,0 +1,56 @@
++require_relative '../helper'
++
++describe "raise-up" do
++ before do
++ @self = "Pad.self = self"
++ @inner = "Pad.inner = self"
++ @outer = "Pad.outer = self"
++ end
++
++ after do
++ Pad.clear
++ end
++
++ it "should raise the exception with raise-up" do
++ redirect_pry_io(InputTester.new("raise NoMethodError", "raise-up NoMethodError")) do
++ lambda { Object.new.pry }.should.raise NoMethodError
++ end
++ end
++
++ it "should raise an unamed exception with raise-up" do
++ redirect_pry_io(InputTester.new("raise 'stop'","raise-up 'noreally'")) do
++ lambda { Object.new.pry }.should.raise RuntimeError, "noreally"
++ end
++ end
++
++ it "should eat the exception at the last new pry instance on raise-up" do
++ redirect_pry_io(InputTester.new(":inner.pry", "raise NoMethodError", @inner,
++ "raise-up NoMethodError", @outer, "exit-all")) do
++ Pry.start(:outer)
++ end
++
++ Pad.inner.should == :inner
++ Pad.outer.should == :outer
++ end
++
++ it "should raise the most recently raised exception" do
++ lambda { mock_pry("raise NameError, 'homographery'","raise-up") }.should.raise NameError, 'homographery'
++ end
++
++ it "should allow you to cd up and (eventually) out" do
++ redirect_pry_io(InputTester.new("cd :inner", "raise NoMethodError", @inner,
++ "deep = :deep", "cd deep","Pad.deep = self",
++ "raise-up NoMethodError", "raise-up", @outer,
++ "raise-up", "exit-all")) do
++ lambda { Pry.start(:outer) }.should.raise NoMethodError
++ end
++
++ Pad.deep.should == :deep
++ Pad.inner.should == :inner
++ Pad.outer.should == :outer
++ end
++
++ it "should jump immediately out of nested contexts with !" do
++ lambda { mock_pry("cd 1", "cd 2", "cd 3", "raise-up! 'fancy that...'") }.should.raise RuntimeError, 'fancy that...'
++ end
++end
+diff --git a/spec/commands/reload_code_spec.rb b/spec/commands/reload_code_spec.rb
+new file mode 100644
+index 0000000..f471e4b
+--- /dev/null
++++ b/spec/commands/reload_code_spec.rb
+@@ -0,0 +1,21 @@
++require_relative '../helper'
++
++describe "reload_code" do
++ describe "reload_current_file" do
++ it 'raises an error source code not found' do
++ proc do
++ eval <<-RUBY, TOPLEVEL_BINDING, 'does_not_exist.rb', 1
++ pry_eval(binding, "reload-code")
++ RUBY
++ end.should.raise(Pry::CommandError)
++ end
++
++ it 'raises an error when class not found' do
++ proc do
++ pry_eval(
++ "cd Class.new(Class.new{ def goo; end; public :goo })",
++ "reload-code")
++ end.should.raise(Pry::CommandError)
++ end
++ end
++end
+diff --git a/spec/commands/save_file_spec.rb b/spec/commands/save_file_spec.rb
+new file mode 100644
+index 0000000..5041e90
+--- /dev/null
++++ b/spec/commands/save_file_spec.rb
+@@ -0,0 +1,177 @@
++require_relative '../helper'
++
++describe "save-file" do
++ before do
++ @tf = Tempfile.new(["pry", ".py"])
++ @path = @tf.path
++ @t = pry_tester
++ end
++
++ after do
++ @tf.close(true)
++ end
++
++ describe "-f" do
++ it 'should save a file to a file' do
++ temp_file do |f|
++ path = f.path
++ f.puts ":cute_horse"
++ f.flush
++
++ @t.eval("save-file '#{path}' --to '#{@path}'")
++
++
++ File.read(@path).should == File.read(path)
++ end
++ end
++ end
++
++ describe "-i" do
++ it 'should save input expressions to a file (single expression)' do
++ @t.eval ':horse_nostrils'
++ @t.eval "save-file -i 1 --to '#{@path}'"
++ File.read(@path).should == ":horse_nostrils\n"
++ end
++
++ it "should display a success message on save" do
++ @t.eval ':horse_nostrils'
++ @t.eval("save-file -i 1 --to '#{@path}'").should =~ /successfully saved/
++ end
++
++ it 'should save input expressions to a file (range)' do
++ @t.eval ':or_nostrils', ':sucking_up_all_the_oxygen', ':or_whatever'
++ @t.eval "save-file -i 1..2 --to '#{@path}'"
++ File.read(@path).should == ":or_nostrils\n:sucking_up_all_the_oxygen\n"
++ end
++
++ it 'should save multi-ranged input expressions' do
++ @t.eval ':or_nostrils', ':sucking_up_all_the_oxygen', ':or_whatever',
++ ':baby_ducks', ':cannot_escape'
++ @t.eval "save-file -i 1..2 -i 4..5 --to '#{@path}'"
++ File.read(@path).should == ":or_nostrils\n:sucking_up_all_the_oxygen\n:baby_ducks\n:cannot_escape\n"
++ end
++ end
++
++ describe "saving methods" do
++ before do
++ @o = Object.new
++ def @o.baby
++ :baby
++ end
++ def @o.bang
++ :bang
++ end
++
++ @t = pry_tester(@o)
++ end
++
++ describe "single method" do
++ it 'should save a method to a file' do
++ @t.eval "save-file --to '#{@path}' baby"
++ File.read(@path).should == Pry::Method.from_obj(@o, :baby).source
++ end
++
++ it "should display a success message on save" do
++ @t.eval("save-file --to '#{@path}' baby").should =~ /successfully saved/
++ end
++
++ it 'should save a method to a file truncated by --lines' do
++ @t.eval "save-file --to '#{@path}' baby --lines 2..4"
++
++ # must add 1 as first line of method is 1
++ File.read(@path).should ==
++ Pry::Method.from_obj(@o, :baby).source.lines.to_a[1..5].join
++ end
++ end
++
++ # TODO: do we want to reintroduce this spec??
++ #
++ # describe "multiple method" do
++ # it 'should save multiple methods to a file' do
++ # @t.eval "save-file #{@path} -m baby -m bang"
++
++ # File.read(@path).should == Pry::Method.from_obj(@o, :baby).source +
++ # Pry::Method.from_obj(@o, :bang).source
++ # end
++
++ # it 'should save multiple methods to a file trucated by --lines' do
++ # @t.eval "save-file #{@path} -m baby -m bang --lines 2..-2"
++
++ # # must add 1 as first line of method is 1
++ # File.read(@path).should == (Pry::Method.from_obj(@o, :baby).source +
++ # Pry::Method.from_obj(@o, :bang).source).lines.to_a[1..-2].join
++ # end
++
++ # it 'should save multiple methods to a file trucated by --lines 1 ' \
++ # '(single parameter, not range)' do
++ # @t.eval "save-file #{@path} -m baby -m bang --lines 1"
++
++ # # must add 1 as first line of method is 1
++ # File.read(@path).should == (Pry::Method.from_obj(@o, :baby).source +
++ # Pry::Method.from_obj(@o, :bang).source).lines.to_a[0]
++ # end
++ # end
++ end
++
++ describe "overwrite by default (no --append)" do
++ it 'should overwrite specified file with new input' do
++ @t.eval ':horse_nostrils'
++ @t.eval "save-file -i 1 --to '#{@path}'"
++
++ @t.eval ':sucking_up_all_the_oxygen'
++ @t.eval "save-file -i 2 --to '#{@path}'"
++
++ File.read(@path).should == ":sucking_up_all_the_oxygen\n"
++ end
++ end
++
++ describe "--append" do
++ it 'should append to end of specified file' do
++ @t.eval ':horse_nostrils'
++ @t.eval "save-file -i 1 --to '#{@path}'"
++
++ @t.eval ':sucking_up_all_the_oxygen'
++ @t.eval "save-file -i 2 --to '#{@path}' -a"
++
++ File.read(@path).should ==
++ ":horse_nostrils\n:sucking_up_all_the_oxygen\n"
++ end
++ end
++
++ describe "saving commands" do
++ it 'should save a command to a file' do
++ @t.eval "save-file --to '#{@path}' show-source"
++ cmd_source = Pry.config.commands["show-source"].source
++ File.read(@path).should == cmd_source
++ end
++ end
++
++ # TODO: reintroduce these specs at some point?
++ #
++ # describe "combined options" do
++ # before do
++ # @o = Object.new
++ # def @o.baby
++ # :baby
++ # end
++
++ # @t = pry_tester(@o)
++ # end
++
++ # it 'should save input cache and a method to a file (in that order)' do
++ # @t.eval ":horse_nostrils"
++ # @t.eval "save-file -i 1 -m baby #{@path}"
++
++ # File.read(@path).should == ":horse_nostrils\n" +
++ # Pry::Method.from_obj(@o, :baby).source
++ # end
++
++ # it 'should select a portion to save using --lines' do
++ # @t.eval ":horse_nostrils"
++ # @t.eval "save-file -i 1 -m baby #{@path} --lines 2..-2"
++
++ # str = ":horse_nostrils\n" + Pry::Method.from_obj(@o, :baby).source
++ # File.read(@path).should == str.lines.to_a[1..-2].join
++ # end
++ # end
++end
+diff --git a/spec/commands/shell_command_spec.rb b/spec/commands/shell_command_spec.rb
+new file mode 100644
+index 0000000..422fc3e
+--- /dev/null
++++ b/spec/commands/shell_command_spec.rb
+@@ -0,0 +1,63 @@
++require_relative '../helper'
++
++describe "Command::ShellCommand" do
++ describe 'cd' do
++ before do
++ @o = Object.new
++
++ @t = pry_tester(@o) do
++ def command_state
++ pry.command_state[Pry::Command::ShellCommand.match]
++ end
++ end
++ end
++
++ describe ".cd" do
++ before do
++ Dir.stubs(:chdir)
++ end
++
++ it "saves the current working directory" do
++ Dir.stubs(:pwd).returns("initial_path")
++
++ @t.eval ".cd new_path"
++ @t.command_state.old_pwd.should == "initial_path"
++ end
++
++ describe "given a path" do
++ it "sends the path to File.expand_path" do
++ Dir.expects(:chdir).with(File.expand_path("new_path"))
++ @t.eval ".cd new_path"
++ end
++ end
++
++ describe "given an empty string" do
++ it "sends ~ to File.expand_path" do
++ Dir.expects(:chdir).with(File.expand_path("~"))
++ @t.eval ".cd "
++ end
++ end
++
++ describe "given a dash" do
++ describe "given no prior directory" do
++ it "raises the correct error" do
++ lambda { @t.eval ".cd -" }.should.raise(StandardError).
++ message.should == "No prior directory available"
++ end
++ end
++
++ describe "given a prior directory" do
++ it "sends the user's last pry working directory to File.expand_path" do
++ Dir.stubs(:pwd).returns("initial_path")
++
++ Dir.expects(:chdir).with(File.expand_path("new_path"))
++ @t.eval ".cd new_path"
++
++ Dir.expects(:chdir).with(File.expand_path("initial_path"))
++ @t.eval ".cd -"
++ end
++ end
++ end
++ end
++ end
++end
+diff --git a/spec/commands/show_doc_spec.rb b/spec/commands/show_doc_spec.rb
+new file mode 100644
+index 0000000..6d347b3
+--- /dev/null
++++ b/spec/commands/show_doc_spec.rb
+@@ -0,0 +1,573 @@
++require_relative '../helper'
++require "fixtures/show_source_doc_examples"
++
++describe "show-doc" do
++ before do
++ @o = Object.new
++
++ # sample doc
++ def @o.sample_method
++ :sample
++ end
++
++ def @o.no_docs;end
++
++ end
++
++ it 'should output a method\'s documentation' do
++ pry_eval(binding, "show-doc @o.sample_method").should =~ /sample doc/
++ end
++
++ it 'should raise exception when cannot find docs' do
++ lambda { pry_eval(binding, "show-doc @o.no_docs") }.should.raise(Pry::CommandError)
++ end
++
++ it 'should output a method\'s documentation with line numbers' do
++ pry_eval(binding, "show-doc @o.sample_method -l").should =~ /\d: sample doc/
++ end
++
++ it 'should output a method\'s documentation with line numbers (base one)' do
++ pry_eval(binding, "show-doc @o.sample_method -b").should =~ /1: sample doc/
++ end
++
++ it 'should output a method\'s documentation if inside method without needing to use method name' do
++ # sample comment
++ def @o.sample
++ pry_eval(binding, 'show-doc').should =~ /sample comment/
++ end
++ @o.sample
++ end
++
++ describe "finding find super method docs with help of `--super` switch" do
++ before do
++ class Daddy
++ # daddy initialize!
++ def initialize(*args); end
++ end
++
++ class Classy < Daddy
++ # classy initialize!
++ def initialize(*args); end
++ end
++
++ class Grungy < Classy
++ # grungy initialize??
++ def initialize(*args); end
++ end
++
++ @o = Grungy.new
++
++ # instancey initialize!
++ def @o.initialize; end
++ end
++
++ after do
++ Object.remove_const(:Grungy)
++ Object.remove_const(:Classy)
++ Object.remove_const(:Daddy)
++ end
++
++ it "finds super method docs" do
++ output = pry_eval(binding, 'show-doc --super @o.initialize')
++ output.should =~ /grungy initialize/
++ end
++
++ it "traverses ancestor chain and finds super method docs" do
++ output = pry_eval(binding, 'show-doc -ss @o.initialize')
++ output.should =~ /classy initialize/
++ end
++
++ it "traverses ancestor chain even higher and finds super method doc" do
++ output = pry_eval(binding, 'show-doc @o.initialize -sss')
++ output.should =~ /daddy initialize/
++ end
++
++ it "finds super method docs without explicit method argument" do
++ fatty = Grungy.new
++
++ # fatty initialize!
++ def fatty.initialize
++ pry_eval(binding, 'show-doc --super')
++ end
++
++ output = fatty.initialize
++ output.should =~ /grungy initialize/
++ end
++
++ it "finds super method docs without `--super` but with the `super` keyword" do
++ fatty = Grungy.new
++
++ fatty.extend Module.new {
++ def initialize
++ :nibble
++ end
++ }
++
++ # fatty initialize!
++ def fatty.initialize
++ pry_eval(binding, 'show-doc --super --super')
++ end
++
++ output = fatty.initialize
++ output.should =~ /grungy initialize/
++ end
++ end
++
++ describe "rdoc highlighting" do
++ it "should syntax highlight code in rdoc" do
++ c = Class.new{
++ # This can initialize your class:
++ #
++ # a = c.new :foo
++ #
++ # @param foo
++ def initialize(foo); end
++ }
++
++ begin
++ t = pry_tester(binding)
++ t.eval("show-doc c#initialize").should =~ /c.new :foo/
++ Pry.config.color = true
++ # I don't want the test to rely on which colour codes are there, just to
++ # assert that "something" is being colourized.
++ t.eval("show-doc c#initialize").should.not =~ /c.new :foo/
++ ensure
++ Pry.config.color = false
++ end
++ end
++
++ it "should syntax highlight `code` in rdoc" do
++ c = Class.new{
++ # After initializing your class with `c.new(:foo)`, go have fun!
++ #
++ # @param foo
++ def initialize(foo); end
++ }
++
++ begin
++ t = pry_tester(binding)
++ t.eval("show-doc c#initialize").should =~ /c.new\(:foo\)/
++ Pry.config.color = true
++ # I don't want the test to rely on which colour codes are there, just to
++ # assert that "something" is being colourized.
++ t.eval("show-doc c#initialize").should.not =~ /c.new\(:foo\)/
++ ensure
++ Pry.config.color = false
++ end
++
++ end
++
++ it "should not syntax highlight `` inside code" do
++ c = Class.new{
++ # Convert aligned output (from many shell commands) into nested arrays:
++ #
++ # a = decolumnize `ls -l $HOME`
++ #
++ # @param output
++ def decolumnize(output); end
++ }
++
++ begin
++ t = pry_tester(binding)
++ Pry.config.color = true
++ t.eval("show-doc c#decolumnize").should =~ /ls -l \$HOME/
++ t.eval("show-doc c#decolumnize").should.not =~ /`ls -l \$HOME`/
++ ensure
++ Pry.config.color = false
++ end
++ end
++ end
++
++ describe "on sourcable objects" do
++ it "should show documentation for object" do
++ # this is a documentation
++ hello = proc { puts 'hello world!' }
++ mock_pry(binding, "show-doc hello").should =~ /this is a documentation/
++ end
++ end
++
++ describe "on modules" do
++ before do
++ # god this is boring1
++ class ShowSourceTestClass
++ def alpha
++ end
++ end
++
++ # god this is boring2
++ module ShowSourceTestModule
++ def alpha
++ end
++ end
++
++ # god this is boring3
++ ShowSourceTestClassWeirdSyntax = Class.new do
++ def beta
++ end
++ end
++
++ # god this is boring4
++ ShowSourceTestModuleWeirdSyntax = Module.new do
++ def beta
++ end
++ end
++ end
++
++ after do
++ Object.remove_const :ShowSourceTestClass
++ Object.remove_const :ShowSourceTestClassWeirdSyntax
++ Object.remove_const :ShowSourceTestModule
++ Object.remove_const :ShowSourceTestModuleWeirdSyntax
++ end
++
++ describe "basic functionality, should show docs for top-level module definitions" do
++ it 'should show docs for a class' do
++ pry_eval("show-doc ShowSourceTestClass").should =~
++ /god this is boring1/
++ end
++
++ it 'should show docs for a module' do
++ pry_eval("show-doc ShowSourceTestModule").should =~
++ /god this is boring2/
++ end
++
++ it 'should show docs for a class when Const = Class.new syntax is used' do
++ pry_eval("show-doc ShowSourceTestClassWeirdSyntax").should =~
++ /god this is boring3/
++ end
++
++ it 'should show docs for a module when Const = Module.new syntax is used' do
++ pry_eval("show-doc ShowSourceTestModuleWeirdSyntax").should =~
++ /god this is boring4/
++ end
++ end
++
++ describe "in REPL" do
++ it 'should find class defined in repl' do
++ t = pry_tester
++ t.eval <<-RUBY
++ # hello tobina
++ class TobinaMyDog
++ def woof
++ end
++ end
++ RUBY
++ t.eval('show-doc TobinaMyDog').should =~ /hello tobina/
++ Object.remove_const :TobinaMyDog
++ end
++ end
++
++ it 'should lookup module name with respect to current context' do
++ constant_scope(:AlphaClass, :BetaClass) do
++ # top-level beta
++ class BetaClass
++ def alpha
++ end
++ end
++
++ class AlphaClass
++ # nested beta
++ class BetaClass
++ def beta
++ end
++ end
++ end
++
++ pry_eval(AlphaClass, "show-doc BetaClass").should =~ /nested beta/
++ end
++ end
++
++ it 'should look up nested modules' do
++ constant_scope(:AlphaClass) do
++ class AlphaClass
++ # nested beta
++ class BetaClass
++ def beta
++ end
++ end
++ end
++
++ pry_eval("show-doc AlphaClass::BetaClass").should =~
++ /nested beta/
++ end
++ end
++
++ describe "show-doc -a" do
++ it 'should show the docs for all monkeypatches defined in different files' do
++ # local monkeypatch
++ class TestClassForShowSource
++ def beta
++ end
++ end
++
++ result = pry_eval("show-doc TestClassForShowSource -a")
++ result.should =~ /used by/
++ result.should =~ /local monkeypatch/
++ end
++
++ describe "messages relating to -a" do
++ it "displays the original definition by default (not a doc of a monkeypatch)" do
++ class TestClassForCandidatesOrder
++ def beta
++ end
++ end
++
++ result = pry_eval("show-doc TestClassForCandidatesOrder")
++ result.should =~ /Number of monkeypatches: 2/
++ result.should =~ /The first definition/
++ end
++
++ it 'indicates all available monkeypatches can be shown with -a ' \
++ '(when -a not used and more than one candidate exists for class)' do
++ # Still reading boring tests, eh?
++ class TestClassForShowSource
++ def beta
++ end
++ end
++
++ result = pry_eval('show-doc TestClassForShowSource')
++ result.should =~ /available monkeypatches/
++ end
++
++ it 'shouldnt say anything about monkeypatches when only one candidate exists for selected class' do
++ # Do not remove me.
++ class Aarrrrrghh
++ def o;end
++ end
++
++ result = pry_eval('show-doc Aarrrrrghh')
++ result.should.not =~ /available monkeypatches/
++ Object.remove_const(:Aarrrrrghh)
++ end
++ end
++ end
++
++ describe "when no class/module arg is given" do
++ before do
++ module TestHost
++
++ # hello there froggy
++ module M
++ def d; end
++ def e; end
++ end
++ end
++ end
++
++ after do
++ Object.remove_const(:TestHost)
++ end
++
++ it 'should return doc for current module' do
++ pry_eval(TestHost::M, "show-doc").should =~ /hello there froggy/
++ end
++ end
++
++ # FIXME: THis is nto a good spec anyway, because i dont think it
++ # SHOULD skip!
++ describe "should skip over broken modules" do
++ before do
++ module TestHost
++ # hello
++ module M
++ binding.eval("def a; end", "dummy.rb", 1)
++ binding.eval("def b; end", "dummy.rb", 2)
++ binding.eval("def c; end", "dummy.rb", 3)
++ end
++
++ # goodbye
++ module M
++ def d; end
++ def e; end
++ end
++ end
++ end
++
++ after do
++ Object.remove_const(:TestHost)
++ end
++
++ it 'should return doc for first valid module' do
++ result = pry_eval("show-doc TestHost::M")
++ result.should =~ /goodbye/
++ result.should.not =~ /hello/
++ end
++ end
++ end
++
++ describe "on commands" do
++ # mostly copied & modified from test_help.rb
++ before do
++ @oldset = Pry.config.commands
++ @set = Pry.config.commands = Pry::CommandSet.new do
++ import Pry::Commands
++ end
++ end
++
++ after do
++ Pry.config.commands = @oldset
++ end
++
++ it 'should display help for a specific command' do
++ pry_eval('show-doc ls').should =~ /Usage: ls/
++ end
++
++ it 'should display help for a regex command with a "listing"' do
++ @set.command /bar(.*)/, "Test listing", :listing => "foo" do; end
++ pry_eval('show-doc foo').should =~ /Test listing/
++ end
++
++ it 'should display help for a command with a spaces in its name' do
++ @set.command "command with spaces", "description of a command with spaces" do; end
++ pry_eval('show-doc command with spaces').should =~ /description of a command with spaces/
++ end
++
++ describe "class commands" do
++ before do
++ # pretty pink pincers
++ class LobsterLady < Pry::ClassCommand
++ match "lobster-lady"
++ description "nada."
++ def process
++ "lobster"
++ end
++ end
++
++ Pry.config.commands.add_command(LobsterLady)
++ end
++
++ after do
++ Object.remove_const(:LobsterLady)
++ end
++
++ it 'should display "help" when looking up by command name' do
++ pry_eval('show-doc lobster-lady').should =~ /nada/
++ Pry.config.commands.delete("lobster-lady")
++ end
++
++ it 'should display actual preceding comment for a class command, when class is used (rather than command name) when looking up' do
++ pry_eval('show-doc LobsterLady').should =~ /pretty pink pincers/
++ Pry.config.commands.delete("lobster-lady")
++ end
++ end
++ end
++
++ describe "should set _file_ and _dir_" do
++ it 'should set _file_ and _dir_ to file containing method source' do
++ t = pry_tester
++ t.process_command "show-doc TestClassForShowSource#alpha"
++ t.pry.last_file.should =~ /show_source_doc_examples/
++ t.pry.last_dir.should =~ /fixtures/
++ end
++ end
++
++ unless Pry::Helpers::BaseHelpers.rbx?
++ describe "can't find class docs" do
++ describe "for classes" do
++ before do
++ module Jesus
++ class Brian; end
++
++ # doink-doc
++ class Jingle
++ def a; :doink; end
++ end
++
++ class Jangle < Jingle; end
++ class Bangle < Jangle; end
++ end
++ end
++
++ after do
++ Object.remove_const(:Jesus)
++ end
++
++ it 'shows superclass doc' do
++ t = pry_tester
++ t.process_command "show-doc Jesus::Jangle"
++ t.last_output.should =~ /doink-doc/
++ end
++
++ it 'errors when class has no superclass to show' do
++ t = pry_tester
++ lambda { t.process_command "show-doc Jesus::Brian" }.should.raise(Pry::CommandError).message.
++ should =~ /Couldn't locate/
++ end
++
++ it 'shows warning when reverting to superclass docs' do
++ t = pry_tester
++ t.process_command "show-doc Jesus::Jangle"
++ t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Jangle.*Showing.*Jesus::Jingle instead/
++ end
++
++ it 'shows nth level superclass docs (when no intermediary superclasses have code either)' do
++ t = pry_tester
++ t.process_command "show-doc Jesus::Bangle"
++ t.last_output.should =~ /doink-doc/
++ end
++
++ it 'shows correct warning when reverting to nth level superclass' do
++ t = pry_tester
++ t.process_command "show-doc Jesus::Bangle"
++ t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Bangle.*Showing.*Jesus::Jingle instead/
++ end
++ end
++
++ describe "for modules" do
++ before do
++ module Jesus
++
++ # alpha-doc
++ module Alpha
++ def alpha; :alpha; end
++ end
++
++ module Zeta; end
++
++ module Beta
++ include Alpha
++ end
++
++ module Gamma
++ include Beta
++ end
++ end
++ end
++
++ after do
++ Object.remove_const(:Jesus)
++ end
++
++ it 'shows included module doc' do
++ t = pry_tester
++ t.process_command "show-doc Jesus::Beta"
++ t.last_output.should =~ /alpha-doc/
++ end
++
++ it 'shows warning when reverting to included module doc' do
++ t = pry_tester
++ t.process_command "show-doc Jesus::Beta"
++ t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Beta.*Showing.*Jesus::Alpha instead/
++ end
++
++ it 'errors when module has no included module to show' do
++ t = pry_tester
++ lambda { t.process_command "show-source Jesus::Zeta" }.should.raise(Pry::CommandError).message.
++ should =~ /Couldn't locate/
++ end
++
++ it 'shows nth level included module doc (when no intermediary modules have code either)' do
++ t = pry_tester
++ t.process_command "show-doc Jesus::Gamma"
++ t.last_output.should =~ /alpha-doc/
++ end
++
++ it 'shows correct warning when reverting to nth level included module' do
++ t = pry_tester
++ t.process_command "show-source Jesus::Gamma"
++ t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Gamma.*Showing.*Jesus::Alpha instead/
++ end
++ end
++ end
++ end
++end
+diff --git a/spec/commands/show_input_spec.rb b/spec/commands/show_input_spec.rb
+new file mode 100644
+index 0000000..6b2856b
+--- /dev/null
++++ b/spec/commands/show_input_spec.rb
+@@ -0,0 +1,17 @@
++require_relative '../helper'
++
++describe "show-input" do
++ before do
++ @t = pry_tester
++ end
++
++ it 'should correctly show the current lines in the input buffer' do
++ @t.push *unindent(<<-STR).split("\n")
++ def hello
++ puts :bing
++ STR
++
++ @t.process_command 'show-input'
++ @t.last_output.should =~ /\A\d+: def hello\n\d+: puts :bing/
++ end
++end
+diff --git a/spec/commands/show_source_spec.rb b/spec/commands/show_source_spec.rb
+new file mode 100644
+index 0000000..d624555
+--- /dev/null
++++ b/spec/commands/show_source_spec.rb
+@@ -0,0 +1,829 @@
++require_relative '../helper'
++require "fixtures/show_source_doc_examples"
++
++describe "show-source" do
++ before do
++ @o = Object.new
++ def @o.sample_method
++ :sample
++ end
++
++ Object.const_set(:Test, Module.new)
++ end
++
++ after do
++ Pad.clear
++ end
++
++ it "should output a method's source" do
++ pry_eval(binding, 'show-source @o.sample_method').should =~ /def @o.sample/
++ end
++
++ it "should output help" do
++ pry_eval('show-source -h').should =~ /Usage:\s+show-source/
++ end
++
++ it "should output a method's source with line numbers" do
++ pry_eval(binding, 'show-source -l @o.sample_method').should =~ /\d+: def @o.sample/
++ end
++
++ it "should output a method's source with line numbers starting at 1" do
++ pry_eval(binding, 'show-source -b @o.sample_method').should =~ /1: def @o.sample/
++ end
++
++ it "should output a method's source if inside method and no name given" do
++ def @o.sample
++ pry_eval(binding, 'show-source').should =~ /def @o.sample/
++ end
++ @o.sample
++ end
++
++ it "should output a method's source inside method using the -l switch" do
++ def @o.sample
++ pry_eval(binding, 'show-source -l').should =~ /def @o.sample/
++ end
++ @o.sample
++ end
++
++ it "should find methods even if there are spaces in the arguments" do
++ def @o.foo(*bars)
++ "Mr flibble"
++ self
++ end
++
++ out = pry_eval(binding, "show-source @o.foo('bar', 'baz bam').foo")
++ out.should =~ /Mr flibble/
++ end
++
++ it "should find methods even if the object overrides method method" do
++ c = Class.new{
++ def method;
++ 98
++ end
++ }
++
++ pry_eval(binding, "show-source c.new.method").should =~ /98/
++ end
++
++ it "should not show the source when a non-extant method is requested" do
++ c = Class.new{ def method; 98; end }
++ mock_pry(binding, "show-source c#wrongmethod").should =~ /Couldn't locate/
++ end
++
++ it "should find instance_methods if the class overrides instance_method" do
++ c = Class.new{
++ def method;
++ 98
++ end
++
++ def self.instance_method; 789; end
++ }
++
++ pry_eval(binding, "show-source c#method").should =~ /98/
++ end
++
++ it "should find instance methods with self#moo" do
++ c = Class.new{ def moo; "ve over!"; end }
++
++ pry_eval(binding, "cd c", "show-source self#moo").should =~ /ve over/
++ end
++
++ it "should not find instance methods with self.moo" do
++ c = Class.new{ def moo; "ve over!"; end }
++
++ proc {
++ pry_eval(binding, 'cd c', 'show-source self.moo')
++ }.should.raise(Pry::CommandError).message.should =~ /Couldn't locate/
++ end
++
++ it "should find normal methods with self.moo" do
++ c = Class.new{ def self.moo; "ve over!"; end }
++
++ pry_eval(binding, 'cd c', 'show-source self.moo').should =~ /ve over/
++ end
++
++ it "should not find normal methods with self#moo" do
++ c = Class.new{ def self.moo; "ve over!"; end }
++
++ proc {
++ pry_eval(binding, 'cd c', 'show-source self#moo')
++ }.should.raise(Pry::CommandError).message.should =~ /Couldn't locate/
++ end
++
++ it "should find normal methods (i.e non-instance methods) by default" do
++ c = Class.new{ def self.moo; "ve over!"; end }
++
++ pry_eval(binding, "cd c", "show-source moo").should =~ /ve over/
++ end
++
++ it "should find instance methods if no normal methods available" do
++ c = Class.new{ def moo; "ve over!"; end }
++
++ pry_eval(binding, "cd c", "show-source moo").should =~ /ve over/
++ end
++
++ describe "with -e option" do
++ before do
++ class FooBar
++ def bar
++ :bar
++ end
++ end
++ end
++
++ after do
++ Object.remove_const(:FooBar)
++ end
++
++ it "evaluates the argument as ruby and shows the source code for the returned value" do
++ ReplTester.start target: binding do
++ input 'show-source -e FooBar.new'
++ output /class FooBar/
++ end
++ end
++ end
++
++ it "should raise a CommandError when super method doesn't exist" do
++ def @o.foo(*bars); end
++
++ proc {
++ pry_eval(binding, "show-source --super @o.foo")
++ }.should.raise(Pry::CommandError).message.should =~ /No superclass found/
++ end
++
++ it "should output the source of a method defined inside Pry" do
++ out = pry_eval("def dyn_method\n:test\nend", 'show-source dyn_method')
++ out.should =~ /def dyn_method/
++ Object.remove_method :dyn_method
++ end
++
++ it 'should output source for an instance method defined inside pry' do
++ pry_tester.tap do |t|
++ t.eval "class Test::A\n def yo\n end\nend"
++ t.eval('show-source Test::A#yo').should =~ /def yo/
++ end
++ end
++
++ it 'should output source for a repl method defined using define_method' do
++ pry_tester.tap do |t|
++ t.eval "class Test::A\n define_method(:yup) {}\nend"
++ t.eval('show-source Test::A#yup').should =~ /define_method\(:yup\)/
++ end
++ end
++
++ it "should output the source of a command defined inside Pry" do
++ command_definition = %{
++ Pry.config.commands.command "hubba-hubba" do
++ puts "that's what she said!"
++ end
++ }
++ out = pry_eval(command_definition, 'show-source hubba-hubba')
++ out.should =~ /what she said/
++ Pry.config.commands.delete "hubba-hubba"
++ end
++
++ describe "finding super methods with help of `--super` switch" do
++ before do
++ class Foo
++ def foo(*bars)
++ :super_wibble
++ end
++ end
++ end
++
++ after do
++ Object.remove_const(:Foo)
++ end
++
++ it "finds super methods with explicit method argument" do
++
++ o = Foo.new
++ def o.foo(*bars)
++ :wibble
++ end
++
++ pry_eval(binding, "show-source --super o.foo").should =~ /:super_wibble/
++ end
++
++ it "finds super methods without explicit method argument" do
++ o = Foo.new
++ def o.foo(*bars)
++ :wibble
++ pry_eval(binding, 'show-source --super')
++ end
++
++ o.foo.should =~ /:super_wibble/
++ end
++
++ it "finds super methods with multiple --super " do
++ o = Foo.new
++
++ o.extend Module.new {
++ def foo
++ :nibble
++ end
++ }
++
++ def o.foo(*bars)
++ :wibble
++ pry_eval(binding, 'show-source --super --super')
++ end
++
++ o.foo.should =~ /:super_wibble/
++ end
++ end
++
++ describe "on sourcable objects" do
++ it "should output source defined inside pry" do
++ pry_tester.tap do |t|
++ t.eval "hello = proc { puts 'hello world!' }"
++ t.eval("show-source hello").should =~ /proc \{ puts/
++ end
++ end
++
++ it "should output source for procs/lambdas stored in variables" do
++ hello = proc { puts 'hello world!' }
++ pry_eval(binding, 'show-source hello').should =~ /proc \{ puts/
++ end
++
++ it "should output source for procs/lambdas stored in constants" do
++ HELLO = proc { puts 'hello world!' }
++ pry_eval(binding, "show-source HELLO").should =~ /proc \{ puts/
++ Object.remove_const(:HELLO)
++ end
++
++ it "should output source for method objects" do
++ def @o.hi; puts 'hi world'; end
++ meth = @o.method(:hi)
++ pry_eval(binding, "show-source meth").should =~ /puts 'hi world'/
++ end
++
++ describe "on variables that shadow methods" do
++ before do
++ @t = pry_tester.eval unindent(<<-EOS)
++ class ::TestHost
++ def hello
++ hello = proc { ' smile ' }
++ pry_tester(binding)
++ end
++ end
++ ::TestHost.new.hello
++ EOS
++ end
++
++ after do
++ Object.remove_const(:TestHost)
++ end
++
++ it "source of variable should take precedence over method that is being shadowed" do
++ source = @t.eval('show-source hello')
++ source.should.not =~ /def hello/
++ source.should =~ /proc \{ ' smile ' \}/
++ end
++
++ it "source of method being shadowed should take precedence over variable
++ if given self.meth_name syntax" do
++ @t.eval('show-source self.hello').should =~ /def hello/
++ end
++ end
++ end
++
++ describe "on variable or constant" do
++ before do
++ class TestHost
++ def hello
++ "hi there"
++ end
++ end
++ end
++
++ after do
++ Object.remove_const(:TestHost)
++ end
++
++ it "should output source of its class if variable doesn't respond to source_location" do
++ test_host = TestHost.new
++ pry_eval(binding, 'show-source test_host').
++ should =~ /class TestHost\n.*def hello/
++ end
++
++ it "should output source of its class if constant doesn't respond to source_location" do
++ TEST_HOST = TestHost.new
++ pry_eval(binding, 'show-source TEST_HOST').
++ should =~ /class TestHost\n.*def hello/
++ Object.remove_const(:TEST_HOST)
++ end
++ end
++
++ describe "on modules" do
++ before do
++ class ShowSourceTestSuperClass
++ def alpha
++ end
++ end
++
++ class ShowSourceTestClass<ShowSourceTestSuperClass
++ def alpha
++ end
++ end
++
++ module ShowSourceTestSuperModule
++ def alpha
++ end
++ end
++
++ module ShowSourceTestModule
++ include ShowSourceTestSuperModule
++ def alpha
++ end
++ end
++
++ ShowSourceTestClassWeirdSyntax = Class.new do
++ def beta
++ end
++ end
++
++ ShowSourceTestModuleWeirdSyntax = Module.new do
++ def beta
++ end
++ end
++ end
++
++ after do
++ Object.remove_const :ShowSourceTestSuperClass
++ Object.remove_const :ShowSourceTestClass
++ Object.remove_const :ShowSourceTestClassWeirdSyntax
++ Object.remove_const :ShowSourceTestSuperModule
++ Object.remove_const :ShowSourceTestModule
++ Object.remove_const :ShowSourceTestModuleWeirdSyntax
++ end
++
++ describe "basic functionality, should find top-level module definitions" do
++ it 'should show source for a class' do
++ pry_eval('show-source ShowSourceTestClass').
++ should =~ /class ShowSourceTestClass.*?def alpha/m
++ end
++
++ it 'should show source for a super class' do
++ pry_eval('show-source -s ShowSourceTestClass').
++ should =~ /class ShowSourceTestSuperClass.*?def alpha/m
++ end
++
++ it 'should show source for a module' do
++ pry_eval('show-source ShowSourceTestModule').
++ should =~ /module ShowSourceTestModule/
++ end
++
++ it 'should show source for an ancestor module' do
++ pry_eval('show-source -s ShowSourceTestModule').
++ should =~ /module ShowSourceTestSuperModule/
++ end
++
++ it 'should show source for a class when Const = Class.new syntax is used' do
++ pry_eval('show-source ShowSourceTestClassWeirdSyntax').
++ should =~ /ShowSourceTestClassWeirdSyntax = Class.new/
++ end
++
++ it 'should show source for a super class when Const = Class.new syntax is used' do
++ pry_eval('show-source -s ShowSourceTestClassWeirdSyntax').
++ should =~ /class Object/
++ end
++
++ it 'should show source for a module when Const = Module.new syntax is used' do
++ pry_eval('show-source ShowSourceTestModuleWeirdSyntax').
++ should =~ /ShowSourceTestModuleWeirdSyntax = Module.new/
++ end
++ end
++
++ before do
++ pry_eval unindent(<<-EOS)
++ class Dog
++ def woof
++ end
++ end
++
++ class TobinaMyDog < Dog
++ def woof
++ end
++ end
++ EOS
++ end
++
++ after do
++ Object.remove_const :Dog
++ Object.remove_const :TobinaMyDog
++ end
++
++ describe "in REPL" do
++ it 'should find class defined in repl' do
++ pry_eval('show-source TobinaMyDog').should =~ /class TobinaMyDog/
++ end
++
++ it 'should find superclass defined in repl' do
++ pry_eval('show-source -s TobinaMyDog').should =~ /class Dog/
++ end
++ end
++
++ it 'should lookup module name with respect to current context' do
++
++ constant_scope(:AlphaClass, :BetaClass) do
++ class BetaClass
++ def alpha
++ end
++ end
++
++ class AlphaClass
++ class BetaClass
++ def beta
++ end
++ end
++ end
++
++ pry_eval(AlphaClass, 'show-source BetaClass').should =~ /def beta/
++ end
++ end
++
++ it 'should lookup nested modules' do
++ constant_scope(:AlphaClass) do
++ class AlphaClass
++ class BetaClass
++ def beta
++ end
++ end
++ end
++
++ pry_eval('show-source AlphaClass::BetaClass').should =~ /class Beta/
++ end
++ end
++
++ # note that pry assumes a class is only monkey-patched at most
++ # ONCE per file, so will not find multiple monkeypatches in the
++ # SAME file.
++ describe "show-source -a" do
++ it 'should show the source for all monkeypatches defined in different files' do
++ class TestClassForShowSource
++ def beta
++ end
++ end
++
++ result = pry_eval('show-source TestClassForShowSource -a')
++ result.should =~ /def alpha/
++ result.should =~ /def beta/
++ end
++
++ it 'should show the source for a class_eval-based monkeypatch' do
++ TestClassForShowSourceClassEval.class_eval do
++ def class_eval_method
++ end
++ end
++
++ result = pry_eval('show-source TestClassForShowSourceClassEval -a')
++ result.should =~ /def class_eval_method/
++ end
++
++ it 'should ignore -a when object is not a module' do
++ TestClassForShowSourceClassEval.class_eval do
++ def class_eval_method
++ :bing
++ end
++ end
++
++ result = pry_eval('show-source TestClassForShowSourceClassEval#class_eval_method -a')
++ result.should =~ /bing/
++ end
++
++ it 'should show the source for an instance_eval-based monkeypatch' do
++ TestClassForShowSourceInstanceEval.instance_eval do
++ def instance_eval_method
++ end
++ end
++
++ result = pry_eval('show-source TestClassForShowSourceInstanceEval -a')
++ result.should =~ /def instance_eval_method/
++ end
++
++ describe "messages relating to -a" do
++ it 'indicates all available monkeypatches can be shown with -a when (when -a not used and more than one candidate exists for class)' do
++ class TestClassForShowSource
++ def beta
++ end
++ end
++
++ result = pry_eval('show-source TestClassForShowSource')
++ result.should =~ /available monkeypatches/
++ end
++
++ it 'shouldnt say anything about monkeypatches when only one candidate exists for selected class' do
++ class Aarrrrrghh
++ def o;end
++ end
++
++ result = pry_eval('show-source Aarrrrrghh')
++ result.should.not =~ /available monkeypatches/
++ Object.remove_const(:Aarrrrrghh)
++ end
++ end
++ end
++
++ describe "when show-source is invoked without a method or class argument" do
++ before do
++ module TestHost
++ class M
++ def alpha; end
++ def beta; end
++ end
++
++ module C
++ end
++
++ module D
++ def self.invoked_in_method
++ pry_eval(binding, 'show-source')
++ end
++ end
++ end
++ end
++
++ after do
++ Object.remove_const(:TestHost)
++ end
++
++ describe "inside a module" do
++ it 'should display module source by default' do
++ out = pry_eval(TestHost::M, 'show-source')
++ out.should =~ /class M/
++ out.should =~ /def alpha/
++ out.should =~ /def beta/
++ end
++
++ it 'should be unable to find module source if no methods defined' do
++ proc {
++ pry_eval(TestHost::C, 'show-source')
++ }.should.raise(Pry::CommandError).
++ message.should =~ /Couldn't locate/
++ end
++
++ it 'should display method code (rather than class) if Pry started inside method binding' do
++ out = TestHost::D.invoked_in_method
++ out.should =~ /invoked_in_method/
++ out.should.not =~ /module D/
++ end
++
++ it 'should display class source when inside instance' do
++ out = pry_eval(TestHost::M.new, 'show-source')
++ out.should =~ /class M/
++ out.should =~ /def alpha/
++ out.should =~ /def beta/
++ end
++
++ it 'should allow options to be passed' do
++ out = pry_eval(TestHost::M, 'show-source -b')
++ out.should =~ /\d:\s*class M/
++ out.should =~ /\d:\s*def alpha/
++ out.should =~ /\d:\s*def beta/
++ end
++
++ describe "should skip over broken modules" do
++ before do
++ module BabyDuck
++
++ module Muesli
++ binding.eval("def a; end", "dummy.rb", 1)
++ binding.eval("def b; end", "dummy.rb", 2)
++ binding.eval("def c; end", "dummy.rb", 3)
++ end
++
++ module Muesli
++ def d; end
++ def e; end
++ end
++ end
++ end
++
++ after do
++ Object.remove_const(:BabyDuck)
++ end
++
++ it 'should return source for first valid module' do
++ out = pry_eval('show-source BabyDuck::Muesli')
++ out.should =~ /def d; end/
++ out.should.not =~ /def a; end/
++ end
++ end
++ end
++ end
++ end
++
++ describe "on commands" do
++ before do
++ @oldset = Pry.config.commands
++ @set = Pry.config.commands = Pry::CommandSet.new do
++ import Pry::Commands
++ end
++ end
++
++ after do
++ Pry.config.commands = @oldset
++ end
++
++ describe "block commands" do
++ it 'should show source for an ordinary command' do
++ @set.command "foo", :body_of_foo do; end
++
++ pry_eval('show-source foo').should =~ /:body_of_foo/
++ end
++
++ it "should output source of commands using special characters" do
++ @set.command "!%$", "I gots the yellow fever" do; end
++
++ pry_eval('show-source !%$').should =~ /yellow fever/
++ end
++
++ it 'should show source for a command with spaces in its name' do
++ @set.command "foo bar", :body_of_foo_bar do; end
++
++ pry_eval('show-source foo bar').should =~ /:body_of_foo_bar/
++ end
++
++ it 'should show source for a command by listing name' do
++ @set.command /foo(.*)/, :body_of_foo_bar_regex, :listing => "bar" do; end
++
++ pry_eval('show-source bar').should =~ /:body_of_foo_bar_regex/
++ end
++ end
++
++ describe "create_command commands" do
++ it 'should show source for a command' do
++ @set.create_command "foo", "babble" do
++ def process() :body_of_foo end
++ end
++ pry_eval('show-source foo').should =~ /:body_of_foo/
++ end
++
++ it 'should show source for a command defined inside pry' do
++ pry_eval %{
++ _pry_.commands.create_command "foo", "babble" do
++ def process() :body_of_foo end
++ end
++ }
++ pry_eval('show-source foo').should =~ /:body_of_foo/
++ end
++ end
++
++ describe "real class-based commands" do
++ before do
++ class ::TemporaryCommand < Pry::ClassCommand
++ match 'temp-command'
++ def process() :body_of_temp end
++ end
++
++ Pry.config.commands.add_command(::TemporaryCommand)
++ end
++
++ after do
++ Object.remove_const(:TemporaryCommand)
++ end
++
++ it 'should show source for a command' do
++ pry_eval('show-source temp-command').should =~ /:body_of_temp/
++ end
++
++ it 'should show source for a command defined inside pry' do
++ pry_eval %{
++ class ::TemporaryCommandInPry < Pry::ClassCommand
++ match 'temp-command-in-pry'
++ def process() :body_of_temp end
++ end
++ }
++ Pry.config.commands.add_command(::TemporaryCommandInPry)
++ pry_eval('show-source temp-command-in-pry').should =~ /:body_of_temp/
++ Object.remove_const(:TemporaryCommandInPry)
++ end
++ end
++ end
++
++ describe "should set _file_ and _dir_" do
++ it 'should set _file_ and _dir_ to file containing method source' do
++ t = pry_tester
++ t.process_command "show-source TestClassForShowSource#alpha"
++ t.pry.last_file.should =~ /show_source_doc_examples/
++ t.pry.last_dir.should =~ /fixtures/
++ end
++ end
++
++ unless Pry::Helpers::BaseHelpers.rbx?
++ describe "can't find class/module code" do
++ describe "for classes" do
++ before do
++ module Jesus
++ module Pig
++ def lillybing; :lillybing; end
++ end
++
++ class Brian; end
++ class Jingle
++ def a; :doink; end
++ end
++
++ class Jangle < Jingle; include Pig; end
++ class Bangle < Jangle; end
++ end
++ end
++
++ after do
++ Object.remove_const(:Jesus)
++ end
++
++ it 'shows superclass code' do
++ t = pry_tester
++ t.process_command "show-source Jesus::Jangle"
++ t.last_output.should =~ /doink/
++ end
++
++ it 'ignores included modules' do
++ t = pry_tester
++ t.process_command "show-source Jesus::Jangle"
++ t.last_output.should.not =~ /lillybing/
++ end
++
++ it 'errors when class has no superclass to show' do
++ t = pry_tester
++ lambda { t.process_command "show-source Jesus::Brian" }.should.raise(Pry::CommandError).message.
++ should =~ /Couldn't locate/
++ end
++
++ it 'shows warning when reverting to superclass code' do
++ t = pry_tester
++ t.process_command "show-source Jesus::Jangle"
++ t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Jangle.*Showing.*Jesus::Jingle instead/
++ end
++
++ it 'shows nth level superclass code (when no intermediary superclasses have code either)' do
++ t = pry_tester
++ t.process_command "show-source Jesus::Bangle"
++ t.last_output.should =~ /doink/
++ end
++
++ it 'shows correct warning when reverting to nth level superclass' do
++ t = pry_tester
++ t.process_command "show-source Jesus::Bangle"
++ t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Bangle.*Showing.*Jesus::Jingle instead/
++ end
++ end
++
++ describe "for modules" do
++ before do
++ module Jesus
++ module Alpha
++ def alpha; :alpha; end
++ end
++
++ module Zeta; end
++
++ module Beta
++ include Alpha
++ end
++
++ module Gamma
++ include Beta
++ end
++ end
++ end
++
++ after do
++ Object.remove_const(:Jesus)
++ end
++
++ it 'shows included module code' do
++ t = pry_tester
++ t.process_command "show-source Jesus::Beta"
++ t.last_output.should =~ /alpha/
++ end
++
++ it 'shows warning when reverting to included module code' do
++ t = pry_tester
++ t.process_command "show-source Jesus::Beta"
++ t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Beta.*Showing.*Jesus::Alpha instead/
++ end
++
++ it 'errors when module has no included module to show' do
++ t = pry_tester
++ lambda { t.process_command "show-source Jesus::Zeta" }.should.raise(Pry::CommandError).message.
++ should =~ /Couldn't locate/
++ end
++
++ it 'shows nth level included module code (when no intermediary modules have code either)' do
++ t = pry_tester
++ t.process_command "show-source Jesus::Gamma"
++ t.last_output.should =~ /alpha/
++ end
++
++ it 'shows correct warning when reverting to nth level included module' do
++ t = pry_tester
++ t.process_command "show-source Jesus::Gamma"
++ t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Gamma.*Showing.*Jesus::Alpha instead/
++ end
++ end
++ end
++ end
++end
+diff --git a/spec/commands/watch_expression_spec.rb b/spec/commands/watch_expression_spec.rb
+new file mode 100644
+index 0000000..765c040
+--- /dev/null
++++ b/spec/commands/watch_expression_spec.rb
+@@ -0,0 +1,119 @@
++require_relative '../helper'
++
++describe "watch expression" do
++
++ # Custom eval that will:
++ # 1) Create an instance of pry that can use for multiple calls
++ # 2) Exercise the after_eval hook
++ # 3) Return the output
++ def eval(expr)
++ output = @tester.eval expr
++ @tester.pry.hooks.exec_hook :after_eval, nil, @tester.pry
++ output
++ end
++
++ before do
++ @tester = pry_tester
++ @tester.pry.hooks.clear :after_eval
++ eval "watch --delete"
++ end
++
++ it "registers the after_eval hook" do
++ eval 'watch 1+1'
++ @tester.pry.hooks.hook_exists?(:after_eval, :watch_expression).should == true
++ end
++
++ it "prints no watched expressions" do
++ eval('watch').should =~ /No watched expressions/
++ end
++
++ it "watches an expression" do
++ eval "watch 1+1"
++ eval('watch').should =~ /=> 2/
++ end
++
++ it "watches a local variable" do
++ eval 'foo = :bar'
++ eval 'watch foo'
++ eval('watch').should =~ /=> :bar/
++ end
++
++ it "prints when an expression changes" do
++ ReplTester.start do
++ input 'a = 1'
++ output '=> 1'
++
++ input 'watch a'
++ output "Watching a\nwatch: a => 1"
++
++ input "a = 2"
++ output "watch: a => 2\n=> 2"
++ end
++ end
++
++ it "prints when an expression is mutated" do
++ ReplTester.start do
++ input 'a = "one"'
++ output '=> "one"'
++
++ input 'watch a'
++ output %(Watching a\nwatch: a => "one")
++
++ input "a.sub! 'o', 'p'"
++ output %(watch: a => "pne"\n=> "pne")
++ end
++ end
++
++ it "doesn't print when an expresison remains the same" do
++ ReplTester.start do
++ input 'a = 1'
++ output '=> 1'
++
++ input 'watch a'
++ output "Watching a\nwatch: a => 1"
++
++ input "a = 1"
++ output "=> 1"
++ end
++ end
++
++ it "continues to work if you start a second pry instance" do
++ ReplTester.start do
++ input 'a = 1'
++ output '=> 1'
++
++ input 'watch a'
++ output "Watching a\nwatch: a => 1"
++
++ input "a = 2"
++ output "watch: a => 2\n=> 2"
++ end
++
++ ReplTester.start do
++ input 'b = 1'
++ output '=> 1'
++
++ input 'watch b'
++ output "Watching b\nwatch: b => 1"
++
++ input "b = 2"
++ output "watch: b => 2\n=> 2"
++ end
++ end
++
++ describe "deleting expressions" do
++ before do
++ eval 'watch :keeper'
++ eval 'watch :delete'
++ eval 'watch -d 2'
++ end
++
++ it "keeps keeper" do
++ eval('watch').should =~ /keeper/
++ end
++
++ it "deletes delete" do
++ eval('watch').should.not =~ /delete/
++ end
++ end
++end
+diff --git a/spec/commands/whereami_spec.rb b/spec/commands/whereami_spec.rb
+new file mode 100644
+index 0000000..f19f49d
+--- /dev/null
++++ b/spec/commands/whereami_spec.rb
+@@ -0,0 +1,237 @@
++require_relative '../helper'
++
++describe "whereami" do
++ it 'should work with methods that have been undefined' do
++ class Cor
++ def blimey!
++ Cor.send :undef_method, :blimey!
++ Pad.binding = binding
++ end
++ end
++
++ Cor.new.blimey!
++
++ # using [.] so the regex doesn't match itself
++ pry_eval(Pad.binding, 'whereami').should =~ /self[.]blimey!/
++
++ Object.remove_const(:Cor)
++ end
++
++ it 'should work in objects with no method methods' do
++ class Cor
++ def blimey!
++ pry_eval(binding, 'whereami').should =~ /Cor[#]blimey!/
++ end
++
++ def method; "moo"; end
++ end
++ Cor.new.blimey!
++ Object.remove_const(:Cor)
++ end
++
++ it 'should properly set _file_, _line_ and _dir_' do
++ class Cor
++ def blimey!
++ pry_eval(binding, 'whereami', '_file_').
++ should == File.expand_path(__FILE__)
++ end
++ end
++
++ Cor.new.blimey!
++ Object.remove_const(:Cor)
++ end
++
++ it 'should work in BasicObjects' do
++ cor = Class.new(BasicObject) do
++ def blimey!
++ ::Kernel.binding # omnom
++ end
++ end.new.blimey!
++
++ pry_eval(cor, 'whereami').should =~ /::Kernel.binding [#] omnom/
++ end
++
++ it 'should show description and correct code when __LINE__ and __FILE__ are outside @method.source_location' do
++ class Cor
++ def blimey!
++ eval <<-END, binding, "spec/fixtures/example.erb", 1
++ pry_eval(binding, 'whereami')
++ END
++ end
++ end
++
++ Cor.instance_method(:blimey!).source.should =~ /pry_eval/
++ Cor.new.blimey!.should =~ /Cor#blimey!.*Look at me/m
++ Object.remove_const(:Cor)
++ end
++
++ it 'should show description and correct code when @method.source_location would raise an error' do
++ class Cor
++ eval <<-END, binding, "spec/fixtures/example.erb", 1
++ def blimey!
++ pry_eval(binding, 'whereami')
++ end
++ END
++ end
++
++ lambda{
++ Cor.instance_method(:blimey!).source
++ }.should.raise(MethodSource::SourceNotFoundError)
++
++ Cor.new.blimey!.should =~ /Cor#blimey!.*Look at me/m
++ Object.remove_const(:Cor)
++ end
++
++ # Now that we use stagger_output (paging output) we no longer get
++ # the "From: " line, as we output everything in one go (not separate output.puts)
++ # and so the user just gets a single `Error: Cannot open
++ # "not.found.file.erb" for reading.`
++ # which is good enough IMO. Unfortunately we can't test for it
++ # though, as we don't hook stdout.
++ #
++ # it 'should display a description and error if reading the file goes wrong' do
++ # class Cor
++ # def blimey!
++ # eval <<-END, binding, "not.found.file.erb", 7
++ # Pad.tester = pry_tester(binding)
++ # Pad.tester.eval('whereami')
++ # END
++ # end
++ # end
++
++ # proc { Cor.new.blimey! }.should.raise(MethodSource::SourceNotFoundError)
++
++ # Pad.tester.last_output.should =~
++ # /From: not.found.file.erb @ line 7 Cor#blimey!:/
++ # Object.remove_const(:Cor)
++ # end
++
++ it 'should show code window (not just method source) if parameter passed to whereami' do
++ class Cor
++ def blimey!
++ pry_eval(binding, 'whereami 3').should =~ /class Cor/
++ end
++ end
++ Cor.new.blimey!
++ Object.remove_const(:Cor)
++ end
++
++ it 'should show entire method when -m option used' do
++ old_size, Pry.config.default_window_size = Pry.config.default_window_size, 1
++ old_cutoff, Pry::Command::Whereami.method_size_cutoff = Pry::Command::Whereami.method_size_cutoff, 1
++ class Cor
++ def blimey!
++ 1
++ 2
++ pry_eval(binding, 'whereami -m').should =~ /def blimey/
++ end
++ end
++ Pry::Command::Whereami.method_size_cutoff, Pry.config.default_window_size = old_cutoff, old_size
++ Cor.new.blimey!
++ Object.remove_const(:Cor)
++ end
++
++ it 'should show entire file when -f option used' do
++ class Cor
++ def blimey!
++ 1
++ 2
++ pry_eval(binding, 'whereami -f').should =~ /show entire file when -f option used/
++ end
++ end
++ Cor.new.blimey!
++ Object.remove_const(:Cor)
++ end
++
++ describe "-c" do
++ it 'should show class when -c option used, and locate correct candidate' do
++ require 'fixtures/whereami_helper'
++ class Cor
++ def blimey!
++ 1
++ 2
++ out = pry_eval(binding, 'whereami -c')
++ out.should =~ /class Cor/
++ out.should =~ /blimey/
++ end
++ end
++ Cor.new.blimey!
++ Object.remove_const(:Cor)
++ end
++
++ it 'should show class when -c option used, and locate correct superclass' do
++ class Cor
++ def blimey!
++ 1
++ 2
++ out = pry_eval(binding, 'whereami -c')
++ out.should =~ /class Cor/
++ out.should =~ /blimey/
++ end
++ end
++
++ class Horse < Cor
++ def pig;end
++ end
++
++ Horse.new.blimey!
++ Object.remove_const(:Cor)
++ Object.remove_const(:Horse)
++ end
++
++ # https://github.com/rubinius/rubinius/pull/2247
++ unless Pry::Helpers::BaseHelpers.rbx?
++ it 'should show class when -c option used, and binding is outside a method' do
++ class Cor
++ def blimey;end
++
++ out = pry_eval(binding, 'whereami -c')
++ out.should =~ /class Cor/
++ out.should =~ /blimey/
++ end
++ Object.remove_const(:Cor)
++ end
++ end
++ end
++
++ it 'should not show line numbers or marker when -n switch is used' do
++ class Cor
++ def blimey!
++ out = pry_eval(binding, 'whereami -n')
++ out.should =~ /^\s*def/
++ out.should.not =~ /\=\>/
++ end
++ end
++ Cor.new.blimey!
++ Object.remove_const(:Cor)
++ end
++
++ it 'should use Pry.config.default_window_size for window size when outside a method context' do
++ old_size, Pry.config.default_window_size = Pry.config.default_window_size, 1
++ :litella
++ :pig
++ out = pry_eval(binding, 'whereami')
++ :punk
++ :sanders
++
++ out.should.not =~ /:litella/
++ out.should =~ /:pig/
++ out.should =~ /:punk/
++ out.should.not =~ /:sanders/
++
++ Pry.config.default_window_size = old_size
++ end
++
++ it "should work at the top level" do
++ pry_eval(Pry.toplevel_binding, 'whereami').should =~
++ /At the top level/
++ end
++
++ it "should work inside a class" do
++ pry_eval(Pry, 'whereami').should =~ /Inside Pry/
++ end
++
++ it "should work inside an object" do
++ pry_eval(Object.new, 'whereami').should =~ /Inside #<Object/
++ end
++end
+diff --git a/spec/completion_spec.rb b/spec/completion_spec.rb
+new file mode 100644
+index 0000000..1207f25
+--- /dev/null
++++ b/spec/completion_spec.rb
+@@ -0,0 +1,214 @@
++require_relative 'helper'
++require "readline" unless defined?(Readline)
++require "pry/input_completer"
++
++def completer_test(bind, pry=nil, assert_flag=true)
++ test = proc {|symbol|
++ Pry::InputCompleter.new(pry || Readline, pry).call(symbol[0..-2], :target => Pry.binding_for(bind)).include?(symbol).should == assert_flag}
++ return proc {|*symbols| symbols.each(&test) }
++end
++
++
++describe Pry::InputCompleter do
++ before do
++ # The AMQP gem has some classes like this:
++ # pry(main)> AMQP::Protocol::Test::ContentOk.name
++ # => :content_ok
++ module SymbolyName
++ def self.name; :symboly_name; end
++ end
++
++ @before_completer = Pry.config.completer
++ Pry.config.completer = Pry::InputCompleter
++ end
++
++ after do
++ Pry.config.completer = @before_completer
++ Object.remove_const :SymbolyName
++ end
++
++ # another jruby hack :((
++ if !Pry::Helpers::BaseHelpers.jruby?
++ it "should not crash if there's a Module that has a symbolic name." do
++ lambda{ Pry::InputCompleter.new(Readline).call "a.to_s.", :target => Pry.binding_for(Object.new) }.should.not.raise Exception
++ end
++ end
++
++ it 'should take parenthesis and other characters into account for symbols' do
++ lambda { Pry::InputCompleter.new(Readline).call(":class)", :target => Pry.binding_for(Object.new)) }.should.not.raise(RegexpError)
++ end
++
++ it 'should complete instance variables' do
++ object = Class.new.new
++
++ # set variables in appropriate scope
++ object.instance_variable_set(:'@name', 'Pry')
++ object.class.send(:class_variable_set, :'@@number', 10)
++
++ # check to see if variables are in scope
++ object.instance_variables.
++ map { |v| v.to_sym }.
++ include?(:'@name').should == true
++
++ object.class.class_variables.
++ map { |v| v.to_sym }.
++ include?(:'@@number').should == true
++
++ # Complete instance variables.
++ b = Pry.binding_for(object)
++ completer_test(b).call('@name', '@name.downcase')
++
++ # Complete class variables.
++ b = Pry.binding_for(object.class)
++ completer_test(b).call('@@number', '@@number.class')
++
++ end
++
++
++ it 'should complete for stdlib symbols' do
++
++ o = Object.new
++ # Regexp
++ completer_test(o).call('/foo/.extend')
++
++ # Array
++ completer_test(o).call('[1].push')
++
++ # Hash
++ completer_test(o).call('{"a" => "b"}.keys')
++
++ # Proc
++ completer_test(o).call('{2}.call')
++
++ # Symbol
++ completer_test(o).call(':symbol.to_s')
++
++ # Absolute Constant
++ completer_test(o).call('::IndexError')
++ end
++
++ it 'should complete for target symbols' do
++ o = Object.new
++
++ # Constant
++ module Mod
++ Con = 'Constant'
++ module Mod2
++ end
++ end
++
++ completer_test(Mod).call('Con')
++
++ # Constants or Class Methods
++ completer_test(o).call('Mod::Con')
++
++ # Symbol
++ foo = :symbol
++ completer_test(o).call(':symbol')
++
++ # Variables
++ class << o
++ attr_accessor :foo
++ end
++ o.foo = 'bar'
++ completer_test(binding).call('o.foo')
++
++ # trailing slash
++ Pry::InputCompleter.new(Readline).call('Mod2/', :target => Pry.binding_for(Mod)).include?('Mod2/').should == true
++ end
++
++ it 'should complete for arbitrary scopes' do
++ module Bar
++ @barvar = :bar
++ end
++
++ module Baz
++ @bar = Bar
++ @bazvar = :baz
++ Con = :constant
++ end
++
++ pry = Pry.new(:target => Baz)
++ pry.push_binding(Bar)
++
++ b = Pry.binding_for(Bar)
++ completer_test(b, pry).call("../@bazvar")
++ completer_test(b, pry).call('/Con')
++ end
++
++ it 'should complete for stdlib symbols' do
++
++ o = Object.new
++ # Regexp
++ completer_test(o).call('/foo/.extend')
++
++ # Array
++ completer_test(o).call('[1].push')
++
++ # Hash
++ completer_test(o).call('{"a" => "b"}.keys')
++
++ # Proc
++ completer_test(o).call('{2}.call')
++
++ # Symbol
++ completer_test(o).call(':symbol.to_s')
++
++ # Absolute Constant
++ completer_test(o).call('::IndexError')
++ end
++
++ it 'should complete for target symbols' do
++ o = Object.new
++
++ # Constant
++ module Mod
++ Con = 'Constant'
++ module Mod2
++ end
++ end
++
++ completer_test(Mod).call('Con')
++
++ # Constants or Class Methods
++ completer_test(o).call('Mod::Con')
++
++ # Symbol
++ foo = :symbol
++ completer_test(o).call(':symbol')
++
++ # Variables
++ class << o
++ attr_accessor :foo
++ end
++ o.foo = 'bar'
++ completer_test(binding).call('o.foo')
++
++ # trailing slash
++ Pry::InputCompleter.new(Readline).call('Mod2/', :target => Pry.binding_for(Mod)).include?('Mod2/').should == true
++ end
++
++ it 'should complete for arbitrary scopes' do
++ module Bar
++ @barvar = :bar
++ end
++
++ module Baz
++ @bar = Bar
++ @bazvar = :baz
++ Con = :constant
++ end
++
++ pry = Pry.new(:target => Baz)
++ pry.push_binding(Bar)
++
++ b = Pry.binding_for(Bar)
++ completer_test(b, pry).call("../@bazvar")
++ completer_test(b, pry).call('/Con')
++ end
++
++ it 'should not return nil in its output' do
++ pry = Pry.new
++ Pry::InputCompleter.new(Readline, pry).call("pry.", :target => binding).should.not.include nil
++ end
++end
+diff --git a/spec/config_spec.rb b/spec/config_spec.rb
+new file mode 100644
+index 0000000..228f30d
+--- /dev/null
++++ b/spec/config_spec.rb
+@@ -0,0 +1,189 @@
++require_relative 'helper'
++describe Pry::Config do
++ describe "reserved keys" do
++ it "raises an ArgumentError on assignment of a reserved key" do
++ local = Pry::Config.new
++ Pry::Config::RESERVED_KEYS.each do |key|
++ should.raise(ArgumentError) { local[key] = 1 }
++ end
++ end
++ end
++
++ describe "traversal to parent" do
++ it "traverses back to the parent when a local key is not found" do
++ local = Pry::Config.new Pry::Config.from_hash(foo: 1)
++ local.foo.should == 1
++ end
++
++ it "stores a local key and prevents traversal to the parent" do
++ local = Pry::Config.new Pry::Config.from_hash(foo: 1)
++ local.foo = 2
++ local.foo.should == 2
++ end
++
++ it "traverses through a chain of parents" do
++ root = Pry::Config.from_hash({foo: 21})
++ local1 = Pry::Config.new(root)
++ local2 = Pry::Config.new(local1)
++ local3 = Pry::Config.new(local2)
++ local3.foo.should == 21
++ end
++ end
++
++ describe ".from_hash" do
++ it "returns an object without a default" do
++ local = Pry::Config.from_hash({})
++ local.default.should == nil
++ end
++
++ it "returns an object with a default" do
++ default = Pry::Config.new(nil)
++ local = Pry::Config.from_hash({}, default)
++ local.default.should == local
++ end
++ end
++
++
++ describe "#respond_to_missing?" do
++ before do
++ @config = Pry::Config.new(nil)
++ end
++
++ it "returns a Method object for a dynamic key" do
++ @config["key"] = 1
++ method_obj = @config.method(:key)
++ method_obj.name.should == :key
++ method_obj.call.should == 1
++ end
++ end
++
++ describe "#respond_to?" do
++ before do
++ @config = Pry::Config.new(nil)
++ end
++
++ it "returns true for a local key" do
++ @config.zzfoo = 1
++ @config.respond_to?(:zzfoo).should == true
++ end
++
++ it "returns false for an unknown key" do
++ @config.respond_to?(:blahblah).should == false
++ end
++ end
++
++ describe "#default" do
++ it "returns nil" do
++ local = Pry::Config.new(nil)
++ local.default.should == nil
++ end
++
++ it "returns the default" do
++ default = Pry::Config.new(nil)
++ local = Pry::Config.new(default)
++ local.default.should == default
++ end
++ end
++
++ describe "#keys" do
++ it "returns an array of local keys" do
++ root = Pry::Config.from_hash({zoo: "boo"}, nil)
++ local = Pry::Config.from_hash({foo: "bar"}, root)
++ local.keys.should == ["foo"]
++ end
++ end
++
++ describe "#==" do
++ it "compares equality through the underlying lookup table" do
++ local1 = Pry::Config.new(nil)
++ local2 = Pry::Config.new(nil)
++ local1.foo = "hi"
++ local2.foo = "hi"
++ local1.should == local2
++ end
++
++ it "compares equality against an object who does not implement #to_hash" do
++ local1 = Pry::Config.new(nil)
++ local1.should.not == Object.new
++ end
++ end
++
++ describe "#forget" do
++ it "forgets a local key" do
++ local = Pry::Config.new Pry::Config.from_hash(foo: 1)
++ local.foo = 2
++ local.foo.should == 2
++ local.forget(:foo)
++ local.foo.should == 1
++ end
++ end
++
++ describe "#to_hash" do
++ it "provides a copy of local key & value pairs as a Hash" do
++ local = Pry::Config.new Pry::Config.from_hash(bar: true)
++ local.foo = "21"
++ local.to_hash.should == { "foo" => "21" }
++ end
++
++ it "returns a duplicate of the lookup table" do
++ local = Pry::Config.new(nil)
++ local.to_hash.merge!("foo" => 42)
++ local.foo.should.not == 42
++ end
++ end
++
++ describe "#merge!" do
++ before do
++ @config = Pry::Config.new(nil)
++ end
++
++ it "merges an object who returns a Hash through #to_hash" do
++ obj = Class.new { def to_hash() {epoch: 1} end }.new
++ @config.merge!(obj)
++ @config.epoch.should == 1
++ end
++
++ it "merges an object who returns a Hash through #to_h" do
++ obj = Class.new { def to_h() {epoch: 2} end }.new
++ @config.merge!(obj)
++ @config.epoch.should == 2
++ end
++
++ it "merges a Hash" do
++ @config.merge!(epoch: 420)
++ @config.epoch.should == 420
++ end
++
++ it "raises a TypeError for objects who can't become a Hash" do
++ should.raise(TypeError) { @config.merge!(Object.new) }
++ end
++ end
++
++ describe "#clear" do
++ before do
++ @local = Pry::Config.new(nil)
++ end
++
++ it "returns true" do
++ @local.clear.should == true
++ end
++
++ it "clears local assignments" do
++ @local.foo = 1
++ @local.clear
++ @local.to_hash.should == {}
++ end
++
++ it "is aliased as #refresh" do
++ @local.method(:clear).should == @local.method(:refresh)
++ end
++ end
++
++ describe "#[]=" do
++ it "stores keys as strings" do
++ local = Pry::Config.from_hash({})
++ local[:zoo] = "hello"
++ local.to_hash.should == { "zoo" => "hello" }
++ end
++ end
++end
+diff --git a/spec/control_d_handler_spec.rb b/spec/control_d_handler_spec.rb
+new file mode 100644
+index 0000000..1c83776
+--- /dev/null
++++ b/spec/control_d_handler_spec.rb
+@@ -0,0 +1,62 @@
++require_relative 'helper'
++
++describe Pry::DEFAULT_CONTROL_D_HANDLER do
++
++ describe "control-d press" do
++
++ before do
++ # Simulates a ^D press.
++ @control_d = "Pry::DEFAULT_CONTROL_D_HANDLER.call('', _pry_)"
++ end
++
++ describe "in an expression" do
++ it "should clear out passed string" do
++ str = 'hello world'
++ Pry::DEFAULT_CONTROL_D_HANDLER.call(str, nil)
++ str.should == ''
++ end
++ end
++
++ describe 'at top-level session' do
++ it 'should break out of a REPL loop' do
++ instance = Pry.new
++ instance.binding_stack.should.not.be.empty
++ instance.eval(nil).should.be.false
++ instance.binding_stack.should.be.empty
++ end
++ end
++
++ describe 'in a nested session' do
++ it 'should pop last binding from the binding stack' do
++ t = pry_tester
++ t.eval "cd Object.new"
++ t.eval("_pry_.binding_stack.size").should == 2
++ t.eval("_pry_.eval(nil)").should.be.true
++ t.eval("_pry_.binding_stack.size").should == 1
++ end
++
++ it "breaks out of the parent session" do
++ ReplTester.start do
++ input 'Pry::REPL.new(_pry_, :target => 10).start'
++ output ''
++ prompt(/10.*> $/)
++
++ input 'self'
++ output '=> 10'
++
++ input nil # Ctrl-D
++ output ''
++
++ input 'self'
++ output '=> main'
++
++ input nil # Ctrl-D
++ output '=> nil' # Exit value of nested REPL.
++ assert_exited
++ end
++ end
++ end
++
++ end
++
++end
+diff --git a/spec/documentation_helper_spec.rb b/spec/documentation_helper_spec.rb
+new file mode 100644
+index 0000000..8cab716
+--- /dev/null
++++ b/spec/documentation_helper_spec.rb
+@@ -0,0 +1,68 @@
++require_relative 'helper'
++
++describe Pry::Helpers::DocumentationHelpers do
++ before do
++ @helper = Pry::Helpers::DocumentationHelpers
++ end
++
++ describe "get_comment_content" do
++ it "should strip off the hash and unindent" do
++ @helper.get_comment_content(" # hello\n # world\n").should == "hello\nworld\n"
++ end
++
++ it "should strip out leading lines of hashes" do
++ @helper.get_comment_content("###############\n#hello\n#world\n").should == "hello\nworld\n"
++ end
++
++ it "should remove shebangs" do
++ @helper.get_comment_content("#!/usr/bin/env ruby\n# This is a program\n").should == "This is a program\n"
++ end
++
++ it "should unindent past separators" do
++ @helper.get_comment_content(" # Copyright Me <me at cirw.in>\n #--\n # So there.\n").should == "Copyright Me <me at cirw.in>\n--\nSo there.\n"
++ end
++ end
++
++ describe "process_rdoc" do
++ before do
++ Pry.config.color = true
++ end
++
++ after do
++ Pry.config.color = false
++ end
++
++ it "should syntax highlight indented code" do
++ @helper.process_rdoc(" 4 + 4\n").should.not == " 4 + 4\n"
++ end
++
++ it "should highlight words surrounded by +s" do
++ @helper.process_rdoc("the +parameter+").should =~ /the \e.*parameter\e.*/
++ end
++
++ it "should syntax highlight things in backticks" do
++ @helper.process_rdoc("for `Example`").should =~ /for `\e.*Example\e.*`/
++ end
++
++ it "should emphasise em tags" do
++ @helper.process_rdoc("for <em>science</em>").should == "for \e[1mscience\e[0m"
++ end
++
++ it "should emphasise italic tags" do
++ @helper.process_rdoc("for <i>science</i>").should == "for \e[1mscience\e[0m"
++ end
++
++ it "should syntax highlight code in <code>" do
++ @helper.process_rdoc("for <code>Example</code>").should =~ /for \e.*Example\e.*/
++ end
++
++ it "should not double-highlight backticks inside indented code" do
++ @helper.process_rdoc(" `echo 5`").should =~ /echo 5/
++ end
++
++ it "should not remove ++" do
++ @helper.process_rdoc("--\n comment in a bubble\n++").should =~ /\+\+/
++ end
++ end
++
++end
+diff --git a/spec/editor_spec.rb b/spec/editor_spec.rb
+new file mode 100644
+index 0000000..a26722a
+--- /dev/null
++++ b/spec/editor_spec.rb
+@@ -0,0 +1,68 @@
++require 'pathname'
++require_relative 'helper'
++
++describe Pry::Editor do
++ class Pry::Editor
++ public :build_editor_invocation_string
++ end
++
++ before do
++ # OS-specific tempdir name. For GNU/Linux it's "tmp", for Windows it's
++ # something "Temp".
++ @tf_dir =
++ if Pry::Helpers::BaseHelpers.mri_19?
++ Pathname.new(Dir::Tmpname.tmpdir)
++ else
++ Pathname.new(Dir.tmpdir)
++ end
++
++ @tf_path = File.join(@tf_dir.to_s, 'hello world.rb')
++
++ @editor = Pry::Editor.new(Pry.new)
++ end
++
++ unless Pry::Helpers::BaseHelpers.windows?
++ describe "build_editor_invocation_string" do
++ it 'should shell-escape files' do
++ invocation_str = @editor.build_editor_invocation_string(@tf_path, 5, true)
++ invocation_str.should =~ /#@tf_dir.+hello\\ world\.rb/
++ end
++ end
++ end
++
++ describe "build_editor_invocation_string on windows" do
++ before do
++ class Pry::Editor
++ def windows?; true; end
++ end
++ end
++
++ after do
++ class Pry::Editor
++ undef windows?
++ end
++ end
++
++ it "should replace / by \\" do
++ invocation_str = @editor.build_editor_invocation_string(@tf_path, 5, true)
++ invocation_str.should =~ %r(\\#{@tf_dir.basename}\\)
++ end
++
++ it "should not shell-escape files" do
++ invocation_str = @editor.build_editor_invocation_string(@tf_path, 5, true)
++ invocation_str.should =~ /hello world\.rb/
++ end
++ end
++
++ describe 'invoke_editor with a proc' do
++ it 'should not shell-escape files' do
++ editor = Pry::Editor.new(Pry.new(editor: proc{ |file, line, blocking|
++ @file = file
++ nil
++ }))
++
++ editor.invoke_editor(@tf_path, 10, true)
++ @file.should == @tf_path
++ end
++ end
++end
+diff --git a/spec/exception_whitelist_spec.rb b/spec/exception_whitelist_spec.rb
+new file mode 100644
+index 0000000..414abbb
+--- /dev/null
++++ b/spec/exception_whitelist_spec.rb
+@@ -0,0 +1,21 @@
++require_relative 'helper'
++
++describe "Pry.config.exception_whitelist" do
++ before do
++ @str_output = StringIO.new
++ end
++
++ it 'should rescue all exceptions NOT specified on whitelist' do
++ Pry.config.exception_whitelist.include?(NameError).should == false
++ lambda { Pry.start(self, :input => StringIO.new("raise NameError\nexit"), :output => @str_output) }.should.not.raise NameError
++ end
++
++ it 'should NOT rescue exceptions specified on whitelist' do
++ old_whitelist = Pry.config.exception_whitelist
++ Pry.config.exception_whitelist = [NameError]
++ lambda { Pry.start(self, :input => StringIO.new("raise NameError"), :output => @str_output) }.should.raise NameError
++ Pry.config.exception_whitelist = old_whitelist
++ end
++end
++
++
+diff --git a/spec/fixtures/candidate_helper1.rb b/spec/fixtures/candidate_helper1.rb
+new file mode 100644
+index 0000000..46056a5
+--- /dev/null
++++ b/spec/fixtures/candidate_helper1.rb
+@@ -0,0 +1,11 @@
++# rank 0
++class CandidateTest
++ def test1
++ end
++
++ def test2
++ end
++
++ def test3
++ end
++end
+diff --git a/spec/fixtures/candidate_helper2.rb b/spec/fixtures/candidate_helper2.rb
+new file mode 100644
+index 0000000..ebc22a9
+--- /dev/null
++++ b/spec/fixtures/candidate_helper2.rb
+@@ -0,0 +1,8 @@
++# rank 1
++class CandidateTest
++ def test4
++ end
++
++ def test5
++ end
++end
+diff --git a/spec/fixtures/cat_load_path b/spec/fixtures/cat_load_path
+new file mode 100644
+index 0000000..e69de29
+diff --git a/spec/fixtures/cat_load_path.rb b/spec/fixtures/cat_load_path.rb
+new file mode 100644
+index 0000000..e69de29
+diff --git a/spec/fixtures/example.erb b/spec/fixtures/example.erb
+new file mode 100644
+index 0000000..43c2efd
+--- /dev/null
++++ b/spec/fixtures/example.erb
+@@ -0,0 +1,5 @@
++<html>
++
++ Look at me, testing my erb!
++
++</html>
+diff --git a/spec/fixtures/example_nesting.rb b/spec/fixtures/example_nesting.rb
+new file mode 100644
+index 0000000..06c9050
+--- /dev/null
++++ b/spec/fixtures/example_nesting.rb
+@@ -0,0 +1,33 @@
++ # []
++class A # ["class A"]
++ def a; end # ["class A"]
++ class B; def b; end; end # ["class A", "class B"]
++end # []
++ # []
++class << A # ["class << A"]
++ class B # ["class << A", "class B"]
++ def c; end # ["class << A", "class B"]
++ end # ["class << A"]
++ # ["class << A"]
++ module F::B # ["class << A", "module F::B"]
++ def foo; end # ["class << A", "module F::B"]
++ end # ["class << A"]
++end # []
++ # []
++module (:symbol.class)::Exciting #
++ def foo; end #
++ class B #
++ def goo; end #
++ end #
++end # []
++ # []
++module C # ["module C"]
++ class D # ["module C", "class D"]
++ def guh; foo.end; end # ["module C", "class D"]
++ end # ["module C"]
++ def bar; :end; end # ["module C"]
++ class << new.bar; end # ["module C"]
++ class << new.bar; def f; end; end #
++ # ["module C"]
++ class << self; def mug; end; end # ["module C", "class << self"]
++end # []
+diff --git a/spec/fixtures/pry_history b/spec/fixtures/pry_history
+new file mode 100644
+index 0000000..6eb63d9
+--- /dev/null
++++ b/spec/fixtures/pry_history
+@@ -0,0 +1,3 @@
++:athos
++:porthos
++:aramis
+diff --git a/spec/fixtures/show_source_doc_examples.rb b/spec/fixtures/show_source_doc_examples.rb
+new file mode 100644
+index 0000000..90efc43
+--- /dev/null
++++ b/spec/fixtures/show_source_doc_examples.rb
+@@ -0,0 +1,22 @@
++# used by show_source_spec.rb and show_doc_spec.rb
++class TestClassForShowSource
++ #doc
++ def alpha
++ end
++end
++
++class TestClassForShowSourceClassEval
++ def alpha
++ end
++end
++
++class TestClassForShowSourceInstanceEval
++ def alpha
++ end
++end
++
++# The first definition (find the second one in show_doc_spec.rb).
++class TestClassForCandidatesOrder
++ def alpha
++ end
++end
+diff --git a/spec/fixtures/slinky.rb b/spec/fixtures/slinky.rb
+new file mode 100644
+index 0000000..e69de29
+diff --git a/spec/fixtures/slinky/stinky.rb b/spec/fixtures/slinky/stinky.rb
+new file mode 100644
+index 0000000..e69de29
+diff --git a/spec/fixtures/testlinkrc b/spec/fixtures/testlinkrc
+new file mode 120000
+index 0000000..a307d52
+--- /dev/null
++++ b/spec/fixtures/testlinkrc
+@@ -0,0 +1 @@
++testrc
+\ No newline at end of file
+diff --git a/spec/fixtures/testrc b/spec/fixtures/testrc
+new file mode 100644
+index 0000000..c1045c0
+--- /dev/null
++++ b/spec/fixtures/testrc
+@@ -0,0 +1,2 @@
++TEST_RC = [] if !Object.const_defined?(:TEST_RC)
++TEST_RC << 0
+diff --git a/spec/fixtures/testrcbad b/spec/fixtures/testrcbad
+new file mode 100644
+index 0000000..fad9f73
+--- /dev/null
++++ b/spec/fixtures/testrcbad
+@@ -0,0 +1,2 @@
++TEST_BEFORE_RAISE = 1
++raise "messin with ya"
+diff --git a/spec/fixtures/whereami_helper.rb b/spec/fixtures/whereami_helper.rb
+new file mode 100644
+index 0000000..661e932
+--- /dev/null
++++ b/spec/fixtures/whereami_helper.rb
+@@ -0,0 +1,6 @@
++class Cor
++ def a; end
++ def b; end
++ def c; end
++ def d; end
++end
+diff --git a/spec/helper.rb b/spec/helper.rb
+new file mode 100644
+index 0000000..b579d8c
+--- /dev/null
++++ b/spec/helper.rb
+@@ -0,0 +1,34 @@
++require 'bundler/setup'
++require 'pry/test/helper'
++Bundler.require :default, :test
++require_relative 'spec_helpers/bacon'
++require_relative 'spec_helpers/mock_pry'
++require_relative 'spec_helpers/repl_tester'
++
++if ENV["COVERAGE"]
++ require "simplecov"
++ SimpleCov.start
++end
++
++class Module
++ public :remove_const
++ public :remove_method
++end
++
++# turn warnings off (esp for Pry::Hooks which will generate warnings
++# in tests)
++$VERBOSE = nil
++
++Pad = Class.new do
++ include Pry::Config::Behavior
++end.new(nil)
++
++# to help with tracking down bugs that cause an infinite loop in the test suite
++if ENV["SET_TRACE_FUNC"]
++ require 'set_trace' if Pry::Helpers::BaseHelpers.rbx?
++ set_trace_func proc { |event, file, line, id, binding, classname|
++ STDERR.printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
++ }
++end
++
++puts "Ruby v#{RUBY_VERSION} (#{defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"}), Pry v#{Pry::VERSION}, method_source v#{MethodSource::VERSION}, CodeRay v#{CodeRay::VERSION}, Slop v#{Slop::VERSION}"
+diff --git a/spec/helpers/table_spec.rb b/spec/helpers/table_spec.rb
+new file mode 100644
+index 0000000..5b8dbc9
+--- /dev/null
++++ b/spec/helpers/table_spec.rb
+@@ -0,0 +1,105 @@
++require_relative '../helper'
++
++describe 'Formatting Table' do
++ it 'knows about colorized fitting' do
++ t = Pry::Helpers::Table.new %w(hihi), :column_count => 1
++ t.fits_on_line?(4).should == true
++ t.items = []
++ t.fits_on_line?(4).should == true
++
++ t.items = %w(hi hi)
++ t.fits_on_line?(4).should == true
++ t.column_count = 2
++ t.fits_on_line?(4).should == false
++
++ t.items = %w(
++ a ccc
++ bb dddd
++ ).sort
++ t.fits_on_line?(8).should == true
++ t.fits_on_line?(7).should == false
++ end
++
++ describe 'formatting - should order downward and wrap to columns' do
++ FAKE_COLUMNS = 62
++ def try_round_trip(expected)
++ things = expected.split(/\s+/).sort
++ actual = Pry::Helpers.tablify(things, FAKE_COLUMNS).to_s.strip
++ [expected, actual].each{|e| e.gsub! /\s+$/, ''}
++ if actual != expected
++ bar = '-'*25
++ puts \
++ bar+'expected'+bar,
++ expected,
++ bar+'actual'+bar,
++ actual
++ end
++ actual.should == expected
++ end
++
++ it 'should handle a tiny case' do
++ try_round_trip(<<-eot)
++asdf asfddd fdass
++ eot
++ end
++
++ it 'should handle the basic case' do
++ try_round_trip(<<-eot)
++aadd ddasffssdad sdsaadaasd ssfasaafssd
++adassdfffaasds f sdsfasddasfds ssssdaa
++assfsafsfsds fsasa ssdsssafsdasdf
++ eot
++ end
++
++ it 'should handle... another basic case' do
++ try_round_trip(<<-EOT)
++aaad dasaasffaasf fdasfdfss safdfdddsasd
++aaadfasassdfff ddadadassasdf fddsasadfssdss sasf
++aaddaafaf dddasaaaaaa fdsasad sddsa
++aas dfsddffdddsdfd ff sddsfsaa
++adasadfaaffds dsfafdsfdfssda ffadsfafsaafa ss
++asddaadaaadfdd dssdss ffssfsfafaadss ssas
++asdsdaa faadf fsddfff ssdfssff
++asfadsssaaad fasfaafdssd s
++ EOT
++ end
++
++ it 'should handle colors' do
++ try_round_trip(<<-EOT)
++\e[31maaaaaaaaaa\e[0m \e[31mccccccccccccccccccccccccccccc\e[0m
++\e[31mbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\e[0m \e[31mddddddddddddd\e[0m
++ EOT
++ end
++
++ it 'should handle empty input' do
++ try_round_trip('')
++ end
++
++ it 'should handle one-token input' do
++ try_round_trip('asdf')
++ end
++ end
++
++ describe 'line length is smaller than the length of the longest word' do
++ before do
++ element = 'swizzle'
++ @elem_len = element.length
++ @out = [element, 'crime', 'fun']
++ end
++
++ it 'should not raise error' do
++ should.not.raise(FloatDomainError) {
++ Pry::Helpers.tablify(@out, @elem_len - 1)
++ }
++ end
++
++ it 'should format output as one column' do
++ table = Pry::Helpers.tablify(@out, @elem_len - 1).to_s
++ table.should == "swizzle\ncrime \nfun "
++ end
++ end
++
++ describe 'decide between one-line or indented output' do
++ Pry::Helpers.tablify_or_one_line('head', %w(ing)).should == 'head: ing'
++ end
++end
+diff --git a/spec/history_array_spec.rb b/spec/history_array_spec.rb
+new file mode 100644
+index 0000000..3f392bb
+--- /dev/null
++++ b/spec/history_array_spec.rb
+@@ -0,0 +1,71 @@
++require_relative 'helper'
++
++describe Pry::HistoryArray do
++ before do
++ @array = Pry::HistoryArray.new 10
++ @populated = @array.dup << 1 << 2 << 3 << 4
++ end
++
++ it 'should have a maximum size specifed at creation time' do
++ @array.max_size.should == 10
++ end
++
++ it 'should be able to be added objects to' do
++ @populated.size.should == 4
++ @populated.to_a.should == [1, 2, 3, 4]
++ end
++
++ it 'should be able to access single elements' do
++ @populated[2].should == 3
++ end
++
++ it 'should be able to access negative indices' do
++ @populated[-1].should == 4
++ end
++
++ it 'should be able to access ranges' do
++ @populated[1..2].should == [2, 3]
++ end
++
++ it 'should be able to access ranges starting from a negative index' do
++ @populated[-2..3].should == [3, 4]
++ end
++
++ it 'should be able to access ranges ending at a negative index' do
++ @populated[2..-1].should == [3, 4]
++ end
++
++ it 'should be able to access ranges using only negative indices' do
++ @populated[-2..-1].should == [3, 4]
++ end
++
++ it 'should be able to use range where end is excluded' do
++ @populated[-2...-1].should == [3]
++ end
++
++ it 'should be able to access slices using a size' do
++ @populated[-3, 2].should == [2, 3]
++ end
++
++ it 'should remove older entries' do
++ 11.times { |n| @array << n }
++
++ @array[0].should == nil
++ @array[1].should == 1
++ @array[10].should == 10
++ end
++
++ it 'should not be larger than specified maximum size' do
++ 12.times { |n| @array << n }
++ @array.entries.compact.size.should == 10
++ end
++
++ it 'should pop!' do
++ @populated.pop!
++ @populated.to_a.should == [1, 2, 3]
++ end
++
++ it 'should return an indexed hash' do
++ @populated.to_h[0].should == @populated[0]
++ end
++end
+diff --git a/spec/history_spec.rb b/spec/history_spec.rb
+new file mode 100644
+index 0000000..0a7c66d
+--- /dev/null
++++ b/spec/history_spec.rb
+@@ -0,0 +1,154 @@
++require_relative 'helper'
++require 'tempfile'
++
++describe Pry do
++ before do
++ Pry.history.clear
++
++ @saved_history = "1\n2\n3\n"
++
++ Pry.history.loader = proc do |&blk|
++ @saved_history.lines.each { |l| blk.call(l) }
++ end
++
++ Pry.load_history
++ end
++
++ after do
++ Pry.history.clear
++ Pry.history.restore_default_behavior
++ Pry.history.instance_variable_set(:@original_lines, 0)
++ end
++
++ describe '#push' do
++ it "should not record duplicated lines" do
++ Pry.history << '3'
++ Pry.history << '_ += 1'
++ Pry.history << '_ += 1'
++ Pry.history.to_a.grep('_ += 1').count.should == 1
++ end
++
++ it "should not record empty lines" do
++ c = Pry.history.to_a.count
++ Pry.history << ''
++ Pry.history.to_a.count.should == c
++ end
++ end
++
++ describe "#clear" do
++ before do
++ @old_file = Pry.config.history.file
++ @hist_file_path = File.expand_path('spec/fixtures/pry_history')
++ Pry.config.history.file = @hist_file_path
++ Pry.history.clear
++ Pry.history.restore_default_behavior
++ Pry.load_history
++ end
++
++ after do
++ Pry.config.history.file = @old_file
++ end
++
++ it "clears this session's history" do
++ Pry.history.to_a.size.should > 0
++ Pry.history.clear
++ Pry.history.to_a.size.should == 0
++ end
++
++ it "doesn't affect the contents of the history file" do
++ Pry.history.to_a.size.should == 3
++ Pry.history.clear
++
++ File.open(@hist_file_path, 'r') { |fh|
++ file = fh.to_a
++
++ file.length.should == 3
++ file.any? { |a| a =~ /athos/ }.should == true
++ }
++ end
++ end
++
++ describe "#history_line_count" do
++ it "counts entries in history" do
++ Pry.history.clear
++ saved_history = "olgierd\ngustlik\njanek\ngrzes\ntomek\n"
++ Pry.history.loader = proc do |&blk|
++ saved_history.lines.each { |l| blk.call(l) }
++ end
++ Pry.load_history
++
++ Pry.history.history_line_count.should == 5
++ end
++ end
++
++ describe "#restore_default_behavior" do
++ it "restores loader" do
++ Pry.history.loader = proc {}
++ Pry.history.restore_default_behavior
++ Pry.history.loader.class.should == Method
++ Pry.history.loader.name.to_sym.should == :read_from_file
++ end
++
++ it "restores saver" do
++ Pry.history.saver = proc {}
++ Pry.history.restore_default_behavior
++ Pry.history.saver.class.should == Method
++ Pry.history.saver.name.to_sym.should == :save_to_file
++ end
++
++ it "restores pusher" do
++ Pry.history.pusher = proc {}
++ Pry.history.restore_default_behavior
++ Pry.history.pusher.class.should == Method
++ Pry.history.pusher.name.to_sym.should == :push_to_readline
++ end
++
++ it "restores clearer" do
++ Pry.history.clearer = proc {}
++ Pry.history.restore_default_behavior
++ Pry.history.clearer.class.should == Method
++ Pry.history.clearer.name.to_sym.should == :clear_readline
++ end
++ end
++
++ describe "#session_line_count" do
++ it "returns the number of lines in history from just this session" do
++ Pry.history << 'you?'
++ Pry.history << 'you are so precious'
++ Pry.history.session_line_count.should == 2
++ end
++ end
++
++ describe ".load_history" do
++ it "should read the contents of the file" do
++ Pry.history.to_a[-2..-1].should == %w(2 3)
++ end
++ end
++
++ describe "saving to a file" do
++ before do
++ @histfile = Tempfile.new(["pryhistory", "txt"])
++ @history = Pry::History.new(:file_path => @histfile.path)
++ Pry.config.history.should_save = true
++ @history.pusher = proc{ }
++ end
++
++ after do
++ @histfile.close(true)
++ Pry.config.history.should_save = false
++ end
++
++ it "should save lines to a file as they are written" do
++ @history.push "5"
++ File.read(@histfile.path).should == "5\n"
++ end
++
++ it "should interleave lines from many places" do
++ @history.push "5"
++ File.open(@histfile.path, 'a'){ |f| f.puts "6" }
++ @history.push "7"
++
++ File.read(@histfile.path).should == "5\n6\n7\n"
++ end
++ end
++end
+diff --git a/spec/hooks_spec.rb b/spec/hooks_spec.rb
+new file mode 100644
+index 0000000..ba28ce6
+--- /dev/null
++++ b/spec/hooks_spec.rb
+@@ -0,0 +1,475 @@
++require_relative 'helper'
++
++describe Pry::Hooks do
++ before do
++ @hooks = Pry::Hooks.new
++ end
++
++ describe "adding a new hook" do
++ it 'should not execute hook while adding it' do
++ run = false
++ @hooks.add_hook(:test_hook, :my_name) { run = true }
++ run.should == false
++ end
++
++ it 'should not allow adding of a hook with a duplicate name' do
++ @hooks.add_hook(:test_hook, :my_name) {}
++
++ lambda { @hooks.add_hook(:test_hook, :my_name) {} }.should.raise ArgumentError
++ end
++
++ it 'should create a new hook with a block' do
++ @hooks.add_hook(:test_hook, :my_name) { }
++ @hooks.hook_count(:test_hook).should == 1
++ end
++
++ it 'should create a new hook with a callable' do
++ @hooks.add_hook(:test_hook, :my_name, proc { })
++ @hooks.hook_count(:test_hook).should == 1
++ end
++
++ it 'should use block if given both block and callable' do
++ run = false
++ foo = false
++ @hooks.add_hook(:test_hook, :my_name, proc { foo = true }) { run = true }
++ @hooks.hook_count(:test_hook).should == 1
++ @hooks.exec_hook(:test_hook)
++ run.should == true
++ foo.should == false
++ end
++
++ it 'should raise if not given a block or any other object' do
++ lambda { @hooks.add_hook(:test_hook, :my_name) }.should.raise ArgumentError
++ end
++
++ it 'should create multiple hooks for an event' do
++ @hooks.add_hook(:test_hook, :my_name) {}
++ @hooks.add_hook(:test_hook, :my_name2) {}
++ @hooks.hook_count(:test_hook).should == 2
++ end
++
++ it 'should return a count of 0 for an empty hook' do
++ @hooks.hook_count(:test_hook).should == 0
++ end
++ end
++
++ describe "Pry::Hooks#merge" do
++ describe "merge!" do
++ it 'should merge in the Pry::Hooks' do
++ h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {}
++ h2 = Pry::Hooks.new
++
++ h2.merge!(h1)
++ h2.get_hook(:test_hook, :testing).should == h1.get_hook(:test_hook, :testing)
++ end
++
++ it 'should not share merged elements with original' do
++ h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {}
++ h2 = Pry::Hooks.new
++
++ h2.merge!(h1)
++ h2.add_hook(:test_hook, :testing2) {}
++ h2.get_hook(:test_hook, :testing2).should.not == h1.get_hook(:test_hook, :testing2)
++ end
++
++ it 'should NOT overwrite hooks belonging to shared event in receiver' do
++ h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {}
++ callable = proc {}
++ h2 = Pry::Hooks.new.add_hook(:test_hook, :testing2, callable)
++
++ h2.merge!(h1)
++ h2.get_hook(:test_hook, :testing2).should == callable
++ end
++
++ it 'should overwrite identical hook in receiver' do
++ callable1 = proc { :one }
++ h1 = Pry::Hooks.new.add_hook(:test_hook, :testing, callable1)
++ callable2 = proc { :two }
++ h2 = Pry::Hooks.new.add_hook(:test_hook, :testing, callable2)
++
++ h2.merge!(h1)
++ h2.get_hook(:test_hook, :testing).should == callable1
++ h2.hook_count(:test_hook).should == 1
++ end
++
++ it 'should preserve hook order' do
++ name = ""
++ h1 = Pry::Hooks.new
++ h1.add_hook(:test_hook, :testing3) { name << "h" }
++ h1.add_hook(:test_hook, :testing4) { name << "n" }
++
++ h2 = Pry::Hooks.new
++ h2.add_hook(:test_hook, :testing1) { name << "j" }
++ h2.add_hook(:test_hook, :testing2) { name << "o" }
++
++ h2.merge!(h1)
++ h2.exec_hook(:test_hook)
++
++ name.should == "john"
++ end
++
++ describe "merge" do
++ it 'should return a fresh, independent instance' do
++ h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {}
++ h2 = Pry::Hooks.new
++
++ h3 = h2.merge(h1)
++ h3.should.not == h1
++ h3.should.not == h2
++ end
++
++ it 'should contain hooks from original instance' do
++ h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {}
++ h2 = Pry::Hooks.new.add_hook(:test_hook2, :testing) {}
++
++ h3 = h2.merge(h1)
++ h3.get_hook(:test_hook, :testing).should == h1.get_hook(:test_hook, :testing)
++ h3.get_hook(:test_hook2, :testing).should == h2.get_hook(:test_hook2, :testing)
++ end
++
++ it 'should not affect original instances when new hooks are added' do
++ h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {}
++ h2 = Pry::Hooks.new.add_hook(:test_hook2, :testing) {}
++
++ h3 = h2.merge(h1)
++ h3.add_hook(:test_hook3, :testing) {}
++
++ h1.get_hook(:test_hook3, :testing).should == nil
++ h2.get_hook(:test_hook3, :testing).should == nil
++ end
++ end
++
++ end
++ end
++
++ describe "dupping a Pry::Hooks instance" do
++ it 'should share hooks with original' do
++ @hooks.add_hook(:test_hook, :testing) do
++ :none_such
++ end
++
++ hooks_dup = @hooks.dup
++ hooks_dup.get_hook(:test_hook, :testing).should == @hooks.get_hook(:test_hook, :testing)
++ end
++
++ it 'adding a new event to dupped instance should not affect original' do
++ @hooks.add_hook(:test_hook, :testing) { :none_such }
++ hooks_dup = @hooks.dup
++
++ hooks_dup.add_hook(:other_test_hook, :testing) { :okay_man }
++
++ hooks_dup.get_hook(:other_test_hook, :testing).should.not == @hooks.get_hook(:other_test_hook, :testing)
++ end
++
++ it 'adding a new hook to dupped instance should not affect original' do
++ @hooks.add_hook(:test_hook, :testing) { :none_such }
++ hooks_dup = @hooks.dup
++
++ hooks_dup.add_hook(:test_hook, :testing2) { :okay_man }
++
++ hooks_dup.get_hook(:test_hook, :testing2).should.not == @hooks.get_hook(:test_hook, :testing2)
++ end
++
++ end
++
++ describe "getting hooks" do
++ describe "get_hook" do
++ it 'should return the correct requested hook' do
++ run = false
++ fun = false
++ @hooks.add_hook(:test_hook, :my_name) { run = true }
++ @hooks.add_hook(:test_hook, :my_name2) { fun = true }
++ @hooks.get_hook(:test_hook, :my_name).call
++ run.should == true
++ fun.should == false
++ end
++
++ it 'should return nil if hook does not exist' do
++ @hooks.get_hook(:test_hook, :my_name).should == nil
++ end
++ end
++
++ describe "get_hooks" do
++ it 'should return a hash of hook names/hook functions for an event' do
++ hook1 = proc { 1 }
++ hook2 = proc { 2 }
++ @hooks.add_hook(:test_hook, :my_name1, hook1)
++ @hooks.add_hook(:test_hook, :my_name2, hook2)
++ hash = @hooks.get_hooks(:test_hook)
++ hash.size.should == 2
++ hash[:my_name1].should == hook1
++ hash[:my_name2].should == hook2
++ end
++
++ it 'should return an empty hash if no hooks defined' do
++ @hooks.get_hooks(:test_hook).should == {}
++ end
++ end
++ end
++
++ describe "clearing all hooks for an event" do
++ it 'should clear all hooks' do
++ @hooks.add_hook(:test_hook, :my_name) { }
++ @hooks.add_hook(:test_hook, :my_name2) { }
++ @hooks.add_hook(:test_hook, :my_name3) { }
++ @hooks.clear(:test_hook)
++ @hooks.hook_count(:test_hook).should == 0
++ end
++ end
++
++ describe "deleting a hook" do
++ it 'should successfully delete a hook' do
++ @hooks.add_hook(:test_hook, :my_name) {}
++ @hooks.delete_hook(:test_hook, :my_name)
++ @hooks.hook_count(:test_hook).should == 0
++ end
++
++ it 'should return the deleted hook' do
++ run = false
++ @hooks.add_hook(:test_hook, :my_name) { run = true }
++ @hooks.delete_hook(:test_hook, :my_name).call
++ run.should == true
++ end
++
++ it 'should return nil if hook does not exist' do
++ @hooks.delete_hook(:test_hook, :my_name).should == nil
++ end
++ end
++
++ describe "executing a hook" do
++ it 'should execute block hook' do
++ run = false
++ @hooks.add_hook(:test_hook, :my_name) { run = true }
++ @hooks.exec_hook(:test_hook)
++ run.should == true
++ end
++
++ it 'should execute proc hook' do
++ run = false
++ @hooks.add_hook(:test_hook, :my_name, proc { run = true })
++ @hooks.exec_hook(:test_hook)
++ run.should == true
++ end
++
++ it 'should execute a general callable hook' do
++ callable = Object.new.tap do |obj|
++ obj.instance_variable_set(:@test_var, nil)
++ class << obj
++ attr_accessor :test_var
++ def call() @test_var = true; end
++ end
++ end
++
++ @hooks.add_hook(:test_hook, :my_name, callable)
++ @hooks.exec_hook(:test_hook)
++ callable.test_var.should == true
++ end
++
++ it 'should execute all hooks for an event if more than one is defined' do
++ x = nil
++ y = nil
++ @hooks.add_hook(:test_hook, :my_name1) { y = true }
++ @hooks.add_hook(:test_hook, :my_name2) { x = true }
++ @hooks.exec_hook(:test_hook)
++ x.should == true
++ y.should == true
++ end
++
++ it 'should execute hooks in order' do
++ array = []
++ @hooks.add_hook(:test_hook, :my_name1) { array << 1 }
++ @hooks.add_hook(:test_hook, :my_name2) { array << 2 }
++ @hooks.add_hook(:test_hook, :my_name3) { array << 3 }
++ @hooks.exec_hook(:test_hook)
++ array.should == [1, 2, 3]
++ end
++
++ it 'return value of exec_hook should be that of last executed hook' do
++ @hooks.add_hook(:test_hook, :my_name1) { 1 }
++ @hooks.add_hook(:test_hook, :my_name2) { 2 }
++ @hooks.add_hook(:test_hook, :my_name3) { 3 }
++ @hooks.exec_hook(:test_hook).should == 3
++ end
++
++ it 'should add exceptions to the errors array' do
++ @hooks.add_hook(:test_hook, :foo1) { raise 'one' }
++ @hooks.add_hook(:test_hook, :foo2) { raise 'two' }
++ @hooks.add_hook(:test_hook, :foo3) { raise 'three' }
++ @hooks.exec_hook(:test_hook)
++ @hooks.errors.map(&:message).should == ['one', 'two', 'three']
++ end
++
++ it 'should return the last exception raised as the return value' do
++ @hooks.add_hook(:test_hook, :foo1) { raise 'one' }
++ @hooks.add_hook(:test_hook, :foo2) { raise 'two' }
++ @hooks.add_hook(:test_hook, :foo3) { raise 'three' }
++ @hooks.exec_hook(:test_hook).should == @hooks.errors.last
++ end
++ end
++
++ describe "integration tests" do
++ describe "when_started hook" do
++ it 'should yield options to the hook' do
++ options = nil
++ Pry.config.hooks.add_hook(:when_started, :test_hook) { |target, opt, _| options = opt }
++
++ redirect_pry_io(StringIO.new("exit"), out=StringIO.new) do
++ Pry.start binding, :hello => :baby
++ end
++
++ options[:hello].should == :baby
++
++ Pry.config.hooks.delete_hook(:when_started, :test_hook)
++ end
++
++ describe "target" do
++
++ it 'should yield the target, as a binding ' do
++ b = nil
++ Pry.config.hooks.add_hook(:when_started, :test_hook) { |target, opt, _| b = target }
++
++ redirect_pry_io(StringIO.new("exit"), out=StringIO.new) do
++ Pry.start 5, :hello => :baby
++ end
++
++ b.is_a?(Binding).should == true
++ Pry.config.hooks.delete_hook(:when_started, :test_hook)
++ end
++
++ it 'should yield the target to the hook' do
++ b = nil
++ Pry.config.hooks.add_hook(:when_started, :test_hook) { |target, opt, _| b = target }
++
++ redirect_pry_io(StringIO.new("exit"), out=StringIO.new) do
++ Pry.start 5, :hello => :baby
++ end
++
++ b.eval('self').should == 5
++ Pry.config.hooks.delete_hook(:when_started, :test_hook)
++ end
++ end
++
++ it 'should allow overriding of target (and binding_stack)' do
++ options = nil
++ o = Object.new
++ class << o; attr_accessor :value; end
++
++ Pry.config.hooks.add_hook(:when_started, :test_hook) { |target, opt, _pry_| _pry_.binding_stack = [Pry.binding_for(o)] }
++
++ redirect_pry_io(InputTester.new("@value = true","exit-all")) do
++ Pry.start binding, :hello => :baby
++ end
++
++ o.value.should == true
++ Pry.config.hooks.delete_hook(:when_started, :test_hook)
++ end
++
++ end
++
++ describe "after_session hook" do
++ it 'should always run, even if uncaught exception bubbles out of repl' do
++ o = OpenStruct.new
++ o.great_escape = Class.new(StandardError)
++
++ old_ew = Pry.config.exception_whitelist
++ Pry.config.exception_whitelist << o.great_escape
++
++ array = [1, 2, 3, 4, 5]
++
++ begin
++ redirect_pry_io(StringIO.new("raise great_escape"), out=StringIO.new) do
++ Pry.start o, :hooks => Pry::Hooks.new.add_hook(:after_session, :cleanup) { array = nil }
++ end
++ rescue => ex
++ exception = ex
++ end
++
++ # ensure that an exception really was raised and it broke out
++ # of the repl
++ exception.is_a?(o.great_escape).should == true
++
++ # check that after_session hook ran
++ array.should == nil
++
++ # cleanup after test
++ Pry.config.exception_whitelist = old_ew
++ end
++
++ describe "before_eval hook" do
++ describe "modifying input code" do
++ it 'should replace input code with code determined by hook' do
++ hooks = Pry::Hooks.new.add_hook(:before_eval, :quirk) { |code, pry| code.replace(":little_duck") }
++ redirect_pry_io(InputTester.new(":jemima", "exit-all"), out = StringIO.new) do
++ Pry.start(self, :hooks => hooks)
++ end
++ out.string.should =~ /little_duck/
++ out.string.should.not =~ /jemima/
++ end
++
++ it 'should not interfere with command processing when replacing input code' do
++ commands = Pry::CommandSet.new do
++ import_from Pry::Commands, "exit-all"
++
++ command "how-do-you-like-your-blue-eyed-boy-now-mister-death" do
++ output.puts "in hours of bitterness i imagine balls of sapphire, of metal"
++ end
++ end
++
++ hooks = Pry::Hooks.new.add_hook(:before_eval, :quirk) { |code, pry| code.replace(":little_duck") }
++ redirect_pry_io(InputTester.new("how-do-you-like-your-blue-eyed-boy-now-mister-death", "exit-all"), out = StringIO.new) do
++ Pry.start(self, :hooks => hooks, :commands => commands)
++ end
++ out.string.should =~ /in hours of bitterness i imagine balls of sapphire, of metal/
++ out.string.should.not =~ /little_duck/
++ end
++ end
++
++ end
++
++ describe "exceptions" do
++ before do
++ Pry.config.hooks.add_hook(:after_eval, :baddums){ raise "Baddums" }
++ Pry.config.hooks.add_hook(:after_eval, :simbads){ raise "Simbads" }
++ end
++
++ after do
++ Pry.config.hooks.delete_hook(:after_eval, :baddums)
++ Pry.config.hooks.delete_hook(:after_eval, :simbads)
++ end
++ it "should not raise exceptions" do
++ lambda{
++ mock_pry("1", "2", "3")
++ }.should.not.raise
++ end
++
++ it "should print out a notice for each exception raised" do
++ mock_pry("1").should =~ /after_eval hook failed: RuntimeError: Baddums\n.*after_eval hook failed: RuntimeError: Simbads/m
++ end
++ end
++ end
++ end
++
++ describe "anonymous hooks" do
++ it 'should allow adding of hook without a name' do
++ @hooks.add_hook(:test_hook, nil) {}
++ @hooks.hook_count(:test_hook).should == 1
++ end
++
++ it 'should only allow one anonymous hook to exist' do
++ @hooks.add_hook(:test_hook, nil) { }
++ @hooks.add_hook(:test_hook, nil) { }
++ @hooks.hook_count(:test_hook).should == 1
++ end
++
++ it 'should execute most recently added anonymous hook' do
++ x = nil
++ y = nil
++ @hooks.add_hook(:test_hook, nil) { y = 1 }
++ @hooks.add_hook(:test_hook, nil) { x = 2 }
++ @hooks.exec_hook(:test_hook)
++ y.should == nil
++ x.should == 2
++ end
++ end
++
++end
+diff --git a/spec/indent_spec.rb b/spec/indent_spec.rb
+new file mode 100644
+index 0000000..6be0270
+--- /dev/null
++++ b/spec/indent_spec.rb
+@@ -0,0 +1,301 @@
++require_relative 'helper'
++
++# Please keep in mind that any hash signs ("#") in the heredoc strings are
++# placed on purpose. Without these editors might remove the whitespace on empty
++# lines.
++describe Pry::Indent do
++ before do
++ @indent = Pry::Indent.new
++ end
++
++ it 'should indent an array' do
++ input = "array = [\n10,\n15\n]"
++ output = "array = [\n 10,\n 15\n]"
++
++ @indent.indent(input).should == output
++ end
++
++ it 'should indent a hash' do
++ input = "hash = {\n:name => 'Ruby'\n}"
++ output = "hash = {\n :name => 'Ruby'\n}"
++
++ @indent.indent(input).should == output
++ end
++
++ it 'should indent a function' do
++ input = "def\nreturn 10\nend"
++ output = "def\n return 10\nend"
++
++ @indent.indent(input).should == output
++ end
++
++ it 'should indent a module and class' do
++ input = "module Foo\n# Hello world\nend"
++ output = "module Foo\n # Hello world\nend"
++ input_class = "class Foo\n# Hello world\nend"
++ output_class = "class Foo\n # Hello world\nend"
++
++ @indent.indent(input).should == output
++ @indent.indent(input_class).should == output_class
++ end
++
++ it 'should indent separate lines' do
++ @indent.indent('def foo').should == 'def foo'
++ @indent.indent('return 10').should == ' return 10'
++ @indent.indent('end').should == 'end'
++ end
++
++ it 'should not indent single line statements' do
++ input = <<TXT.strip
++def hello; end
++puts "Hello"
++TXT
++
++ @indent.indent(input).should == input
++ end
++
++ it 'should handle multiple open and closing tokens on a line' do
++ input = <<TXT.strip
++[10, 15].each do |num|
++puts num
++end
++TXT
++
++ output = <<TXT.strip
++[10, 15].each do |num|
++ puts num
++end
++TXT
++
++ @indent.indent(input).should == output
++ end
++
++ it 'should properly indent nested code' do
++ input = <<TXT.strip
++module A
++module B
++class C
++attr_accessor :test
++# keep
++def number
++return 10
++end
++end
++end
++end
++TXT
++
++ output = <<TXT.strip
++module A
++ module B
++ class C
++ attr_accessor :test
++ # keep
++ def number
++ return 10
++ end
++ end
++ end
++end
++TXT
++
++ @indent.indent(input).should == output
++ end
++
++ it 'should indent statements such as if, else, etc' do
++ input = <<TXT.strip
++if a == 10
++#
++elsif a == 15
++#
++else
++#
++end
++#
++while true
++#
++end
++#
++for num in [10, 15, 20]
++#
++end
++#
++for num in [10, 15, 20] do
++#
++end
++TXT
++
++ output = <<TXT.strip
++if a == 10
++ #
++elsif a == 15
++ #
++else
++ #
++end
++#
++while true
++ #
++end
++#
++for num in [10, 15, 20]
++ #
++end
++#
++for num in [10, 15, 20] do
++ #
++end
++TXT
++
++ @indent.indent(input).should == output
++ end
++
++ it "should correctly handle while <foo> do" do
++ input = "while 5 do\n5\nend"
++ @indent.indent(input).should == "while 5 do\n 5\nend"
++ end
++
++ it "should ident case statements" do
++ input = <<TXT.strip
++case foo
++when 1
++2
++when 2
++if 3
++4
++end
++when 5
++#
++else
++#
++end
++TXT
++
++ output = <<TXT.strip
++case foo
++when 1
++ 2
++when 2
++ if 3
++ 4
++ end
++when 5
++ #
++else
++ #
++end
++TXT
++
++ @indent.indent(input).should == output
++ end
++
++ it "should indent correctly with nesting" do
++ @indent.indent("[[\n[]]\n]").should == "[[\n []]\n]"
++ @indent.reset.indent("[[\n[]]\n]").should == "[[\n []]\n]"
++ @indent.reset.indent("[[{\n[] =>\n[]}]\n]").should == "[[{\n [] =>\n []}]\n]"
++ end
++
++ it "should not indent single-line ifs" do
++ @indent.indent("foo if bar\n#").should == "foo if bar\n#"
++ @indent.reset.indent("foo() if bar\n#").should == "foo() if bar\n#"
++ @indent.reset.indent("foo 'hi' if bar\n#").should == "foo 'hi' if bar\n#"
++ @indent.reset.indent("foo 1 while bar\n#").should == "foo 1 while bar\n#"
++ @indent.reset.indent("super if true\n#").should == "super if true\n#"
++ @indent.reset.indent("true if false\n#").should == "true if false\n#"
++ @indent.reset.indent("String if false\n#").should == "String if false\n#"
++ end
++
++ it "should indent cunningly disguised ifs" do
++ @indent.indent("{1 => if bar\n#").should == "{1 => if bar\n #"
++ @indent.reset.indent("foo(if bar\n#").should == "foo(if bar\n #"
++ @indent.reset.indent("bar(baz, if bar\n#").should == "bar(baz, if bar\n #"
++ @indent.reset.indent("[if bar\n#").should == "[if bar\n #"
++ @indent.reset.indent("true; while bar\n#").should == "true; while bar\n #"
++ end
++
++ it "should differentiate single/multi-line unless" do
++ @indent.indent("foo unless bar\nunless foo\nbar\nend").should == "foo unless bar\nunless foo\n bar\nend"
++ end
++
++ it "should not indent single/multi-line until" do
++ @indent.indent("%w{baz} until bar\nuntil foo\nbar\nend").should == "%w{baz} until bar\nuntil foo\n bar\nend"
++ end
++
++ it "should indent begin rescue end" do
++ input = <<INPUT.strip
++begin
++doo :something => :wrong
++rescue => e
++doit :right
++end
++INPUT
++ output = <<OUTPUT.strip
++begin
++ doo :something => :wrong
++rescue => e
++ doit :right
++end
++OUTPUT
++
++ @indent.indent(input).should == output
++ end
++
++ it "should not indent inside strings" do
++ @indent.indent(%(def a\n"foo\nbar"\n end)).should == %(def a\n "foo\nbar"\nend)
++ @indent.indent(%(def a\nputs %w(foo\nbar), 'foo\nbar'\n end)).should == %(def a\n puts %w(foo\nbar), 'foo\nbar'\nend)
++ end
++
++ it "should not indent inside HEREDOCs" do
++ @indent.indent(%(def a\nputs <<FOO\n bar\nFOO\nbaz\nend)).should == %(def a\n puts <<FOO\n bar\nFOO\n baz\nend)
++ @indent.indent(%(def a\nputs <<-'^^'\n bar\n\t^^\nbaz\nend)).should == %(def a\n puts <<-'^^'\n bar\n\t^^\n baz\nend)
++ end
++
++ it "should not indent nested HEREDOCs" do
++ input = <<INPUT.strip
++def a
++puts <<FOO, <<-BAR, "baz", <<-':p'
++foo
++FOO
++bar
++BAR
++tongue
++:p
++puts :p
++end
++INPUT
++
++ output = <<OUTPUT.strip
++def a
++ puts <<FOO, <<-BAR, "baz", <<-':p'
++foo
++FOO
++bar
++BAR
++tongue
++:p
++ puts :p
++end
++OUTPUT
++
++ @indent.indent(input).should == output
++ end
++
++ describe "nesting" do
++ test = File.read("spec/fixtures/example_nesting.rb")
++
++ test.lines.each_with_index do |line, i|
++ result = line.split("#").last.strip
++ if result == ""
++ it "should fail to parse nesting on line #{i + 1} of example_nesting.rb" do
++ lambda {
++ Pry::Indent.nesting_at(test, i + 1)
++ }.should.raise(Pry::Indent::UnparseableNestingError)
++ end
++ else
++ it "should parse nesting on line #{i + 1} of example_nesting.rb" do
++ Pry::Indent.nesting_at(test, i + 1).should == eval(result)
++ end
++ end
++ end
++ end
++end
+diff --git a/spec/method/patcher_spec.rb b/spec/method/patcher_spec.rb
+new file mode 100644
+index 0000000..95b5f3e
+--- /dev/null
++++ b/spec/method/patcher_spec.rb
+@@ -0,0 +1,34 @@
++require_relative '../helper'
++
++describe Pry::Method::Patcher do
++
++ before do
++ @x = Object.new
++ def @x.test; :before; end
++ @method = Pry::Method(@x.method(:test))
++ end
++
++ it "should change the behaviour of the method" do
++ @x.test.should == :before
++ @method.redefine "def @x.test; :after; end\n"
++ @x.test.should == :after
++ end
++
++ it "should return a new method with new source" do
++ @method.source.strip.should == "def @x.test; :before; end"
++ @method.redefine("def @x.test; :after; end\n").
++ source.strip.should == "def @x.test; :after; end"
++ end
++
++ it "should change the source of new Pry::Method objects" do
++ @method.redefine "def @x.test; :after; end\n"
++ Pry::Method(@x.method(:test)).source.strip.should == "def @x.test; :after; end"
++ end
++
++ it "should preserve visibility" do
++ class << @x; private :test; end
++ @method.visibility.should == :private
++ @method.redefine "def @x.test; :after; end\n"
++ Pry::Method(@x.method(:test)).visibility.should == :private
++ end
++end
+diff --git a/spec/method_spec.rb b/spec/method_spec.rb
+new file mode 100644
+index 0000000..b667267
+--- /dev/null
++++ b/spec/method_spec.rb
+@@ -0,0 +1,507 @@
++require_relative 'helper'
++require 'set'
++
++describe Pry::Method do
++ it "should use String names for compatibility" do
++ klass = Class.new { def hello; end }
++ Pry::Method.new(klass.instance_method(:hello)).name.should == "hello"
++ end
++
++ describe ".from_str" do
++ it 'should look up instance methods if no methods available and no options provided' do
++ klass = Class.new { def hello; end }
++ meth = Pry::Method.from_str(:hello, Pry.binding_for(klass))
++ meth.should == klass.instance_method(:hello)
++ end
++
++ it 'should look up methods if no instance methods available and no options provided' do
++ klass = Class.new { def self.hello; end }
++ meth = Pry::Method.from_str(:hello, Pry.binding_for(klass))
++ meth.should == klass.method(:hello)
++ end
++
++ it 'should look up instance methods first even if methods available and no options provided' do
++ klass = Class.new { def hello; end; def self.hello; end }
++ meth = Pry::Method.from_str(:hello, Pry.binding_for(klass))
++ meth.should == klass.instance_method(:hello)
++ end
++
++ it 'should look up instance methods if "instance-methods" option provided' do
++ klass = Class.new { def hello; end; def self.hello; end }
++ meth = Pry::Method.from_str(:hello, Pry.binding_for(klass), {"instance-methods" => true})
++ meth.should == klass.instance_method(:hello)
++ end
++
++ it 'should look up methods if :methods option provided' do
++ klass = Class.new { def hello; end; def self.hello; end }
++ meth = Pry::Method.from_str(:hello, Pry.binding_for(klass), {:methods => true})
++ meth.should == klass.method(:hello)
++ end
++
++ it 'should look up instance methods using the Class#method syntax' do
++ klass = Class.new { def hello; end; def self.hello; end }
++ meth = Pry::Method.from_str("klass#hello", Pry.binding_for(binding))
++ meth.should == klass.instance_method(:hello)
++ end
++
++ it 'should look up methods using the object.method syntax' do
++ klass = Class.new { def hello; end; def self.hello; end }
++ meth = Pry::Method.from_str("klass.hello", Pry.binding_for(binding))
++ meth.should == klass.method(:hello)
++ end
++
++ it 'should NOT look up instance methods using the Class#method syntax if no instance methods defined' do
++ klass = Class.new { def self.hello; end }
++ meth = Pry::Method.from_str("klass#hello", Pry.binding_for(binding))
++ meth.should == nil
++ end
++
++ it 'should NOT look up methods using the object.method syntax if no methods defined' do
++ klass = Class.new { def hello; end }
++ meth = Pry::Method.from_str("klass.hello", Pry.binding_for(binding))
++ meth.should == nil
++ end
++
++ it 'should look up methods using klass.new.method syntax' do
++ klass = Class.new { def hello; :hello; end }
++ meth = Pry::Method.from_str("klass.new.hello", Pry.binding_for(binding))
++ meth.name.should == "hello"
++ end
++
++ it 'should take care of corner cases like mongo[] e.g Foo::Bar.new[]- issue 998' do
++ klass = Class.new { def []; :hello; end }
++ meth = Pry::Method.from_str("klass.new[]", Pry.binding_for(binding))
++ meth.name.should == "[]"
++ end
++
++ it 'should take care of cases like $ mongo[] - issue 998' do
++ f = Class.new { def []; :hello; end }.new
++ meth = Pry::Method.from_str("f[]", Pry.binding_for(binding))
++ meth.name.should == "[]"
++ end
++
++ it 'should look up instance methods using klass.meth#method syntax' do
++ klass = Class.new { def self.meth; Class.new; end }
++ meth = Pry::Method.from_str("klass.meth#initialize", Pry.binding_for(binding))
++ meth.name.should == "initialize"
++ end
++
++ it 'should look up methods using instance::bar syntax' do
++ klass = Class.new{ def self.meth; Class.new; end }
++ meth = Pry::Method.from_str("klass::meth", Pry.binding_for(binding))
++ meth.name.should == "meth"
++ end
++
++ it 'should not raise an exception if receiver does not exist' do
++ lambda { Pry::Method.from_str("random_klass.meth", Pry.binding_for(binding)) }.should.not.raise
++ end
++ end
++
++ describe '.from_binding' do
++ it 'should be able to pick a method out of a binding' do
++ Pry::Method.from_binding(Class.new{ def self.foo; binding; end }.foo).name.should == "foo"
++ end
++
++ it 'should NOT find a method from the toplevel binding' do
++ Pry::Method.from_binding(TOPLEVEL_BINDING).should == nil
++ end
++
++ it "should find methods that have been undef'd" do
++ c = Class.new do
++ def self.bar
++ class << self; undef bar; end
++ binding
++ end
++ end
++
++ m = Pry::Method.from_binding(c.bar)
++ m.name.should == "bar"
++ end
++
++ # Our source_location trick doesn't work, due to https://github.com/rubinius/rubinius/issues/953
++ unless Pry::Helpers::BaseHelpers.rbx?
++ it 'should find the super method correctly' do
++ a = Class.new{ def gag33; binding; end; def self.line; __LINE__; end }
++ b = Class.new(a){ def gag33; super; end }
++
++ g = b.new.gag33
++ m = Pry::Method.from_binding(g)
++
++ m.owner.should == a
++ m.source_line.should == a.line
++ m.name.should == "gag33"
++ end
++ end
++
++ it 'should find the right method if a super method exists' do
++ a = Class.new{ def gag; binding; end; }
++ b = Class.new(a){ def gag; super; binding; end; def self.line; __LINE__; end }
++
++ m = Pry::Method.from_binding(b.new.gag)
++
++ m.owner.should == b
++ m.source_line.should == b.line
++ m.name.should == "gag"
++ end
++
++ # Temporarily disabled to work around rubinius/rubinius#2871.
++ unless Pry::Helpers::BaseHelpers.rbx?
++ it "should find the right method from a BasicObject" do
++ a = Class.new(BasicObject) { def gag; ::Kernel.binding; end; def self.line; __LINE__; end }
++
++ m = Pry::Method.from_binding(a.new.gag)
++ m.owner.should == a
++ m.source_file.should == __FILE__
++ m.source_line.should == a.line
++ end
++ end
++
++ it 'should find the right method even if it was renamed and replaced' do
++ o = Object.new
++ class << o
++ def borscht
++ "nips"
++ binding
++ end
++ alias paella borscht
++ def borscht() paella end
++ end
++
++ m = Pry::Method.from_binding(o.borscht)
++ m.source.should == Pry::Method(o.method(:paella)).source
++ end
++ end
++
++ describe 'super' do
++ it 'should be able to find the super method on a bound method' do
++ a = Class.new{ def rar; 4; end }
++ b = Class.new(a){ def rar; super; end }
++
++ obj = b.new
++
++ zuper = Pry::Method(obj.method(:rar)).super
++ zuper.owner.should == a
++ zuper.receiver.should == obj
++ end
++
++ it 'should be able to find the super method of an unbound method' do
++ a = Class.new{ def rar; 4; end }
++ b = Class.new(a){ def rar; super; end }
++
++ zuper = Pry::Method(b.instance_method(:rar)).super
++ zuper.owner.should == a
++ end
++
++ it 'should return nil if no super method exists' do
++ a = Class.new{ def rar; super; end }
++
++ Pry::Method(a.instance_method(:rar)).super.should == nil
++ end
++
++ it 'should be able to find super methods defined on modules' do
++ m = Module.new{ def rar; 4; end }
++ a = Class.new{ def rar; super; end; include m }
++
++ zuper = Pry::Method(a.new.method(:rar)).super
++ zuper.owner.should == m
++ end
++
++ it 'should be able to find super methods defined on super-classes when there are modules in the way' do
++ a = Class.new{ def rar; 4; end }
++ m = Module.new{ def mooo; 4; end }
++ b = Class.new(a){ def rar; super; end; include m }
++
++ zuper = Pry::Method(b.new.method(:rar)).super
++ zuper.owner.should == a
++ end
++
++ it 'should be able to jump up multiple levels of bound method, even through modules' do
++ a = Class.new{ def rar; 4; end }
++ m = Module.new{ def rar; 4; end }
++ b = Class.new(a){ def rar; super; end; include m }
++
++ zuper = Pry::Method(b.new.method(:rar)).super
++ zuper.owner.should == m
++ zuper.super.owner.should == a
++ end
++ end
++
++ describe 'all_from_class' do
++ def should_find_method(name)
++ Pry::Method.all_from_class(@class).map(&:name).should.include(name)
++ end
++
++ it 'should be able to find public instance methods defined in a class' do
++ @class = Class.new{ def meth; 1; end }
++ should_find_method('meth')
++ end
++
++ it 'should be able to find private and protected instance methods defined in a class' do
++ @class = Class.new { protected; def prot; 1; end; private; def priv; 1; end }
++ should_find_method('priv')
++ should_find_method('prot')
++ end
++
++ it 'should find methods all the way up to Kernel' do
++ @class = Class.new
++ should_find_method('exit!')
++ end
++
++ it 'should be able to find instance methods defined in a super-class' do
++ @class = Class.new(Class.new{ def meth; 1; end }) {}
++ should_find_method('meth')
++ end
++
++ it 'should be able to find instance methods defined in modules included into this class' do
++ @class = Class.new{ include Module.new{ def meth; 1; end; } }
++ should_find_method('meth')
++ end
++
++ it 'should be able to find instance methods defined in modules included into super-classes' do
++ @class = Class.new(Class.new{ include Module.new{ def meth; 1; end; } })
++ should_find_method('meth')
++ end
++
++ it 'should attribute overridden methods to the sub-class' do
++ @class = Class.new(Class.new{ include Module.new{ def meth; 1; end; } }) { def meth; 2; end }
++ Pry::Method.all_from_class(@class).detect{ |x| x.name == 'meth' }.owner.should == @class
++ end
++
++ it 'should be able to find methods defined on a singleton class' do
++ @class = (class << Object.new; def meth; 1; end; self; end)
++ should_find_method('meth')
++ end
++
++ it 'should be able to find methods on super-classes when given a singleton class' do
++ @class = (class << Class.new{ def meth; 1; end}.new; self; end)
++ should_find_method('meth')
++ end
++ end
++
++ describe 'all_from_obj' do
++ describe 'on normal objects' do
++ def should_find_method(name)
++ Pry::Method.all_from_obj(@obj).map(&:name).should.include(name)
++ end
++
++ it "should find methods defined in the object's class" do
++ @obj = Class.new{ def meth; 1; end }.new
++ should_find_method('meth')
++ end
++
++ it "should find methods defined in modules included into the object's class" do
++ @obj = Class.new{ include Module.new{ def meth; 1; end } }.new
++ should_find_method('meth')
++ end
++
++ it "should find methods defined in the object's singleton class" do
++ @obj = Object.new
++ class << @obj; def meth; 1; end; end
++ should_find_method('meth')
++ end
++
++ it "should find methods in modules included into the object's singleton class" do
++ @obj = Object.new
++ @obj.extend Module.new{ def meth; 1; end }
++ should_find_method('meth')
++ end
++
++ it "should find methods all the way up to Kernel" do
++ @obj = Object.new
++ should_find_method('exit!')
++ end
++
++ it "should not find methods defined on the classes singleton class" do
++ @obj = Class.new{ class << self; def meth; 1; end; end }.new
++ Pry::Method.all_from_obj(@obj).map(&:name).should.not.include('meth')
++ end
++
++ it "should work in the face of an overridden send" do
++ @obj = Class.new{ def meth; 1; end; def send; raise EOFError; end }.new
++ should_find_method('meth')
++ end
++ end
++
++ describe 'on classes' do
++ def should_find_method(name)
++ Pry::Method.all_from_obj(@class).map(&:name).should.include(name)
++ end
++
++ it "should find methods defined in the class' singleton class" do
++ @class = Class.new{ class << self; def meth; 1; end; end }
++ should_find_method('meth')
++ end
++
++ it "should find methods defined on modules extended into the class" do
++ @class = Class.new{ extend Module.new{ def meth; 1; end; } }
++ should_find_method('meth')
++ end
++
++ it "should find methods defined on the singleton class of super-classes" do
++ @class = Class.new(Class.new{ class << self; def meth; 1; end; end })
++ should_find_method('meth')
++ end
++
++ it "should not find methods defined within the class" do
++ @class = Class.new{ def meth; 1; end }
++ Pry::Method.all_from_obj(@obj).map(&:name).should.not.include('meth')
++ end
++
++ it "should find methods defined on Class" do
++ @class = Class.new
++ should_find_method('allocate')
++ end
++
++ it "should find methods defined on Kernel" do
++ @class = Class.new
++ should_find_method('exit!')
++ end
++
++ it "should attribute overridden methods to the sub-class' singleton class" do
++ @class = Class.new(Class.new{ class << self; def meth; 1; end; end }) { class << self; def meth; 1; end; end }
++ Pry::Method.all_from_obj(@class).detect{ |x| x.name == 'meth' }.owner.should == (class << @class; self; end)
++ end
++
++ it "should attrbute overridden methods to the class not the module" do
++ @class = Class.new { class << self; def meth; 1; end; end; extend Module.new{ def meth; 1; end; } }
++ Pry::Method.all_from_obj(@class).detect{ |x| x.name == 'meth' }.owner.should == (class << @class; self; end)
++ end
++
++ it "should attribute overridden methods to the relevant singleton class in preference to Class" do
++ @class = Class.new { class << self; def allocate; 1; end; end }
++ Pry::Method.all_from_obj(@class).detect{ |x| x.name == 'allocate' }.owner.should == (class << @class; self; end)
++ end
++ end
++
++ describe 'method resolution order' do
++ module LS
++ class Top; end
++
++ class Next < Top; end
++
++ module M; end
++ module N; include M; end
++ module O; include M; end
++ module P; end
++
++ class Low < Next; include N; include P; end
++ class Lower < Low; extend N; end
++ class Bottom < Lower; extend O; end
++ end
++
++ def singleton_class(obj); class << obj; self; end; end
++
++ it "should look at a class and then its superclass" do
++ Pry::Method.instance_resolution_order(LS::Next).should == [LS::Next] + Pry::Method.instance_resolution_order(LS::Top)
++ end
++
++ it "should include the included modules between a class and its superclass" do
++ Pry::Method.instance_resolution_order(LS::Low).should == [LS::Low, LS::P, LS::N, LS::M] + Pry::Method.instance_resolution_order(LS::Next)
++ end
++
++ it "should not include modules extended into the class" do
++ Pry::Method.instance_resolution_order(LS::Bottom).should == [LS::Bottom] + Pry::Method.instance_resolution_order(LS::Lower)
++ end
++
++ it "should include included modules for Modules" do
++ Pry::Method.instance_resolution_order(LS::O).should == [LS::O, LS::M]
++ end
++
++ it "should include the singleton class of objects" do
++ obj = LS::Low.new
++ Pry::Method.resolution_order(obj).should == [singleton_class(obj)] + Pry::Method.instance_resolution_order(LS::Low)
++ end
++
++ it "should not include singleton classes of numbers" do
++ Pry::Method.resolution_order(4).should == Pry::Method.instance_resolution_order(Fixnum)
++ end
++
++ it "should include singleton classes for classes" do
++ Pry::Method.resolution_order(LS::Low).should == [singleton_class(LS::Low)] + Pry::Method.resolution_order(LS::Next)
++ end
++
++ it "should include modules included into singleton classes" do
++ Pry::Method.resolution_order(LS::Lower).should == [singleton_class(LS::Lower), LS::N, LS::M] + Pry::Method.resolution_order(LS::Low)
++ end
++
++ it "should include modules at most once" do
++ Pry::Method.resolution_order(LS::Bottom).count(LS::M).should == 1
++ end
++
++ it "should include modules at the point which they would be reached" do
++ Pry::Method.resolution_order(LS::Bottom).should == [singleton_class(LS::Bottom), LS::O] + (Pry::Method.resolution_order(LS::Lower))
++ end
++
++ it "should include the Pry::Method.instance_resolution_order of Class after the singleton classes" do
++ Pry::Method.resolution_order(LS::Top).should ==
++ [singleton_class(LS::Top), singleton_class(Object), singleton_class(BasicObject),
++ *Pry::Method.instance_resolution_order(Class)]
++ end
++ end
++ end
++
++ describe 'method_name_from_first_line' do
++ it 'should work in all simple cases' do
++ meth = Pry::Method.new(nil)
++ meth.send(:method_name_from_first_line, "def x").should == "x"
++ meth.send(:method_name_from_first_line, "def self.x").should == "x"
++ meth.send(:method_name_from_first_line, "def ClassName.x").should == "x"
++ meth.send(:method_name_from_first_line, "def obj_name.x").should == "x"
++ end
++ end
++
++ describe 'method aliases' do
++ before do
++ @class = Class.new {
++ def eat
++ end
++
++ alias fress eat
++ alias_method :omnomnom, :fress
++
++ def eruct
++ end
++ }
++ end
++
++ it 'should be able to find method aliases' do
++ meth = Pry::Method(@class.new.method(:eat))
++ aliases = Set.new(meth.aliases)
++
++ aliases.should == Set.new(["fress", "omnomnom"])
++ end
++
++ it 'should return an empty Array if cannot find aliases' do
++ meth = Pry::Method(@class.new.method(:eruct))
++ meth.aliases.should.be.empty
++ end
++
++ it 'should not include the own name in the list of aliases' do
++ meth = Pry::Method(@class.new.method(:eat))
++ meth.aliases.should.not.include "eat"
++ end
++
++ it 'should find aliases for top-level methods' do
++ # top-level methods get added as private instance methods on Object
++ class Object
++ private
++ def my_top_level_method ; end
++ alias my_other_top_level_method my_top_level_method
++ end
++
++ meth = Pry::Method.new(method(:my_top_level_method))
++ meth.aliases.should.include 'my_other_top_level_method'
++
++ class Object
++ remove_method :my_top_level_method
++ end
++ end
++
++ it 'should be able to find aliases for methods implemented in C' do
++ meth = Pry::Method(Hash.new.method(:key?))
++ aliases = Set.new(meth.aliases)
++
++ aliases.should == Set.new(["include?", "member?", "has_key?"])
++ end
++ end
++end
+diff --git a/spec/pager_spec.rb b/spec/pager_spec.rb
+new file mode 100644
+index 0000000..5e64b2c
+--- /dev/null
++++ b/spec/pager_spec.rb
+@@ -0,0 +1,66 @@
++require_relative "helper"
++describe "Pry::Pager" do
++ describe "PageTracker" do
++ before do
++ @pt = Pry::Pager::PageTracker.new(10, 10)
++ end
++
++ def record_short_line
++ @pt.record "012345678\n"
++ end
++
++ def record_long_line
++ @pt.record "0123456789012\n"
++ end
++
++ def record_multiline
++ @pt.record "0123456789012\n01\n"
++ end
++
++ def record_string_without_newline
++ @pt.record "0123456789"
++ end
++
++ def record_string_with_color_codes
++ @pt.record(CodeRay.scan("0123456789", :ruby).term + "\n")
++ end
++
++ it "records short lines that don't add up to a page" do
++ 9.times { record_short_line }
++ @pt.page?.should.be.false
++ end
++
++ it "records short lines that do add up to a page" do
++ 10.times { record_short_line }
++ @pt.page?.should.be.true
++ end
++
++ it "treats a long line as taking up more than one row" do
++ 4.times { record_long_line }
++ @pt.page?.should.be.false
++ record_long_line
++ @pt.page?.should.be.true
++ end
++
++ it "records a string with an embedded newline" do
++ 3.times { record_multiline }
++ @pt.page?.should.be.false
++ record_short_line
++ @pt.page?.should.be.true
++ end
++
++ it "doesn't count a line until it ends" do
++ 12.times { record_string_without_newline }
++ @pt.page?.should.be.false
++ record_short_line
++ @pt.page?.should.be.true
++ end
++
++ it "doesn't count ansi color codes towards length" do
++ 9.times { record_string_with_color_codes }
++ @pt.page?.should.be.false
++ record_string_with_color_codes
++ @pt.page?.should.be.true
++ end
++ end
++end
+diff --git a/spec/prompt_spec.rb b/spec/prompt_spec.rb
+new file mode 100644
+index 0000000..ddda435
+--- /dev/null
++++ b/spec/prompt_spec.rb
+@@ -0,0 +1,61 @@
++require_relative 'helper'
++
++describe "Prompts" do
++ describe "one-parameter prompt proc" do
++ it 'should get full config object' do
++ config = nil
++ redirect_pry_io(InputTester.new("exit-all")) do
++ Pry.start(self, :prompt => proc { |v| config = v })
++ end
++ config.is_a?(Pry::Config).should == true
++ end
++
++ it 'should get full config object, when using a proc array' do
++ config1 = nil
++ redirect_pry_io(InputTester.new("exit-all")) do
++ Pry.start(self, :prompt => [proc { |v| config1 = v }, proc { |v| config2 = v }])
++ end
++ config1.is_a?(Pry::Config).should == true
++ end
++
++ it 'should receive correct data in the config object' do
++ config = nil
++ redirect_pry_io(InputTester.new("def hello", "exit-all")) do
++ Pry.start(self, :prompt => proc { |v| config = v })
++ end
++
++ config.eval_string.should =~ /def hello/
++ config.nesting_level.should == 0
++ config.expr_number.should == 1
++ config.cont.should == true
++ config._pry_.is_a?(Pry).should == true
++ config.object.should == self
++ end
++ end
++
++ describe "BACKWARDS COMPATIBILITY: 3 parameter prompt proc" do
++ it 'should get 3 parameters' do
++ o = n = p = nil
++ redirect_pry_io(InputTester.new("exit-all")) do
++ Pry.start(:test, :prompt => proc { |obj, nesting, _pry_|
++ o, n, p = obj, nesting, _pry_ })
++ end
++ o.should == :test
++ n.should == 0
++ p.is_a?(Pry).should == true
++ end
++
++ it 'should get 3 parameters, when using proc array' do
++ o1 = n1 = p1 = nil
++ redirect_pry_io(InputTester.new("exit-all")) do
++ Pry.start(:test, :prompt => [proc { |obj, nesting, _pry_|
++ o1, n1, p1 = obj, nesting, _pry_ },
++ proc { |obj, nesting, _pry_|
++ o2, n2, p2 = obj, nesting, _pry_ }])
++ end
++ o1.should == :test
++ n1.should == 0
++ p1.is_a?(Pry).should == true
++ end
++ end
++end
+diff --git a/spec/pry_defaults_spec.rb b/spec/pry_defaults_spec.rb
+new file mode 100644
+index 0000000..404094d
+--- /dev/null
++++ b/spec/pry_defaults_spec.rb
+@@ -0,0 +1,428 @@
++require_relative 'helper'
++
++version = 1
++
++describe "test Pry defaults" do
++ before do
++ @str_output = StringIO.new
++ end
++
++ after do
++ Pry.reset_defaults
++ Pry.config.color = false
++ end
++
++ describe "input" do
++ after do
++ Pry.reset_defaults
++ Pry.config.color = false
++ end
++
++ it 'should set the input default, and the default should be overridable' do
++ Pry.config.input = InputTester.new("5")
++ Pry.config.output = @str_output
++ Object.new.pry
++ @str_output.string.should =~ /5/
++
++ Pry.config.output = @str_output
++ Object.new.pry :input => InputTester.new("6")
++ @str_output.string.should =~ /6/
++ end
++
++ it 'should pass in the prompt if readline arity is 1' do
++ Pry.prompt = proc { "A" }
++
++ arity_one_input = Class.new do
++ attr_accessor :prompt
++ def readline(prompt)
++ @prompt = prompt
++ "exit-all"
++ end
++ end.new
++
++ Pry.start(self, :input => arity_one_input, :output => StringIO.new)
++ arity_one_input.prompt.should == Pry.prompt.call
++ end
++
++ it 'should not pass in the prompt if the arity is 0' do
++ Pry.prompt = proc { "A" }
++
++ arity_zero_input = Class.new do
++ def readline
++ "exit-all"
++ end
++ end.new
++
++ lambda { Pry.start(self, :input => arity_zero_input, :output => StringIO.new) }.should.not.raise Exception
++ end
++
++ it 'should not pass in the prompt if the arity is -1' do
++ Pry.prompt = proc { "A" }
++
++ arity_multi_input = Class.new do
++ attr_accessor :prompt
++
++ def readline(*args)
++ @prompt = args.first
++ "exit-all"
++ end
++ end.new
++
++ Pry.start(self, :input => arity_multi_input, :output => StringIO.new)
++ arity_multi_input.prompt.should == nil
++ end
++
++ end
++
++ it 'should set the output default, and the default should be overridable' do
++ Pry.config.output = @str_output
++
++ Pry.config.input = InputTester.new("5")
++ Object.new.pry
++ @str_output.string.should =~ /5/
++
++ Pry.config.input = InputTester.new("6")
++ Object.new.pry
++ @str_output.string.should =~ /5\n.*6/
++
++ Pry.config.input = InputTester.new("7")
++ @str_output = StringIO.new
++ Object.new.pry :output => @str_output
++ @str_output.string.should.not =~ /5\n.*6/
++ @str_output.string.should =~ /7/
++ end
++
++ it "should set the print default, and the default should be overridable" do
++ new_print = proc { |out, value| out.puts "=> LOL" }
++ Pry.config.print = new_print
++
++ Pry.new.print.should == Pry.config.print
++ Object.new.pry :input => InputTester.new("\"test\""), :output => @str_output
++ @str_output.string.should == "=> LOL\n"
++
++ @str_output = StringIO.new
++ Object.new.pry :input => InputTester.new("\"test\""), :output => @str_output,
++ :print => proc { |out, value| out.puts value.reverse }
++ @str_output.string.should == "tset\n"
++
++ Pry.new.print.should == Pry.config.print
++ @str_output = StringIO.new
++ Object.new.pry :input => InputTester.new("\"test\""), :output => @str_output
++ @str_output.string.should == "=> LOL\n"
++ end
++
++ describe "pry return values" do
++ it 'should return nil' do
++ Pry.start(self, :input => StringIO.new("exit-all"), :output => StringIO.new).should == nil
++ end
++
++ it 'should return the parameter given to exit-all' do
++ Pry.start(self, :input => StringIO.new("exit-all 10"), :output => StringIO.new).should == 10
++ end
++
++ it 'should return the parameter (multi word string) given to exit-all' do
++ Pry.start(self, :input => StringIO.new("exit-all \"john mair\""), :output => StringIO.new).should == "john mair"
++ end
++
++ it 'should return the parameter (function call) given to exit-all' do
++ Pry.start(self, :input => StringIO.new("exit-all 'abc'.reverse"), :output => StringIO.new).should == 'cba'
++ end
++
++ it 'should return the parameter (self) given to exit-all' do
++ Pry.start("carl", :input => StringIO.new("exit-all self"), :output => StringIO.new).should == "carl"
++ end
++ end
++
++ describe "prompts" do
++ before do
++ Pry.config.output = StringIO.new
++ end
++
++ def get_prompts(pry)
++ a = pry.select_prompt
++ pry.eval "["
++ b = pry.select_prompt
++ pry.eval "]"
++ [a, b]
++ end
++
++ it 'should set the prompt default, and the default should be overridable (single prompt)' do
++ Pry.prompt = proc { "test prompt> " }
++ new_prompt = proc { "A" }
++
++ pry = Pry.new
++ pry.prompt.should == Pry.prompt
++ get_prompts(pry).should == ["test prompt> ", "test prompt> "]
++
++
++ pry = Pry.new(:prompt => new_prompt)
++ pry.prompt.should == new_prompt
++ get_prompts(pry).should == ["A", "A"]
++
++ pry = Pry.new
++ pry.prompt.should == Pry.prompt
++ get_prompts(pry).should == ["test prompt> ", "test prompt> "]
++ end
++
++ it 'should set the prompt default, and the default should be overridable (multi prompt)' do
++ Pry.prompt = [proc { "test prompt> " }, proc { "test prompt* " }]
++ new_prompt = [proc { "A" }, proc { "B" }]
++
++ pry = Pry.new
++ pry.prompt.should == Pry.prompt
++ get_prompts(pry).should == ["test prompt> ", "test prompt* "]
++
++
++ pry = Pry.new(:prompt => new_prompt)
++ pry.prompt.should == new_prompt
++ get_prompts(pry).should == ["A", "B"]
++
++ pry = Pry.new
++ pry.prompt.should == Pry.prompt
++ get_prompts(pry).should == ["test prompt> ", "test prompt* "]
++ end
++
++ describe 'storing and restoring the prompt' do
++ before do
++ make = lambda do |name,i|
++ prompt = [ proc { "#{i}>" } , proc { "#{i+1}>" } ]
++ (class << prompt; self; end).send(:define_method, :inspect) { "<Prompt-#{name}>" }
++ prompt
++ end
++ @a , @b , @c = make[:a,0] , make[:b,1] , make[:c,2]
++ @pry = Pry.new :prompt => @a
++ end
++ it 'should have a prompt stack' do
++ @pry.push_prompt @b
++ @pry.push_prompt @c
++ @pry.prompt.should == @c
++ @pry.pop_prompt
++ @pry.prompt.should == @b
++ @pry.pop_prompt
++ @pry.prompt.should == @a
++ end
++
++ it 'should restore overridden prompts when returning from file-mode' do
++ pry = Pry.new(:prompt => [ proc { 'P>' } ] * 2)
++ pry.select_prompt.should == "P>"
++ pry.process_command('shell-mode')
++ pry.select_prompt.should =~ /\Apry .* \$ \z/
++ pry.process_command('shell-mode')
++ pry.select_prompt.should == "P>"
++ end
++
++ it '#pop_prompt should return the popped prompt' do
++ @pry.push_prompt @b
++ @pry.push_prompt @c
++ @pry.pop_prompt.should == @c
++ @pry.pop_prompt.should == @b
++ end
++
++ it 'should not pop the last prompt' do
++ @pry.push_prompt @b
++ @pry.pop_prompt.should == @b
++ @pry.pop_prompt.should == @a
++ @pry.pop_prompt.should == @a
++ @pry.prompt.should == @a
++ end
++
++ describe '#prompt= should replace the current prompt with the new prompt' do
++ it 'when only one prompt on the stack' do
++ @pry.prompt = @b
++ @pry.prompt.should == @b
++ @pry.pop_prompt.should == @b
++ @pry.pop_prompt.should == @b
++ end
++ it 'when several prompts on the stack' do
++ @pry.push_prompt @b
++ @pry.prompt = @c
++ @pry.pop_prompt.should == @c
++ @pry.pop_prompt.should == @a
++ end
++ end
++ end
++ end
++
++ describe "view_clip used for displaying an object in a truncated format" do
++ DEFAULT_OPTIONS = {
++ max_length: 60
++ }
++ MAX_LENGTH = DEFAULT_OPTIONS[:max_length]
++
++ describe "given an object with an #inspect string" do
++ it "returns the #<> format of the object (never use inspect)" do
++ o = Object.new
++ def o.inspect; "a" * MAX_LENGTH; end
++
++ Pry.view_clip(o, DEFAULT_OPTIONS).should =~ /#<Object/
++ end
++ end
++
++ describe "given the 'main' object" do
++ it "returns the #to_s of main (special case)" do
++ o = TOPLEVEL_BINDING.eval('self')
++ Pry.view_clip(o, DEFAULT_OPTIONS).should == o.to_s
++ end
++ end
++
++ describe "the list of prompt safe objects" do
++ [1, 2.0, -5, "hello", :test].each do |o|
++ it "returns the #inspect of the special-cased immediate object: #{o}" do
++ Pry.view_clip(o, DEFAULT_OPTIONS).should == o.inspect
++ end
++ end
++
++ it "returns #<> format of the special-cased immediate object if #inspect is longer than maximum" do
++ o = "o" * (MAX_LENGTH + 1)
++ Pry.view_clip(o, DEFAULT_OPTIONS).should =~ /#<String/
++ end
++
++ it "returns the #inspect of the custom prompt safe objects" do
++ Barbie = Class.new { def inspect; "life is plastic, it's fantastic" end }
++ Pry.config.prompt_safe_objects << Barbie
++ output = Pry.view_clip(Barbie.new, DEFAULT_OPTIONS)
++ output.should == "life is plastic, it's fantastic"
++ end
++ end
++
++ describe "given an object with an #inspect string as long as the maximum specified" do
++ it "returns the #<> format of the object (never use inspect)" do
++ o = Object.new
++ def o.inspect; "a" * DEFAULT_OPTIONS; end
++
++ Pry.view_clip(o, DEFAULT_OPTIONS).should =~ /#<Object/
++ end
++ end
++
++ describe "given a regular object with an #inspect string longer than the maximum specified" do
++
++ describe "when the object is a regular one" do
++ it "returns a string of the #<class name:object idish> format" do
++ o = Object.new
++ def o.inspect; "a" * (DEFAULT_OPTIONS + 1); end
++
++ Pry.view_clip(o, DEFAULT_OPTIONS).should =~ /#<Object/
++ end
++ end
++
++ describe "when the object is a Class or a Module" do
++ describe "without a name (usually a c = Class.new)" do
++ it "returns a string of the #<class name:object idish> format" do
++ c, m = Class.new, Module.new
++
++ Pry.view_clip(c, DEFAULT_OPTIONS).should =~ /#<Class/
++ Pry.view_clip(m, DEFAULT_OPTIONS).should =~ /#<Module/
++ end
++ end
++
++ describe "with a #name longer than the maximum specified" do
++ it "returns a string of the #<class name:object idish> format" do
++ c, m = Class.new, Module.new
++
++
++ def c.name; "a" * (MAX_LENGTH + 1); end
++ def m.name; "a" * (MAX_LENGTH + 1); end
++
++ Pry.view_clip(c, DEFAULT_OPTIONS).should =~ /#<Class/
++ Pry.view_clip(m, DEFAULT_OPTIONS).should =~ /#<Module/
++ end
++ end
++
++ describe "with a #name shorter than or equal to the maximum specified" do
++ it "returns a string of the #<class name:object idish> format" do
++ c, m = Class.new, Module.new
++
++ def c.name; "a" * MAX_LENGTH; end
++ def m.name; "a" * MAX_LENGTH; end
++
++ Pry.view_clip(c, DEFAULT_OPTIONS).should == c.name
++ Pry.view_clip(m, DEFAULT_OPTIONS).should == m.name
++ end
++ end
++
++ end
++
++ end
++
++ end
++
++ describe 'quiet' do
++ it 'should show whereami by default' do
++ Pry.start(binding, :input => InputTester.new("1", "exit-all"),
++ :output => @str_output,
++ :hooks => Pry::DEFAULT_HOOKS)
++
++ @str_output.string.should =~ /[w]hereami by default/
++ end
++
++ it 'should hide whereami if quiet is set' do
++ Pry.new(:input => InputTester.new("exit-all"),
++ :output => @str_output,
++ :quiet => true,
++ :hooks => Pry::DEFAULT_HOOKS)
++
++ @str_output.string.should == ""
++ end
++ end
++
++ describe 'toplevel_binding' do
++ it 'should be devoid of local variables' do
++ pry_eval(Pry.toplevel_binding, "ls -l").should.not =~ /version/
++ end
++
++ it 'should have self the same as TOPLEVEL_BINDING' do
++ Pry.toplevel_binding.eval('self').should.equal? TOPLEVEL_BINDING.eval('self')
++ end
++
++ # https://github.com/rubinius/rubinius/issues/1779
++ unless Pry::Helpers::BaseHelpers.rbx?
++ it 'should define private methods on Object' do
++ TOPLEVEL_BINDING.eval 'def gooey_fooey; end'
++ method(:gooey_fooey).owner.should == Object
++ Pry::Method(method(:gooey_fooey)).visibility.should == :private
++ end
++ end
++ end
++
++ it 'should set the hooks default, and the default should be overridable' do
++ Pry.config.input = InputTester.new("exit-all")
++ Pry.config.hooks = Pry::Hooks.new.
++ add_hook(:before_session, :my_name) { |out,_,_| out.puts "HELLO" }.
++ add_hook(:after_session, :my_name) { |out,_,_| out.puts "BYE" }
++
++ Object.new.pry :output => @str_output
++ @str_output.string.should =~ /HELLO/
++ @str_output.string.should =~ /BYE/
++
++ Pry.config.input.rewind
++
++ @str_output = StringIO.new
++ Object.new.pry :output => @str_output,
++ :hooks => Pry::Hooks.new.
++ add_hook( :before_session, :my_name) { |out,_,_| out.puts "MORNING" }.
++ add_hook(:after_session, :my_name) { |out,_,_| out.puts "EVENING" }
++
++ @str_output.string.should =~ /MORNING/
++ @str_output.string.should =~ /EVENING/
++
++ # try below with just defining one hook
++ Pry.config.input.rewind
++ @str_output = StringIO.new
++ Object.new.pry :output => @str_output,
++ :hooks => Pry::Hooks.new.
++ add_hook(:before_session, :my_name) { |out,_,_| out.puts "OPEN" }
++
++ @str_output.string.should =~ /OPEN/
++
++ Pry.config.input.rewind
++ @str_output = StringIO.new
++ Object.new.pry :output => @str_output,
++ :hooks => Pry::Hooks.new.
++ add_hook(:after_session, :my_name) { |out,_,_| out.puts "CLOSE" }
++
++ @str_output.string.should =~ /CLOSE/
++
++ Pry.reset_defaults
++ Pry.config.color = false
++ end
++end
+diff --git a/spec/pry_output_spec.rb b/spec/pry_output_spec.rb
+new file mode 100644
+index 0000000..dc59400
+--- /dev/null
++++ b/spec/pry_output_spec.rb
+@@ -0,0 +1,117 @@
++require_relative 'helper'
++
++describe Pry do
++ describe "output failsafe" do
++ after do
++ Pry.config.print = Pry::DEFAULT_PRINT
++ end
++
++ it "should catch serialization exceptions" do
++ Pry.config.print = lambda { |*a| raise "catch-22" }
++
++ lambda {
++ mock_pry("1")
++ }.should.not.raise
++ end
++
++ it "should display serialization exceptions" do
++ Pry.config.print = lambda { |*a| raise "catch-22" }
++
++ mock_pry("1").should =~ /\(pry\) output error: #<RuntimeError: catch-22>/
++ end
++
++ it "should catch errors serializing exceptions" do
++ Pry.config.print = lambda do |*a|
++ raise Exception.new("catch-22").tap{ |e| class << e; def inspect; raise e; end; end }
++ end
++
++ mock_pry("1").should =~ /\(pry\) output error: failed to show result/
++ end
++ end
++
++ describe "DEFAULT_PRINT" do
++ it "should output the right thing" do
++ mock_pry("[1]").should =~ /^=> \[1\]/
++ end
++
++ it "should include the =>" do
++ pry = Pry.new
++ accumulator = StringIO.new
++ pry.config.output = accumulator
++ pry.config.print.call(accumulator, [1], pry)
++ accumulator.string.should == "=> \[1\]\n"
++ end
++
++ it "should not be phased by un-inspectable things" do
++ mock_pry("class NastyClass; undef pretty_inspect; end", "NastyClass.new").should =~ /#<.*NastyClass:0x.*?>/
++ end
++
++ it "doesn't leak colour for object literals" do
++ mock_pry("Object.new").should =~ /=> #<Object:0x[a-z0-9]+>\n/
++ end
++ end
++
++ describe "output_prefix" do
++ it "should be able to change output_prefix" do
++ pry = Pry.new
++ accumulator = StringIO.new
++ pry.config.output = accumulator
++ pry.config.output_prefix = "-> "
++ pry.config.print.call(accumulator, [1], pry)
++ accumulator.string.should == "-> \[1\]\n"
++ end
++ end
++
++ describe "color" do
++ before do
++ Pry.config.color = true
++ end
++
++ after do
++ Pry.config.color = false
++ end
++
++ it "should colorize strings as though they were ruby" do
++ pry = Pry.new
++ accumulator = StringIO.new
++ colorized = CodeRay.scan("[1]", :ruby).term
++ pry.config.output = accumulator
++ pry.config.print.call(accumulator, [1], pry)
++ accumulator.string.should == "=> #{colorized}\n"
++ end
++
++ it "should not colorize strings that already include color" do
++ pry = Pry.new
++ f = Object.new
++ def f.inspect
++ "\e[1;31mFoo\e[0m"
++ end
++ accumulator = StringIO.new
++ pry.config.output = accumulator
++ pry.config.print.call(accumulator, f, pry)
++ # We add an extra \e[0m to prevent color leak
++ accumulator.string.should == "=> \e[1;31mFoo\e[0m\e[0m\n"
++ end
++ end
++
++ describe "output suppression" do
++ before do
++ @t = pry_tester
++ end
++ it "should normally output the result" do
++ mock_pry("1 + 2").should == "=> 3\n"
++ end
++
++ it "should not output anything if the input ends with a semicolon" do
++ mock_pry("1 + 2;").should == ""
++ end
++
++ it "should output something if the input ends with a comment" do
++ mock_pry("1 + 2 # basic addition").should == "=> 3\n"
++ end
++
++ it "should not output something if the input is only a comment" do
++ mock_pry("# basic addition").should == ""
++ end
++ end
++end
+diff --git a/spec/pry_repl_spec.rb b/spec/pry_repl_spec.rb
+new file mode 100644
+index 0000000..43c77ec
+--- /dev/null
++++ b/spec/pry_repl_spec.rb
+@@ -0,0 +1,102 @@
++require_relative 'helper'
++
++describe "The whole thing" do
++ it "should let you run commands in the middle of multiline expressions" do
++ ReplTester.start do
++ input 'def a'
++ input '!'
++ output /^Input buffer cleared/
++
++ input '5'
++ output '=> 5'
++ end
++ end
++
++ it "should rescue exceptions" do
++ ReplTester.start do
++ input 'raise "lorum"'
++ output /^RuntimeError: lorum/
++
++ if defined?(java)
++ input 'raise java.lang.Exception.new("foo")'
++ output /Exception: foo/
++
++ input 'raise java.io.IOException.new("bar")'
++ output /IOException: bar/
++ end
++ end
++ end
++
++ describe "eval_string and binding_stack" do
++ it "shouldn't break if we start a nested REPL" do
++ ReplTester.start do
++ input 'Pry::REPL.new(_pry_, :target => 10).start'
++ output ''
++ prompt /10.*> $/
++
++ input 'self'
++ output '=> 10'
++
++ input nil # Ctrl-D
++ output ''
++
++ input 'self'
++ output '=> main'
++ end
++ end
++
++ it "shouldn't break if we start a nested instance" do
++ ReplTester.start do
++ input 'Pry.start(10, _pry_.config)'
++ output ''
++ prompt /10.*> $/
++
++ input 'self'
++ output '=> 10'
++
++ input nil # Ctrl-D
++ output '=> nil' # return value of Pry session
++
++ input 'self'
++ output '=> main'
++ end
++ end
++
++ it "shouldn't break if we pop bindings in Ruby" do
++ ReplTester.start do
++ input 'cd 10'
++ output ''
++ prompt /10.*> $/
++
++ input '_pry_.binding_stack.pop'
++ output /^=> #<Binding/
++ prompt /main.*> $/
++
++ input '_pry_.binding_stack.pop'
++ output /^=> #<Binding/
++ assert_exited
++ end
++ end
++
++ it "should immediately evaluate eval_string after cmd if complete" do
++ set = Pry::CommandSet.new do
++ import Pry::Commands
++
++ command 'hello!' do
++ eval_string.replace('"hello"')
++ end
++ end
++
++ ReplTester.start(:commands => set) do
++ input 'def x'
++ output ''
++ prompt /\* $/
++
++ input 'hello!'
++ output '=> "hello"'
++ prompt /> $/
++ end
++ end
++ end
++
++end
+diff --git a/spec/pry_spec.rb b/spec/pry_spec.rb
+new file mode 100644
+index 0000000..ca5a3f9
+--- /dev/null
++++ b/spec/pry_spec.rb
+@@ -0,0 +1,414 @@
++require_relative 'helper'
++
++describe Pry do
++ before do
++ @str_output = StringIO.new
++ end
++
++ describe "Exotic object support" do
++ # regression test for exotic object support
++ it "Should not error when return value is a BasicObject instance" do
++ ReplTester.start do
++ input('BasicObject.new').should =~ /^=> #<BasicObject:/
++ end
++ end
++ end
++
++ describe 'DISABLE_PRY' do
++ before do
++ ENV['DISABLE_PRY'] = 'true'
++ end
++
++ after do
++ ENV.delete 'DISABLE_PRY'
++ end
++
++ it 'should not binding.pry' do
++ binding.pry.should == nil
++ end
++
++ it 'should not Pry.start' do
++ Pry.start.should == nil
++ end
++ end
++
++ describe "Pry.critical_section" do
++ it "should prevent Pry being called" do
++ output = StringIO.new
++ Pry.config.output = output
++ Pry.critical_section do
++ Pry.start
++ end
++ output.string.should =~ /Pry started inside Pry/
++ end
++ end
++
++ describe "Pry.binding_for" do
++
++ # regression test for burg's bug (see git history)
++ it "Should not error when object doesn't have a valid == method" do
++ o = Object.new
++ def o.==(other)
++ raise
++ end
++
++ lambda { Pry.binding_for(o) }.should.not.raise Exception
++ end
++
++ it "should not leak local variables" do
++ [Object.new, Array, 3].each do |obj|
++ Pry.binding_for(obj).eval("local_variables").should.be.empty
++ end
++ end
++
++ it "should work on frozen objects" do
++ a = "hello".freeze
++ Pry.binding_for(a).eval("self").should.equal? a
++ end
++ end
++
++ describe "#last_exception=" do
++ before do
++ @pry = Pry.new binding: binding
++ @e = mock_exception "foo.rb:1"
++ end
++
++ it "returns an instance of Pry::LastException" do
++ @pry.last_exception = @e
++ @pry.last_exception.wrapped_exception.should == @e
++ end
++
++ it "returns a frozen exception" do
++ @pry.last_exception = @e.freeze
++ @pry.last_exception.should.be.frozen?
++ end
++
++ it "returns an object who mirrors itself as the wrapped exception" do
++ @pry.last_exception = @e.freeze
++ @pry.last_exception.should.be.instance_of?(StandardError)
++ end
++ end
++
++ describe "open a Pry session on an object" do
++ describe "rep" do
++ before do
++ class Hello
++ end
++ end
++
++ after do
++ Object.send(:remove_const, :Hello)
++ end
++
++ # bug fix for https://github.com/banister/pry/issues/93
++ it 'should not leak pry constants into Object namespace' do
++ lambda{
++ pry_eval(Object.new, "Command")
++ }.should.raise(NameError)
++ end
++
++ it 'should be able to operate inside the BasicObject class' do
++ pry_eval(BasicObject, ":foo", "Pad.obj = _")
++ Pad.obj.should == :foo
++ end
++
++ it 'should set an ivar on an object' do
++ o = Object.new
++ pry_eval(o, "@x = 10")
++ o.instance_variable_get(:@x).should == 10
++ end
++
++ it 'should display error if Pry instance runs out of input' do
++ redirect_pry_io(StringIO.new, @str_output) do
++ Pry.start
++ end
++ @str_output.string.should =~ /Error: Pry ran out of things to read/
++ end
++
++ it 'should make self evaluate to the receiver of the rep session' do
++ o = :john
++ pry_eval(o, "self").should == o
++ end
++
++ it 'should define a nested class under Hello and not on top-level or Pry' do
++ mock_pry(Pry.binding_for(Hello), "class Nested", "end")
++ Hello.const_defined?(:Nested).should == true
++ end
++
++ it 'should suppress output if input ends in a ";" and is an Exception object (single line)' do
++ mock_pry("Exception.new;").should == ""
++ end
++
++ it 'should suppress output if input ends in a ";" (single line)' do
++ mock_pry("x = 5;").should == ""
++ end
++
++ it 'should be able to evaluate exceptions normally' do
++ was_called = false
++ mock_pry("RuntimeError.new", :exception_handler => proc{ was_called = true })
++ was_called.should == false
++ end
++
++ it 'should notice when exceptions are raised' do
++ was_called = false
++ mock_pry("raise RuntimeError", :exception_handler => proc{ was_called = true })
++ was_called.should == true
++ end
++
++ it 'should not try to catch intended exceptions' do
++ lambda { mock_pry("raise SystemExit") }.should.raise SystemExit
++ # SIGTERM
++ lambda { mock_pry("raise SignalException.new(15)") }.should.raise SignalException
++ end
++
++ describe "multi-line input" do
++ it "works" do
++ mock_pry('x = ', '1 + 4').should =~ /5/
++ end
++
++ it 'should suppress output if input ends in a ";" (multi-line)' do
++ mock_pry('def self.blah', ':test', 'end;').should == ''
++ end
++
++ describe "newline stripping from an empty string" do
++ it "with double quotes" do
++ mock_pry('"', '"').should =~ %r|"\\n"|
++ mock_pry('"', "\n", "\n", "\n", '"').should =~ %r|"\\n\\n\\n\\n"|
++ end
++
++ it "with single quotes" do
++ mock_pry("'", "'").should =~ %r|"\\n"|
++ mock_pry("'", "\n", "\n", "\n", "'").should =~ %r|"\\n\\n\\n\\n"|
++ end
++
++ it "with fancy delimiters" do
++ mock_pry('%(', ')').should =~ %r|"\\n"|
++ mock_pry('%|', "\n", "\n", '|').should =~ %r|"\\n\\n\\n"|
++ mock_pry('%q[', "\n", "\n", ']').should =~ %r|"\\n\\n\\n"|
++ end
++ end
++
++ describe "newline stripping from an empty regexp" do
++ it "with regular regexp delimiters" do
++ mock_pry('/', '/').should =~ %r{/\n/}
++ end
++
++ it "with fancy delimiters" do
++ mock_pry('%r{', "\n", "\n", '}').should =~ %r{/\n\n\n/}
++ mock_pry('%r<', "\n", '>').should =~ %r{/\n\n/}
++ end
++ end
++
++ describe "newline from an empty heredoc" do
++ it "works" do
++ mock_pry('<<HERE', 'HERE').should =~ %r|""|
++ mock_pry("<<'HERE'", "\n", 'HERE').should =~ %r|"\\n"|
++ mock_pry("<<-'HERE'", "\n", "\n", 'HERE').should =~ %r|"\\n\\n"|
++ end
++ end
++ end
++ end
++
++ describe "repl" do
++ describe "basic functionality" do
++ it 'should set an ivar on an object and exit the repl' do
++ input_strings = ["@x = 10", "exit-all"]
++ input = InputTester.new(*input_strings)
++
++ o = Object.new
++
++ pry_tester = Pry.start(o, :input => input, :output => StringIO.new)
++
++ o.instance_variable_get(:@x).should == 10
++ end
++ end
++
++ describe "complete_expression?" do
++ it "should not mutate the input!" do
++ clean = "puts <<-FOO\nhi\nFOO\n"
++ a = clean.dup
++ Pry::Code.complete_expression?(a)
++ a.should == clean
++ end
++ end
++
++ describe "history arrays" do
++ it 'sets _ to the last result' do
++ t = pry_tester
++ t.eval ":foo"
++ t.eval("_").should == :foo
++ t.eval "42"
++ t.eval("_").should == 42
++ end
++
++ it 'sets out to an array with the result' do
++ t = pry_tester
++ t.eval ":foo"
++ t.eval "42"
++ res = t.eval "_out_"
++
++ res.should.be.kind_of Pry::HistoryArray
++ res[1..2].should == [:foo, 42]
++ end
++
++ it 'sets _in_ to an array with the entered lines' do
++ t = pry_tester
++ t.eval ":foo"
++ t.eval "42"
++ res = t.eval "_in_"
++
++ res.should.be.kind_of Pry::HistoryArray
++ res[1..2].should == [":foo\n", "42\n"]
++ end
++
++ it 'uses 100 as the size of _in_ and _out_' do
++ pry_tester.eval("[_in_.max_size, _out_.max_size]").should == [100, 100]
++ end
++
++ it 'can change the size of the history arrays' do
++ pry_tester(:memory_size => 1000).eval("[_out_, _in_].map(&:max_size)").should == [1000, 1000]
++ end
++
++ it 'store exceptions' do
++ mock_pry("foo!", "Pad.in = _in_[-1]; Pad.out = _out_[-1]")
++
++ Pad.in.should == "foo!\n"
++ Pad.out.should.be.kind_of NoMethodError
++ end
++ end
++
++ describe "last_result" do
++ it "should be set to the most recent value" do
++ pry_eval("2", "_ + 82").should == 84
++ end
++
++ # This test needs mock_pry because the command retvals work by
++ # replacing the eval_string, so _ won't be modified without Pry doing
++ # a REPL loop.
++ it "should be set to the result of a command with :keep_retval" do
++ Pry::Commands.block_command '++', '', :keep_retval => true do |a|
++ a.to_i + 1
++ end
++
++ mock_pry('++ 86', '++ #{_}').should =~ /88/
++ end
++
++ it "should be preserved over an empty line" do
++ pry_eval("2 + 2", " ", "\t", " ", "_ + 92").should == 96
++ end
++
++ it "should be preserved when evalling a command without :keep_retval" do
++ pry_eval("2 + 2", "ls -l", "_ + 96").should == 100
++ end
++ end
++
++ describe "nesting" do
++ after do
++ Pry.reset_defaults
++ Pry.config.color = false
++ end
++
++ it 'should nest properly' do
++ Pry.config.input = InputTester.new("cd 1", "cd 2", "cd 3", "\"nest:\#\{(_pry_.binding_stack.size - 1)\}\"", "exit-all")
++
++ Pry.config.output = @str_output
++
++ o = Object.new
++
++ pry_tester = o.pry
++ @str_output.string.should =~ /nest:3/
++ end
++ end
++
++ describe "defining methods" do
++ it 'should define a method on the singleton class of an object when performing "def meth;end" inside the object' do
++ [Object.new, {}, []].each do |val|
++ pry_eval(val, 'def hello; end')
++ val.methods(false).map(&:to_sym).include?(:hello).should == true
++ end
++ end
++
++ it 'should define an instance method on the module when performing "def meth;end" inside the module' do
++ hello = Module.new
++ pry_eval(hello, "def hello; end")
++ hello.instance_methods(false).map(&:to_sym).include?(:hello).should == true
++ end
++
++ it 'should define an instance method on the class when performing "def meth;end" inside the class' do
++ hello = Class.new
++ pry_eval(hello, "def hello; end")
++ hello.instance_methods(false).map(&:to_sym).include?(:hello).should == true
++ end
++
++ it 'should define a method on the class of an object when performing "def meth;end" inside an immediate value or Numeric' do
++ [:test, 0, true, false, nil,
++ (0.0 unless Pry::Helpers::BaseHelpers.jruby?)].each do |val|
++ pry_eval(val, "def hello; end");
++ val.class.instance_methods(false).map(&:to_sym).include?(:hello).should == true
++ end
++ end
++ end
++
++ describe "Object#pry" do
++
++ after do
++ Pry.reset_defaults
++ Pry.config.color = false
++ end
++
++ it "should start a pry session on the receiver (first form)" do
++ Pry.config.input = InputTester.new("self", "exit-all")
++
++ str_output = StringIO.new
++ Pry.config.output = str_output
++
++ 20.pry
++
++ str_output.string.should =~ /20/
++ end
++
++ it "should start a pry session on the receiver (second form)" do
++ Pry.config.input = InputTester.new("self", "exit-all")
++
++ str_output = StringIO.new
++ Pry.config.output = str_output
++
++ pry 20
++
++ str_output.string.should =~ /20/
++ end
++
++ it "should raise if more than two arguments are passed to Object#pry" do
++ lambda { pry(20, :quiet, :input => Readline) }.should.raise ArgumentError
++ end
++ end
++
++ describe "Pry.binding_for" do
++ it 'should return TOPLEVEL_BINDING if parameter self is main' do
++ _main_ = lambda { TOPLEVEL_BINDING.eval('self') }
++ Pry.binding_for(_main_.call).is_a?(Binding).should == true
++ Pry.binding_for(_main_.call).should == TOPLEVEL_BINDING
++ Pry.binding_for(_main_.call).should == Pry.binding_for(_main_.call)
++ end
++ end
++ end
++ end
++
++ describe 'setting custom options' do
++ it 'should not raise for unrecognized options' do
++ should.not.raise?(NoMethodError) {
++ instance = Pry.new(:custom_option => 'custom value')
++ }
++ end
++ end
++
++ describe "a fresh instance" do
++ it "should use `caller` as its backtrace" do
++ location = "#{__FILE__}:#{__LINE__ + 1}"[1..-1] # omit leading .
++ backtrace = Pry.new.backtrace
++
++ backtrace.should.not.be.nil
++ backtrace.any? { |l| l.include?(location) }.should.be.true
++ end
++ end
++end
+diff --git a/spec/pryrc_spec.rb b/spec/pryrc_spec.rb
+new file mode 100644
+index 0000000..ade0473
+--- /dev/null
++++ b/spec/pryrc_spec.rb
+@@ -0,0 +1,97 @@
++require_relative 'helper'
++
++describe Pry do
++ describe 'loading rc files' do
++ before do
++ Pry::HOME_RC_FILE.replace "spec/fixtures/testrc"
++ Pry::LOCAL_RC_FILE.replace "spec/fixtures/testrc/../testrc"
++ Pry.instance_variable_set(:@initial_session, true)
++ Pry.config.should_load_rc = true
++ Pry.config.should_load_local_rc = true
++ end
++
++ after do
++ Pry::HOME_RC_FILE.replace "~/.pryrc"
++ Pry::LOCAL_RC_FILE.replace "./.pryrc"
++ Pry.config.should_load_rc = false
++ Object.remove_const(:TEST_RC) if defined?(TEST_RC)
++ end
++
++ it "should never run the rc file twice" do
++ Pry.start(self, :input => StringIO.new("exit-all\n"), :output => StringIO.new)
++ TEST_RC.should == [0]
++
++ Pry.start(self, :input => StringIO.new("exit-all\n"), :output => StringIO.new)
++ TEST_RC.should == [0]
++ end
++
++ # Resolving symlinks doesn't work on jruby 1.9 [jruby issue #538]
++ unless Pry::Helpers::BaseHelpers.jruby_19?
++ it "should not load the rc file twice if it's symlinked differently" do
++ Pry::HOME_RC_FILE.replace "spec/fixtures/testrc"
++ Pry::LOCAL_RC_FILE.replace "spec/fixtures/testlinkrc"
++
++ Pry.start(self, :input => StringIO.new("exit-all\n"), :output => StringIO.new)
++
++ TEST_RC.should == [0]
++ end
++ end
++
++ it "should not load the pryrc if it cannot expand ENV[HOME]" do
++ old_home = ENV['HOME']
++ ENV['HOME'] = nil
++ Pry.config.should_load_rc = true
++ lambda { Pry.start(self, :input => StringIO.new("exit-all\n"), :output => StringIO.new) }.should.not.raise
++
++ ENV['HOME'] = old_home
++ end
++
++ it "should not run the rc file at all if Pry.config.should_load_rc is false" do
++ Pry.config.should_load_rc = false
++ Pry.config.should_load_local_rc = false
++ Pry.start(self, :input => StringIO.new("exit-all\n"), :output => StringIO.new)
++ Object.const_defined?(:TEST_RC).should == false
++ end
++
++ describe "that raise exceptions" do
++ before do
++ Pry::HOME_RC_FILE = "spec/fixtures/testrcbad"
++ Pry.config.should_load_local_rc = false
++
++ putsed = nil
++
++ # YUCK! horrible hack to get round the fact that output is not configured
++ # at the point this message is printed.
++ (class << Pry; self; end).send(:define_method, :puts) { |str|
++ putsed = str
++ }
++
++ @doing_it = lambda{
++ Pry.start(self, :input => StringIO.new("Object::TEST_AFTER_RAISE=1\nexit-all\n"), :output => StringIO.new)
++ putsed
++ }
++ end
++
++ after do
++ Object.remove_const(:TEST_BEFORE_RAISE)
++ Object.remove_const(:TEST_AFTER_RAISE)
++ (class << Pry; undef_method :puts; end)
++ end
++
++ it "should not raise exceptions" do
++ @doing_it.should.not.raise
++ end
++
++ it "should continue to run pry" do
++ @doing_it[]
++ Object.const_defined?(:TEST_BEFORE_RAISE).should == true
++ Object.const_defined?(:TEST_AFTER_RAISE).should == true
++ end
++
++ it "should output an error" do
++ @doing_it.call.split("\n").first.should =~
++ %r{Error loading .*spec/fixtures/testrcbad: messin with ya}
++ end
++ end
++ end
++end
+diff --git a/spec/regression/readline_spec.rb b/spec/regression/readline_spec.rb
+new file mode 100644
+index 0000000..65427db
+--- /dev/null
++++ b/spec/regression/readline_spec.rb
+@@ -0,0 +1,39 @@
++# These specs ensure that Pry doesn't require readline until the first time a
++# REPL is started.
++
++require "helper"
++require "shellwords"
++
++describe "Readline" do
++ before do
++ @ruby = RbConfig.ruby.shellescape
++ @pry_dir = File.expand_path(File.join(__FILE__, '../../../lib')).shellescape
++ end
++
++ it "is not loaded on requiring 'pry'" do
++ code = <<-RUBY
++ require "pry"
++ p defined?(Readline)
++ RUBY
++ `#@ruby -I #@pry_dir -e '#{code}'`.should == "nil\n"
++ end
++
++ it "is loaded on invoking 'pry'" do
++ code = <<-RUBY
++ require "pry"
++ Pry.start self, input: StringIO.new("exit-all"), output: StringIO.new
++ puts defined?(Readline)
++ RUBY
++ `#@ruby -I #@pry_dir -e '#{code}'`.end_with?("constant\n").should == true
++ end
++
++ it "is not loaded on invoking 'pry' if Pry.input is set" do
++ code = <<-RUBY
++ require "pry"
++ Pry.input = StringIO.new("exit-all")
++ Pry.start self, output: StringIO.new
++ p defined?(Readline)
++ RUBY
++ `#@ruby -I #@pry_dir -e '#{code}'`.end_with?("nil\n").should == true
++ end
++end
+diff --git a/spec/run_command_spec.rb b/spec/run_command_spec.rb
+new file mode 100644
+index 0000000..787ffd0
+--- /dev/null
++++ b/spec/run_command_spec.rb
+@@ -0,0 +1,23 @@
++require_relative 'helper'
++
++describe "Pry.run_command" do
++ before do
++ o = Object.new
++ def o.drum
++ "roken is dodelijk"
++ end
++ @context = Pry.binding_for(o)
++ end
++
++ it 'performs a simple ls' do
++ @context.eval("hokey_pokey = 10")
++ Pry.run_command "ls", :context => @context, :output => out = StringIO.new
++ out.string.should =~ /hokey_pokey/
++ end
++
++ # This is a regression test as 0.9.11 broke this behaviour
++ it 'can perform a show-source' do
++ Pry.run_command "show-source drum", :context => @context, :output => out = StringIO.new
++ out.string.should =~ /roken is dodelijk/
++ end
++end
+diff --git a/spec/spec_helpers/bacon.rb b/spec/spec_helpers/bacon.rb
+new file mode 100644
+index 0000000..2a7721a
+--- /dev/null
++++ b/spec/spec_helpers/bacon.rb
+@@ -0,0 +1,86 @@
++# Colorize output (based on greeneggs (c) 2009 Michael Fleet)
++# TODO: Make own gem (assigned to rking)
++module Bacon
++ class Context
++ include PryTestHelpers
++ end
++
++ COLORS = {'F' => 31, 'E' => 35, 'M' => 33, '.' => 32}
++ USE_COLOR = !(ENV['NO_PRY_COLORED_BACON'] == 'true') && Pry::Helpers::BaseHelpers.use_ansi_codes?
++
++ module TestUnitOutput
++ def handle_requirement(description)
++ error = yield
++
++ if error.empty?
++ print colorize_string('.')
++ else
++ print colorize_string(error[0..0])
++ end
++ end
++
++ def handle_summary
++ puts
++ puts ErrorLog if Backtraces
++
++ out = "%d tests, %d assertions, %d failures, %d errors" %
++ Counter.values_at(:specifications, :requirements, :failed, :errors)
++
++ if Counter.values_at(:failed, :errors).inject(:+) > 0
++ puts colorize_string(out, 'F')
++ else
++ puts colorize_string(out, '.')
++ end
++ end
++
++ def colorize_string(text, color = nil)
++ if USE_COLOR
++ "\e[#{ COLORS[color || text] }m#{ text }\e[0m"
++ else
++ text
++ end
++ end
++ end
++end
++
++# Reset top-level binding at the beginning of each test case.
++module Bacon
++ class Context
++ def it_with_reset_binding(description, &block)
++ Pry.toplevel_binding = nil
++ it_without_reset_binding(description, &block)
++ end
++ alias it_without_reset_binding it
++ alias it it_with_reset_binding
++ end
++end
++
++# Support mocha
++# mocha-on-bacon (c) Copyright (C) 2011, Eloy Durán <eloy.de.enige at gmail.com>
++module Bacon
++ module MochaRequirementsCounter
++ def self.increment
++ Counter[:requirements] += 1
++ end
++ end
++
++ class Context
++ include Mocha::API
++
++ def it_with_mocha(description, &block)
++ it_without_mocha(description) do
++ begin
++ mocha_setup
++ block.call
++ mocha_verify(MochaRequirementsCounter)
++ rescue Mocha::ExpectationError => e
++ raise Error.new(:failed, e.message)
++ ensure
++ mocha_teardown
++ end
++ end
++ end
++ alias it_without_mocha it
++ alias it it_with_mocha
++ end
++end
+diff --git a/spec/spec_helpers/mock_pry.rb b/spec/spec_helpers/mock_pry.rb
+new file mode 100644
+index 0000000..c724611
+--- /dev/null
++++ b/spec/spec_helpers/mock_pry.rb
+@@ -0,0 +1,44 @@
++def mock_pry(*args)
++ args.flatten!
++ binding = args.first.is_a?(Binding) ? args.shift : binding()
++ options = args.last.is_a?(Hash) ? args.pop : {}
++
++ input = InputTester.new(*args)
++ output = StringIO.new
++
++ redirect_pry_io(input, output) do
++ binding.pry(options)
++ end
++
++ output.string
++end
++
++# Set I/O streams. Out defaults to an anonymous StringIO.
++def redirect_pry_io(new_in, new_out = StringIO.new)
++ old_in = Pry.config.input
++ old_out = Pry.config.output
++
++ Pry.config.input = new_in
++ Pry.config.output = new_out
++ begin
++ yield
++ ensure
++ Pry.config.input = old_in
++ Pry.config.output = old_out
++ end
++end
++
++class InputTester
++ def initialize(*actions)
++ @orig_actions = actions.dup
++ @actions = actions
++ end
++
++ def readline(*)
++ @actions.shift
++ end
++
++ def rewind
++ @actions = @orig_actions.dup
++ end
++end
+diff --git a/spec/spec_helpers/repl_tester.rb b/spec/spec_helpers/repl_tester.rb
+new file mode 100644
+index 0000000..51457e1
+--- /dev/null
++++ b/spec/spec_helpers/repl_tester.rb
+@@ -0,0 +1,112 @@
++# This is for super-high-level integration testing.
++
++require 'thread'
++require 'delegate'
++
++class ReplTester
++ class Input
++ def initialize(tester_mailbox)
++ @tester_mailbox = tester_mailbox
++ end
++
++ def readline(prompt)
++ @tester_mailbox.push prompt
++ mailbox.pop
++ end
++
++ def mailbox
++ Thread.current[:mailbox]
++ end
++ end
++
++ class Output < SimpleDelegator
++ def clear
++ __setobj__(StringIO.new)
++ end
++ end
++
++ def self.start(options = {}, &block)
++ Thread.current[:mailbox] = Queue.new
++ instance = nil
++ input = Input.new(Thread.current[:mailbox])
++ output = Output.new(StringIO.new)
++
++ redirect_pry_io input, output do
++ instance = new(options)
++ instance.instance_eval(&block)
++ instance.ensure_exit
++ end
++ ensure
++ if instance && instance.thread && instance.thread.alive?
++ instance.thread.kill
++ end
++ end
++
++ attr_accessor :thread, :mailbox, :last_prompt
++
++ def initialize(options = {})
++ @pry = Pry.new(options)
++ @repl = Pry::REPL.new(@pry)
++ @mailbox = Thread.current[:mailbox]
++
++ @thread = Thread.new do
++ begin
++ Thread.current[:mailbox] = Queue.new
++ @repl.start
++ ensure
++ Thread.current[:session_ended] = true
++ mailbox.push nil
++ end
++ end
++
++ wait # wait until the instance reaches its first readline
++ end
++
++ # Accept a line of input, as if entered by a user.
++ def input(input)
++ reset_output
++ repl_mailbox.push input
++ wait
++ @pry.output.string
++ end
++
++ # Assert that the current prompt matches the given string or regex.
++ def prompt(match)
++ match.should === last_prompt
++ end
++
++ # Assert that the most recent output (since the last time input was called)
++ # matches the given string or regex.
++ def output(match)
++ match.should === @pry.output.string.chomp
++ end
++
++ # Assert that the Pry session ended naturally after the last input.
++ def assert_exited
++ @should_exit_naturally = true
++ end
++
++ # @private
++ def ensure_exit
++ if @should_exit_naturally
++ @thread[:session_ended].should.be.true
++ else
++ input "exit-all"
++ raise "REPL didn't die" unless @thread[:session_ended]
++ end
++ end
++
++ private
++
++ def reset_output
++ @pry.output.clear
++ end
++
++ def repl_mailbox
++ @thread[:mailbox]
++ end
++
++ def wait
++ @last_prompt = mailbox.pop
++ end
++end
+diff --git a/spec/sticky_locals_spec.rb b/spec/sticky_locals_spec.rb
+new file mode 100644
+index 0000000..7caf931
+--- /dev/null
++++ b/spec/sticky_locals_spec.rb
+@@ -0,0 +1,180 @@
++require_relative 'helper'
++
++describe "Sticky locals (_file_ and friends)" do
++ it 'locals should all exist upon initialization' do
++ proc {
++ pry_eval '_file_', '_dir_', '_ex_', '_pry_', '_'
++ }.should.not.raise(NameError)
++ end
++
++ it 'locals should still exist after cd-ing into a new context' do
++ proc {
++ pry_eval 'cd 0', '_file_', '_dir_', '_ex_', '_pry_', '_'
++ }.should.not.raise(NameError)
++ end
++
++ it 'locals should keep value after cd-ing (_pry_)' do
++ pry_tester.tap do |t|
++ pry = t.eval '_pry_'
++ t.eval 'cd 0'
++ t.eval('_pry_').should == pry
++ end
++ end
++
++ describe '_ex_' do
++ it 'returns the last exception without wrapping it in a LastException' do
++ ReplTester.start do
++ input 'raise "halp"'
++
++ input '_ex_.message == "halp"'
++ output '=> true'
++
++ input 'Kernel.instance_method(:class).bind(_ex_).call'
++ output '=> RuntimeError'
++ end
++ end
++
++ it 'keeps its value after cd-ing' do
++ ReplTester.start do
++ input 'error blah'
++ input '$x = _ex_'
++ input 'cd 0'
++
++ input '_ex_ == $x'
++ output '=> true'
++ end
++ end
++ end
++
++ it 'locals should keep value after cd-ing (_file_ and _dir_)' do
++ Pry.config.commands.command "file-and-dir-test" do
++ set_file_and_dir_locals("/blah/ostrich.rb")
++ end
++
++ pry_eval('file-and-dir-test', 'cd 0', '_file_').
++ should =~ /\/blah\/ostrich\.rb/
++
++ pry_eval('file-and-dir-test', 'cd 0', '_dir_').
++ should =~ /\/blah/
++
++ Pry.config.commands.delete "file-and-dir-test"
++ end
++
++ it 'locals should return last result (_)' do
++ pry_tester.tap do |t|
++ lam = t.eval 'lambda { |foo| }'
++ t.eval('_').should == lam
++ end
++ end
++
++ it 'locals should return second last result (__)' do
++ pry_tester.tap do |t|
++ lam = t.eval 'lambda { |foo| }'
++ t.eval 'num = 1'
++ t.eval('__').should == lam
++ end
++ end
++
++ describe "User defined sticky locals" do
++ describe "setting as Pry.config option" do
++ it 'should define a new sticky local for the session (normal value)' do
++ Pry.config.extra_sticky_locals[:test_local] = :john
++ o = Object.new
++ redirect_pry_io(InputTester.new("@value = test_local",
++ "exit-all")) do
++ Pry.start(o)
++ end
++ o.instance_variable_get(:@value).should == :john
++ Pry.config.extra_sticky_locals = {}
++ end
++
++ it 'should define a new sticky local for the session (proc)' do
++ Pry.config.extra_sticky_locals[:test_local] = proc { :john }
++
++ o = Object.new
++ redirect_pry_io(InputTester.new("@value = test_local",
++ "exit-all")) do
++ Pry.start(o)
++ end
++
++ o.instance_variable_get(:@value).should == :john
++ Pry.config.extra_sticky_locals = {}
++ end
++
++ end
++
++ describe "passing in as hash option when creating pry instance" do
++ it 'should define a new sticky local for the session (normal value)' do
++ o = Object.new
++ redirect_pry_io(InputTester.new("@value = test_local",
++ "exit-all")) do
++ Pry.start(o, :extra_sticky_locals => { :test_local => :john } )
++ end
++
++ o.instance_variable_get(:@value).should == :john
++ end
++
++ it 'should define multiple sticky locals' do
++ o = Object.new
++ redirect_pry_io(InputTester.new("@value1 = test_local1",
++ "@value2 = test_local2",
++ "exit-all")) do
++ Pry.start(o, :extra_sticky_locals => { :test_local1 => :john ,
++ :test_local2 => :carl} )
++ end
++
++ o.instance_variable_get(:@value1).should == :john
++ o.instance_variable_get(:@value2).should == :carl
++ end
++
++
++ it 'should define a new sticky local for the session (as Proc)' do
++ o = Object.new
++ redirect_pry_io(InputTester.new("@value = test_local",
++ "exit-all")) do
++ Pry.start(o, :extra_sticky_locals => { :test_local => proc { :john }} )
++ end
++
++ o.instance_variable_get(:@value).should == :john
++ end
++ end
++
++ describe "hash option value should override config value" do
++ it 'should define a new sticky local for the session (normal value)' do
++ Pry.config.extra_sticky_locals[:test_local] = :john
++
++ o = Object.new
++ redirect_pry_io(InputTester.new("@value = test_local",
++ "exit-all")) do
++ Pry.start(o, :extra_sticky_locals => { :test_local => :carl })
++ end
++
++ o.instance_variable_get(:@value).should == :carl
++ Pry.config.extra_sticky_locals = {}
++ end
++ end
++
++ it 'should create a new sticky local' do
++ t = pry_tester
++ t.eval "_pry_.add_sticky_local(:test_local){ :test_value }"
++ t.eval("test_local").should == :test_value
++ end
++
++ it 'should still exist after cd-ing into new binding' do
++ t = pry_tester
++ t.eval "_pry_.add_sticky_local(:test_local){ :test_value }"
++ t.eval "cd Object.new"
++ t.eval("test_local").should == :test_value
++ end
++
++ it 'should provide different values for successive block invocations' do
++ pry = Pry.new
++ pry.push_binding binding
++ pry.add_sticky_local(:test_local) { rand }
++ value1 = pry.evaluate_ruby 'test_local'
++ value2 = pry.evaluate_ruby 'test_local'
++ value1.should.not == value2
++ end
++ end
++
++end
+diff --git a/spec/syntax_checking_spec.rb b/spec/syntax_checking_spec.rb
+new file mode 100644
+index 0000000..cd2700f
+--- /dev/null
++++ b/spec/syntax_checking_spec.rb
+@@ -0,0 +1,81 @@
++require_relative 'helper'
++
++describe Pry do
++ before do
++ @str_output = StringIO.new
++ end
++
++ [
++ ["p = '", "'"],
++ ["def", "a", "(); end"],
++ ["p = <<FOO", "lots", "and", "lots of", "foo", "FOO"],
++ ["[", ":lets,", "'list',", "[/nested/", "], things ]"],
++ ["abc =~ /hello", "/"],
++ ["issue = %W/", "343/"],
++ ["pouts(<<HI, 'foo", "bar", "HI", "baz')"],
++ ].each do |foo|
++ it "should not raise an error on broken lines: #{foo.join("\\n")}" do
++ redirect_pry_io(InputTester.new(*foo), @str_output) do
++ Pry.start
++ end
++
++ @str_output.string.should.not =~ /SyntaxError/
++ end
++ end
++
++ [
++ ["end"],
++ ["puts )("],
++ ["1 1"],
++ ["puts :"]
++ ] + (Pry::Helpers::BaseHelpers.rbx? ? [] : [
++ ["def", "method(1"], # in this case the syntax error is "expecting ')'".
++ ["o = Object.new.tap{ def o.render;","'MEH'", "}"] # in this case the syntax error is "expecting keyword_end".
++ ]).compact.each do |foo|
++ it "should raise an error on invalid syntax like #{foo.inspect}" do
++ redirect_pry_io(InputTester.new(*foo), @str_output) do
++ Pry.start
++ end
++
++ @str_output.string.should =~ /SyntaxError/
++ end
++ end
++
++ it "should not intefere with syntax errors explicitly raised" do
++ redirect_pry_io(InputTester.new(%q{raise SyntaxError, "unexpected $end"}), @str_output) do
++ Pry.start
++ end
++
++ @str_output.string.should =~ /SyntaxError/
++ end
++
++ it "should allow trailing , to continue the line" do
++ pry = Pry.new
++ Pry::Code.complete_expression?("puts 1, 2,").should == false
++ end
++
++ it "should complete an expression that contains a line ending with a ," do
++ pry = Pry.new
++ Pry::Code.complete_expression?("puts 1, 2,\n3").should == true
++ end
++
++ it "should not suppress the error output if the line ends in ;" do
++ mock_pry("raise RuntimeError, 'foo';").should =~ /RuntimeError/
++ end
++
++ it "should not clobber _ex_ on a SyntaxError in the repl" do
++ mock_pry("raise RuntimeError, 'foo'", "puts foo)", "_ex_.is_a?(RuntimeError)").should =~ /^RuntimeError.*\nSyntaxError.*\n=> true/m
++ end
++
++ it "should allow whitespace delimeted strings" do
++ mock_pry('"%s" %% foo ').should =~ /"foo"/
++ end
++
++ it "should allow newline delimeted strings" do
++ mock_pry('"%s" %%','foo').should =~ /"foo"/
++ end
++
++ it "should allow whitespace delimeted strings ending on the first char of a line" do
++ mock_pry('"%s" %% ', ' #done!').should =~ /"\\n"/
++ end
++end
+diff --git a/spec/wrapped_module_spec.rb b/spec/wrapped_module_spec.rb
+new file mode 100644
+index 0000000..d3d32d0
+--- /dev/null
++++ b/spec/wrapped_module_spec.rb
+@@ -0,0 +1,276 @@
++require_relative 'helper'
++
++describe Pry::WrappedModule do
++
++ describe "#initialize" do
++ it "should raise an exception when a non-module is passed" do
++ lambda{ Pry::WrappedModule.new(nil) }.should.raise ArgumentError
++ end
++ end
++
++ describe "candidates" do
++ before do
++ class Host
++ %w(spec/fixtures/candidate_helper1.rb
++ spec/fixtures/candidate_helper2.rb).each do |file|
++ binding.eval File.read(file), file, 1
++ end
++
++ # rank 2
++ class CandidateTest
++ def test6
++ end
++ end
++
++ class PitifullyBlank
++ DEFAULT_TEST = CandidateTest
++ end
++
++ FOREVER_ALONE_LINE = __LINE__ + 1
++ class ForeverAlone
++ class DoublyNested
++ # nested docs
++ class TriplyNested
++ def nested_method
++ end
++ end
++ end
++ end
++ end
++ end
++
++ describe "number_of_candidates" do
++ it 'should return the correct number of candidates' do
++ Pry::WrappedModule(Host::CandidateTest).number_of_candidates.should == 3
++ end
++
++ it 'should return 0 candidates for a class with no nested modules or methods' do
++ Pry::WrappedModule(Host::PitifullyBlank).number_of_candidates.should == 0
++ end
++
++ it 'should return 1 candidate for a class with a nested module with methods' do
++ Pry::WrappedModule(Host::ForeverAlone).number_of_candidates.should == 1
++ end
++ end
++
++ describe "ordering of candidates" do
++ it 'should return class with largest number of methods as primary candidate' do
++ Pry::WrappedModule(Host::CandidateTest).candidate(0).file.should =~ /helper1/
++ end
++
++ it 'should return class with second largest number of methods as second ranked candidate' do
++ Pry::WrappedModule(Host::CandidateTest).candidate(1).file.should =~ /helper2/
++ end
++
++ it 'should return class with third largest number of methods as third ranked candidate' do
++ Pry::WrappedModule(Host::CandidateTest).candidate(2).file.should =~ /#{__FILE__}/
++ end
++
++ it 'should raise when trying to access non-existent candidate' do
++ lambda { Pry::WrappedModule(Host::CandidateTest).candidate(3) }.should.raise Pry::CommandError
++ end
++ end
++
++ describe "source_location" do
++ it 'should return primary candidates source_location by default' do
++ wm = Pry::WrappedModule(Host::CandidateTest)
++ wm.source_location.should == wm.candidate(0).source_location
++ end
++
++ it 'should return the location of the outer module if an inner module has methods' do
++ wm = Pry::WrappedModule(Host::ForeverAlone)
++ File.expand_path(wm.source_location.first).should == File.expand_path(__FILE__)
++ wm.source_location.last.should == Host::FOREVER_ALONE_LINE
++ end
++
++ it 'should return nil if no source_location can be found' do
++ Pry::WrappedModule(Host::PitifullyBlank).source_location.should == nil
++ end
++ end
++
++ describe "source" do
++ it 'should return primary candidates source by default' do
++ wm = Pry::WrappedModule(Host::CandidateTest)
++ wm.source.should == wm.candidate(0).source
++ end
++
++ it 'should return source for highest ranked candidate' do
++ Pry::WrappedModule(Host::CandidateTest).candidate(0).source.should =~ /test1/
++ end
++
++ it 'should return source for second ranked candidate' do
++ Pry::WrappedModule(Host::CandidateTest).candidate(1).source.should =~ /test4/
++ end
++
++ it 'should return source for third ranked candidate' do
++ Pry::WrappedModule(Host::CandidateTest).candidate(2).source.should =~ /test6/
++ end
++
++ it 'should return source for deeply nested class' do
++ Pry::WrappedModule(Host::ForeverAlone::DoublyNested::TriplyNested).source.should =~ /nested_method/
++ Pry::WrappedModule(Host::ForeverAlone::DoublyNested::TriplyNested).source.lines.count.should == 4
++ end
++ end
++
++ describe "doc" do
++ it 'should return primary candidates doc by default' do
++ wm = Pry::WrappedModule(Host::CandidateTest)
++ wm.doc.should == wm.candidate(0).doc
++ end
++
++ it 'should return doc for highest ranked candidate' do
++ Pry::WrappedModule(Host::CandidateTest).candidate(0).doc.should =~ /rank 0/
++ end
++
++ it 'should return doc for second ranked candidate' do
++ Pry::WrappedModule(Host::CandidateTest).candidate(1).doc.should =~ /rank 1/
++ end
++
++ it 'should return doc for third ranked candidate' do
++ Pry::WrappedModule(Host::CandidateTest).candidate(2).doc.should =~ /rank 2/
++ end
++
++ it 'should return docs for deeply nested class' do
++ Pry::WrappedModule(Host::ForeverAlone::DoublyNested::TriplyNested).doc.should =~ /nested docs/
++ end
++ end
++
++ after do
++ Object.remove_const(:Host)
++ end
++ end
++
++ describe ".method_prefix" do
++ before do
++ Foo = Class.new
++ @foo = Foo.new
++ end
++
++ after do
++ Object.remove_const(:Foo)
++ end
++
++ it "should return Foo# for normal classes" do
++ Pry::WrappedModule.new(Foo).method_prefix.should == "Foo#"
++ end
++
++ it "should return Bar# for modules" do
++ Pry::WrappedModule.new(Kernel).method_prefix.should == "Kernel#"
++ end
++
++ it "should return Foo. for singleton classes of classes" do
++ Pry::WrappedModule.new(class << Foo; self; end).method_prefix.should == "Foo."
++ end
++
++ describe "of singleton classes of objects" do
++ Pry::WrappedModule.new(class << @foo; self; end).method_prefix.should == "self."
++ end
++
++ describe "of anonymous classes should not be empty" do
++ Pry::WrappedModule.new(Class.new).method_prefix.should =~ /#<Class:.*>#/
++ end
++
++ describe "of singleton classes of anonymous classes should not be empty" do
++ Pry::WrappedModule.new(class << Class.new; self; end).method_prefix.should =~ /#<Class:.*>./
++ end
++ end
++
++ describe ".singleton_class?" do
++ it "should be true for singleton classes" do
++ Pry::WrappedModule.new(class << ""; self; end).singleton_class?.should == true
++ end
++
++ it "should be false for normal classes" do
++ Pry::WrappedModule.new(Class.new).singleton_class?.should == false
++ end
++
++ it "should be false for modules" do
++ Pry::WrappedModule.new(Module.new).singleton_class?.should == false
++ end
++ end
++
++ describe ".singleton_instance" do
++ it "should raise an exception when called on a non-singleton-class" do
++ lambda{ Pry::WrappedModule.new(Class).singleton_instance }.should.raise ArgumentError
++ end
++
++ it "should return the attached object" do
++ Pry::WrappedModule.new(class << "hi"; self; end).singleton_instance.should == "hi"
++ Pry::WrappedModule.new(class << Object; self; end).singleton_instance.should.equal?(Object)
++ end
++ end
++
++ describe ".super" do
++ describe "receiver is a class" do
++ before do
++ @a = Class.new
++ @m = Module.new
++ @b = Class.new(@a)
++ @b.send(:include, @m)
++ @c = Class.new(@b)
++ end
++
++ it 'should return superclass for a wrapped class' do
++ Pry::WrappedModule(@c).super.wrapped.should == @b
++ end
++
++ it 'should return nth superclass for a wrapped class' do
++ d = Class.new(@c)
++ Pry::WrappedModule(d).super(2).wrapped.should == @b
++ end
++
++ it 'should ignore modules when retrieving nth superclass' do
++ Pry::WrappedModule(@c).super(2).wrapped.should == @a
++ end
++
++ it 'should return nil when no nth superclass exists' do
++ Pry::WrappedModule(@c).super(10).should == nil
++ end
++
++ it 'should return self when .super(0) is used' do
++ c = Pry::WrappedModule(@c)
++ c.super(0).should == c
++ end
++ end
++
++ describe "receiver is a module" do
++ before do
++ @m1 = Module.new
++ @m2 = Module.new.tap { |v| v.send(:include, @m1) }
++ @m3 = Module.new.tap { |v| v.send(:include, @m2) }
++ end
++
++ it 'should not ignore modules when retrieving supers' do
++ Pry::WrappedModule(@m3).super.wrapped.should == @m2
++ end
++
++ it 'should retrieve nth super' do
++ Pry::WrappedModule(@m3).super(2).wrapped.should == @m1
++ end
++
++ it 'should return self when .super(0) is used' do
++ m = Pry::WrappedModule(@m1)
++ m.super(0).should == m
++ end
++ end
++ end
++
++ describe ".from_str" do
++ it 'should lookup a constant' do
++ m = Pry::WrappedModule.from_str("Host::CandidateTest", binding)
++ m.wrapped.should == Host::CandidateTest
++ end
++
++ it 'should lookup a local' do
++ local = Host::CandidateTest
++ m = Pry::WrappedModule.from_str("local", binding)
++ m.wrapped.should == Host::CandidateTest
++ end
++
++ it 'should lookup an ivar' do
++ @ivar = Host::CandidateTest
++ m = Pry::WrappedModule.from_str("@ivar", binding)
++ m.wrapped.should == Host::CandidateTest
++ end
++ end
++end
diff --git a/debian/patches/0002-Modify-upstream-spec-for-Debian-Package.patch b/debian/patches/0002-Modify-upstream-spec-for-Debian-Package.patch
new file mode 100644
index 0000000..3851efb
--- /dev/null
+++ b/debian/patches/0002-Modify-upstream-spec-for-Debian-Package.patch
@@ -0,0 +1,37 @@
+From: Youhei SASAKI <uwabami at gfd-dennou.org>
+Date: Tue, 12 Aug 2014 19:50:15 +0900
+Subject: Modify upstream spec for Debian Package
+
+Signed-off-by: Youhei SASAKI <uwabami at gfd-dennou.org>
+---
+ Rakefile | 0
+ spec/helper.rb | 9 +++------
+ 2 files changed, 3 insertions(+), 6 deletions(-)
+ create mode 100644 Rakefile
+
+diff --git a/Rakefile b/Rakefile
+new file mode 100644
+index 0000000..e69de29
+diff --git a/spec/helper.rb b/spec/helper.rb
+index b579d8c..da296cf 100644
+--- a/spec/helper.rb
++++ b/spec/helper.rb
+@@ -1,15 +1,12 @@
+ require 'bundler/setup'
+ require 'pry/test/helper'
+-Bundler.require :default, :test
++require 'ostruct'
++require 'bacon'
++require 'mocha/api'
+ require_relative 'spec_helpers/bacon'
+ require_relative 'spec_helpers/mock_pry'
+ require_relative 'spec_helpers/repl_tester'
+
+-if ENV["COVERAGE"]
+- require "simplecov"
+- SimpleCov.start
+-end
+-
+ class Module
+ public :remove_const
+ public :remove_method
diff --git a/debian/patches/fix_spelling.patch b/debian/patches/fix_spelling.patch
deleted file mode 100644
index 258fd58..0000000
--- a/debian/patches/fix_spelling.patch
+++ /dev/null
@@ -1,15 +0,0 @@
-Description: fix spelling, not forwarded, upstream will remove manpages
-Author: Jonas Genannt <jonas.genannt at capi2name.de>
-Forwarded: not-needed
-
---- a/man/pry.1
-+++ b/man/pry.1
-@@ -43,7 +43,7 @@
- .
- .TP
- \fB\-\-no\-plugins\fR
--Supress loading of plugins\.
-+Suppress loading of plugins\.
- .
- .TP
- \fB\-\-installed\-plugins\fR
diff --git a/debian/patches/series b/debian/patches/series
index 1201281..c135c64 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1,2 @@
-# fix_spelling.patch
+0001-Import-upstream-rspec-files.patch
+0002-Modify-upstream-spec-for-Debian-Package.patch
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/pry.git
More information about the Pkg-ruby-extras-commits
mailing list