Home > is_a_collection

is_a_collection

Is_a_collection is a project mainly written in Ruby, based on the MIT license.

A small gem that adds #find and #all to a class to keep track of it's instances.

== is_a_collection

=== API breaking change

As of version 0.1.0 an error gets raise on primary key collision. For the reasons read the new Indices section below. As of version 0.1.1 the error is IsACollection::DuplicateKeyError, not IsACollection::DuplicateKey any more.

=== Basics

A small gem that adds #find and #all to a class to keep track of its instances.

module AE::Assert alias :should :assert end

require 'is_a_collection'

class A is_a_collection

def initialize(*args)
  super
end

def id
  object_id
end

end

a = A.new A.all.assert == [a] b = A.new A.all.assert == [a,b] A.find(a.id) a.destroy A.all.should == [b]

As you can see: By default is_a_collection looks for an #id method and uses that as primary key for its index. But you can tell what method to use, #name in this example.

class B attr_reader :name is_a_collection :name

def initialize(name)
  @name = name
  add_to_collection
end
def destroy
  remove_from_collection
end

end

a = B.new('foo') B.all.assert == [a] b = B.new('bar') B.all.assert == [a,b] B.find('foo') a.destroy B.all.assert == [b]

is_a_collection hooks itself into #initialize and #destroy and calls its own #add_to_collection respectivly #remove_from_collection there. This means, if you define #initialize or #destroy in your class (and not in one of its superclasses), you either have to explicitly call #super (to give is_a_collection a chance to do its work) or call #add_to_collection and #remove_from_collection yourself.

==== Note to calling #super rubies other than 1.9.1 or 1.9.2.

If Object is the superclass of the Class you're using is_a_collection in, be careful that Object#initialize has the arity 0. So make sure you call super without any arguments. As super implicitly passes all arguments, you may need to call it like this: super *[]. Directly using #add_to_collection may be more… intuitive.

See http://www.ruby-forum.com/topic/330466 and http://redmine.ruby-lang.org/issues/show/2451 for more information.

=== Indices

As of the latest version is_a_collection supports arbitrary indices.

class Song attr_reader :title, :genre is_a_collection :title, :index => :genre

def initialize(title, genre)
  @title, @genre = title, genre
  add_to_collection
end
def destroy
  remove_from_collection
end

end

With this genre index defined, all instances of Song get added to a reverse lookup index. You can get songs with the #find_by_genre instance method.

s1 = Song.new 'foobar', 'Rock' s2 = Song.new 'foobaz', 'Rock' s3 = Song.new 'fuu', 'Pop'

Song.find_by_genre('Rock').to_a.assert == [s1,s2]

==== The breaking change

Before the index capabilities got added, a new instance with a primary key that was already present would just overwrite the other instance in the index. Now with the new index stuff, an instance can be references by the primary index and one or more other indices. If the primary index entry would be overridden as before, the other indices would still reference the first instance, but it would be hard to delete it afterwards. As this would lead to an object leak I decided the best solution is to raise an error on duplicate key entry.

== It doesn't work?

Did you call super in #initialize? Yes? I'm glad to help: Issues[https://github.com/niko/is_a_collection/issues]

== QED

You can run this documentation with QED[https://github.com/rubyworks/qed]

Previous:TestEcho