Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> it’s built into Ruby!

Nitpick: technically `Gem::Version` is part of `rubygems`, and while `rubygems` is (typically) packaged with Ruby, it's actually entirely optional, so much so that `rubygems` actually monkeypatches† Ruby core's `Kernel` (notably `require`) to inject gem functionality.

MRuby has none of it, and CRuby has a `--disable-rubygems` configure flag.

Back in 1.8 days, you even had to manually require `rubygems`!

https://github.com/ruby/rubygems/tree/4e4d2b32353c8ded870c14...



Nitpicking your nitpick, but Ruby’s standard library has three components:

* default libraries (these are maintained by the Ruby core team, delivered with Ruby, and upgraded only as part of Ruby version upgrades.)

* default gems (these are maintained by the Ruby core team, delivered with Ruby, not removable, can be required directly just like default libraries, but can be updated separately from Ruby version upgrades.)

* bundled gems (these are gems that are delivered and installed with Ruby, but which can be upgraded separately or removed.)

Rubygems is a default gem. [0] It used to not be part of the standard library, but it has been since Ruby 1.9, released in 2007.

[0] see, https://stdgems.org/


Frankly I wish Python's standard library were more like this. Maybe then we wouldn't be seeing tens of millions of daily downloads of pip (most likely orchestrated by other copies of pip!), requests (already vendored by pip!), setuptools, six (compatibility wrappers for ancient 2.x code, declared as a dependency by python-dateutil so that it can keep supporting 2.x, even though it's overwhelmingly downloaded for up-to-date Python installations)....

...There are presumably many other ways to solve that problem, but still.


When Ruby gemified the standard library, it wasn't about moving popular third-party libs into the standard library as gems, but making large parts of the standard library separately updateable (and, in some cases, removeable); all of the standard library used to be the equivalent of "default libraries", the change was moving them from that status to default or bundled gems.

So, doing the same thing with Python would be less like bundling requests with python and more like moving http into a wheel that was installed with python but could be upgraded separately.


> Nitpicking your nitpick

That's not a nitpick, that's paraphrasing ;)

> It used to not be part of the standard library, but it has been since Ruby 1.9, released in 2007.

That's the mention of 1.8 I made, but it's a bit more complex: it still can be excluded, in two ways:

- at build time via `configure` (and then it's not even there)

- at run time via `--disable-gems`

The interaction between rubygems and ruby core is surprisingly small.

> Rubygems is a default gem

It is not! See `lib/ruby/gems/3.3.0/specifications/default` in any Ruby install, or in source the absence of _any_ gemspec for `rubygems` while there is for bundler[0].

Instead it's, as you mentioned, a default library.

The very principle of gems is that you can have multiple versions of a gem separately installed (to the point of allowing only one to be visible at any one time, activated by `rubygems`-provided `Kernel.gem`). The implementation of that is done by `rubygems` itself so if it were a gem, one would not be able to activate `rubygems` without `rubygems` itself...

This is also why it can be special-case upgraded only via the very special `gem update --system`, which downloads a "gem" named `rubygems-update` (not `rubygems`); scare quotes because it's using the gem format and infrastructure mostly as a delivery mechanism, not by being an _actual_ gem[1] in the traditional sense (well it is a gem, but a gem of an updater, not of `rubygems` itself).

When updated, the new copy of rubygems is installed in `site_ruby`, because the load path is the only mechanism available to define location priority (`ruby --disable-gems -e 'p $LOAD_PATH'`).

Fun fact: the only thing that "prevents" a file present it `${PREFIX}/lib/ruby/3.4.0/rubygems` to not be `load`ed or `require`d is merely that new code in `${PREFIX}/lib/ruby/site_ruby/3.4.0` shall not make reference to it, but it's all perfectly visible otherwise.

    docker run --rm -it ruby:3.4 /bin/bash
    gem update --system
    ls -ld /usr/local/lib/ruby/3.4.0/rubygems /usr/local/lib/ruby/site_ruby/3.4.0/rubygems
    echo 'p __dir__' > /usr/local/lib/ruby/3.4.0/rubygems/foo.rb
    ruby -e 'p $LOAD_PATH; require "rubygems/foo"'
[0]: https://github.com/ruby/ruby/blob/v3_4_7/lib/bundler/bundler...

[1]: https://github.com/ruby/rubygems/blob/v3.7.2/hide_lib_for_up...


I just remembered, in those days, there was an alias called `ubygems` so you could pass `-rubygems` (ie, `-r` with `ubygems` as the argument) on the command line as if it was a first-class feature

it's so typical of ruby culture "haha, what if I do this silly thing" and then that gets shipped to production





Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: