diff --git a/Docs/releases/v4.0.3.md b/Docs/releases/v4.0.3.md
index 73c1f2088..e441f778d 100644
--- a/Docs/releases/v4.0.3.md
+++ b/Docs/releases/v4.0.3.md
@@ -31,6 +31,23 @@ gh attestation verify ironruby-4.0.3-win-x64-setup.exe --repo Largo/ironruby
Setup 6.7.3 from `Util/installer/ironruby.iss`, and installed, run and uninstalled there
before it is published.
+### Changed
+
+- **`ironruby` at a terminal starts irb**, as `python` starts its interactive interpreter:
+ with no script and no `-e`, and stdin a terminal, `ironruby` is `iirb`. From a pipe or a
+ file it still reads the program from stdin, as `ruby` does, and so do `ironruby -`,
+ `-n`, `-p`, `-c` and `-x`.
+- **IronRuby no longer uses a CRuby's gems.** It used to offer the gem directory of a CRuby
+ 4.0 found on the PATH for third-party gems. That loaded CRuby's code into IronRuby: with
+ CRuby on the PATH, `igem install` loaded CRuby's rdoc plugin over the rdoc IronRuby ships
+ ("already initialized constant RDoc::VERSION") and then failed generating the gem's
+ documentation. IronRuby now reads only its own gem directories; a gem it needs is
+ installed for it, with `igem install` or Bundler. `IRONRUBY_NO_HOST_GEMS` is gone with it.
+- **`igem install` builds no documentation unless asked**, as on TruffleRuby: generating ri
+ and rdoc takes longer than installing most gems. `igem install --document` (or
+ `gem: --document` in `~/.gemrc`) builds it with the rdoc IronRuby ships, and uninstalling
+ the gem removes it again.
+
### Fixes
- **irb starts on Windows again.** In 4.0.2 it stopped at once with `unknown symbol
@@ -40,3 +57,10 @@ gh attestation verify ironruby-4.0.3-win-x64-setup.exe --repo Largo/ironruby
IronRuby that was an index, not an address. It is a real address now, of a block holding
the String's bytes, and what C writes there through Fiddle comes back into the String, as
with CRuby - so reline runs as Ruby ships it.
+- **irb shows results on Windows.** After the first result it stopped with
+ `Errno::ENOTTY` from `IO#winsize`: IronRuby's io/console asked only termios for the
+ terminal size, which Windows does not have. It now asks the console, as CRuby does, and
+ raises `Errno::EBADF` off a console, as CRuby does on Windows.
+- **`require 'ripper'` gives `Ripper::Filter`**, as in CRuby. rdoc's Ruby parser subclasses
+ it, and generating a gem's documentation failed with `uninitialized constant
+ Ripper::Filter`.
diff --git a/README.md b/README.md
index a48bf4bff..295f614a1 100644
--- a/README.md
+++ b/README.md
@@ -280,12 +280,11 @@ versions CRuby 4.0.6 bundles, so `require "rexml/document"` and `ir -S rake` wor
every machine, with or without a CRuby next to IronRuby.
[`Util/install-bundled-gems.rb`](Util/install-bundled-gems.rb) installs them from a CRuby
source tarball's `gems/*.gem` and lists the ones left out and why (the C extensions IronRuby
-implements itself, and the ones that need `rbs`). A host CRuby 4.0's gem directory is still
-offered for third-party gems, but never for a gem IronRuby ships;
-`IRONRUBY_NO_HOST_GEMS=1` turns it off entirely.
+implements itself, and the ones that need `rbs`). IronRuby never uses the gems of a CRuby
+installed on the same machine: a gem it needs is installed for IronRuby, with `igem install`
+or Bundler.
-A C extension is never built: there is no `ruby.h` to compile against, and the gem whose
-extension is missing is often in a read-only host CRuby tree. Such a gem is left alone -
+A C extension is never built: there is no `ruby.h` to compile against. Such a gem is left alone -
its `.rb` files load, a real `require` of the `.so` raises `LoadError`, and the pure-Ruby
fallback most of them carry is used instead.
diff --git a/Src/IronRuby.Tests/RubyTests.cs b/Src/IronRuby.Tests/RubyTests.cs
index 234b2c436..d875ee62f 100644
--- a/Src/IronRuby.Tests/RubyTests.cs
+++ b/Src/IronRuby.Tests/RubyTests.cs
@@ -733,6 +733,8 @@ public Tests(Driver/*!*/ driver) {
Fiddle_AnsiSuffix1,
PackPointer_RealAddress1,
PackPointer_RelineWin32Api1,
+ IoConsole_WinsizeOffTerminal1,
+ Ripper_Filter1,
Dir_ChdirRelative1,
File_ExpandTildeOrder1,
File_FlockReadpartialRlimit1,
diff --git a/Src/IronRuby.Tests/Runtime/MiscTests.cs b/Src/IronRuby.Tests/Runtime/MiscTests.cs
index f1ad5e78b..994148c55 100644
--- a/Src/IronRuby.Tests/Runtime/MiscTests.cs
+++ b/Src/IronRuby.Tests/Runtime/MiscTests.cs
@@ -1093,6 +1093,57 @@ p File.expand_path('~') == (windows ? 'Y:/profile' : File.expand_path('~'))
");
}
+ ///
+ /// IO#winsize off a terminal raises what MRI raises: ENOTTY from ioctl on Linux and macOS,
+ /// EBADF from the console API on Windows, where IronRuby used to have no winsize at all -
+ /// irb asks $stdout for it before showing each result, and died after the first one.
+ /// A console's own size needs a console, which a test run does not have.
+ ///
+ public void IoConsole_WinsizeOffTerminal1() {
+ TestOutput(@"
+require 'ruby4'
+require 'io/console'
+require 'tmpdir'
+windows = File::ALT_SEPARATOR == '\\'
+path = File.join(Dir.tmpdir, ""ir-winsize-#{Process.pid}.txt"")
+File.open(path, 'w') do |f|
+ begin
+ f.winsize
+ rescue SystemCallError => e
+ p e.class == (windows ? Errno::EBADF : Errno::ENOTTY)
+ end
+end
+File.delete(path)
+", @"
+true
+");
+ }
+
+ ///
+ /// require 'ripper' gives Ripper::Filter, as MRI's ripper.rb does: rdoc's Ruby parser
+ /// subclasses it, and `gem install` generating documentation died on the NameError.
+ ///
+ public void Ripper_Filter1() {
+ TestOutput(@"
+require 'ruby4'
+require 'ripper'
+class Words < Ripper::Filter
+ def on_default(event, tok, data)
+ data << [lineno, column, event, tok]
+ end
+end
+Words.new(""x = 1 # one\n"").parse([]).each { |t| p t }
+", @"
+[1, 0, :on_ident, ""x""]
+[1, 1, :on_sp, "" ""]
+[1, 2, :on_op, ""=""]
+[1, 3, :on_sp, "" ""]
+[1, 4, :on_int, ""1""]
+[1, 5, :on_sp, "" ""]
+[1, 6, :on_comment, ""# one\n""]
+");
+ }
+
///
/// What RubyGems and Bundler need from the file system on Windows, where each of these
/// used to P/Invoke libc or raise: File#flock (RubyGems locks every binstub it writes),
diff --git a/Src/Libraries/Termios/Termios.cs b/Src/Libraries/Termios/Termios.cs
index 36729f905..4e21aa556 100644
--- a/Src/Libraries/Termios/Termios.cs
+++ b/Src/Libraries/Termios/Termios.cs
@@ -15,6 +15,7 @@
using IronRuby.Builtins;
using IronRuby.Runtime;
using Microsoft.Scripting.Runtime;
+using Microsoft.Scripting.Utils;
namespace IronRuby.StandardLibrary.Termios {
@@ -31,7 +32,8 @@ namespace IronRuby.StandardLibrary.Termios {
///
/// The constants are Linux's (asm-generic/termbits.h, asm-generic/ioctls.h). On a
/// platform without termios is false and every call returns nil
- /// or false, which io/console.rb turns into the ENOTTY MRI raises off a non-terminal.
+ /// or false, which io/console.rb turns into the error MRI raises off a non-terminal -
+ /// except winsize, which Windows answers from the console API, as MRI does there.
///
[RubyModule("Termios")]
public static class TermiosOps {
@@ -181,10 +183,15 @@ public static bool TcFlush(RubyModule/*!*/ self, [NotNull]RubyIO/*!*/ io, [Defau
#region winsize
///
- /// ioctl(TIOCGWINSZ) as [rows, columns], or nil when this is not a terminal.
+ /// ioctl(TIOCGWINSZ) as [rows, columns], or nil when this is not a terminal. On Windows
+ /// it is the console window's size, from GetConsoleScreenBufferInfo, as MRI's
+ /// io/console answers it there - irb asks $stdout for it before it shows each result.
///
[RubyMethod("winsize", RubyMethodAttributes.PublicSingleton)]
public static object WinSize(RubyModule/*!*/ self, [NotNull]RubyIO/*!*/ io) {
+ if (!_supported) {
+ return WindowsWinSize(io);
+ }
int fd = DescriptorOf(io);
if (fd < 0) {
return null;
@@ -218,6 +225,52 @@ public static bool SetWinSize(RubyModule/*!*/ self, [NotNull]RubyIO/*!*/ io,
return sys_ioctl(fd, TIOCSWINSZ, buffer) == 0;
}
+ private const int STD_INPUT_HANDLE = -10;
+ private const int STD_OUTPUT_HANDLE = -11;
+ private const int STD_ERROR_HANDLE = -12;
+
+ ///
+ /// CONSOLE_SCREEN_BUFFER_INFO: dwSize, dwCursorPosition (COORDs), wAttributes, then
+ /// srWindow - Left, Top, Right, Bottom as shorts at 10, 12, 14 and 16 - and
+ /// dwMaximumWindowSize. 22 bytes, laid out by hand like struct termios above.
+ ///
+ private const int ScreenBufferInfoSize = 22;
+
+ [DllImport("kernel32", SetLastError = true)]
+ private static extern IntPtr GetStdHandle(int nStdHandle);
+
+ [DllImport("kernel32", SetLastError = true)]
+ private static extern bool GetConsoleScreenBufferInfo(IntPtr hConsoleOutput, byte[] info);
+
+ ///
+ /// The visible window of the console a standard stream is attached to, as MRI computes
+ /// it: srWindow.Bottom - Top + 1 rows and Right - Left + 1 columns. nil for an IO
+ /// that is no standard stream, and for one that is not a console - redirected, or
+ /// the input side, which has no screen buffer.
+ ///
+ private static object WindowsWinSize(RubyIO/*!*/ io) {
+ if (io.Closed) {
+ return null;
+ }
+ int std;
+ switch (io.ConsoleStreamType) {
+ case ConsoleStreamType.Input: std = STD_INPUT_HANDLE; break;
+ case ConsoleStreamType.Output: std = STD_OUTPUT_HANDLE; break;
+ case ConsoleStreamType.ErrorOutput: std = STD_ERROR_HANDLE; break;
+ default: return null;
+ }
+ byte[] info = new byte[ScreenBufferInfoSize];
+ if (!GetConsoleScreenBufferInfo(GetStdHandle(std), info)) {
+ return null;
+ }
+ short left = BitConverter.ToInt16(info, 10), top = BitConverter.ToInt16(info, 12);
+ short right = BitConverter.ToInt16(info, 14), bottom = BitConverter.ToInt16(info, 16);
+ var result = new RubyArray(2);
+ result.Add(bottom - top + 1);
+ result.Add(right - left + 1);
+ return result;
+ }
+
#endregion
#region constants
diff --git a/Src/Ruby/Builtins/RubyIO.cs b/Src/Ruby/Builtins/RubyIO.cs
index 9642753e8..2b5854dea 100644
--- a/Src/Ruby/Builtins/RubyIO.cs
+++ b/Src/Ruby/Builtins/RubyIO.cs
@@ -218,8 +218,15 @@ public ConsoleStreamType? ConsoleStreamType {
if (Closed) {
return null;
}
- var stream = GetStream();
- var console = stream.BaseStream as ConsoleStream;
+ // A copy that could not dup(2) the descriptor - #dup of a console stream on
+ // Windows - wraps the original's buffered stream in one of its own, so the
+ // console may be more than one buffer down.
+ Stream stream = GetStream().BaseStream;
+ RubyBufferedStream buffered;
+ while ((buffered = stream as RubyBufferedStream) != null) {
+ stream = buffered.BaseStream;
+ }
+ var console = stream as ConsoleStream;
return console != null ? console.StreamType : (ConsoleStreamType?)null;
}
}
diff --git a/Src/Ruby/Hosting/RubyCommandLine.cs b/Src/Ruby/Hosting/RubyCommandLine.cs
index 2f9ef5ba7..9b95d37e4 100644
--- a/Src/Ruby/Hosting/RubyCommandLine.cs
+++ b/Src/Ruby/Hosting/RubyCommandLine.cs
@@ -84,9 +84,9 @@ protected override int Run() {
// A script argument of "-" says to read the program from stdin, and is how the CRuby
// test suite runs a program in a child process; ARGV is what follows it. The options
- // parser gives "-" when there is neither -e nor a script, so `ironruby` alone reads
- // stdin as `ruby` does - at a terminal too, until EOF. A host that skips the parser
- // and gives neither still gets stdin when it is redirected.
+ // parser gives "-" when there is neither -e nor a script and stdin is not a terminal
+ // (at one it gives irb), so `ironruby` alone reads a piped program as `ruby` does. A
+ // host that skips the parser and gives neither still gets stdin when it is redirected.
if (Options.Command == null &&
(Options.FileName == "-" || (Options.FileName == null && System.Console.IsInputRedirected))) {
// The program is read as bytes: a magic comment may say they are not UTF-8, and
diff --git a/Src/Ruby/Hosting/RubyOptionsParser.cs b/Src/Ruby/Hosting/RubyOptionsParser.cs
index ffe713fcf..d6038fcfb 100644
--- a/Src/Ruby/Hosting/RubyOptionsParser.cs
+++ b/Src/Ruby/Hosting/RubyOptionsParser.cs
@@ -843,13 +843,40 @@ protected override void AfterParse() {
ConsoleOptions.Exit = true;
}
- // `ruby` with neither -e nor a script reads the program from stdin until EOF - at a
- // terminal too - as if "-" had been given, and $0 is "-" (MRI, JRuby). IronRuby used to
- // start the DLR's interactive console there; irb is `irb` / `iirb`. ironrubyw, which has
- // no console, then reads nothing and exits, as rubyw does.
+ // `ruby` with neither -e nor a script reads the program from stdin until EOF, as if "-"
+ // had been given, and $0 is "-" (MRI, JRuby); so does `ironruby` when stdin is a pipe
+ // or a file. At a terminal it starts irb instead, as `python` starts its interactive
+ // interpreter there: `ironruby` alone is then `iirb`, the -S irb that ironruby.cmd and
+ // ironruby find in RUBYPATH. An explicit "-", and -n, -p, -c and -x, which are about
+ // stdin, still read it. ironrubyw, which has no console, reads nothing and exits, as
+ // rubyw does. Only an irb found in RUBYPATH or PATH runs: FindMainFileFromPath hands
+ // back a name it did not find unchanged, and that would be a file called irb in the
+ // current directory.
if (!ConsoleOptions.Exit && ConsoleOptions.Command == null && ConsoleOptions.FileName == null) {
- ConsoleOptions.FileName = "-";
- LanguageSetup.Options["MainFile"] = "-";
+ string irb = StartsInteractive() ? FindMainFileFromPath("irb") : null;
+ if (irb != null && irb != "irb" && Platform.FileExists(irb)) {
+ ConsoleOptions.FileName = irb;
+ SetupOptionsForMainFile();
+ } else {
+ ConsoleOptions.FileName = "-";
+ LanguageSetup.Options["MainFile"] = "-";
+ }
+ }
+ }
+
+ ///
+ /// Whether `ironruby` with no program should be interactive: stdin is a terminal (a
+ /// console on Windows, which .NET tells apart from NUL), and no option asked for stdin.
+ ///
+ private bool StartsInteractive() {
+ if (LanguageSetup.Options.ContainsKey("LoopOverInput") || LanguageSetup.Options.ContainsKey("CheckSyntaxOnly") ||
+ LanguageSetup.Options.ContainsKey("SkipToRubyShebang")) {
+ return false;
+ }
+ try {
+ return !Console.IsInputRedirected;
+ } catch (IOException) {
+ return false;
}
}
diff --git a/Src/StdLib/ironruby/io/console.rb b/Src/StdLib/ironruby/io/console.rb
index d773097a2..33b8da80d 100644
--- a/Src/StdLib/ironruby/io/console.rb
+++ b/Src/StdLib/ironruby/io/console.rb
@@ -203,10 +203,12 @@ def ttymode
# -------------------------------------------------------------------- size
- # [rows, columns] of the terminal this IO is connected to.
+ # [rows, columns] of the terminal this IO is connected to. Off one, MRI raises
+ # ENOTTY from ioctl, and on Windows EBADF - the error GetConsoleScreenBufferInfo
+ # leaves for a handle that is no console output, STDIN's included.
def winsize
size = ::Termios.winsize(self)
- raise Errno::ENOTTY, __console_name__ unless size
+ raise (::Termios.supported? ? Errno::ENOTTY : Errno::EBADF), __console_name__ unless size
size
end
diff --git a/Src/StdLib/ironruby/ripper.rb b/Src/StdLib/ironruby/ripper.rb
index decd93ee2..f14243edd 100644
--- a/Src/StdLib/ironruby/ripper.rb
+++ b/Src/StdLib/ironruby/ripper.rb
@@ -704,3 +704,7 @@ def match(n = 0)
end
require 'ripper/sexp_builder'
+# MRI's ripper.rb requires ripper/filter too; rdoc's Ruby parser subclasses Ripper::Filter.
+# An autoload, as filter.rb requires ripper/lexer, which here is this file: required from
+# here it would be a circular require.
+Ripper.autoload :Filter, 'ripper/filter'
diff --git a/Src/StdLib/ruby/4.0/rubygems/defaults/ironruby.rb b/Src/StdLib/ruby/4.0/rubygems/defaults/ironruby.rb
index 7c9fd80c1..ad4cb7d51 100644
--- a/Src/StdLib/ruby/4.0/rubygems/defaults/ironruby.rb
+++ b/Src/StdLib/ruby/4.0/rubygems/defaults/ironruby.rb
@@ -38,70 +38,16 @@ def self.user_dir
end
##
- # Gem trees belonging to a matching host CRuby installation.
+ # No host CRuby's gems.
#
- # IronRuby is a drop-in for the CRuby release whose standard library it
- # vendors, and pure-Ruby gems installed for that CRuby load unchanged here.
- # Rather than force every user to set GEM_PATH, look for a `ruby` on PATH and
- # offer its /lib/ruby/gems/ read-only, when the API
- # version matches ours. Set IRONRUBY_NO_HOST_GEMS=1 to opt out.
- #
- # What these trees may provide, and what they may not
- # ----------------------------------------------------
- # They are a convenience for *third-party* gems only. Nothing IronRuby ships
- # may come from them: not a default gem (the gemspecs in
- # specifications/default, see default_specifications_dir) and not a bundled
- # gem (the gems Util/install-bundled-gems.rb installs into default_dir -
- # rake, rexml, minitest, csv, logger, ...). IronRubyHostGemFilter at the end
- # of this file drops the host's copy of every gem whose name IronRuby's own
- # gem home has, whatever its version, so `require "rexml/document"` and
- # `ir -S rake` resolve to the same files on every machine: the ones in this
- # tree, or a newer release the user installed *for IronRuby*.
- #
- # That used to be otherwise. Before the bundled gems were shipped here, a
- # machine with CRuby 4.0 installed got rake 13 and rexml 3.4 from the host,
- # and one without it - Windows, CI, most users - got a LoadError or a 1.9-era
- # copy, with nothing in between to say which it was.
- #
- # Why this is still on by default
- # -------------------------------
- # Turning it into an opt-in was considered and not done. With the filter it
- # can no longer change what the standard library is, so what is left is the
- # convenience - a Gemfile or a script that uses a gem the host CRuby already
- # has works without installing it again for IronRuby - and the ruby-bench,
- # Rails and popular-gem setups on this project's machines are built on it.
- # IRONRUBY_NO_HOST_GEMS=1 is what makes a run behave like a machine with no
- # CRuby at all, and is how the self-containment check is run.
- #
- # Bundler narrows GEM_HOME and GEM_PATH to its bundle_path on every command,
- # which would hide these trees and default_dir alike; Gem.path below keeps
- # both.
-
- def self.host_ruby_dirs # :nodoc:
- return @host_ruby_dirs if defined?(@host_ruby_dirs) && @host_ruby_dirs
-
- @host_ruby_dirs = []
- return @host_ruby_dirs if ENV["IRONRUBY_NO_HOST_GEMS"]
-
- seen = {}
- (ENV["PATH"] || "").split(File::PATH_SEPARATOR).each do |dir|
- next if dir.empty?
-
- exe = File.join(dir, "ruby#{RbConfig::CONFIG["EXEEXT"]}")
- next unless File.file?(exe)
-
- prefix = File.dirname(File.dirname(exe))
- gems = File.join(prefix, "lib", "ruby", "gems", ruby_api_version)
- next unless File.directory?(gems)
- next if seen[gems]
-
- seen[gems] = true
- @host_ruby_dirs << gems
- end
- @host_ruby_dirs
- rescue StandardError
- @host_ruby_dirs = []
- end
+ # IronRuby reads only its own gem trees: the user's (user_dir), GEM_HOME and
+ # GEM_PATH, and default_dir with the gems it ships. It used to also offer a
+ # CRuby 4.0 found on PATH - its /lib/ruby/gems/4.0.0 - for third-party
+ # gems, filtered so that none IronRuby ships came from there. That still
+ # loaded that CRuby's code into IronRuby in ways no filter caught: its
+ # RubyGems plugins (rdoc's hooked rdoc 7.0.4 into every `gem install`), and
+ # gems installed for one interpreter running on the other. A gem IronRuby
+ # needs is installed for IronRuby, with `igem install` or Bundler.
##
# Where the default gems' specifications live.
@@ -205,25 +151,49 @@ def self.default_path
path << user_dir if user_home && File.exist?(user_home)
path << default_dir
path << vendor_dir if vendor_dir && File.directory?(vendor_dir)
- path.concat(host_ruby_dirs)
path
end
##
- # IronRuby's own gem home and the host trees stay on Gem.path even when
- # something narrows GEM_HOME and GEM_PATH - which Bundler does on every
- # command, pinning both to its bundle_path (and GEM_PATH to nothing at all
- # when a path is configured). On CRuby that loses little, because
- # bundle_path defaults to the very directory the bundled gems are in; here it
- # would hide them, and a Gemfile that names rake or minitest would go to
- # rubygems.org for a gem this tree already has. default_dir holds the
- # bundled gems IronRuby ships (Util/install-bundled-gems.rb) and the host
- # trees are filtered (IronRubyHostGemFilter), so both are read-only extra
- # sources, like a vendor directory, and appending them is always safe. They
- # go last, so a gem installed into GEM_HOME or GEM_PATH is found first.
+ # IronRuby's own gem home stays on Gem.path even when something narrows
+ # GEM_HOME and GEM_PATH - which Bundler does on every command, pinning both to
+ # its bundle_path (and GEM_PATH to nothing at all when a path is configured).
+ # On CRuby that loses little, because bundle_path defaults to the very
+ # directory the bundled gems are in; here it would hide them, and a Gemfile
+ # that names rake or minitest would go to rubygems.org for a gem this tree
+ # already has. default_dir holds the bundled gems IronRuby ships
+ # (Util/install-bundled-gems.rb), so it is a read-only extra source, like a
+ # vendor directory, and appending it is always safe. It goes last, so a gem
+ # installed into GEM_HOME or GEM_PATH is found first.
def self.path
- paths.path | [default_dir] | host_ruby_dirs
+ paths.path | [default_dir]
+ end
+
+ ##
+ # No documentation unless asked for, as on TruffleRuby: generating ri and
+ # rdoc takes longer than installing most gems, and is rarely read. `gem
+ # install --document` (or a "gem: --document" line in ~/.gemrc) still builds
+ # it, through the hooks below.
+
+ def self.platform_defaults
+ { "gem" => "--no-document" }
+ end
+
+ # rdoc ships in IronRuby's standard library rather than as a gem, so no
+ # install wrote the plugin stub that registers its hooks on CRuby (rdoc's
+ # rubygems_plugin.rb, through /plugins). These register the same
+ # two, and load rdoc only when one runs. RDoc::RubyGemsHook.generate reads
+ # the install's --document / --no-document itself. ::RDoc, because inside
+ # Gem, RDoc is Gem::RDoc - rubygems/rdoc.rb's alias for the hook class.
+ done_installing do |installer, specs|
+ require "rdoc/rubygems_hook"
+ ::RDoc::RubyGemsHook.generate(installer, specs)
+ end
+
+ pre_uninstall do |uninstaller|
+ require "rdoc/rubygems_hook"
+ ::RDoc::RubyGemsHook.remove(uninstaller)
end
##
@@ -296,13 +266,13 @@ def self.ironruby_default_gem_names # :nodoc:
end
##
- # Lazy loading of the host CRuby's default gemspecs.
+ # Lazy loading of the default gemspecs.
#
# Upstream's Gem::Specification.load_defaults evaluates every gemspec in
# Gem.default_specifications_dir at boot, purely to feed
# Gem.register_default_spec - which only wants, per gem, the list of paths
# that `require` should map to it. On CRuby that directory holds a handful
- # of specs and the eval is compiled C; here it is the host's 46 default
+ # of specs and the eval is compiled C; here it is IronRuby's own default
# gemspecs, and evaluating them is by far the largest single cost of
# `require "rubygems"`.
#
@@ -321,7 +291,7 @@ def self.ironruby_default_gem_names # :nodoc:
##
# The standard library this process is running out of. A source tree can be
# checked out many times over - every worktree on this box shares one home
- # directory and one host CRuby - so it is part of the cache's identity: the
+ # directory - so it is part of the cache's identity: the
# recorded feature paths point into *this* tree, and requiring another
# worktree's copy of rubygems/dependency.rb would be a real bug.
@@ -495,11 +465,9 @@ def self.load_defaults # :nodoc:
# RubyGems builds a gem's extensions lazily, the first time something
# activates it - installing a gem builds its dependencies' extensions too.
# On IronRuby that can only fail: there is no ruby.h and no CRuby ABI to
- # compile against. Worse, the gem whose extension is missing is usually one
- # in the *host* CRuby's tree (which is offered read-only, see
- # host_ruby_dirs), so the attempt writes a half-built Makefile and a
- # gem_make.out into someone else's installation before it fails, and takes
- # the whole `gem install` down with it.
+ # compile against. The attempt writes a half-built Makefile and a
+ # gem_make.out into the gem's directory before it fails, and takes the whole
+ # `gem install` down with it.
#
# Doing nothing leaves the gem exactly as it is: its .rb files load, the
# missing .so raises a plain LoadError if something really reaches for it,
@@ -638,8 +606,8 @@ def ironruby_provided_library? # :nodoc:
# running Ruby, and Gem::Dependency#matching_specs then rejects it. On
# IronRuby a C extension is never built, so that rule would make every gem
# with an extension - and every gem that merely depends on one - impossible
- # to activate: parser depends on racc, and racc's .so exists only for the
- # host CRuby. Most such gems carry a pure-Ruby fallback that the extension
+ # to activate: parser depends on racc, and racc's .so exists only for
+ # CRuby. Most such gems carry a pure-Ruby fallback that the extension
# merely accelerates (racc/parser.rb rescues the LoadError of racc/cparse),
# and the ones that do not fail at require time with a plain LoadError for
# the extension file, which is a better answer than refusing to resolve.
@@ -699,65 +667,4 @@ def full_require_paths
end
BasicSpecification.prepend(IronRubyProvidedGem)
-
- ##
- # A host CRuby's copy of a gem IronRuby ships is never used.
- #
- # host_ruby_dirs offers a matching CRuby's gem tree read-only, which is right
- # for third-party pure-Ruby gems. It also offers that CRuby's *installed*
- # bigdecimal, json, psych and bundler, though, and an installed gem sorts
- # ahead of a default gem of the same version - so the host's bigdecimal-4.0.1
- # shadowed the one in Src/Libraries, and, worse, the host's bundler shadowed
- # the bundler shipped here: a Gemfile.lock saying `BUNDLED WITH 4.0.12` made
- # Bundler::SelfManager switch to the host's 4.0.12, an upstream release with
- # none of IronRuby's carve-outs, which then dropped every extension gem from
- # its index and aborted the bundle.
- #
- # The same goes for the bundled gems in default_dir, for a quieter reason: the
- # host's rake-13.4.2 is newer than the rake-13.3.1 shipped here, so on a
- # machine with CRuby it would win activation, and `ir -S rake` would run a
- # different rake there than everywhere else.
- #
- # So drop the host's copy of every gem IronRuby has its own of - a default
- # gem, or any gem in its own gem home - from the index entirely. Only the
- # host trees are filtered: a gem the user installed *for IronRuby* over a
- # shipped one is still an upgrade and still wins, exactly as on CRuby.
- #
- # Defined ahead of rubygems/specification_record.rb (which reopens the class)
- # and prepended, so the real definition cannot overwrite it.
-
- ##
- # The names of the gems in IronRuby's own gem home, default and installed:
- # the ones a host tree may not provide. Read from file names, so that
- # nothing is evaluated.
-
- def self.ironruby_own_gem_names # :nodoc:
- @ironruby_own_gem_names ||= begin
- installed = Dir.glob(File.join(default_dir, "specifications", "*.gemspec")).map do |file|
- File.basename(file, ".gemspec")[/\A(.+)-[^-]+\z/, 1]
- end
- (ironruby_default_gem_names + installed.compact).uniq
- end
- rescue StandardError
- @ironruby_own_gem_names = ironruby_default_gem_names
- end
-
- class SpecificationRecord; end
-
- module IronRubyHostGemFilter # :nodoc:
- private
-
- def installed_stubs(pattern)
- stubs = super
- host = Gem.host_ruby_dirs
- return stubs if host.empty?
-
- names = Gem.ironruby_own_gem_names
- return stubs if names.empty?
-
- stubs.reject {|stub| host.include?(stub.base_dir) && names.include?(stub.name) }
- end
- end
-
- SpecificationRecord.prepend(IronRubyHostGemFilter)
end
diff --git a/Util/install-bundled-gems.rb b/Util/install-bundled-gems.rb
index f4e6772a0..2fe144d55 100644
--- a/Util/install-bundled-gems.rb
+++ b/Util/install-bundled-gems.rb
@@ -25,7 +25,8 @@
# interpreter into its default gem home, which `require` finds by activating
# them. IronRuby used to have 1.9-era copies of most of them on $LOAD_PATH -
# rake 0.8.7, rexml 3.1.7.3, MiniTest 1.6 - and got the modern ones only on a
-# machine that also had CRuby 4.0 installed, through Gem.host_ruby_dirs. With
+# machine that also had CRuby 4.0 installed, through that CRuby's gem tree
+# (which IronRuby no longer reads at all). With
# these installed here the modern gem is always present, on every machine and
# on Windows, and the 1.9 copies are gone.
#