Некоторое время назад мне нужно было решение для разумного импорта библиотек в VBScript.
VBScript, для справки, не имеет встроенных возможностей импорта.Традиционный метод импорта файлов заключается в использовании SSI, который выгружает содержимое дословного включения во включающее устройство.Это менее чем оптимально по ряду причин: нет способа избежать множественного включения, нет способа указать каталог библиотеки и т. Д. Поэтому я написал свою собственную функцию.Это довольно просто, используя executeGlobal
со словарем для отслеживания импортированных модулей и оборачивая все это в объект для инкапсуляции:
class ImportFunction
private libraries_
private sub CLASS_INITIALIZE
set libraries_ = Server.createObject("Scripting.Dictionary")
end sub
public default property get exec (name)
if not libraries_.exists(name) then
' The following line will find the actual path of the named library '
dim lib_path: set lib_path = Path.resource_path(name & ".lib", "libraries")
on error resume next
' Filesystem is a class of mine; its operation should be fairly obvious '
with FileSystem.open(lib_path, "")
executeGlobal .readAll
if Err.number <> 0 then
Response.write "Error importing library "
Response.write lib_path & "<br>"
Response.write Err.source & ": " & Err.description
end if
end with
on error goto 0
libraries_.add name, null
end if
end property
end class
dim import: set import = new ImportFunction
' Example:
import "MyLibrary"
В любом случае, это работает довольно хорошо, но это много работыесли я не в конечном итоге использовать библиотеку.Я хотел бы сделать это ленивым, чтобы поиск, загрузка и выполнение файловой системы выполнялись только в том случае, если библиотека фактически используется.Это упрощается тем, что к функциям каждой библиотеки обращаются исключительно через одноэлементный объект в глобальной области действия с тем же именем, что и библиотека.Например:
' StringBuilder.lib '
class StringBuilderClass ... end class
class StringBuilderModule
public function [new]
set [new] = new StringBuilderClass
end function
...
end class
dim StringBuilder: set StringBuilder = new StringBuilderModule
import "StringBuilder"
dim sb: set sb = StringBuilder.new
Таким образом, очевидно, что для ленивого импортера очевидным подходом является определение StringBuilder как объекта, который при доступе загружает StringBuilder.lib изаменить себя.
К сожалению, VBScripts затрудняет это из-за отсутствия метапрограммирующих конструкций.Например, не существует аналога method_missing
Руби, который сделал бы реализацию тривиальной.
Сначала я подумал о том, чтобы основная функция import
использовала executeGlobal
для создания глобальной функции с именем StringBuilder.не принимая аргументов, которые, в свою очередь, загружали бы StringBuilder.lib, а затем использовали executeGlobal
, чтобы "затенить" себя (функцию) с помощью синглтона StringBuilder.С этим есть две проблемы: во-первых, использование executeGlobal
для определения функции, которая затем переопределяет себя с использованием executeGlobal
, в целом выглядит довольно схематично, а во-вторых, оказывается, что в VBScript вы можете переопределить только функциюс переменной, если рассматриваемая функция является встроенной.Oooookay.
Следующая мысль, которую я имел, делала то же самое, за исключением того, что вместо того, чтобы использовать executeGlobal
для замены функции переменной, используйте ее для замены функции другой функцией, которая просто возвращает одиночный код.Это потребует, чтобы синглтон был сохранен в отдельной глобальной переменной.Недостатки этого подхода (помимо присущей ему некошерстности стратегии) заключаются в том, что доступ к синглтону привел бы к дополнительным накладным расходам при вызове функции и что из-за эксцентриситета синтаксического анализа интерпретатора синглтон больше не мог использовать свойства по умолчанию.В целом, это довольно сложная проблема, и странные причуды VBScript не помогают.Любые идеи или предложения приветствуются.