You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Gem::Specification.find_by_name返回正确的Ruby Gem版本

解决方案:获取当前激活的Gem规格而非全局查找

这个问题我之前也碰到过,核心原因是Bundler和RubyGems处理版本锁定的逻辑差异:

  • 用bundle exec运行时,Bundler会强制整个环境使用Gemfile.lock里的版本,所以Gem::Specification.find_by_name会乖乖返回锁定的0.0.1版本。
  • 但脱离Bundler用my_exe _0.0.1_(或gem _0.0.1_ my_exe)运行时,RubyGems只是把指定版本的gem加入加载路径,但find_by_name默认会遍历所有已安装的gem,返回最新的匹配版本,完全忽略你在命令行指定的版本。

下面是两种可靠的解决方法:

方法一:直接使用当前激活的Gem规格(推荐)

RubyGems在激活指定版本的gem时,会把它的规格信息存入Gem.loaded_specs哈希表,这个表里的就是当前进程正在使用的gem版本。直接替换你的代码:

# 原来的代码(有问题)
spec = Gem::Specification.find_by_name("my_gem")

# 替换成这个
spec = Gem.loaded_specs["my_gem"]

这样不管你是通过bundle exec还是RubyGems版本指定符运行,都能拿到当前正在使用的0.0.1版本的规格信息。

方法二:给find_by_name指定版本约束

如果你一定要保留find_by_name的调用,可以从当前激活的规格里获取版本,再作为约束传入:

current_version = Gem.loaded_specs["my_gem"].version
spec = Gem::Specification.find_by_name("my_gem", "= #{current_version}")

或者如果你能从命令行参数里解析出指定的版本(比如用户输入的_0.0.1_),也可以直接用那个版本字符串作为约束,但这种方法不如第一种可靠,因为RubyGems可能已经处理了版本激活,loaded_specs里的信息是最准确的。

为什么这能解决问题?

当你用my_exe _0.0.1_运行时,RubyGems会自动激活0.0.1版本的my_gem,并把它的规格加入Gem.loaded_specs。而find_by_name默认不考虑当前激活的版本,只会全局搜索最新的符合条件的gem,所以必须明确指定版本约束或者直接使用loaded_specs。

内容的提问来源于stack exchange,提问作者CodeSmith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 11:10:55