We will conquer Ruby together! Drop eleventh

    Another drop in our Ruby glass ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ). Talk about selfworking with CSV and handling exceptions.

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

    Some objects everywhere mean the same thing, for example, numbers and keywords like defand class. However, the meaning of most elements is contextual.

    self and current object


    One of the cornerstones of Ruby is the current object, accessible through the keyword self. At each moment of the program’s work, there is only one self; you can recognize this object using several rules. First of all, you need to know the context, there are few types of it, here they are: the top level, class definition blocks, module definition blocks, and method definition blocks.

    The highest level refers to code written outside of any classes and modules. For example, if we open a new .rbfile and write only x=1, then we will create a local variable of the highest level х. If we write
    def m
    end

    then we get the highest level method. At the highest level, Ruby provides us with a start up selfand, when trying to identify it, returns it main. mainIs a special term that uses the selfdefault object when referring to itself.

    In the definition of a class or module self, the class object itself, here is 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
    selfinside the definition of the instance method is tricky, and here's the thing. When the interpreter reads the block def/end, it determines the method immediately. However, the code inside the method is executed only when it is called by the object, which will be selffor this method.

    Here is a short summary of the behavior self:

    image

    Db in .txt


    Many applications need to store and manipulate data. Sometimes files are opened for this, the necessary changes are made and the result is displayed on the screen or saved back to the 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, which is manipulated by the program itself or complex, for example, consist of terabytes of data distributed on dedicated servers. By the way, Ruby can be used in this case too, however we will consider an option with the simplest database.

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

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

    Each line represents a separate person and the attributes of each are separated by commas.

    Ruby contains a standard cvs library that allows you to use text files containing CSV data as a simple database that is easy to manipulate. The library contains the CSV class, which will help us in our work. We load the data from the CVS file into the array using the readCSV class method and read and change the 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 times when things are not going the right way: people enter the wrong data, the files you are counting on do not exist (or you do not have access rights to them), memory runs out, etc. There are several ways out of such situations. The easiest way to exit the program is when something happened wrong.

    A less radical solution is that each method should return something like status data, which indicates whether the processing was successful, and then it is necessary to test the data received from the method. However, testing each result will make the code unreadable.

    Another alternative approach is to use exceptions. When something goes wrong (that is, an exception condition appears), exceptions are thrown. At a high level, the program will have a piece of code (an exception handler) that 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. The exception passes through all the handlers until it meets the required one; if it is not there, the program closes. This behavior exists in C ++, Java, and Ruby.

    Imagine a text editor. The user must enter a name in the dialog SaveAsand clickОК. Since the user himself decides what data to enter, we cannot know whether he has the rights 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 shut down, the data will not be lost, and we will have a second chance. Everything that is between beginand rescueis protected. If an exception occurs, then control is passed to the block between rescueand end. The global variable $!transmits an error message and it is displayed on the screen. In order to control only certain types of exceptions, we write from c rescue. For example, to handle only errors when writing a file, we use an expression rescue IOError. If we want to catch several types of exceptions in one handler, we list them separated by commas, or (which is more convenient) 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'm writing what interests you at the moment - I hope you like it too. As always - waiting for comments!

    Also popular now: