Can I access or find a object from it's instance variable?

  • Thread starter Aki Wakabayashi
  • Start date
A

Aki Wakabayashi

Hello.

Absolute newb here, and my very first post, so please bear with me...I
would like to be able to access an object with it's instance variable. I
simplified my example, but for instance:


class Foo
attr_accessor :some_id
end


one = Foo.new('7a')
two = Foo.new('2t')
three = Foo.new('33')


Is it possible to use the instance variable @some_id to access the
object itself? I was thinking of creating a class method for class Foo
such as:

class Foo
attr_accessor :some_id

self.find(some_id)
# somehow get an array of all the Foo objects, and iterate through
their
# some_id attributes until a match(s) is found, return the object(s)
end
end

...so I can do something like Foo.find('7a43') to access the object
'one'.

I am exhausted from searching how to get an array or hash of objects of
a given class, and I think I'm going in the wrong direction. Any
pointers will be greatly appreciated.


Thank you in advance :)
 
A

Aki Wakabayashi

Aki said:
...so I can do something like Foo.find('7a43') to access the object
'one'.

I meant to say " Foo.find('7a') ", not "Foo.find('7a43')".
 
S

Sean O'Halpin

Hello.

Absolute newb here, and my very first post, so please bear with me...I
would like to be able to access an object with it's instance variable. I
simplified my example, but for instance:


class Foo
=A0attr_accessor :some_id
end


one =3D Foo.new('7a')
two =3D Foo.new('2t')
three =3D Foo.new('33')


Is it possible to use the instance variable @some_id to access the
object itself? I was thinking of creating a class method for class Foo
such as:

class Foo
=A0attr_accessor :some_id

=A0self.find(some_id)
=A0 =A0# somehow get an array of all the Foo objects, and iterate through
their
=A0 =A0# some_id attributes until a match(s) is found, return the object(= s)
=A0end
end

...so I can do something like Foo.find('7a43') to access the object
'one'.

I am exhausted from searching how to get an array or hash of objects of
a given class, and I think I'm going in the wrong direction. Any
pointers will be greatly appreciated.


Thank you in advance :)

Here's one way (not terribly efficient):

class Foo
attr_accessor :eek:id
def initialize(oid)
@oid =3D oid
end

def self.find(oid)
found =3D nil
ObjectSpace.each_object(self) do |o|
if o.oid =3D=3D oid
found =3D o
break
end
end
found
end
end

one =3D Foo.new('7a')
two =3D Foo.new('2t')
three =3D Foo.new('33')

Foo.find('7a') # =3D> #<Foo:0x244c8 @oid=3D"7a">

Regards,
Sean
 
A

Aki Wakabayashi

Thank you Ian, and Sean.

I'm surprised that I got a reply so quickly! I was just reading p404 of
the Pickaxe book(1.8) and reading about ObjectSpace, but it was really
brief, and I was reading it over and over until I started to begin
talking to myself (not good).

What I really wanted was to get the actual identifier of the object, but
for now I'll create a instance variable for the actual identifier so I
can put it in the to_s method, and I can get things working.

I know it's not the Rubyist way, but I just started, so hopefully I can
find a better way later and post it here.

Once again, thank you guys. You were very supportive, and I would have
not figured this out so painlessly without your help.


Aki
 
C

Christopher Dicely

Hello.

Absolute newb here, and my very first post, so please bear with me...I
would like to be able to access an object with it's instance variable. I
simplified my example, but for instance:


class Foo
=C2=A0attr_accessor :some_id
end


one =3D Foo.new('7a')
two =3D Foo.new('2t')
three =3D Foo.new('33')


Is it possible to use the instance variable @some_id to access the
object itself? I was thinking of creating a class method for class Foo
such as:

class Foo
=C2=A0attr_accessor :some_id

=C2=A0self.find(some_id)
=C2=A0 =C2=A0# somehow get an array of all the Foo objects, and iterate t= hrough
their
=C2=A0 =C2=A0# some_id attributes until a match(s) is found, return the o= bject(s)
=C2=A0end
end

...so I can do something like Foo.find('7a43') to access the object
'one'.

I am exhausted from searching how to get an array or hash of objects of
a given class, and I think I'm going in the wrong direction. Any
pointers will be greatly appreciated.


Thank you in advance :)

Others have posted ways using ObjectSpace, which works; its always
seemed to me though that if you know you are going to need to do
something like that with objects of a particular class, that it may
often make more sense to do something like this:

class Foo
attr_reader :key

@@instances =3D Hash.new {|h,k| h[k] =3D []}

def self.find(key_val)
@@instances[key_val].first
end

def self.find_all(key_val)
@@instances[key_val].dup
end

def key=3D(new_key)
@@instances[@key].delete self
@@instances[new_key] << self
@key =3D new_key
end

def initialize(key_val)
@key =3D key_val
@@instances[key_val] << self
end
end
 
L

Leo

class Foo
=A0 attr_reader :key

=A0 @@instances =3D Hash.new {|h,k| h[k] =3D []}
[...]
=A0 def initialize(key_val)
=A0 =A0 @key =3D key_val
=A0 =A0 @@instances[key_val] << self
=A0 end
end

I don't know ruby well enough but I'd assume a weak reference would be
preferable -- unless the script won't run very long anyway.

In general, if you want control over the instances of a class, you
could also consider something singleton like:


require 'weakref'

class Foo
attr_reader :key
@instances =3D {}

def initialize(key)
@key =3D key
end

def self.instance(key)
find(key) || Foo.new(key).tap {|o| @instances[key] =3D
WeakRef.new(o)}
end

def self.find(key)
if @instances.has_key?(key) and @instances[key].weakref_alive?
@instances[key].__getobj__
end
end
end

a =3D Foo.instance("a")
a1 =3D Foo.instance("a")
a2 =3D Foo.find("a")
p a.object_id, a1.object_id, a2.object_id
 
C

Christopher Dicely

class Foo
=C2=A0 attr_reader :key

=C2=A0 @@instances =3D Hash.new {|h,k| h[k] =3D []}
[...]
=C2=A0 def initialize(key_val)
=C2=A0 =C2=A0 @key =3D key_val
=C2=A0 =C2=A0 @@instances[key_val] << self
=C2=A0 end
end

I don't know ruby well enough but I'd assume a weak reference would be
preferable -- unless the script won't run very long anyway.

Yeah, in most real-world cases using this basic design, you're
probably going to want to either use weak references (and add code to
manage them so that dead references are silently cleaned up rather
than throwing exceptions, or provide an explicit ability to delete an
instance from the class-level index, depending on how you expect
objects of the class to be used.
 
F

F. Senault

Le 8 mars 2009 à 03:55, Aki Wakabayashi a écrit :
Hello.

Absolute newb here, and my very first post, so please bear with me...I
would like to be able to access an object with it's instance variable. I
simplified my example, but for instance:

I've have to solve the same problem some time ago, here's how I've done
it (with a small example) :

http://pastie.org/410782

(In the original problem, I used the cache system to enable the use of
object instances, ids or keys indifferently in method calls.)

Fred
 
R

Robert Klemme

What I really wanted was to get the actual identifier of the object, but

What exactly do you mean by "actual identifier"? If you mean #object_id
then there is method ObjectSpace._id2ref.

http://www.ruby-doc.org/core/classes/ObjectSpace.html#M006793
for now I'll create a instance variable for the actual identifier so I
can put it in the to_s method, and I can get things working.

If you mean the object id then you do not need an instance variable to
put it into to_s's output.
I know it's not the Rubyist way, but I just started, so hopefully I can
find a better way later and post it here.

The question is: what are you trying to achieve?

Kind regards

robert
 
A

Aki Wakabayashi

Thank you everyone. I would like thank every one one by one, but I think
that will make this place look like a blog and I'm not sure if that's
proper to this forum. But I really appreciate everyone's support.

Creating a class variable, or using weak references (though still
complicated to me) made very much sense. The code at
http://pastie.org/410782 was clear to the point where a @name instance
variable is added to the class.

After cramming all this code into by head, I started to wonder if I was
able to do what I wanted to by using the #object_id? I'm not sure at
this point. Below is an example of what I wanted to achieve.
What exactly do you mean by "actual identifier"? If you mean #object_id
then there is method ObjectSpace._id2ref.

I meant the variable that I used to point to the object, when they are
created like:

var = Foo.new(77)

I wanted to get access to 'var' by using it's @some_id which is 77.
The question is: what are you trying to achieve?

Thank you for asking. I was wondering how to update relations(imagine a
social networking site) between objects of a single Class. I hope this
will clarify why I want to access the variable of the object with its
instance variable. This how far I got last night:

class Foo

attr_accessor :name, :some_id, :relations

def self.update_relationship(foo1, foo2)
# code that adds @relations for foo1, and foo2 and updates it with
# it's own MINUS its own :some_id, and updates other @some_id's
included
# in foo1.relations + foo2.relations.
end

def self.find_by_some_id(some_id)
found = nil
ObjectSpace.each_object(Foo) { |o| found = o if o.oid == oid}
found
end

def to_s
@name
end

end


(create two objects):

John = Foo.new('John', 1,[])
Dave = Foo.new('Dave', 2,[])

(create a relationship between the two):

Foo.update_relationship(John, Dave)

John.relations -> [2]
Dave.relations -> [1]


Let's assume that along the line more objects are created and a new
relationship is created with John.(I'm just going to create a new object
and populate it's @relations instance variable, so the variables are
visible)

Steve = Foo.new('Steve', 104, [55, 77])

Foo.update_relationship(Steve, John)

John.relations -> [2, 55, 77, 104]
Steve.relations -> [1,2,55,77]

...well, that's good, but all the other objects (with @some_id 2, 55 and
77) would have to be updated right? For starters, Dave, the second
object (with @some_id = 2) is currently still:

Dave.relations -> [1]

Where it has to be updated to [1, 55, 77, 104]

So in order to access the Dave object, I only had 2, it's @some_id
instance variable to access it. Now, since I included the variable name
in the instance variable I can access the Dave object with the
find_by_some_id class method, and
get the @name instance variable which is the same as the variable (THIS
IS WHERE I THOUGHT IT WAS NOT A RUBYIST SOLUTION)

I'm going to read a little more and see if I can use the object's
#object_id to do all of this.

Thank you.

Aki
 
C

Christopher Dicely

Thank you everyone. I would like thank every one one by one, but I think
that will make this place look like a blog and I'm not sure if that's
proper to this forum. But I really appreciate everyone's support.

Creating a class variable, or using weak references (though still
complicated to me) made very much sense. The code at
http://pastie.org/410782 was clear to the point where a @name instance
variable is added to the class.

After cramming all this code into by head, I started to wonder if I was
able to do what I wanted to by using the #object_id? I'm not sure at
this point. Below is an example of what I wanted to achieve.
What exactly do you mean by "actual identifier"? =C2=A0If you mean #obje= ct_id
then there is method ObjectSpace._id2ref.

I meant the variable that I used to point to the object, when they are
created like:

var =3D Foo.new(77)

I wanted to get access to 'var' by using it's @some_id which is 77.
The question is: what are you trying to achieve?

Thank you for asking. I was wondering how to update relations(imagine a
social networking site) between objects of a single Class. I hope this
will clarify why I want to access the variable of the object with its
instance variable. This how far I got last night:

class Foo

=C2=A0attr_accessor :name, :some_id, :relations

=C2=A0def self.update_relationship(foo1, foo2)
=C2=A0 =C2=A0# code that adds @relations for foo1, and foo2 and updates i= t with
=C2=A0 =C2=A0# it's own MINUS its own :some_id, and updates other @some_i= d's
included
=C2=A0 =C2=A0# in foo1.relations + foo2.relations.
=C2=A0end

=C2=A0def self.find_by_some_id(some_id)
=C2=A0 =C2=A0found =3D nil
=C2=A0 =C2=A0ObjectSpace.each_object(Foo) { |o| found =3D o if o.oid =3D= =3D oid}
=C2=A0 =C2=A0found
=C2=A0end

=C2=A0def to_s
=C2=A0 =C2=A0@name
=C2=A0end

end


(create two objects):

John =3D Foo.new('John', 1,[])
Dave =3D Foo.new('Dave', 2,[])

(create a relationship between the two):

Foo.update_relationship(John, Dave)

John.relations -> [2]
Dave.relations -> [1]


Let's assume that along the line more objects are created and a new
relationship is created with John.(I'm just going to create a new object
and populate it's @relations instance variable, so the variables are
visible)

Steve =3D Foo.new('Steve', 104, [55, 77])

Foo.update_relationship(Steve, John)

John.relations -> [2, 55, 77, 104]
Steve.relations -> [1,2,55,77]

...well, that's good, but all the other objects (with @some_id 2, 55 and
77) would have to be updated right? For starters, Dave, the second
object (with @some_id =3D 2) is currently still:

Dave.relations -> [1]

Where it has to be updated to [1, 55, 77, 104]

So in order to access the Dave object, I only had 2, it's @some_id
instance variable to access it. Now, since I included the variable name
in the instance variable I can access the Dave object with the
find_by_some_id class method, and
get the @name instance variable which is the same as the variable (THIS
IS WHERE I THOUGHT IT WAS NOT A RUBYIST SOLUTION)

I'm going to read a little more and see if I can use the object's
#object_id to do all of this.

Thank you.

Aki

Note that because Ruby objects are passed as references, you generally
don't need to keep relationships using an identifier, you can just
keep a list of the "related" objects in an instance variable (the code
becomes less clear when you store an identifier instead of the object
itself, you probably aren't saving space, and you are probably hurting
performance by necessitating a method call to lookup the actual object
from the identifier.)
 
R

Robert Klemme

You can't really as this is a local variable and you would have to know
the scope (or binding) where to search - the name alone is not
sufficient. However, for the problem you are trying to solve this is
not necessary.
The question is: what are you trying to achieve?
Thank you for asking. I was wondering how to update relations(imagine a
social networking site) between objects of a single Class. I hope this
will clarify why I want to access the variable of the object with its
instance variable. This how far I got last night:

class Foo

attr_accessor :name, :some_id, :relations

def self.update_relationship(foo1, foo2)
# code that adds @relations for foo1, and foo2 and updates it with
# it's own MINUS its own :some_id, and updates other @some_id's
included
# in foo1.relations + foo2.relations.
end

def self.find_by_some_id(some_id)
found = nil
ObjectSpace.each_object(Foo) { |o| found = o if o.oid == oid}
found
end

def to_s
@name
end

end


(create two objects):

John = Foo.new('John', 1,[])
Dave = Foo.new('Dave', 2,[])

(create a relationship between the two):

Foo.update_relationship(John, Dave)

John.relations -> [2]
Dave.relations -> [1]


Let's assume that along the line more objects are created and a new
relationship is created with John.(I'm just going to create a new object
and populate it's @relations instance variable, so the variables are
visible)

Steve = Foo.new('Steve', 104, [55, 77])

Foo.update_relationship(Steve, John)

John.relations -> [2, 55, 77, 104]
Steve.relations -> [1,2,55,77]

...well, that's good, but all the other objects (with @some_id 2, 55 and
77) would have to be updated right? For starters, Dave, the second
object (with @some_id = 2) is currently still:

Dave.relations -> [1]

Where it has to be updated to [1, 55, 77, 104]

So in order to access the Dave object, I only had 2, it's @some_id
instance variable to access it. Now, since I included the variable name
in the instance variable I can access the Dave object with the
find_by_some_id class method, and
get the @name instance variable which is the same as the variable (THIS
IS WHERE I THOUGHT IT WAS NOT A RUBYIST SOLUTION)

I'm going to read a little more and see if I can use the object's
#object_id to do all of this.
Note that because Ruby objects are passed as references, you generally
don't need to keep relationships using an identifier, you can just
keep a list of the "related" objects in an instance variable (the code
becomes less clear when you store an identifier instead of the object
itself, you probably aren't saving space, and you are probably hurting
performance by necessitating a method call to lookup the actual object
from the identifier.)

Adding to that, Aki, if you need to maintain relationships more often
then you could follow a similar approach as has been taken with
attr_accessor and write methods that generate the code for relationship
maintenance. E.g.

class Module
def one_to_one(name, cl)
module_eval %Q{
def #{name}=(x)
# logic to set relationship consistently
end

def #{name}
@#{name}
end
}

cl.module_eval %Q{
# similar for the other side
}
end
end

and then

class Foo
one_to_one :parent, Foo
end

I guess something like this does exist already. You can check the RAA.

If you use ActiveRecord for persistence you get these things for free.

Kind regards

robert
 
A

Aki Wakabayashi

Thank you Robert.

Sorry for the late reply. It took me a while to understand your
code since I only started to code in Ruby about a month ago.

class Module
def one_to_one(name, cl)
module_eval %Q{
...

class Foo
one_to_one :parent, Foo
end

If you use ActiveRecord for persistence you get these things for free.

I looked into this and it seems to fit my needs. Also, thank you for
telling me about RAA. I didn't know of it's existence until you
mentioned it.

I'm not using Ruby for projects(yet), but the more I dive into it the
more
flexible it seems and it's fun. I hope I can be able to come up with
code like
the one above with a couple more months of practice.

Aki
 

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

Forum statistics

Threads
473,982
Messages
2,570,189
Members
46,735
Latest member
HikmatRamazanov

Latest Threads

Top