зеркало из https://github.com/github/ruby.git
[ruby/irb] Restructure workspace management
(https://github.com/ruby/irb/pull/888) * Remove dead irb_level method * Restructure workspace management Currently, workspace is an attribute of IRB::Context in most use cases. But when some workspace commands are used, like `pushws` or `popws`, a workspace will be created and used along side with the original workspace attribute. This complexity is not necessary and will prevent us from expanding multi-workspace support in the future. So this commit introduces a @workspace_stack ivar to IRB::Context so IRB can have a more natural way to manage workspaces. * Fix pushws without args * Always display workspace stack after related commands are used https://github.com/ruby/irb/commit/61560b99b3
This commit is contained in:
Родитель
162e13c884
Коммит
57ca5960ad
15
lib/irb.rb
15
lib/irb.rb
|
@ -933,7 +933,7 @@ module IRB
|
|||
|
||||
def debug_readline(binding)
|
||||
workspace = IRB::WorkSpace.new(binding)
|
||||
context.workspace = workspace
|
||||
context.replace_workspace(workspace)
|
||||
context.workspace.load_commands_to_main
|
||||
@line_no += 1
|
||||
|
||||
|
@ -1269,12 +1269,11 @@ module IRB
|
|||
# Used by the irb command +irb_load+, see IRB@IRB+Sessions for more
|
||||
# information.
|
||||
def suspend_workspace(workspace)
|
||||
@context.workspace, back_workspace = workspace, @context.workspace
|
||||
begin
|
||||
yield back_workspace
|
||||
ensure
|
||||
@context.workspace = back_workspace
|
||||
end
|
||||
current_workspace = @context.workspace
|
||||
@context.replace_workspace(workspace)
|
||||
yield
|
||||
ensure
|
||||
@context.replace_workspace current_workspace
|
||||
end
|
||||
|
||||
# Evaluates the given block using the given +input_method+ as the
|
||||
|
@ -1534,7 +1533,7 @@ class Binding
|
|||
|
||||
if debugger_irb
|
||||
# If we're already in a debugger session, set the workspace and irb_path for the original IRB instance
|
||||
debugger_irb.context.workspace = workspace
|
||||
debugger_irb.context.replace_workspace(workspace)
|
||||
debugger_irb.context.irb_path = irb_path
|
||||
# If we've started a debugger session and hit another binding.irb, we don't want to start an IRB session
|
||||
# instead, we want to resume the irb:rdbg session.
|
||||
|
|
|
@ -15,7 +15,23 @@ module IRB
|
|||
description "Show workspaces."
|
||||
|
||||
def execute(*obj)
|
||||
irb_context.workspaces.collect{|ws| ws.main}
|
||||
inspection_resuls = irb_context.instance_variable_get(:@workspace_stack).map do |ws|
|
||||
truncated_inspect(ws.main)
|
||||
end
|
||||
|
||||
puts "[" + inspection_resuls.join(", ") + "]"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def truncated_inspect(obj)
|
||||
obj_inspection = obj.inspect
|
||||
|
||||
if obj_inspection.size > 20
|
||||
obj_inspection = obj_inspection[0, 19] + "...>"
|
||||
end
|
||||
|
||||
obj_inspection
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -22,10 +22,11 @@ module IRB
|
|||
# +other+:: uses this as InputMethod
|
||||
def initialize(irb, workspace = nil, input_method = nil)
|
||||
@irb = irb
|
||||
@workspace_stack = []
|
||||
if workspace
|
||||
@workspace = workspace
|
||||
@workspace_stack << workspace
|
||||
else
|
||||
@workspace = WorkSpace.new
|
||||
@workspace_stack << WorkSpace.new
|
||||
end
|
||||
@thread = Thread.current
|
||||
|
||||
|
@ -229,15 +230,24 @@ module IRB
|
|||
IRB.conf[:HISTORY_FILE] = hist
|
||||
end
|
||||
|
||||
# Workspace in the current context.
|
||||
def workspace
|
||||
@workspace_stack.last
|
||||
end
|
||||
|
||||
# Replace the current workspace with the given +workspace+.
|
||||
def replace_workspace(workspace)
|
||||
@workspace_stack.pop
|
||||
@workspace_stack.push(workspace)
|
||||
end
|
||||
|
||||
# The top-level workspace, see WorkSpace#main
|
||||
def main
|
||||
@workspace.main
|
||||
workspace.main
|
||||
end
|
||||
|
||||
# The toplevel workspace, see #home_workspace
|
||||
attr_reader :workspace_home
|
||||
# WorkSpace in the current context.
|
||||
attr_accessor :workspace
|
||||
# The current thread in this context.
|
||||
attr_reader :thread
|
||||
# The current input method.
|
||||
|
@ -489,7 +499,7 @@ module IRB
|
|||
# to #last_value.
|
||||
def set_last_value(value)
|
||||
@last_value = value
|
||||
@workspace.local_variable_set :_, value
|
||||
workspace.local_variable_set :_, value
|
||||
end
|
||||
|
||||
# Sets the +mode+ of the prompt in this context.
|
||||
|
@ -585,7 +595,7 @@ module IRB
|
|||
|
||||
if IRB.conf[:MEASURE] && !IRB.conf[:MEASURE_CALLBACKS].empty?
|
||||
last_proc = proc do
|
||||
result = @workspace.evaluate(line, @eval_path, line_no)
|
||||
result = workspace.evaluate(line, @eval_path, line_no)
|
||||
end
|
||||
IRB.conf[:MEASURE_CALLBACKS].inject(last_proc) do |chain, item|
|
||||
_name, callback, arg = item
|
||||
|
@ -596,7 +606,7 @@ module IRB
|
|||
end
|
||||
end.call
|
||||
else
|
||||
result = @workspace.evaluate(line, @eval_path, line_no)
|
||||
result = workspace.evaluate(line, @eval_path, line_no)
|
||||
end
|
||||
|
||||
set_last_value(result)
|
||||
|
|
|
@ -12,7 +12,7 @@ module IRB # :nodoc:
|
|||
if defined? @home_workspace
|
||||
@home_workspace
|
||||
else
|
||||
@home_workspace = @workspace
|
||||
@home_workspace = workspace
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -25,11 +25,11 @@ module IRB # :nodoc:
|
|||
# See IRB::WorkSpace.new for more information.
|
||||
def change_workspace(*_main)
|
||||
if _main.empty?
|
||||
@workspace = home_workspace
|
||||
replace_workspace(home_workspace)
|
||||
return main
|
||||
end
|
||||
|
||||
@workspace = WorkSpace.new(_main[0])
|
||||
replace_workspace(WorkSpace.new(_main[0]))
|
||||
|
||||
if !(class<<main;ancestors;end).include?(ExtendCommandBundle)
|
||||
main.extend ExtendCommandBundle
|
||||
|
|
|
@ -18,7 +18,7 @@ module IRB # :nodoc:
|
|||
|
||||
if defined?(@eval_history) && @eval_history
|
||||
@eval_history_values.push @line_no, @last_value
|
||||
@workspace.evaluate "__ = IRB.CurrentContext.instance_eval{@eval_history_values}"
|
||||
workspace.evaluate "__ = IRB.CurrentContext.instance_eval{@eval_history_values}"
|
||||
end
|
||||
|
||||
@last_value
|
||||
|
@ -49,7 +49,7 @@ module IRB # :nodoc:
|
|||
else
|
||||
@eval_history_values = EvalHistory.new(no)
|
||||
IRB.conf[:__TMP__EHV__] = @eval_history_values
|
||||
@workspace.evaluate("__ = IRB.conf[:__TMP__EHV__]")
|
||||
workspace.evaluate("__ = IRB.conf[:__TMP__EHV__]")
|
||||
IRB.conf.delete(:__TMP_EHV__)
|
||||
end
|
||||
else
|
||||
|
|
|
@ -49,12 +49,12 @@ module IRB
|
|||
if IRB.conf[:USE_LOADER] != opt
|
||||
IRB.conf[:USE_LOADER] = opt
|
||||
if opt
|
||||
(class<<@workspace.main;self;end).instance_eval {
|
||||
(class<<workspace.main;self;end).instance_eval {
|
||||
alias_method :load, :irb_load
|
||||
alias_method :require, :irb_require
|
||||
}
|
||||
else
|
||||
(class<<@workspace.main;self;end).instance_eval {
|
||||
(class<<workspace.main;self;end).instance_eval {
|
||||
alias_method :load, :__original__load__IRB_use_loader__
|
||||
alias_method :require, :__original__require__IRB_use_loader__
|
||||
}
|
||||
|
|
|
@ -6,21 +6,6 @@
|
|||
|
||||
module IRB # :nodoc:
|
||||
class Context
|
||||
|
||||
# Size of the current WorkSpace stack
|
||||
def irb_level
|
||||
workspace_stack.size
|
||||
end
|
||||
|
||||
# WorkSpaces in the current stack
|
||||
def workspaces
|
||||
if defined? @workspaces
|
||||
@workspaces
|
||||
else
|
||||
@workspaces = []
|
||||
end
|
||||
end
|
||||
|
||||
# Creates a new workspace with the given object or binding, and appends it
|
||||
# onto the current #workspaces stack.
|
||||
#
|
||||
|
@ -28,20 +13,16 @@ module IRB # :nodoc:
|
|||
# information.
|
||||
def push_workspace(*_main)
|
||||
if _main.empty?
|
||||
if workspaces.empty?
|
||||
print "No other workspace\n"
|
||||
return nil
|
||||
if @workspace_stack.size > 1
|
||||
# swap the top two workspaces
|
||||
previous_workspace, current_workspace = @workspace_stack.pop(2)
|
||||
@workspace_stack.push current_workspace, previous_workspace
|
||||
end
|
||||
else
|
||||
@workspace_stack.push WorkSpace.new(workspace.binding, _main[0])
|
||||
if !(class<<main;ancestors;end).include?(ExtendCommandBundle)
|
||||
main.extend ExtendCommandBundle
|
||||
end
|
||||
ws = workspaces.pop
|
||||
workspaces.push @workspace
|
||||
@workspace = ws
|
||||
return workspaces
|
||||
end
|
||||
|
||||
workspaces.push @workspace
|
||||
@workspace = WorkSpace.new(@workspace.binding, _main[0])
|
||||
if !(class<<main;ancestors;end).include?(ExtendCommandBundle)
|
||||
main.extend ExtendCommandBundle
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -50,11 +31,7 @@ module IRB # :nodoc:
|
|||
#
|
||||
# Also, see #push_workspace.
|
||||
def pop_workspace
|
||||
if workspaces.empty?
|
||||
print "workspace stack empty\n"
|
||||
return
|
||||
end
|
||||
@workspace = workspaces.pop
|
||||
@workspace_stack.pop if @workspace_stack.size > 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -482,7 +482,8 @@ module TestIRB
|
|||
class CwwsTest < WorkspaceCommandTestCase
|
||||
def test_cwws_returns_the_current_workspace_object
|
||||
out, err = execute_lines(
|
||||
"cwws.class",
|
||||
"cwws",
|
||||
"self.class"
|
||||
)
|
||||
|
||||
assert_empty err
|
||||
|
@ -493,51 +494,56 @@ module TestIRB
|
|||
class PushwsTest < WorkspaceCommandTestCase
|
||||
def test_pushws_switches_to_new_workspace_and_pushes_the_current_one_to_the_stack
|
||||
out, err = execute_lines(
|
||||
"pushws #{self.class}::Foo.new\n",
|
||||
"cwws.class",
|
||||
"pushws #{self.class}::Foo.new",
|
||||
"self.class",
|
||||
"popws",
|
||||
"self.class"
|
||||
)
|
||||
assert_empty err
|
||||
assert_include(out, "#{self.class}::Foo")
|
||||
|
||||
assert_match(/=> #{self.class}::Foo\n/, out)
|
||||
assert_match(/=> #{self.class}\n$/, out)
|
||||
end
|
||||
|
||||
def test_pushws_extends_the_new_workspace_with_command_bundle
|
||||
out, err = execute_lines(
|
||||
"pushws Object.new\n",
|
||||
"pushws Object.new",
|
||||
"self.singleton_class.ancestors"
|
||||
)
|
||||
assert_empty err
|
||||
assert_include(out, "IRB::ExtendCommandBundle")
|
||||
end
|
||||
|
||||
def test_pushws_prints_help_message_when_no_arg_is_given
|
||||
def test_pushws_prints_workspace_stack_when_no_arg_is_given
|
||||
out, err = execute_lines(
|
||||
"pushws\n",
|
||||
"pushws",
|
||||
)
|
||||
assert_empty err
|
||||
assert_match(/No other workspace/, out)
|
||||
assert_include(out, "[#<TestIRB::PushwsTe...>]")
|
||||
end
|
||||
|
||||
def test_pushws_without_argument_swaps_the_top_two_workspaces
|
||||
out, err = execute_lines(
|
||||
"pushws #{self.class}::Foo.new",
|
||||
"self.class",
|
||||
"pushws",
|
||||
"self.class"
|
||||
)
|
||||
assert_empty err
|
||||
assert_match(/=> #{self.class}::Foo\n/, out)
|
||||
assert_match(/=> #{self.class}\n$/, out)
|
||||
end
|
||||
end
|
||||
|
||||
class WorkspacesTest < WorkspaceCommandTestCase
|
||||
def test_workspaces_returns_the_array_of_non_main_workspaces
|
||||
def test_workspaces_returns_the_stack_of_workspaces
|
||||
out, err = execute_lines(
|
||||
"pushws #{self.class}::Foo.new\n",
|
||||
"workspaces.map { |w| w.class.name }",
|
||||
"workspaces",
|
||||
)
|
||||
|
||||
assert_empty err
|
||||
# self.class::Foo would be the current workspace
|
||||
# self.class would be the old workspace that's pushed to the stack
|
||||
assert_include(out, "=> [\"#{self.class}\"]")
|
||||
end
|
||||
|
||||
def test_workspaces_returns_empty_array_when_no_workspaces_were_added
|
||||
out, err = execute_lines(
|
||||
"workspaces.map(&:to_s)",
|
||||
)
|
||||
|
||||
assert_empty err
|
||||
assert_include(out, "=> []")
|
||||
assert_match(/\[#<TestIRB::Workspac...>, #<TestIRB::Workspac...>]\n/, out)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -557,7 +563,7 @@ module TestIRB
|
|||
"popws\n",
|
||||
)
|
||||
assert_empty err
|
||||
assert_match(/workspace stack empty/, out)
|
||||
assert_match(/\[#<TestIRB::PopwsTes...>\]\n/, out)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче