Помните, в прошлой части была схема взаимодействия модулей? Теперь пришло время рассмотреть её подробнее:

image

Для первоначального обучения всех желающих есть учебник «Язык Lua за 15 минут» (советую постоянно держать её открытой). Здесь я постараюсь рассматривать детали, которые относятся к проекту и не упоминаются в учебниках — только в справочниках и форумах (по возможности).

Для понимания кода нужно принять во внимание следующие особенности разработки на Lua:
  • Язык разрабатывался, как система обработки семантических и числовых массивов данных.
  • В языке большое количество конструкций и функций, предназначенных для парсинга информационных потоков (да-да!)
  • И самое главное — практически все виды сложных данных представляют собой табличные области. В прямом смысле!
  • Таким образом, опять-таки, все усложнённые объекты представляют собой так называемые метатаблицы — это массивы, которые хранят в себе описание и информацию экземпляра. Вложенность метатаблиц может быть поистине феерической!


Что такое модуль на языке Lua? Это скрипт, оформленный определённым образом, позволяющим ссылаться на него из текущего местоположения.

Пример кода из модуля баланса:
local saldo = {} --[[ Экземпляр определяется локально, дабы никто, кроме самого экземпляра, не имел к ней прямой доступ. --]]

function saldo.common()

--[[ Расчёт баланса по совокупности всех документов. --]]

        end

function saldo.customer()

--[[ Функция расчёта баланса на клиента. --]]

        end

return saldo --[[ Возвращаем экземпляр старшему модулю. --]]


Вы видите в начале модуля определение "local saldo = {}" — таким образом мы создаём экземпляр метатаблицы. Все дальнейшие данные — описание функций, циклы, переменные, возвратные значения — будут передаваться в этот метамассив. Массив создаётся локальным, что позволяет запускать его только в текущем модуле, из-под которого он определён. Пример:
ezhi = {}
petrucco = {}
babushka = {}

--[[ Самая "милая" ошибка - когда ты забываешь определять метатаблицу и пишешь классы. Сидишь потом, по два часа мучаешься ... --]]

function ezhi.sobak()

--[[ А Ежи бы собак ... --]]

        return "А Ежи взял и укусил Петруччо!"

        end

function petrucco.pochtmeister()

        local ezhi_bil = ezhi.sobak()
        babushka.fas( ezhi_bil )

--[[ Всё, теперь никто, кроме Петруччо, Ежи на бабушку не натравит ... --]]

        end

function babushka.fas(sobak)

        print(sobak)

        end

petrucco.pochtmeister()

end



В итоге мы получаем модуль, который спокойно сидит у себя в области определения и в общую программу не «светит». Главное — определить это модуль.

Пример модуля базы:
local database = {}

function database.link()
--[[ Инициализируем драйвер базы и подсоединяемся --]]        
        driver = require "luasql.sqlite3"
        env = driver.sqlite3()
        db = env:connect("standart.sqlite3")
        return db

        end

return database

Вот так осуществляется вызов модуля из исполнительного модуля:
local feedback = {}

function feedback.change()

        base = require "database" --[[ Здесь мы создаём экземпляр компонента luasql --]]
	query = base.link() --[[ А здесь мы его подключаем к базе. --]]

        str = 'SELECT feedback.number, feedback.phone, customer.name FROM feedback, customer WHERE feedback.customer = customer.number;' 
--[[ Это типичный запрос для баз без автоматической линковки таблиц --]]

        thread = query:execute(str)
	data = thread:fetch({}, "a") --[[ Тут мы создаём поток запроса и считываем его. Дальше уже издеваемся, как хотим. --]]

        while data do
                print("| № " .. data.number .. " | " .. data.name .. " | " .. data.phone .. " |" )
                data = thread:fetch(data, "a")
        end

--[[ Здесь мы построчно извлекаем эти данные. Всё по - старинке --]]

        end

return feedback

Ещё одна приятная особенность языка — процедуры и данные могут вызываются через точку. Это позволяет унифицировать обращения к элементам метатаблицы и извратить информационную схему совершенно любым удобным образом:
content = {} --[[ Всегда помним об этом! --]]
content[1] = {} --[[ И об этом тоже! --]]
сontent[1] = { name, family, surname } --[[ Можно делать так, --]]
content[1].name = {}
content[1].name = content --[[ Да, можно и так! --]]
content[1].family = {}
content[1].family = require "luasql.sqlite3" --[[ Отдышитесь, это просто функция. --]]
content[1].surname = {}
content[1].surname = { mother, father } 
content[1].surname.father[1] = {}
content[1].surname.father[1] = "name" --[[ И так до бесконечности! --]]

На закуску, пример запуска исполнительного модуля для телефоного справочника (из главного меню):
local cvs = {}

function cvs.run()


        ...
        feedback = require "feedback"

        ...

        init = 100 --[[ Есть у меня такой грех при инициализации переменных --]]

        while init > 0 do

                print("\n Выберите действие: \n")
                ...
                print(": 12 : Изменить телефон клиента")
                ...

                init = tonumber( io.stdin:read() ) --[[ Из-за слабой типизации языка требуется часто проводить конверсию данных. Консольный ввод всегда будет текстовым. --]]	

                if init == 1 then
			customer.add()
                ...
                elseif init == 12 then
                        feedback.change()
                ...
                elseif init == 0 then
                        print("\n Завершение программы. \n")
                else
                        print("\n Команда не корректна. \n")
                end

        end
        ...
        feedback = nil --[[ В Lua это обозначает пустое множество! А также средство для очистки "мусора" --]]
        ...
        init = nil

end

cvs.run() --[[ Запускаем главный модуль! --]]

return cvs

В следующей статье я подробно рассмотрю работу модуля базы и его взаимодействие с процедурами и данными.

P.S. Маленькая просьба — если хотите передать замечание по этому циклу статей, прошу предварительно прочитать статью «Разработка микро-учётной системы на lua, часть вторая. Постановка задачи», в которой я указываю условия разработки программы и функции, которые на неё возлагаются. Учитывайте это.
Поделиться с друзьями
-->

Комментарии (1)


  1. iSage
    27.05.2016 04:03
    +2

    Ugh.
    1) используйте метатаблицы
    2) всегда используйте local (если, конечно, переменная действительно не должна быть глобальной)