1

Frequently, the same method X gets called from different objects A, B, C. Is it possible to get a name of the caller object(A, B, C) from inside method X

eg :

class Sample
  def method
    # what needs to be done here?
  end
end

n1 = Sample.new
n2 = Sample.new

n1.method #=> expected output is to print n1
n2.method #=> expected output is to print n2
Stefan
  • 109,145
  • 14
  • 143
  • 218
user2753200
  • 11
  • 1
  • 2

4 Answers4

5

No, this doesn't work. Imaging the following:

n1 = Sample.new
n2 = n1

n2.method #=> ambiguous, both n1 and n2 would be valid

You could assign a name to your instances instead:

class Sample
  attr_accessor :name
end

n1 = Sample.new
n1.name = :n1

n2 = Sample.new
n2.name = :n2


n1.name #=> :n1
n2.name #=> :n2
Stefan
  • 109,145
  • 14
  • 143
  • 218
  • 1
    Technically `n2.method` is not ambiguous syntactically. Instead Ruby's internal structures make it unresolvable (and possible not advisable in any case) to find which pointer was used. – Neil Slater Sep 06 '13 at 07:24
  • @NeilSlater is this possible in any language? – Stefan Sep 06 '13 at 08:22
  • I'd hate to say "never", but no I cannot think of a language where you can discover the variable name programmatically. Probably a few can be hacked to do so via caller stack and code introspection - something that may work in a majority of cases. Still this would an abuse of variable names even in languages where it was possible, and the OP probably has other ways of achieving whatever the unstated higher-level goal is. – Neil Slater Sep 06 '13 at 08:32
4

As others said, working with the object_id directly is most probably the much better approach.

Anyway, something along this line might work in your case:

class Sample
  def method(&b)
    eval("local_variables.select {|v| eval(v.to_s).object_id == #{object_id}}", 
         b.binding)
  end
end

n1 = Sample.new
n2 = Sample.new
n3 = n2

p n1.method {}         #=> [:n1]
p n2.method {}         #=> [:n2, :n3]
p Sample.new.method {} #=> []

It returns all (local) variables in the current scope referencing the callee object. If each of your objects is referenced by exactly one variable, this might be what you are looking for.

Suggested by Neil Slater: you can also use the gem binding_of_caller to simplify transferring the binding:

require 'binding_of_caller'

class Sample
  def method
    binding.of_caller(1).eval(
      "local_variables.select {|v| eval(v.to_s).object_id == #{object_id}}"
    )
  end
end

n1 = Sample.new
n2 = Sample.new
n3 = n2

p n1.method         #=> [:n1]
p n2.method         #=> [:n2, :n3]
p Sample.new.method #=> []

(tested with version 0.7.2 of the gem).

undur_gongor
  • 15,657
  • 5
  • 63
  • 75
3

Any object can be identified by its object_id:

class Sample
  def method
    puts self.object_id
  end
end

n1 = Sample.new
n2 = Sample.new

puts n1.object_id
n1.method

puts n2.object_id
n2.method

--output:--
2152302060
2152302060
2152302040
2152302040

Variable names...not so much.

7stud
  • 46,922
  • 14
  • 101
  • 127
0

Just returning self should work,

Here is an example:

class Sample
  attr_accessor :name
  def method
    puts self  
    puts self.name  
  end
end

n1 = Sample.new
n1.name = "Bangalore"
n2 = Sample.new
n2.name = "Chennai"


n1.method #=> expected output is to print n1
n2.method #=> expected output is to print n2


-------
Output: 
#<Sample:0x7f492f62c030> # n1 object
Bangalore # n1.name 
#<Sample:0x7f492f62bec8> # n2 object
Chennai #n2.name
Srikanth Jeeva
  • 3,005
  • 4
  • 38
  • 58
  • 1
    I think the OP is confusing variable name with object identity, and it is not 100% clear which is really required. Former is inadvisable to make use of (except perhaps in stack traces), latter is as per your answer, relatively straightforward. – Neil Slater Sep 06 '13 at 12:12