Помните, в прошлой части была схема взаимодействия модулей? Теперь пришло время рассмотреть её подробнее:
Для первоначального обучения всех желающих есть учебник «Язык Lua за 15 минут» (советую постоянно держать её открытой). Здесь я постараюсь рассматривать детали, которые относятся к проекту и не упоминаются в учебниках — только в справочниках и форумах (по возможности).
Для понимания кода нужно принять во внимание следующие особенности разработки на Lua:
Что такое модуль на языке Lua? Это скрипт, оформленный определённым образом, позволяющим ссылаться на него из текущего местоположения.
Пример кода из модуля баланса:
Вы видите в начале модуля определение "local saldo = {}" — таким образом мы создаём экземпляр метатаблицы. Все дальнейшие данные — описание функций, циклы, переменные, возвратные значения — будут передаваться в этот метамассив. Массив создаётся локальным, что позволяет запускать его только в текущем модуле, из-под которого он определён. Пример:
В итоге мы получаем модуль, который спокойно сидит у себя в области определения и в общую программу не «светит». Главное — определить это модуль.
Пример модуля базы:
Вот так осуществляется вызов модуля из исполнительного модуля:
Ещё одна приятная особенность языка — процедуры и данные могут вызываются через точку. Это позволяет унифицировать обращения к элементам метатаблицы и извратить информационную схему совершенно любым удобным образом:
На закуску, пример запуска исполнительного модуля для телефоного справочника (из главного меню):
В следующей статье я подробно рассмотрю работу модуля базы и его взаимодействие с процедурами и данными.
P.S. Маленькая просьба — если хотите передать замечание по этому циклу статей, прошу предварительно прочитать статью «Разработка микро-учётной системы на lua, часть вторая. Постановка задачи», в которой я указываю условия разработки программы и функции, которые на неё возлагаются. Учитывайте это.
Для первоначального обучения всех желающих есть учебник «Язык 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, часть вторая. Постановка задачи», в которой я указываю условия разработки программы и функции, которые на неё возлагаются. Учитывайте это.
Поделиться с друзьями
iSage
Ugh.
1) используйте метатаблицы
2) всегда используйте local (если, конечно, переменная действительно не должна быть глобальной)