📜 ⬆️ ⬇️

Let's beat Ruby together! Drop eleventh

Another drop in our glass is Ruby ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ). Let's talk about self , working with CSV and exception handling.

When describing and discussing computer programs, we often use figurative and human metaphors. For example, we say that we are in a class or returning from a method call. Sometimes it makes sense to speak in the second person, for example, object.respond_to?("x") : “Hey, object, will you answer ? And while the program is interpreted, the context changes again and again.

Some objects always mean the same thing, for example, numbers and keywords like def and class . However, the meaning of most elements depends on the context.

self and current object


One of Ruby's cornerstones is the current object, accessible via the self keyword. At each moment of the program there is only one self , this object can be recognized using several rules. First of all, you need to know the context, its types are few, here they are: the top level, the class definition blocks, the module definition blocks, and the method definition blocks.
')
The highest level refers to code written outside of any classes or modules. For example, if we open a new .rb file and write only x=1 , then we will create a top-level local variable . If we write
def m
end

then we get the top level method. At the highest level, Ruby provides us with a start (start up) self and, in an attempt to identify it, will return main . main is a special term that uses the self object by default when referring to itself.

In the definition of a class or self module - the object of the class itself, here's a demo:
class C
puts "Started class C:"
puts self # C
module M
puts "Module C::M:"
puts self # C::M
end
puts "Back C:"
puts self # C
end
self inside the definition of the instance method is tricky, and that's the point. When the interpreter reads the def/end block, it determines the method immediately. However, the code inside the method is executed only when it is called by the object, which will be self for this method.

Here is a small summary of the self behavior:

image

Db in .txt


Many applications need to store and manipulate data. Sometimes files are opened for this, necessary changes are made and the result is displayed on the screen or saved back to a file. In some situations, however, a database is required. A database is a system for organizing and storing data on a computer in a systematic way. The database can be simple as a text file that is manipulated by the program itself or complex, for example, it can consist of terrabytes of data distributed on dedicated servers. By the way, Ruby can be used in this case too, but we will consider the variant with the simplest database.

The database can be a simple text file, as in the case of CSV (Comma-Separated Values), where for each data item you can store attributes separated by commas. Let's create a file db.txt , in which we write the CSV data, for example, such:

Fred Bloggs,Manager,Male,45
Laura Smith,Cook,Female,23
Debbie Watts,Professor,Female,38

Each line is a separate person and each attribute is separated by commas.

Ruby contains the standard cvs library, which allows text files containing CSV data to be used as a simple database that is easy to manipulate. The library contains a class CSV, which will help us in our work. Load the data from the CVS file into the array using the read method of the CSV class and read and change that thread from the array:
require 'csv'
a= CSV . read ( 'db.txt' )
puts a. inspect
puts a [ 0 ][ 0 ] # Fred Bloggs
puts a [ 1 ][ 0 ] # Laura Smith
puts a [ 2 ][ 0 ] # Debbie Watts
a [ 1 ][ 1 ] = "Marine"
p ( a [ 1 ]) # ["Laura Smith", "Marine", "Female", "23"]

Now that we have the data we need, we need to save the CSV back, the csv module will do everything for us:
CSV . open ( 'bd.txt' , 'w' ) do |csv|
a. each do |a|
csv << a
end
end


Exceptions


In any program, there are moments when things are not going the right way: people enter incorrect data, files that you rely on do not exist (or you do not have access rights to them), memory runs out, etc. There are several ways out of similar situations. The easiest way to exit the program is when something wrong happened.

A less radical solution is that each method must return something like status data that indicates whether the processing was successful, and then you need to test the data from the method. However, testing each result will make the code poorly readable.

Another alternative approach is to use exceptions. When something goes wrong (i.e. an exception condition appears), exceptions are thrown. At a high level, the program will have a piece of code (exception handler), which will monitor the appearance of such a signal and respond to it in a certain way.

Also in one program there can be many exception handlers, each of which handles certain types of errors. An exception passes through all the handlers until it meets the required one, if it does not exist, the program closes. This behavior is in C ++, Java and Ruby.

Imagine a text editor. The user must enter the name in the SaveAs dialog and click . Since the user himself decides what data to enter, we can not know whether he has the right to write this file, whether there is free space on the disk. We will use exceptions:
text = editor ()
location = ask_user ()
begin
File . open ( location, w ) do |file|
save_work ( file, text )
end
rescue
puts " . : #{$!}"
end

Now if something goes wrong, the program will not complete the work, the data will not be lost and we will have a second chance. Everything between begin and rescue is protected. If an exception occurs, control is transferred to the block between the rescue and end . Global variable $! sends an error message and it is displayed on the screen. In order to control only certain types of exceptions, we write out from in rescue . For example, to handle only errors when writing a file, use the expression rescue IOError . If we want to catch several types of exceptions in one handler, then we list them separated by commas, or (which is more convenient) to write a handler for each type:
rescue IOError
puts -- $!.
rescue SystemCallError
puts -- $!.
end


Epilogue


Yes, I do not forget about pure Ruby and as far as possible and necessary I will continue to write. Maybe the pieces are jerky, but I am writing what is of interest at the moment - I hope you will like it too. As always - waiting for comments!

Source: https://habr.com/ru/post/50151/


All Articles