在C#中加载封送的Ruby对象

时间:2010-02-28 22:33:00

标签: c# ruby rubygems

当您运行命令gem outdated -V时,命令的输出显示类似于此的内容:

GET http://rubygems.org/latest_specs.4.8.gz
302 Found
GET http://production.s3.rubygems.org/latest_specs.4.8.gz
200 OK

这将向您发送一个gzip文件,其中包含另一个名为latest_specs.4.8的文件,您可以Marshal.load使用一个简单的Ruby应用程序,如下所示:

require 'pp'
require 'rubygems/version'

# This assumes you've downloaded the file to the current directory
pp Marshal.load(File.open('latest_specs.4.8')) 

运行它,它会打印一个看起来像这样的多维Array

[
    ["rails", Gem::Version.new("2.3.5"), "ruby"],
    ["sinatra", Gem::Version.new("0.9.4"), "ruby"],
    ["watir", Gem::Version.new("1.6.5"), "ruby"]
]

非常简单,但我正在尝试制作一个C#RubyGems GUI应用程序,当你有过时的宝石时会提醒你。

现在,由于update_specs文件是由Ruby编组的,有没有办法在不运行系统命令gem outdated的情况下在C#中访问它?

1 个答案:

答案 0 :(得分:0)

查看Gem::Commands::OutdatedCommand docs,看起来抓住列表并不会太困难。

只需修改#execute

中的代码即可
# File lib/rubygems/commands/outdated_command.rb, line 18
  def execute
    locals = Gem::SourceIndex.from_installed_gems

    locals.outdated.sort.each do |name|
      local = locals.find_name(name).last

      dep = Gem::Dependency.new local.name, ">= #{local.version}"
      remotes = Gem::SpecFetcher.fetcher.fetch dep
      remote = remotes.last.first

      say "#{local.name} (#{local.version} < #{remote.version})"
    end
  end

您可以执行类似

的操作
def outdated_gems
  locals = Gem::SourceIndex.from_gems_in *Gem::SourceIndex.installed_spec_directories
  locals.outdated.sort.map {|name| locals.find_name(name).last }
end

def latest_remote_gem local
  dep = Gem::Dependency.new local.name, ">= #{local.version}"
  remotes = Gem::SpecFetcher.fetcher.fetch dep
  remotes.last.first
end

#...

updated_gems = outdated_gems.map { |gem| [gem, latest_remote_gem(local)] }

updated_gems.each do |local,remote|
  # do something interesting with local.name, local.version & remote.version
end