已安装的宝石清单?

189

是否有一种Ruby方法可以调用以获取已安装的宝石列表?

我想解析gem list的输出。

还有其他方法可以实现这个功能吗?

11个回答

423

14
问题本身“gem list”中已经包含了更好的答案。 - Ahmad Ismail
gem list 正好符合我的需求,而且在命令行界面上记忆和使用起来更加简单。为什么要用那么多命令来完成同一件事情呢? - Dave Everitt
a) gem list,b) gem query和c) gem query --local之间的区别是什么?这三个命令似乎具有相同的行号。 - Timo

60

Gem命令现在已经包含在Ruby 1.9+中,并成为Ruby pre-1.9的标准补充。

require 'rubygems'

name = /^/i
dep = Gem::Dependency.new(name, Gem::Requirement.default)
specs = Gem.source_index.search(dep)
puts specs[0..5].map{ |s| "#{s.name} #{s.version}" }
# >> Platform 0.4.0
# >> abstract 1.0.0
# >> actionmailer 3.0.5
# >> actionpack 3.0.5
# >> activemodel 3.0.5
# >> activerecord 3.0.5

这里是获取列表的更新方法:

require 'rubygems'

def local_gems
   Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.group_by{ |g| g.name }
end
因为local_gems依赖于group_by,它返回一个哈希表,其中键是 gem 的名称,值是包含已安装该 gem 实例的数组,并按版本号排序。这使得可以执行以下操作:
my_local_gems = local_gems()

my_local_gems['actionmailer']
# => [Gem::Specification.new do |s|
#       s.authors = ["David Heinemeier Hansson"]
#       s.date = Time.utc(2013, 12, 3)
#       s.dependencies = [Gem::Dependency.new("actionpack",
#         Gem::Requirement.new(["= 4.0.2"]),
#         :runtime),
#        Gem::Dependency.new("mail",
#         Gem::Requirement.new(["~> 2.5.4"]),
#         :runtime)]
#       s.description = "Email on Rails. Compose, deliver, receive, and test emails using the familiar controller/view pattern. First-class support for multipart email and attachments."
#       s.email = "david@loudthinking.com"
#       s.homepage = "http://www.rubyonrails.org"
#       s.licenses = ["MIT"]
#       s.name = "actionmailer"
#       s.require_paths = ["lib"]
#       s.required_ruby_version = Gem::Requirement.new([">= 1.9.3"])
#       s.requirements = ["none"]
#       s.rubygems_version = "2.0.14"
#       s.specification_version = 4
#       s.summary = "Email composition, delivery, and receiving framework (part of Rails)."
#       s.version = Gem::Version.new("4.0.2")
#       end]

而且:

puts my_local_gems.map{ |name, specs| 
  [ 
    name,
    specs.map{ |spec| spec.version.to_s }.join(',')
  ].join(' ') 
}
# >> actionmailer 4.0.2
...
# >> arel 4.0.1,5.0.0
...
# >> ZenTest 4.9.5
# >> zucker 13.1

最后一个例子类似于gem query --local命令行,只不过您可以访问特定宝石规范的所有信息。


2
需要注意的是,现在使用带有正则表达式的"Dependency.new"已经被弃用。 - Martin Poljak

36

两者皆是

gem query --local

 ruby -S gem list --local

列表有69个条目

虽然

ruby -e 'puts Gem::Specification.all_names'

返回 82

我使用 wc -l 命令来获取数字,不确定这是否是正确的检查方式。尝试将输出重定向到文本文件并进行比较,但那并没有帮助——需要逐个手动比较。


4
原因很简单。第一个命令每个宝石只添加1个条目,并在同一行上用括号列出其版本。最后一个 ruby 命令将每个宝石版本单独列在一行中。例如:sass (3.3.14, 3.3.7, 3.3.6, 3.2.19)`sass-3.3.14`, `sass-3.3.7`, `sass-3.3.6`, `sass-3.2.19` - kaiser

11

这个方法已经存在很长一段时间了:

ruby -e 'puts Gem::Specification.all_names'

1
ruby -e 'puts Gem::Specification.all_names' 给我返回了“-e:1: uninitialized constant Gem (NameError)”这个错误。我该如何解决? - Metahuman

7
Gem::Specification.map {|a| a.name}

然而,如果你的应用程序使用了Bundler,它将仅返回本地依赖 gem 的列表。要获取所有已安装的 gem :

def all_installed_gems
   Gem::Specification.all = nil    
   all = Gem::Specification.map{|a| a.name}  
   Gem::Specification.reset
   all
end

当我在rails console中使用它时,会出现NoMethodError: undefined method 'any?' for nil:NilClass的错误。 - iconoclast

6
请使用以下代码(在控制台模式下):
Gem::Specification.all_names

1
你能改善你的回答吗? - MZaragoza
改进或让我知道您对我的答案有什么不喜欢的地方。 - Игорь Хлебников
这里需要解释一下这个代码对现有答案的补充。我为什么要使用这段代码?它是做什么的?与这个答案这个答案有何不同? - ggorlen

5
这是一行非常好的代码,可以打印出所有宝石的版本、主页和描述信息:
Gem::Specification.sort{|a,b| a.name <=> b.name}.map {|a| puts "#{a.name} (#{a.version})"; puts "-" * 50; puts a.homepage; puts a.description; puts "\n\n"};nil

3
一个更现代化的版本是使用类似以下的内容...
require 'rubygems'
puts Gem::Specification.all().map{|g| [g.name, g.version.to_s].join('-') }

注意:Evgeny的答案中第一部分非常相似……但由于页面格式,很容易被忽略。


3

请在终端中尝试:

ruby -S gem list --local

1
请注意,OP想要一个Ruby的方法 - the Tin Man

1
也许你可以从gems目录中获取文件(gems)?
gemsdir = "gems directory"
gems = Dir.new(gemsdir).entries

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接