зеркало из https://github.com/github/ruby.git
[ruby/irb] Fix nested IRB sessions' history saving
(https://github.com/ruby/irb/pull/652) 1. Dynamically including `HistorySavingAbility` makes things unnecessarily complicated and should be avoided. 2. Because both `Reline` and `Readline` use a single `HISTORY` constant to store history data. When nesting IRB sessions, only the first IRB session should handle history loading and saving so we can avoid duplicating history. 3. History saving callback should NOT be stored in `IRB.conf` as it's recreated every time `IRB.setup` is called, which would happen when nesting IRB sessions. https://github.com/ruby/irb/commit/0fef0ae160
This commit is contained in:
Родитель
6acfc50bcc
Коммит
ab0f90f1f5
|
@ -482,9 +482,16 @@ module IRB
|
|||
end
|
||||
|
||||
def run(conf = IRB.conf)
|
||||
in_nested_session = !!conf[:MAIN_CONTEXT]
|
||||
conf[:IRB_RC].call(context) if conf[:IRB_RC]
|
||||
conf[:MAIN_CONTEXT] = context
|
||||
|
||||
save_history = !in_nested_session && conf[:SAVE_HISTORY] && context.io.support_history_saving?
|
||||
|
||||
if save_history
|
||||
context.io.load_history
|
||||
end
|
||||
|
||||
prev_trap = trap("SIGINT") do
|
||||
signal_handle
|
||||
end
|
||||
|
@ -496,6 +503,7 @@ module IRB
|
|||
ensure
|
||||
trap("SIGINT", prev_trap)
|
||||
conf[:AT_EXIT].each{|hook| hook.call}
|
||||
context.io.save_history if save_history
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ require_relative "workspace"
|
|||
require_relative "inspector"
|
||||
require_relative "input-method"
|
||||
require_relative "output-method"
|
||||
require_relative "history"
|
||||
|
||||
module IRB
|
||||
# A class that wraps the current state of the irb session, including the
|
||||
|
@ -130,8 +129,6 @@ module IRB
|
|||
else
|
||||
@io = input_method
|
||||
end
|
||||
self.save_history = IRB.conf[:SAVE_HISTORY] if IRB.conf[:SAVE_HISTORY]
|
||||
|
||||
@extra_doc_dirs = IRB.conf[:EXTRA_DOC_DIRS]
|
||||
|
||||
@echo = IRB.conf[:ECHO]
|
||||
|
@ -154,13 +151,6 @@ module IRB
|
|||
|
||||
def save_history=(val)
|
||||
IRB.conf[:SAVE_HISTORY] = val
|
||||
|
||||
if val
|
||||
context = (IRB.conf[:MAIN_CONTEXT] || self)
|
||||
if context.io.support_history_saving? && !context.io.singleton_class.include?(HistorySavingAbility)
|
||||
context.io.extend(HistorySavingAbility)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def save_history
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
module IRB
|
||||
module HistorySavingAbility # :nodoc:
|
||||
def HistorySavingAbility.extended(obj)
|
||||
IRB.conf[:AT_EXIT].push proc{obj.save_history}
|
||||
obj.load_history
|
||||
obj
|
||||
def support_history_saving?
|
||||
true
|
||||
end
|
||||
|
||||
def load_history
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#
|
||||
|
||||
require_relative 'completion'
|
||||
require_relative "history"
|
||||
require 'io/console'
|
||||
require 'reline'
|
||||
|
||||
|
@ -167,6 +168,8 @@ module IRB
|
|||
include ::Readline
|
||||
end
|
||||
|
||||
include HistorySavingAbility
|
||||
|
||||
# Creates a new input method object using Readline
|
||||
def initialize
|
||||
self.class.initialize_readline
|
||||
|
@ -219,10 +222,6 @@ module IRB
|
|||
true
|
||||
end
|
||||
|
||||
def support_history_saving?
|
||||
true
|
||||
end
|
||||
|
||||
# Returns the current line number for #io.
|
||||
#
|
||||
# #line counts the number of times #gets is called.
|
||||
|
@ -250,6 +249,7 @@ module IRB
|
|||
|
||||
class RelineInputMethod < InputMethod
|
||||
HISTORY = Reline::HISTORY
|
||||
include HistorySavingAbility
|
||||
# Creates a new input method object using Reline
|
||||
def initialize
|
||||
IRB.__send__(:set_encoding, Reline.encoding_system_needs.name, override: false)
|
||||
|
@ -451,10 +451,6 @@ module IRB
|
|||
str += " and #{inputrc_path}" if File.exist?(inputrc_path)
|
||||
str
|
||||
end
|
||||
|
||||
def support_history_saving?
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
class ReidlineInputMethod < RelineInputMethod
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
# frozen_string_literal: false
|
||||
require 'irb'
|
||||
require 'readline'
|
||||
require "tempfile"
|
||||
|
||||
require_relative "helper"
|
||||
|
||||
return if RUBY_PLATFORM.match?(/solaris|mswin|mingw/i)
|
||||
|
||||
module TestIRB
|
||||
class HistoryTest < TestCase
|
||||
def setup
|
||||
|
@ -205,4 +208,87 @@ module TestIRB
|
|||
end
|
||||
end
|
||||
end
|
||||
end if not RUBY_PLATFORM.match?(/solaris|mswin|mingw/i)
|
||||
|
||||
class NestedIRBHistoryTest < IntegrationTestCase
|
||||
def test_history_saving_with_nested_sessions
|
||||
write_history ""
|
||||
|
||||
write_ruby <<~'RUBY'
|
||||
def foo
|
||||
binding.irb
|
||||
end
|
||||
|
||||
binding.irb
|
||||
RUBY
|
||||
|
||||
run_ruby_file do
|
||||
type "'outer session'"
|
||||
type "foo"
|
||||
type "'inner session'"
|
||||
type "exit"
|
||||
type "'outer session again'"
|
||||
type "exit"
|
||||
end
|
||||
|
||||
assert_equal <<~HISTORY, @history_file.open.read
|
||||
'outer session'
|
||||
foo
|
||||
'inner session'
|
||||
exit
|
||||
'outer session again'
|
||||
exit
|
||||
HISTORY
|
||||
end
|
||||
|
||||
def test_history_saving_with_nested_sessions_and_prior_history
|
||||
write_history <<~HISTORY
|
||||
old_history_1
|
||||
old_history_2
|
||||
old_history_3
|
||||
HISTORY
|
||||
|
||||
write_ruby <<~'RUBY'
|
||||
def foo
|
||||
binding.irb
|
||||
end
|
||||
|
||||
binding.irb
|
||||
RUBY
|
||||
|
||||
run_ruby_file do
|
||||
type "'outer session'"
|
||||
type "foo"
|
||||
type "'inner session'"
|
||||
type "exit"
|
||||
type "'outer session again'"
|
||||
type "exit"
|
||||
end
|
||||
|
||||
assert_equal <<~HISTORY, @history_file.open.read
|
||||
old_history_1
|
||||
old_history_2
|
||||
old_history_3
|
||||
'outer session'
|
||||
foo
|
||||
'inner session'
|
||||
exit
|
||||
'outer session again'
|
||||
exit
|
||||
HISTORY
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def write_history(history)
|
||||
@history_file = Tempfile.new('irb_history')
|
||||
@history_file.write(history)
|
||||
@history_file.close
|
||||
@irbrc = Tempfile.new('irbrc')
|
||||
@irbrc.write <<~RUBY
|
||||
IRB.conf[:HISTORY_FILE] = "#{@history_file.path}"
|
||||
RUBY
|
||||
@irbrc.close
|
||||
@envs['IRBRC'] = @irbrc.path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Загрузка…
Ссылка в новой задаче