Создаем свою библиотеку для OneScript

Программирование - Практика программирования

124
Как упаковать свою библиотеку в пакет? Что такое загрузчик и зачем он нужен? Как вообще создать свою библиотеку? Разбираемся на примере.

Оглавление

Введение. 2

Подготовка окружения. 2

Первый прототип. 2

Под капотом – загрузка библиотек. 6

Соглашение о структуре каталогов. 9

Первые тесты.. 11

Тестирование с помощью 1testrunner. 12

Классы и модули. 15

Перечисления. 19

Под капотом – lib.config. 21

Автодополнение. 22

Публичные и приватные классы и модули. 23

Сборка пакета. 25

Публикация пакета в хаб. 28

Заключение. 28

 

Введение

В своей предыдущей статье я рассказывал об имеющихся в экосистеме OneScript полезных библиотеках и приложениях. В этой статье мы попробуем написать свою библиотеку с нуля. Заранее извиняюсь за огромное количество упоминаний слова «библиотека» в тексте статьи :)

В рамках текущего повествования будут рассматриваться библиотеки, написанные на языке 1С. Написание библиотеки на C#/F#/VB.Net для OneScript заслуживает отдельной статьи.

Для начала напомню, что такое «библиотека». Библиотека – это особым образом упакованный сценарий (или набор сценариев), которые можно переиспользовать в других сценариях и подключать с помощью инструкции #Использовать. Инструкция #Использовать (в базовом варианте) умеет подключать библиотеки «по имени» и по пути к корневому каталогу библиотеки.

Подготовка окружения

Определимся с необходимым окружением.

  1. Естественно, нам понадобится сам движок - http://oscript.io/
  2. Разработку я буду вести в Visual Studio Code - https://code.visualstudio.com/
  3. Для упрощения редактирования сценариев OneScript у меня установлен плагин «Language 1C (BSL) Plugin)» - https://marketplace.visualstudio.com/items?itemName=xDrivenDevelopment.language-1c-bsl
  4. Для упрощения запуска и получения возможностей отладки, установим отладчик OneScript для Visual Studio Code. Если вы используете "стабильную" версию движка OneScript, то вы можете установить его через MarketPlace, встроенный в VSCode - имя пакета OneScript Debug. Если вы используете "ночную" версию движка, то необходимо скачать файл с расширением «vsix» со страницы http://oscript.io/download и установить его вручную через команду "Установка из VSIX" в VSCode

В рабочем каталоге создадим два новых подкаталога:

  • calculation – здесь будет жить наша библиотека
  • my_project – здесь будет жить проект, который использует библиотеку

Как и положено в любом how-to, мы будем писать библиотеку, складывающую и умножающую числа :) Еще и тестами ее покроем.

Первый прототип

Для начала заложим прототип нашей библиотеки. Для удобства я открою в VSCode рабочий каталог с двумя подкаталогами:

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

Функция Сложить(Слагаемое1, Слагаемое2) Экспорт

    Возврат Слагаемое1 + Слагаемое2;

КонецФункции

 

В корне каталога my_project создадим script.os, который будет изображать наше полезное прикладное ПО, использующее библиотеку calculation

Содержимое скрипта script.os:

#Использовать "../calculation"

 

Сумма = Вычислитель.Сложить(2, 2);

 

Сообщить(Сумма);

Разберемся построчно с написанным.

В первой строке используется специальная инструкция «Использовать», которая пытается найти и подключить библиотеку. Данной инструкции передается путь к корневому каталогу библиотеки, т.е. происходит подключение «по пути». Путь может быть как абсолютным, так и относительным. Для удобства мы используем относительный.

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

В последней строке мы выводим в консоль полученное значение.

Как же теперь это запустить? Есть несколько вариантов.

Классический – открыть консоль или встроенный в VSC терминал (сочетание клавиш ctrl-ё или команда «Посмотреть: Переключить интегрированный терминал») и выполнить скрипт напрямую с помощью интерпретатора oscript:

Второй вариант – с помощью встроенных команд по запуску скриптов. Нажмем F1 и в поисковой строке наберем «task». Выберем пункт «Задачи: Выполнить задачу»:

Появится еще одно окно, в котором нам нужно выполнить одну команду «oscript: OneScript: run»

Но мы же не просто так ставили отладчик?

Третий способ – запуск скрипта с помощью 1Script Debugger. Для начала нам надо создать специальный конфигурационный файл launch.json. Сделать это можно почти автоматически – нужно нажать в редакторе клавишу F5, в вывалившемся сверху окошке выбрать “1Script Debugger”. После этого в подкаталоге .vscode появится файл launch.json примерно со следующим содержимым:

Его назначение – хранить информацию о «конфигурациях запуска». Одну такую конфигурацию мы только что и создали.

Вернемся к нашему скрипту script.os и снова нажмем F5. После запуска на некоторое время должно появиться с окошком контроля выполнения кода (на скриншоте сверху слева) и в «Консоли отладки» (на скриншоте снизу) должно вывестись «4».

Если вы вообще не видите какого-либо окна снизу, то открыть «Консоль отладки» можно:

  • нажатием комбинации клавиш Ctrl+Shift+Y
  • выполнив команду «Посмотреть: Консоль отладки» из командного меню, вызываемого по клавише F1
  • выполнив команду «Вид» -> «Консоль отладки» из главного меню (вверху окна VSCode)
  • переключившись на вкладку «Отладка» (в левой части VSCode) и нажав кнопку «Консоль отладки»

Тем, кто успел открыть терминал, нужно будет вручную ткнуть по заголовку вкладки «Консоль отладки»

Точки останова тоже работают. И «табло» есть – тут оно называется «Контрольные значения». Оно не такое богатое, как в конфигураторе, но тоже очень сильно помогает.

Поздравляю, вы написали свою первую библиотеку! :)

Под капотом – загрузка библиотек

Постараемся понять, почему и как оно работает.

Пока мы не успели ничего сконфигурировать в нашей библиотеке - наш единственный сценарий «Вычислитель» лежит в корне каталога библиотеки. Когда мы «используем» с помощью соответствующей инструкции какую-либо библиотеку, OneScript выполняет определенную последовательность действий.

Сначала интерпретатор в корневом каталоге библиотеки ищет и пытается выполнить специальный «волшебный» сценарий package-loader.os – так называемый «загрузчик библиотек». Это специальный сценарий, который, как следует из его названия, занимается загрузкой библиотек – добавлением в область видимости классов и модулей, которые предоставляются библиотекой. В специальной процедуре-обработчике «ПриЗагрузкеБиблиотеки» среди параметров есть «СтандартнаяОбработка». Если в результате работы загрузчика она останется выставлена в «Истина» или файл package-loader.os в корне библиотеки вовсе отсутствует, то загрузка библиотеки переходит к следующему шагу.

На следующем шаге выполняется загрузчик «по умолчанию» - это такой же файл package-loader.os, который располагается в «системном каталоге библиотек». Значение системного каталога библиотек берется из параметра lib.system в файле oscript.cfg, расположенного либо в каталоге с точкой входа в приложение (первоначально запускаемый сценарий, например my_project/script.os) либо в каталоге самого интерпретатора oscript.exe. В базовом варианте (как у нас), lib.system начинает вести в место установки OneScript, подкаталог lib.

В моем случае, OneScript установлен в %USERPROFILE%/AppData/Local/ovm/current. Расположение каталогов и файлов на скриншоте ниже.

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

На заключительном шаге загрузки библиотеки в дело вступает уже сам движок OneScript. Он максимально категоричен – ищет все файлы с расширением os в корневом каталоге библиотеки и подключает их как «модули». Именно это и произошло в нашем случае – файл Вычислитель из корня библиотеки был подключен как «модуль» и стал доступен для вызова и обращения «через точку» в сценарии script.os.

Схематично данный процесс можно представить так:

Чтобы развеять страх по поводу всей этой конструкции загрузчиков, попробуем вмешаться в процесс.

Создадим в каталоге calculation файл package-loader.os со следующим содержимым:

Процедура ПриЗагрузкеБиблиотеки(Путь, СтандартнаяОбработка, Отказ)

    

    Сообщить("Я - загрузчик библиотеки calculation!");

 

    СтандартнаяОбработка = Ложь;

 

    ПутьКМодулю = ОбъединитьПути(ТекущийСценарий().Каталог, "Вычислитель.os");

    ДобавитьМодуль(ПутьКМодулю, "Вычислитель");

 

КонецПроцедуры

 

В первой строке обозначена сигнатура метода. В параметре «Путь» передается путь к каталогу библиотеки, СтандартнаяОбработка – флаг продолжения выполнения последовательности действий по процессу загрузки, а Отказ – стандартный флаг сигнализирования об ошибках при загрузке библиотеки.

Вторая строка просто выводит сообщение в консоль.

Третья строка говорит интерпретатору OneScript, что текущий сценарий сможет загрузить эту библиотеку, и после его выполнения дополнительных действий совершать не требуется (см. схему).

В четвертой строке мы вычисляем путь к модулю, который хотим подключить. Для этого используются функции:

  • «ТекущийСценарий», возвращающая информацию о выполняемом в данный момент файле сценария (в том числе его расположение)
  • «ОбъединитьПути», складывающая различные части пути к файлам с учетом системных разделителей пути

В пятой строке вызывается процедура «ДобавитьМодуль», выполняющая фактическую регистрацию объекта в пространстве имен, с двумя параметрами:

  • Путь к подключаемому сценарию
  • Имя, под которым будет зарегистрирован объект

В пару к процедуре «ДобавитьМодуль» существует процедура «ДобавитьКласс»

Если мы снова откроем сценарий script.os и нажмем F5, то увидим в консоли отладки новое сообщение:

Наш загрузчик успешно отработал. Он не только вывел сообщение в консоль, но и корректно зарегистрировал модуль.

Соглашение о структуре каталогов

Рано или поздно библиотека выйдет за пределы одного-двух файлов в корне репозитория. Захочется вынести отдельно исходники библиотеки, тесты, документацию, служебные файлы… В конце концов, скоро мы и до классов дойдем, а стандартный загрузчик библиотек (на уровне интерпретатора) умеет подключать модули, но не классы.

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

Существует «соглашение о структуре каталогов» библиотеки. Все файлы *.os, которые располагаются в каталогах:

  • Классы
  • Classes
  • src/Классы
  • src/Classes

подключаются как «классы».

Аналогичным образом все файлы *.os, которые располагаются в каталогах:

  • Модули
  • Modules
  • src/Модули
  • src/Modules

подключатся как «модули».

Соглашение это не кровью написанное, а вполне определенным образом зашито в системном загрузчике библиотек. Если вы откроете файл package.loader (МестоУстановкиOneScript/lib/package-loader.os), то в процедуре «ПриЗагрузкеБиблиотеки» увидите вызов процедуры «ОбработатьСтруктуруКаталоговПоСоглашению». Именно в этой процедуре и указан список каталогов, в котором производится поиск.

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

Для начала удалим файл package-loader.os из каталога calculation – он нам больше не нужен. Затем создадим подкаталог «src» и в нем подкаталог «Модули». Переместим туда файл «Вычислитель.os» и снова выполним (F5) сценарий script.os

Если все сделано без ошибок, то в консоли отладки будет выведена сумма двух чисел.

Убедимся, что это отработал системный загрузчик библиотек, а не очередная «магия» интерпретатора OneScript. Переключимся на вкладку «Терминал», запустим cmd (если по умолчанию терминал запускается в powershell) и выполним следующую команду:

(set OSLIB_LOADER_TRACE=1) && (oscript .\my_project\script.os)

Установка переменной среды OSLIB_LOADER_TRACE=1 заставит системный загрузчик библиотек активно информировать о своих действиях в консоль.

В выводе команды виден текст обработки каталогов «по соглашению».

Данный текст будет выводиться только при использовании OneScript версии 1.0.19 и новее, либо после обновления системного загрузчика библиотек актуальным текстом сценария

Первые тесты

Один мой друг показывал мне список задач (с реального проекта) по доработке с описанием задачи и способом приемки работ. Напротив большинства пунктов стояло загадочное «проверка визуально». Сейчас наша библиотека проверяется только «визуально», а это несколько несерьезно.

Попробуем добавить первый тест!

В каталоге библиотеки calculation создадим подкаталог tests и новый файл ПроверкаВычисления.os

Содержимое файла:

#Использовать asserts

#Использовать ".."

 

Результат = Вычислитель.Сложить(2, 2);

Ожидаем.Что(Результат).Равно(5);

 

 

В первой строке с помощью инструкции «Использовать» подключается библиотека asserts. Asserts – это библиотека, содержащая модули, помогающие в написании тестов. Она содержит два модуля: «Утверждения» и «Ожидаем» – для тестирования в unit- (модульное) и fluent- (текучее, цепное) стилях соответственно. Исходники библиотеки доступны по ссылке: https://github.com/oscript-library/asserts

Обратите внимание, имя библиотеки asserts указано без кавычек. Это способ подключения библиотек «по имени». Вычисление пути библиотеки делается очень просто – берется системный (и дополнительный, если он объявлен) каталог библиотек, к нему добавляется имя библиотеки – на выходе путь к каталогу библиотеки. Далее всё по той же схеме, что и при подключении библиотеки «по пути».

Второй строкой следует загадочная конструкция с использованием «..». В этом тоже нет никакой магии. Вспомним, что наш сценарий теста лежит в каталоге tests. Подключение библиотеки «по пути» умеет работать с относительными каталогами. Две точки – это обозначение родительского каталога. Складываем все три знания и получаем, что загрузчик библиотек будет пытаться загрузить каталог calculation, являющийся корнем нашей библиотеки. А в этом корне есть каталог src и вообще он всячески удовлетворяет «соглашению о структуре каталогов».

Таким образом на третьей строке нам становится доступен объект «Вычислитель» и его методы.

На четвертой строке применяется библиотека asserts. «Ожидаем» – это обращение к модулю этой библиотеки, функция «Что» устанавливает контекст проверки – мы проверяем результат работы функции «Сложить», функция «Равно» будет проверять переданное ей значение с сохраненным в контексте.

Если сейчас запустить этот сценарий (F5), то в «Консоли отладки» мы получим сообщение:

В этом сообщении есть две проблемы.

Пока у нас есть единственный тест, мы еще способны удержать в голове, что происходит. Когда количество тестов будет расти, стандартного сообщения об исключении начнет не хватать. Мы можем помочь сами себе, заполнив второй параметр в функции «Что» текстом сообщения с исключением:

Теперь помимо текста исключения от библиотеки «asserts» (о том, что 4 не равно 5) мы видим и наше дополнительное сообщение об ошибке.

Вторая проблема этого сообщения – тесты падают :) Причем падают по нашей вине. Поправим аргумент функции «Равно» на 4. После этого тест должен завершиться без ошибок.

Тестирование с помощью 1testrunner

Для тестирования библиотек сообществом разработано несколько фреймворков тестирования. Основные из них:

  • 1testrunner – для модульного и сценарного тестирования – является портом фреймворка xUnitFor1C для OneScript
  • 1bdd – для проверки поведения на основе требований в виде feature-файлов – не является прямым портом, но в целом похож на фреймворк Vanessa-Behavior

Данные фрейморки позволяют получать подробные отчеты о тестировании в нескольких форматах. Если эти фреймворки еще не установлены на вашем компьютере, их можно поставить через OneScript Package Manager, выполнив команду «opm install 1testrunner» и «opm install 1bdd» соответственно.

Адаптируем наш первый тест к использованию фреймворка 1testrunner. Для этого нам надо добавить в наш сценарий ПроверкаВычисления.os специальную функцию ПолучитьСписокТестов, возвращающую массив имен экспортных процедур, осуществляющих тестирование. А сами строки по проверке результата сложения перенести в эту новую процедуру. Дополнительно надо добавить две процедуры (ПередЗапускомТеста и ПослеЗапускаТеста), в которых при необходимости можно дополнительно сконфигурировать тест (нам пока нечего конфигурировать, поэтому мы не станем этого делать). Должно получиться что-то вроде такого:

#Использовать asserts

#Использовать ".."

 

Функция ПолучитьСписокТестов(ЮнитТестирование) Экспорт

    ВсеТесты = Новый Массив;    

    ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоДваПлюсДваРавноЧетыре");

    

    Возврат ВсеТесты;

КонецФункции

 

Процедура ПередЗапускомТеста() Экспорт

КонецПроцедуры

 

Процедура ПослеЗапускаТеста() Экспорт

КонецПроцедуры

 

 

Процедура ТестДолжен_ПроверитьЧтоДваПлюсДваРавноЧетыре() Экспорт

    Результат = Вычислитель.Сложить(2, 2);

    Ожидаем.Что(Результат, "Ожидаем, что 2 + 2 = 4").Равно(4);

КонецПроцедуры

 

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

Как теперь все это запустить?

В редакторе VSCode (а точнее в плагине для поддержки языка 1C и OneScript) уже зашито несколько задач по тестированию. Нажмем F1 и в поисковой строке наберем «task». Выберем пункт «Задачи: Выполнить задачу»:

Появится еще одно окно, в котором нам нужно выполнить одну из команд «1testrunner»:

Если у вас открыт рабочий каталог сразу с двумя подкаталогами, то задача «Testing project» упадет с ошибкой, т.к. по умолчанию запускаются тесты из каталога tests, а у меня он вложен в подкаталог calculation. Конечно же, это можно подправить, нажав на шестеренку справа от задачи и скорректировав путь к тестам, но я просто выполню задачу «Testing current test-file».

Наградой нам станет «зеленая полоса» от фреймворка 1testrunner и сообщение о том, что все наши тесты (один :) ) пройдены.

Похожего результата можно добиться и запуская 1testrunner из терминала. Например, вот так можно запустить все тесты из каталога «tests»:

Классы и модули

В чем же разница между «модулями» и «классами», про которые я периодически рассказываю? Ключевых различий между ними два.

Первое различие - это способ инстанцирования объекта, другими словами – способ получения объекта, с которым можно начать что-то делать.

«Модуль» в контексте OneScript – это такой сценарий, обращаться к которому можно сразу же после запуска приложения. Если проводить аналогию с 1С, то это что-то вроде «общего модуля».

«Класс» в контексте OneScript – это такой сценарий, обращаться к которому можно только после получения конкретного «экземпляра» объекта с помощью ключевого слова Новый. По аналогии с 1С – это любые объекты: массив, структура, таблица значений. Только в OneScript эти классы не ограничены метаданными конфигурации, их можно создавать самому.

Второе различие вытекает из первого. Все сценарии в OneScript могут содержать переменные, объявленные в заголовке сценария с помощью ключевого слова Перем. Обращаю ваше внимание – в модулях тоже может содержаться несколько верхнеуровневых переменных.

Технически и модули и классы – это просто некие объекты в памяти, хранящие значения набора свойств и содержимое методов. Соответственно значения, сохраненные в свойствах (переменных) модуля, будут одинаковыми во всех местах вызова этого модуля (т.к. модуль инстанцируется один раз при начале работы системе). А значения свойств у классов будут различаться у каждого инстанцированного экземпляра класса.

Я рекомендую еще раз перечитать предыдущий абзац. И еще разок.

Возвращаемся к разработке нашей библиотеки - расширим ее потенциальные возможности.

Наш вычислитель планируется сделать очень умным. Например, он может уметь складывать числа, хранящиеся не только в памяти, но и на диске, или в SQL базе. Не спрашивайте зачем :)

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

Следуя принципу Test-First сначала напишем тест на новую функциональность. Добавим в тестовый сценарий «ПроверкаВычисления» новую процедуру:

Процедура ТестДолжен_ПроверитьСложениеДвухЧиселВПамяти() Экспорт

    ЧислоВПамяти1 = Новый ЧислоВПамяти(1);

    ЧислоВПамяти2 = Новый ЧислоВПамяти(3);

 

    Результат = Вычислитель.Сложить(ЧислоВПамяти1, ЧислоВПамяти2);

    Ожидаем.Что(Результат, "Ожидаем, что сложение чисел из памяти работает").Равно(4);

КонецПроцедуры

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

Не забудем добавить новый тест в функцию «ПолучитьСписокТестов».

Дополнительно добавим новый тест, проверяющий работу нашего класса. Создадим в каталоге calculation/tests новый файл ЧислоВПамяти.os

#Использовать asserts

#Использовать ".."

 

Функция ПолучитьСписокТестов(ЮнитТестирование) Экспорт

    ВсеТесты = Новый Массив;    

    ВсеТесты.Добавить("ТестДолжен_ПроверитьСохранениеЗначенийВЧислоВПамяти");

    

    Возврат ВсеТесты;

КонецФункции

 

Процедура ПередЗапускомТеста() Экспорт

КонецПроцедуры

 

Процедура ПослеЗапускаТеста() Экспорт

КонецПроцедуры

 

Процедура ТестДолжен_ПроверитьСохранениеЗначенийВЧислоВПамяти() Экспорт

    ЧислоВПамяти = Новый ЧислоВПамяти(10);

    

    Ожидаем.Что(

        ЧислоВПамяти.Получить(),

        "Ожидаем, число 10 сохранилось в памяти объекта ЧислоВПамяти"

    ).Равно(10);

КонецПроцедуры

В данном тесте мы создаем новый экземпляр класса ЧислоВПамяти (передав ему начальное значение 10) и пытаемся получить это значение из класса.

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

1testrunner -runall .\calculation\tests\

В теле сообщения помимо текстов исключения видно общую статистику:

Наконец, переходим к разработке! В каталоге calculation/src создадим новый подкаталог Классы. В новом подкаталоге создадим файл ЧислоВПамяти.os – хранилище нашего нового класса.

В качестве реализации класса предлагаю такое решение «в лоб»:

Перем ХранимоеЗначение;

 

Процедура ПриСозданииОбъекта(УстанавливаемоеЗначение)

    ХранимоеЗначение = УстанавливаемоеЗначение;

КонецПроцедуры

 

Функция Получить() Экспорт

    Возврат ХранимоеЗначение;

КонецФункции

В качестве хранилища значения «числа в памяти» будет выступать переменная на уровне класса. С помощью специального процедуры «ПриСозданииОбъекта» (аналогия в 1С – ПриСозданииНаСервере у формы) мы описываем конструктор объекта. В нашем случае при вызове конструктора необходимо будет передать 1 параметр, который сохранится в переменной ХранимоеЗначение.

Конструктор объекта может и отсутствовать. Тогда инстанцирование объекта происходит без параметров, через вызов Новый ИмяКласса()

Функция «Получить» является способом возвращения значения, сохраненного в объекте.

Если снова запустить полный прогон тестов, то можно заметить, что количество прошедших тестов увеличилось – тест класса ЧислоВПамяти перестал выкидывать исключение.

Для «починки» последнего теста необходимо поправить получение значений слагаемых в модуле «Вычислитель». Откроем его (calculation/src/Модули/Вычислитель.os) и заменим реализацию функции сложить на следующую:

Функция Сложить(Слагаемое1, Слагаемое2) Экспорт

    РеальноеСлагаемое1 = ПолучитьРеальноеСлагаемое(Слагаемое1);

    РеальноеСлагаемое2 = ПолучитьРеальноеСлагаемое(Слагаемое2);

    Возврат РеальноеСлагаемое1 + РеальноеСлагаемое2;

КонецФункции

 

Функция ПолучитьРеальноеСлагаемое(Слагаемое)

    Если ТипЗнч(Слагаемое) = Тип("Число") Тогда

        РеальноеСлагаемое = Слагаемое;

    Иначе

        РеальноеСлагаемое = Слагаемое.Получить();

    КонецЕсли;

    

    Возврат РеальноеСлагаемое;

КонецФункции

Во-первых, добавим функцию ПолучитьРеальноеСлагаемое, которое будет возвращать число, которое нужно сложить. Если вдруг в Вычислитель передали реальное «число», то будет возвращаться сам параметр. Если же был передан какой-то объект, например, ЧислоВПамяти, будет выполняться попытка «получения» значения из этого объекта.

На этот раз запуск тестов должен показать три зеленых теста!

На сладкое, добавим немного «защитного программирования». Как автор класса ЧислоВПамяти, я хочу быть уверенным, что в конструктор объекта передается именно число, а не, например, строка.

Test-first! В тесте ЧислоВПамяти (calculation/tests/ЧислоВПамяти.os) добавим новый тест со следующим содержанием:

Процедура ТестДолжен_ПроверитьВыбросИсключенияПриСохраненииСтроки() Экспорт

    

    Попытка

        ЧислоВПамяти = Новый ЧислоВПамяти("Строка");

        ВызватьИсключение "Должен был произойти вызов исключения!";    

    Исключение

        Ожидаем.Что(

            ОписаниеОшибки(),

            "Описание ошибки содержит информацию о неверном аргументе"

        ).Содержит("Передан аргумент неверного типа");

    КонецПопытки;

    

КонецПроцедуры

 

В данном тесте используется трюк ожидания исключения. Для начала в попытке пытаемся создать новое ЧислоВПамяти, передав в конструктор «Строку». Если наш код работает корректно, то конструктор объекта выдаст исключение и мы провалимся в секцию «Исключение». Если же этого не произошло, мы явно вызываем исключение с текстом «Должен был произойти вызов исключения!». В любом случае мы попадаем в секцию «Исключение», где с помощью модуля из asserts «ожидаем», что ОписаниеОшибки(), содержит нужный нам текст.

Для “обычных” методов классов/модулей можно воспользоваться конструкцией Ожидаем.Что(Объект).Метод(ИмяМетода).ВыбрасываетИсключение(ТекстИсключения)

Запуск всех тестов добавит единичку в список провалившихся тестов.

Вернемся в класс ЧислоВПамяти (calculation/src/Классы/ЧислоВПамяти.os). Проверим тип аргумента с помощью библиотеки asserts:

#Использовать asserts

 

Перем ХранимоеЗначение;

 

Процедура ПриСозданииОбъекта(УстанавливаемоеЗначение)

    Ожидаем.Что(УстанавливаемоеЗначение, "Передан аргумент неверного типа").ИмеетТип("Число");

    ХранимоеЗначение = УстанавливаемоеЗначение;

КонецПроцедуры

 

Функция Получить() Экспорт

    Возврат ХранимоеЗначение;

КонецФункции

 Первым делом добавим подключение библиотеки в начале модуля с помощью инструкции «Использовать». Затем в конструкторе объекта (процедуре ПриСозданииОбъекта) с помощью модуля «Ожидаем» проверим, что переданное значение ИмеетТип Число. Как видите, библиотеку asserts можно использовать не только в тестировании, но при написании конкретного прикладного кода.

Теперь все тесты снова станут зелеными.

Подобным образом можно добавить хранение чисел в любом доступном хранилище, будь то файл на диске, облачный сервис с http-интерфейсом доступа или полноценная 1С с подключением через ComОбъект (пожалуйста, не надо так).

Перечисления

При разработке библиотек периодически возникает желание создать что-то вроде перечисления. Режимы работы, типы операций… Попробуем заложить фундамент расширяемости в нашу библиотеку, добавив универсальную функцию вычисления результата и перечисление, указывающее на тип операции вычисления.

В качестве хранилища значений перечисления будет выступать «модуль» с экспортными переменными. Вы же помните, что модуль может содержать переменные?

Создадим файл calculation/src/Модули/ТипыОпераций.os:

Содержимое файла:

Перем Сложение Экспорт;

Перем Умножение Экспорт;

 

Сложение = 0;

Умножение = 1;

Здесь в качестве «элементов перечисления» выступают экспортные переменные (свойства) модуля. Обращение к такому перечислению будет почти аналогично 1С:

ТипыОпераций.Сложение

В качестве значений переменных могут выступать любые данные, главное, чтобы «элементы перечисления» имели различные сравниваемые значения переменных – числа, строки, булево и т.д.

Обращаю внимание, что данные значения «перечисления» по сути являются изменяемыми данными, прикладная библиотека может выполнить код в духе:

ТипыОпераций.Сложение = 123;

И он выполнится без ошибок – свойство-то экспортное, то есть доступное всем и каждому. Для исключения побочных эффектов можно применять методику get-еров:

  • у значений элементов перечисления убирается ключевое Экспорт
  • под каждый элемент перечисления создается функция (обычно одноименная), возвращающая значение элемента перечисления. Например, ТипыОпераций.Сложение()

Такой подход позволит обеспечить неизменяемость значений перечисления, но и перестает выглядеть как собственно «перечисления». Какой способ применять – выбирать вам.

После создания перечисления добавим универсальную функцию вычисления результата.

Test first! :)

Откроем файл с тестами (calculation/tests/ПроверкаВычисления.os) и добавим два новых теста:

Процедура ТестДолжен_ПроверитьСложениеЧерезУниверсальнуюФункцию() Экспорт

    Результат = Вычислитель.ВыполнитьВычисление(ТипыОпераций.Сложение, 2, 2);

    Ожидаем.Что(Результат, "Ожидаем, что сложение через универсальную функцию работает").Равно(4);

КонецПроцедуры

 

Процедура ТестДолжен_ПроверитьУмножениеЧерезУниверсальнуюФункцию() Экспорт

    Результат = Вычислитель.ВыполнитьВычисление(ТипыОпераций.Умножение, 2, 3);

    Ожидаем.Что(Результат, "Ожидаем, что умножение через универсальную функцию работает").Равно(6);

КонецПроцедуры

В данных тестах мы предполагаем, что в модуле «Вычислитель» появится универсальная функция ВыполнитьВычисление, в которую можно передать тип операции и параметры-числа.

Перейдем к реализации данной функции. В файл calculation/src/Модули/Вычислитель.os добавим пару новых функций и напишем их реализации:

Функция ВыполнитьВычисление(ТипОперации, Операнд1, Операнд2) Экспорт
    Если ТипОперации = ТипыОпераций.Сложение Тогда
        Возврат Сложить(Операнд1, Операнд2);
    ИначеЕсли ТипОперации = ТипыОпераций.Умножение Тогда
        Возврат Умножить(Операнд1, Операнд2);
    Иначе
        ВызватьИсключение "Неизвестный тип операции";
    КонецЕсли;
КонецФункции
 
Функция Умножить(Множитель1, Множитель2) Экспорт
    РеальныйМножитель1 = ПолучитьРеальноеСлагаемое(Множитель1);
    РеальныйМножитель2 = ПолучитьРеальноеСлагаемое(Множитель2);
    Возврат РеальныйМножитель1 * РеальныйМножитель2;
КонецФункции

В функции «ВыполнитьВычисление» первым делом пытаемся понять, что за тип операции нам передали. В зависимости от типа операции вызываем ту или иную функцию вычисления. Рефакторинг функции «ПолучитьРеальноеСлагаемое» (ее имя и имена переменных внутри) оставлю на вас – теперь же тесты есть, уже не страшно. Кстати, они снова зеленые!

Под капотом – lib.config

К сожалению, «соглашение именования каталогов» не всегда применимо. С ростом нашей библиотеки нам может понадобится по-другому группировать файлы в каталогах. Ортодоксальные разработчики именуют файлы латиницей, при этом хотят обращаться модулям и классам на кириллице. Или вообще сделать двуязычные имена модулей/классов – не дублировать же файлы на диске!

Для решения этих задач (и не только перечисленных) в «системный загрузчик библиотек» было добавлено еще одно «соглашение» о правилах загрузки. На этот раз оно не завязано на структуру каталогов – описание типов подключаемых сценариев (и их системных) имен описывается в отдельном текстовом файле lib.config, расположенном в корневом каталоге библиотеки:

Описание имеющихся модулей и классов выглядит так:

<package-def>
    <class name="ЧислоВПамяти" file="src/Классы/ЧислоВПамяти.os"/>
    <module name="Вычислитель" file="src/Модули/Вычислитель.os"/>
    <module name="ТипыОпераций" file="src/Модули/ТипыОпераций.os"/>
</
package-def>

Структура файла говорит сама за себя. Расскажу о нескольких важных моментах:

1)      Для системного загрузчика библиотек проверка на наличие lib.config в корне библиотеки является более приоритетным, чем загрузка по «соглашению о структуре каталогов». Если библиотека содержит файл lib.config, то подключение сценариев по «соглашению» выполняться не будет.

2)      Файл lib.config может содержать несколько строчек, ведущих на один и тот же файл. Например, вы можете добавить английский синоним модулю Вычислитель – для этого надо всего лишь скопировать строчку с подключением «вычислителя» и в качестве значения атрибута name указать Calculation. OneScript подключит этот сценарий два раза, создав два разных объекта в памяти – для английского синонима и для русского.

3)      Более того, вы можете подключать один и тот же файл сценария как разные типы – модуль и класс. Тогда в глобальном пространстве имен прикладного сценария будет доступен и «модуль» (со своим отдельным хранилищем значений переменных), так и инстанцирование новых объектов через конструктор, с использованием ключевого слова «Новый». Этим, кстати, пользуется библиотека tempfiles, предназначенная для управления создаваемыми временными файлами. По имени ВременныеФайлы доступен «глобальный менеджер временных файлов», единый для всех точек обращения к этому модулю, а при необходимости, вы можете дополнительно проинициализировать «Новый МенеджерВременныхФайлов». С точки зрения реализации это один и тот же файл сценария, просто два раза прописанный в lib.config.

Автодополнение

Редактор Visual Studio Code (а точнее плагин Language 1C (BSL) для него) поддерживает базовые возможности по автодополнению методов классов и модулей, предоставляемых библиотеками.

Для работы системы автодополнения нужно выполнить три шага:

  1. На вашей локальной машине должен стоять пакет-приложение oscript-config. Поставить его можно из хаба пакетов с помощью команды opm install oscript-config. Поставили один раз и забыли.
  2. Библиотека, от которой вы хотите получить автодополнение, должна содержать файл lib.config. Именно этот файл ищет плагин для VSCode и по нему определяет, какие файлы (и их содержимое) надо добавлять в систему автодополнения.
  3. Объект, к которому идет обращение, должен называться так же, как он подключается к системе типов самого движка OneScript. Если с модулями проблем нет (кому придет в голову сохранять ссылку на модуль в другой переменной), то с классами есть небольшая засада. Для получения автодополнения имен методов, например, у класса УправлениеКонфигуратором (из пакета v8runner), имя переменной должно равно УправлениеКонфигуратором.

Т.е. после нажатия на Ctrl+Space в таком коде (после точки) вы сможете увидеть список его методов:

УправлениеКонфигуратором = Новый УправлениеКонфигуратором();

УправлениеКонфигуратором.

Аналогично для и для нашего класса ЧислоВПамяти. Пользователи смогут пользоваться автодополнением только если будут именовать переменные так же, как и класс (привет, Массив = Новый Массив!)

Пункт, который зависит от нас, как от авторов библиотеки – наличие файла lib.config – уже выполнен, так что у вас есть все шансы получить благодарного пользователя не только потому, что ваша библиотека работает, но и потому, что ей удобно пользоваться.

Публичные и приватные классы и модули

Все типы классов и модулей, подключаемых в OneScript, попадают в «глобальную область видимости». Т.е. будучи подключенными раз, они будут доступных из всех закоулков вашего прикладного приложения (в рамках одного запуска, естественно). Поэтому понятие «приватных», т.е. невидимых для внешнего пользователя классов и модулей в OneScript несколько размыто.

Однако, с учетом работающей системы автодополнения, мы можем хотя бы ограничить количество классов и модулей, доступных к выбору по Ctrl+Space.

В качестве примера реализации такого сокрытия возьмем библиотеку fluent - https://github.com/nixel2007/oscript-fluent/tree/v0.3.1

Если обратиться к содержимому lib.config в корне библиотеки, то можно увидеть два объекта – один класс и один модуль:

Однако, дерево файлов выглядит интереснее:

На верхнем уровне каталога src созданы уже стандартные подкаталоги Классы и Модули, в которых находятся файлы, объявленные в lib.config. Дополнительно в src располагается каталог «internal», в котором так же есть свои «классы» и «модули».

Если открыть, например, файл src/Классы/ПроцессорКоллекций, то в заголовке файла можно увидеть такую конструкцию:

После подключения стандартных библиотек «по имени» происходит подключение каталога “../internal”.

Вся эта конструкция как-то работает, при этом «внутренние» класс и модуль (с постфиксом «служебный» недоступны в системе автодополнения. Попробуем разобраться, что же происходит.

  1. При «использовании» пакета fluent системный загрузчик библиотек считывает содержимое файла lib.config
  2. По содержимому lib.config движок OneScript подключает класс ПроцессорКоллекции и модуль ПроцессорыКоллекций
  3. При инициализации указанных класса и модуля происходит использование библиотеки «../internal» «по пути»
  4. Системный загрузчик библиотек анализирует содержимое каталога «../internal», не находит там файла lib.config, но определяет соответствие «соглашению о структуре каталогов»
  5. Движок OneScript подключает «служебные» модуль и класс.

Параллельно этому процессу система автодополнения Visual Studio Code анализирует файл lib.config, располагающийся в корне библиотеки fluent и подключает описанные там класс и модуль.

Таким образом с одной стороны (со стороны движка OneScript) у нас есть полностью работающая библиотека с четырьмя сценариями – двумя классами («публичным» и «служебным») и двумя модулями (так же «публичным» и «служебным»). А со стороны системы автодополнения было прочитано только два сценария – один класс и один модуль.

«Честным» сокрытием внутренних классов это можно назвать с большой натяжкой, но выкручиваемся как можем :)

Еще раз напоминаю, что все классы и модули подключаются в глобальную область видимости. Как следствие возможен конфликт имен между различными библиотеками. Не стоит называть «внутренний» модуль каким-то очень распространенным именем, например, «Параметры». Назовите его «Параметры_ИмяВашейБиблиотеки». Вам как разработчику не составит труда при реализации вашей внутренней логики печатать на пару символов больше, а остальные пользователи скажут вам «спасибо» за бесконфликтную библиотеку.

Сборка пакета

Итак, наш пакет готов к тому, чтобы поделиться им с сообществом. Большинство хороших и известных библиотек собираются в специальное «пакеты» и публикуются в хаб пакетов. «Пакет» - это особым образом упакованный zip-архив, который OneScript Package Manager (opm) умеет собирать, публиковать и устанавливать.

Все хорошие пакеты помимо содержимого в виде кода имеют описание библиотеки в файле README.md. Md – это расширение файлов, обозначающее язык MarkDown. Практически все репозитории, которые вы встретите на просторах GitHub, имеют описание в виде файла README.md.

Создадим в корне каталога calculation файл README.md примерно со следующим содержимым:

Если выполнить команду «Markdown: Открыть область предварительный просмотра» (или нажать комбинацию клавиш ctrl-k, затем v), то откроется отдельное окно, в котором отобразится итоговый внешний вид файла MarkDown:

Для сборки пакета нам необходимо заполнить специальное «описание пакета» - небольшой сценарий, в котором указываются данные о пакете.

Создадим в каталоге calculation новый файл с именем packagedef (без расширения) – package definition:

Содержимое файла:

Описание.Имя("calculation")

    .Версия("1.0.0")

    .Автор("Nikita Gryzlov")

    .АдресАвтора("nixel2007@gmail.com")

    .Описание("Арифметические операции для любителей функционального программирования")

    .ВерсияСреды("1.0.17")

    .ВключитьФайл("src")

    .ВключитьФайл("lib.config")

    .ВключитьФайл("README.md")

    .ЗависитОт("asserts", "0.3.1")

;

Эти эльфийские письмена на самом деле не делают ничего магического. Packagedef – это специальный файл, который используется opm при сборке пакета. Это обычный сценарий на языке 1C/OneScript. При его инициализации в область видимости добавляется экземпляр класса «ОписаниеПакета», содержимое этого класса можно подсмотреть в репозитории opm (https://github.com/oscript-library/opm/blob/master/src/%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D1%8B/%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5%D0%9F%D0%B0%D0%BA%D0%B5%D1%82%D0%B0.os). В файле packagedef мы вызываем методы этого класса, которые занимаются заполнением содержимого.

Пробежимся по используемым функциям:

  • Описание пакета обычно начинается с указания идентификатора (имени) библиотеки. Далее в произвольном порядке следуют все остальные поля
  • Версия пакета (библиотеки)
  • Автор
  • Email автора для связи
  • Текстовое описание пакета
  • ВерсияСреды – минимальная версия движка OneScript, требуемая для использования данного пакета
  • ВключитьФайл – пути к файлам и каталогам, которые необходимо добавить в пакет при сборке. Сюда же можно добавить файлы примеров использования, любую документацию и вообще все, что вы пожелаете загрузить на конечный компьютер пользователя
  • ЗависитОт – зависимости нашего пакета от других пакетов. Класс ЧислоВПамяти использует библиотеку asserts для проверки типов переданных значений, поэтому нам нужно указать эту зависимость в описании пакета. При установке нашего пакета opm будет контролировать наличие всех зависимостей и доустанавливать нужные при необходимости

Если начать копаться во внутренностях opm, то можно выяснить, что если packagedef будет содержать вызовы функций «ОпределяетКласс» и «ОпределяетМодуль», то файл lib.config сформируется автоматически. Т.е. в целом мы могли его и не формировать руками, а описать в едином месте в packagedef. Однако, если структура каталогов библиотеки не будет удовлетворять «соглашению о структуре каталогов», то нам самим будет тяжелее ее разрабатывать и тестировать, т.к. тесты и отладчик не будут знать, какие классы и откуда загружать. Поэтому моя личная рекомендация – формируем файл руками и «включаем» его в packagedef.

Описание пакета готово, попробуем собрать наш пакет! Для этого выполним команду opm build с указанием пути к каталогу, в котором располагается файл packagedef:

На выходе получаем файл ospx – собранный пакет. При желании его можно открыть любым zip-архиватором и поисследовать.

Что мы можем делать с этим пакетом? Как минимум мы можем его установить!

У opm есть команда install, среди параметров которой есть параметр -f, отвечающий за путь к файлу пакета, который необходимо установить. Если он не указан, то пакет скачивается с хаба пакетов в облаке, иначе берется указанный файл.

Если OneScript у вас установлен «как обычно» в Program files, то может потребоваться запуск командной строки с правами администратора.

Выполнение этой команды привело к установке пакета calculation в системный каталог пакетов. Физически это выглядит так:

Создался новый каталог по имени пакета (calculation), в каталоге расположены файлы, которые мы указали как «включаемые» в packagedef.

Зачем это все? Теперь мы можем «использовать» нашу библиотеку «по имени»! Вернемся в сценарий my_project/script.os и заменим строку «использования» библиотеки с «пути» (с кавычками и двумя точками) на подключение «по имени» (без кавычек и каких-либо путей):

Сценарий продолжает работать и выдавать в консоль цифру «4», а значит, мы сделали все правильно.

Если переоткрыть редактор VSCode (или выполнить команду Language 1C (BSL): Update reference cache), то наша библиотека отобразиться Синтакс-Помощнике, в разделе oscript-library:

Публикация пакета в хаб

Наша библиотека собрана в пакет, дело осталось за малым – поделиться библиотекой со всем миром! Конечно же, можно скидывать файл ospx коллегам в скайп/гиттер/слак, но лучше разместить его в хабе пакетов. Для этого нужно сделать три вещи:

  1. Исходники библиотеки должны быть опубликованы на GitHub. Я не буду подробно останавливаться на принципах работы с гитом, на ИС есть достаточно базовых статей на эту тему. От вас не требуется ничего сверхтяжелого – создать новый репозиторий на GitHub, закоммитить все содержимое библиотеки и запушить изменения.
  2. Постучаться по различным каналам связи к администраторам организации oscript-library (https://github.com/oscript-library) на GitHub или написать в Gitter-канал библиотеки пакетов (https://gitter.im/EvilBeaver/oscript-library) – дать ссылку на ваш реп и попросить добавить в хаб пакетов. Через некоторое время вам скажут «угумс!» и вы можете приступать непосредственно к публикации.
  3. Публикация пакета производится так же с помощью утилиты opm.

Теперь подробнее о публикации. Публикация выполняется с помощью команды opm push. Как следует из справки нам необходимо указать два или три параметра:

--file – это путь к файлу ospx. Можно использовать маску поиска.

--token – токен авторизации с сервера GitHub. Новый токен можно создать новый на странице https://github.com/settings/tokens. Сохраните значение токена, если планируете им пользоваться в дальнейшем, GitHub отображает его только в момент генерации, после обновления страницы значение пропадет.

--channel – канал публикации. Если вы публикуете изменения из git-репозитория и ветки master, то указание этого параметра не требуется.

Обычно, я выполняю публикацию с помощью следующей команды:

opm push --file *.ospx --token МойГитхабТокен

После успешного выполнения команды в Gitter-канале oscript-library появится примерно такое сообщение:

И самое главное, что пакет станет доступен в хабе пакетов http://hub.oscript.io.

Заключение

Thats all, folks! Надеюсь, этот гайд поможет вам влиться в увлекательный мир создания библиотек для OneScript, и количество нового и полезного начнет стремительно расти :)

Финальное содержимое каталога calculation можно найти в моем репозитории на GitHub - https://github.com/nixel2007/infostart-calculation

124

См. также

Комментарии
Сортировка: Древо
1. Infactum 263 06.03.18 14:38 Сейчас в теме
Вот это правильная статья, в отличие от того, что в последнее время в топе болтается.
Liris; SerebanSK; bulpi; o4karek; antonst1; fancy; CSiER; kuntashov; Evil Beaver; +9 Ответить
2. nixel 508 06.03.18 14:45 Сейчас в теме
3. Evil Beaver 5245 06.03.18 15:44 Сейчас в теме
Фундаментально, ага!

Для получения автодополнения имен методов, например, у класса УправлениеКонфигуратором (из пакета v8runner), имя переменной должно равно УправлениеКонфигуратором.


Вот у меня точно помню, что переменная называлась иначе, а подсказка в VSC все равно срабатывала. Может в VSC уже и выведение типа переменной сделано, а мы пропустили?
4. nixel 508 06.03.18 16:00 Сейчас в теме
(3)

Фундаментально, ага!


Прелестно, прелестно! :)

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


А ты уверен, что у тебя после точки выводились нужные тебе процедуры и функции, а оно не совпало (случайно) с каким-то зарегистрированным классом/модулем?
5. lustin 973 06.03.18 16:58 Сейчас в теме
(0) теперь для чистоты эксперимента - делаем ставки сколько новых библиотек появится ;-).

Круто кстати - особенно BPMN
creatermc; nixel; +2 Ответить
6. nixel 508 06.03.18 17:16 Сейчас в теме
(5) ну, ты жаловался периодически на тему "как же создать новую библиотеку". вот тебе полноценный гайд :D
olegtymko; +1 1 Ответить
29. Steelvan 12.03.18 15:57 Сейчас в теме
(6) ... полноценное руководство
22. bulpi 130 09.03.18 18:04 Сейчас в теме
Не по теме публикации, чисто потрепаться. Одному мне кажется, что все эти тесты - не более, чем игры взрослых мальчиков в солдатики? Подозреваю, что таких как я , большинство, но все молчат, боясь показать свою "немодность" и "непродвинутость". Любая проблема должна быть решена наипростейшим образом, в том числе проблема тестирования. "Визуальное" тестирование и есть наипростейшее решение. А вот это все Ожидаем.Что(Результат).Равно(5)
- "горе от ума". Возможно, это нужно в ооо...чень больших проектах, которых примерно 0.01% от общего количества. За всю жизнь ни разу в таких не участвовал.
23. nixel 508 09.03.18 22:38 Сейчас в теме
(22) любой более-менее серийный/серьёзный продукт надо тестировать. Когда твой скрипт запускается больше, чем один раз и обрастает функциональностью, когда от него зависит работа продакшн контура, его развёртывание и более сложное использование - без тестирования любой баг в логике влетает во вполне ощутимые деньги.
Точно так же и с конфигурациями. Bdd/Tdd спасают производство и ускоряют разработку (хотя для большинства этот пункт звучит удивительно и непонятно)
24. nixel 508 09.03.18 22:41 Сейчас в теме
(22) визуальное тестирование, которое производится более двух раз, обычно уже дороже, чем написание автоматизированного теста. А отсутствие тестирования обычно дороже, чем его отсутствие :) простая мотивация.
25. nixel 508 10.03.18 00:55 Сейчас в теме
(24) а наличие тестирования дороже, чем его отсутствие *
26. nixel 508 10.03.18 11:09 Сейчас в теме
(25) и с третьей попытки - отсутствие тестирования дороже, чем его наличие :)

P.S. Вчера был тяжёлый день
27. baton_pk 374 10.03.18 20:28 Сейчас в теме
(22)
игры взрослых мальчиков в солдатики

это как велосипедный шлем, как наколенники при катании на роликах, как очки и перчатки во время ремонта, как строительные ботинки со стаканом в носке. "Крутые парни с улицы" смотрят на всё это свысока, но профессионалы без этого за дело не берутся.
Evil Beaver; SerebanSK; artbear; nixel; JohnyDeath; +5 Ответить
28. vano-ekt 1101 11.03.18 08:25 Сейчас в теме
(22)
игры взрослых мальчиков в солдатики

не обращай внимания, они даже ИС читают curl'ом , а не хромом
зачем нажимать целых две кнопки ctrl+F в браузере, когда можно вызвать программу с десятью опциями?
те же яйца, но в другой корзинке IDE
7. artbear 1065 06.03.18 17:39 Сейчас в теме
Отличная статья.

Зачем это все? Теперь мы можем «использовать» нашу библиотеку «по имени»! Вернемся в сценарий my_project/script.os и заменим строку «использования» библиотеки с «пути» (с кавычками и двумя точками) на подключение «по имени» (без кавычек и каких-либо путей):

а теперь попробуйте доработать библиотеку в исходниках, запустить тесты и получить прохождение тестов не своих исходников, а уже установленной библиотеки.

Предлагаю написать, что
+ мы можем «использовать» нашу библиотеку «по имени»
+ для этого создадим новый сценарий вне каталога исходников библиотеки и обратимся к нашей установленной библиотеке

и также лучше указать, что #Использовать ".." должно быть первым в списке #Использовать для исключения проблем разработки
8. nixel 508 06.03.18 18:06 Сейчас в теме
(7) новый сценарий и так вне каталога библиотеки располагается, это внешний проект, созданный в начале статьи. в чем вопрос?
9. artbear 1065 06.03.18 18:16 Сейчас в теме
(8) Упс, не увидел на скриншоте.
Значит, заработался, пора домой!
16. artbear 1065 07.03.18 11:15 Сейчас в теме
(8) Предлагаю указать, что #Использовать ".." должно быть первым в списке #Использовать для исключения дальнейших проблем разработки
10. AlexWhite 156 06.03.18 20:28 Сейчас в теме
11. Brawler 390 06.03.18 21:09 Сейчас в теме
Завидую тем, кто не погряз в учетных дебрях типовых и тренирует пытливые мозги!))
Осознаю, что наблюдаю со стороны за рождением чего-то значительного.
Так держать!!!
12. kuntashov 361 06.03.18 23:09 Сейчас в теме
Заранее извиняюсь за огромное количество упоминаний слова «библиотека» в тексте статьи :)


$ curl -s -L https://infostart.ru/public/791568 | iconv -f cp1251 -t utf8 | grep -o 'библио*' | wc -l
139
artbear; JohnyDeath; Evil Beaver; lustin; nixel; +5 Ответить
13. nixel 508 07.03.18 01:24 Сейчас в теме
(12) кажется, что это новый рекорд :D
kuntashov; +1 Ответить
18. Evil Beaver 5245 07.03.18 14:02 Сейчас в теме
(12) Эта строчка заслуживает отдельной гик-медали. Как посчитать количество вхождений слова в интернет-статье одной строчкой консоли, используя только стандартные утилиты unix ))
bulpi; artbear; +2 Ответить
19. baton_pk 374 07.03.18 14:48 Сейчас в теме
(18)
я позанудствую, но слово "Библиотека" есть в разделах в меню слева. Ещё наверняка в каких-нибудь мета-тэгах.
20. Evil Beaver 5245 07.03.18 16:22 Сейчас в теме
(19) Пулреквест в oneliner от Кунташова?
kuntashov; +1 Ответить
21. kuntashov 361 07.03.18 17:18 Сейчас в теме
(19) Я подумал, что в данном случае погрешностью в пару случаев можно пренебречь :)
14. new_user 273 07.03.18 08:57 Сейчас в теме
15. nixel 508 07.03.18 09:29 Сейчас в теме
(14) спасибо, Саш :) ждать от тебя библиотеку?)
30. new_user 273 21.03.18 16:23 Сейчас в теме
(15) да, простенькую, но полезную)
17. Samarkan63 07.03.18 11:47 Сейчас в теме
Интересная тема, понаблюдаю )
41. Gureev 23.04.18 16:07 Сейчас в теме
Может не очень в тему, подскажите, можно ли OneScript собрать в exe'шник?
42. nixel 508 23.04.18 17:31 Сейчас в теме
(41) да, можно. oscript -make путь/к/главному/файлу/os имя.exe
Оставьте свое сообщение