简体   繁体   中英

When building a Ruby gem, how do you specify which files Bundler should require?

In the past, based on a stylistic decision, I've created gems that use use names containing dashes:

foo-bar

However, the folder structure under lib looks more like this:

lib
  foo_bar.rb

If I use one of my own gems in the Gemfile of another project, Bundler doesn't require the library automatically. If I use one of my single word named gems ( bundy for example) in another project's Gemfile, the auto-require works.

Based on the default structure of a gem project created with Bundler, I'm guessing that Bundler is trying to require the contents of lib/foo/bar.rb . Unknown to me, gems seem to expect a '-' in the gem name to relate to a '/' in the path name.

What if I want Bundler to require lib/foo_bar.rb ? Can this be done without:

  • Changing the name of the gem? (Some gems are in use in projects owned by companies I no longer work for, so I don't want to do this.)
  • Adding extraneous files to manage includes? (Seems messy and unprofessional.)
  • Adding an explicit require to the 'gem' declaration in the Gemfile? (Seems unprofessional.)

Looking through the Bundler code, I found that the auto-require path comes from one of two places:

  • The 'require' setting in the Gemfile
  • The name of the gem itself.

     #/lib/bundler/dependency.rb ... if options.key?('require') @autorequire = Array(options['require'] || []) end ... 

and:

      #/lib/bundler/runtime.rb
      ...
      if dep.autorequire.nil? && dep.name.include?('-')
        begin
          namespaced_file = dep.name.gsub('-', '/')
          Kernel.require namespaced_file
        rescue LoadError => e
          REQUIRE_ERRORS.find { |r| r =~ e.message }
          raise if $1 != namespaced_file
        end
      end
      ...

This replaces the - characters in the gem's name with '/', just as I found from my experiments. From the looks of it, it also swallows the exception if it encounters a require error trying to require the transformed gem name. (It re-throws for others, so presumably it will fail if a gem's internal dependencies are broken.)

I can't find any other mechanism for setting an autorequire file, so I'll grudgingly have to use my second option: add an extra file in the location that Bundler expects which requires the files I need.

If you are creating a gem, it is better to include gems you depend on in your .gemspec file

Gem::Specification.new do |spec|
  ...
  spec.add_dependency "gem-name-whatev", "~> 1.5" # just like Gemfile
  spec.add_development_dependency "other-gem"
  ...
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM