Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Expand on Nat Williams' work on GemVersionCollection

It's now considered immutable, and I've massively cut down the API footprint.
  • Loading branch information...
commit 303999221cfbe53a46a4860dc6058a73121562d7 1 parent a6f3ac9
@cwninja cwninja authored
View
23 lib/geminabox.rb
@@ -33,6 +33,7 @@ def fixup_bundler_rubygems!
end
autoload :GemVersionCollection, "geminabox/gem_version_collection"
+ autoload :GemVersion, "geminabox/gem_version"
autoload :DiskCache, "geminabox/disk_cache"
before do
@@ -54,7 +55,7 @@ def fixup_bundler_rubygems!
query_gems = params[:gems].split(',').sort
cache_key = query_gems.join(',')
disk_cache.cache(cache_key) do
- deps = load_gems.gems.select {|gem| query_gems.include?(gem.name) }.map do |gem|
+ deps = load_gems.select {|gem| query_gems.include?(gem.name) }.map do |gem|
spec = spec_for(gem.name, gem.number)
{
:name => gem.name,
@@ -187,15 +188,19 @@ def disk_cache
@disk_cache = Geminabox::DiskCache.new(File.join(settings.data, "_cache"))
end
+ def all_gems
+ %w(specs prerelease_specs).map{ |specs_file_type|
+ specs_file_path = File.join(settings.data, "#{specs_file_type}.#{Gem.marshal_version}.gz")
+ if File.exists?(specs_file_path)
+ Marshal.load(Gem.gunzip(Gem.read_binary(specs_file_path)))
+ else
+ []
+ end
+ }.inject(:|)
+ end
+
def load_gems
- @loaded_gems ||=
- %w(specs prerelease_specs).inject(GemVersionCollection.new){|gems, specs_file_type|
- specs_file_path = File.join(settings.data, "#{specs_file_type}.#{Gem.marshal_version}.gz")
- if File.exists?(specs_file_path)
- gems |= Geminabox::GemVersionCollection.new(Marshal.load(Gem.gunzip(Gem.read_binary(specs_file_path))))
- end
- gems
- }
+ @loaded_gems ||= Geminabox::GemVersionCollection.new(all_gems)
end
def index_gems(gems)
View
5 lib/geminabox/gem_version.rb
@@ -24,6 +24,11 @@ def <=>(other)
sort
end
+ def ==(other)
+ return false unless other.class == self.class
+ [name, number, platform] == [other.name, other.number, other.platform]
+ end
+
def gemfile_name
included_platform = ruby? ? nil : platform
[name, number, included_platform].compact.join('-')
View
68 lib/geminabox/gem_version_collection.rb
@@ -1,65 +1,63 @@
require 'geminabox/gem_version'
+# This class represents a sorted collection of Geminabox::GemVersion objects.
+# It it used widely throughout the system for displaying and filtering gems.
class Geminabox::GemVersionCollection
include Enumerable
- def size
- @gems.size
- end
-
- attr_reader :gems
-
+ # Array of Geminabox::GemVersion objects, or an array of [name, version,
+ # platform] triples.
def initialize(initial_gems=[])
- @gems = []
- initial_gems.each { |gemdef| self << gemdef }
- sort!
- end
-
- def <<(version_or_def)
- version = if version_or_def.is_a?(Geminabox::GemVersion)
- version_or_def
- else
- Geminabox::GemVersion.new(*version_or_def)
- end
-
- @gems << version
+ @gems = initial_gems.map{|object|
+ coerce_to_gem_version(object)
+ }.sort
end
+ # FIXME: Terminology makes no sense when the version are not all of the same
+ # name
def oldest
@gems.first
end
+ # FIXME: Terminology makes no sense when the version are not all of the same
+ # name
def newest
@gems.last
end
- def |(other)
- self.class.new(self.gems | other.gems)
+ def size
+ @gems.size
end
def each(&block)
@gems.each(&block)
end
- def by_name
- grouped = @gems.inject(hash_of_collections) do |grouped, gem|
- grouped[gem.name] << gem
- grouped
- end.sort_by{|name, gems| name.downcase }
+ # The collection can contain gems of different names, this method groups them
+ # by name, and then sorts the different version of each name by version and
+ # platform.
+ #
+ # yields 'foo_gem', version_collection
+ def by_name(&block)
+ @grouped ||= @gems.group_by(&:name).map{|name, collection|
+ [name, Geminabox::GemVersionCollection.new(collection)]
+ }.sort_by{|name, collection|
+ name.downcase
+ }
if block_given?
- grouped.each(&Proc.new)
+ @grouped.each(&block)
else
- grouped
+ @grouped
end
end
- def sort!
- @gems.sort!
- end
-
- private
- def hash_of_collections
- Hash.new { |h,k| h[k] = self.class.new }
+private
+ def coerce_to_gem_version(object)
+ if object.is_a?(Geminabox::GemVersion)
+ object
+ else
+ Geminabox::GemVersion.new(*object)
+ end
end
end
View
46 test/units/gem_version_collection_test.rb
@@ -0,0 +1,46 @@
+require 'test_helper'
+
+class GemVersionCollectionTest < MiniTest::Unit::TestCase
+ GIB = Geminabox
+ def test_it_coerces_things_to_gem_versions
+ expected = GIB::GemVersion.new('foo', '1.2.3', 'ruby')
+ actual = GIB::GemVersionCollection.new([['foo', '1.2.3', 'ruby']]).oldest
+
+ assert_equal expected, actual
+ end
+
+ def test_it_groups_by_name
+ subject = GIB::GemVersionCollection.new([
+ ['foo', '1.2.3', 'ruby'],
+ ['foo', '1.2.4', 'ruby'],
+ ['bar', '1.2.4', 'ruby']
+ ])
+
+ actual = Hash[subject.by_name]
+ assert_equal GIB::GemVersionCollection, actual['foo'].class
+ assert_equal 2, actual['foo'].size
+ assert_equal 1, actual['bar'].size
+ end
+
+ def test_it_should_be_sorted_by_version
+ subject = GIB::GemVersionCollection.new([
+ ['foo', '1.2.3', 'ruby'],
+ ['foo', '1.2.4', 'ruby'],
+ ['foo', '1.0.4', 'ruby']
+ ])
+
+ assert_equal '1.0.4', subject.oldest.version.to_s
+ assert_equal '1.2.4', subject.newest.version.to_s
+ end
+
+ def test_it_should_be_sorted_by_name_first
+ subject = GIB::GemVersionCollection.new([
+ ['bbb', '1.2.3', 'ruby'],
+ ['aaa', '1.2.4', 'ruby'],
+ ['bbb', '1.0.4', 'ruby']
+ ])
+
+ assert_equal 'bbb', subject.oldest.name
+ assert_equal 'aaa', subject.newest.name
+ end
+end

1 comment on commit 3039992

@natw

Much cleaner, thanks.

Please sign in to comment.
Something went wrong with that request. Please try again.