Any way to determine which object called a method?
As an option, there is a binding_of_caller
gem that allows you to execute code in context of any caller on the call stack (caller, caller's caller and so on). It's useful for inspecting (read do anything at any position on the call stack) call stack in development, as used in better_errors
.
Objects of class
Binding
encapsulate the execution context at some particular place in the code and retain this context for future use.– http://www.ruby-doc.org/core-2.1.4/Binding.html
Should I mention, this technique should only be used for debugging, fun or educational purposes, because it violates principles of OOP really badly.
Mostly because of eval
.
Let's prepare stuff:
require 'binding_of_caller' # I assume, you installed this gem already?
Get the immediate (closest on stack, hence 0
) caller instance:
binding.of_caller(0).eval('self')
...or even an immediate calling method:
binding.of_caller(0).eval('__method__')
If you need to get higher up the call stack, use numbers other than 0
for getting a caller's binding.
Awfully hacky. But if you really need this — there you go.
How to find the object that called a method in Java
Checking the callers of a method is a quite common request from inexperienced programmers. I'm surprised that it doesn't appear more often on SO. But it's a really incredibly bad idea (just check out the Java 2 (and perhaps worse earlier) Security Model).
There are few circumstances where it's important to implement this restriction. As Oli Charlesworth say, just don't do it. But let's assume that it is important, but we're not going to do stack inspection.
Let's start by assuming we trust the group. A working but nonsensical approach is to pass to the group an object standing in for the person that only the person can create. (Note Java language access restrictions are class-based. A different instance could create such a stand in, but the code would have to be within the Person
class.)
public final class Group { // Can't have a malicious subclass.
public void deregisterPerson(Person.Standin standin) {
Person person = standin.person();
...
}
}
public class Person { // May be subclassed.
public final class Standin { // Could be one per Person.
private Standin() { // Hide constructor from other outer classes.
}
public Person person() {
return Person.this;
}
}
private void groupDeregister(Group group) {
group.deregisterPerson(new Standin());
}
}
If we don't trust the group, then we could extend the stand-in to reference the group. This prevents a malicious group deregistering a person from other groups.
public class Group { // Can have malicious subclasses.
public void deregisterPerson(Person.GroupDeregister deregister) {
if (deregister.group() != this) { // Not equals...
throw new IllegalArgumentException();
}
Person person = deregister.person();
...
}
}
public class Person { // May be subclassed.
public final class GroupDeregister {
private final Group group;
private GroupDeregister(Group group) { // Hidden.
this.group = group;
}
public Person person() {
return Person.this;
}
public Group group() {
return group;
}
}
private void groupDeregister(Group group) {
group.deregisterPerson(new GroupDeregister(group));
}
}
Another approach is to make a "public" version of Person that can be exposed to others.
public class Person { // "PrivatePerson"
public PublicPerson publicPerson() {
return new PublicPerson(this);
}
private void groupRegister(Group group) {
group.registerPerson(this);
}
private void groupDeregister(Group group) {
group.deregisterPerson(this);
}
...
}
public class PublicPerson {
private final Person person;
public PublicPerson(Person person) {
this.person = person;
}
@Override public final boolean equals(Object obj) {
return obj instanceof Person && (Person)obj.person == person;
}
@Override public final int hashCode() {
return person.hashCode();
}
...methods, but no raw registration...
}
public class Group {
private final Set<Person> members = new IdentityHashSet<>(); // No Object.equals.
public void registerPerson(Person person) {
members.add(person);
}
public void deregisterPerson(Person person) {
members.remove(person);
}
public Set<PublicPerson> members() {
// This will be more concise in Java SE 8.
Set<PublicPerson> publics = new HashSet<>();
for (Member member : members) {
publics.add(member.publicPerson());
}
return unmodifiableSet(publics);
}
}
(Objects.requireNonNull
left out for "brevity".)
JS: Is there a way to tell what object called a function?
Can't you pass an ID to the Flash object when you instantiate it? (via a query string or params). Then you could use that ID in your JavaScript function calls.
Javascript: know which object function has been called
One approach could be to use a Proxy to create "tracked" objects where you intercept any method invocations:
function trackMethodCalls(obj) {
const handler = {
// anytime we do obj.someMethod
// we actually return the interceptedMethod instead
get(target, propKey, receiver) {
const method = target[propKey];
// we only do something special if we're working with a function
// on the object. If the property isn't a function we can just return
// it as normal.
if (typeof method !== 'function') {
return method;
}
return function interceptedMethod(...args) {
const result = method.apply(this, args);
console.log(
`${propKey}(${args.join(",")}) = ${JSON.stringify(result)}`
);
return result;
};
}
};
return new Proxy(obj, handler);
}
const obj = {
val: 2,
double(x) {
return this.val * x;
}
};
const trackedObj = trackMethodCalls(obj);
trackedObj.double(4);
get object on which a method was called in Python
If you never plan on reassigning math_ops
outside A
, this is fairly simple to do.
from modules import math_ops
class A():
def __init__():
self.math_ops = math_ops.B(self)
self.number = 1
modules/math_ops.py:
class B():
def __init__(self, creator):
self.creator = creator
def add_1():
creator.number += 1
I will mention it again in case you skimmed the first line, the following will generate unexpected results since B
is tracking the creator of the object rather than the caller.
a1 = A()
a2 = A()
a1.math_ops = a2.math_ops
a1.math_ops.add_1() # a2 is updated
If that looks like something you might wanna do, the answer is a tad more complicated. Here's my attempt:
from modules import math_ops
class A():
def __init__(self):
self._math_ops = math_ops.B(self)
self.number = 1
@property
def math_ops(self):
self._math_ops.set_caller(self)
return self._math_ops
@math_ops.setter
def math_ops(self, new_math_ops):
self._math_ops = new_math_ops
modules/math_ops.py:
class B():
def __init__(self, caller):
self.caller = caller
def set_caller(self, caller):
self.caller = caller
def add_1(self):
self.caller.number += 1
Related Topics
How to Get the Latest Record from Each Group in Activerecord
How to Avoid Putting the Magic Encoding Comment on Top of Every Utf-8 File in Ruby 1.9
Ruby/Rails - .Each Iterator Is Printing Entire Array at the End of the Loop
How to Cache a Calculated Column in Rails
Active Admin - Refresh Second Drop Down Based on First Drop Down, Ruby on Rails
How to Randomly Iterate Through a Large Range
Run Ruby Script in Elevated Mode
In Ruby, How to Check If Method "Foo=()" Is Defined
Ruby: Extracting Words from String
How to Set an Option as Selected Using Selenium Webdriver (Selenium 2.0) Client in Ruby
Ruby/Sinatra - Serving Up CSS, JavaScript, or Image Files
Ruby - Determining Method Origins
How to Access (Devise) Current_User in a Rspec Feature Test