0.0
No commit activity in last 3 years
No release in over 3 years
A small gem that adds #find, #all and #destroy to a class to keep track of its instances.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 0
 Project Readme

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 www.ruby-forum.com/topic/330466 and 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

QED¶ ↑

You can run this documentation with QED