Undefining class at runtime
This post explains undefining the class at runtime.
Im not gonna explain the live-cases where this might be used. Ask Uncle Google for that.
Lets jump in at d code directly.
When u create a new class, say “Person”, two things happen:
- A new object of type(class) Class is instantiated.
- A new constant called Person will be instantiated and will hold the value of the class-object created above.
Proof: Class Person;end;
Try, Person.class #=> Class. This means that the Person holds a value which is of class Class. (1 is proved).
Try, Person = 123 #=> Curses saying, Person is already initialized, which means Person is a constant. (2 is proved).
Now, All the constants(Person) and other are silently ducked into the class Object.
Proof: Object.class_eval{Person} #=> Person Class
So, we should understand by now that the newly created class Person resides as a constant of the class Object.
So if we could somehow remove that constant, then the class Person will also be removed.
There is a method called remove_const for the class Object.
So, try Object.remove_const : Person #=> Curses, NoMethodError: private method `remove_const’ called for Object:Class
This is becoz, remove_const is a private method of Object class.
So the worry now is, how to invoke a private method.
We have two solutions:
- Object.send(:remove_const , : Person)
- Object.class_eval{remove_const : Person}
Now try, Person.new. # Curses, uninitialized constant Person
Voila, job done. Very rarely does an ERROR MESSAGE makes us feel happy. Well, kind of an article.
You can learn much about class_eval from this very good article by Khaled.
add attribute at runtime
I’m all excited abt this post.
Coz this is something i learnt just now, and consider it my best learning till now in RUBY.
Q: How to add attributes to a class at runtime?
A:
class Class
def new_attr (attr_name)
class_eval {attr_accessor :"#{attr_name}"}
end
end
class_eval : Evaluates a string or a block in the context of the receiver, here the class.
Explanation:
1) We defined a new method to the CLASS called new_attr, which is intended to add new attributes at runtime.
2) This method needs the name of the new attribute to be passed.
3) In the definition, it calls class_eval, which means “DO SOMETHING AT THE CLASS LEVEL”
4) What to do is specified in the block after the class_eval, which says : attr_accessor “#{attr_name}”, which will become attr_accessor :name when we call new_attr(‘name’).
5) We know that attr_accessor is rails syntactic sugar to create the a specific instance variable, and its set/get (read/write) methods. So here, when we call new_attr(‘name’), its creating a new instance variable (@name) and 2 new methods ‘name” and “name=”.
Try this;
class Person; end;
This creates a bare class Person.
p = Person.new
Try, p.name, it throws an error cursing “Undefined method name”.
Its fairly expected coz, Person has no attribute called name.
Now, say Person.new_attr(‘name’)
now try, p.name, it will not curse you.
To check, try Person.singleton_methods.include?(“name”)
This says TRUE.
Hope this article comes handy.