How to know which method created an object - ruby

In order to debug the methods or whatever that consume a lot of memory or create many objects, I need to measure the amount of variables by the memory consumed, etc., of every module, class or method, and then list them.
I want to know which method/class/module created a given object. I can write a parser, but I want to know if there is anything easier. Is that possible? I'm doing something like this:
ObjectSpace.each_object String do |obj|
method = get_parent_method_of(obj)
#....
end

Related

Better method for dynamically calling methods from input?

Is it better to use case/when things or the send method when dynamically calling methods based on user input? "better" based primarily on good coding practices.
input = gets.chomp
case input
when foo
foo
when bar
bar
end
versus
input = gets.chomp #Where hopefully the input would be 'foo' or 'bar'
send(input)
Your wording makes the question incredibly hard to read.
If I understood you correctly, you want to call methods based on user input. One alternative would be to check every possible value and call a method, the other - to use send directly.
First of all, notice that in your first example, you were calling method1 when the user entered foo. If you used send(input) you would have called foo instead. So they are not exactly the same.
You can achieve the same behavior by putting the input->method mapping in a hash like so:
dispatch = {foo: :method1, bar: :method2}
input = gets.chomp.to_sym
send(dispatch[input])
Another thing to note is that send in the original situation would call any method passed. You can instead whitelist the possible methods with the hash above and checking if such value exists:
send(dispatch[input]) if dispatch.key? input
Now to the question of when to use one or the other:
If you have 2, 3, 5 or so possibilities, prefer explicitly listing them. It will be faster, easier to read, easier to do static code analysis and so on.
If you have hundreds and thousands of different methods, prefer send. The costs outweigh the benefits of being DRY.
If the list of allowed methods is generated dynamically, you don't have a choice - use send. Examples:
You want to call methods to a given object and that object is different each time
You want to allow different methods depending on the user's permissions
You want to implement a REPL or some other awesome tool that has extremely dynamic needs
In general, don't use meta programming, unless there is significant gain or you don't have any other choice.
Unless you'd like your user to be able to call any method in the method lookup chain, including private methods which send can invoke, it probably makes sense for you to lock it down and only allow your users some methods.
If you don't specify an object to send to (like in your code above), Ruby will look at self for a method by that name and then use a normal method lookup. In other words self will be the first link in the method lookup chain. If you do specify an object, maybe an object that you create for that purpose for example, another option might be to use the methods like try or respond_to?.
input = gets.chomp
if defined?(input.to_sym)
send(input)
else
puts "No such thing!"

How does ruby Marshal.load work in the context of object restoration?

Serialization in Ruby can be done via the built-in Marshal module.
It provides methods for dumping an object and loading it.
I'm writing some serialization and wondering how an object can be loaded and all of its attributes restored, without actually calling the constructor?
For example, suppose I have a class
class Test
def initialize(id)
#id = id
end
end
Suppose I serialized it to (assuming a very simplified scheme that likely doesn't work in general)
{
"Test": {
"id": 3
}
}
When I want to load it back, I figured I'll just instantiate a new Test object and set its attributes. However, calling the new method will throw an exception because I didn't pass in an ID yet. Indeed, I haven't gotten to the point where I have read the ID, and in general, a constructor could take any arbitrary number of arguments, and I don't want to have to write custom logic for each and every class.
When you load the object via Marshal.load, it just somehow works. How does it work?
See this answer for an explanation of what the default Class::new does. You can mimic this behavior without adding the call to initialize. Instead, you would manually set the state of the class via something similar to instance_variable_set. Note, this is just a suggesstion of how you can implement this yourself. The actual Marshal.load is likely written in c, but it would do something similar.

In Ruby, how to init an instance variables in a constructor implemented as a class method?

I have an object PersistentObject which you can think of as plucked out of an ORM, it's an object which you can use natively in your programming language (agnostic to the backend), and it has methods load and save for committing changes to a database.
I want my PersistentObject to be faultable, i.e. I want to be able to initialize it as a lightweight pointer which server only to reference the object in the database. And when (if) the moment comes then I can fault it into memory by actually going to the database and fetching it. The point here is to be able to add this object to collections as a reference without ever needing to fetch the object. I also want to be able to initialize the object the old fashioned way with classic constructor and then commit it to the database (this is handy when you need to create a new object from scratch, rather than manipulating an existing one).
So I have an object which has multiple constructors: a classic one, and one that creates a fault based on the object GUID in the database. And when the object is initialized as a fault, I want instance methods to be able to access that state as an instance variable because operations on a fault are different to those on a fully loaded object. But for obvious reasons, I don't want clients messing with my inner state so I don't want to create an accessor for the ivar. So my question is, how do I init/set an ivar from a class method in an object instance in such a way that outside clients of my class can't mess with it (i.e. set its value to something else)?
Sorry for all the words, the code should make it a lot clearer. I've tried something which obviously doesn't work but illustrates the point nicely. Apologies if this is an elementary question, I'm quite new to Ruby.
class PersistentObject
def initialize(opts={})
#id = opts[:id] || new_id
#data = opts[:data] || nil
end
def self.new_fault(id)
new_object = PersistentObject.new
new_object.#fault = true #<----- How do you achieve this?
new_object
end
def new_id
#returns a new globally unique id
end
def fault?
#fault
end
def load
if fault?
#fault in the object from the database by fetching the record corresponding to the id
#fault = false
end
end
def save
#save the object to the database
end
end
#I create a new object as a fault, I can add it to collections, refer to it all I want, etc., but I can't access it's data, I just have a lightweight pointer which can be created without ever hitting the database
o = PersistentObject.new_fault("123")
#Now let's suppose I need the object's data, so I'll load it
o.load
#Now I can use the object, change it's data, etc.
p o.data
o.data = "foo"
#And when I'm ready I can save it back to the database
o.save
EDIT:
I should say that my heart isn't set on accessing that instance's ivar from the class method, I'd be more than happy to hear of an idiomatic Ruby pattern for solving this problem.
You could use instance_eval:
new_object.instance_eval { #fault = true }
or instance_variable_set:
new_object.instance_variable_set(:#fault, true)
If your goal is to set the instance variable then I agree with Stephan's answer. To answer your edit, another approach is to add another option to the constructor:
class PersistentObject
def initialize(opts={})
#id = opts[:id] || new_id
#data = opts[:data] || nil
#fault = opts[:fault] || false
end
def self.new_fault(id)
self.new(fault: true)
end
...
Unfortunately, Ruby's unconventional implementation of private/protected make them non-viable for this problem.
This is not possible. And I am not talking about "not possible in Ruby", I am talking about mathematically, logically impossible. You have two requirements:
Another object should not be allowed to set #fault.
Another object should be allowed to set #fault. (Remember, PersistentObject is just yet another object.)
It should be immediately obvious that those two requirements contradict each other and thus what you want simply cannot be done. Period.
You can create an attr_writer for #fault, then PersistentObject can write to it … but so can everybody else. You can make that writer private, then PersistentObject needs to use metaprogramming (i.e. send) to circumvent that access protection … but so can everybody else. You can use instance_variable_set to have PersistentObject set #fault directly … but so can everybody else.

Calling original new() method from within overridden new()?

I have a class whose initialize method gets data from a remote source, which it then uses to set its object attributes.
I'm expecting this class to be heavily used, possibly hundreds of times within a program. I'd like to reduce the overhead network calls by caching objects that have already been instantiated, which I'd then return to the user when they ask to instantiate that object again.
For that, I've been considering overriding the new method for this class. It would check to see if the cached object is available, and if so, return that reference. Otherwise, it would call the regular new method for the object, which would allocate memory and call initialize like usual.
If I override the new() method in a class, is it possible to call the original new method via something like super()?
Yes, super without parameters will call the parent method with the same parameters passed to the new method.
Or, you can cherry-pick parameters by adding them to super(p1, p2, ...).
Regarding what you want to do by remembering previous invocations, that's called "memoizing" and there is at least one memoize gem for it, or, you can write your own, depending on your needs.
It's pretty easy to do using a hash. Use the parameters used when invoking the new method as the key, and the value is the instance you want to return. Without examples of your code it's hard to come up with an example that's custom-fit, but this is a simple, untested, version:
def initialize(*args)
#memoizer ||= {}
return #memoizer[args] if #memoizer[args]
# do what you will with the args in this initializer,
# then create a new instance for the future.
#memoizer[args] = super(args)
end
The idea is that #memoizer remembers the "arity" of the call and automatically returns the result of similar calls. If that set of parameters haven't been seen before it'll compute and create the new instance and then return it.
This breaks down when the result could change with the same set of input parameters. You don't want to memoize database calls or anything using random or a date/time value, or that returns something outside your control. Trying to use it in those cases will return stale or wrong values unless you design in a method to sweep through and revalidate the #memoizer values periodically.
Also, there is no flushing mechanism, so #memoizer will only grow in size, and could possibly consume all available space given enough different input values. To deal with that you could also have a timestamp for when the value was added to #memoizer, and periodically purge entries that exceed a given lifetime. Only "live" values would remain in the hash then.
Useful information is at: "Memoize Techniques in Ruby and Rails".
either via super or via an alias_method chain
super is better if you sub-class
Check this: When monkey patching a method, can you call the overridden method from the new implementation?

Using Instance Variables in Class Methods - Ruby

I have a class something like below, and I used instance variables (array) to avoid using lots of method parameters.
It works as I expected but is that a good practice?
Actually I wouldn't expect that worked, but I guess class methods are not working as static methods in other languages.
class DummyClass
def self.dummy_method1
#arr = []
# Play with that array
end
def self.dummy_method2
# use #arr for something else
end
end
The reason instance variables work on classes in Ruby is that Ruby classes are instances themselves (instances of class Class). Try it for yourself by inspecting DummyClass.class. There are no "static methods" in the C# sense in Ruby because every method is defined on (or inherited into) some instance and invoked on some instance. Accordingly, they can access whatever instance variables happen to be available on the callee.
Since DummyClass is an instance, it can have its own instance variables just fine. You can even access those instance variables so long as you have a reference to the class (which should be always because class names are constants). At any point, you would be able to call ::DummyClass.instance_variable_get(:#arr) and get the current value of that instance variable.
As for whether it's a good thing to do, it depends on the methods.
If #arr is logically the "state" of the instance/class DummyClass, then store it in instance variable. If #arr is only being used in dummy_method2 as an operational shortcut, then pass it as an argument. To give an example where the instance variable approach is used, consider ActiveRecord in Rails. It allows you to do this:
u = User.new
u.name = "foobar"
u.save
Here, the name that has been assigned to the user is data that is legitimately on the user. If, before the #save call, one were to ask "what is the name of the user at this point", you would answer "foobar". If you dig far enough into the internals (you'll dig very far and into a lot of metaprogramming, you'll find that they use instance variables for exactly this).
The example I've used contains two separate public invocations. To see a case where instance variables are still used despite only one call being made, look at the ActiveRecord implementation of #update_attributes. The method body is simply load(attributes, false) && save. Why does #save not get passed any arguments (like the new name) even though it is going to be in the body of save where something like UPDATE users SET name='foobar' WHERE id=1;? It's because stuff like the name is information that belongs on the instance.
Conversely, we can look at a case where instance variables would make no sense to use. Look at the implementation of #link_to_if, a method that accepts a boolean-ish argument (usually an expression in the source code) alongside arguments that are ordinarily accepted by #link_to such as the URL to link to. When the boolean condition is truthy, it needs to pass the rest of the arguments to #link_to and invoke it. It wouldn't make much sense to assign instance variables here because you would not say that the invoking context here (the renderer) contains that information in the instance. The renderer itself does not have a "URL to link to", and consequently, it should not be buried in an instance variable.
Those are class instance variables and are a perfectly legitimate things in ruby: classes are objects too (instances of Class) and so have instance variables.
One thing to look out for is that each subclass will have its own set of class instance variables (after all these are different objects): If you subclassed DummyClass, class methods on the subclass would not be able to see #arr.
Class variables (##foo) are of course the other way round: the entire class hierarchy shares the same class variables.

Resources