Некоторое время назад мне было нужно решение нормально импортировать библиотеки в VBScript.
VBScript, для ссылки, не имеет никакой сборки - в возможностях импорта. Традиционный метод импорта файлов состоит в том, чтобы использовать SSI, который выводит содержание включать verbatim в includer. Это меньше оптимально по ряду причин: нет никакого способа избежать нескольких включение, нет никакого способа указать каталог библиотеки, и т.д. Таким образом, я записал свою собственную функцию. Это довольно просто, с помощью 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 конструкций метапрограммирования. Например, нет никакого аналога Ruby method_missing
, который сделал бы реализацию тривиальной.
Моя первая мысль была для основного import
функционируйте для использования executeGlobal
создать глобальную функцию под названием StringBuilder, берущий аргументы, которые в свою очередь загрузили бы StringBuilder.lib и затем использовали бы executeGlobal
к самой "тени" (функция) с одиночным элементом StringBuilder. Существует две проблемы с этим: во-первых, использование executeGlobal
определить функцию, которая затем переопределяет себя использование executeGlobal
походит на довольно поверхностную идею в целом, и во-вторых, оказывается, что в VBScript, можно только переопределить функцию с переменной, если рассматриваемая функция является встроенным. Oooookay.
Следующая мысль, которую я имел, делала то же самое, кроме вместо использования executeGlobal
для замены функции переменной используйте его для замены функции другой функцией, которая просто возвратила одиночный элемент. Это потребовало бы, чтобы одиночный элемент был сохранен в отдельной глобальной переменной. Недостатки к этому подходу (кроме свойственной некошерности стратегии) - то, что доступ к одиночному элементу добавил бы вызов функции наверху и что, из-за эксцентриситетов парсинга интерпретатора, одиночный элемент больше не мог использовать свойства по умолчанию.
В целом, это - довольно липкая проблема, и нечетные причуды VBScript не имеют справки. Любые идеи или предложения приветствовались бы.