L'James Notetag System v 1.0
ОПИСАНИЕ
Скрипт служит для облегчения работы с ноуттегами в кастомных скриптах
Возможности
* Выполнение заданного действия при совпадении заданного регэкса
* Автоматическое получение значений из ноуттегов по заданным правилам и сохранение их в содержимом объекта
ВВЕДЕНИЕ
Основная идея системы - автоматическое считывание и преобразование ноуттегов в значения, называемые параметрами, которые потом можно получить из объекта базы данных с помощью get_param
Параметры бывают четырёх видов:
- * Значения (Value) - просто одно значение некоторого типа, например, целое число
- * Массивы (Array) - собственно, массив значений
- * Хеши (Hash) - набор пар ключ-значение
- * Трейты (Trait) - значение булевского типа. Наличие соответствующего ноуттега в объекте присваивает трейту значение true, отсутствие - false
Чтобы система могла распознавать параметры, требуется создать расширение системы, в котором происходит задание стиля и регистрация схем параметров (правил распознавания) для конкретных классов базы данных. Для этого используется простой DSL.
Расширение выглядит примерно так
LJ::NOTETAGS.extension do
# Задание стиля расширения
trait_parser create_parser.add_anon_matcher("[%s]"){|x| true}
# Регистрация схем параметров
declare_feature do
register :power, hash(:percent).limit(:fire, :ice, :lightning)
# Регистрирует ноуттеги вида <power fire 150%> - хешевый параметр. После
# загрузки будет истинно obj.power[:fire] == 1.5
# Другой способ:
# hash(:percent).set_limit(:fire, :ice, :lightning).register(:power)
end
declare_skill do
register :piercing, trait
end
declare(RPG::Actor, RPG::Enemy) do
register :undead, trait
end
end
Чтобы получить значение параметра, нужно использовать obj.get_param(:name) или просто obj.name, где obj - объект класса базы данных
Параметры могут быть использованы как features из RPG Maker VXA - то есть, параметры на экипировке и статусном эффекте переходят на персонажа или врага. Для получения значения параметров можно использовать battler.get_feature(:feature_name) или просто battler.feature_name, где battler - это Game_Battler
ЗАДАНИЕ СТИЛЯ
Стиль расширения применяется ко всем параметрам, объявленным в этом расширении.
Например, в примере выше задаётся вид трейтов [name] вместо <<name>>. Задание стиля выполняется при помощи следующих методов
- * param_parser - задание с помощью парсера (см. ниже) регэксов для распознавания параметров значений, хешей и массивов.
- По умолчанию <name value> и <name>\n value \n</name>
- * trait_parser - задание с помощью парсера регэксов для распознавания трейтов.
- По умолчанию <<name>>
- * arg_selector - регэкс, использующийся схемами хешей и массивов для выделения из ноуттега аргументов. Содержит одну группу, которая захватывает аргумент. По умолчанию, аргумент - это всё, кроме запятых и перевода строки: селектор выделит из <name val1, val2, val3> аргументы "val1", "val2" и "val3"
- * hash_splitter - регэкс, использующийся хешами для того, чтобы в аргументе, выделенном селектором, выбрать ключ и значение. Содержит две группы, первая захватывает ключ, вторая - значение. По умолчанию деление происходит на первом пробеле: ab cde fgh создаст пару :ab => "cde fgh"
Поя
снение:
Пусть распознаётся хеш-параметр <hash a aaa, bb bb b, c cccc cccc>. Сначала он находится в заметке. После чего из строки "a aaa, bb bb b, c cccc cccc" выделяются аргументы "a aaa", "bb bb b" и "c cccc cccc". А затем с помощью сплиттера из каждого аргумента выделяется ключ и значение: "a" -> "aaa", "bb" -> "bb b", "c" -> "cccc cccc". После этого ключ и значение обрабатываются конвертерами и складываются аккумуляторами (см. ниже), из чего мы получаем {:a -> "aaa", :bb -> "bbb", :c "cccc cccc"}
Для выделения параметров из заметки используются парсеры. Парсер - это набор регэксов и кода, выделяющего из MatchData регэкса строку значения. Свой парсер можно делать с помощью create_parser, после чего к нему добавлять регэксы с помощью следующих методов
- * parser.add_matcher(regex){matcher} просто добавляет распознавание для фиксированного регэкса. Matcher принимает на вход MatchData и возвращает строку со значением
- * parser.add_anon_regex(regex_str){matcher} добавляет распознавание для регэкса с распознаванием имени. regex_str - это строка, в которой первый %s будет заменён на имя параметра, прежде чем она будет преобразована в регэкс. Оба метода возвращают self, поэтому их можно вызывать цепочкой
Пример задания стиля
trait_parser create_parser.add_anon_matcher("[%s]"){|x| true}.add_anon_matcher("\"%s\"")
# Такой парсер будет распознавать трейты [name] и "name"
hash_splitter /^([^\s]+)\s*=>\s*(.*?)&/
# Хеши будут иметь вид <power fire => 150%>
ЗАДАНИЕ КЛАССОВ
Для того, чтобы в заметках экземпляра класса проводился поиск, классы нужно зарегистрировать в системе. Делается это с помощью метода register:
declare(*classes) do
# Регистрация схем
end
*classes - перечень классов, в которых будет проводиться поиск параметров по схемам. Для работы требуется, чтобы в классе был метод note.
Также для классов базы данных есть специальные методы: declare_actor, declare_class, declare_item и так далее. Методы declare_usableitem, declare_equipitem и declare_baseitem регистрируют параметры в нескольких классах. Метод declare_features позволяет зарегистрировать параметры, которые будут вести себя как стандартные features/traits/особенности в RPG Maker VXA - то есть, например, параметры героя зависят от его экипировки
РЕГИСТРАЦИЯ СХЕМ
Схемы регистрируются так
register name, scheme
или так
scheme.register(name)
Схема - это правила, по которым будет распознаваться тег. Для создания схемы, нужно вызвать метод value, array, hash или trait, после чего настроить схему. У value, array и hash можно задать шаблон параметра - value(:int), чтобы получить уже частично настроенную схему.
При этом имя может содержать символ подчёркивания. В заметках оно будет распознаваться и как подчёркивание, и как пробел
Также можно создать свой тип параметра. Для этого нужно отнаследовать класс LJ::NOTETAGS::SchemeBase или LJ::NOTETAGS::ParamScheme.
- * В SchemeBase нужно перегрузить методы load(note) - принимает текст заметки и возвращает значение и shared_accumulator(a,b) - метод, который принимает два объекта, полученые из load, и возвращает новый объект, который является их "суммой". Если схема используется только в одном классе, можно опустить
- * ParamScheme в конструкторе принимает загрузчик (self), парсер, значение по умолчанию и значение, которое имеет параметр до начала присваивания (т.е., которое передаётся в качестве acc при первом вызове). Нужно перегрузить методы shared_accumulator(a, b) и accumulate(acc, val) - метод, который принимает объект и результат парсера и возвращает объект, являющийся результатом добавления значения в объект
Также, помимо схем, можно зарегистрировать в системе регэкс и действие, которое нужно выполнять, когда он будет найден. Делается это при помощи register_regex, в параметры которого передаётся регэкс и блок действий, который принимает MatchData и текущий объект
НАСТРОЙКА СХЕМ
Конвертер - это функция, которая принимает строку и возвращает значение параметра
Аккумулятор - это функция, которая принимает существующее значение параметра и новое значение и возвращает изменённое значение параметра. Используется, когда встречается несколько ноуттегов для одного параметра в одном объекте
Для настройки стандартных схем применяются следующие методы, свои для каждого типа схемы. Методы возвращают self и могут вызываться цепочкой
Value:
- * set_converter - задать конвертер. Конвертер по умолчанию оставляет значение строкой
- * set_accumulator - задать аккумулятор. Аккумулятор по умолчанию заменяет текущее значение новым
- * set_method_accumulator - задать аккумулятор вида {|acc, val| acc.m(val)}, где m передаётся в качестве аргумента
- * set_default - задать значение, которое будет сохранено, когда в заметке не встречено ноуттегов с соответствующим именем
- * set_startval - задать значение, которое аккумулятор будет считать текущим перед первым присваиванием. Например, целочисленный параметр с startval=1, default = 0 добавит единицу к итоговому значению, но вернёт 0, если тегов найдено не было. При startval = nil (по умолчанию), первый встреченный ноуттег просто сохраняет значение в параметр без участия аккумулятора
- * set_limit - задать список значений, которые будут приниматься при парсинге. Когда лимит - nil (по умолчанию) - ограничение снимается
Пример: value.set_default(0).set_converter{|x| x.to_i}.set_method_accumulator(:+)
Результатом будет суммируемый целочисленный параметр. Аналогично value(:int)
Array:
- * set_converter - задать конвертер для элементов массива
- * set_unique - если true, то повторяющиеся значения не будут добавлены в параметр. По умолчанию true
- * set_limit - задать список значений, которые будут приниматься при парсинге. Когда лимит - nil (по умолчанию) - ограничение снимается
Пример: array.set_converter{|x| x.to_sym}
Это массив неповторяющихся символов
Hash:
- * set_key_limit - задать список значений, которыми может быть ключ. Если nil, ограничение снимается
- * set_key_converter - задать конвертер для ключей. По умолчанию ключ конвертируется в символ
- * Значение, возвращённое через hash[key] ведёт себя как значение-параметр, возвращённый get_param, и настраивается теми же методами:
- ** set_converter
- ** set_accumulator
- ** set_method_accumulator
- ** set_default
- ** set_startval
- ** set_limit
Пример
: hash.set_key_limit(:fire :ice, :lightning).set_val_default(1).
set_val_converter{|x| x.chomp("%").to_i/100.0}.set_val_method_accumulator(:*)
Эквивалентно :percent, но с ограничением на ключ
Trait:
Трейты не настраиваются
ШАБЛОНЫ ПАРАМЕТРОВ
Параметры-значения, массивы и хеши можно задать при помощи шаблонов и получить уже преднастроенную схему, с готовыми конвертерами и аккумуляторами. Для создания схемы по шаблону требуется указать тип шаблона
- :int - целочисленные значения. Значение по умолчанию 0, аккумулятор складывает значения
- :str - строковые значения. Аккумулятор складывает значения, разделяя их пробелом
- :sym - символьные значения. Аккумулятор заменяет старое значение новым.
- :percent - значения в процентах. Конвертер обрубает знак % при необходимости и делит на 100.0. Значение по умолчанию 1, аккумулятор умножает значения
- :pluspercent - значения в процентах. Вместо умножения аккумулятор их складывает. Так, два +50% дадут значение 2.0, а не 2.25.