Перейти к содержимому


Фотография

Плюсы и минусы использования Lua-кода в качестве файла конфигурации


  • Авторизуйтесь для ответа в теме
Сообщений в теме: 15

#1 Онлайн   eu_tomat

eu_tomat
  • Хранители Кода
  • Сообщений: 880
  • Уровень сигнала: 6,36%
  • В игре: 48 час. 1 мин.

Награды

                          

Отправлено 13 Январь 2017 - 13:05

В этой теме я предлагаю обсудить плюсы и минусы использования Lua-кода в качестве файла конфигурации. Побудила меня к этому недавняя тема, в которой один форумчанин предложил использовать библиотеку JSON, а другой счел такое решение избыточным. У меня есть свое решение, но оно спорное. И чтобы не мусорить в той теме, предлагаю обсудить его здесь. Надеюсь, раздел я выбрал подходящий.

Есть два файла:
test.cfg
-- Файл конфигурации
return{
a=1;
b=2;
c=3;
--можно выполнять вычисления прямо в конфиге
bufLen=1024*1024*4;
--и даже задействовать стандартные или пользовательские функции, если они указаны в окружении
hypotenuse=sqrt(3^2+4^2);
--в тестовых целях можно спровоцировать ошибку обработки конфига:
--z=z.z;
}
test.lua

-- обычно достаточно указать пустое окружение
local env={} env._G=env
-- но если требуется произвести вычисления прямо в конфиге
--  с привлечением методов или даже целых библиотек,
--  то их следует добавить в окружение
local env={sqrt=math.sqrt} env._G=env
-- получение конфигурации и возможных ошибок при ее обработке
local cfg={pcall(loadfile("test.cfg",nil,env))}
-- проверка на наличие ошибок
if not cfg[1] then
  error("Ошибка в файле конфигурации\n  "..cfg[2],0)
else
  -- получение самой конфигурации (без статуса ошкбки)
  cfg=cfg[2]
end
-- таблица конфигурации готова к использованию!
for k,v in pairs(cfg)do print(k,v)end
Достоинства подхода:
  • обладает возможностями, идентичными JSON
  • не требует дополнительных библиотек
  • малый объем дополнительного кода
  • возможность указания вычисляемых параметров даже с использованием функций
Недостатки:
  • Имеется возможность Lua-инъекции
Так как пользователь сам формирует конфигурационный файл, то опасность Lua-инъекции мне представляется незначительной, тем более в рамках OpenComputers, да и вообще внутри MineCraft. Считаю даже, что такое решение с определенными ограничениями годится и для реального использования.

Тем не менее, интересно узнать мнение опытных программистов, какие сложности возникают при использовании lua-кода в качестве файла конфигурации.

Если решение где-то уже обсуждалось, прошу кинуть ссылку на него.

#2 Онлайн   Fingercomp

Fingercomp
  • Гуру
  • Сообщений: 2 002
  • Уровень сигнала: 169,33%
  • В игре: 1278 час. 43 мин.

Награды

                                               

Отправлено 13 Январь 2017 - 15:01

Вполне можно использовать и Луа-конфиги. Достаточно немного обёртки. чтобы защититься от "вандализма" в конфиге.

 

Конфиг:

message.helloworld = "Hello, world!"
message.error = "I caught an error."

emoji.bomb = ""
emoji.heart = "♥"

answer = 42

-- what is this?
coordinates = {1,2,3}

 

Код

Спойлер

 

В base находятся категории — это таблицы, которые будут иметь обработку значений из конфига.

В default, как ни странно, находятся дефолтные значения. Обязательно должны быть все таблицы из base. Кроме того, конфиг не засетит ключ, если его не будет в default.

 

После запуска код напишет это:

Hello, world!
supertest

  • eu_tomat это нравится

#3 Оффлайн   Totoro

Totoro
  • Хранители Кода
  • Сообщений: 1 735
  • Уровень сигнала: 0,29%
  • В игре: 2 час. 13 мин.

Награды

                                      

Отправлено 13 Январь 2017 - 16:36

Именно этим занимается стандартный Serialization API.

Он превращает Lua табличку в текстовый Lua-код, и обратно.

С тем отличием, что не дает сериализовывать функции.

Плюс - невозможность инъкции. Минус - в конфиге нельзя ничего вычислять. В принципе, конфиг и не для этого.


  • NEO и eu_tomat это нравится

#4 Онлайн   eu_tomat

eu_tomat
  • Автор темы
  • Хранители Кода
  • Сообщений: 880
  • Уровень сигнала: 6,36%
  • В игре: 48 час. 1 мин.

Награды

                          

Отправлено 13 Январь 2017 - 17:52

Именно этим занимается стандартный Serialization API.
Он превращает Lua табличку в текстовый Lua-код, и обратно.
С тем отличием, что не дает сериализовывать функции.
Плюс - невозможность инъкции. Минус - в конфиге нельзя ничего вычислять. В принципе, конфиг и не для этого.

Хотел поспорить, что десериализация не воспринимает комментарии, которые гораздо важнее возможности вычислений в конфиге.
Но проверка выявила, что комментарии тоже воспринимаются. А это не всякий обработчик JSON умеет.

Upd: (текст про обнаружение ошибок перенес в следующее сообщение)

Сообщение отредактировал eu_tomat: 13 Январь 2017 - 20:06


#5 Онлайн   Fingercomp

Fingercomp
  • Гуру
  • Сообщений: 2 002
  • Уровень сигнала: 169,33%
  • В игре: 1278 час. 43 мин.

Награды

                                               

Отправлено 13 Январь 2017 - 19:07

Именно этим занимается стандартный Serialization API.

Он превращает Lua табличку в текстовый Lua-код, и обратно.

С тем отличием, что не дает сериализовывать функции.

Плюс - невозможность инъкции. Минус - в конфиге нельзя ничего вычислять. В принципе, конфиг и не для этого.

Сериализованные строки требуют запятую в конце строки, которую я лично, например, постоянно забываю в файлах programs.cfg в репах своих, из-за чего клиент матерится. Мой вариант же позволяет эти запятые не ставить, что очень удобно. Ну и молчу уже про то, что в конфиге можно задавать даже функции.


Сообщение отредактировал Fingercomp: 13 Январь 2017 - 19:08

  • eu_tomat это нравится

#6 Онлайн   eu_tomat

eu_tomat
  • Автор темы
  • Хранители Кода
  • Сообщений: 880
  • Уровень сигнала: 6,36%
  • В игре: 48 час. 1 мин.

Награды

                          

Отправлено 13 Январь 2017 - 20:05

При десериализации конфига невозможно установить, в какой строке файла произошла ошибка. Это минус. При выполнении – легко.
Правда, сейчас ни мой вариант, ни вариант @Fingercomp не способны обнаруживать любые возможные ошибки. Для полной обработки ошибок их нужно ловить как на этапе компиляции (в load), так и выполнения (в pcall) кода.

#7 Оффлайн   Totoro

Totoro
  • Хранители Кода
  • Сообщений: 1 735
  • Уровень сигнала: 0,29%
  • В игре: 2 час. 13 мин.

Награды

                                      

Отправлено 13 Январь 2017 - 22:33

Ну, да. Я с вами согласен. Запятые надо ставить, и ошибки невнятные.

 

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

 

К тому же конфиг - это такая штука, которую не слишком часто трогают, как вы сами знаете.

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



#8 Оффлайн   SDV

SDV
  • Пользователи
  • Сообщений: 655
  • Уровень сигнала: 27,07%
  • В игре: 204 час. 27 мин.
  • ГородO.R.E.N.B.U.R.G.

Награды

        

Отправлено 14 Январь 2017 - 11:01

в которой один форумчанин предложил использовать библиотеку JSON

А я популярен, меня уже начали упоминать везде :D

 

А это не всякий обработчик JSON умеет.

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

Да, второй вопрос это костыли-костылевские нужно использовать чтобы записать изменения в JSON здесь.

И тут как раз удобнее юзать обычную старую добрую табличку с массивами {}

Но как говорится кому что удобно и судя по тому топику его автор предпочел использовать мой способ.



#9 Онлайн   eu_tomat

eu_tomat
  • Автор темы
  • Хранители Кода
  • Сообщений: 880
  • Уровень сигнала: 6,36%
  • В игре: 48 час. 1 мин.

Награды

                          

Отправлено 14 Январь 2017 - 12:28

А я популярен, меня уже начали упоминать везде :D
...
Я лишь предложил унифицированный метод хранения значений, тем более JSON все-таки более обширный и используется везде и всеми ЯПами.

Да тебя как ни упомянешь, а ник уже устарел. В следующий раз упомяну тебя как «Мистер – семь ников на неделе», станешь еще популярнее.

JSON хорош своей универсальностью и поддержкой во многих ЯП – это точно. Но о какой универсальности и других ЯП можно говорить, находясь в рамках СС и OC? К тому же, за универсальность приходится платить потреблением памяти и дискового пространства. Ты смотрел на размер этого модуля? Теперь сравни с объемами памяти, предоставляемыми OpenComputers. Есть стимул сберечь память для данных поважнее этой либы. Поэтому в контексте Майнкрафта единственным достоинством JSON остается синтаксический контроль, которого можно достичь гораздо более эффективными методами

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


Тянуть зависимости для исполнения Lua-кода тоже не требуется. Расплатой за контроль синтаксиса конфига является небольшое увеличение кода:
-- формирование пустого окружения и сокрытие глобального окружения
local cfg={} cfg._G=cfg
-- получение конфигурации и возможных ошибок при ее обработке
local ld,er = loadfile("./test-cfg.cfg","",cfg)
if ld then ld,er = pcall(ld) end
-- вывод ошибок, возникших как на этапе компиляции, так и исполнения кода
if not ld then
  error("Ошибка в файле конфигурации:\n\t"..er,0)
end
-- таблица конфигурации готова к использованию!
for k,v in pairs(cfg)do print(k,v)end
Парсер Fingercomp нужен лишь для логического контроля, хотя тоже полностью его не обеспечивает. А если логический контроль важен, то он будет использован в почти в неизменном виде как в случае исполнения конфига, как десериализации, так и JSON.

Что касается Lua-инъекций, то с этим, похоже, нет особых проблем. Главное, не пихать load в окружение обработки конфига.

Сообщение отредактировал eu_tomat: 14 Январь 2017 - 12:31


#10 Онлайн   Fingercomp

Fingercomp
  • Гуру
  • Сообщений: 2 002
  • Уровень сигнала: 169,33%
  • В игре: 1278 час. 43 мин.

Награды

                                               

Отправлено 14 Январь 2017 - 13:22

У меня не парсер, а кастомное окружение для скрипта и выхлопа, которое позволяет программисту не париться с дефолтными значениями везде, а юзеру — легко редактировать конфиг.



#11 Оффлайн   SDV

SDV
  • Пользователи
  • Сообщений: 655
  • Уровень сигнала: 27,07%
  • В игре: 204 час. 27 мин.
  • ГородO.R.E.N.B.U.R.G.

Награды

        

Отправлено 14 Январь 2017 - 14:46

Да тебя как ни упомянешь, а ник уже устарел. В следующий раз упомяну тебя как «Мистер – семь ников на неделе», станешь еще популярнее.

 

а другой счел такое решение избыточным.

А чтож ты ник другого не вспомнил, он вроде бы как был LeshaInc так и он и есть :D



#12 Онлайн   eu_tomat

eu_tomat
  • Автор темы
  • Хранители Кода
  • Сообщений: 880
  • Уровень сигнала: 6,36%
  • В игре: 48 час. 1 мин.

Награды

                          

Отправлено 14 Январь 2017 - 16:51

@Fingercomp, мне одно не понятно: для чего задействованы все эти трюки с метаметодами? В чем преимущество такого кода перед более простым?

Можно же сначала тупо (через load/pcall) всосать файл в таблицу cfgUsr, а потом аккуратно перенести нужное в таблицу cfgWrk, изначально хранящую дефолтные значения. Заодно можно проверить и совпадение типа, и лишние поля в файле конфигурации.
function cfgUpd( cfgWrk, cfgUsr, prefix )
  local prefix = prefix or ""
  local type_v
  -- перебор значений таблицы cfgWrk,
  --    перенос (с удалением) соответсвующих значений из cfgUsr
  for k,v in pairs(cfgWrk)do
    if cfgUsr[k] then
      type_v = type(v)
      if type(cfgUsr[k]) ~= type_v then
        error("Ошибка в файле конфигурации: type("..prefix.."."..k..")~="..type_v,0)
      end
      if type_v~="table" then
        cfgWrk[k] = cfgUsr[k]
      else
        cfgUpd( cfgWrk[k], cfgUsr[k], prefix.."."..k )
      end
      cfgUsr[k]=nil
    end
  end
  -- перебор таблицы cfgUsr, все это ошибочные поля
  for k,v in pairs(cfgUsr)do
    error("Ошибка в файле конфигурации: недопустимое поле '"..prefix.."."..k.."'",0)
  end
end
Upd: Сегодня взглянул на свой код еще раз, он неправильно обрабатывает лишние поля во вложенных таблицах. Позже перепишу.

Сообщение отредактировал eu_tomat: 15 Январь 2017 - 12:09


#13 Оффлайн   ALeXeR

ALeXeR
  • Пользователи
  • Сообщений: 204
  • Уровень сигнала: 33,9%
  • В игре: 255 час. 59 мин.
  • ГородОдесса

Отправлено 16 Январь 2017 - 22:14

у меня  вообще своя либка для конфигурационных файлов) простая как двери) чем-то похожа на ini)



#14 Онлайн   eu_tomat

eu_tomat
  • Автор темы
  • Хранители Кода
  • Сообщений: 880
  • Уровень сигнала: 6,36%
  • В игре: 48 час. 1 мин.

Награды

                          

Отправлено 16 Январь 2017 - 23:06

у меня  вообще своя либка для конфигурационных файлов) простая как двери) чем-то похожа на ini)

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

Можешь рассказать, насколько твоя либа компактна и удобна? Меня в основном интересует сравнение с описанным здесь методом.

#15 Оффлайн   ALeXeR

ALeXeR
  • Пользователи
  • Сообщений: 204
  • Уровень сигнала: 33,9%
  • В игре: 255 час. 59 мин.
  • ГородОдесса

Отправлено 25 Январь 2017 - 13:06

Моя либа - один из простых механизмов хранения конфигурации и других данных, в теории по скорости работы не должна уступать либе сериализации, но в отличии от неё в моей либе структура файла в вполне читабельна и правима если открыть ещё текстовым редактом, там могут хранится пары ключ-значение, значение 2х типов - строка и число, и можно хранить множества таких же значений с еденичной вложенностью, в общем минимализм и легко редактировать вручную - для этого я ещё писал)

Сообщение отредактировал ALeXeR: 25 Январь 2017 - 13:08


#16 Онлайн   eu_tomat

eu_tomat
  • Автор темы
  • Хранители Кода
  • Сообщений: 880
  • Уровень сигнала: 6,36%
  • В игре: 48 час. 1 мин.

Награды

                          

Отправлено 25 Январь 2017 - 13:36

Моя либа - один из простых механизмов хранения конфигурации и других данных, в теории по скорости работы не должна уступать либе сериализации, но в отличии от неё в моей либе структура файла в вполне читабельна и правима если открыть ещё текстовым редактом, там могут хранится пары ключ-значение, значение 2х типов - строка и число, и можно хранить множества таких же значений с еденичной вложенностью, в общем минимализм и легко редактировать вручную - для этого я ещё писал)

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




Количество пользователей, читающих эту тему: 0

0 пользователей, 0 гостей, 0 анонимных