有没有办法让捆绑器自动需要 gem 而无需在 gemfile 中指定它们?

Is there a way to have bundler automatically require gems without specifying them in the gemfile?

我正在尝试让自定义 rspec 格式化程序在使用捆绑器的多个项目中工作。由于我已将 rspec 格式化程序安装为全局 gem,因此我希望不需要将 gem 添加到每个项目的 gem 文件中。

有没有办法让捆绑器自动执行:

group :test { gem 'my-globally-installed-rspec-formatter' }

以便测试环境中的任何项目都会自动加载该依赖项,但在其实际 Gemfile 中不需要它?

您可以将 gems 放入 .gemspec 但这与将其放入 Gemfile

基本上是同一个问题

我解决这个问题的方法是在 .gemspecGemfile 中包含两行中间件,然后将所有 gem 依赖项移出 [=16] =] 和 .gemspec

这是通过使用子模块来处理的。这让很多人感到害怕。

对于某些人来说,这就像驾驶宇宙飞船飞过五个城市街区,但对于管理 5 个以上 gem 团队且具有相同依赖关系的人来说,这会有所帮助。再加上诸如通用 RuboCop 标准之类的东西,使用共享子模块就变得很有价值。

一旦你实现了一个子模块,你的 Gemfile 可能看起来像这样,从 Celluloid 的当前版本我们有一个正在实现的 celluloid/culture 子模块:

require File.expand_path("../culture/sync", __FILE__)
Celluloid::Sync::Gemfile[self]

引用此方法...

module Celluloid
  module Sync
    module Gemfile
      class << self
        def [](dsl)
          dsl.source("https://rubygems.org")
          dsl.gemspec
          Gems.gemfile(dsl)
        end
      end
    end
  end
end

这又是运行这个方法,在Celluloid::Gems ...

def gemfile(dsl)
  loader do |name, spec|
    params = [name, spec["version"] || ">= 0"]
    req = spec["gemfile"] || {}
    params << req.each_with_object({}) { |(k, v), o| o[k.to_sym] = v }
    current = dsl.dependencies.find { |d| d.name == name }
    dsl.dependencies.delete(current) if current
    dsl.gem(*params)
  end
end

private

def loader
  @dependencies.each do |name, spec|
    next if name == gem_name
    spec ||= {}
    yield name, spec
  end
end

循环遍历预加载到 @dependencies 中的 yaml 文件...

bundler:
nenv:
dotenv:

benchmark_suite:
  dependency: development

rubocop:
  dependency: development

pry:
  dependency: development

rake:
  dependency: development

rspec:
  dependency: development

coveralls:
  gemfile:
    require: false

celluloid:
  dependency: core
  version: ">= 0.17.0.pre7"
  gemfile:
    github: celluloid/celluloid
    branch: 0.17.0-prerelease
    submodules: true

celluloid-essentials:
  dependency: module
  gemfile:
    github: celluloid/celluloid-essentials
    branch: master
    submodules: true

celluloid-supervision:
  dependency: module
  gemfile:
    github: celluloid/celluloid-supervision
    branch: master
    submodules: true

celluloid-pool:
  dependency: module
  gemfile:
    github: celluloid/celluloid-pool
    branch: master
    submodules: true

celluloid-fsm:
  dependency: module
  gemfile:
    github: celluloid/celluloid-fsm
    branch: master
    submodules: true

celluloid-extras:
  dependency: module
  gemfile:
    github: celluloid/celluloid-extras
    branch: master
    submodules: true

timers:
  version: "~> 4.0.0"
  gemfile:
    github: celluloid/timers

rspec-logsplit:
  version: ">= 0.1.2"
  gemfile:
    github: "abstractive/rspec-logsplit"
    branch: "master"
    require: false

.gemspec 也应用了类似的技术,如下所示:

require File.expand_path("../culture/sync", __FILE__)

Gem::Specification.new do |gem|
  #de Unique statements which are not shareable.    
  Celluloid::Sync::Gemspec[gem]
end

您应该自己查看 celluloid/culture 存储库以查看整个解决方案,其中包括一种机制,当您 运行 bundle update 例如。

对我们来说,上面解释和解决的问题非常烦人,它催生了这种方法,最终可能成为它自己的 'product',特别是因为它还解决了 Bundler 中的 other issues , 但很少有人真正需要整个 arrangement 。我想这种方法是有争议的。如果您对此策略感兴趣,我可以以可重用的方式发布我的解决方案。

实际上我意识到有一个 rspec 标志 --require 它将自动加载依赖项...所以我能够在我的本地 rvm gem 中安装 gem设置,然后制作一个 ~/.rspec 文件:

--color
--tty
--require '/Users/me/.rvm/gems/ruby-2.0.0-p451@global/gems/fancy-formatter-0.11/lib/fancy_formatter.rb'
--format FancyFormatter

它会自动在我的所有项目中运行。