Skip to content

Commit bc92379

Browse files
tompngmatzbot
authored andcommitted
[ruby/irb] Don't use delegator to install helper methods to main
object (ruby/irb#1031) IRB used delegator to install command as a method of frozen main object. Command is not a method now. We can drop it. ruby/irb@2f1c593801
1 parent edf5a73 commit bc92379

File tree

6 files changed

+42
-30
lines changed

6 files changed

+42
-30
lines changed

lib/irb.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,16 +1463,21 @@ def truncate_prompt_main(str) # :nodoc:
14631463
end
14641464
end
14651465

1466+
def basic_object_safe_main_call(method)
1467+
main = @context.main
1468+
Object === main ? main.__send__(method) : Object.instance_method(method).bind_call(main)
1469+
end
1470+
14661471
def format_prompt(format, ltype, indent, line_no) # :nodoc:
14671472
format.gsub(/%([0-9]+)?([a-zA-Z%])/) do
14681473
case $2
14691474
when "N"
14701475
@context.irb_name
14711476
when "m"
1472-
main_str = @context.main.to_s rescue "!#{$!.class}"
1477+
main_str = basic_object_safe_main_call(:to_s) rescue "!#{$!.class}"
14731478
truncate_prompt_main(main_str)
14741479
when "M"
1475-
main_str = @context.main.inspect rescue "!#{$!.class}"
1480+
main_str = basic_object_safe_main_call(:inspect) rescue "!#{$!.class}"
14761481
truncate_prompt_main(main_str)
14771482
when "l"
14781483
ltype

lib/irb/command/internal_helpers.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def ruby_args(arg)
1919
# Use throw and catch to handle arg that includes `;`
2020
# For example: "1, kw: (2; 3); 4" will be parsed to [[1], { kw: 3 }]
2121
catch(:EXTRACT_RUBY_ARGS) do
22-
@irb_context.workspace.binding.eval "IRB::Command.extract_ruby_args #{arg}"
22+
@irb_context.workspace.binding.eval "::IRB::Command.extract_ruby_args #{arg}"
2323
end || [[], {}]
2424
end
2525
end

lib/irb/completion.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ def eval_global_variables
156156
end
157157

158158
def eval_class_constants
159-
::Module.instance_method(:constants).bind(eval("self.class")).call
159+
klass = ::Object.instance_method(:class).bind_call(receiver)
160+
::Module.instance_method(:constants).bind_call(klass)
160161
end
161162
end
162163
}

lib/irb/workspace.rb

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
# by Keiju ISHITSUKA([email protected])
55
#
66

7-
require "delegate"
8-
97
require_relative "helper_method"
108

119
IRB::TOPLEVEL_BINDING = binding
@@ -16,7 +14,7 @@ class WorkSpace
1614
# set self to main if specified, otherwise
1715
# inherit main from TOPLEVEL_BINDING.
1816
def initialize(*main)
19-
if main[0].kind_of?(Binding)
17+
if Binding === main[0]
2018
@binding = main.shift
2119
elsif IRB.conf[:SINGLE_IRB]
2220
@binding = TOPLEVEL_BINDING
@@ -70,37 +68,16 @@ def initialize(*main)
7068
unless main.empty?
7169
case @main
7270
when Module
73-
@binding = eval("IRB.conf[:__MAIN__].module_eval('binding', __FILE__, __LINE__)", @binding, __FILE__, __LINE__)
71+
@binding = eval("::IRB.conf[:__MAIN__].module_eval('::Kernel.binding', __FILE__, __LINE__)", @binding, __FILE__, __LINE__)
7472
else
7573
begin
76-
@binding = eval("IRB.conf[:__MAIN__].instance_eval('binding', __FILE__, __LINE__)", @binding, __FILE__, __LINE__)
74+
@binding = eval("::IRB.conf[:__MAIN__].instance_eval('::Kernel.binding', __FILE__, __LINE__)", @binding, __FILE__, __LINE__)
7775
rescue TypeError
7876
fail CantChangeBinding, @main.inspect
7977
end
8078
end
8179
end
8280

83-
case @main
84-
when Object
85-
use_delegator = @main.frozen?
86-
else
87-
use_delegator = true
88-
end
89-
90-
if use_delegator
91-
@main = SimpleDelegator.new(@main)
92-
IRB.conf[:__MAIN__] = @main
93-
@main.singleton_class.class_eval do
94-
private
95-
define_method(:binding, Kernel.instance_method(:binding))
96-
define_method(:local_variables, Kernel.instance_method(:local_variables))
97-
# Define empty method to avoid delegator warning, will be overridden.
98-
define_method(:exit) {|*a, &b| }
99-
define_method(:exit!) {|*a, &b| }
100-
end
101-
@binding = eval("IRB.conf[:__MAIN__].instance_eval('binding', __FILE__, __LINE__)", @binding, *@binding.source_location)
102-
end
103-
10481
@binding.local_variable_set(:_, nil)
10582
end
10683

@@ -111,6 +88,9 @@ def initialize(*main)
11188
attr_reader :main
11289

11390
def load_helper_methods_to_main
91+
# Do not load helper methods to frozen objects and BasicObject
92+
return unless Object === @main && !@main.frozen?
93+
11494
ancestors = class<<main;ancestors;end
11595
main.extend ExtendCommandBundle if !ancestors.include?(ExtendCommandBundle)
11696
main.extend HelpersContainer if !ancestors.include?(HelpersContainer)

test/irb/command/test_cd.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ def foo
1919
end
2020
end
2121
22+
class BO < BasicObject
23+
def baz
24+
"this is baz"
25+
end
26+
end
27+
2228
binding.irb
2329
RUBY
2430
end
@@ -40,6 +46,19 @@ def test_cd
4046
assert_match(/irb\(Foo\):006>/, out)
4147
end
4248

49+
def test_cd_basic_object_or_frozen
50+
out = run_ruby_file do
51+
type "cd BO.new"
52+
type "cd 1"
53+
type "cd Object.new.freeze"
54+
type "exit"
55+
end
56+
57+
assert_match(/irb\(#<BO:.+\):002>/, out)
58+
assert_match(/irb\(1\):003>/, out)
59+
assert_match(/irb\(#<Object:.+\):004>/, out)
60+
end
61+
4362
def test_cd_moves_top_level_with_no_args
4463
out = run_ruby_file do
4564
type "cd Foo"

test/irb/test_context.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,13 @@ def main.inspect; to_s.inspect; end
652652
assert_equal('irb("aaaaaaaaaaaaaaaaaaaaaaaaaaaa...)>', irb.send(:format_prompt, 'irb(%M)>', nil, 1, 1))
653653
end
654654

655+
def test_prompt_main_basic_object
656+
main = BasicObject.new
657+
irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new)
658+
assert_match(/irb\(#<BasicObject:.+\)/, irb.send(:format_prompt, 'irb(%m)>', nil, 1, 1))
659+
assert_match(/irb\(#<BasicObject:.+\)/, irb.send(:format_prompt, 'irb(%M)>', nil, 1, 1))
660+
end
661+
655662
def test_prompt_main_raise
656663
main = Object.new
657664
def main.to_s; raise TypeError; end

0 commit comments

Comments
 (0)