From: shevegen@... Date: 2017-08-29T11:33:54+00:00 Subject: [ruby-core:82511] [Ruby trunk Feature#13847] Gem activated problem for default gems Issue #13847 has been updated by shevegen (Robert A. Heiler). > Also, in this use case, it seems to be enough to use [..] > require 'json', version: :default, into: :Bundler Matz will decided but I wanted to comment on what Hiroshi Shibata wrote. Kernel require presently accepts no additional arguments: https://ruby-doc.org/core-2.4.1/Kernel.html#method-i-require So I guess the proposal also means to extend Kernel#require if I understood it correctly. I may be wrong but I think that matz may wish to keep require simple. I myself have, since some time, wanted to have some more useful or powerful ways for ruby to handle add-ons in general stored in different files. Some time ago I noticed that load() has a second argument (boolean - true or false), and if false then the loaded file will not modify the namespace. So it will be an anonymous module. That was quite interesting to me. There are also some tricks to be able to access the module still such as on: http://iceruby.blogspot.co.at/2014/07/or-how-to-get-anonymous-module-from.html (In case the above link no longer works at some point in time, and you don't want to search via the wayback www archive, I'll very briefly mention what they do: They use catch/throw trick such as: throw :wrapper, Module.nesting.last and catch the error that way catch :wrapper do load File.expand_path('b.rb'), true Which was an interesting idea.) Anyway, to come back to Hiroshi Shibata, I actually agree with the proposal, although I come from another direction (in general to have more power and control about how to load up add-ons and external code, so this is why I am in support of it). In Gemfiles, please correct me if I am wrong but there are ways to speciically load certain versions such as via: gem 'openssl', '2.0.4' So in my opinion, I believe that it may make sense for require to accept a Hash too. This Hash could allow for additional parameters that would allow us rubyists for more finer-grained control. Hiroshi gave the example: require 'json', version: '2.0.2', into: :Bundler Perhaps we could also re-define importable namespaces, a bit similar as to load() but actually attaching onto the main namespace of the current ruby gem. For example, if I have a project called foobar, with module Foobar, and I am including an external project called bla, that has a toplevel module namespace called Bla, then I could perhaps say that the namespace Bla never "exists" but instead becomes attached towards module Foobar at once. Syntax proposals: require 'bla', version: '2.0.2', attach_as_namespace :Foobar or something like this. However, please do not get too distracted by my suggestion above; it's just what I personally would like to be able to have. It is not so important for me whether this is part of require, or load, or some other way, I am more interested in the functionality, since I needed it a few times already. I do not want to make Hiroshi's proposal too complicated, so I want to end that I agree with his proposal. +1 ---------------------------------------- Feature #13847: Gem activated problem for default gems https://bugs.ruby-lang.org/issues/13847#change-66322 * Author: hsbt (Hiroshi SHIBATA) * Status: Open * Priority: Normal * Assignee: * Target version: 2.5 ---------------------------------------- If you try to use some default gems with a fixed version using Bundler, there are cases where the current RubyGems/Bundler/Ruby specification can not be used with the version specified by the user. For example ``` $ ruby -v ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin17] $ gem list | grep openssl openssl (2.0.5, 2.0.4, default: 2.0.3) ``` In the environment such as ```require 'openssl'```, the version that is activated when openssl is searched with openssl is the version found first, ie 2.0.5. ``` $ ruby -ropenssl -e 'p OpenSSL::VERSION' "2.0.5" ``` At this time, for example, suppose the user really wants to use openssl 2.0.4 and wrote the following Gemfile. ``` > cat Gemfile # frozen_string_literal: true source "https://rubygems.org" gem 'openssl', '2.0.4' ``` Unfortunately, since rubygems has required openssl before the bundler runs it will result in an activated error like this: ``` > bundle exec ruby -ropenssl -e 'p OpenSSL::VERSION' /path/to/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.15.4/lib/bundler/runtime.rb:317:in `check_for_activated_spec!': You have already activated openssl 2.0.5, but your Gemfile requires openssl 2.0.4. Prepending `bundle exec` to your command may solve this. (Gem::LoadError) ``` This problem can be avoided by bundling it as a vendoring library under bundler's repository if it is a default gem implemented with pure ruby. Https://github.com/bundler/bundler/blob/master/lib/bundler/vendor/fileutils/lib/fileutils.rb In the case of bundler, by separating the namespace as `Bundler::FileUtils`, even the version specified by the user is made available without conflict at the time of activate. However, this method can not be used with C extension library. Since we want to use json/psych from the bundler team with rubygems/bundler to serialize data, we need about whether we can implement a way to avoid some kind of C extension on Ruby itself. I discussed with @indirect who is maintainer of RubyGems/Bundler. We can resolve this problem like following feature of ruby. ``` require_for_bundler 'json', '2.0.2' ``` When we declared above `require_for_bundler`, We put a json-2.0.2 to placed in a namespace like `Bundler::JSON`. There were similar issues in the past as well. https://bugs.ruby-lang.org/issues/10320 I think that the way of writing ```require 'json', version: '2.0.2', into: :Bundler``` which extended the method like this issue seems like that. Also, in this use case, it seems to be enough to use ```require 'json', version: :default, into: :Bundler``` which forces the use of default gem. Matz, How do you think about this feature? -- https://bugs.ruby-lang.org/ Unsubscribe: