Bug #17623


irb starts with some local variables already defined

Added by UlyssesZhan (有丘 詹) 2 months ago. Updated 28 days ago.

Target version:
ruby -v:
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x64-mingw32]


irb(main):001:0> a = 1
=> 1
irb(main):002:0> def f = a
=> :f
irb(main):003:0> f
=> "D:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/irb-1.3.0/exe/irb"

I have not idea what it means.
The codes just work fine outside irb.
Maybe it is a bug.

Updated by mame (Yusuke Endoh) 2 months ago

I cannot reproduce the issue.

$ ruby -v
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux]

$ irb
irb(main):001:0* a = 1
=> 1
irb(main):002:1* def f = a
=> :f
irb(main):003:0> f
Traceback (most recent call last):
        5: from /home/mame/local/bin/irb:23:in `<main>'
        4: from /home/mame/local/bin/irb:23:in `load'
        3: from /home/mame/local/lib/ruby/gems/3.0.0/gems/irb-1.3.0/exe/irb:11:in `<top (required)>'
        2: from (irb):3:in `<main>'
        1: from (irb):2:in `f'
NameError (undefined local variable or method `a' for main:Object)

$ ruby
a = 1
def f = a
-:2:in `f': undefined local variable or method `a' for main:Object (NameError)
        from -:3:in `<main>'

Does your .irbrc have something?

Updated by xtkoba (Tee KOBAYASHI) 2 months ago

It reproduces with Ruby 3.0.0-1 (x64) from RubyInstaller, and it seems that f has already been defined when the first prompt (irb(main):001:0>) appears.

It does not reproduce with my own x64-mingw32 build.

Updated by xtkoba (Tee KOBAYASHI) 2 months ago

I found that f is indeed defined in RubyInstaller's irb.cmd:

--- original/irb.cmd
+++ RubyInstaller/irb.cmd
@@ -28,7 +28,7 @@

 if Gem.respond_to?(:activate_bin_path)
-load Gem.activate_bin_path('irb', 'irb', version)
+f = Gem.activate_bin_path('irb', 'irb', version); require 'irbrc_predefiner'; load f
 gem "irb", version
 load Gem.bin_path("irb", "irb", version)

The same goes for str or version with every environment:

irb(main):001:0> str
=> nil
irb(main):002:0> version
=> ">= 0.a"

I have no idea whether it is a bug or not that the local variables defind in irb command are visible from IRB.

Actions #5

Updated by jeremyevans0 (Jeremy Evans) about 2 months ago

  • Assignee set to marcandre (Marc-Andre Lafortune)
  • Status changed from Open to Assigned

Eregon (Benoit Daloze) is correct. This issue first started in Ruby 3.0. It does not occur when the irb --context-mode is 1, 2, or 3 (Ruby 2.7 default), but it does occur when --context-mode is 4 (Ruby 3.0 default) or 0. Between Ruby 2.7 and 3.0, the default irb --context-mode switched from 3 to 4 to fix #9580.

It seems undesirable to me that irb would have local variables predefined other than _. While the f local variable is RubyInstaller specific, the str and version local variables are not. So I think this should be considered a bug.

Assigning to marcandre (Marc-Andre Lafortune), since he made the --context-mode change in irb. One possible solution is to accept the new irb behavior, and modify the binstubs to not expose or create local variables. An easy way to do that:

proc do
  # previous binstub code

The problem with that approach is it adds a stack frame. An alternative approach that doesn't add a stack frame is to switch to a much uglier approach using instance variables (which can be removed, unlike local variables):

require 'rubygems'

@version = ">= 0.a"

@str = ARGV.first
if @str
  @str = @str.b[/\A_(.*)_\z/, 1]
  if @str and Gem::Version.correct?(@str)
    @version = @str

if Gem.respond_to?(:activate_bin_path)
load Gem.activate_bin_path('irb', 'irb', @version.tap{remove_instance_variable(:@version)})
gem "irb", @version
load Gem.bin_path("irb", "irb", @version.tap{remove_instance_variable(:@version)})

Updated by marcandre (Marc-Andre Lafortune) 28 days ago

  • Subject changed from endless def can access to outer local variables and lead to unexpected result to irb starts with some local variables already defined

I think this is a nice solution:


Also available in: Atom PDF