We've seen the invocation of a method before, and it will let the program jump from where the method is invoked to the definition body of the method. Programs are not run in a straight line, and the order of execution is influenced by some rules and some programming structures called control flows.
Ruby's control flow has the following:
Conditional execution (Conditional execution)-executes according to the authenticity of an expression.
Loops (looping)-code that repeats together.
Iteration (iteration)-when invoking a method, it is provided with a piece of code that can be invoked multiple times when it executes.
Exception (exceptions)-handles exception conditions.
Executing code by condition
Ruby provides a number of methods based on conditional program flow. There are two main categories, if there are case.
If and their friends
If used like this:
If condition
# condition, if it's true, execute the code here.
End
If can be nested using:
If condition
# condition, if it's true, execute the code here.
If Condition2
# Condition2, if it's true, execute the code here.
End
End
If it can be put on one line, use the keyword then after the condition, like this:
If x > Ten then puts X end
Or use a semicolon:
if x > 10; Puts X; End
Conditional execution often involves multiple branches, and you may want to do something when the conditions are successful and do something else when you fail. You can use else or elsif. The usage is this:
If condition
# condition is true to execute the code here
Else
# condition is false to execute the code here
End
Plus elsif can continue to add the criteria to be judged:
If Condition1
# Condition1 is true to execute the code here
Elsif Condition2
# Condition1 is False
# Condition2 is true to execute the code here
elsif Condition3
# Condition1 and Condition2 are false
# Condition3 is True will execute the code here
End
Do an experiment:
Print "Enter an integer:"
n = gets.to_i
If n > 0
Puts "you entered a positive number."
elsif N < 0
Puts "you entered a negative number."
Else
Puts "The number you entered is 0."
End
Try again the negative form of the condition, you can use NOT and!, first try not:
If not (x = = 1)
Try again! Resolution
if! (x = = 1)
Unless with if not with if! The effect of the same, try unless:
Unless X ==1
19:59 * *
21:15 * *
If you can also use this:
Puts ' big number! ' if x > 100
The above code can be interpreted as:
If x > 100
Puts ' big number! '
End
Unless can also be used in this way:
Puts ' big number! ' unless x <= 100
If an if statement succeeds, the value of the entire declaration is represented by the successful branch, and an experiment is done:
x = 1
If x < 0
Negative
elsif x > 0
Positive
Else
' 0 '
End
IRB will tell you that the value of the if whole declaration above will be the string ' positive '. If the if declaration does not succeed, it returns nil.
21:37 * *
Allocation in a conditional subject
September 9, 2016 8:52 * * *
Allocation syntax and conditional expressions intersect at two points, in the body of the conditional expression, the allocation may or may not occur, and on the condition test:
if x = 1
y = 2
End
x = 1 is the assignment in the conditional test, and y = 2 is the assignment in the conditional body.
Allocation in a conditional subject
The compilation language has a compile-time, and run-time two statements. Ruby is a scripting language, and the interpreter parses the code before running the script, and then makes some decisions, such as identifying and configuring local variables.
The Ruby interpreter sees this form: identifiers, Equals, values, like this:
x = 1
The interpreter assigns a space to the local variable x.
Look at this example:
If False
x = 1
End
P X
P y
In the example above, the action to assign X was not executed because it was wrapped in a failed condition test. But Ruby's interpreter sees x = 1, the inference program may use local variable x, and the interpreter doesn't care if x gets a value. It gives X a nil value, so the output x, the result is nil, but when you output a nonexistent local variable, a serious error occurs.
Distribution in conditional testing
Look at an example:
if x = 1
Puts ' Hi '
End
The thing above in the condition test is an assignment (x = 1), notice that it is not going to compare equality, like x = = 1. The distribution in the conditional test is the same as in other places, where the value of x is set to 1. The test itself considers the condition to be if 1, which is true, so that the object in the conditional body is executed, and a hi is output.
And you'll see a warning:
Warning:found = in conditional, should is = =
Ruby would have thought that if X =1 would have been successful and the subject would have been executed, Ruby would have thought you might have been wrong and would have given you a warning that the warning would suggest you use the = = operator, which would test whether two values are equal.
Ruby knows it's not a mistake to do this:
if x = y
Unlike x = 1, x = y is not necessarily successful as a condition test.
9:37 * * *
Case
9:51 * *
The case declaration begins with an expression, which is generally a separate object or variable. Then there are some possible matches, and each possible match is included in a when declaration with a code in it. Eventually only one match wins and then executes the code in this when.
To understand the use of case, let's take a look at an example:
print ' Exit? (yes/no): '
Answer = Gets.chomp
Case answer
When ' Yes '
Puts ' Goodbye! '
Exit
When ' no '
Puts ' we go on! '
Else
Puts ' don't know what you're saying, suppose it's no '
End
Puts ' Continue the program ... '
A case statement, use the keyword of the case to start, then is a when block, there is an optional else, end the case to use a last keyword. Only one match will eventually prevail and then execute the code inside it. In the example above, if "yes" is entered, the program exits. If it is "no" or any other value, the program can continue to run.
In one, you can add multiple matches:
Case answer
When ' y ', ' yes '
Puts ' Goodbye! '
Exit
# etc
In the example above, we used a comma to separate some possible matches in the when, and it was sort of like a or operator. The above means that if the input is "Y" or "yes", it prints "good-bye" and exits the program.
When is what happened
Each Ruby object has a case equality method, the name is = = =, the result of calling = = is to determine if a when is matched.
The above example, we can rewrite this:
If ' yes ' = = Answer
Puts ' Goodbye! '
Exit
elsif ' no ' = = Answer
Puts ' we go on! '
Else
Puts ' don't know what you're saying, suppose it's no '
End
Stand in infix operator (infix operator) angle See = =, it is actually the method of syntactic sugar:
If ' yes '. = = = (Answer)
Let's see why it returns True when answer contains Yes:
' yes ' = = = Answer
Calling the triple (= = =) method returns True because the third method is defined for the string. When you ask a string it itself is not a third and other string (string1 = = string2), you are asking the string of its own content, one to the other string to compare, if the match, it will return true, otherwise it will return false.
Each class can define its own method of = =, and can use its own case-equality logic.
Case/when is the object = = Other_object Camouflage, Object = = Other_object is actually object. The disguise of = = = = (other_object).
Object Case Behavior
Class Ticket
Attr_accessor:venue,:d ate.
Def initialize (venue, date)
Self.venue = Venue
Self.date = Date
End
def = = = (Other_ticket)
Self.venue = = Other_ticket.venue
End
End
Ticket1 = Ticket.new (' Town Hall ', "07/08/13")
Ticket2 = ticket.new (' Conference Center ', "07/08/13")
Ticket3 = Ticket.new (' Town Hall ', "08/09/13")
Puts "Ticket1 's position is: #{ticket1.venue}"
Case Ticket1
When Ticket2
Puts ' with Ticket2 in one place '
When Ticket3
Puts ' with Ticket3 in one place '
Else
Puts ' no match '
End
The results of the execution are:
Ticket1 's position is: Town Hall
In the same place as Ticket3.
return value
If there is a success in the WHEN/ELSE clause, the return value of the case declaration is the result of executing the code in the double sentence. If all the matches fail, the entire declaration returns to nil.
10:40 * * *
Loops
11:02 * * *
Unconditional loop
Use loop, like this:
Loop Codeblock
There are two forms of code block, one using curly braces ({}) and one using do and end operators. The following examples illustrate both of these forms:
Loop {puts ' looping forever! '}
Loop do
Puts ' looping forever! '
End
You can't let the cycle go on forever, you need to let it stop at some point.
Control loop
Use break keyword:
n = 1
Loop do
n = n + 1
Break if n > 9
End
Use next to skip the current loop:
n = 1
Loop do
n = n + 1
Next unless n = 10
Break
End
Conditional loops
The key word for conditional cycling is while and until.
While
A condition that loops if true. Starts with a while, ends, and the code between them is what each loop does:
n = 1
While N < 11
Puts N
n = n + 1
End
Puts ' Done! '
The above code output is:
1
2
3
4
5
6
7
8
9
10
Complete!
N < 11 The condition is true and the loop will be executed. The value of n increases by 1 each time the loop is cycled.
While can also be put to the end of the loop, to match the use of Begin/end keywords:
n = 1
Begin
Puts N
n = n + 1
End While N < 11
Puts ' Done! '
While the start and end are somewhat different, if you place the while at the beginning, if the condition is false, the loop will not be executed once. But if you put the while to the end, if the while condition is false, the loop is executed once.
Until
n = 1
Until n > 10
Puts N
n = n + 1
End
The body of the loop is executed until the condition is true.
While and until modifiers
Use until:
n = 1
n = n + 1 until n = 10
Puts ' count to 10! '
You can also use the while:
n = 1
n = n + 1 while n < 10
Puts ' count to 10! '
Do an experiment:
A = 1
A = 1 until true
The value of a is still 1, because true is already true.
And do an experiment:
A = 1
Begin
A + + 1
End until True
The code in the middle of the begin and end is executed once.
Loops the value of a list
Do an experiment:
numbers = [1, 2, 3]
For N in numbers
Puts N
End
The results of the execution are:
1
2
3
11:30 * * *
Iterations
6:51 * *
The raw material of the iterator
The method is invoked on an object, and control is passed to the body of the method (a different scope), and after the method is executed, the control is returned to the point after the place where the method is invoked. To get to know two new structures, the code block and the keyword yield.
We have seen such an example before:
Loop {puts ' looping forever! '}
The code above will always output that information, think about it, what the hell is going on? Why does puts be executed in the loop? The answer is: loop is an iterator. An iterator is a Ruby method that calls this method with a bit of extra material and expects you to provide it with a block of code. A brace will be divided into a block of code.
The loop method can access the code in the code block, which means the method can call or execute the code block. To get your iterator to do this, you can use the keyword yield. Code blocks and yield are the main ingredients of an iterator.
Self-made iterator
Write a loop of your own:
def My_loop
While True
Yield
End
End
Or a little bit more simple:
def My_loop
Yield while true
End
Call it:
My_loop {puts ' my-looping forever! '}
To provide a block of code for My_loop, the method can give control to it, when the method of control to the code block, code block code will be run, after completion of control will be returned to the method.
Profiling method Calls
There are several forms of method invocation in Ruby:
Recipient object or Variable
Point
Method name
Parameter list (optional, default is ())
code block (optional, no default)
Note that the argument list and code block are two different forms of calling methods. Here are the legitimate Ruby method calls:
Loop {puts ' Hi '}
Loop () {puts ' Hi '}
String.scan (/[^,]+/)
String.scan (/[^,]+/) {|word| puts Word}
The difference between using a code block and not using a code block when calling a method is whether the method can be yield. If there is a block of code, the method can be yield, if not, it cannot, because there is nothing to yield.
There are ways to do something, whether you give it a code block or not. For example String#split, this method separates its string recipients according to the delimiters you pass to it, and then puts the detached elements in an array. But if you pass this method a block of code, split will yield the detached item to a block of code, in which you can easily process each substring, output it, put it in the database, and so on.
Curly braces with do/end code block
Do/end, and curly braces, can be divided into a block of code using both of these forms. Let's do an experiment:
>> array = [1,2,3]
=> [1, 2, 3]
>> Array.map {|n| n * 10}
=> [10, 20, 30]
>> Array.map do |n| n * Ten End
=> [10, 20, 30]
>> puts Array.map {|n| n * 10}
10
20
30
=> Nil
>> puts Array.map do |n| n * Ten End
#<enumerator:0x007ff60922ccf0>
=> Nil
Above the:
Puts Array.map {|n| n * 10}
The equivalent is:
Puts (Array.map {|n| n * 10})
Above the:
Puts Array.map do |n| n * Ten End
The equivalent is:
Puts (Array.map) do |n| n * Ten End
Using that version of Do/end is actually equivalent to:
Puts Array.map
Times
The Times is an instance method of an integer class that you can call this method on an integer. Run the code block n times and the final return value will also be n.
Try it on IRB:
>> 5.times {puts ' I love u '}
I love u
I love u
I love u
I love u
I love u
=> 5
Yielding give a block of code, return from a method, they are not the same thing, the times above can prove this very well. A method can be yield to its blocks many times, from zero to infinity. But each method can only return once it has done what it has to do. For example, the above example, the output 5 times I love u, completed after the return of a 5.
It's sort of like figure skating, jump up, do some spin in the air, and then hit the ground. No matter how many laps you turn in the air, you can only jump up once, landing also only once. Method makes the method run once, and then returns once. But in between them, it's like a rotating action in the air, and the method can be yield control to the code block 0 or more times.
>> 5.times {|i| puts "I Love u #{i}"}
I love u 0
I love u 1
I love u 2
I love u 3
I love u 4
=> 5
Create one's own times:
Class Integer
def my_times
c = 0
Until C = Self
Yield (c)
C + 1
End
End
End
Use the my_times you define:
>> 5.my_times {|i| puts "I Love u #{i}"}
I love u 0
I love u 1
I love u 2
I love u 3
I love u 4
=> Nil
Yield concept I still a little vague, such as the meaning of the word itself, I am a little fascinated, is "give up"? What does it mean to yield a value? is to produce a value? Bring a value?
each
Run each method on the object of a set, each of which yield each item in the collection into your code block.
Do a simple experiment with each operation:
>> array = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
>> Array.each {|e| puts "process #{e}"}
Processing 1
Processing 2
Processing 3
Processing 4
Processing 5
=> [1, 2, 3, 4, 5]
Do one more of your own:
Class Array
def My_each
c = 0
Until C = size
Yield (Self[c])
C + 1
End
Self
End
End
Use:
>> array = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
>> Array.my_each {|e| puts "process #{e}"}
Processing 1
Processing 2
Processing 3
Processing 4
Processing 5
=> [1, 2, 3, 4, 5]
9:06 * *
From each to map
September 10, 2016 9:10 * *
Music: "Everything'll Flow" http://music.163.com/#/song?id=28000793
The map processes an array of elements at once and brings each element to the code block at a time. The difference between each and map is that each returned a value of its recipient, and the map returns a new array. The new array is the same size as the original array, but the items in the new array are iterated back from the code block.
Try the map:
>> names = ["David", "Alan", "Black"]
=> ["David", "Alan", "Black"]
>> names.map {|name| Name.upcase}
=> ["DAVID", "ALAN", "Black"]
The result is a new array in which the position of each element in the array is the same as the original array, but is handled through a block of code. Map tells us that in an iteration, the code block returns the value that the method gives it. The returned value will be the value of the call yield.
In order to implement our own my_map, we have to arrange an accumulator array, and successfully execute the value returned by the code block into this array. Then we'll take this accumulator array as the result of calling My_map.
First, implement a simple version of the map feature:
Class Array
def My_map
c = 0
ACC = []
Until C = size
ACC << yield (Self[c])
C + 1
End
Acc
End
End
And then use our own definition of My_map:
>> names = ["David", "Alan", "Black"]
=> ["David", "Alan", "Black"]
>> names.my_map {|name| Name.upcase}
=> ["DAVID", "ALAN", "Black"]
Create a map on each basis:
Class Array
# put the definition of My_each here
def My_map
ACC = []
My_each {|e| ACC << yield (e)}
Acc
End
End
parameter and variable scope of block
The parameters in the code block are surrounded by vertical bars, and the method parameters are wrapped in parentheses.
First look at a method:
def args_unleashed (A,b=1,*c,d,e)
Puts ' parameters: '
P A,b,c,d,e
End
Use the code block method to modify the above method:
def block_args_unleashed
Yield (1,2,3,4,5)
End
block_args_unleashed do |a,b=1,*c,d,e|
Puts ' parameters: '
P A,b,c,d,e
End
The result of the output is:
Parameters:
1
2
[3]
4
5
The method definition opens a new use field, and the scope of the code block is a little more complex.
Do an experiment and see how much X is going to be output in the code block:
def Block_scope_demo
x = 100
1.times do
Puts X
End
End
The result of performing block_scope_demo output is 100.
And do an experiment:
def block_scope_demo_2
x = 100
1.times do
x = 200
End
Puts X
End
The result of performing block_scope_demo_2 output is 200. The inside of the block and the outer x are the same.
Let's look at an example:
def Block_local_parameter
x = 100
[1,2,3].each do |x|
Puts "parameter x is #{x}"
x = x + 10
Puts "redistribute x in the chunk, now it is #{x}"
End
Puts "on the outside X is still #{x}"
End
The result of the output is:
Parameter x is 1
Redistribute X in the block, now it's 11.
Parameter x is 2
Redistribute X in the block, now it's 12.
Parameter x is 3
Redistribute X in the block, now it's 13.
On the outside X is still 100
is not the same x in the block as the block, because X is used as an argument to the chunk. Even if X is reassigned within a chunk, it does not affect the outer x. That is, you can use any variable in the parameters of a block.
Sometimes you might want to use some temporary variables in the block, and they don't take arguments when calling blocks, and you don't want the variables that affect the outside definition in the block, you can do this:
def block_local_variable
x = ' Raw X '
3.times do |i;x|
x = i
Puts "in the Block X is now #{x}"
End
Puts "ended the block, now X is #{x}"
End
The result:
In the block, X is now 0.
In the block, X is now 1.
In the block, X is now 2.
The block is ended, and now X is the original X
A semicolon is followed by x, which means that the block uses its own x. The variables following the semicolon are not the parameters of the block, they are reserved names, the variables that you want to use temporarily in the block, and do not want to affect the variables that are already defined in the outside world.
10:53 * * *
Handling Errors
10:53 * * *
Ruby triggers an exception if it encounters an unacceptable behavior at run time (raising an exception).
Save the anomaly.
An exception is an instance object of the Exception class or its descendant class. Triggering an exception means stopping the execution of the program and then handling the exception encountered or quitting the program completely. Handling exceptions depends on whether you provide rescue.
Do an experiment:
Ruby-e ' 1/0 '
-e:1:in '/': divided by 0 (zerodivisionerror)
From-e:1:in ' <main> '
With a number divided by 0, the exception that appears is Zerodivisionerror, which is actually a descendant class of Exception. To see some common exceptions:
The default exception that is triggered by the Runtimeerror:raise method.
Nomethoderror: The invoked method does not exist in the object, method_missing triggers the exception.
Nameerror: The interpreter encounters a label that it does not understand.
IOError: Reads the stream that has been turned off, reads the read-only stream of these operations.
Errno::error: Related to File I/O.
TypeError: The method receives an argument that it cannot handle.
Argumenterror: There is a problem with the number of parameters used.
Rescue
Encountered exceptions can be saved using rescue. A begin and end, the middle of which is rescue:
print ' Enter a number: '
n = gets.to_i
Begin
result = 100/n
Rescue
Puts ' can't get it, did you enter 0? '
Exit
End
The result of the puts "100/#{n}" is #{result} "
Execute code, if you enter a 0, the program will trigger Zerodivisionerror, we use rescue to save, the way is to output a message, and then exit the program.
The above example rescue is StandardError, if you want to save a special mistake, you can do this:
Rescue Zerodivisionerror
Rescue in the method and code block
method is provided with an implicit begin/end in the code block. So you can do this:
def open_user_file
Print "File to open:"
filename = Gets.chomp
FH = File.Open (filename)
Yield FH
Fh.close
Rescue
Puts "Can't open the file you want!" "
End
The operation to open the file if an exception occurs, the control will be given to the rescue clause. Using Begin/end, you can better control which exceptions you want to handle:
def open_user_file
Print "File to open:"
filename = Gets.chomp
Begin
FH = File.Open (filename)
Rescue
Puts "Can't open the file you want!" "
End
Yield FH
Fh.close
End
Triggering an exception
Use raise plus the name of the exception you want to trigger.
def fussy_method (x)
Raise Argumenterror, "I need a number under 10" unless X < 10
End
Fussy_method (20)
The results of the execution are:
Demo.rb:2:in ' Fussy_method ': I need a number below 10 (argumenterror)
From Demo.rb:5:in ' <main> '
Rescue can save the above anomalies like this:
Begin
Fussy_method (20)
Rescue Argumenterror
Puts "unacceptable numbers"
End
The following two lines of code have the same effect:
Raise "Problem! "
Raise RuntimeError, "Question!" "
Catch an exception in the rescue
To give an exception object to a variable, you can use the => operator, plus the rescue command. There are some methods on the exception object, such as BackTrace and message methods. BackTrace returns an array that represents the call heap when an exception occurs: Method name, filename, line number. The message method returns information about the raise hint.
def fussy_method (x)
Raise Argumenterror, "I need a number under 10" unless X < 10
End
Begin
Fussy_method (20)
Rescue Argumenterror => E
Puts "This number is not acceptable."
Puts "BackTrace:"
Puts E.backtrace
Puts "information:"
Puts E.message
End
The results of the execution are:
This number cannot receive
BackTrace:
Demo.rb:2:in ' Fussy_method '
Demo.rb:6:in ' <main> '
Information:
I need a number under 10.
Ensure
If you want to read a line in a file, if a particular substring is not found in the line, a Argumenterror exception is triggered, and if found, the substring is returned. However, after completing the method you will want to turn off the file processing. You can do this:
def line_from_file (filename, substring)
FH = File.Open (filename)
Begin
line = Fh.gets
Raise Argumenterror unless Line.include? (substring)
Rescue
Puts "Invalid row"
Raise
Ensure
Fh.close
End
Return line
End
To create your own exception class
Your own exception class can inherit the Exception class:
Class Mynewexception < Exception
End
Raise Mynewexception, "There's been a new mistake!" "