Bidirectionnal relation


#1

Hi everyone,
I have a problem with bidirectional relations : how to implements it ?

I can’t implements it with 2 relations without synchronize them :

no synchronization

class Entity
attr_accessor :mother
attr_reader :daughters
def initialize
@daughters = []
end
end

a = Entity.new
b = Entity.new
a.mother = b
puts (b.daughters.include? a) # false
a.daughters << b
puts (b.mother == a) # false

too bad…

Try with a simple synchronization :

simple synchronization

class Entity
attr_reader :mother, :daughters
def initialize
@daughters = []
end
def mother= m
@mother.daughters.delete self unless @mother.nil?
@mother = m
@mother.daughters << self unless @mother.nil?
end
def add_daughter d
unless d.nil?
@daughters << d
d.mother = self
end
end
end

a = Entity.new
b = Entity.new
a.mother = b
puts (b.daughters.include? a) # true
a.daughters << b # it’s possible so why not use it ?
puts (b.mother == a) # false

ok for some operations, but not exhaustive.

The problem seems to come from @daughters which is a simple Array.
Let’s fix it :

better synchronization

class Entity
attr_reader :mother, :daughters
def initialize
@daughters = []
class << @daughters
attr_accessor :mother
alias old_add <<
def << d, recc=false
old_add d
d.mother = @mother unless recc
end
alias old_delete delete
def delete d
if include? d
d.mother = nil
old_delete d
end
end
end
@daughters.mother = self
end
def mother= m
@mother.daughters.delete self unless @mother.nil?
@mother = m
@mother.daughters.<<(self, true) unless @mother.nil?
end
def add_daughter d
unless d.nil?
@daughters << d
d.mother = self
end
end
end

a = Entity.new
b = Entity.new
a.mother = b
puts (b.daughters.include? a) # true
a.daughters << b
puts (b.mother == a) # true

ok it works (I think), but I need to redefine all methods from
@daughters

26 lines more than the first (and natural) solution, for a really simple
problem… I don’t think I’ll often use it.

I tried to implement a solution with a real relation, but I had too many
problems.

If anyone has a suggestion (solution or link or anything) to implement
transparent bidirectional relation… :slight_smile:
Thanks !


#2

dohzya wrote:

Hi everyone,
I have a problem with bidirectional relations : how to implements it ?

How about:
class Female
attr_accessor :mother
def initialize( name )
@name = name
@daughters = []
end
def daughters
@daughters.dup.freeze
end
def mother=( mom )
@mother = mom
unless mom.daughters.include?( self )
mom.add_daughter( self )
end
end
def add_daughter( girl )
@daughters << girl unless @daughters.include?( girl )
girl.mother = self
end
def inspect
“<Female ‘#{@name}’>”
end
end

a = Female.new( ‘Strami’ )
b = Female.new( ‘Lisa’ )
c = Female.new( ‘Imogen’ )

b.mother = a
p a.daughters.include?( b )
#=> true

b.daughters << c
#=> Error: can’t modify frozen array (TypeError)

b.add_daughter c

p a.daughters
#=> [<Female ‘Lisa’>]

p b.daughters
#=> [<Female ‘Imogen’>]

p c.mother
#=> <Female ‘Lisa’>


#3

2007/7/24, dohzya removed_email_address@domain.invalid:

I have a problem with bidirectional relations : how to implements it ?
(…)
If anyone has a suggestion (solution or link or anything) to implement
transparent bidirectional relation… :slight_smile:

Hi Etienne,

in ruby-talk:121602 I posted a little library to implement this.
Here’s your example:

require “relation”

class Entity
end

Relation.new Entity, :one, :mother, Entity, :many, :daughters

a = Entity.new
b = Entity.new

a.mother = b
puts(b.daughters.include?(a)) # => true

a.daughters << b
puts(b.mother == a) # => true

If you find nothing else maybe I should create my first gem…

Regards,
Pit


#4

Le jeudi 26 juillet 2007 à 01:25 +0900, Pit C. a écrit :

a.mother = b

Why find again ? it’s exactly what I want !

I wait for your gem, thanks :slight_smile:


#5

Le jeudi 26 juillet 2007 à 01:25 +0900, Pit C. a écrit :

2007/7/24, dohzya removed_email_address@domain.invalid:

I have a problem with bidirectional relations : how to implements
it ?

(…)
If anyone has a suggestion (solution or link or anything) to
implement
end
puts(b.mother == a) # => true

If you find nothing else maybe I should create my first gem…

Regards,
Pit

Why find again ? it’s exactly what I want !

I wait for your gem, thanks :slight_smile:


#6

Le jeudi 26 juillet 2007 à 01:25 +0900, Pit C. a écrit :

2007/7/24, dohzya removed_email_address@domain.invalid:

I have a problem with bidirectional relations : how to implements
it ?

(…)
If anyone has a suggestion (solution or link or anything) to
implement
end
puts(b.mother == a) # => true

If you find nothing else maybe I should create my first gem…

Regards,
Pit

Why find again ? it’s exactly what I want !

I wait for your gem, thanks :slight_smile:

(and I hate my mail client…)