Розробка мікро-облікової системи на lua, частина третя. Lua і взаємодія модулів

Пам'ятаєте, у попередній частині була схема взаємодії модулів? Тепер настав час розглянути її детальніше:

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 do data
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() ) --[[ Із-за слабкої типізації мови, необхідно часто проводити конверсію даних. Консольний enter завжди буде текстовим. --]] 

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

У наступній статті я детально розгляну роботу модуля бази та його взаємодія з процедурами та даними.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.