Каталог расширений

Популярные теги

3gp       avi       fb2       jpg       mp3       pdf      

Lua как создать файл


Основы декларативного программирования на Lua / Хабр

Луа (Lua) — мощный, быстрый, лёгкий, расширяемый и встраиваемый скриптовый язык программирования. Луа удобно использовать для написания бизнес-логики приложений.

Отдельные части логики приложения часто бывает удобно описывать в декларативном стиле. Декларативный стиль программирования отличается от более привычного многим императивного тем, что описывается, в первую очередь, каково нечто а не как именно оно создаётся. Написание кода в декларативном стиле часто позволяет скрыть лишние детали реализации.

Луа — мультипарадигменный язык программирования. Одна из сильных сторон Луа — хорошая поддержка декларативного стиля. В этой статье я кратко опишу базовые декларативные средства, предоставлямые языком Луа.

Пример


В качестве наивного примера возьмём код создания диалогового окна с текстовым сообщением и кнопкой в императивном стиле:
function build_message_box(gui_builder)<br/>
  local my_dialog = gui_builder:dialog()<br/>
  my_dialog:set_title("Message Box")<br/>
 <br/>
  local my_label = gui_builder:label()<br/>
  my_label:set_font_size(20)<br/>
  my_label:set_text("Hello, world!")<br/>
  my_dialog:add(my_label)<br/>
 <br/>
  local my_button = gui_builder:button()<br/>
  my_button:set_title("OK")<br/>
  my_dialog:add(my_button)<br/>
 <br/>
  return my_dialog<br/>
end

В декларативном стиле этот код мог бы выглядеть так:
build_message_box = gui:dialog "Message Box"<br/>
{<br/>
  gui:label "Hello, world!" { font_size = 20 };<br/>
  gui:button "OK" { };<br/>
}

Гораздо нагляднее. Но как сделать, чтобы это работало?

Основы


Чтобы разобраться в чём дело, нужно знать о некоторых особенностях языка Луа. Я поверхностно расскажу о самых важных для понимания данной статьи. Более подробную информацию можно получить по ссылкам ниже.
Динамическая типизация

Важно помнить, что Луа — язык с динамической типизацией. Это значит, что тип в языке связан не с переменной, а с её значением. Одна и та же переменная может принимать значения разных типов:
a = "the meaning of life" --> была строка,<br/>
a = 42                    --> стало число

Таблицы

Таблицы (table) — основное средство композиции данных в Луа. Таблица — это и record и array и dictionary и set и object.

Для программирования на Луа очень важно хорошо знать этот тип данных. Я кратко остановлюсь лишь на самых важных для понимания деталях.

Создаются таблицы при помощи «конструктора таблиц» (table constructor) — пары фигурных скобок.

Создадим пустую таблицу t:

t = { }

Запишем в таблицу t строку «one» по ключу 1 и число 1 по ключу «one»:
t[1] = "one"<br/>
t["one"] = 1

Содержимое таблицы можно указать при её создании:
t = { [1] = "one", ["one"] = 1 }

Таблица в Луа может содержать ключи и значения всех типов (кроме nil). Но чаще всего в качестве ключей используются целые положительные числа (array) или строки (record / dictionary). Для работы с этими типами ключей язык предоставляет особые средства. Я остановлюсь только на синтаксисе.

Во-первых: при создании таблицы можно опускать положительные целочисленные ключи для идущих подряд элементов. При этом элементы получают ключи в том же порядке, в каком они указаны в конструкторе таблицы. Первый неявный ключ — всегда единица. Явно указанные ключи при выдаче неявных игнорируются.

Следующие две формы записи эквивалентны:

t = { [1] = "one", [2] = "two", [3] = "three" }<br/>
t = { "one", "two", "three" }

Во-вторых: При использовании строковых литералов в качестве ключей можно опускать кавычки и квадратные скобки, если литерал удовлетворяет ограничениям, налагаемым на луашные идентификаторы.

При создании таблицы следующие две формы записи эквивалентны:

t = { ["one"] = 1 }<br/>
t = { one = 1 }

Аналогично для индексации при записи…
t["one"] = 1<br/>
t.one = 1

… И при чтении:
print(t["one"])<br/>
print(t.one)

Функции

Функции в Луа — значения первого класса. Это значит, что функцию можно использовать во всех случаях, что и, например, строку: присваивать переменной, хранить в таблице в качестве ключа или значения, передавать в качестве аргумента или возвращаемого значения другой функции.

Функции в Луа можно создавать динамически в любом месте кода. При этом внутри функции доступны не только её аргументы и глобальные переменные, но и локальные переменные из внешних областей видимости. Функции в Луа, на самом деле, это замыкания (closures).

function make_multiplier(coeff)<br/>
  return function(value)<br/>
    return value * coeff<br/>
  end<br/>
end<br/>
 <br/>
local x5 = make_multiplier(5)<br/>
print(x5(10)) --> 50

Важно помнить, что «объявление функции» в Луа — на самом деле синтаксический сахар, скрывающий создание значения типа «функция» и присвоение его переменной.

Следующие два способа создания функции эквивалентны. Создаётся новая функция и присваивается глобальной переменной mul.

С сахаром:

function mul(lhs, rhs) return lhs * rhs end

Без сахара:
mul = function(lhs, rhs) return lhs * rhs end

Вызов функции без круглых скобок

В Луа можно не ставить круглые скобки при вызове функции с единственным аргументом, если этот аргумент — строковый литерал или конструктор таблицы. Это очень удобно при написании кода в декларативном стиле.

Строковый литерал:

my_name_is = function(name)<br/>
  print("Use the force,", name)<br/>
end<br/>
 <br/>
my_name_is "Luke" --> Use the force, Luke

Без сахара:
my_name_is("Luke")

Конструктор таблицы:
shopping_list = function(items)<br/>
  print("Shopping list:")<br/>
  for name, qty in pairs(items) do<br/>
    print("*", qty, "x", name)<br/>
  end<br/>
end<br/>
 <br/>
shopping_list<br/>
{<br/>
  milk = 2;<br/>
  bread = 1;<br/>
  apples = 10;<br/>
}<br/>
 <br/>
--> Shopping list:<br/>
--> * 2 x milk<br/>
--> * 1 x bread<br/>
--> * 10 x apples

Без сахара:
shopping_list(<br/>
      {<br/>
        milk = 2;<br/>
        bread = 1;<br/>
        apples = 10;<br/>
      }<br/>
  )

Цепочки вызовов

Как я уже упоминал, функция в Луа может вернуть другую функцию (или даже саму себя). Возвращённую функцию можно вызвать сразу же:
function chain_print(...)<br/>
  print(...)<br/>
  return chain_print<br/>
end<br/>
 <br/>
chain_print (1) ("alpha") (2) ("beta") (3) ("gamma")<br/>
--> 1<br/>
--> alpha<br/>
--> 2<br/>
--> beta<br/>
--> 3<br/>
--> gamma

В примере выше можно опустить скобки вокруг строковых литералов:
chain_print (1) "alpha" (2) "beta" (3) "gamma"

Для наглядности приведу эквивалентный код без «выкрутасов»:
do<br/>
  local tmp1 = chain_print(1)<br/>
  local tmp2 = tmp1("alpha")<br/>
  local tmp3 = tmp2(2)<br/>
  local tmp4 = tmp3("beta")<br/>
  local tmp5 = tmp4(3)<br/>
  tmp5("gamma")<br/>
end

Методы

Объекты в Луа — чаще всего реализуются при помощи таблиц.

За методами, обычно, скрываются значения-функции, получаемые индексированием таблицы по строковому ключу-идентификатору.

Луа предоставляет специальный синтаксический сахар для объявления и вызова методов — двоеточие. Двоеточие скрывает первый аргумент метода — self, сам объект.

Следующие три формы записи эквивалентны. Создаётся глобальная переменная myobj, в которую записывается таблица-объект с единственным методом foo.

С двоеточием:

myobj = { a_ = 5 }<br/>
 <br/>
function myobj:foo(b)<br/>
  print(self.a_ + b)<br/>
end<br/>
 <br/>
myobj:foo(37) --> 42

Без двоеточия:
myobj = { a_ = 5 }<br/>
 <br/>
function myobj.foo(self, b)<br/>
  print(self.a_ + b)<br/>
end<br/>
 <br/>
myobj.foo(myobj, 37) --> 42

Совсем без сахара:
myobj = { ["a_"] = 5 }<br/>
 <br/>
myobj["foo"] = function(self, b)<br/>
  print(self["a_"] + b)<br/>
end<br/>
 <br/>
myobj["foo"](myobj, 37) --> 42

Примечание: Как можно заметить, при вызове метода без использования двоеточия, myobj упоминается два раза. Следующие два примера, очевидно, не эквивалентны в случае, когда get_myobj() выполняется с побочными эффектами.

С двоеточием:

get_myobj():foo(37)

Без двоеточия:
get_myobj().foo(get_myobj(), 37)

Чтобы код был эквивалентен варианту с двоеточием, нужна временная переменная:
do <br/>
  local tmp = get_myobj()<br/>
  tmp.foo(tmp, 37) <br/>
end

При вызове методов через двоеточие также можно опускать круглые скобки, если методу передаётся единственный явный аргумент — строковый литерал или конструктор таблицы:
foo:bar ""<br/>
foo:baz { }

Реализация


Теперь мы знаем почти всё, что нужно для того, чтобы наш декларативный код заработал. Напомню как он выглядит:
build_message_box = gui:dialog "Message Box"<br/>
{<br/>
  gui:label "Hello, world!" { font_size = 20 };<br/>
  gui:button "OK" { };<br/>
}

Что же там написано?

Приведу эквивалентную реализацию без декларативных «выкрутасов»:
do<br/>
  local tmp_1 = gui:label("Hello, world!")<br/>
  local label = tmp_1({ font_size = 20 })<br/>
 <br/>
  local tmp_2 = gui:button("OK")<br/>
  local button = tmp_2({ })<br/>
 <br/>
  local tmp_3 = gui:dialog("Message Box")<br/>
  build_message_box = tmp_3({ label, button })<br/>
end

Интерфейс объекта gui

Как мы видим, всю работу выполняет объект gui — «конструктор» нашей функции build_message_box(). Теперь уже видны очертания его интерфейса.

Опишем их в псевдокоде:

 gui:label(title : string) => function(parameters : table) : [gui_element] gui:button(text : string) => function(parameters : table) : [gui_element] gui:dialog(title : string) => function(element_list : table) : function 

Декларативный метод

В интерфейсе объекта gui чётко виден шаблон — метод, принимающий часть аргументов и возвращающий функцию, принимающую остальные аргументы и возвращающую окончательный результат.

Для простоты, будем считать, что мы надстраиваем декларативную модель поверх существующего API gui_builder, упомянутого в императивном примере в начале статьи. Напомню код примера:

function build_message_box(gui_builder)<br/>
  local my_dialog = gui_builder:dialog()<br/>
  my_dialog:set_title("Message Box")<br/>
 <br/>
  local my_label = gui_builder:label()<br/>
  my_label:set_font_size(20)<br/>
  my_label:set_text("Hello, world!")<br/>
  my_dialog:add(my_label)<br/>
 <br/>
  local my_button = gui_builder:button()<br/>
  my_button:set_title("OK")<br/>
  my_dialog:add(my_button)<br/>
 <br/>
  return my_dialog<br/>
end

Попробуем представить себе, как мог бы выглядеть метод gui:dialog():
function gui:dialog(title)<br/>
  return function(element_list)<br/>
 <br/>
    -- Наша build_message_box():<br/>
    return function(gui_builder) <br/>
      local my_dialog = gui_builder:dialog()<br/>
      my_dialog:set_title(title)<br/>
 <br/>
      for i = 1, #element_list do<br/>
        my_dialog:add(<br/>
            element_list[i](gui_builder)<br/>
          )<br/>
      end<br/>
 <br/>
      return my_dialog      <br/>
    end<br/>
 <br/>
  end<br/>
end

Ситуация с [gui_element] прояснилась. Это — функция-конструктор, создающая соответствующий элемент диалога.

Функция build_message_box() создаёт диалог, вызывает функции-конструкторы для дочерних элементов, после чего добавляет эти элементы к диалогу. Функции-конструкторы для элементов диалога явно очень похожи по устройству на build_message_box(). Генерирующие их методы объекта gui тоже будут похожи.

Напрашивается как минимум такое обобщение:

function declarative_method(method)<br/>
  return function(self, name)<br/>
    return function(data)<br/>
      return method(self, name, data)<br/>
    end<br/>
  end<br/>
end

Теперь gui:dialog() можно записать нагляднее:
gui.dialog = declarative_method(function(self, title, element_list)<br/>
  return function(gui_builder) <br/>
    local my_dialog = gui_builder:dialog()<br/>
    my_dialog:set_title(title)<br/>
 <br/>
    for i = 1, #element_list do<br/>
      my_dialog:add(<br/>
          element_list[i](gui_builder)<br/>
        )<br/>
    end<br/>
 <br/>
    return my_dialog      <br/>
  end<br/>
end)

Реализация методов gui:label() и gui:button() стала очевидна:
gui.label = declarative_method(function(self, text, parameters)<br/>
  return function(gui_builder) <br/>
    local my_label = gui_builder:label()<br/>
 <br/>
    my_label:set_text(text)<br/>
    if parameters.font_size then<br/>
      my_label:set_font_size(parameters.font_size)<br/>
    end<br/>
 <br/>
    return my_label<br/>
  end<br/>
end)<br/>
 <br/>
gui.button = declarative_method(function(self, title, parameters)<br/>
  return function(gui_builder) <br/>
    local my_button = gui_builder:button()<br/>
 <br/>
    my_button:set_title(title)<br/>
    -- Так сложилось, что у нашей кнопки нет параметров.<br/>
 <br/>
    return my_button<br/>
  end<br/>
end)

Что же у нас получилось?


Проблема улучшения читаемости нашего наивного императивного примера успешно решена.

В результате нашей работы мы, фактически, реализовали с помощью Луа собственный предметно-ориентированный декларативный язык описания «игрушечного» пользовательского интерфейса (DSL).

Благодаря особенностям Луа реализация получилась дешёвой и достаточно гибкой и мощной.

В реальной жизни всё, конечно, несколько сложнее. В зависимости от решаемой задачи нашему механизму могут потребоваться достаточно серьёзные доработки.

Например, если на нашем микро-языке будут писать пользователи, нам понадобится поместить выполняемый код в песочницу. Также, нужно будет серьёзно поработать над понятностью сообщений об ошибках.

Описанный механизм — не панацея, и применять его нужно с умом как и любой другой. Но, тем не менее, даже в таком простейшем виде, декларативный код может сильно повысить читаемость программы и облегчить жизнь программистам.

Полностью работающий пример можно посмотреть здесь.

Дополнительное чтение

Lua - File I / O

Библиотека ввода / вывода используется для чтения и управления файлами в Lua. В Lua существует два вида файловых операций, а именно неявные файловые дескрипторы и явные файловые дескрипторы.

Для следующих примеров мы будем использовать пример файла test.lua, как показано ниже.

-- sample test.lua -- sample2 test.lua 

Простая операция открытия файла использует следующее утверждение.

file = io.open (filename [, mode]) 

Различные режимы файлов перечислены в следующей таблице.

Sr.No. Режим и описание
1

«р»

Режим только для чтения. Это режим по умолчанию, в котором открывается существующий файл.

2

«ж»

Режим записи включен, который перезаписывает существующий файл или создает новый файл.

3

«а»

Режим добавления, который открывает существующий файл или создает новый файл для добавления.

4

«г +»

Режим чтения и записи для существующего файла.

5

«ш +»

Все существующие данные удаляются, если файл существует или создается новый файл с разрешениями на чтение и запись.

6

«а +»

Режим добавления с включенным режимом чтения, который открывает существующий файл или создает новый файл.

«р»

Режим только для чтения. Это режим по умолчанию, в котором открывается существующий файл.

«ж»

Режим записи включен, который перезаписывает существующий файл или создает новый файл.

«а»

Режим добавления, который открывает существующий файл или создает новый файл для добавления.

«г +»

Режим чтения и записи для существующего файла.

«ш +»

Все существующие данные удаляются, если файл существует или создается новый файл с разрешениями на чтение и запись.

«а +»

Режим добавления с включенным режимом чтения, который открывает существующий файл или создает новый файл.

Неявные файловые дескрипторы

Неявные файловые дескрипторы используют стандартные режимы ввода / вывода или используют один входной и один выходной файл. Пример использования неявных файловых дескрипторов показан ниже.

-- Opens a file in read file = io.open("test.lua", "r") -- sets the default input file as test.lua io.input(file) -- prints the first line of the file print(io.read()) -- closes the open file io.close(file) -- Opens a file in append mode file = io.open("test.lua", "a") -- sets the default output file as test.lua io.output(file) -- appends a word test to the last line of the file io.write("-- End of the test.lua file") -- closes the open file io.close(file)

Когда вы запустите программу, вы получите вывод первой строки файла test.lua. Для нашей программы мы получили следующий вывод.

-- Sample test.lua 

Это была первая строка утверждения в файле test.lua для нас. Также строка «- Конец файла test.lua» будет добавлена ​​к последней строке кода test.lua.

В приведенном выше примере вы можете увидеть, как неявные дескрипторы работают с файловой системой, используя методы io. «X». В приведенном выше примере используется io.read () без необязательного параметра. Необязательный параметр может быть любым из следующих.

Sr.No. Режим и описание
1

«* п»

Читает из текущей позиции файла и возвращает число, если существует в позиции файла или возвращает ноль.

2

«* а»

Возвращает все содержимое файла из текущей позиции файла.

3

«* л»

Читает строку из текущей позиции файла и перемещает позицию файла на следующую строку.

4

число

Читает количество байтов, указанных в функции.

«* п»

Читает из текущей позиции файла и возвращает число, если существует в позиции файла или возвращает ноль.

«* а»

Возвращает все содержимое файла из текущей позиции файла.

«* л»

Читает строку из текущей позиции файла и перемещает позицию файла на следующую строку.

число

Читает количество байтов, указанных в функции.

Другие распространенные методы ввода / вывода включают в себя:

  • io.tmpfile () — возвращает временный файл для чтения и записи, который будет удален после завершения работы программы.

  • io.type (file) — возвращает ли файл, закрытый файл или ноль на основе входного файла.

  • io.flush () — очищает выходной буфер по умолчанию.

  • io.lines (необязательное имя файла) — предоставляет универсальный итератор цикла, который циклически просматривает файл и закрывает файл в конце, если указано имя файла или файл по умолчанию используется и не закрывается в конце цикла ,

io.tmpfile () — возвращает временный файл для чтения и записи, который будет удален после завершения работы программы.

io.type (file) — возвращает ли файл, закрытый файл или ноль на основе входного файла.

io.flush () — очищает выходной буфер по умолчанию.

io.lines (необязательное имя файла) — предоставляет универсальный итератор цикла, который циклически просматривает файл и закрывает файл в конце, если указано имя файла или файл по умолчанию используется и не закрывается в конце цикла ,

Явные файловые дескрипторы

Мы часто используем явный файловый дескриптор, который позволяет нам манипулировать несколькими файлами одновременно. Эти функции очень похожи на неявные файловые дескрипторы. Здесь мы используем file: function_name вместо io.function_name. Следующий пример версии файла того же самого примера неявных файловых дескрипторов показан ниже.

-- Opens a file in read mode file = io.open("test.lua", "r") -- prints the first line of the file print(file:read()) -- closes the opened file file:close() -- Opens a file in append mode file = io.open("test.lua", "a") -- appends a word test to the last line of the file file:write("--test") -- closes the open file file:close()

Когда вы запустите программу, вы получите вывод, аналогичный примеру неявных дескрипторов.

-- Sample test.lua 

Все режимы открытия файлов и параметров для чтения для внешних дескрипторов такие же, как и для неявных файловых дескрипторов.

Другие распространенные файловые методы включают в себя:

  • file: seek (необязательный fromce, необязательное смещение) — параметр Fromce имеет значение «set», «cur» или «end». Устанавливает новый указатель файла с обновленной позицией файла от начала файла. Смещения в этой функции начинаются с нуля. Смещение измеряется от начала файла, если первый аргумент «установлен»; из текущей позиции в файле, если это «cur»; или из конца файла, если это «конец». Значения аргумента по умолчанию — «cur» и 0, поэтому текущую позицию файла можно получить, вызвав эту функцию без аргументов.

  • file: flush () — очищает выходной буфер по умолчанию.

  • io.lines (необязательное имя файла) — предоставляет универсальный итератор цикла, который циклически просматривает файл и закрывает файл в конце, если указано имя файла или файл по умолчанию используется и не закрывается в конце цикла ,

file: seek (необязательный fromce, необязательное смещение) — параметр Fromce имеет значение «set», «cur» или «end». Устанавливает новый указатель файла с обновленной позицией файла от начала файла. Смещения в этой функции начинаются с нуля. Смещение измеряется от начала файла, если первый аргумент «установлен»; из текущей позиции в файле, если это «cur»; или из конца файла, если это «конец». Значения аргумента по умолчанию — «cur» и 0, поэтому текущую позицию файла можно получить, вызвав эту функцию без аргументов.

file: flush () — очищает выходной буфер по умолчанию.

io.lines (необязательное имя файла) — предоставляет универсальный итератор цикла, который циклически просматривает файл и закрывает файл в конце, если указано имя файла или файл по умолчанию используется и не закрывается в конце цикла ,

Пример использования метода поиска показан ниже. Он смещает курсор от 25 позиций до конца файла. Функция чтения печатает остаток файла с позиции поиска.

-- Opens a file in read file = io.open("test.lua", "r") file:seek("end",-25) print(file:read("*a")) -- closes the opened file file:close()

Вы получите вывод, похожий на следующий.

sample2 test.lua --test 

Вы можете поэкспериментировать со всеми различными режимами и параметрами, чтобы узнать все возможности операций с файлами Lua.

Пример работы с файлами в QLua (Lua)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 
-- Флаг поддержания работы скрипта IsRun = true;   function main() -- Пытается открыть файл в режиме "чтения/записи" f = io.open(getScriptPath().."\\Test.txt","r+"); -- Если файл не существует if f == nil then -- Создает файл в режиме "записи" f = io.open(getScriptPath().."\\Test.txt","w"); -- Закрывает файл f:close(); -- Открывает уже существующий файл в режиме "чтения/записи" f = io.open(getScriptPath().."\\Test.txt","r+"); end; -- Записывает в файл 2 строки f:write("Line1\nLine2"); -- "\n" признак конца строки -- Сохраняет изменения в файле f:flush(); -- Встает в начало файла -- 1-ым параметром задается относительно чего будет смещение: "set" - начало, "cur" - текущая позиция, "end" - конец файла -- 2-ым параметром задается смещение f:seek("set",0); -- Перебирает строки файла, выводит их содержимое в сообщениях for line in f:lines() do message(tostring(line));end -- Закрывает файл f:close(); -- Цикл будет выполнятся, пока IsRun == true while IsRun do sleep(100); end; end;   function OnStop() IsRun = false; end;

Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!

как перестать встраивать и начать жить / Хабр

Lua: как перестать встраивать и начать жить

За Lua прочно закрепилась слава полуязыка — инструмента, который при случае можно встроить, чтобы заскриптовать приложение, написанное на компилируемом языке вроде С++. Тем не менее Lua является вполне самостоятельным языком, имеющим свой интерпретатор, возможность создания модулей, большое число библиотек, и при этом данный ЯП обладает минимальным размером среди аналогов. Проще говоря у нас есть все, чтобы создавать такие же приложения как на perl, python, и вообще любом другом распространенном языке программирования.

Я могу предложить вам следующие доводы в пользу Lua:

  • — приложения будут легко переносимы между Windows и Linux (не факт что код будет работать без изменений, но портирование правда пройдет безболезненно, если не были использованы платформоспецифичные библиотеки)
  • — малый оверхед создаваемых программ
  • — высокая скорость работы и загрузки приложений
  • — возможность оперативно «приклеить» к вашему приложению любую С-библиотеку — лучшего «клея» для библиотек вы не найдете
  • — приятный минималистичный синтаксис языка, с возможностью реализации на нем современных парадигм программирования
  • — программы на Lua очень легко развертывать
  • — малое потребление памяти

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

В качестве графического тулкита будем использовать iup — кроссплатформенную библиотеку, изначально созданную с расчетом использования из Lua.

Установка Lua SDK

В рамках идеи использования Lua как самостоятельного ЯП, была создана сборка Lua for Windows, которая содержит себе библиотеки, необходимые в повседневных задачах, возникающих при программировании под указанную ОС: работы с БД, GUI, парсинг XML и т.д. Пусть вас не смущает, что версия Lua в сборке 5.1, а не 5.2 — особой разницы в нашем случае между ними нет.

Скачайте и установите сборку.

Краткое описание концепции iup

Я долго думал, как же расписать процесс создания программы, не вдаваясь подробно в устройство iup. И решил коротко описать его основные принципы:
  • — iup.dialog является корневым элементом интерфейса программы — в этом контейнере размещаются все элементы
  • — позиционирование элементов в контейнере производится при помощи layout-ов: задания правил размещения элемента в контейнере. Iup сам расположит и отрисует элемент согласно правилам. Основные контейнеры — фрейм, вертикальный сайзер, горизонтальный сайзер.
  • — обработчики событий задаются в виде функций, прикрепленных к виджету
  • — после создания диалога запускается цикл обработки событий

Если вы ранее писали для GUI при помощи Tk, WxWidgets или WinAPI, то все это покажется знакомым. Если нет, то программа довольно подробно покрыта комментариями.
Код программы
-- подключение библиотек iup require("iuplua" ) require("iupluacontrols") require("iuplua_pplot") -- библиотека для работы с Canvas, чтобы сохранять график в файл require("cdlua") require("iupluacd") require("string") -- глобальные переменные для виджетов и настроек программы -- максимальное число графиков plots_number = 5 -- виджеты вкладок, где будут размещаться виджеы ввода данных для каждого графика tabs = {} -- контейнеры для виджетов vboxes = {} -- чекбоксы для выбора того, какие графики строить checkboxes = {} -- здесь храним виджеты с текстом данных о точках coords = {} -- виджеты подписи для каждого графика legends = {} -- виджеты обозначения осей координат global_legend = {} -- к величайшему стыду, в Lua нет стандартной функции split function string:split(sep) local sep, fields = sep or ":", {} local pattern = string.format("([^%s]+)", sep) self:gsub(pattern, function(c) fields[#fields+1] = c end) return fields end -- функция рисует на плоттере график по указаным точкам function draw_plot(pwidget, pnum, data) x = data[1].value:split(",") y = data[2].value:split(",") if checkboxes[pnum].value == "OFF" then return end if not (#x == #y) or #x == 0 then iup.Message("Ошибка", "Задано неверное число точек для графика " .. pnum) return end iup.PPlotBegin(pwidget, 0) iup.PPlotAdd(pwidget, 0, 0) for i = 1,#x do iup.PPlotAdd(pwidget, x[i], y[i]) end iup.PPlotEnd(pwidget) end -- виджет отвечающий за кнопку построения графика plot_btn = iup.button{ title = "Построить"} -- колбэк для кнопки "построить график" function plot_btn:action() -- создать виджет графопостроителя plot = iup.pplot { expand="YES", TITLE = "Simple Line", MARGINBOTTOM="65", MARGINLEFT="65", AXS_XLABEL = global_legend[1].value, AXS_YLABEL = global_legend[2].value, LEGENDSHOW="YES", LEGENDPOS="TOPLEFT", size = "400x300" } -- этот блок для обхода бага - без него подпись к первому графику отображаться не будет iup.PPlotBegin(plot, 0) iup.PPlotAdd(plot,0,0) plot.DS_LEGEND = "" iup.PPlotEnd(plot) -- обходим виджеты с данными for i = 1, plots_number do -- чтобы свеженарисованный графи отобразился с правильной подписью print(legends[i].value) plot.DS_LEGEND = legends[i].value -- рисуем график draw_plot(plot, i, coords[i]) end -- кнопка сохранения графика в картинку на диске save_btn = iup.button{ title = "Сохранить" } -- теперь создаем само окно, где будет отображаться график plot_dg = iup.dialog { iup.vbox -- это вертикальный сайзер, помести в него графопостроитель и кнопку { plot, save_btn }, } -- обработчик кнопки сохранения графика function save_btn:action() -- создаем диалог выбора имени файла ля сохранения -- в связи с ограничениями библиотеки сохранять можно только в EMF fs_dlg = iup.filedlg{DIALOGTYPE = "SAVE", FILTER = "*.emf" } iup.Popup(fs_dlg) -- если файл выбран if tonumber(fs_dlg.STATUS) >= 0 then -- дописать при необходимости нужное расширение pic = fs_dlg.value if not (string.sub(pic, string.len(pic)-3) == ".emf") then pic = pic .. ".emf" end -- создаем псевдо-холст, ассоциированный с файлом tmp_cv = cd.CreateCanvas(cd.EMF, pic .. " 400x300") -- выводим график на холст iup.PPlotPaintTo(plot, tmp_cv) -- сохраняем данные в файл cd.KillCanvas(tmp_cv) end end -- отображаем диалог с графиком plot_dg:showxy(iup.CENTER, iup.CENTER) -- запускаем петлю обработки событий для диалога if (iup.MainLoopLevel()==0) then iup.MainLoop() end end -- в цикле создаем вкладки, в которых мы будем размещать виджеты -- для сбора данных for i=1,plots_number do -- создание текстовых виджетов, куда будут вводиться координаты точек coords[i] = {} for j = 1,2 do coords[i][j] = iup.text { expand="HORIZONTAL", multiline = "YES", VISIBLELINES = 5 } end -- виджет для редактирования подписи к графику legends[i] = iup.text{ expand = "HORIZONTAL" } -- создаем контейнер вкладки и заполняем его элементами vboxes[i] = iup.vbox { iup.hbox { iup.label { title = "Подпись графика:" }, legends[i] }, iup.hbox { iup.label { title="X : ", }, coords[i][1] }, iup.hbox { iup.label { title="Y : ", }, coords[i][2] }; expand="YES", } -- меняем заголовк вкладки vboxes[i].tabtitle = "График " .. i -- создаем чекбокс, который будет указывать на то, нужно ли строить -- график по данным из указанной вкладки checkboxes[i] = iup.toggle{ title= "График" .. i, value = "ON" } end -- теперь из заполненных нами контейнеров создаем вкладки tabs = iup.tabs{unpack(vboxes)} -- создаем текстовые виджеты для редактирования подписей осей global_legend[1] = iup.text{} global_legend[2] = iup.text{} -- создаем фрейм для общих настроек графика frame = iup.frame { iup.vbox { iup.label{ title="Использовать данные:", expand="HORIZONTAL" }, iup.vbox { unpack(checkboxes) }, iup.label{}, -- пустую подпись можно использовать как распорку iup.label{title = "Подписи"}, iup.hbox { iup.label{ title = "Ось X "}, global_legend[1] }, iup.hbox { iup.label{ title = "Ось Y "}, global_legend[2] }, iup.label{}, plot_btn }; expand = "VERTICAL", } -- создаем главное окно программы и наносим на него настройки и табы dg = iup.dialog { iup.hbox { frame, tabs }, title="Строим график", size = "HALF" } -- показываем главное окно и запускаем обработку событий dg:showxy(iup.CENTER, iup.CENTER) if (iup.MainLoopLevel()==0) then iup.MainLoop() end 
Пара слов о развертывании

Скрипт можно запустить при помощи команды:
lua plotter.exe 

В данном случае библиотеки будут подключаться из поддиректории clibs/, которая находится в директории, куда был установлен Lua for Windows. Чтобы максимально компактно упаковать скрипт и библиотеки для переноса на другую машину, достаточно скопировать в одну папку следущие файлы(указаны с относительными путями от директории установки Lua):

lua.exe lib/lua5.1.dll clibs/cd.dll clibs/cdlua51.dll clibs/iup.dll clibs/iup_pplot.dll clibs/iupcd.dll clibs/iupcontrols.dll clibs/iupgl.dll clibs/iuplua51.dll clibs/iuplua_pplot51.dll clibs/iupluacd51.dll clibs/iupluacontrols51.dll clibs/freetype6.dll 

Не забудьте поместить в эту папку и сам скрипт с программой. Теперь вы можете перенести эту папку на другую машину и запустить вашу программы командой, указанной выше. При этом никакие другие действия по установке библиотек и рантайма не нужны.

К сожалению файлы cd.dll, cdluad51.dll и iupcd.dll в данной версии Lua for Windows могут работать некорректно, поэтому рекомендую взять их из архива по ссылке ниже.

Итоги

Архив с рабочей версией тут, для удобства добавлена пускалка app.bat.

Скриншоты:

В результате получили, пусть и неказистую, утилиту, имеющую такой же функционал, как и если бы она была написана на «серьезном» языке программирования. При этом простую в развертывании и суммарным весом менее 2 мб. Потребление памяти — около 7 мб. Исходный код доступен для редактирования, сам Lua интерактивно понятен, что упрощает доработку подобного софта на местах.

На мой взгляд, это отличный выбор для написания учебного софта для школ и институтов, а также для внутреннего использования на предприятиях. Так как слабые машины до сих пор в изобилии присутствуют в подобных местах по всему СНГ, то использование Luа подобным образом целесообразно, особенно в свете постепнного прихода Linux на десктопы. К тому же тенденцию потери исходников самописного софта при жуткой его же забагованности можно приравнять к национальному бедствию.

практическое применение? — Хабр Q&A

Луа, будучи, очень простым и компактным языком — легко встраиваться. Включаете пару десятков чистых сишных файлов в проект — и вуаля — у вас встроеный язык. Еще, настраиваемость — по большому счету, в плане библиотек, луа это скорее скелет языка, чем полноценный язык програмирования. Иногда при встраивание вообще выкидвают большую часть (или всю) «стандартную» библиотеку, заменяя ее специализированной под домейн, фактически создавая специализированный язык. Еще один плюс — компактность. Я как-то давно, проверял возможность запускать луа-интерпретатор в качестве отладочного модуля на встроенном чипе (я не говорю про смартфоны, а про «жесткий» embedded). Так вот, виртуальная машина луа (правда почти без библиотек и без интерпретатора, кормить ей надо было уже байткод) занимала 15кб (!) RISC кода. Оказалось, что вполне реально запустить было на том железе, хотя в конце эту идею зарубили как слишком сумашедшую («интепретатор в нашем RT?!»). Идем дальше, Луа можно использовать в качестве декларативного языка, но с «плюшкой» в виде динамичности и читаемости человеком, в отличии скажем от статических декларативных систем, например XML. Я как-то делал декларативную систему описания автоматических тестов на луа, получилось по-моему, неплохо. :) А из более простых примеров такого применения — это файлы конфигурации. Простые файлы var=value легко распарсить вручную, на зато на луа можо сделать вот так:
width = 100
height = width*1.2
positions[0] = {x=0, y=height-20 }

Причем реализуется буквально в пару строчек со стороны хоста — инициализовать луа, запарсить и выполнить скрип, считать получившиеся глобальные переменные, все.

Вообщем давайте просуммируем: если нужен легко встраиваемый, компактный, настраиваемый и быстрый скриптовый язык, чтобы расширить функциональность вашей программе — луа отлично для это подходит. Но если нужный полноценный самостоятельный язык, c богатой библиотекой и возможность писать приложения от начала до конца, то лучше посмотреть в сторону «серьёзных» собратьев, скажем Пайтона (Perl, Ruby, whatever). Их, кстати, тоже можно встроить в качество скриптового языка, просто это далеко не всегда оправданно там, где можно ограничится луа.

Вот.

ЗЫ: JavaScript в чем-то похож на луа тем, что он тоже почти никогда не используется как «самостоятельный» язык.

Пример работы с файлами в QLua (Lua)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 
-- Флаг поддержания работы скрипта IsRun = true;   function main() -- Пытается открыть файл в режиме "чтения/записи" f = io.open(getScriptPath().."\\Test.txt","r+"); -- Если файл не существует if f == nil then -- Создает файл в режиме "записи" f = io.open(getScriptPath().."\\Test.txt","w"); -- Закрывает файл f:close(); -- Открывает уже существующий файл в режиме "чтения/записи" f = io.open(getScriptPath().."\\Test.txt","r+"); end; -- Записывает в файл 2 строки f:write("Line1\nLine2"); -- "\n" признак конца строки -- Сохраняет изменения в файле f:flush(); -- Встает в начало файла -- 1-ым параметром задается относительно чего будет смещение: "set" - начало, "cur" - текущая позиция, "end" - конец файла -- 2-ым параметром задается смещение f:seek("set",0); -- Перебирает строки файла, выводит их содержимое в сообщениях for line in f:lines() do message(tostring(line));end -- Закрывает файл f:close(); -- Цикл будет выполнятся, пока IsRun == true while IsRun do sleep(100); end; end;   function OnStop() IsRun = false; end;

Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!

Lua: начало работы

Lua - мощный и быстрый язык программирования это легко изучить, использовать и встроить в ваше приложение.

Lua разработан как легкий встраиваемый язык сценариев. Он используется для всевозможные приложения, от игр до веб-приложений и обработки изображений.

Увидеть о странице для подробностей и некоторые причины, по которым вам следует выбрать Lua.

Посмотрите, как выглядят и работают программы Lua в живая демонстрация.

Хорошее место для начала изучения Lua - книга Программирование на Lua, доступно в в мягкой обложке и как электронная книга. Первое издание находится в свободном доступе в Интернете. Смотрите также примечания к курсу на основе этой книги.

Официальное определение языка Lua дается в справочное руководство.

Увидеть страница документации и вики для большего.

Наши сообщество дружелюбен и, скорее всего, поможет вам, если вам нужно. Просто посетите список рассылки, чат, а также переполнение стека.

Если вам нужна помощь на португальском языке, Присоединяйся к Список рассылки Lua BR и посетить pt.stackoverflow.

Смотрите также то ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ, поддерживаемый сообществом вики а также LuaFaq, и намного дольше uFAQ.

Если вам нужно дополняют стандартные библиотеки Lua для решения более сложных задач, визит LuaRocks, основной репозиторий модулей Lua. Смотрите также Потрясающий Lua, тщательно подобранный список качественных пакетов и ресурсов Lua. В lua-users вики перечисляет многие дополнения, созданные пользователями для Lua.

Вы можете помочь поддержать проект Lua от покупка книги опубликовано Lua.org и по делать пожертвование.

Вы также можете помочь распространить информацию о Lua, купив продукты Lua. в Zazzle.

Использовать живая демонстрация играть с Lua если вы не хотите ничего устанавливать на свой компьютер.

Чтобы запускать программы Lua на вашем компьютере, вам понадобится автономный интерпретатор Lua и, возможно, некоторые дополнительные библиотеки Lua. Используйте свой любимый текстовый редактор для написания программ Lua. Убедитесь, что вы сохранили свои программы в виде обычного текста.Если вам нужна IDE, попробуйте Студия ZeroBrane.

Если вы используете Windows, пытаться LuaDist, многоплатформенный дистрибутив Lua, включающий батареи.

Если вы используете Linux или Mac OS X, Lua либо уже установлен в вашей системе, либо для него есть пакет Lua. Убедитесь, что у вас установлена ​​последняя версия Lua. (в настоящее время 5.4.1).

Lua также довольно легко собрать из исходного кода, как объяснено ниже.

Строительство из источника

Lua очень легко собрать и установить.Просто скачайте и следовать инструкции в пакете.

Вот простой сеанс терминала, который скачивает текущий выпуск Lua и собирает его в системе Linux:

 curl -R -O http://www.lua.org/ftp/lua-5.4.1.tar.gz tar zxf lua-5.4.1.tar.gz cd lua-5.4.1 сделать все испытания 
Если у вас нет curl, попробуйте wget.

Если вы используете Windows и хотите собрать Lua из исходного кода, есть подробные инструкции в вики.

Заготовка

Чтобы встроить Lua в вашу программу C или C ++, вам понадобятся заголовки Lua для компиляции вашей программы и библиотека Lua для связи с ней.Если вы получаете готовый пакет Lua для своей платформы, вам, вероятно, также понадобится пакет для разработки. В противном случае просто скачать Lua и добавьте его исходный каталог в свой проект.

.

Lua Как создать настраиваемую функцию, которая может использоваться для отслеживания переменных

Переполнение стека
  1. Около
  2. Товары
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
  2. Переполнение стека для команд Где разработчики и технологи делятся частными знаниями с коллегами
  3. Вакансии Программирование и связанные с ним технические возможности карьерного роста
  4. Талант
.

Создание вашего первого скрипта на Lua

Документация FiveM
  • Документация
  • Форум
  • Раздор
  • Серверы
  • GitHub
  • Условия использования
  • Документация
      • Руководство клиента
        • Где купить GTA V Системные Требования Отключение антивируса Установка FiveM Консольные команды
      • Руководство по серверу
        • Настройка сервера Серверные команды Переход с CitizenMP.Сервер
      • Руководство по написанию сценариев
          • Введение в сценарии
            • Введение в ресурсы Создание вашего первого скрипта на C # Создание вашего первого скрипта на JavaScript Создание вашего первого скрипта на Lua О собственных функциях
          • Время выполнения сценариев
            • Скрипты на Lua Скрипты в JavaScript Создание сценариев на C #
          • Переход с устаревших методов
.

Как я могу загрузить и выполнить файл lua из другого файла lua

Переполнение стека
  1. Около
  2. Товары
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
  2. Переполнение стека для команд Где разработчики и технологи делятся частными знаниями с коллегами
  3. Вакансии Программирование и связанные с ним технические возможности карьерного роста
.

api - Lua C: Как мне использовать исходный код Lua для создания интерпретатора Lua, который будет выполнять заданные блоки кода Lua?

Переполнение стека
  1. Около
  2. Товары
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
.

Как я могу выполнить файл, отличный от Lua, из сценария Lua?

Переполнение стека
  1. Около
  2. Товары
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
  2. Переполнение стека для команд Где разработчики и технологи делятся частными знаниями с коллегами
  3. Вакансии Программирование и связанные с ним технические возможности карьерного роста
  4. Талант Нанимайте технических специалистов и создавайте свой бренд работодателя
.

Смотрите также