Metaprogramming is a program that can operate other programs. for example, macros in C language are an advanced technique in programming. here we will take a look at the basics of Ruby Metaprogramming.
Note 1:
The code contains variables, classes, and methods, collectively referred to as language construct ).
# test.rbclass Greeting def initialize(text) @text = text end def welcome @text endendmy_obj = Greeting.new("hello")puts my_obj.classputs my_obj.class.instance_methods(false) #false means not inheritedputs my_obj.instance_variablesresult =>Greetingwelcome@text
Summary:
The instance method inherits from the class, and the instance variable exists in the object itself.
Both class and object are the first class values in ruby.
Application example:
mongo API for ruby => Mongo::MongoClient# testmongo.rbrequire 'mongo'require 'pp'include Mongo# the members of replcation-set# test mongodb server version 2.6.0host = "192.168.11.51"# The port of members# If the port is 27017 by default then otherport don't need to assignmentotherport = ""port = otherport.length != 0 ? otherport : MongoClient::DEFAULT_PORTopts = {:pool_size => 5, :pool_timeout => 10}# Create a new connectionclient = MongoClient.new(host, port, opts)# puts client.classputs client.class.constantsputs client.instance_variablesputs client.class.instance_methods(false)
Output separately
Constant, Instance Attribute, Instance Method
Note 2: Dynamic Call
When you call a method, a message is actually sent to an object.
class MyClass def my_method(args) args * 10 endendobj = MyClass.newputs obj.my_method(5)puts "**"puts obj.send(:my_method, 6)
Result:
50**60
You can use object # send () to replace the dot mark to call the MyClass # my_method () method:
obj.send(:my_method, 6)
The first parameter of the send () method is the message to be sent to the object. it can be a symbol (: symbol) or a string. other parameters are directly transmitted to the called method.
It can dynamically decide which method to call and become a Dynamic Dispatch.
Note 3: differences between symbols and strings
1. the characters in the string can be modified because they are immutable.
2. faster operations on symbols.
3. symbols are usually used to indicate the name of a thing.
For example:
puts 1.send(:+, 4) => 5String#to_sym(),String#intern() => string to symbolString#to_s(),String#id2name() => symbol to string"caoqing".to_sym() => :caoqing:caoqing.to_s() => "caoqing"
Pattern dispatch is used in dynamic dispatching.
puts obj.class.instance_methods(true).delete_if{ |method_name| method_name !~ /^my/}result => my_method
Note 4: dynamic definition
Use the Module # define_method () method to define a method.
class MyClass define_method :my_method do |args| args * 3 endendobj = MyClass.newputs obj.my_method(10)
Result:30
The single-piece method allows you to add a method to a single object. Singleton methods
# test.rbstr = "My name is caoqing."def str.title? self.upcase == selfendputs str.title?puts str.methods.grep(/^title?/)puts str.singleton_methods
Result:
falsetitle?title?
Note 5:
The essence of a class method. a class is an object and a class name is a constant. The method called on the class is the same as the method called on the object:
obj.my_methodCla.class_method
Duck Typing: whether the object can respond to a method. it can be a common method or a single-piece method.
The essence of class methods is that they are a single-piece method of the class.
def obj.method # method bodyend
Obj can be an object reference, a constant class name or self.
Class Macro)
Ruby objects have no attributes. you can use the pseudo-state method to define attributes.
Module # attr _ * () method to define the accessors. Class macros are not keywords but methods.
Eigenclass
The single-piece method searches for the saved place in the ancestor chain according to the conventional method. obj indicates that the object cannot be saved or exists in the class. otherwise, all instances can share this method.
The object has a unique hidden class called eigenclass of the object.
Enter eigenclass scope:
class << obj codeend
If you want to obtain eigenclass references, you can return self when leaving this scope:
Appendix:
Differences between class variables, instance variables, class methods, and instance methods
@: Var variables
@: Instance variable
Self (? Clas,:). method: Class method
Method: instance method
# test.rbclass Foo @@var = "lion" def self.method01 puts "cat" @name = "cat" @@var = "cat" puts @name end def self.method02 puts "tiger" @name = "tiger" @@var = "tiger" puts @name end def self.method03 puts "dog" @name = "dog" @@var = "dog" puts @name end def putsname puts @name puts @@var endendobj = Foo.new# obj.method01 => (NoMethodError)obj.putsname => lionFoo.method01Foo.method02Foo.method03obj.putsname
Result:
lioncatcattigertigerdogdogdog