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

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

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.

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

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 на десктопы. К тому же тенденцию потери исходников самописного софта при жуткой его же забагованности можно приравнять к национальному бедствию.

Lua - Установка Lua

Установка lua это вопрос, который возникает достаточно часто. Что, вообще-то, достаточно удивительно, потому как установка lua на самом деле, крайне проста и понятна. Можно даже сказать, что там вообще нечего делать. Но, раз уж такие вопросы возникают, давайте немного поговорим об установке Lua.

Установка Луа. Скачиваем

Первое, что нам нужно будет сделать перед установкой, это скачать исходники луа с её официального сайта: http://www.lua.org/download.html. Для установки, естественно, нам понадобится самая последняя версия, на данный момент это lua 5.1.4. После скачивания, естественно, надо разархивировать исходники lua в отдельную папку.

Установка Луа. Компиляция.

Есть два варианта компиляции луа, которые, в принципе, ничем не отличаются ))) Первый – это компиляция из Visual Studio Command Prompt:

  1. Запускаем Visual Studio
  2. Выполняем Tools->Visual Studio Command Prompt
  3. Переходим в папку с луа, в директорию etc. Вот так: cd D:/mylibs/lua-5.1.4
  4. запускаем скрипт компиляции луа: etc/luavs.bat
  5. Мы получили нужны нам файлы lua.exe и luac.exe

Второй способ без запуска Visual Studio:

  1. В любом файл-мендеже (я лично работаю в FAR) заходим в папку где_луа/etc/
  2. Редактируем файл, первой строкой ставим: call “путь_к_вижуалстудио/VC/bin/vcvars32.bat”
  3. Добавляем вторую строку: cd .. и сохраняем файл
  4. Запускаем, получаем искомые экзешники

Установка Луа. Доступ

Что бы вы могли запускать луа откуда угодно – вам надо добавить их (путь к ним) в переменную окружения %PATH%. Думаю, Вы сами прекрасно знаете как это сделать. В любом случае, нам не нужны эти файлы, т.к. мы планируем использовать луа внтри наших программ, а не как отдельное приложение. После этого считайте, что сама установка Lua завершена, вам лишь остаётся прописать в Visual Studio пути в получившейся .lib и хидерам луа.

Установка Луа. Статическая линковка.

Меня лично выводит из себя то, что с каждый проектом, использующим луа, приходится таскать и lua.dll , поскольку без неё программы работать не будут. А что бы они работали – надо что бы луа линковалась с нашей программой статически. Делается это тоже совсем не сложно:

  1. Делаем в Visual Studio новый проект, Win32Project, назовём его “LuaLib”
  2. Тип проекта указываем “Static Library”, отключаем использование Precompiled Header, нажимаем Finish
  3. Добавляем в проект все файлы .h и .c, кроме lua.c и luac.c
  4. Что бы компилятор не выдавал нам варнингов, в настройки проекта (Protec/Propreties/Preprocessor) добавляем ;_CRT_SECURE_NO_WARNINGS (не забудьте сделать это и для релиз и для дебаг-версии!!!)
  5. В настройках линковки (Project/Properties/Librarian/General/OutputFile) указываем какие имена библиотек мы хотим. Я указал lua.lib для релиза и lua-debug.lib для дебага.
  6. Компилируем дебаг и релиз-версии. Получаем нужные нам либы
  7. Прописываем пути к ним в Visual Studio

Установка Луа. Проверка.

Проверим, всё ли работает. Создаём новый проект (я сделал консольный проект win32). Дописываем инклюды луа:

extern "C" { # include "lua.h" # include "lauxlib.h" # include "lualib.h" } #include <conio.h> // надо для _getch()

и доделываем сам main():

int _tmain(int argc, _TCHAR* argv[]) { lua_State *L;   L = lua_open();//Создаем стэк   luaL_openlibs(L);//подключить стандартные библиотеки   int status = luaL_loadfile(L, "test.lua");//загрузить файл /* Состояние стtка: [-1]main <--top of the stack */ if (status) { (void)fprintf(stderr, "file not found\n"); return 1; } int result = lua_pcall(L, 0, LUA_MULTRET, 0); _getch(); return 0; }

В настройки линковщика (Project/Properties/Linker/Input/Addition Dependencies) не забываем добавить нашу библиотеку (lua.lib для релиза и lua-debug.lib для дебага). Компилируем. Создаём тестовый файлик с луа-скриптом:

for i = 1, 10 do print(i) end

Запускаем и видим то, что и хотели. Теперь мы можем использовать Луа в наших программах и не таскать с собой этот ненавистный lua.dll – мне кажется, что это намного удобнее и приятнее )

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

В следующих уроках мы более подробно поговорим про использование луа-скриптов в программах и, в частности, в играх.

Ещё по этой теме:

Пример работы с файлами в 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;

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

Пример работы с файлами в 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-пользователи вики перечисляет многие дополнения, созданные пользователями для 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. Талант Нанимайте технических специалистов и создавайте свой бренд работодателя
  5. Реклама Обратитесь к разработчикам и технологам со всего мира
  6. О компании
.Сценарий

- Sifteo: как создать файл .txt с помощью LUA-скрипта?

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

premake - Как записать файл premake5.lua?

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

Как скачать файл в Lua, но записать в локальный файл, как работает

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

- Почему make-файл luarocks не может найти мой интерпретатор lua?

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

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