- PVSM.RU - https://www.pvsm.ru -
Всем доброго времени суток, уважаемые читатели.
Те, кто сталкивался с написанием скриптов автоматизации в Windows на языках JScript и VBScript наверняка знают о том, что очевидного способа подключения других скриптов в исполняемый — «задачка та еще», возможности же подключать их каскадом, т.е. подключать скрипты, которые в свою очередь сами подключают другие скрипты, не предусмотрено вовсе.
Я же расскажу о том, как я преодолел это обстоятельство в отношении скриптов написанных на JScript, при этом побаловал себя «плюшками» в виде возможности делать это по абсолютному и относительному пути (в том числе и из подключаемых скриптов), «сингулярностью загрузки скрипта» т.е. механизмом гарантирующим, что один и тот же скрипт подгрузится лишь единожды.
Написать решил по причине того, что некоторые коллеги посчитали мое решение довольно интересным, начали им пользоваться, возможно оно покажется приемлемым и Вам.
Заинтересовавшихся прошу под кат.
Позволю себе небольшое предисловие, а для тех кто и так понял о чем собственно речь, или не любит разглагольствование — милости прошу к абзацу «Продумываем идею»
И действительно, то о чем я намереваюсь рассказать, это не что иное, как очередной «велосипед», «Тогда зачем?» — спросите Вы.
Во-первых, велосипед велосипедом, а такого функционала «из коробки» всё-же нет.
Маловато аргументов?
Прежде чем придти к решению «Легче написать самому!(и по столу так Хрясь!)» я естественно потратил не один час на попытку освоения «изкорбочного» арсенала, поинтересовался у системных администраторов, как с такой проблемой справляются они. Оказалось, что они ни как не справляются — нет значит нет. Повторяющийся функционал копируется из скрипта в скрипт. Боле не менее сложные скрипты, этак строк в 150-200, в которых около половины — объявления повсеместно использующихся сущностей (COM/OLE/ActiveX объекты), и обыденная обработка ошибок, аля «открытие несуществующего файла». Из скрипта в скрипт, я проверял, даже попросил у товарища аудиенции с его системными администраторами, там все собственно говоря то же самое ( у «них» превалирует все-же VBScript, где эта проблема так же не решается из коробки, или PowerShell)
Про автоматизацию в среде Microsoft Windows через написание скриптов на специфической реализации стандарта ECMA-262 — языке JScript [1] (который такой же как JavaScript, но другой).
И в частности, про возможность из таких скриптов создавать библиотеки, которые в последствии можно будет легко подключить, как впрочем и любой другой скрипт написанный на JScript.
Перечисленные в заголовке абзаца альтернативы требуют изучения новой технологии (с узкой областью применимости). JScript же снимает с наших плеч важный пункт изучения такой технологии — знание языка программирования. Позволю себе утверждать, что JavaScript, в том или ином виде, очень часто является языком с которым программист ранее сталкивался. Я был не исключением.
Да, такая технологии есть в нашем «изкоробочном» арсенале, но:
Во-первых, при подключении через тег script в файлах формата WSF [2], имеется возможность подключить скрипт только на один уровень, т.е. в подключаемом скрипте что либо еще подключить уже не получится. Подключать друг друга, судя по всему, не имеется возможности (по крайней мере, очевидного пути точно нет).
Во-вторых, файл формата WSF требует описания в соответствии с самобытным подмножеством XML [3], что требует освоения еще одной технологии применимость которой специфична до безобразия. (хотя основная причина — см.«во-первых»)
Вдохновением для меня послужила система подключения модулей в Node.js с которой довелось немного поработать. Мне такая модель показалась настолько удобной, что отказываться от нее мне очень не хотелось.
Как вы наверное уже догадались, кроме как через богомерзкий eval() ничего у нас не выйдет.
И более того, нас интересует не просто eval(), а eval() как метод глобального объекта. В JScript не существует иной возможности выполнить код через eval() так, чтобы объявленные в нем сущности принадлежали к глобальному объекту, кроме как вызов его из основного стека. В противном случае например при вызове из функции все что мы вызовем, умрет вместе со [scope] объекта функции, да и будет доступно только в ней.
Помимо команд подключения нам потребуется финальная команда инициализации.
Дабы не плодить глобальных объектов, заключим весь механизм в единственный объект jsImport.
Механиз состоит из 2-х частей:
jsImport.include(TargetScript); где TargetScript это абсолютный или относительный путь к подключаемому скрипту.
*через вызов данного метода производится непосредственная загрузка исходных кодов скрипта (или каскада скриптов),
jsImport.initialization
*данное свойство необходимо передать в eval() глобального объекта, для инициализации загруженных через jsImport.include() скриптов.
Проще всего понять о чем, и для чего на конкретном примере [4], выполнив mainScript.js из каталога MainDir
Листинг (без комментариев):
var jsImport = new Object();
jsImport.initialization = "";
jsImport.include = function (TargetScript, ParentDir){
jsImport.fso = jsImport.fso || new ActiveXObject("Scripting.FileSystemObject");
var includedLibs = jsImport.includedLibs = jsImport.includedLibs || new Array();
var ParentDir = ParentDir || WScript.ScriptFullName.replace(/[^\]+$/, '');
PathValidation(ParentDir);
for (i in includedLibs){
if(i == TargetScript){jsImport.include.AlreadyLoaded = true};
};
if(typeof jsImport.include.AlreadyLoaded == "undefined" || jsImport.include.AlreadyLoaded !== true){
if(jsImport.fso.FileExists(TargetScript)){
var SourseBuffer = jsImport.fso.OpenTextFile(TargetScript).ReadAll();
var includeArray = includeParser();
jsImport.initialization = jsImport.initialization + SourseBuffer;
if(includeArray.length != 0){
for(i in includeArray){
jsImport.include(includeArray[i].replace(/\\/, "\"), TargetScript.replace(/[^\]+$/,""));
};
};
jsImport.includedLibs.push(TargetScript); AlreadyLoaded = false;
} else {
WScript.Echo("Target " + TargetScript + " not found");
};
function includeParser(){
var pattern = /jsImport.include(["'](.*?)["'])/g;
var result;
var includeArray = [];
while ( (result = pattern.exec(SourseBuffer)) != null) {
includeArray.push(result[1]);
SourseBuffer = SourseBuffer.replace(result[0],"");
pattern.lastIndex = 0;
};
return includeArray;
};
function PathValidation(ParentDir){
if(TargetScript.charAt(1) !== ":"){
var dot = TargetScript.charAt(2);
if(dot == "."){
var OutsidePath = ParentDir, counter= 1;
while(dot == "."){
counter++;
dot = TargetScript.charAt(counter);
OutsidePath = StepOutside(OutsidePath);
};
TargetScript = OutsidePath + TargetScript.substring(counter);
dot = "undefined"; counter = "undefined"; OutsidePath = "undefined";
} else {
if(TargetScript.substring(0,2) == ".."){TargetScript = TargetScript.substring(2)};
if(TargetScript.substring(0,2) !== "\\"){TargetScript = "\\" + TargetScript};
TargetScript = ParentDir + TargetScript.substring(1);
};
};
function StepOutside(outside){
outside = outside.replace(/\\/, "")
return outside.substring(0, outside.lastIndexOf("\"));
};
};
};
};
jsImport.include('\EmbeddedDir\EmbeddedScript.js')
jsImport.include("SecondIncludeTest.js")
eval(jsImport.initialization)
SecondIncludeFunction()
OutsideFunction()
EmbeddedFunction()
WScript.Echo(Embedded.Constant)
WScript.Echo(Embedded3)
Подключив этот механизм к исполняемому скрипту, можно вдоволь «наподключать» себе всего, что хочется в виде отдельной библиотеки, которой возможно потребуется что либо еще для своей работы и т.д.
Осозновая, что с точки зрения JavaScript-кода, кое-что можно сделать лаконичнее и оптимальнее, надеюсь коллективный хабраразум подскажет и направит. Аминь!
PS: Лишь бы кому ни будь пригодилось.
Автор: RUVATA
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/10325
Ссылки в тексте:
[1] JScript: http://ru.wikipedia.org/wiki/JScript
[2] WSF: http://en.wikipedia.org/wiki/Windows_Script_File
[3] самобытным подмножеством XML: http://msdn.microsoft.com/en-us/library/15x4407c%28v=vs.84%29.aspx
[4] примере: https://docs.google.com/open?id=0B0wnpMigiMOFV3RldFN0bER6Vkk
Нажмите здесь для печати.