From f19481efa194271e2ad38d4f6e4f20e618d484db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mon=20ou=C3=AFe?= Date: Sun, 15 May 2011 11:29:14 +0200 Subject: [PATCH 1/7] Added a HistoryArrray class --- lib/pry.rb | 1 + lib/pry/history_array.rb | 105 +++++++++++++++++++++++ test/test_history_array.rb | 169 +++++++++++++++++++++++++++++++++++++ 3 files changed, 275 insertions(+) create mode 100644 lib/pry/history_array.rb create mode 100644 test/test_history_array.rb diff --git a/lib/pry.rb b/lib/pry.rb index 9f822be8..422910a4 100644 --- a/lib/pry.rb +++ b/lib/pry.rb @@ -22,6 +22,7 @@ end require "pry/version" require "pry/hooks" require "pry/print" +require "pry/history_array" require "pry/helpers" require "pry/command_set" require "pry/commands" diff --git a/lib/pry/history_array.rb b/lib/pry/history_array.rb new file mode 100644 index 00000000..2fc7bba8 --- /dev/null +++ b/lib/pry/history_array.rb @@ -0,0 +1,105 @@ +class Pry + # A history array is an array to which you can only add elements. Older + # entries are removed progressively, so that the aray never contains more than + # N elements. + # + # History arrays are used by Pry to store the output of the last commands. + # + # @example + # ary = Pry::HistoryArray.new 10 + # ary << 1 << 2 << 3 + # ary[0] # => 1 + # ary[1] # => 2 + # 10.times { |n| ary << n } + # ary[0] # => nil + # ary[-1] # => 9 + class HistoryArray + include Enumerable + + # @param [Integer] size Maximum amount of objects in the array + def initialize(size) + @max_size = size + + @hash = {} + @count = 0 + end + + # Pushes an object at the end of the array + # @param [Object] value Object to be added + def <<(value) + @hash[@count] = value + + if @hash.size > max_size + @hash.delete(@count - max_size) + end + + @count += 1 + + self + end + + # @overload [](index) + # @param [Integer] index Index of the item to access. + # @return [Object, nil] Item at that index or nil if it has been removed. + # @overload [](index, size) + # @param [Integer] index Index of the first item to access. + # @param [Integer] size Amount of items to access + # @return [Array, nil] The selected items. Nil if index is greater than + # the size of the array. + # @overload [](range) + # @param [Range] range Range of indices to access. + # @return [Array, nil] The selected items. Nil if index is greater than + # the size of the array. + def [](index_or_range, size = nil) + if index_or_range.is_a? Integer + index = convert_index(index_or_range) + + if size + end_index = index + size + index > @count ? nil : (index...[end_index, @count].min).map do |n| + @hash[n] + end + else + @hash[index] + end + else + range = convert_range(index_or_range) + range.begin > @count ? nil : range.map { |n| @hash[n] } + end + end + + # @return [Integer] Amount of objects in the array + def size + @count + end + + def each + ((@count - size)...@count).each do |n| + yield @hash[n] + end + end + + def to_a + ((@count - size)...@count).map { |n| @hash[n] } + end + + def inspect + to_a.inspect + end + + # @return [Integer] Maximum amount of objects in the array + attr_reader :max_size + + private + def convert_index(n) + n >= 0 ? n : @count + n + end + + def convert_range(range) + end_index = convert_index(range.end) + end_index += 1 unless range.exclude_end? + + Range.new(convert_index(range.begin), [end_index, @count].min, true) + end + end +end diff --git a/test/test_history_array.rb b/test/test_history_array.rb new file mode 100644 index 00000000..ce801283 --- /dev/null +++ b/test/test_history_array.rb @@ -0,0 +1,169 @@ +require 'helper' + +class Pry + # A history array is an array to which you can only add elements. Older + # entries are removed progressively, so that the aray never contains more than + # N elements. + # + # @example + # ary = Pry::HistoryArray.new 10 + # ary << 1 << 2 << 3 + # ary[0] # => 1 + # ary[1] # => 2 + # 10.times { |n| ary << n } + # ary[0] # => nil + # ary[-1] # => 9 + class HistoryArray + include Enumerable + + # @param [Integer] size Maximum amount of objects in the array + def initialize(size) + @max_size = size + + @hash = {} + @count = 0 + end + + # Pushes an object at the end of the array + # @param [Object] value Object to be added + def <<(value) + @hash[@count] = value + + if @hash.size > max_size + @hash.delete(@count - max_size) + end + + @count += 1 + + self + end + + # @overload [](index) + # @param [Integer] index Index of the item to access. + # @return [Object, nil] Item at that index or nil if it has been removed. + # @overload [](index, size) + # @param [Integer] index Index of the first item to access. + # @param [Integer] size Amount of items to access + # @return [Array, nil] The selected items. Nil if index is greater than + # the size of the array. + # @overload [](range) + # @param [Range] range Range of indices to access. + # @return [Array, nil] The selected items. Nil if index is greater than + # the size of the array. + def [](index_or_range, size = nil) + if index_or_range.is_a? Integer + index = convert_index(index_or_range) + + if size + end_index = index + size + index > @count ? nil : (index...[end_index, @count].min).map do |n| + @hash[n] + end + else + @hash[index] + end + else + range = convert_range(index_or_range) + range.begin > @count ? nil : range.map { |n| @hash[n] } + end + end + + # @return [Integer] Amount of objects in the array + def size + @count + end + + def each + ((@count - size)...@count).each do |n| + yield @hash[n] + end + end + + def to_a + ((@count - size)...@count).map { |n| @hash[n] } + end + + def inspect + to_a.inspect + end + + # @return [Integer] Maximum amount of objects in the array + attr_reader :max_size + + private + def convert_index(n) + n >= 0 ? n : @count + n + end + + def convert_range(range) + end_index = convert_index(range.end) + end_index += 1 unless range.exclude_end? + + Range.new(convert_index(range.begin), [end_index, @count].min, true) + end + end +end + +describe Pry::HistoryArray do + before do + @array = Pry::HistoryArray.new 10 + 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 + @array << 1 << 2 << 3 + @array.size.should == 3 + @array.to_a.should == [1, 2, 3] + end + + it 'should be able to access single elements' do + @array << 1 << 2 << 3 + @array[2].should == 3 + end + + it 'should be able to access negative indices' do + @array << 1 << 2 << 3 + @array[-1].should == 3 + end + + it 'should be able to access ranges' do + @array << 1 << 2 << 3 << 4 + @array[1..2].should == [2, 3] + end + + it 'should be able to access ranges starting from a negative index' do + @array << 1 << 2 << 3 << 4 + @array[-2..3].should == [3, 4] + end + + it 'should be able to access ranges ending at a negative index' do + @array << 1 << 2 << 3 << 4 + @array[2..-1].should == [3, 4] + end + + it 'should be able to access ranges using only negative indices' do + @array << 1 << 2 << 3 << 4 + @array[-2..-1].should == [3, 4] + end + + it 'should be able to use range where end is excluded' do + @array << 1 << 2 << 3 << 4 + @array[-2...-1].should == [3] + end + + it 'should be able to access slices using a size' do + @array << 1 << 2 << 3 << 4 + @array[-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 +end From e0224000db8359c1c7b5aa1b9ea9304a583b9255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mon=20ou=C3=AFe?= Date: Sun, 15 May 2011 12:03:16 +0200 Subject: [PATCH 2/7] Added a first try to implement _in_ and _out_ arrays in Pry --- lib/pry/history_array.rb | 2 +- lib/pry/pry_instance.rb | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/pry/history_array.rb b/lib/pry/history_array.rb index 2fc7bba8..b6beb179 100644 --- a/lib/pry/history_array.rb +++ b/lib/pry/history_array.rb @@ -84,7 +84,7 @@ class Pry end def inspect - to_a.inspect + "#<#{self.class} size=#{size} first=#{@count - size} max_size=#{max_size}>" end # @return [Integer] Maximum amount of objects in the array diff --git a/lib/pry/pry_instance.rb b/lib/pry/pry_instance.rb index 9477e252..e246ceaf 100644 --- a/lib/pry/pry_instance.rb +++ b/lib/pry/pry_instance.rb @@ -34,6 +34,9 @@ class Pry end @command_processor = CommandProcessor.new(self) + + @input_array = HistoryArray.new(100) + @output_array = HistoryArray.new(100) end # Get nesting data. @@ -72,7 +75,10 @@ class Pry # Make sure special locals exist target.eval("_pry_ = ::Pry.active_instance") - target.eval("_ = ::Pry.last_result") + target.eval("_ = ::Pry.last_result") + target.eval("_in_ = ::Pry.active_instance.instance_eval { @input_array }") + target.eval("_out_ = ::Pry.active_instance.instance_eval { @output_array }") + self.session_target = target end @@ -154,6 +160,8 @@ class Pry # save the pry instance to active_instance Pry.active_instance = self target.eval("_pry_ = ::Pry.active_instance") + target.eval("_in_ = ::Pry.active_instance.instance_eval { @input_array }") + target.eval("_out_ = ::Pry.active_instance.instance_eval { @output_array }") @last_result_is_exception = false @@ -191,6 +199,7 @@ class Pry @suppress_output = true if eval_string =~ /;\Z/ || null_input?(val) + @input_array << eval_string eval_string end @@ -251,6 +260,7 @@ class Pry # @param [Binding] target The binding to set `_` on. def set_last_result(result, target) Pry.last_result = result + @output_array << result target.eval("_ = ::Pry.last_result") end From a38cb7299078dd076bb70a220da8cb0f23bbe7ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mon=20ou=C3=AFe?= Date: Sun, 15 May 2011 12:08:59 +0200 Subject: [PATCH 3/7] Changed the place where input_array was modified --- lib/pry/pry_instance.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/pry/pry_instance.rb b/lib/pry/pry_instance.rb index e246ceaf..c655580a 100644 --- a/lib/pry/pry_instance.rb +++ b/lib/pry/pry_instance.rb @@ -169,7 +169,11 @@ class Pry # Do not want __FILE__, __LINE__ here because we need to distinguish # (eval) methods for show-method and friends. # This also sets the `_` local for the session. - set_last_result(target.eval(r(target)), target) + code = r(target) + res = set_last_result(target.eval(code), target) + + @input_array << code + res rescue SystemExit => e exit rescue Exception => e @@ -199,7 +203,6 @@ class Pry @suppress_output = true if eval_string =~ /;\Z/ || null_input?(val) - @input_array << eval_string eval_string end From deab37f28e8265c846e8fef06af5153602a63980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mon=20ou=C3=AFe?= Date: Sun, 15 May 2011 12:24:52 +0200 Subject: [PATCH 4/7] Removed duplicate implementation from tests --- test/test_history_array.rb | 104 ------------------------------------- 1 file changed, 104 deletions(-) diff --git a/test/test_history_array.rb b/test/test_history_array.rb index ce801283..fecd3555 100644 --- a/test/test_history_array.rb +++ b/test/test_history_array.rb @@ -1,109 +1,5 @@ require 'helper' -class Pry - # A history array is an array to which you can only add elements. Older - # entries are removed progressively, so that the aray never contains more than - # N elements. - # - # @example - # ary = Pry::HistoryArray.new 10 - # ary << 1 << 2 << 3 - # ary[0] # => 1 - # ary[1] # => 2 - # 10.times { |n| ary << n } - # ary[0] # => nil - # ary[-1] # => 9 - class HistoryArray - include Enumerable - - # @param [Integer] size Maximum amount of objects in the array - def initialize(size) - @max_size = size - - @hash = {} - @count = 0 - end - - # Pushes an object at the end of the array - # @param [Object] value Object to be added - def <<(value) - @hash[@count] = value - - if @hash.size > max_size - @hash.delete(@count - max_size) - end - - @count += 1 - - self - end - - # @overload [](index) - # @param [Integer] index Index of the item to access. - # @return [Object, nil] Item at that index or nil if it has been removed. - # @overload [](index, size) - # @param [Integer] index Index of the first item to access. - # @param [Integer] size Amount of items to access - # @return [Array, nil] The selected items. Nil if index is greater than - # the size of the array. - # @overload [](range) - # @param [Range] range Range of indices to access. - # @return [Array, nil] The selected items. Nil if index is greater than - # the size of the array. - def [](index_or_range, size = nil) - if index_or_range.is_a? Integer - index = convert_index(index_or_range) - - if size - end_index = index + size - index > @count ? nil : (index...[end_index, @count].min).map do |n| - @hash[n] - end - else - @hash[index] - end - else - range = convert_range(index_or_range) - range.begin > @count ? nil : range.map { |n| @hash[n] } - end - end - - # @return [Integer] Amount of objects in the array - def size - @count - end - - def each - ((@count - size)...@count).each do |n| - yield @hash[n] - end - end - - def to_a - ((@count - size)...@count).map { |n| @hash[n] } - end - - def inspect - to_a.inspect - end - - # @return [Integer] Maximum amount of objects in the array - attr_reader :max_size - - private - def convert_index(n) - n >= 0 ? n : @count + n - end - - def convert_range(range) - end_index = convert_index(range.end) - end_index += 1 unless range.exclude_end? - - Range.new(convert_index(range.begin), [end_index, @count].min, true) - end - end -end - describe Pry::HistoryArray do before do @array = Pry::HistoryArray.new 10 From b96f00cebd0747a795338883d781b9c5e03811b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mon=20ou=C3=AFe?= Date: Sun, 5 Jun 2011 18:37:54 +0200 Subject: [PATCH 5/7] Allowed size of history arrays to be set in Pry.config --- lib/pry/config.rb | 3 +++ lib/pry/pry_class.rb | 4 +++- lib/pry/pry_instance.rb | 8 +++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/pry/config.rb b/lib/pry/config.rb index acb61c8b..338c91ac 100644 --- a/lib/pry/config.rb +++ b/lib/pry/config.rb @@ -88,6 +88,9 @@ class Pry # `plugins.strict_loading` (Boolean) which toggles whether referring to a non-existent plugin should raise an exception (defaults to `false`) # @return [OpenStruct] attr_accessor :plugins + + # @return [Integer] Amount of results that will be stored into _out_ + attr_accessor :memory_size end end diff --git a/lib/pry/pry_class.rb b/lib/pry/pry_class.rb index 5a2fe3d1..75c9062e 100644 --- a/lib/pry/pry_class.rb +++ b/lib/pry/pry_class.rb @@ -69,7 +69,7 @@ class Pry def_delegators :@plugin_manager, :plugins, :load_plugins, :locate_plugins delegate_accessors :@config, :input, :output, :commands, :prompt, :print, :exception_handler, - :hooks, :color, :pager, :editor + :hooks, :color, :pager, :editor, :memory_size end # Load the rc files given in the `Pry::RC_FILES` array. @@ -199,6 +199,8 @@ class Pry config.history.save = true config.history.load = true config.history.file = File.expand_path("~/.pry_history") + + config.memory_size = 100 end # Set all the configurable options back to their default values diff --git a/lib/pry/pry_instance.rb b/lib/pry/pry_instance.rb index 904d5595..c77e18ab 100644 --- a/lib/pry/pry_instance.rb +++ b/lib/pry/pry_instance.rb @@ -28,9 +28,6 @@ class Pry refresh(options) @command_processor = CommandProcessor.new(self) - - @input_array = HistoryArray.new(100) - @output_array = HistoryArray.new(100) end # Refresh the Pry instance settings from the Pry class. @@ -53,6 +50,10 @@ class Pry send "#{key}=", value end + size = options[:memory_size] || Pry.memory_size + @input_array = Pry::HistoryArray.new(size) + @output_array = Pry::HistoryArray.new(size) + true end @@ -120,6 +121,7 @@ class Pry target.eval("_out_ = ::Pry.active_instance.instance_eval { @output_array }") set_active_instance(target) + @input_array << nil # add empty input so _in_ and _out_ match set_last_result(Pry.last_result, target) self.session_target = target From ee0186692895028603f582ab89d5d546a86ba4a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mon=20ou=C3=AFe?= Date: Mon, 6 Jun 2011 17:14:16 +0200 Subject: [PATCH 6/7] Added Pry#memory_size= to set the size of _in_ and _out_ --- lib/pry/pry_instance.rb | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/pry/pry_instance.rb b/lib/pry/pry_instance.rb index c77e18ab..d69a8bd6 100644 --- a/lib/pry/pry_instance.rb +++ b/lib/pry/pry_instance.rb @@ -39,7 +39,7 @@ class Pry attributes = [ :input, :output, :commands, :print, :exception_handler, :hooks, :custom_completions, - :prompt + :prompt, :memory_size ] attributes.each do |attribute| @@ -50,10 +50,6 @@ class Pry send "#{key}=", value end - size = options[:memory_size] || Pry.memory_size - @input_array = Pry::HistoryArray.new(size) - @output_array = Pry::HistoryArray.new(size) - true end @@ -77,6 +73,17 @@ class Pry end end + # @return [Integer] The maximum amount of objects remembered by the _in_ and + # _out_ arrays. Defaults to 100. + def memory_size + @output_array.max_size + end + + def memory_size=(size) + @input_array = Pry::HistoryArray.new(size) + @output_array = Pry::HistoryArray.new(size) + end + # Get nesting data. # This method should not need to be accessed directly. # @return [Array] The unparsed nesting information. From 7ade5da980b635c7cff589af58d4b8ad1246c5ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mon=20ou=C3=AFe?= Date: Mon, 6 Jun 2011 17:14:29 +0200 Subject: [PATCH 7/7] Added tests for _in_ and _out_ --- test/test_pry.rb | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/test_pry.rb b/test/test_pry.rb index 5c102cfa..b3d4a6a2 100644 --- a/test/test_pry.rb +++ b/test/test_pry.rb @@ -134,6 +134,56 @@ describe Pry do end end + describe "history arrays" do + it 'sets _ to the last result' do + res = [] + input = InputTester.new *[":foo", "self << _", "42", "self << _"] + pry = Pry.new(:input => input, :output => Pry::NullOutput) + pry.repl(res) + + res.should == [:foo, 42] + end + + it 'sets _out_ to an array with the result' do + res = {} + input = InputTester.new *[":foo", "42", "self[:res] = _out_"] + pry = Pry.new(:input => input, :output => Pry::NullOutput) + pry.repl(res) + + res[:res].should.be.kind_of Pry::HistoryArray + res[:res][1..2].should == [:foo, 42] + end + + it 'sets _in_ to an array with the entered lines' do + res = {} + input = InputTester.new *[":foo", "42", "self[:res] = _in_"] + pry = Pry.new(:input => input, :output => Pry::NullOutput) + pry.repl(res) + + res[:res].should.be.kind_of Pry::HistoryArray + res[:res][1..2].should == [":foo\n", "42\n"] + end + + it 'uses 100 as the size of _in_ and _out_' do + res = [] + input = InputTester.new *["self << _out_.max_size << _in_.max_size"] + pry = Pry.new(:input => input, :output => Pry::NullOutput) + pry.repl(res) + + res.should == [100, 100] + end + + it 'can change the size of the history arrays' do + res = [] + input = InputTester.new *["self << _out_.max_size << _in_.max_size"] + pry = Pry.new(:input => input, :output => Pry::NullOutput, + :memory_size => 1000) + pry.repl(res) + + res.should == [1000, 1000] + end + end + describe "test loading rc files" do before do