#!/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 = {} # name => number of uses names_to_counts = Hash.new 0 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 dependencies.each do |dependency| names_to_counts[dependency] += 1 end end $names = names_of_first_use def link name if $names[name] then "#{name}" else name end end puts "" puts "RubyGems Dependency Statistics" puts "
" puts "

#{data.length} total gems" 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 puts "

#{deps_used} of #{gem_count} gems used as dependencies (#{percent}%)" longest = names_to_first_use.map { |name,| name.to_s.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 "

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})" most_uses = names_to_counts.values.max most_dependend_upon = names_to_counts.invert[most_uses] puts "

most depended upon is #{link most_dependend_upon} with #{most_uses} uses" puts "

" puts 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 uses = names_to_counts[name] use_percent = (uses / data.length.to_f * 100).to_i puts "
#{name}
" puts "
first used on #{first_use_date.strftime '%Y-%m-%d'}
" puts "
first released on #{first_release.strftime '%Y-%m-%d'}
" puts "
days before first use #{lag}
" puts "
first used by #{link first_use_name}
" puts "
uses #{uses} (#{use_percent}%)
" puts end puts "
"