Notes on basic learning of ruby metaprogramming

Time:2021-10-21

Note 1:
The code contains variables, classes and methods, which are collectively referred to as language construct.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# test.rb
class Greeting
 def initialize(text)
  @text = text
 end
 
 def welcome
  @text
 end
end
my_obj = Greeting.new("hello")
puts my_obj.class
puts my_obj.class.instance_methods(false) #false means not inherited
puts my_obj.instance_variables
 
result =>
Greeting
welcome
@text

Summary:
The instance method inherits from the class, and the instance variable exists in the object itself.
Classes and objects are the first type of values in ruby.

Application example:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
mongo API for ruby => Mongo::MongoClient
 
# testmongo.rb
require 'mongo'
require 'pp'
 
include Mongo
 
# the members of replcation-set
# test mongodb server version 2.6.0
host = "192.168.11.51"
# The port of members
# If the port is 27017 by default then otherport don't need to assignment
otherport = ""
port = otherport.length != 0 ? otherport : MongoClient::DEFAULT_PORT
 
opts = {:pool_size => 5, :pool_timeout => 10}
# Create a new connection
client = MongoClient.new(host, port, opts)
 
# puts client.class
puts client.class.constants
puts client.instance_variables
puts client.class.instance_methods(false)

Output separately

?
1
Constant, Instance Attribute, Instance Method

Note 2: dynamic call
When you call a method, you actually send a message to an object.

?
1
2
3
4
5
6
7
8
9
10
class MyClass
 def my_method(args)
  args * 10
 end
end
obj = MyClass.new
 
puts obj.my_method(5)
puts "**"
puts obj.send(:my_method, 6)

 

result:

?
1
2
3
50
**
60

You can use object #send() instead of the dot marker to call MyClass #my_ Method() method:

?
1
obj.send(:my_method, 6)

The first parameter of the send () method is the message to be sent to the object, which can be a symbol (: symbol) or a string. Other parameters will be passed directly to the calling method.
The technology that can dynamically decide which method to call becomes dynamic dispatch.

Note 3: the difference between symbols and strings
1. The symbol is immutable, and the characters in the string can be modified.
2. The operation for symbols is faster.
3. Symbols are usually used to indicate the name of things.
For example:

?
1
2
3
4
5
puts 1.send(:+, 4) => 5
String#to_sym(),String#intern() => string to symbol
String#to_s(),String#id2name() => symbol to string
"caoqing".to_sym() => :caoqing
:caoqing.to_s() => "caoqing"

The method of using pattern dispatch in dynamic dispatch.

?
1
2
3
puts obj.class.instance_methods(true).delete_if{ |method_name| method_name !~ /^my/}
result =>
my_method

Note 4: dynamic definition
Using module #define_ The method () method defines a method.

?
1
2
3
4
5
6
7
class MyClass
 define_method :my_method do |args|
  args * 3
 end
end
obj = MyClass.new
puts obj.my_method(10)

result:30

Singleton methods allow you to add a method to a single object. singleton methods

?
1
2
3
4
5
6
7
8
9
# test.rb
str = "My name is caoqing."
def str.title?
 self.upcase == self
end
 
puts str.title?
puts str.methods.grep(/^title?/)
puts str.singleton_methods

result:

?
1
2
3
false
title?
title?

Note 5:
The essence of class method is that class is an object and class name is a constant. Calling a method on a class is the same as calling a method on an object:

?
1
2
obj.my_method
Cla.class_method

Duck typing: whether the object can respond to methods, which can be ordinary methods or singleton methods.
The essence of class methods is that they are a singleton method of a class.

?
1
2
3
def obj.method
 # method body
end

OBJ can be an object reference, a constant class name, or self.

Class macro
RubyThe object has no attributes. You can use the mimicry method to define attributes.
Module#attr_* () method to define the accessor. Class macros are not keywords but methods.

Eigenclass
The singleton method looks for places in the ancestor chain that cannot be saved according to the conventional method. Obj is an object that cannot be saved or exist in the class. Otherwise, all instances can share this method.
Object has a unique hidden class called its eigenclass.
Enter the scope of eigenclass:

?
1
2
3
class << obj
 code
end

If you want to get the reference of eigenclass, you can return self when leaving the scope:

Appendix:
Class variable, instance variable, class method, instance method difference
@@                             : Var class variable
@                             : Instance variable
self(?clas,::).method         : Class method
method                         : Example method

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# test.rb
class 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
 end
end
 
obj = Foo.new
# obj.method01   => (NoMethodError)
 
obj.putsname   => lion
 
Foo.method01
Foo.method02
Foo.method03
obj.putsname

result:

?
1
2
3
4
5
6
7
8
9
lion
cat
cat
tiger
tiger
dog
dog
 
dog