Describes a class-like construct: a module. When designing a program, we divide the large components into small chunks, and you can mix and match the behavior of the objects.
Similar to classes, modules also bundle methods with constants. What is different is that there are no instances of the module. You can use a module that has a particular function in a class or in a particular object.
Class is a subclass of the module class, which means that all class objects should also be a module object.
10:26 * * *
Creating and using Modules
10:26 * * *
Module MyFirstModule
def Say_hello
Puts ' Hello '
End
End
After we create a class, we can create an instance of this class, and the instance can execute the instance method inside the class. However, there is no instance of the module, the module can be mixed (mixed in,mix-in,mixin) into the class, with the method include and prepend. An instance of such a class can use the instance method defined in the module.
Use the module defined above:
Class Moduletester
Include MyFirstModule
End
MT = Moduletester.new
Mt.say_hello
The Moduletester object above invokes the Say_hello method, which outputs a hello. This method is mixed into an instance method defined in the MyFirstModule within the Moduletester class.
Mixing modules in a class is like inheriting a superclass. For example, Class B inherits the Class A, so instances of Class B can invoke instance methods from Class A. Another example is the C class that mixes module m so that instances of Class C can invoke the method defined in module M. The difference between an inheritance class and a mixed module is that you can mix multiple modules in a class, and you can't let a class inherit multiple classes.
A module lets us share its code across multiple classes, because any class can mix the same module.
Create a module
The module provides us with a way to collect and encapsulate behavior. Here we can write a module that encapsulates the properties of a heap (stack) and then mixes the modules into one or more classes so that the behavior in the module is passed on to the object.
A heap (stack) is a data format that is backward, and goes out (Lifo:last in, first). Like a pile of plates, the first plate, the one that was last put in the pile. Often discussed with the heap also has a concept: queue, it is advanced, first out (FIFO), such as the Civil Affairs bureau window in front of the team, ranked in the first position of the people first to complete the formalities.
First put the following code in the Stacklike.rb file:
Module Stacklike
def stack
@stack | | = []
End
def add_to_stack (obj)
Stack.push (obj)
End
def Take_from_stack
Stack.pop
End
End
In the Stacklike module above, we use an array to represent the heap, which is stored in an instance variable, the name is @stack, and the instance variable can be obtained by means of stack. This method uses the conditional settings variable, | | = is an operator, and only if the variable is not nil or false will the value of the variable be equal to a particular value. This is the first time that stack is invoked, it will set @stack let it be equal to a blank array, the subsequent call again, @stack already have a value, it will go back to its value.
Calling the Add_to_stack method adds an object to the heap, which adds the object to the end of the @stack array. Take_from_stack deletes the last object in the array. The push and pop used in these methods are the instance methods in the Array class.
The Stacklike module we define is actually selectively implementing some of the behaviors that already exist in the array object, adding an element to the end of the array, and deleting the last element in the array. Compared to the heap, the array is more flexible and the heap cannot do all the array capable. For example, you can delete any sequence of items in the array, not in the heap, you can only delete the recently added elements.
Now we've defined a module that implements some of the behavior of the heap, which is to manage some projects, new projects can be added to the end, and the most recently added can be deleted. Let's take a look at how to use the module.
Mixing modules in a class
To do an experiment, create a file, the name is STACK.RB, add the following code:
Require_relative ' Stacklike '
Class Stack
Include Stacklike
End
The blending method here is include, which mixes the Stacklike module into the stack class so that the object of the Stack class has the method defined in the Stacklike module.
When you use require or load, the things you want to load are placed in a set of quotes, but the things you load with include and prepend do not need to use quotes. Because require and load use strings as their parameter values, include the name of the module, and the module's name is a constant. Require and load to find files on disk, include and prepend will operate in memory.
The name of the class is a noun, and the name of the module is an adjective. Stack objects are stacklike.
Do an experiment:
s = stack.new
S.add_to_stack (' Item 1 ')
S.add_to_stack (' Item 2 ')
S.add_to_stack (' Item 3 ')
Puts ' current objects in the heap: '
Puts S.stack
Taken = S.take_from_stack
Puts ' deleted the object: '
Puts taken
Puts ' now in the heap is: '
Puts S.stack
The execution will output:
Current objects in the heap:
Item 1
Item 2
Item 3
The object was deleted:
Item 3
Now in the heap is:
Item 1
Item 2
Continue using Modules
To do an experiment, create a file, the name is CARGOHOLD.RB (aircraft cargo), the code is as follows:
Require_relative ' Stacklike '
Class Suitcase
End
Class Cargohold
Include Stacklike
def load_and_report (obj)
print ' Loading object: '
Puts obj.object_id
Add_to_stack (obj)
End
def unload
Take_from_stack
End
End
CH = cargohold.new
SC1 = Suitcase.new
SC2 = Suitcase.new
SC3 = Suitcase.new
Ch.load_and_report (SC1)
Ch.load_and_report (SC2)
Ch.load_and_report (SC3)
first_unloaded = Ch.unload
print ' The first line in the plane is: '
Puts first_unloaded.object_id
The result of executing it is:
Loading object:70328907390400
Loading object:70328907390380
Loading object:70328907390360
The first line to go off the plane is: 70328907390360
12:00 * * *
Modules, classes and methods lookup
12:06 * * *
After the object receives the message sent to it, it will try to execute the same method as the information, either by definition in the class to which the object belongs, or by the superclass of the class, or by the modules that are mixed into the class. Send the message to the object what exactly happened?
method to find
The following example shows the inheritance of loading modules and classes:
Module M
def
Puts "' The ' method ' in module M"
End
End
Class C
Include M
End
Class D < C
End
obj = d.new
Obj.report
The example method is defined in module M, the C class is mixed with module M, Class D is a subclass of Class C, and obj is an instance of Class D, the object of obj can call the method.
From an object's perspective, suppose you are an object, someone sends you a message, you have to find a way to respond, and the idea is probably like this:
I'm a Ruby, someone sent me a ' news ' message, and I have to find a way in my way of finding a call, which may be in a class or a module.
I'm an example of class D. Do you have this method in class D?
No
Is there a hybrid module for class D?
No
Class D Super Class (superclass) C, which has no definition of the example method?
No
C-Class in the mixed module yet?
Yes, mixed modules M
Is there a method in the M module?
Yes
Well, just call this method.
Find this method search is over, can not find will trigger the error, this error is triggered by the Method_missing method.
Method with the same name
A method of the same name can appear only once in each class or module at any time. An object uses the method it first finds.
Do an experiment:
Module M
def
Puts ' in module M '
End
End
Module N
def
Puts ' in module N '
End
End
Class C
Include M
Include N
End
c = c.new
C.report
The result of executing it would be:
In module N, the
It is not valid to load the same module multiple times, so try this:
Class C
Include M
Include N
Include M
End
The results of the execution will still be:
In module N, the
12:49 * * * *
Prepend
1:40 * * *
A module that is loaded using the Prepend object is used first. That is, if a method is defined in both the class and the module, it will use the method in the module loaded with the prepend.
Take a look at an example:
Module Mefirst
def
Puts ' Greetings from the module '
End
End
Class Person
Prepend Mefirst
def
Puts ' greetings from the class '
End
End
p = person.new
P.report
The results of the execution will be:
Greetings from the module
Super
Do an experiment:
Module M
def
Puts ' The method of the ' in Module M '
End
End
Class C
Include M
def
Puts ' C-class in the method of the "
Puts ' triggers the previous level of the method '
Super
Puts "came back from calling Super."
End
End
c = c.new
C.report
The results of the execution are:
The method of the methods in class C
Triggers the previous level of the method
The method of the way in module M
Back from call Super.
C is an example of Class C, C.report is to send a message to C, the receipt of the beginning of the search method, the first found the C class, here defines the method of the case, so will go to execute it.
In the C class in the method, called super, meaning that even if the object found the information corresponding to the method, it must continue to find the next matching the method, the next match is in the module M defined in the method, and will go to execute it.
Try one more example of using super:
Class Bicycle
Attr_reader:gears,: wheels,: Seats
def initialize (gears = 1)
@wheels = 2
@seats = 1
@gears = Gears
End
End
Class Tandem < Bicycle
def initialize (gears)
Super
@seats = 2
End
End
There are two classes, Bicycle bicycles, tandem double bicycles, Tandem Bicycle class. A super is used in the Initialize method of the Tandem, which calls the Initialize method in the Bicycle class, which sets the default values for some properties. The two-person bike has two seats, so we have again set the default value of the @seats in the Initialize method of the Tandem.
The behavior of the super handling parameter:
Calling-super,super without parameters automatically forwards the method that the argument passes to it.
Call with a blank parameter-super (), and super does not send parameters.
Calls with specific parameters-super (A, B, C), and super only sends these parameters.
2:23 * * *
Method_missing method
14:35 * * *
The Kernel module provides an instance method called Method_missing, which is called if the object receives a message that does not know how to respond.
Try this:
>> obj = object.new
=> #<object:0x007fdef1958fa8>
>> Obj.blah
nomethoderror:undefined method ' blah ' for #<object:0x007fdef1958fa8>
From (IRB): 2
From/usr/local/bin/irb:11:in ' <main> '
We can cover method_missing:
>> def obj.method_missing (M, *args)
>> puts "You can't call #{m on this object, try something else." "
>> End
=>: method_missing
>> Obj.blah
You can't invoke blah on this object, try something else.
=> Nil
Combination Method_missing and Super
Usually we intercept the unknown information, and then decide how to deal with it, we can handle it, or send it to the original method_missing. Using super is easy to implement, look at an example:
Class Student
Def method_missing (M, *args)
If M.to_s.start_with? (' Grade_for_ ')
# return to the appropriate grade, based on parsing ' method name
Else
Super
End
End
End
The code above, if the method being invoked is started with grade_for, it will be processed, such as Grade_for_english. If not, the original method_missing is invoked.
Try a more complicated example. For example, we want to create a person class that can be used like this:
j = person.new ("John")
p = person.new ("Paul")
g = person.new ("George")
r = person.new ("Ringo")
J.has_friend (P)
J.has_friend (g)
G.has_friend (P)
R.has_hobby ("Rings")
Person.all_with_friends (P). Each do |person|
Puts "#{person.name} is friends with #{p.name}"
End
Person.all_with_hobbies ("Rings"). Each do |person|
Puts "#{person.name} is into Rings"
End
We want to output something like this:
John is friends with Paul
George is friends with Paul
Ringo is into rings
A person can have friends and hobbies, people can find out all the friends of a person, or have a hobby of all the people. These two functions are implemented using the All_with_friends and All_with_hobbies methods.
The All_with_* method on the person class can be modified using method_missing to define a piece of code in the class:
Class Person
Def self.method_missing (M, *args)
# code here
End
End
M is the name of the method, it can be started with all_with, or it can not, if we are to deal with it, if not to the original method_missing. Change this again:
Class Person
Def self.method_missing (M, *args)
method = m.to_s
If Method.start_with? (' All_with_ ')
# Processing requests here
Else
Super
End
End
End
Person object to track all of its friends and hobbies
The person class tracks all people
Everyone has a name.
Class Person
People = []
Attr_reader:name,: Hobbies,: Friends
Def initialize (name)
@name = Name
@hobbies = []
@friends = []
People << Self
End
def has_hobby (Hobby)
@hobbies << Hobby
End
def has_friend (Friend)
@friends << Friend
End
Every time a newcomer is instantiated, it is placed in the array of people. There are several read properties, Name,hobbies,friends.
The Initialize method has a name variable that is placed in the @name attribute and also initializes hobbies and friends, which are used in Has_hobby and Has_friend methods.
And then complete the person.method_missing:
Def self.method_missing (M, *args)
method = m.to_s
If Method.start_with? (' All_with_ ')
attr = Method[9..-1]
If self.public_method_defined? (attr)
People.find_all do |person|
Person.send (attr). Include? (Args[0])
End
Else
Raise Argumenterror, "Can ' t find #{attr}"
End
Else
Super
End
End
All the code is as follows:
Class Person
People = []
Attr_reader:name,: Hobbies,: Friends
Def initialize (name)
@name = Name
@hobbies = []
@friends = []
People << Self
End
def has_hobby (Hobby)
@hobbies << Hobby
End
def has_friend (Friend)
@friends << Friend
End
Def self.method_missing (M, *args)
method = m.to_s
If Method.start_with? (' All_with_ ')
attr = Method[9..-1]
If self.public_method_defined? (attr)
People.find_all do |person|
Person.send (attr). Include? (Args[0])
End
Else
Raise Argumenterror, "Can ' t find #{attr}"
End
Else
Super
End
End
End
j = person.new ("John")
p = person.new ("Paul")
g = person.new ("George")
r = person.new ("Ringo")
J.has_friend (P)
J.has_friend (g)
G.has_friend (P)
R.has_hobby ("Rings")
Person.all_with_friends (P). Each do |person|
Puts "#{person.name} is friends with #{p.name}"
End
Person.all_with_hobbies ("Rings"). Each do |person|
Puts "#{person.name} is into Rings"
End
The results of the execution will be:
John is friends with Paul
George is friends with Paul
Ringo is into rings