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


#1

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 :slight_smile:


#2

Aki W. wrote:

…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’)”.


#3

Aki W. wrote:

Aki W. wrote:

…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’)”.

Be inspired!
http://www.juixe.com/techknow/index.php/2007/01/22/ruby-class-tutorial/


#4

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


#5

On Sun, Mar 8, 2009 at 2:55 AM, Aki W. removed_email_address@domain.invalid
wrote:

class Foo
‘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 :slight_smile:

Here’s one way (not terribly efficient):

class Foo
attr_accessor :oid
def initialize(oid)
@oid = oid
end

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

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

Foo.find(‘7a’) # => #<Foo:0x244c8 @oid=“7a”>

Regards,
Sean


#6

class Foo
attr_reader :key

@@instances = Hash.new {|h,k| h[k] = []}
[…]
def initialize(key_val)
@key = key_val
@@instances[key_val] << self
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 = {}

def initialize(key)
    @key = key
end

def self.instance(key)
    find(key) || Foo.new(key).tap {|o| @instances[key] =

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 = Foo.instance(“a”)
a1 = Foo.instance(“a”)
a2 = Foo.find(“a”)
p a.object_id, a1.object_id, a2.object_id


#7

On Sun, Mar 8, 2009 at 1:29 AM, Leo removed_email_address@domain.invalid wrote:

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.


#8

Le 8 mars 2009 à 03:55, Aki W. 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


#9

On 08.03.2009 05:57, Aki W. wrote:

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


#10

On Sat, Mar 7, 2009 at 6:55 PM, Aki W. removed_email_address@domain.invalid
wrote:

class Foo
‘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 :slight_smile:

Posted via http://www.ruby-forum.com/.

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 = Hash.new {|h,k| h[k] = []}

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

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

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

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


#11

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


#12

On Sun, Mar 8, 2009 at 8:32 AM, Aki W. removed_email_address@domain.invalid
wrote:

able to do what I wanted to by using the #object_id? I’m not sure at
I wanted to get access to ‘var’ by using it’s @some_id which is 77.
 attr_accessor :name, :some_id, :relations
  ObjectSpace.each_object(Foo) { |o| found = o if o.oid == oid}
(create two objects):

John.relations -> [2, 55, 77, 104]
So in order to access the Dave object, I only had 2, it’s @some_id

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.)


#13

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


#14

On 08.03.2009 19:01, Christopher D. wrote:

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.

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.

def self.update_relationship(foo1, foo2)
end
John = Foo.new(‘John’, 1,[])
Let’s assume that along the line more objects are created and a new

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