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

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:

···

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

Aki Wakabayashi 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')".

···

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

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

···

On Sun, Mar 8, 2009 at 2:55 AM, Aki Wakabayashi <zzyzx2001@gmail.com> wrote:

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:

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

···

On Sat, Mar 7, 2009 at 6:55 PM, Aki Wakabayashi <zzyzx2001@gmail.com> wrote:

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:
--
Posted via http://www.ruby-forum.com/\.

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

···

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:

--
The me that you know doesn't come around much (Nine inch Nails,
That part of me isn't here anymore The Becoming)
All pain disappears it's the nature of my circuitry
Drowns out all I hear there's no escape from this my new consciousness

Aki Wakabayashi wrote:

Aki Wakabayashi 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!

···

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

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

···

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

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

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.

···

On Sun, Mar 8, 2009 at 1:29 AM, Leo <minilith@gmail.com> wrote:

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.

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

···

On 08.03.2009 05:57, Aki Wakabayashi wrote:

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

···

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

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

···

On Sun, Mar 8, 2009 at 8:32 AM, Aki Wakabayashi <zzyzx2001@gmail.com> wrote:

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

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.

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

···

On 08.03.2009 19:01, Christopher Dicely wrote:

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

···

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