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

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
40527b1623d59294b7a75730bf9bd0b5?d=identicon&s=25 Aki Wakabayashi (akiwakabayashi)
on 2009-03-08 03:56
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 :)
40527b1623d59294b7a75730bf9bd0b5?d=identicon&s=25 Aki Wakabayashi (akiwakabayashi)
on 2009-03-08 04:00
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')".
0814ff69e309b033508b3c7f363236fd?d=identicon&s=25 Ian Trudel (backorder)
on 2009-03-08 05:10
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!
http://www.juixe.com/techknow/index.php/2007/01/22...
E1d641bfe4071a5413bac781f06d3fd1?d=identicon&s=25 Sean O'halpin (sean)
on 2009-03-08 05:10
(Received via mailing list)
On Sun, Mar 8, 2009 at 2:55 AM, Aki Wakabayashi <zzyzx2001@gmail.com>
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 :)

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
40527b1623d59294b7a75730bf9bd0b5?d=identicon&s=25 Aki Wakabayashi (akiwakabayashi)
on 2009-03-08 05:58
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
D7463bd611f227cfb2ef4da4a978a203?d=identicon&s=25 Christopher Dicely (Guest)
on 2009-03-08 09:54
(Received via mailing list)
On Sat, Mar 7, 2009 at 6:55 PM, Aki Wakabayashi <zzyzx2001@gmail.com>
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 :)
> --
> 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
87ef5d1e14b148eb596433bc17ffe690?d=identicon&s=25 Leo (Guest)
on 2009-03-08 10:31
(Received via mailing list)
> 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
D7463bd611f227cfb2ef4da4a978a203?d=identicon&s=25 Christopher Dicely (Guest)
on 2009-03-08 10:49
(Received via mailing list)
On Sun, Mar 8, 2009 at 1:29 AM, Leo <minilith@gmail.com> 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.
B57c5af36f5c1f33243dd8b2dd9043b1?d=identicon&s=25 F. Senault (Guest)
on 2009-03-08 11:20
(Received via mailing list)
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
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2009-03-08 14:31
(Received via mailing list)
On 08.03.2009 05:57, Aki Wakabayashi 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.h...

> 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
40527b1623d59294b7a75730bf9bd0b5?d=identicon&s=25 Aki Wakabayashi (akiwakabayashi)
on 2009-03-08 17:34
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
D7463bd611f227cfb2ef4da4a978a203?d=identicon&s=25 Christopher Dicely (Guest)
on 2009-03-08 19:04
(Received via mailing list)
On Sun, Mar 8, 2009 at 8:32 AM, Aki Wakabayashi <zzyzx2001@gmail.com>
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.)
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2009-03-08 22:56
(Received via mailing list)
On 08.03.2009 19:01, Christopher Dicely 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
40527b1623d59294b7a75730bf9bd0b5?d=identicon&s=25 Aki Wakabayashi (akiwakabayashi)
on 2009-03-09 15:25
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
This topic is locked and can not be replied to.