Ruby Metaprogramming Classes and BlankSlate Classes
Today I feel like going back to the foundation of Ruby "Classes". Classes are nothing but objects. This is the most distinguised aspect of Ruby which set it apart from other languages. 1. Class is object First we have to make sure that we understand 'object' and 'class' and 'methods' ...
Today I feel like going back to the foundation of Ruby "Classes". Classes are nothing but objects. This is the most distinguised aspect of Ruby which set it apart from other languages.
1. Class is object
First we have to make sure that we understand 'object' and 'class' and 'methods' clearly.
class MyClass def my_method @var = 1 end end obj = MyClass.new obj.class #MyClass
Here is the point: instance variable @var lives in object obj where method my_method lives in class MyClass. Instance_method lives in class because because different object use the same method.
Now the crucial point is: every class is an object of class Class, which in turn has 3 unherited instance methods [:new, :allocate, :superclass]. So as a result every classes has 3 method above at least. Let follow the following examples:
"ruby".class # => String String.class # => Class inherited = false Class.instance_methods(inherited) # => [:superclass, :allocate, :new]
BasicOject is the root class of Ruby. BasicObject is just created in Ruby 1.9 to create a BlankSlate class which we will discuss later.
String.superclass # => Object Object.superclass # => BasicObject BasicObject.superclass # => nil
Every class is just an object even 'BasicObject'
Oject.class # => Class BasicOject.class # => Class
Let see what is the superclass of Class
Class.superclass # => Module Module.superclass # => Object
So, a class is just module with three additional methods— new( ), allocate( ), and superclass( )—that allow you to create objects or arrange classes into hierarchies. Apart from these (admittedly important) differences, classes and modules are pretty much the same. Most of what applies to classes also applies to modules, and vice versa.
2. What is BlankSlate class?
For example, you have code like which implement method_missing one aspectof the magics of Ruby metaprogramming: We have class Phone.
class Phone def respond_to?(method) @data_source.respond_to?("get_#{method}_info" ) || super end def initialize(book_id, data_source) @id = phone_id @data_source = data_source end def method_missing(name, *args) super if !@data_source.respond_to?("get_#{name}_info" ) info = @data_source.send("get_#{name}_info" , args[0]) price = @data_source.send("get_#{name}_price" , args[0]) result = "#{name.to_s.capitalize}: #{info} ($#{price})" return "* #{result}" if price >= 100 result end end
And Class DataSource.
class DataSource def initialize end def get_display_info(phone_id) "Retina screen" end def get_display_price(phone_id) 40 end def get_cpu_info(phone_id) "2.16 Ghz" end def get_cpu_price(phone_id) 220 end end
If we run the following code:
my_phone = Phone.new(12, DataSource.new) my_phone.cpu # => "* Cpu: 2.16 Ghz ($220)" my_phone.display # => nil
It should display message
"Display: Retina screen ($40)" But on the contrary it show nil
Let's find out:
Object.instance_methods.grep /^d/ # => [:dup, :display, :define_singleton_method]
It seems that Object defines a method named display( ) (a seldom-used method that prints an object on a port and always returns nil). Computer inherits from Object, so it gets the display( ) method. The call to Phone#display( ) finds a real method by that name, so it never lands on method_missing( ). You’re calling a real, live method instead of a Ghost Method.
Wheneverthe name of a Ghost Method clashes with the name of a real, inherited method, the latter wins. If you don’t need the inherited method, you can fix the problem by removing it. To stay on the safe side, you might want to remove most inherited methods from your proxies right away. The result is called a Blank Slate, a class that has fewer methods than the Object class itself.
So we make some change to class Phone
class Phone instance_methods.each do |m| undef_method m unless m.to_s =~ /^__|method_missing|respond_to?/ end ... end
Now if you run code again everything is just fine.
We will meet more in the next post and more in depth on metaprogramming. I hope you enjoy the lesson. Finally I welcome any comments which will help improve my future post. Thank you. Please follow and subcribe.