#!/usr/local/bin/ruby require 'rubygems' require 'rubygems/remote_fetcher' file = "Marshal.#{Gem.marshal_version}.Z" uri = URI.parse "http://gems.rubyforge.org/#{file}" data = Gem::RemoteFetcher.fetcher.fetch_path uri data = Gem.inflate data data = Marshal.load data # name => [date1, date2] names_to_dates = Hash.new { |h,k| h[k] = [] } # name => { date1 => version1 } names_to_dates_to_versions = Hash.new { |h,k| h[k] = {} } # name => { date1 => [dep1, dep2] } names_to_dependencies = Hash.new { |h,k| h[k] = {} } # name => date_used_as_dependency names_to_first_use = {} # name => used_by names_of_first_use = {} # name => days_to_first_use names_to_lag = {} data.each do |name, spec| name = spec.name version = spec.version.to_s date = spec.date dependencies = spec.dependencies.map do |dep| case dep when Gem::Dependency then dep.name when Array then dep.first else raise dep.inspect end end names_to_dates[name] << date names_to_dates_to_versions[name][date] = version names_to_dependencies[name][date] = dependencies end names_to_dates.each do |name, dates| dates.sort! do |a, b| b <=> a end dates.each do |release_date| deps = names_to_dependencies[name][release_date] next if deps.empty? deps.each do |dep_name| first_use = names_to_first_use[dep_name] if first_use.nil? or first_use > release_date then names_to_first_use[dep_name] = release_date names_of_first_use[dep_name] = name end end end end deps_used = names_to_first_use.length gem_count = names_to_dates.length percent = (deps_used / gem_count.to_f * 100).to_i longest = names_to_first_use.map { |name,| name.length }.max names_to_first_use.each do |name, date| first_release = names_to_dates[name].last next if first_release.nil? # wtf gem ">= 0.5" lag = (date.to_i / 86400) - (first_release.to_i / 86400) names_to_lag[name] = lag end total_lag = 0 names_to_lag.each { |name, lag| total_lag += lag > 0 ? lag : 0 } average_lag = (total_lag / names_to_lag.length.to_f).round puts "#{deps_used} of #{gem_count} gems used as dependencies (#{percent}%)" puts "average time to first use is #{average_lag} days" max_time_to_use = names_to_lag.values.max max_time_name = names_to_lag.invert[max_time_to_use] puts "maximum time to first use is #{max_time_to_use} (#{max_time_name})" puts names_to_lag.sort_by { |name,| name }.each do |name, lag| first_use_date = names_to_first_use[name] first_use_name = names_of_first_use[name] first_release = names_to_dates[name].last puts "%*s used on %s" % [-longest, name, first_use_date.strftime('%Y-%m-%d')] puts "#{' ' * (longest - 4)} released on #{first_release.strftime '%Y-%m-%d'}" puts "#{' ' * (longest - 8)} days before use #{lag}" puts "#{' ' * (longest)} used by #{first_use_name}" puts end