Open Class and Monkey patches
in Ruby, a class defines a method that does not differ from any other statement, and is executed on a line. The following example:
Class Example
def method_1
puts ' method 1 '
end
class Example
def method_2
puts ' Method 2 ' End end
In this case, when the class example is first defined, there is not a class called example, so Ruby starts to define the class, and when you define the class later, Ruby discovers that the class already exists and returns the class, not a new class.
Because of this feature, Ruby is inherently capable of opening an existing class and dynamically modifying its contents, even if it is a class of the standard class library. For example, you can add a method that removes punctuation and special characters from a string to the SDK's string class: To_alphanumeric
Class String
def to_alphanumeric
gsub/[^\w\s]/, ' End
'
h&& ^^ Ello. to_ Alphanumeric #==>hello
, then all string objects have the ability to "To_alphanumeric", which is generally referred to as open class technology.
The Open class technology described above actually implies a certain risk, in particular, when using open class technology to extend a standard class library in large systems, because many developers are extending classes, when multiple extension methods have the same name, the latter will always overwrite the front, causing the entire system to crash, The industry put this reckless modification of the class by the way abbreviated as a monkey patch (Monkey Patch). Therefore, when using open class technology, must be cautious.
Instance variables
in Ruby, the instance variable is stored in the object, however, it has no relationship to the class of the object, and when the instance variable is assigned to the object, the instance variable is generated, and plainly, the instance variable is like a hashmap on the object, each of which can be used with its own different hashmap , as the following example:
Class Person
def name
@name = ' Xianlinbox '
end
p = person.new
puts P.instance_variables #==>nil
p.name
puts P.instance_variables #==> @name
Method
as an object, there is a need for methods in addition to the instance variables (also called attributes). But in Ruby, the definition of a method is not in the object, but in the object's own class, because "objects that share the same class must also share the same method." However, it cannot be said that class has a method called "methods," because the method cannot be invoked using "Class.method", and that class has an instance method "methods", which means that the instance object of the class must be created and invoked by the instance object.
If you want to define a class method, you must prefix the class name with the following when you define the method:
Class Person
def person.name
@name = ' Xianlinbox '
end
The class itself is also an object
in Ruby, class itself is an object, and all the rules about objects apply to class.
Puts "Hello". Class #=> String
puts String.class #=> class
puts Class.class #=> class
puts Class.instance_methods (false) #=> [: superclass,:allocate,:new]
puts Class.instance_variables #=> Nil
Inheritance system of Class
Puts String.superclass #=> Object
puts Class.superclass #=> Module
puts Module.superclass #=> Object
puts Object.superclass #=> basicobjec
puts Basicobject.superclass #= > Nil
Basicobject is the root node of the inheritance system.
All classes inherit from object.
Class is an inheritance enhancement of module, adding new () and allocate () methods to create an instance.
Search and execution of methods
the methods of objects in Ruby are defined in the class, when an object wants to execute a method, the first thing to do is to find the method, and the Ruby compiler looks for the method by looking at the first step in its own class and, if not, along the ancestor chain (ancestors) of that class.
String.ancestors # => [String, comparable, Object, Kernel, Basicobject]
Why there are comparable and kernal, because of the mechanism of module, when a class has a module, the compiler places the module on the ancestor chain closest to the class, and the string class include the comparable module, Kernal is include in the object class.
The method executes with a recipient, and the method is executed in the recipient object, which is the so-called self object. In general, the self object is assumed by the last object that receives the method, in the definition of the class and module (and outside the definition of any method), and the Self object is held by a class or module.
Dynamic Invocation Method
the usual method is called "Object name. Method Name," and there's a cool feature in Ruby that you can use the Send () method to take the name of the method you want to call as a parameter so that you can decide which method to call when the code is run, until the last minute. This technique is called dynamic distribution (Dispatch). This technique is useful, for example, when there is a profile object in the project that is initialized according to the configuration file, and different users may set different values during use. It is common practice to determine which attribute the key value of a property corresponds to, and then call the corresponding set method as follows:
Config.name = v if isnameproperty? (k)
Config.password = v if ispasswordproperty? (k)
Config.port = v if isportproperty? (k)
...
Looking at such a pile of code that looks like a brother, can not help but create an impulse to castrate them. If you use a dynamic Invoke method, the code can be simplified as follows:
Load_config (' config.properties '). Each do |k, v|
Config.send ("#{k}=", V)
According to each key value obtained, the set method of the corresponding property is adjusted, the code is much more refreshing, and the load method is not required to be modified in the Future Extension config object.
Dynamic Definition Method
In addition to dynamic invocation methods, Ruby even supports the dynamic definition of methods by providing a method name and a block that acts as the body of a method by using the Module#define_method () method. Cases:
Class MyClass
define_method:d oublestring do |args|
args * 2
end
t = myclass.new
puts t.doublestring ("he") # => hehe
With this black spell, later, you can extract the different parts of a similar method as parameters, and then use a method definition to fix all the methods.
Method_missing () method
Ruby is a dynamic language, and the compiler does not detect the behavior of the method invocation, so you can invoke a method that does not exist. At run time, all calls that do not find the corresponding method call a method_missing () method defined in the Kernal module, so each object inherits the method. The Method_missing () method in Kernal throws a Nomethoderror exception, which is what the compiler does.
However, we can override this method and make it interesting. For example, to create a struct, when you want a new attribute, you just have to assign a value to it to magically produce it.
Class MyStruct
def initialize
@attributes = {}
end
def method_missing (name, *args)
attribute = name.to_s
if attribute =~/=$/
@attributes [attribute.chop] = Args[0]
else
@attributes [attribute] End End
s = mystruct.new
S.weibo = "@xianlinbox"
puts S.weibo # => @ Xianlinbox
This, from the caller's point of view, is no different from the normal method, but the actual receiver does not have the method of the corresponding method, the ruby term is called the Phantom Approach (Ghost method). For the Phantom method, in addition to customizing the method, you can forward the method to another object, and of course, you can wrap some of your own logic before and after forwarding, which is called dynamic Proxy, which is the same as the dynamic invocation mentioned earlier.
After using method_missing to process the Phantom method, all calls that do not exist will come here, which may cause some error messages to be not intuitive (you can't see the hint of nosuchmethod), so when using the method_missing scheme , be sure to limit its scope of use, and invoke the Super.method_missing method of the parent class, so that it does not belong to the scope of the report what is wrong or what is wrong.
Whiteboard classes and Retention methods
Each class has a bunch of methods inherited from the parent class, and when using dynamic Proxy technology, if a phantom method and the real method (which you don't expect to inherit) collide with the name, the latter wins, causing the system to complain. Therefore, in the use of dynamic Proxy technology, you can delete the majority of inherited methods in the proxy class, avoid the name conflict, delete the inheritance method of the class, is called Whiteboard class (Blank Slate), the way to delete the class method has 2, one is to call Module#undef_ Method methods, one is to invoke the Module#remove_method method.
In Ruby's object class, there are some methods that are used internally, and if redefined, or deleted, may cause Ruby to hang up somehow, in order to prevent this from happening, Ruby starts with "__" in front of these method names, which is called the retention method, When you try to modify these methods, Ruby gives a warning.