1

Тема: JScript: Фреймворк

Приветствую. Поделюсь мыслями. Честно говоря, давно не вижу развития скриптинга под JScript в среде WSH. Возможно это связано тем, что довольно часто код пишется "с нуля", что явно тормозит разработку. Аналогичная ситуация была с JavaScript довольно недавно в браузерах. Несмотря на скептицизм, который был распространен в то время, фреймворки позволили оживить странички на более продвинутом уровне. А сейчас и они сплошь и рядом.
В общем, я написал ряд функций, которые позволят упростить жизнь разработчиков в определенных случаях.
Фреймворк является принципиально плоским, а названия и функционал функций взяты из языка программирования AutoIt. В общем, буду рад единомышленникам, а также надеюсь, что это пригодится кому-нибудь.

В настоящее время реализованы следующие функции:

+ открыть спойлер

Enumerator.prototype.toArray

Function.prototype.bind
String.prototype.trim
Array.prototype.indexOf
Array.prototype.lastIndexOf
Array.prototype.forEach
Array.prototype.map
Array.prototype.filter
Array.prototype.every
Array.prototype.some

GenerateString()
WMIQuery()
MsgBox

GetAppDataCommonDir()
GetAppDataDir()
GetExe()
GetPID()
GetCommonFilesDir()
GetComputerName()
GetComSpec()
GetCPUArc()
GetDesktopCommonDir()
GetDesktopDir()
GetDocumentsCommonDir()
GetFavoritesCommonDir()
GetFavoritesDir()
GetMyDocumentsDir()
GetHomePath()
GetHomeDrive()
GetStartMenuCommonDir()
GetStartMenuDir()
GetUserProfileDir()
GetSystemDir()
GetTempDir()
GetProgramFilesDir()
GetProgramsCommonDir()
GetProgramsDir()
GetWindowsDir()
GetWorkingDir()
GetScriptDir()
GetScriptFullPath()
GetScriptName()
GetDesktopHeight()
GetDesktopWidth()
GetDesktopDepth()
GetHOUR()
GetMDAY()
GetMIN()
GetMON()
GetMSEC()
GetSEC()
GetWDAY()
GetYDAY()
GetYEAR()
GetFULLDATE()
GetUserName()
GetLogonServer()
GetIPAddress1()
GetMacAddress()
GetPublicIPAddress()
GetOSArch()
GetOSBuild()
GetOSLang()
GetOSInstallDate()
GetOSServicePack()
GetOSVersion()
ProcessClose(ProcName)
ProcessExists(ProcName)
ProcessWait(process, timeout=0)
ProcessWaitClose(process, timeout=0)


13/11/2013
DirCopy Copies a directory and all sub-directories and files (Similar to xcopy).
DirCreate Creates a directory/folder.
FileDelete Delete one or more files. (принудительное удаление. принимает как массивы файлов, так и просто путь) поддерживает удаление по маске.
FileExists Checks if a file or directory exists.
DirMove Moves a directory and all sub-directories and files
FileMove Moves one or more files
DirRemove Deletes a directory/folder.
FileCopy Copies one or more files.
DriveGetDrive Returns an array containing the enumerated drives.
FileGetVersion Returns the "File" version information.
FileChangeDir Changes the current working directory.
DriveGetFileSystem Returns File System Type of a drive.
DriveGetLabel Returns Volume Label of a drive, if it has one.
DriveGetSerial Returns Serial Number of a drive.
DriveGetType Returns drive type.
DriveMapAdd Maps a network drive.
DriveMapDel Disconnects a network drive.
DriveMapGet Retrieves the details of a mapped drive.
DriveSetLabel Sets the Volume Label of a drive.
DriveSpaceFree Returns the free disk space of a path in Megabytes.
DriveSpaceTotal Returns the total disk space of a path in Megabytes.
DriveStatus Returns the status of the drive as a string.

15/11/13:
StringCompare Compares two strings with options.
StringInStr Checks if a string contains a given substring.
StringIsAlNum Checks if a string contains only alphanumeric characters.
StringIsAlpha Checks if a string contains only alphabetic characters.
StringIsASCII Checks if a string contains only ASCII characters in the range 0x00 - 0x7f (0 - 127).
StringIsDigit Checks if a string contains only digit (0-9) characters.
StringIsFloat Checks if a string is a floating point number.
StringIsInt Checks if a string is an integer.
StringIsLower Checks if a string contains only lowercase characters.
StringIsSpace Checks if a string contains only whitespace characters.
StringIsUpper Checks if a string contains only uppercase characters.
StringIsXDigit Checks if a string contains only hexadecimal digit (0-9, A-F) characters.
StringLeft Returns a number of characters from the left-hand side of a string.
StringLen Returns the number of characters in a string.
StringLower Converts a string to lowercase.
StringMid Extracts a number of characters from a string.
StringRight Returns a number of characters from the right-hand side of a string.
StringStripCR Removes all carriage return values ( Chr(13) ) from a string.
StringStripWS Strips the white space in a string.
StringTrimLeft Trims a number of characters from the left hand side of a string.
StringTrimRight Trims a number of characters from the right hand side of a string.
StringUpper Converts a string to uppercase. Asc Returns the ASCII code of a character.

19/11/13:
StringAddCR Takes a string and prefixes all linefeed characters ( Chr(10) ) with a carriage return character ( Chr(13) ).
StringFormat Returns a formatted string (similar to the C sprintf() function).
StringFromASCIIArray Converts an array of ASCII codes to a string.
StringReplace Replaces substrings in a string.
StringSplit Splits up a string into substrings depending on the given delimiters.
StringToASCIIArray Converts a string to an array containing the ASCII code of each character.
printf
sprintf

27.03.14:
ProcessList Returns an array listing the currently running processes (names and PIDs).
Sleep Pause script execution.
AscW Returns the unicode code of a character.
Asc Returns the ASCII code of a character.
ChrW Returns a character corresponding to a unicode code.
Chr Returns a character corresponding to an ASCII code.
TimerInit Returns a handle that can be passed to TimerDiff() to calculate the difference in milliseconds.
TimerDiff Returns the difference in time from a previous call to TimerInit().
Hex Returns a string representation of an integer or of a binary type converted to hexadecimal.
Dec Returns a numeric representation of a hexadecimal string.
ProcessGetStats Returns an array about Memory or IO infos of a running process.
ProcessSetPriority Changes the priority of a process
FileGetTime Returns the time and date information for a file.
IsAdmin Checks if the current user has full administrator privileges.
ClipGet Retrieves text from the clipboard.
ClipPut Writes text to the clipboard.
FileSelectFolder Initiates a Browse For Folder dialog.
Run Runs an external program.
RunWait Runs an external program and pauses script execution until the program finishes.
FileGetShortName Returns the 8.3 short path+name of the path+name passed.
FileGetLongName Returns the long path+name of the path+name passed.
FileGetSize Returns the size of a file in bytes.
DirGetSize Returns the size in bytes of a given directory.
EnvGet Retrieves an environment variable.
FileCreateShortcut Creates a shortcut (.lnk) to a file.
FileGetShortcut Retrieves details about a shortcut.
FileSearch
FileSearchStop
FileSearchAll
FileFindFirst
FileSetTime Sets the timestamp of one of more files.
FileGetAttrib Returns a code string representing a file's attributes.
FileSetAttrib Sets the attributes of one or more files.
ShellExecute Runs an external program using the ShellExecute API.
ShellExecuteWait Runs an external program using the ShellExecute API and pauses script execution until it finishes.
MemGetStats Retrieves memory related information.
RegDelete Deletes a key or value from the registry.

09/04/2014
FileGetEncoding Determines the text encoding used in a file.

Функции работы с реестром, поддержка работы с удаленными машинами.
RegEnumValues Reads the name of a value according to its instance.
RegRead Reads the value in a registry.
RegWriteValue Writes the value in a registry. // поддержка всех типов данных
RegEnumKeys  Reads the name of a subkey according to its instance.
RegCreateKey Creates the key in a registry.
RegWrite Creates key or writes the value in a registry.
RegCheckKeyAccess
RegDeleteKey
RegDeleteValue
RegDelete Deletes a key or value from the registry.

Работа с INI-файлами.
INIGetObject Парсинг ini-файла. Возвращает специальный объект.
INISaveObject Save the object to a file.
IniReadSectionNames Reads all sections in a standard format .ini file.
IniReadSection Reads all key/value pairs from a section in a standard format .ini file.
IniRead Reads a value from a standard format .ini file.
IniRenameSection Renames a section in a standard format .ini file.
IniDelete Deletes a value from a standard format .ini file.
IniWriteSection Writes a section to a standard format .ini file.
IniWrite Writes a value to a standard format .ini file.

Код прикреплен к посту.

А эти функции будут реализованы в ближайшее время

+ открыть спойлер

FileClose Closes a previously opened text file.
FileFlush Flushes the file's buffer to disk.
FileGetPos Retrieves the current file position.
FileInstall Include and install a file with the compiled script.
FileOpen Opens a text file for reading or writing.
FileOpenDialog Initiates a Open File Dialog.
FileRead Read in a number of characters from a previously opened text file.
FileReadLine Read in a line of text from a previously opened text file.
FileRecycle Sends a file or directory to the recycle bin.
FileRecycleEmpty Empties the recycle bin.
FileSaveDialog Initiates a Save File Dialog.
FileSetPos Sets the current file position.
FileWrite Append a text/data to the end of a previously opened file.
FileWriteLine Append a line of text to the end of a previously opened text file.

Binary Returns the binary representation of an expression.
BinaryLen Returns the number of bytes in a binary variant.
BinaryMid Extracts a number of bytes from a binary variant.
BinaryToString Converts a binary variant into a string.
StringToBinary Converts a string into binary data.

RunAs Runs an external program under the context of a different user.
RunAsWait Runs an external program under the context of a different user and pauses script execution until the program finishes.

Shutdown Shuts down the system.
StderrRead Reads from the STDERR stream of a previously run child process.
StdinWrite Writes a number of characters to the STDIN stream of a previously run child process.
StdioClose Closes all resources associated with a process previously run with STDIO redirection.
StdoutRead Reads from the STDOUT stream of a previously run child process.
FtpSetProxy Sets the internet proxy to use for ftp access.
HttpSetProxy Sets the internet proxy to use for http access.
HttpSetUserAgent Sets the user-agent string sent with InetGet() and InetRead() requests.
InetClose Closes a handle returned from InetGet().
InetGet Downloads a file from the internet using the HTTP, HTTPS or FTP protocol.
InetGetInfo Returns detailed data for a handle returned from InetGet().
InetGetSize Returns the size (in bytes) of a file located on the internet.
InetRead Downloads a file from the internet using the HTTP, HTTPS or FTP protocol.

Ping Pings a host and returns the roundtrip-time.
EnvSet Writes an environment variable.
EnvUpdate Refreshes the OS environment.

Отредактировано 09/04/14

2

Re: JScript: Фреймворк

Методы ECMA262-5 - удобно для тех, кто в курсе, но можно и без них.
Остальное - по-моему у каждого разработчика есть свои наработки - библиотеки подобных функций.
Никакого скепсиса - так вижу.
Идея понравилась. Если "правильно" подойти к реализации + карта ляжет может что-нибудь доброе получится.
Я бы создал репозиторий на каком-нибудь GitHub или Google Code для совместной разработки и общения.
Создание сообщества единомышленников в случае развития идеи очень важно.
По коду - я бы... как это правильно... закрыл scope... ну как-то так в общем:


(function() {
// здесь код библиотеки
})();

3 (изменено: im2002, 2013-11-06 10:27:09)

Re: JScript: Фреймворк

Покажите пример использования первой ф-ции. Как я понимаю надо передать как аргумент коллекцию, поручим массив... так? Enumerator.prototype.toArray это не конструкция языка а информативное название функции?
пытался так:

var SWbemServices = GetObject("winmgmts:\\\\.\\root\\cimv2");
var SWbemObjectSet = SWbemServices.InstancesOf("Win32_service");

Enumerator.prototype.toArray(SWbemObjectSet);

WScript.Echo(Result[1] + "\n" + Result[2]);                      // пишет, что Result не определено ???

4 (изменено: dab00, 2013-11-06 12:09:18)

Re: JScript: Фреймворк

Пример использования первой функции (toArray) +  map:


new Enumerator(new ActiveXObject("Scripting.FileSystemObject").Drives).toArray().map(function(drive) {
  WScript.Echo(drive.DriveLetter);
});

Т.е. из коллекции получаем массив, после чего к примеру мапим его как нам надо.

upd: не совсем удачный пример - лучше forEach:


new Enumerator(new ActiveXObject("Scripting.FileSystemObject").Drives).toArray().forEach(function(drive) {
  WScript.Echo(drive.DriveLetter);
});

Функция map() вернет нам массив, состоящий из определенных свойств объектов.

5

Re: JScript: Фреймворк

Полностью поддерживаю идею с репозитарием.
Маленькое замечание по коду: все "WScript.CreateObject" необходимо заменить на "new ActiveXObject". Иначе из области применения фрэймворка придется исключить HTA

6 (изменено: greg zakharov, 2013-11-08 10:21:52)

Re: JScript: Фреймворк

JSman пишет:

...А сейчас и они сплошь и рядом...

Здесь с Вашей стороны есть доля лукавства: фреймворки и библиотеки главным образом пишутся для вэба, а узконаправленных, скажем, для административных задач - водятся ли они вообще в дикой природе?

dab00 пишет:

...ну как-то так в общем:...

Запихать все в ананимную функцию, как это делает большинство разрабов различных библиотек, можно, но стоит ли? Кидать все в одну кучу, делая тем самым API библиотеки или фреймворка труднодокументируемым, а главное сложным в использовании (и отладке), многих и побуждает к написанию того, что народ любит называть "плагинами", а на деле лишь является оберткой над API. На мой субъективный взгляд логичней бить логику библиотеки на классы, связывая после их в единое целое. Например, функции для работы с массивами помещаем в класс arr:

var arr = arr || {
//методы класса
};

И так далее. Это в значительной мере упрощает документирование, разработку и эксплуатацию. По крайней мере scope.js (библиотека, написанная для одного проекта) такой подход оправдала.

dab00 пишет:

Методы ECMA262-5 - удобно для тех, кто в курсе, но можно и без них.

А Вы уверены, что абсолютно все разработчики данный документ не читают? Идею же с репозиториями...

mozers пишет:

Полностью поддерживаю идею с репозитарием...

...также поддерживаю.

7

Re: JScript: Фреймворк

greg zakharov пишет:

На мой субъективный взгляд логичней бить логику библиотеки на классы...

Согласен, первое что пришло в голову по аналогии с веб-либами, пожалуй вариант с анонимной функцией здесь не подойдет.

greg zakharov пишет:

...для административных задач - водятся ли они вообще в дикой природе...

Думаю не водятся, у каждого свои либы.

JSman пишет:

Аналогичная ситуация была с JavaScript довольно недавно в браузерах.

По аналогии с ситуацией в веб можно попробовать написать что-то более-менее универсальное, но чтобы это не осталось таким "кухонным концертом" нужно привлекать как можно больше публики. Репозиторий был бы в тему.
В общем автора .

8

Re: JScript: Фреймворк

Рад, что откликнулись. Думаю, не стоит опасаться захламления глобального пространства имен, потому что никто не запрещает использовать такую классную штуку как http://code.google.com/intl/ru/closure/ … rview.html. При большом желании можно код обернуть в анонимную функцию. Но это мелочи в реализации.

Код уже залит на GitHub. Я бы хотел рассказать о моем видении на реализацию этого проекта.

Многие фреймворки уже реализованы для других языков. Поэтому мне так кажется, что выдумывать какие-то свои функции или объектную модель нецелесообразно В этой связи я допускаю внедрение в код общеизвестных и распространенных функций из других языков программирования.
Например, неплохо иметь под рукой в JScript функции аналогичные встроенным в VBS. Наличие таких функций ускорит конвертацию кода из VBS в JS, с чем я частенько сталкиваюсь.  Мне очень нравится простота AutoIt. По большому счету там все есть, что нужно администратору.

Какой алгоритм работы? Да все просто, я буду брать справочник AutoIt|VBScript и переписывать функции в JS.

Что касается модулей, то можно их сделать в отдельном файле, никаких проблем нет. Но я не сторонник классической идеи о модульности типа NewMath = {Method1: ...}. Может быть не прав. Сборку рабочего кода вполне можно сделать отдельной утилитой с применением удаления мусорного кода.

9 (изменено: Rumata, 2013-11-14 08:16:21)

Re: JScript: Фреймворк

Идея хорошая, но "валить" в все в одну кучу - не есть хорошо. Лучше создать для каждого объекта отдельный файл. Окончательной сборкой можно заниматься на этапе публикования. Что кстати и делает Google Closure.

Также можно глянуть сюда - http://code.google.com/p/jsxt/. Например, обсуждение в теме JScript/VBScript: WSH интерпретатор. Идеи сборки файлов там реализованы. Есть место оптимизации.

Привести к единому виду имена функций не мешало бы. А то олучается какой-то разброд: одни пишутся так - словоСлово, другие пишутся так - СловоСлово. В js принят первый стиль - словоСлово.

Функции для работы с файловой системой лучше "спрятать" под каким-то заданным именем, например, FileSystem, FSO, FS. По крайей мере освободиться глобальное пространство имен для конечного пользователя.

Очень неудобно, что в JScript до сих пор не реализованы методы объекта Array. Приходится самому реализовывать или брать готовое.

Расширение обекта Enumerator предлагалось, но этузиазма в народе не встретило. Можно почитать здесь:
JScript: Расширение объекта Enumerator, упрощение работы с коллекциями

( 2 * b ) || ! ( 2 * b )

10

Re: JScript: Фреймворк

Rumata пишет:

Очень неудобно, что в JScript до сих пор не реализованы методы объекта Array. Приходится самому реализовывать или брать готовое.

Расширение обекта Enumerator предлагалось, но этузиазма в народе не встретило. Можно почитать здесь:
JScript: Расширение объекта Enumerator, упрощение работы с коллекциями

Мне вполне нравится Ваша идея с Enumerator.prototype.forItems и я использовал свой аналог функции, правда назвал как forEach. Реализовано как-то так.


Enumerator.prototype.forEach = function (action, that /*opt*/)
{
    this.toArray().forEach(action, that);
}
Rumata пишет:

Привести к единому виду имена функций не мешало бы. А то олучается какой-то разброд: одни пишутся так - словоСлово, другие пишутся так - СловоСлово. В js принят первый стиль - словоСлово.

В текущий момент функции пишутся и названы в соответствии с документацией AutoIt. Что касается стиля расширения прототипов, то я использую, как Вы сказали, «словоСлово». Но если Вы любите программировать, например, на PHP, и Вам очень нравится определенная функция, которая могла бы упростить жизнь в разработке, то без проблем можете ее реализовать так, как она описана и именована в документации к PHP. Вот к примеру, мне очень нравится использование переменных в строках, например

echo "$a - a value"


И в скором времени это будет внесено в функционал.
Конечно, можно спорить на эту тему, но я вижу фреймворк как платформу, которая  позволяет довольно быстро переносить код из одного языка в другой, в том числе для ускорения разработки.

Rumata пишет:

Идея хорошая, но "валить" в все в одну кучу - не есть хорошо. Лучше создать для каждого объекта отдельный файл.
...
Функции для работы с файловой системой лучше "спрятать" под каким-то заданным именем, например, FileSystem, FSO, FS. По крайей мере освободиться глобальное пространство имен для конечного пользователя.

Думаю, что полностью код фреймворка подключать нецелесообразно. В настоящий момент я себе поставил задачу напихать как можно больше функционала, который мне обычно нужен в работе. При этом при завершении написания кода, использующего фреймворк, я его прогоняю через Google Closure, который удаляет неиспользуемые функции. В принципе у меня нет огромных проектов на WSH, где я бы беспокоился о захламлении глобального пространства имен.
Что касается вопроса о вводе модулей, то мне сейчас немного сложно на него ответить. Я стараюсь сделать код максимально понятным и локаничным, а фреймворк плоским. Подумаю над этим. Вот что приходит в голову: сделать как можно гибче и демократичней, например как в Дельфи. Там можно подключать модули, при этом разработчик может писать как <название модуля> точка <функция> либо просто <функция>. То есть использование "префиксов" функций в коде можно оставить на выбор разработчику.

Rumata пишет:

Также можно глянуть сюда - http://code.google.com/p/jsxt/. Например, обсуждение в теме JScript/VBScript: WSH интерпретатор. Идеи сборки файлов там реализованы. Есть место оптимизации.

Работа интересная. Я помню. Взял на заметку. К ней вернусь чуток позже.

11

Re: JScript: Фреймворк

Может быть чушь скажу, но мне кажется, структура должна быть такой: базовый фреймворк чисто JS-ный, без заимствований синтаксиса других языков, а к нему "тематические" минифреймворки, например VBS-фреймворк: собственных алгоритмов не содержит, а лишь переводит имена/синтаксис избранных Васиковских функций, обращаясь к одной или нескольким функциям базового. Так же для других языков. С одной стороны, это позволит избежать дублирования кода, если функционально одинаковые функции в разных языках имеют разные имена, а с другой - пользователи, незнающие какого-то из языков, получат доступ к функционалу через знание другого.

12

Re: JScript: Фреймворк

Serge Yolkin, синтаксис как был JS, так и останется. Писать с большой буквы или маленькой - это вообще не является проблемой. Весь код исправляется одним регулярным выражением. Дублирования кода не стоит бояться, потому что весь мусор (неиспользуемый) на этапе преобработки будет выпилен либо Google Closure, либо аналогом, которым я также занимаюсь. Вопрос о паковке функций в массивы/объекты/файлы/модули также легко решаем преобработкой. Например, засунем функции работы с файловой системой в отдельный файл FS.js. Никаких препятствий не вижу использовать эти функции либо через объект FS.<method> либо <method>. Все это решается предварительной обработкой кода. Сейчас же мне интересна реализация тех функций, которые я назвал на "To Do". А все остальное - вторично и решаемо.

13 (изменено: Serge Yolkin, 2013-11-15 13:10:55)

Re: JScript: Фреймворк

JSman, Вы не поняли идею.
Скажем, в JS нет полезной функции "ПолучитьЧегоТоТам()" - добавляем её в фреймворк JS. Но в языке SuperPuper есть такая функция, только называется она "ТамПолучитьЧегоТо" - можно добавить такую функцию в фреймворк SuperPuper, она будет ссылаться на на "ПолучитьЧегоТоТам()" фреймворка JS. Т.е. человек, знакомый с языком SuperPuper использует знакомое ему имя функции, а работает, разумеется, JS из базового фреймворка. Если в другом языке, том же VBS например, тоже есть такая или подобная функция, то её имя добавляем в фреймворк VBS со ссылкой на тот же код базового фреймворка. Таким образом, если Некто владеет AutoIt,  ему понадобится фреймворк AutoIt, как транслятор имён, и, разумеется базовый, а тот, кому нравится VBS - будет использовать с базовым фреймворк VBS. Просто примерил на себя: мне легче написать собственный код на JS, чем использовать имена удобных и красивых функций AutoIt, PHP и др. поскольку я понятия не имею, какие там функции...

14 (изменено: badik, 2013-11-15 15:13:44)

Re: JScript: Фреймворк

В JScript нет команды include
Фреймворк придется подгружать динамически.
Предлагаю рабочий пример  eval работает как в WSH, так и NET (exe файл)

P.S про условную компиляцию до конца месяца напишу отдельно

примечание:файл с форума выгружается коряво но 7zip его читает

Post's attachments

eval_test.zip 3.41 kb, 14 downloads since 2013-11-15 

You don't have the permssions to download the attachments of this post.

15

Re: JScript: Фреймворк

badik, +1 за .NET. Абсолютно солидарен. Делаем eval и подключаем модуль-файл как объект с функциями или как функции. Пусть каждый сам решает как ему удобно. Ну, а потом вполне можно через утить убрать мусор, а вместо инклудов вставить куски кода, чтобы избавиться eval.

Serge Yolkin пишет:

JSman, Вы не поняли идею.
Скажем, в JS нет полезной функции "ПолучитьЧегоТоТам()" - добавляем её в фреймворк JS. Но в языке SuperPuper есть такая функция, только называется она "ТамПолучитьЧегоТо" - можно добавить такую функцию в фреймворк SuperPuper, она будет ссылаться на на "ПолучитьЧегоТоТам()" фреймворка JS. Т.е. человек, знакомый с языком SuperPuper использует знакомое ему имя функции, а работает, разумеется, JS из базового фреймворка. Если в другом языке, том же VBS например, тоже есть такая или подобная функция, то её имя добавляем в фреймворк VBS со ссылкой на тот же код базового фреймворка. Таким образом, если Некто владеет AutoIt,  ему понадобится фреймворк AutoIt, как транслятор имён, и, разумеется базовый, а тот, кому нравится VBS - будет использовать с базовым фреймворк VBS. Просто примерил на себя: мне легче написать собственный код на JS, чем использовать имена удобных и красивых функций AutoIt, PHP и др. поскольку я понятия не имею, какие там функции...

Идея мне понятна. Разумеется должен быть скелет фреймворка, на который будет опираться полный перечень функций модулей или "минифреймворков". В теории звучит все логично и красиво. На практике же могут возникнуть 2 сложности:
1) макаронный код. Это когда каждая строчка цепляет за собой другую функцию модуля. В итоге получается объемный код. С этим столкнулись разработчики на Дельфи, когда с пустой формы получали исполняемый файл размером 600 кб.
2)проблема выбора Апи. Тут либо самому придумывать названия функций и строить свои структуры либо использовать готовый Апи. я предложил за основу взять (использовать в качестве скелета) фреймворк AutoIt, разновидность скриптового языка, который также направлен на упрощение автоматизации. Ничего сложного нет. Справка подробно расписывает каждую функцию.
Я еще раз повторюсь, что дублирующий код не бойтесь писать, ничего страшного в этом нет. Мусор будет вырезаться автоматически.

16

Re: JScript: Фреймворк

1) потому и предложил разделить модули - скелет отдельно, трансляторы - отдельно, и никаких перекрёстных ссылок, только из транслятора в базу (скелет)
2) при наличии желания/времени на изучение справки по AutoIt, возможно, и писать будет проще на AutoIt...

17 (изменено: Rumata, 2013-11-16 02:00:20)

Re: JScript: Фреймворк

Какой смысл в реализации функций BitXXX, математических функций, строковых функций извлечения или трансформации части строки, функций преобразования чисел в строку? Все это либо заложено в синтаксисе языка (битовые операции), либо реализовано в методах базовых объектов (Math, String.prototype, Integer.prototype).

( 2 * b ) || ! ( 2 * b )

18

Re: JScript: Фреймворк

Rumata, согласен. Удалил. Что касается функций StringXXX, то предлагаю их оставить, так как они довольно часто используются.

19 (изменено: Rumata, 2013-11-16 09:27:26)

Re: JScript: Фреймворк

StringXXX могут быть полезны. Но не стоит бездумно копировать средства одного языка, когда они уже реализованы. Например, весь букет предлагаемых функций под спойлером покрывается следующими свойствами и методами:

+ .length, .replace(), .split(), .slice()

StringCompare
StringInStr
StringLeft
StringLen
StringMid
StringRegExp
StringRegExpReplace
StringReplace
StringRight
StringSplit

И лучшее им место, как мне кажется, прототип объекта String (хотя у этого способа есть противники, но агрументация ни слаба, ни сильна; можно сказать, это все "философия"). Например:


String.prototype.trim = function()
{
    return this.replace(/^\s+|\s+$/g, '');
};

String.prototype.trimLeft = function()
{
    return this.replace(/^\s+/, '');
};

String.prototype.trimRight = function()
{
    return this.replace(/\s+$/, '');
};

Проверка строк на соответствие некоторому критерию могут быть интересны при частом использовании или для улучшения читабельности кода. Опять же разумно спрятать в прототип:


String.prototype.isAlpha = function()
{
    return /^[a-z]+$/gi.test(this);
};

String.prototype.isAlnum = function()
{
    return /^[0-9a-z]+$/gi.test(this);
};

и т.д.

А потом все богатство использовать:


var cArgs = WScript.Arguments;

var param = cArgs.item(0).trim();

if ( param.isAlnum() ) {
    // Строка состоит только из цифр и букв латинского алфавита
}
( 2 * b ) || ! ( 2 * b )

20 (изменено: dab00, 2013-11-16 11:44:31)

Re: JScript: Фреймворк

Rumata пишет:

И лучшее им место, как мне кажется, прототип объекта String...

+, например вот так решает Крокфорд

Rumata пишет:

Integer.prototype

Наверное подразумевали Number.prototype.

21

Re: JScript: Фреймворк

Rumata, dab00, отлично. Добавляем в прототип. Я думаю на всякий пожарный можно и отдельно функциями сделать. Если не используется в коде, то выпилится. Вечером добавлю функционал.

22 (изменено: greg zakharov, 2013-11-16 14:19:47)

Re: JScript: Фреймворк

dab00 пишет:

Наверное подразумевали Number.prototype.

Подразумевалось то, что подразумевалось. Диапазон знакового целочисленного типа, насколько помню, лежит в пределах от -2147483648 до 2147483647, и если попытаться определить тип этих значений с помощью оператора typeof, получим Number. Следовательно, определить самостоятельно целочисленный тип в JavaScript более, чем возможно, правда есть несколько нюансов, например, как идентифицировать Integer без приведения к таковому с помощью parseInt? Можно, в принципе, ориентироваться на наличие точки, намекающей на тип Float, или, учитывая, что в JavaScript имеется возможность представлять числа в виде строк (и наоборот), то можно вполне предопределить тип, а точнее его диапазон с помощью регулярных выражений, но насколько все это эффективно и нужно ли вводить понятия int, uint и иже с ними, судить не берусь. Могу лишь напомнить про следующие числовые константы:

WScript.echo(NaN); //1,#QNAN
WScript.echo(Number.NaN); //-1,#IND
WScript.echo(Infinity); //1,#INF
WScript.echo(Number.NEGATIVE_INFINITY); //-1,#INF
WScript.echo(Number.POSITIVE_INFINITY); //1,#INF
WScript.echo(Number.MAX_VALUE); //1,79769313486232E+308
WScript.echo(Number.MIN_VALUE); //4,94065645841247E-324

Если быть объективным, этих констант достаточно, чтобы проводить довольно сложные вычисления, не заморачиваясь с вводом новых типов данных.

Rumata пишет:

..."валить" в все в одну кучу - не есть хорошо.

Позвольте заметить, что конечное слово все же за разработчиком. Единственное, на что действительно стоит обратить внимание в данном случае - доступность документации.

JSman пишет:

...и я использовал свой аналог функции, правда назвал как forEach...

Можно и вовсе сократить до each, как в Ruby.

Rumata пишет:

В js принят первый стиль - словоСлово.

Это все равно что венгерская нотация в C\C++.  Наиболее верным является не то, насколько жестко разработчик придерживается стилистических рекомендаций, а простота восприятия кода. Например, кому-то покажется функция вида:

function getStringLength() {...}

куда более осмысленной, чем просто:

function stringLength() {...}

Навязывание норм развитого социализма только тормозит развитие науки и прогресса вцелом.

23

Re: JScript: Фреймворк

Встряну в последний раз. Чесслово, больше занудствовать не буду.
Вот все последние посты очень наглядно демонстрируют, что я предложил: функциям StringXXX, BitXXX место в AutoIt, или, если угодно, в AutoIt2js фреймворке. Нравятся такие имена - пожалуйста, в базовый даже ничего добавлять не надо, поскольку в самом JS реализовано, "each, как в Ruby" добавить в Ruby2js и т.д. а в базовый, собственно JS, добавлять !только! полезный, но отсутствующий функционал, не загоняясь по синтаксису других языков. Таким образом, ForEach и each из разных фреймворков-трансляторов могут ссылаться на один и тот же код базового фреймворка. Теоретически, если проект заинтересует достаточное количество участников, работу над трансляторами можно будет и поделить, JSman достанется только модерация базового фреймворка

24

Re: JScript: Фреймворк

Serge Yolkin, да Вы поймите меня правильно. Я абсолютно "за" в отношении ввода пространства имен/модулей/файлов/библиотек и т.п. Только вот Вы мне подскажите: что есть "базовый" js-фреймворк?:) Это сборище функций, которое я сам придумаю? - Да, и, кстати, это абсолютно верно, но вот скажите зачем нам создавать велосипед заново, придумывая спецификации, апи? Лучше же от чего-то отталкиваться. Если опыт чей-то имеется в смежной области, так почему бы не воспользоваться им?
Или Вы думаете базовый функционал - это просто расширение прототипов в соответствии со стандартами ECMA либо традициями других фреймворков под веб? - Тогда возникает вопрос: "А в чем собственно фишка и в чем удобство?".
Попробуйте ответить на вопросы: Какова точка отсчета для фреймворка? И как ее задать?
Понимаете, я должен исходить из того, что я должен сделать такой базовый функционал, который в первую очередь будет заточен под решение административных/управленческих задач. Говорить сообществу разработчиков о том, что "Ребята, выучите сначала мой базовый функционал, который я родил вот только что, а только потом берите сливки с других языков и реализуйте их модулями причем на базе моего базового фреймворка" несколько неправильно. Я должен что-то взять за основу, что простое, плоское, локаничное, интуитивно понятное, а также популярное хотя бы среди какой-то части скриптописателей. Разумеется, надо использовать готовые спецификации. Просто в качестве дефолтного я выбрал AutoIt. Поэтому базовым фреймворком будет AutoIt. Но я напоминаю о том, что это не означает, что разработчик будет таскать за собой огромную библу с мусорным кодом. То, что разработчик будет использовать в рабочем коде, то и останется после обработки. Ничего лишнего.
Если мы упремся в конфликт имен функций из разных языков программирования, то и в этом ничего страшного нет, потому что никто не мешает задать приоритет модулей из отдельных файлов. Сейчас вопрос только в реализации функционала. Причем все очень демократично. Публикуйте — разберемся.

Serge Yolkin, Вы не занудствуете. Вы задаете абсолютно правильные и логичные вопросы. Когда есть скептики, значит есть над чем думать. И это очень хорошо.

25 (изменено: Serge Yolkin, 2013-11-16 18:20:29)

Re: JScript: Фреймворк

Ну, раз не занудствую...

что есть "базовый" js-фреймворк?:) Это сборище функций, которое я сам придумаю?

Нет. Это функции, обеспечивающие работу трансляторов в том случае, когда их работа (в части реализации отдельной функции) не обеспечивается собственным функционалом JS. Т.е., если Вы решили отталкиваться от AutoIt, Все функции с AutoIt именами Вы помещаете в фреймворк AutoIt[2js], те из них, аналоги которых есть в JS (о чём писал Rumata) реализуете в нём сразу (замена синтаксиса), а те, для которых нужен более серьёзный код (циклы, условия, создание дополнительных объектов и т.д.) реализуете в базовом фреймворке, на который Ваш транслятор ссылается точно так же, как чей-либо скрипт на фреймворк-транслятор. Т.е. создаваемый скрипт запрашивает функционал у фреймворка-транслятора, а он, в свою очередь (при необходимости), у базового фреймворка. Фреймворк-транслятор другого языка поступает точно так же. Из "обязательных" трансляторов предположу VBS2js, AutoIt2js (раз уж Вы его выбрали ), возможно, PHP2js, как весьма распространённого языка. Остальные, как Ruby, например, можно отдать на откуп энтузиастам, которые будут запрашивать/предлагать свои расширения/дополнения имеющегося функционала базового фреймворка по своим потребностям, а Вы будете расширять/дополнять...

При этом, в базовый фреймворк можно добавлять и полезный функционал, отсутствующий в других языках. Добавлять ли ссылки на него в трансляторы - решается отдельно для каждого транслятора, но он может быть доступен напрямую: скрипт <-> базовый фреймворк.

26

Re: JScript: Фреймворк

dab00 пишет:

Наверное подразумевали Number.prototype.

Точно. Это у меня опечатка.

greg zakharov пишет:

Диапазон знакового целочисленного типа, насколько помню, лежит в пределах от -2147483648 до 2147483647, и если попытаться определить тип этих значений с помощью оператора typeof, получим Number. Следовательно, определить самостоятельно целочисленный тип в JavaScript более, чем возможно, правда есть несколько нюансов, например, как идентифицировать Integer без приведения к таковому с помощью parseInt?

В этом плане (если действительно есть такая необходимость - определение целочисленности) есть интересный ход, хак, но изящный


var x = Math.PI;
alert(x >>> 0);
alert(x >> 0);
alert(x << 0);
alert(x ^ 0);
alert(x | 0);

Вcе они а) отбрасывают дробную часть числа, б) обнуляют результат, если число по модулю превышает 0xFFFFFFFF (2^32-1), Но здесь есть одна тонкость: числа больше 0x7FFFFFFF можно рассматривать как отрицательные так и положительные. Например, 0x80000001:


0x80000001 >>  0 == -2147483647
0x80000001 >>> 0 == 2147483649

Справедливо и обратное:


-1 >>  0 == -1
-1 >>> 0 == 4294967295

Иногда может потребоваться одно, иногда - другое.

Rumata пишет:

..."валить" в все в одну кучу - не есть хорошо.

greg zakharov пишет:

Позвольте заметить, что конечное слово все же за разработчиком. Единственное, на что действительно стоит обратить внимание в данном случае - доступность документации.

Согласен с Вами. Но ограниченный набор отдельных файлов, каждый из которых содержит определенный, ограниченный функционал, лучше, чем один сплошной файл. Если есть зависимости (фнукционал файла А зависит от некотрых функций файла Б)  - задокументировать в шапке файла.

Так любой сможет с легкостью использовать часть функционала не вытягивая всю библиотеку (например, если кому-то захочется использовать "массивные" функции forEach, map и прочие в реализации JSMan, то он, кто-то легко разберется, что искомое находится в файле Array.js).

Serge Yolkin пишет:

...не загоняясь по синтаксису других языков. Таким образом, ForEach и each из разных фреймворков-трансляторов могут ссылаться на один и тот же код базового фреймворка.

Для меня здесь ключевая фраза - "не загоняясь по синтаксису других языков". Думаю, что не стоит приближать один язык к другому. JS от этого лучше не станет, если он будет похожим на AutoIt. Если кто-то желает програмировать на JS, похожем на AutoIt, может быть он выбрал не тот язык для программирования? В частности, для меня Ruby далек, так же как Cobol, поэтому первые ассоциации при виде each связаны с jQuery, в котором он реализован через абы как - передача параметров прямо противоположна стандартному forEach. Вот пример (об чем думал Джон?):


var x = [1, 2, 3];
$.each(x, function(index, value) { alert(value); });

x.forEach(function(value, index) { alert(value); });
JSman пишет:

что есть "базовый" js-фреймворк?:) Это сборище функций, которое я сам придумаю?.

Согласен полностью. Фактически, фреймворк - это некий набор готовых утилит, методов, оторые упрощают разработку. В теме уже несколько раз упоминался Closure, поэтому разделение на файлы весьма логично, коли лишнее будет удалятся автоматически на этапе сборки.

( 2 * b ) || ! ( 2 * b )

27

Re: JScript: Фреймворк

Rumata пишет:

...хак, но изящный...

Ну хорошо, а смысл плодить псевдотипы? Вот скажите, на JavaScript написано немало кода, но при этом никто не жаловался на отсутсвие целочисленных типов со знаком или без оного, - смысл ныне браться за перераспределение типов? Игры со смещением таковыми и останутся, если они неприменимы на практике, а на практике, еще раз повторю, никто не заморачивается отсутсвием некоторых типов в JavaScript. Саму же идею можно вполне взять на карандаш.

Rumata пишет:

Согласен с Вами. Но ограниченный набор отдельных файлов, каждый из которых содержит определенный, ограниченный функционал, лучше, чем один сплошной файл. Если есть зависимости (фнукционал файла А зависит от некотрых функций файла Б)  - задокументировать в шапке файла.

Простите, но идея классов мной уже выдвигалась, однако была отвергнута, поэтому еще раз повторюсь - давайте с уважением отнесемся к мнению автора темы.

Rumata пишет:

Думаю, что не стоит приближать один язык к другому.

Увы, но каждый из языков что-то наследует от предшественников. Фреймворк в данном случае по сути является оберткой над встроенными средствами языка, реализующим функции AutoIt, в виду чего, а также

Serge Yolkin пишет:

Остальные, как Ruby, например, можно отдать на откуп энтузиастам...

могу лишь заметить, что уже полгода как работаю над реализацией интерпретатора Ruby на JavaScript, - именно интерпретатора, а не реализацией функций языка на JavaScript.

28 (изменено: Rumata, 2013-11-16 19:08:50)

Re: JScript: Фреймворк

greg zakharov

Ну хорошо, а смысл плодить псевдотипы?

Я то лично противник этого. Но речь шла именно о

greg zakharov пишет:

определить самостоятельно целочисленный тип в JavaScript более, чем возможно, правда есть несколько нюансов, например, как идентифицировать Integer без приведения к таковому с помощью parseInt?

Поэтому я и привел то решение. Кому надо - тот воспользуется и напишет свою реализацию определения целого числа.

идея классов мной уже выдвигалась, однако была отвергнута, поэтому еще раз повторюсь - давайте с уважением отнесемся к мнению автора темы.

Ни в коей мере не отвергаю мнение ни автора (JSMan в данном случае), ни чье-либо другое (Ваше). Речь только о разделении единого файла на этапе разработки на неколько отдельных файлов. Которые проще сопровождать и проще использовать отдельно.

Фреймворк в данном случае по сути является оберткой над встроенными средствами языка, реализующим функции AutoIt

Так ли необходимо реализовывать функционал одного языка в другом с точностью до API? Не лучше ли использовать другой язык? Например, в своей работе я использую очень часть Perl и JScript. Будучи на win-машине, использую js, если мне достаточно его средств, либо перехожу на Perl, если решение на нем быстрее проще в реализации и сопровождении. Тем более если это сиюминутная задача, то я возьму Perl (иногда JS, потому что мне не нравится работа с временем в Perl). Но я не создаю фреймфорк perl2js.
Но это только мое мнение. Каждый язык имеет свои средства работы с существующими объектами. дублирование классного средства одного языка в другом должно быть органично в рамках данного языка. Например, есть несколько реализаций C-подобной функции sprintf в js. Можно использовать существующее готовое, можно переписать с нуля. Задача стоит в API - как использовать функцию: sprintf("форматирующая строка", аргументы) или "форматирующая строка".sprintf(аргументы). В данном случае оба варианта хороши, но второй - более js-подобный.
Автор же волен решать свои задачи, если они ему необходимы. Тем более если в массах они найдут отклик.

( 2 * b ) || ! ( 2 * b )

29

Re: JScript: Фреймворк

В общем, довольно интересно почитать рассуждения. Конечно, всем не угодишь. У каждого опыт разный. Я несколько загрузился по теме "что же является базовым фреймворком". Рассуждения привели к следующему.

С одной стороны, говорят необходимо разбить на модули все функции, которые связаны с массивами, строками, числами, файловой системой. На самом же деле, следуя такой логике, должен появиться отдельный файл работы с реестром (что сводится по сути к 5 функциям), работы с вебом http (опять же до 5 функций), работа с процессами (3-4 функции) и т.п. А к чему это приведет?

Код разработчика, который работает с файловой системой, интернетом, а также мапит массив, обязан включить следующий код:


var AR = include("array.js");
var FS = include("filesystem.js");
var Inet = include("http.js");

То есть, по такой логике, я должен досконально знать какая именно функция находится в каждом файле фреймворка. Зачем нам такая модульность?

Окей, продолжу рассуждение. Функций же полно? А языки разные. Как делить будем? Придется либо в коде каждой тематической библы помечать из какого языка функция, либо создавать модуль типа <Язык_программирования>.<Модуль>. Каждый файл опять же надо будет изучать разработчику. Сколько инклудов будет в коде разработчика? Тьма. Запутаемся все. Основных функций для разработчика вполне достаточно не более 100.

Так что же все-таки можно назвать базовой частью фреймворка?
Базовая часть фреймворка, то бишь его основа — это те функции, которые нужны в первую очередь разработчику. А это означает, что разработчику нужно работать и со строками, с массивами, файловой системой, интернетом и т.п. Значит основной модуль должен это все включить в себя.

Рассмотрим псевдо-код (на базе разрабатываемого фреймворка), который является решением этой темы:


FileCopy( FileFind("%USERPROFILE%", /\.mab$/), "\\\\server\\mab\\name.mab");

а если вообще пофантазировать, то получится такое:


FileCopy( FileFind("%USERPROFILE%", /\.mab$/), @"\\server\mab\name.mab");

Не правда ли просто? И таких примеров решений на форуме можно привести полным-полно. Даже с инклудами играть не хочется.

Я понимаю, если, допустим, кто-то захочет реализовать работу с облаком Яндекс.Диск, Google Drive, FTP. Вот тогда - да. Модуль определенно нужен. Потому что модуль не должен у разработчика отбирать "основной" функционал, он преподносит ему дополнительный/изолированный функционал.

Что касается псевдо типов, то по мне это все надуманно. Кому реально нужны integer, float? Каков смысл? Но научить typeof отличать объект от array необходимо.

Далее, что касается sprintf. Rumata, идеологически я предпочитаю оба варианта. Неиспользуемое все равно при обработке будет выпилено. Не бойтесь избыточности.

В общем, подведу маленький итог своих рассуждений. То, что написано в первом топике, а также в секции To Do - это будет базовым фреймворком, плюс кое-что еще. Трансляторы языков — об этом рано говорить. Взять тот же perl. Реально под него все с нуля надо будет писать. Что поделаешь.

У меня вопрос к разработчикам. Хорошо, ну вот поделим сейчас базовую часть на string.js, array.js, fs.js, process.js, base.js. Что дальше будет? Сразу начнем программировать? :-D

UPD: Обновил.

+ открыть спойлер

StringCompare Compares two strings with options.
StringInStr Checks if a string contains a given substring.
StringIsAlNum Checks if a string contains only alphanumeric characters.
StringIsAlpha Checks if a string contains only alphabetic characters.
StringIsASCII Checks if a string contains only ASCII characters in the range 0x00 - 0x7f (0 - 127).
StringIsDigit Checks if a string contains only digit (0-9) characters.
StringIsFloat Checks if a string is a floating point number.
StringIsInt Checks if a string is an integer.
StringIsLower Checks if a string contains only lowercase characters.
StringIsSpace Checks if a string contains only whitespace characters.
StringIsUpper Checks if a string contains only uppercase characters.
StringIsXDigit Checks if a string contains only hexadecimal digit (0-9, A-F) characters.
StringLeft Returns a number of characters from the left-hand side of a string.
StringLen Returns the number of characters in a string.
StringLower Converts a string to lowercase.
StringMid Extracts a number of characters from a string.
StringRight Returns a number of characters from the right-hand side of a string.
StringStripCR Removes all carriage return values ( Chr(13) ) from a string.
StringStripWS Strips the white space in a string.
StringTrimLeft Trims a number of characters from the left hand side of a string.
StringTrimRight Trims a number of characters from the right hand side of a string.
StringUpper Converts a string to uppercase. Asc Returns the ASCII code of a character.

30

Re: JScript: Фреймворк

Как эта ф-я работает/должна работать?

// Add ECMA262-5 Array methods if not supported natively
//
if (!('indexOf' in Array.prototype)) {
    Array.prototype.indexOf= function(find, i /*opt*/) {
        if (i===undefined) i= 0;
        if (i<0) i+= this.length;
        if (i<0) i= 0;
        for (var n= this.length; i<n; i++)
            if (i in this && this[i]===find)
                return i;
        return -1;
    };
}

даже, если заменить знак "<" на ">" в последнем if , то она всегда будет возвращать индекс элемента массива
начиная с 0. Зачем тогда параметр i?

var myArr = ["aaa", "bbb", "ccc"];
myArr.indexOf('ccc', 0);             // вернёт 2
myArr.indexOf('ccc', 1);             // вернёт также 2...

31 (изменено: Rumata, 2013-11-18 10:52:35)

Re: JScript: Фреймворк

Зачем тогда параметр i?

поиск с заданной позиции:


x = ['a', 'b', 'c', 'a', 'b']
x.indexOf('b') // == 1
x.indexOf('b', 2) // == 4

Можно реализовать поиск всех вхождений заданного элемента.

( 2 * b ) || ! ( 2 * b )

32

Re: JScript: Фреймворк

Rumata пишет:

поиск с заданной позиции:


x = ['a', 'b', 'c', 'a', 'b']
x.indexOf('b') // == 1
x.indexOf('b', 2) // == 4

Можно реализовать поиск всех вхождений заданного элемента.

Дык не работает же... о том и пишу....

33

Re: JScript: Фреймворк

im2002, покажите код. Я проверил, все работает.

34

Re: JScript: Фреймворк

Обновил первый пост. Не смотря на большую занятость, разработка мелкими шажками продолжается. Код на HTA полностью функционирует.

Первый этап скоро добью. Осталось порядка 50-60 функций, но это пустяки. Затем, покажу реализацию отброса неиспользуемых функций, чтобы результирующий код был как можно компактнее и проще.

35 (изменено: dab00, 2014-03-28 07:41:46)

Re: JScript: Фреймворк

JSman пишет:

Не смотря на большую занятость, разработка мелкими шажками продолжается

Хочу познакомить с одной интересной находкой - Traceur.
Если правильно понял - пишем на ES6 - компилируем в ES3. По-моему в тему. Сорри, пока сам не пробовал.

36

Re: JScript: Фреймворк

dab00, в точку :-). Это и есть третий этап.

37

Re: JScript: Фреймворк

Работа не стоит на месте.

Решена проблема избыточного кода. Урезается на ура. Остается разобраться с удалением неиспользуемых методов прототипов.

Итак, в первую очередь вам понадобится Google Closure.
Файл compiler.jar расположите рядом с со скриптовым файлом compiler.js. Код compiler.js приведен ниже.

Для работы бросьте ваш скрипт на compiler.js и получите оптимизированный для исполнения код.


// compiler.js
// если осуществлялся запуск скрипта без параметра, то завершаем работу.
if (WScript.Arguments.length == 0) WScript.Quit();

var WshShell = new ActiveXObject("WScript.Shell");

var FileName = WScript.Arguments(0); // путь файла для обработки.
var FileNameTmp =  GetScriptDir()+GenerateString(12); // временный файл для сохранения промежуточного результата
var FileNameOut =  (/\./.test(FileName) ? FileName.replace(/\.[^\.]+$/, ".out.js") : (FileName + ".out.js")); // путь файла с результатами

var FSO = new ActiveXObject("Scripting.FileSystemObject");
var ForReading = 1,
    ForWriting = 2,
    ForAppending = 8;

// аналог VB-MsgBox в JS
function MsgBox(strText, strTitle, nType) {
    return WshShell.Popup(strText, 0, strTitle, nType);
}

//генерирует строку из случайных символов латиницы цифр.
function GenerateString(L) {
    if (!L) L = 8;
    return new ActiveXObject('Scriptlet.TypeLib').Guid.replace(/[^\w]+/g, "").slice(0, L);
}

// отображаем значение s в диалоговом окне. При нажатии на "отмена" осуществляется выход из кода. 
function alert(s)
{
    return;
    if (MsgBox(s, "", 1)==2) WScript.Quit();
}

//возвращает директорию расположения скрипта
function GetScriptDir() {
    return GetScriptFullPath().replace(/[^\\]+$/g, "");
}

//возвращает имя скриптового файла. Универсально для HTA и WSH.
function GetScriptFullPath() {
    if (this.location && this.location.href) return location.href.replace(/^.+\/\/\//, "").replace(/\//g, "\\");
    if (this.WScript) return WScript.ScriptFullName;
    return "";
}

//устанавливаем директорию нахождения скрипта в качестве рабочей. 
WshShell.CurrentDirectory = GetScriptDir();

// Открываем файл и читаем код
var f = FSO.OpenTextFile(FileName, 1, 0, -2);
var source = f.ReadAll();
f.Close();

//парсим js-код, выявляем конструкции языка: регулярные выражения, комментарии, строковые литералы.
//на выходе имеем двухуровневый массив [тип_конструкции][значение].
var tmp = ParseJS(source);

var resFile = FSO.OpenTextFile(FileNameTmp, 2, 1);

//выявляем методы и свойства объектов в коде и меняем их синтаксическое написание так: asd.e() -> asd["e"]()
// сохраняем это в промежуточном файле.
resFile.Write(Replacer(tmp));
resFile.Close();

// запускаем GoogleClosure для обработки временного файла и сохраняем в выходной файл.
WshShell.Run("%WinDir%\\System32\\java.exe -jar \""+GetScriptDir()+"compiler.jar\" --js \""+FileNameTmp+"\" --formatting=pretty_print  --compilation_level ADVANCED_OPTIMIZATIONS --use_only_custom_externs --use_types_for_optimization --js_output_file \""+FileNameOut+"\"", 1, 1);
FSO.DeleteFile(FileNameTmp, true)

MsgBox("Результаты сохранены в файле: " + FileNameOut);
WScript.Quit();

//функция парсинга js. code - текстовый фрагмент, который будет обработан
//парсим js-код, выявляем конструкции языка: регулярные выражения, комментарии, строковые литералы.
//на выходе имеем двухуровневый массив, где элемент - это [[тип_конструкции], [значение]].

function ParseJS(code) {
    var tmp = code, // копия code, которая будет обрабатываться и изменяться в процессе парсинга.  
        found = "", // строка с найденной начальной конструкцией языка
        startpos = 0,
        result = []; // результирующий массив
    var searchValues = /\/\*\[?|["']|\/\/|(?:(^|[;\}\{\(=!\?]|return)\s*)\/(?![\*\/])/m;
    var types = { 
        '/*': "comment",
        '/*[': "resource",
        '"': "string",
        "'": "string",
        '//': "comment",
        "/": "regexp"
    }; // типы конструкций языка


// находим точку начала входа в конструкцию
    function getStartPointOfValues(m) {
        
        var t=0;
        found = m;
        var pos = arguments[arguments.length-2];
               
        if (/[^\/]\/$/.test(m)) {
            found = "/"; t=m.length-1;
        }
        
        result.push(["code", tmp.slice(0,pos+t)]);
        alert(tmp.slice(0,pos));
        
        tmp = tmp.slice(pos + m.length);
    }

// находим точку окончания конструкции языка
    function getEndPointOfValues(m) {
        var pos = arguments[arguments.length-2];
        var content = tmp.slice(0, pos);
        
        result.push([types[found], found+tmp.slice(0,pos + m.length)]);
        tmp = tmp.slice(pos + m.length);
    }

// функция перебора кода
    function findValues() {
        tmp.replace(searchValues, getStartPointOfValues);

        if (found == '"') tmp.replace(/(?:^"|(?:\\\\|[^\\])")/, getEndPointOfValues);
        if (found == "'") tmp.replace(/(?:^'|(?:\\\\|[^\\])')/, getEndPointOfValues);
        if (found == '//') tmp.replace(/[\r\n]/, getEndPointOfValues);
        if (found == '/*' || found == '/*[') tmp.replace(/\*\//, getEndPointOfValues);
        if (found == "/") tmp.replace(/(?!\\).\//, getEndPointOfValues);
        found = "";
        return tmp;
    }

    //Перебираем содержание.
    while (tmp != findValues()) {}
    result.push(["code",tmp]);
    tmp = "";
    return result;
}


function Replacer(strct)
{
    var result=[];
    
    for (var i=0, l=strct.length; i<l; i++)
    {
        if (strct[i][0] == "code") result.push(strct[i][1].replace(/\.\s*([\$_a-z0-9]+)/ig, '["$1"]'));
        else result.push(strct[i][1]);
    }
    return result.join("");
}

На здоровье!

Что касается предложения с множеством тематических файлов (например, string.js, array.js и т.п.) для облегчения разработки, то оно скоро будет реализовано. Постараюсь использовать гитхаб (увы, не привык). А вообще, пора уже добить проект :-)

38

Re: JScript: Фреймворк

Функция подключения модулей.

Этот вариант функции пока подключает файл скрипта, можно указать каталог, тогда буду подключены все файлы в каталоге.

Немного предисловия. Ядро фреймворка состоит из нескольких файлов, функции которых будут лежать в глобальном пространстве. Большая часть функций ядра перечислена в посте № 1.

Далее, я сделал возможность не только расширения глобального объекта, но и возможность замкнуть это на свой объект.


var GlobalObject = this;

// Include.Libs - словарь модулей
// Include.DefaultNameSpace - область видимости по умолчанию
function Include(JsPath, NameSpace)
{
    var method, module, lib, code, stream;
    var FSO = new ActiveXObject("Scripting.FileSystemObject");
    var WshShell = new ActiveXObject("WScript.Shell");
    
    JsPath = WshShell.ExpandEnvironmentStrings(JsPath);
    // если файла нет, то оканчиваем работу
    
    if (FSO.FolderExists(JsPath)) 
    {
        var files = new Enumerator(FSO.GetFolder(JsPath).Files);
        var scripts = [];
        for (; !files.atEnd(); files.moveNext())
        {
            if (/\.js$/i.test(files.item())) scripts.push(files.item());
        }
       
        for (var i=0; i<scripts.length; i++) Include(scripts[i], NameSpace);
        return true;
    }
    
    if (!FSO.FileExists(JsPath)) return false;
    // избавляемся от относительных путей, формируем полный путь. 
    JsPath = FSO.GetFile(JsPath).Path;
    // устанавливаем пространство имен, на которое будет распространяться импортируемый модуль.
    // если оно не задано в функции, то испортируемые функции подключаются к глобальному объекту (точнее к указателю this).
    if (!arguments.callee.DefaultNameSpace)arguments.callee.DefaultNameSpace = GlobalObject;
    if (!NameSpace) NameSpace = arguments.callee.DefaultNameSpace;
    if (!arguments.callee.Libs) arguments.callee.Libs = {};
    lib = arguments.callee.Libs[JsPath];
    // если модуль ранее подгружался
    if (lib) 
    {
        // то импортируем уже загруженные указатели функций модуля в объект, который кеширует перечень функций
        // нужна оптимизация, которая предотвратит повторное присвоение функций в namespace
        for (method in lib)
        {
            NameSpace[method]=lib[method];
        }
        return true;
    }
    else 
    {
        lib = arguments.callee.Libs[JsPath] = {};
        // если библиотека не подгружалась ранее, то осуществляется ее чтение и интерпретация
        if (FSO.GetFile(JsPath).Size==0) return "";
        stream = FSO.OpenTextFile(JsPath, 1, 0, -2),
        code = stream.ReadAll();
        stream.Close();
        module = eval("("+code+")");
        // далее, данные помещаются и в кеш, и в namespace
        for (method in module)
        {
            lib[method]=module[method];
            NameSpace[method]=module[method];
        }
    }
    return true;
}

   
Include("test3.js");
A();

var s = {};
Include("test3.js", s);
s.A();

Include.DefaultNameSpace = GlobalObject;     
(function(){
    Include("test3.js");
    A();
}
)();

Модуль выглядит примерно так:


(
(function (){
    MsgBox("Hello from module")
}
)(),

{
A : function () {
    MsgBox("123");
},

B : function () {
}

}
)

Как мы видим есть функция инициализации, которая будет вызвана только один раз, в какой бы неймспейс модуль не подключался бы. Экземпляры функций при разных неймспейсах не создаются дополнительно. Все кешируется. Объектам раздаются указатели на функции. Принципиально отказался от приватных переменных.

Теперь ядро фреймворка разделяю на файлы, чтобы можно было легко их проверять на корректность.

Есть проблема отладки, так как используется eval.
Также будет добавлена проверка конфликта имен функций модуля.

39

Re: JScript: Фреймворк

Черновик фреймворка и кодогенератора. В результате будет создан файл output.js без лишних функций.


Include("core");

function Main()
{
    FileCreateShortcut(GetWindowsDir() + "\\explorer.exe", GetDesktopDir() + "\\cmd.exe.lnk", GetWindowsDir(), "/e,c:\\", "Tooltip description of the shortcut.", GetSystemDir() + "\\shell32.dll", "CTRL+ALT+t", "15", 7);
    var res = FileGetShortcut(GetDesktopDir() + "\\cmd.exe.lnk");
    MsgBox(res);
    res[0]=GetWindowsDir() + "\\System32\\calc.exe";
    FileCreateShortcut.apply(null, res);
    res = FileGetShortcut(GetDesktopDir() + "\\cmd.exe.lnk");
    MsgBox(res);
    Exit();
}


FwBuildCode("Main", "output.js");
Exit();

// Include.Libs - словарь модулей
// Include.DefaultNameSpace - область видимости по умолчанию
function Include(JsPath, NameSpace)
{
    this.GlobalObject = this;
    var method, module, lib, code, stream;
    var FSO = new ActiveXObject("Scripting.FileSystemObject");
    var WshShell = new ActiveXObject("WScript.Shell");
    
    JsPath = WshShell.ExpandEnvironmentStrings(JsPath);
    // если файла нет, то оканчиваем работу
    
    if (FSO.FolderExists(JsPath)) 
    {
        var files = new Enumerator(FSO.GetFolder(JsPath).Files);
        var scripts = [];
        for (; !files.atEnd(); files.moveNext())
        {
            if (/\.js$/i.test(files.item())) scripts.push(files.item());
        }
       
        for (var i=0; i<scripts.length; i++) Include(scripts[i], NameSpace);
        return true;
    }
    
    if (!FSO.FileExists(JsPath)) return false;
    // избавляемся от относительных путей, формируем полный путь. 
    JsPath = FSO.GetFile(JsPath).Path;
    // устанавливаем пространство имен, на которое будет распространяться импортируемый модуль.
    // если оно не задано в функции, то испортируемые функции подключаются к глобальному объекту (точнее к указателю this).
    if (!arguments.callee.DefaultNameSpace)arguments.callee.DefaultNameSpace = GlobalObject;
    if (!NameSpace) NameSpace = arguments.callee.DefaultNameSpace;
    if (!arguments.callee.Libs) arguments.callee.Libs = {};
    lib = arguments.callee.Libs[JsPath];
    // если модуль ранее подгружался
    if (lib) 
    {
        // то импортируем уже загруженные указатели функций модуля в объект, который кеширует перечень функций
        // нужна оптимизация, которая предотвратит повторное присвоение функций в namespace
        for (method in lib)
        {
            NameSpace[method]=lib[method];
        }
        return true;
    }
    else 
    {
        lib = arguments.callee.Libs[JsPath] = {};
        // если библиотека не подгружалась ранее, то осуществляется ее чтение и интерпретация
        if (FSO.GetFile(JsPath).Size==0) return "";
        stream = FSO.OpenTextFile(JsPath, 1, 0, -2),
        code = stream.ReadAll();
        stream.Close();
        module = eval("("+code+")");
        // далее, данные помещаются и в кеш, и в namespace
        for (method in module)
        {
            lib[method]=module[method];
            NameSpace[method]=module[method];
        }
    }
    return true;
}

https://mega.co.nz/#!xpY2DaAI!0Wf0FycvN … ymnU5NP8oE

40 (изменено: Parazit, 2018-10-02 11:09:31)

Re: JScript: Фреймворк

Del.