Hi,
I recently had an idea of faking load paths [0] to satisfy bundler's
loading and help bring our behavior closer to upstream while still
unbundling the libraries.
To automatically test for the usual user's workflow with bundler and a
default gem (only RDoc so far),
I have created small TMT test suite [1]. It pulls the Ruby RPMs from my
copr repo
https://copr.fedorainfracloud.org/coprs/jackorp/ruby-rdoc-default-gem/ .
It is adjustable to fit your own copr if you wish to do your own changes
[2], TMT can also install RPMs from a local directory, but that's going
off-topic.
One of my TODO item here is to validate this against some rbenv Ruby
install.
To the loading itself and my examination.
Default gems seem to skip bundler somewhere and go their own path which
is more similar to regular `Kernel.require` without bundler.
Therefore, just having it on the default load path, where default gems
are expected to exist is enough.
However, regular Ruby loading also means that it expects a certain
layout that it won't search for itself if it can't find a subfile, see
Rake and `rdoc/task` below.
So, if we place `rdoc.rb` into `/usr/share/ruby/` that adjusts the load
path accordingly and then just passes on the require, that's enough if
the code is either
~~~
$ cat foo.rb
require 'rdoc'
p RDoc::VERSION # Demonstrate that RDoc is available
~~~
and run with bundler `bundle exec ruby ./foo.rb`.
or in CLI like this: `bundle exec ruby -rrdoc -e 'p RDoc::VERSION'`.
In both cases, the associated Gemfile is empty. No gems are recored in
the file.
My approach, at this point in time, falls apart with Rake and RDoc using
`require rdoc/task`, as there is no /usr/share/ruby/rdoc/task.rb. I am
unable to track down the exact code path,
but it seems to skip some places inside bundler, even rubygems, that
could otherwise make it possible to work (with a few minor adjustments
of course).
This demostrated a problem, we'd have to fake out the whole structure of
any gem we'd like to unbundle this way.
That, of course, is a possibility.
So the pros / cons of this approach currently seem:
+ we'd unbundle default gems away
+ no more symlinks.
+ closer to upstream behavior for the users
- We'd have to retain the structure and provide each "fake" path to a file.
* Though we are doing something a small bit similar with the symlinks.
- added complexity of writing correct paths into the files on their
correct places.
Alternatively, this is just an academic idea, populate the default load
path with default gems.
I, however, do not know where would the right place for that be, or what
would be the cons of this approach
(apart from potentially breaking expectations set accross the whole Ruby
environment for loadables).
Also to adjust the Kernel.require, but that feels very wrong (also
potentially unsafe, as the code is in C AFAICT, and very divergent from
upstream).
But I have quickly dismissed these as I have high doubts such patches
would ever be accepted upstream and maintainability of such approaches
is quetionable at best.
Additionally, I am not sure what should be the behaviour with the plain
rdoc executable and bundler executed like this: `bundle exec rdoc`
I will try to apply the approach of faking the whole gem directory and
file tree in /usr/share/ruby for RDoc and record my findings.
I am open to discussion, should you want to share your thoughts or ideas
regarding this topic.
Regards,
Jarek Prokop
[0]
https://src.fedoraproject.org/fork/jackorp/rpms/ruby/c/1f660500090ad6d176...
[1]
https://gitlab.com/jackorp/test_default_gem_fedora_ruby
[2]
https://gitlab.com/jackorp/test_default_gem_fedora_ruby/-/blob/7658195644...