Wb-rules 2.0: различия между версиями
(Перенаправление на Wb-rules) Метка: новое перенаправление |
м (Добавил displaytitle) |
||
(не показаны 2 промежуточные версии этого же участника) | |||
Строка 1: | Строка 1: | ||
{{DISPLAYTITLE: Движок правил wb-rules 2.0 }} | |||
В обновлённом движке правил wb-rules присутствует ряд важных нововведений, касающихся логики написания сценариев. | |||
= Сценарии = | |||
== Изоляция сценариев == | |||
Начиная с версии wb-rules 2.0, каждый файл сценария запускается в своём отдельном пространстве имён — '''контексте'''. Таким образом, каждый сценарий может определять | |||
свои функции и глобальные переменные без риска изменить поведение других сценариев. | |||
=== Пример === | |||
В качестве примера приведём два сценария, одновременно запускаемых в движке правил. Каждый сценарий определяет глобальные переменные и функции. | |||
В предыдущих версиях wb-rules обращение к глобальной переменной, изменяемой в нескольких файлах сценариев, может привести к неопределённому поведению. В версиях, начиная с 2.0, поведение строго определено и такое же, как будто сценарий единственный в системе. | |||
В комментариях указан вывод команд log для ранних версий и для актуальной версии. | |||
'''Сценарий 1 (rules1.js)''' | |||
<syntaxhighlight lang="js"> | |||
test1 = 42; | |||
setTimeout(function myFuncOne() { | |||
log("myFuncOne called"); | |||
log("test1: {}, test2: {}", test1, test2); | |||
// раньше: test1: [либо 42, либо 84], test2: Hello | |||
// теперь: test1: 42, test2: (undefined) | |||
// (будет выведена ошибка выполнения: ReferenceError: identifier 'test2' undefined) | |||
}, 1000); | |||
</syntaxhighlight> | |||
'''Сценарий 2 (rules2.js)''' | |||
<syntaxhighlight lang="js"> | |||
test1 = 84; | |||
test2 = "Hello"; | |||
setTimeout(function myFuncTwo() { | |||
log("myFuncTwo called"); | |||
log("test1: {}, test2: {}", test1, test2); | |||
// раньше: test1: [либо 42, либо 84], test2: Hello | |||
// теперь: test1: 84, test2: Hello | |||
}, 1000); | |||
</syntaxhighlight> | |||
=== Примечание === | |||
В предыдущих версиях wb-rules для изоляции правил рекомендовалось использовать замыкание, т.е. | |||
оборачивание кода сценария в конструкцию: | |||
<syntaxhighlight lang="js"> | |||
(function() { | |||
// код сценария идёт здесь | |||
})(); | |||
</syntaxhighlight> | |||
Начиная с версии 2.0, в подобной конструкции нет необходимости. Тем не менее, старые сценарии, использующие эту конструкцию, продолжат работу без изменений в поведении. | |||
=== Обходные пути === | |||
Если в вашей системе использовалось общее глобальное пространство для хранения общих данных и функций, есть несколько способов реализации такого поведения: | |||
==== Использование модулей ==== | |||
Можно написать модуль для организации взаимодействия. У модулей есть статическое хранилище, общее для всех файлов, импортировавших модуль. (см. [[#module.static|module.static]]) | |||
==== Постоянное хранилище ==== | |||
Для обмена данными также можно использовать глобальные постоянные хранилища (PersistentStorage). | |||
'''Внимание:''' при использовании глобальных постоянных хранилищ может произойти совпадение имён, в этом случае возможно нарушение поведения, которое трудно обнаружить. | |||
<syntaxhighlight lang="js"> | |||
var ps = new PersistentStorage("my-global-storage", {global: true}); | |||
/// ... | |||
ps.myvar = "value"; // это значение доступно для всех пользователей хранилища с именем "my-global-storage" | |||
</syntaxhighlight> | |||
==== Прототип глобального объекта ==== | |||
'''ВНИМАНИЕ:''' метод считается «грязным», т.к. все переменные и функции, опубликованные таким образом, становятся доступными всем сценариям в системе. Старайтесь избегать этого способа. За неопределённое поведение при использовании этого метода несёт ответственность сам программист. | |||
Глобальные объекты всех сценариев имеют общий объект — ''прототип'', в котором определены стандартные функции wb-rules (такие, как <code>defineRule</code>, <code>setTimeout</code> и т.д.). Через него можно передавать переменные или функции в общую область видимости. | |||
<syntaxhighlight lang="js"> | |||
global.__proto__.myVar = 42; // теперь myVar — общая переменная для всех сценариев | |||
// из других сценариев к переменной можно обращаться так | |||
log("shared myVar: {}", myVar); | |||
// или вот так, что чуть более аккуратно, т.к. однозначно показывает, где определена переменная | |||
log("shared myVar: {}", global.__proto__.myVar); | |||
</syntaxhighlight> | |||
Правило поиска переменной в первом случае будет выглядеть так: | |||
# Проверяем, есть ли <code>myVar</code> среди локальных переменных (определённой как <code>var myVar = ...</code>). | |||
# Если нет, проверяем, есть ли <code>myVar</code> в глобальном объекте (определённой как <code>myVar = ...</code>). | |||
# Если нет, проверяем, есть ли <code>myVar</code> в ''прототипе'' глобального объекта (определённой как <code>global.__proto__.myVar</code>). | |||
Поиск останавливается, как только переменная найдена. | |||
Таким образом, первый способ обращения будет работать только в том случае, если <code>myVar</code> не определена в верхних областях видимости. | |||
== Анонимные правила == | |||
Теперь правила можно объявлять анонимно (без задания специального имени). Это позволит уменьшить путаницу и неочевидное поведение системы при дублировании имён правил в одном скрипте.Уникальные имена для анонимных правил генерируются автоматически. Старый синтаксис (с явным заданием имени правила) продолжит работу без изменений. | |||
'''ВНИМАНИЕ:''' начиная с версии 2.0, при объявлении правил с одинаковыми именами в одном файле теперь будет возвращаться ошибка. | |||
=== Пример === | |||
<syntaxhighlight lang="js"> | |||
defineRule({ | |||
whenChanged: "mydev/test", | |||
then: function() { | |||
log("mydev/test changed"); | |||
} | |||
}); | |||
</syntaxhighlight> | |||
== Управление правилами == | |||
В wb-rules 2.0 также появляется возможность управлять выполнением правил. Теперь функция <code>defineRule()</code> возвращает идентификатор созданного правила (аналогично <code>setTimeout()/setInterval()</code>), который можно использовать позже для: | |||
* выключения/включения отработки правила; | |||
* принудительного запуска тела правила. | |||
По умолчанию, все правила включены. | |||
=== Пример === | |||
<syntaxhighlight lang="js"> | |||
var myRule = defineRule({ | |||
whenChanged: "mydev/test", | |||
then: function() { | |||
log("mydev/test changed"); | |||
} | |||
}); | |||
// ... | |||
disableRule(myRule); // отключить проверку и выполнение правила | |||
enableRule(myRule); // разрешить выполнение правила | |||
runRule(myRule); // принудительно запустить тело правила (функцию then) | |||
// на текущий момент не поддерживается передача аргументов в then | |||
</syntaxhighlight> | |||
== Постоянное хранилище данных == | |||
В wb-rules 2.0 добавлена поддержка постоянных хранилищ. По сути, это объекты, значения в которых будут сохраняться | |||
даже при потере питания контроллера. Такие хранилища удобно использовать для хранения состояний или конфигурации. | |||
<syntaxhighlight lang="js"> | |||
var ps = new PersistentStorage("my-storage"); | |||
ps.key = "Hello World"; | |||
log(ps.key); | |||
</syntaxhighlight> | |||
По умолчанию, хранилища создаются локальными для данного файла сценария, с привязкой к имени файла. Таким образом, при создании хранилищ с одинаковыми именами в разных файлах сценариев, создастся два разных хранилища (и сценарий не получит доступа к «чужим» данным). | |||
Однако, есть возможность создавать глобальные хранилища. Для этого нужно добавить аргумент { global: true } в вызов конструктора: | |||
<syntaxhighlight lang="js"> | |||
var ps = new PersistentStorage("my-storage", { global: true }); | |||
</syntaxhighlight> | |||
Если такое хранилище уже было создано когда-либо ранее, сценарий получит к нему доступ. | |||
== Виртуальные устройства == | |||
В предыдущих версиях wb-rules значения контролов виртуальных устройств хранились только в MQTT retained, что не очень надёжно (в случае потери питания данные могли быть легко утеряны). Начиная с версии 2.0, эти значения сохраняются также в специальное хранилище в постоянной памяти и восстанавливаются при загрузке сценария. | |||
Если необходимо каждый раз при перезагрузке скрипта восстанавливать строго определённое значение (т.е. не восстанавливать предыдущее сохранённое), | |||
можно добавить в описание контрола поле <code>forceDefault</code>: | |||
<syntaxhighlight lang="js"> | |||
defineVirtualDevice("vdev", { | |||
... | |||
cells: { | |||
... | |||
mycell: { | |||
type: "value", | |||
value: 10, | |||
forceDefault: true // при каждой загрузке сценария поле mycell будет получать значение 10 | |||
} | |||
} | |||
}); | |||
</syntaxhighlight> | |||
По умолчанию поле принимает значение <code>false</code>. | |||
= Модули = | |||
Начиная с версии 2.0, в движке правил wb-rules появилась поддержка подключаемых JS-модулей (похожая по поведению на аналогичную в Node.js, но с некоторыми особенностями). | |||
== Расположение == | |||
Поиск модулей происходит по следующим путям (в заданном порядке): | |||
* <code>/etc/wb-rules-modules</code> | |||
* <code>/usr/share/wb-rules-modules</code> | |||
Таким образом, пользовательские модули удобно складывать в <code>/etc/wb-rules-modules</code>. | |||
Добавить свои пути можно редактированием <code>/etc/default/wb-rules</code> добавлением путей | |||
к переменной WB_RULES_MODULES через разделитель <code>:</code>: | |||
<syntaxhighlight lang="bash"> | |||
... | |||
WB_RULES_MODULES="/etc/wb-rules-modules:/usr/share/wb-rules-modules" | |||
... | |||
</syntaxhighlight> | |||
== Подключение модуля к сценарию == | |||
Подключение модуля происходит с помощью функции <code>require()</code>. Она возвращает объект, экспортированный | |||
модулем (exports). | |||
<syntaxhighlight lang="js"> | |||
... | |||
var myModule = require("myModule"); | |||
... | |||
</syntaxhighlight> | |||
При этом движок правил будет искать файл <code>myModule.js</code> по очереди в директориях поиска (см. Расположение). | |||
Также допустим поиск файла модуля по поддиректориям в директориях поиска, тогда вызов будет выглядеть так: | |||
<syntaxhighlight lang="js"> | |||
... | |||
var myModule = require("path/to/myModule"); | |||
... | |||
</syntaxhighlight> | |||
После того, как файл будет найден, его содержимое будет выполнено, и из файла будет передан объект exports. | |||
'''Примечание 1:''' если модуль был подключен в одном сценарии несколько раз (несколько вызовов require("myModule")), | |||
содержимое файла модуля будет выполнено только в первый раз, а при повторных вызовах будет возвращаться сохранённый | |||
объект exports. | |||
'''Примечание 2:''' если модуль подключается в разных сценариях, для каждого сценария будет создан свой объект модуля | |||
и заново выполнен весь код модуля. Если модулю требуется использовать данные, общие для всех файлов сценариев, | |||
для хранения данных следует использовать объект <code>module.static</code>. | |||
== Создание модуля == | |||
Для создания модуля достаточно создать файл с именем, соответствующим имени модуля (с расширением .js) в директории <code>/etc/wb-rules-modules</code>. | |||
В этом файле будут доступны все стандартные функции wb-rules, а также набор специальных объектов, с помощью | |||
которого можно реализовать необходимый функционал модуля. | |||
=== Объект exports === | |||
С помощью объекта exports можно передавать пользовательскому сценарию параметры и методы. | |||
==== Пример ==== | |||
Файл модуля <code>/etc/wb-rules-modules/myModule.js</code> | |||
<syntaxhighlight lang="js"> | |||
exports.hello = function(text) { | |||
log("Hello from module, {}", text); | |||
}; | |||
exports.answer = 42; | |||
</syntaxhighlight> | |||
Файл сценария scenario.js | |||
<syntaxhighlight lang="js"> | |||
var m = require("myModule"); | |||
m.hello("world"); // выведет в лог "Hello from module, world" | |||
log("The answer is {}", m.answer); // выведет в лог "The answer is 42" | |||
</syntaxhighlight> | |||
'''Будьте внимательны:''' объект exports можно '''только дополнять значениями''', но не переопределять. | |||
Иначе значения экспортированы не будут! | |||
<syntaxhighlight lang="js"> | |||
exports = function(text) { | |||
log("Hello from module, {}", text); | |||
}; | |||
// Ожидание: | |||
var m = require("my-module"); | |||
m("world"); // не работает | |||
// На практике m будет пустым объектом. | |||
// Та же проблема произойдёт при использовании такой конструкции: | |||
exports = { | |||
hello: function(text) { | |||
log("Hello from module, {}", world); | |||
}, | |||
answer: 42 | |||
}; | |||
</syntaxhighlight> | |||
=== Объект module === | |||
Объект module содержит параметры, относящиеся непосредственно к файлу модуля. | |||
==== module.filename ==== | |||
Содержит полный путь до файла ''модуля''. Например, для модуля, сохранённого в <code>/etc/wb-rules-modules/myModule.js</code>: | |||
<syntaxhighlight lang="js"> | |||
log(module.filename); // выведет /etc/wb-rules-modules/myModule.js | |||
</syntaxhighlight> | |||
==== module.static ==== | |||
Объект, хранящий данные, общие для всех экземпляров данного модуля. Его следует использовать для тех данных, | |||
которые должны быть доступны сразу во всех сценариях, использующих данный модуль. | |||
Файл <code>/etc/wb-rules-modules/myModule.js</code> | |||
<syntaxhighlight lang="js"> | |||
exports.counter = function() { | |||
if (module.static.count === undefined) { | |||
module.static.count = 1; | |||
} | |||
log("Number of calls: {}", module.static.count); | |||
module.static.count++; | |||
}; | |||
</syntaxhighlight> | |||
Файл сценария <code>scenario1.js</code> | |||
<syntaxhighlight lang="js"> | |||
var m = require("myModule"); | |||
m.counter(); | |||
m.counter(); | |||
</syntaxhighlight> | |||
Файл сценария <code>scenario2.js</code> | |||
<syntaxhighlight lang="js"> | |||
var m = require("myModule"); | |||
m.counter(); | |||
m.counter(); | |||
m.counter(); | |||
</syntaxhighlight> | |||
В результате работы двух скриптов в логе окажется 5 сообщений: | |||
<pre> | |||
Number of calls: 1 | |||
Number of calls: 2 | |||
Number of calls: 3 | |||
Number of calls: 4 | |||
Number of calls: 5 | |||
</pre> | |||
=== __filename === | |||
Переменная <code>__filename</code> берётся из глобального объекта сценария, к которому подключается модуль, и содержит имя файла | |||
сценария. | |||
В случае, если модуль подключается в другом модуле, переменная <code>__filename</code>, тем не менее, будет содержать именно | |||
имя файла сценария — вершины дерева зависимостей. | |||
Файл <code>/etc/wb-rules-modules/myModule.js</code> | |||
<syntaxhighlight lang="js"> | |||
exports.hello = function() { | |||
log(__filename); | |||
}; | |||
</syntaxhighlight> | |||
Файл сценария <code>/etc/wb-rules/scenario1.js</code> | |||
<syntaxhighlight lang="js"> | |||
var m = require("myModule"); | |||
m.hello(); // выведет scenario1.js | |||
</syntaxhighlight> | |||
= Замеры производительности = | |||
Cм. [[Special:MyLanguage/Движок_правил_wb-rules_2.0/Производительность|Замеры производительности]] |
Версия 10:57, 18 июня 2021
В обновлённом движке правил wb-rules присутствует ряд важных нововведений, касающихся логики написания сценариев.
Сценарии
Изоляция сценариев
Начиная с версии wb-rules 2.0, каждый файл сценария запускается в своём отдельном пространстве имён — контексте. Таким образом, каждый сценарий может определять свои функции и глобальные переменные без риска изменить поведение других сценариев.
Пример
В качестве примера приведём два сценария, одновременно запускаемых в движке правил. Каждый сценарий определяет глобальные переменные и функции.
В предыдущих версиях wb-rules обращение к глобальной переменной, изменяемой в нескольких файлах сценариев, может привести к неопределённому поведению. В версиях, начиная с 2.0, поведение строго определено и такое же, как будто сценарий единственный в системе.
В комментариях указан вывод команд log для ранних версий и для актуальной версии.
Сценарий 1 (rules1.js)
test1 = 42;
setTimeout(function myFuncOne() {
log("myFuncOne called");
log("test1: {}, test2: {}", test1, test2);
// раньше: test1: [либо 42, либо 84], test2: Hello
// теперь: test1: 42, test2: (undefined)
// (будет выведена ошибка выполнения: ReferenceError: identifier 'test2' undefined)
}, 1000);
Сценарий 2 (rules2.js)
test1 = 84;
test2 = "Hello";
setTimeout(function myFuncTwo() {
log("myFuncTwo called");
log("test1: {}, test2: {}", test1, test2);
// раньше: test1: [либо 42, либо 84], test2: Hello
// теперь: test1: 84, test2: Hello
}, 1000);
Примечание
В предыдущих версиях wb-rules для изоляции правил рекомендовалось использовать замыкание, т.е. оборачивание кода сценария в конструкцию:
(function() {
// код сценария идёт здесь
})();
Начиная с версии 2.0, в подобной конструкции нет необходимости. Тем не менее, старые сценарии, использующие эту конструкцию, продолжат работу без изменений в поведении.
Обходные пути
Если в вашей системе использовалось общее глобальное пространство для хранения общих данных и функций, есть несколько способов реализации такого поведения:
Использование модулей
Можно написать модуль для организации взаимодействия. У модулей есть статическое хранилище, общее для всех файлов, импортировавших модуль. (см. module.static)
Постоянное хранилище
Для обмена данными также можно использовать глобальные постоянные хранилища (PersistentStorage).
Внимание: при использовании глобальных постоянных хранилищ может произойти совпадение имён, в этом случае возможно нарушение поведения, которое трудно обнаружить.
var ps = new PersistentStorage("my-global-storage", {global: true});
/// ...
ps.myvar = "value"; // это значение доступно для всех пользователей хранилища с именем "my-global-storage"
Прототип глобального объекта
ВНИМАНИЕ: метод считается «грязным», т.к. все переменные и функции, опубликованные таким образом, становятся доступными всем сценариям в системе. Старайтесь избегать этого способа. За неопределённое поведение при использовании этого метода несёт ответственность сам программист.
Глобальные объекты всех сценариев имеют общий объект — прототип, в котором определены стандартные функции wb-rules (такие, как defineRule
, setTimeout
и т.д.). Через него можно передавать переменные или функции в общую область видимости.
global.__proto__.myVar = 42; // теперь myVar — общая переменная для всех сценариев
// из других сценариев к переменной можно обращаться так
log("shared myVar: {}", myVar);
// или вот так, что чуть более аккуратно, т.к. однозначно показывает, где определена переменная
log("shared myVar: {}", global.__proto__.myVar);
Правило поиска переменной в первом случае будет выглядеть так:
- Проверяем, есть ли
myVar
среди локальных переменных (определённой какvar myVar = ...
). - Если нет, проверяем, есть ли
myVar
в глобальном объекте (определённой какmyVar = ...
). - Если нет, проверяем, есть ли
myVar
в прототипе глобального объекта (определённой какglobal.__proto__.myVar
).
Поиск останавливается, как только переменная найдена.
Таким образом, первый способ обращения будет работать только в том случае, если myVar
не определена в верхних областях видимости.
Анонимные правила
Теперь правила можно объявлять анонимно (без задания специального имени). Это позволит уменьшить путаницу и неочевидное поведение системы при дублировании имён правил в одном скрипте.Уникальные имена для анонимных правил генерируются автоматически. Старый синтаксис (с явным заданием имени правила) продолжит работу без изменений.
ВНИМАНИЕ: начиная с версии 2.0, при объявлении правил с одинаковыми именами в одном файле теперь будет возвращаться ошибка.
Пример
defineRule({
whenChanged: "mydev/test",
then: function() {
log("mydev/test changed");
}
});
Управление правилами
В wb-rules 2.0 также появляется возможность управлять выполнением правил. Теперь функция defineRule()
возвращает идентификатор созданного правила (аналогично setTimeout()/setInterval()
), который можно использовать позже для:
- выключения/включения отработки правила;
- принудительного запуска тела правила.
По умолчанию, все правила включены.
Пример
var myRule = defineRule({
whenChanged: "mydev/test",
then: function() {
log("mydev/test changed");
}
});
// ...
disableRule(myRule); // отключить проверку и выполнение правила
enableRule(myRule); // разрешить выполнение правила
runRule(myRule); // принудительно запустить тело правила (функцию then)
// на текущий момент не поддерживается передача аргументов в then
Постоянное хранилище данных
В wb-rules 2.0 добавлена поддержка постоянных хранилищ. По сути, это объекты, значения в которых будут сохраняться даже при потере питания контроллера. Такие хранилища удобно использовать для хранения состояний или конфигурации.
var ps = new PersistentStorage("my-storage");
ps.key = "Hello World";
log(ps.key);
По умолчанию, хранилища создаются локальными для данного файла сценария, с привязкой к имени файла. Таким образом, при создании хранилищ с одинаковыми именами в разных файлах сценариев, создастся два разных хранилища (и сценарий не получит доступа к «чужим» данным).
Однако, есть возможность создавать глобальные хранилища. Для этого нужно добавить аргумент { global: true } в вызов конструктора:
var ps = new PersistentStorage("my-storage", { global: true });
Если такое хранилище уже было создано когда-либо ранее, сценарий получит к нему доступ.
Виртуальные устройства
В предыдущих версиях wb-rules значения контролов виртуальных устройств хранились только в MQTT retained, что не очень надёжно (в случае потери питания данные могли быть легко утеряны). Начиная с версии 2.0, эти значения сохраняются также в специальное хранилище в постоянной памяти и восстанавливаются при загрузке сценария.
Если необходимо каждый раз при перезагрузке скрипта восстанавливать строго определённое значение (т.е. не восстанавливать предыдущее сохранённое),
можно добавить в описание контрола поле forceDefault
:
defineVirtualDevice("vdev", {
...
cells: {
...
mycell: {
type: "value",
value: 10,
forceDefault: true // при каждой загрузке сценария поле mycell будет получать значение 10
}
}
});
По умолчанию поле принимает значение false
.
Модули
Начиная с версии 2.0, в движке правил wb-rules появилась поддержка подключаемых JS-модулей (похожая по поведению на аналогичную в Node.js, но с некоторыми особенностями).
Расположение
Поиск модулей происходит по следующим путям (в заданном порядке):
/etc/wb-rules-modules
/usr/share/wb-rules-modules
Таким образом, пользовательские модули удобно складывать в /etc/wb-rules-modules
.
Добавить свои пути можно редактированием /etc/default/wb-rules
добавлением путей
к переменной WB_RULES_MODULES через разделитель :
:
...
WB_RULES_MODULES="/etc/wb-rules-modules:/usr/share/wb-rules-modules"
...
Подключение модуля к сценарию
Подключение модуля происходит с помощью функции require()
. Она возвращает объект, экспортированный
модулем (exports).
...
var myModule = require("myModule");
...
При этом движок правил будет искать файл myModule.js
по очереди в директориях поиска (см. Расположение).
Также допустим поиск файла модуля по поддиректориям в директориях поиска, тогда вызов будет выглядеть так:
...
var myModule = require("path/to/myModule");
...
После того, как файл будет найден, его содержимое будет выполнено, и из файла будет передан объект exports.
Примечание 1: если модуль был подключен в одном сценарии несколько раз (несколько вызовов require("myModule")), содержимое файла модуля будет выполнено только в первый раз, а при повторных вызовах будет возвращаться сохранённый объект exports.
Примечание 2: если модуль подключается в разных сценариях, для каждого сценария будет создан свой объект модуля
и заново выполнен весь код модуля. Если модулю требуется использовать данные, общие для всех файлов сценариев,
для хранения данных следует использовать объект module.static
.
Создание модуля
Для создания модуля достаточно создать файл с именем, соответствующим имени модуля (с расширением .js) в директории /etc/wb-rules-modules
.
В этом файле будут доступны все стандартные функции wb-rules, а также набор специальных объектов, с помощью которого можно реализовать необходимый функционал модуля.
Объект exports
С помощью объекта exports можно передавать пользовательскому сценарию параметры и методы.
Пример
Файл модуля /etc/wb-rules-modules/myModule.js
exports.hello = function(text) {
log("Hello from module, {}", text);
};
exports.answer = 42;
Файл сценария scenario.js
var m = require("myModule");
m.hello("world"); // выведет в лог "Hello from module, world"
log("The answer is {}", m.answer); // выведет в лог "The answer is 42"
Будьте внимательны: объект exports можно только дополнять значениями, но не переопределять. Иначе значения экспортированы не будут!
exports = function(text) {
log("Hello from module, {}", text);
};
// Ожидание:
var m = require("my-module");
m("world"); // не работает
// На практике m будет пустым объектом.
// Та же проблема произойдёт при использовании такой конструкции:
exports = {
hello: function(text) {
log("Hello from module, {}", world);
},
answer: 42
};
Объект module
Объект module содержит параметры, относящиеся непосредственно к файлу модуля.
module.filename
Содержит полный путь до файла модуля. Например, для модуля, сохранённого в /etc/wb-rules-modules/myModule.js
:
log(module.filename); // выведет /etc/wb-rules-modules/myModule.js
module.static
Объект, хранящий данные, общие для всех экземпляров данного модуля. Его следует использовать для тех данных, которые должны быть доступны сразу во всех сценариях, использующих данный модуль.
Файл /etc/wb-rules-modules/myModule.js
exports.counter = function() {
if (module.static.count === undefined) {
module.static.count = 1;
}
log("Number of calls: {}", module.static.count);
module.static.count++;
};
Файл сценария scenario1.js
var m = require("myModule");
m.counter();
m.counter();
Файл сценария scenario2.js
var m = require("myModule");
m.counter();
m.counter();
m.counter();
В результате работы двух скриптов в логе окажется 5 сообщений:
Number of calls: 1 Number of calls: 2 Number of calls: 3 Number of calls: 4 Number of calls: 5
__filename
Переменная __filename
берётся из глобального объекта сценария, к которому подключается модуль, и содержит имя файла
сценария.
В случае, если модуль подключается в другом модуле, переменная __filename
, тем не менее, будет содержать именно
имя файла сценария — вершины дерева зависимостей.
Файл /etc/wb-rules-modules/myModule.js
exports.hello = function() {
log(__filename);
};
Файл сценария /etc/wb-rules/scenario1.js
var m = require("myModule");
m.hello(); // выведет scenario1.js