Robert Klemme
11/18/2004 9:41:00 AM
"Curt Sampson" <cjs@cynic.net> schrieb im Newsbeitrag
news:Pine.NEB.4.58.0411181431440.649@angelic-vtfw.cvpn.cynic.net...
>
> I've been dealing with some slightly more complex groups of data lately.
> Say, something like this:
>
> I have a dozen Libraries. Each library carries some volumes of zero
> or more Journals. For example, Library L1 might have volumes 1-35 of
> Journal J1, and Library L2 might have volumes 25-40 of Journal J1. Each
> Volume has one or more Articles in it, and the same Article might be
> found in multiple Volumes of the same or different Journals.
>
> So I make classes for all of these and started hooking them up together,
> beginning with the obvious tree structure (Libraries reference Journals,
> which reference Volumes, which reference Articles.) But then I realize
> that I had some lookups I wanted to do that needed some different types
> of references, for example, "name all the Journals that have published
> Article A37."
>
> So I start adding more ways of doing efficient lookups, start to worry
about
> various data structures getting out of sync, get some fairly nasty code
> to search down through tree structures, and start to become unhappy.
>
> And then it hits me. The source of all my problems is that, stuck in my
> 'A has a B' reference rut, I've just constructed a hierarchial database,
> which is the source of all my pain.
>
> Well, this is a problem we solved forty years ago when Codd came up with
> the idea of relational databases. So, has anybody built some sort of
> relational storage system for Ruby that will let me describe my data in
> some sort of E/R-ish way and get stuff out from any direction I care to
use?
You probably just need bidrectional relations plus hashes as indexes. You
could define some utility code that establishes a relation between two
classes and a specialized indexing class that tracks attribute changes
automatically.
Something along this rough outline:
require 'set'
class Foo; attr_accessor :bar end
class Index
INDEXES = {}
def initialize(cl, field)
name = "#{cl.name}::#{field}"
@cl = cl
@field = field
@h = Hash.new {|h,k| h[k]=Set.new}
self.class::INDEXES[name] = self
@cl.class_eval "def #{field}=(x) idx = Index::INDEXES['#{name}'];
idx.remove(self, @#{field}); @#{field}=x; idx.add(self, @#{field}) end"
end
def add(obj, val)
@h[val].add(obj)
end
def remove(obj, val)
@h[val].delete(obj)
end
def get_all(val)
@h[val]
end
end
Index.new(Foo, :bar)
f=Foo.new
f.bar = 100
Index::INDEXES["Foo::bar"].get_all(100)
I would not use a relational approach because you loose the expressiveness
of an OO language.
Kind regards
robert