tags:

views:

98

answers:

1

When you run the command gem outdated -V, the output of the command displays something similar to this:

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

This will send you a gzip file that contains another file called latest_specs.4.8 which you can Marshal.load with a simple Ruby app like so:

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')) 

Run this and it will pretty print a multi-dimensional Array that looks like so:

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

Pretty simple, but I am trying to make a C# RubyGems GUI application that would alert you when you have outdated gems.

Now, since the latest_specs file is marshaled by Ruby, is there any way I could access it within C# without running the system command gem outdated?

A: 

Looking at the Gem::Commands::OutdatedCommand docs, it looks like grabbing the list would not be too difficult.

Just modify the code from #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

You could do something like

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
BaroqueBobcat
Yeah, I've already messed around with this in Ruby. But I am trying to recreate it in C#. I can download and unGzip the latest_specs file in C# but I can't unmarshal it within C#.
c00lryguy
Have you tried using iron ruby? You can use the DLR interface to call into it from .NET http://www.ironruby.net/Documentation/.NET/Hosting
BaroqueBobcat