Bidirectionnal relation

D

dohzya

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... :)
Thanks !
 
G

Gavin Kistner

dohzya said:
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'>
 
P

Pit Capitain

2007/7/24 said:
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... :)

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, :eek:ne, :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
 
D

dohzya

Le jeudi 26 juillet 2007 à 01:25 +0900, Pit Capitain a écrit :
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, :eek:ne, :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

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

I wait for your gem, thanks :)
 
D

dohzya

Le jeudi 26 juillet 2007 à 01:25 +0900, Pit Capitain a écrit :
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, :eek:ne, :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

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

I wait for your gem, thanks :)
 
D

dohzya

Le jeudi 26 juillet 2007 à 01:25 +0900, Pit Capitain a écrit :
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, :eek:ne, :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

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

I wait for your gem, thanks :)

(and I hate my mail client...)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,263
Messages
2,571,312
Members
47,987
Latest member
Gaurav

Latest Threads

Top