Перейти к содержимому

Ktlo

Пользователи
  • Публикации

    96
  • Зарегистрирован

  • Посещение

  • Победитель дней

    9

Сообщения, опубликованные пользователем Ktlo


  1. Всмысле ?

     

    На этом сервере нет.

     

    Смысла данной либы нет, т.к. параллельная отрисовка у тебя всё равно не выйдет. Параллельность сможет сработать только при использовании функций, приостанавливающих действие каждого потока: coroutine.yield(), sleep(), os.pullEvent(), os.pullEventRaw() и т. д.

    • Нравится 2

  2. Перенос статьи

    Эта тема была перенесена из блока "Статьи".


    Эта простая программа служит в основном для декора. С её помощью вы сможете с лёгкостью выводить список цистерн, подключённых к компьютеру, с подробной информацией о каждой. Скачать её можно с pastebin CAUxJx2T.

    Как запустить
    Я подумал, что для такой программы не нужна система, поэтому для работы вам необходимо установить её на EEPROM. Комплектация компьютера - минимальная, необходим процессор первого уровня, видеокарта (желательно второго уровня), монитор (тоже желательно второго уровня), адаптеры с расширением tank controller с подключёнными цистернами.

    Как работает
    Программа ищет всё подключённые к компьютеру адаптеры с модулем tank controller. Более того вы можете спокойно присоединять цистерны ко всем её сторонам, и они все будут отображаться, главное не делайте это во время работы программы. Когда всё подключено, просто запустите компьютер.
    В конечном итоге всё должно выглядеть примерно так:
    0_13ca71_74a86267_orig.png


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

    Вы также можете прописать каждому типу жидкости свой цвет. У меня это проделано только для воды лавы и молока, что можно увидеть на скриншоте. Для этого откройте файл любым редактором и найдите первую локальную таблицу fluids в ней название каждой жидкости соответствует цвету, вам следует просто продолжить таблицу, также вы можете изменить надпись на верху, для этого придайте переменной name значение любой строки, но старайтесь не использовать 2-байтовые символы.

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

    Обновление
    Я постарался учесть все ваши пожелания в коментариях и обновил программу. Ниже перечислены все изменения.
    • Если размер каждой цистерны на экране меньше 15 в ширину, то он фиксируется на 15, другие же цистерны, которые не попали на экран можно увидеть, тыкнув в правую часть экрана, при этом экран будет прокручиваться вправо на одну ячейку цистерны. Если необходимо вернуться назад тыкните в левую часть экрана.
    • Plug-and-Play добавлен, но плохо работает или вообще не работает с компонентами tank controller. Подключение новых цистерн и отключение работает без проблем.
    • Теперь программа также может работать с OpenOS, но лучше использовать EEPROM.

  3. Object API

    (Работаю над названием)

    Представляю вам третью версию Object API, которое я начал писать ещё давно, первых двух версий вы здесь не найдёте. Это библиотека работает только на Computer Craft, так что возможно зря я её писал...  :unsure: В любом случае, я надеюсь, что вы оцените. Сейчас в этой библиотеке есть следующие элементы: Button, CheckBox, Graph, Image, Label, Process, Registry, TextBox (не доделано). Планирую написать ещё очень много.
     
    Скачать можно с pastebin:

    pastebin get 3Bq2Sgvi object
    

    Устанавливается стандартной функцией os.loadAPI("object") или с помощью require. Под мою функцию она изначально была лучше адаптированна. Но не подумайте, со стандартной функцией работает.



     
    Изображение


    Получение объекта изображения:

    Image = Object.Image{xPos=number, yPos=number, Image=table or string[, Term=table, Width=number, Height=number, xOffset=number, yOffset=number, BackgroundColor=number, BorderStyle=string, BorderColor=number, LinesColor=number, Visible=boolean]} 

    Обязательные аргументы:

    • xPos и yPos — положение верхнего, левого угла изображения,
    • Image — таблица изображения или путь до него, можно загружать изображение стандартной программы paint с помощью paintutils.loadImage или изображение формата nft с помощью функции Object.Image.LoadNFT.

    Необязательные аргументы:

    • Term — объект окна или монитора, где будет отображаться изображение,
    • Width, Height — ширина и высота изображения,
    • xOffset, yOffset — смещение изображения по x и y соответственно,
    • BackgroundColor — цвет за изображением, если равен нулю, то не используется,
    • BorderStyle — стиль рамки вокруг изображения, может быть "none", "box" или "lines",
    • BorderColor — цвет рамки,
    • LinesColor — цвет линий на рамке,
    • Visible — ели false, не рисует изображение автоматически,
    • Key — номер кнопки.

    Таблица Object.Image также содержит функцию для загрузки nft изображений:

    tImage = Object.Image.LoadNFT( "path" ) 

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

     

    Все параметры объекта можно поменять, например:

    Image.xOffset = Image.xOffset+4 

    Также объект содержит только читаемый параметр Image.Path, который устанавливается при указании пути до файла.

     

    Методы:

    • Image.Draw() — рисует объект,
    • Image.Detect(event=string, tEvent=table) — детектирует следующие действия, связанные с изображением: "mouse_click", "mouse_up", "mouse_drag", "mouse_scroll", "monitor_touch" и "key", где event — ожидаемое действие, а tEvent — таблица с информацией действия полученной от os.pullEvent (tEvent = { os.pullEvent() }), если tEvent не указано, будет прослушивать действие сам.

     

     

     

    Потом напишу про остальные объекты.


  4. И можно ли будет от такого класса сделать наследника если невозможно добавлять новые поля?

    Можно:

    function newClass()
          local object, private = class()
          setmetatable(object, {}) --Удаляем метатаблицу
          object.foo(...) --Добавляем метод
                --<Что-нибудь>
          end
          setmetatable(object, private) --Возвращаем нашу метатаблицу назад
          return object, private
    end
    

  5. Это как? Так что ли?

    Obj1:Metod1()     --Вызов метода объекта 1 (нормальный)
    Obj2:Metod2()     --Вызов метода объекта 2 (нормальный)
    Obj1.Metod1(Obj2) --Вызов метода объекта 1 для объекта 2 (странный) 

    Да, так.

     

    Был несколько разочарован реализацией readonly-полей. Я надеялся на:

    print(Obj.ReadOnlyVar)  -- читаем поле
    --> 123
    Obj.ReadOnlyVar=456     -- пытаемся изменить
    print(Obj.ReadOnlyVar)  -- повторно читаем поле
    --> 123
    

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


  6. local function toLines(str, w) --Переносит текст на следующую строку, если не хватает места
    А "/n" отменили?

    Тогда будет писать с начала строки, а нужно, чтобы писал на кнопке.

     

    local function rusType(var) --Руссифицированная функция type
    Зачем?

     

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


  7. Данное API будет добавлять в вашу систему более удобные средства программирования разных элементов типа кнопки, картинки, процесса в виде разных объектов. Это API ещё находится в разработке, пока я добавил один элемент, кнопку. Я постарался сделать это API максимально гибким, и пока я не начал делать следующий элемент, хотелось бы услышать ваше мнение. Устанавливается всё очень просто, как любая другая библиотека. Скачать можно с pastebin.



    Кнопка


    Для того, чтобы получить кнопку, как объект, нужно использовать следующую функцию:

    local Object = require("Имя_файла")
    
    local Button = Object.New.Button{xPos=number, yPos=number, Width=number, Height=number} 
    

    Разберём необходимые параметры:

    •  xPos, yPos - числа, обозначающее положение верхнего левого угла кнопки;
    • Width, Height - длина и высота соответственно.

    Также кнопки есть дополнительные параметры, которые можно не указывать:

    • Screen - адрес монитора с кнопкой (переключает видеокарту на другой монитор, если параметр указывает на не подключённый монитор), выдаёт ошибку, если такого монитора нет;
    • Text - текст на кнопке, переносится на следующую строку по центру кнопки автоматически;
    • TextColor - цвет текста, если не указан, ставит белый;
    • BackgroundColor - цвет кнопки, если не указан ставит синий;
    • ActiveColor - цвет нажатой кнопки, по стандарту зелёный;
    • InactiveColor - цвет неиспользуемой кнопки, по стандарту серый;
    • Time - время нажатия, по стандарту 0.3 секунды;
    • Style - стиль кнопки. Их всего два, с округлёнными углами (по стандарту) и ровный прямоугольник;
    • Visible - параметр видимости, не рисует кнопку автоматически, если false, и рисует, если true.

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

    Также вы спокойно можете сделать так:

    local Object = require"object"
    local params = {xPos=2, yPos=2, Width=10 ,Height=4, Text=54679183}
    local Button1 = Object.New.Button(params)
    local Button2 = Object.New.Button(params) 

    И это будет работать.


     

    Для получения значения одного из параметров, можно сделать следующее:

    local Text = Button.Text 

    Но вы не можете сделать это в другую сторону, а именно:

    Button.Text = "klopsterinator" --Не работает 

    Все параметры, которые вы задали при создании кнопки (включая свои, которых нет в списке) - только читаемые.


     

    Кнопка имеет 3 встроенных функции (а можно ведь и свои сделать  :giggle:). Первая из них это:

    Button.Draw( state ) --Рисует кнопку 

    Если параметр state не указан, то будет нарисована обычная кнопка, если "active", то активная, если "inactive", то неактивная.

    Далее:

    Button.Set{} 

    Меняет любые параметры кнопки и добавляет ваши.

    Button.Detect{Action=string} 

    Детектирует действия на экране, связанные с кнопкой, возвращает true, если действие с кнопкой произошло, false, если нет, и значение CurrentButton. Имеет несколько параметров.

    Необходимые:

    • Action - действие, может быть "touch", "drag", "scroll" и "drop".

    Дополнительные:

    • Button - целевая кнопка мыши или целевое направление действия "scroll".

    Следующие несколько параметров нужны, если вы используете несколько кнопок одновременно.

    • Screen - экран, полученный из функции event.pull(),
    • x, y - координаты точки, полученные из функции event.pull(),
    • CurrentButton - то же, что и Button, только полученное из event.pull().

     

    Пример кода

     

     

    local Object = require"object"
    local event = require"event"
    
    local Button = Object.New.Button{xPos=2, yPos=2, Width=11, Height=4, Text="Я - кнопка,и я работаю!!!"}
    local detect = { }
    detect.Action = "touch"
    _, detect.Screen, detect.x, detect.y, detect.CurrentButton = event.pull(detect.Action)
    if Button.Detect(detect) then
    	Button.Set{Text="Нажата"}
    	Button.Draw("inactive")
    end 

     

     

     

     

     

    Если есть какие-то предложения по улучшению, пишите.

    • Нравится 1

  8. Я видел статью про ООП (Объектно-Ориентированного Программирования), написанную на этом форуме, и вот, что могу сказать, он может быть немного непонятен новичкам в Lua. Я всегда пользовался другим способом создания "классов".

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

     

    В Lua классов как таковых нет, но если пофантазировать, то можно представить функцию как класс, а объект как таблицу.

     

    Создание простого псевдо-класса

     

     

    1. И так создаем новую функцию и называем её к примеру class.

    function class() --Объявление класса
    	--Тело класса
    end --Конец класса
    

    Пока это просто пустая функция.

     

    2.Теперь пропишем в теле класса следующее:

    function class() --Объявление класса
    	local Me = { } --Создание объекта
    	return Me --Возвращение объекта (производного класса)
    end --Конец класса
    

    Теперь мы создали пустую таблицу и заставили функцию вернуть её. Для создания полноценного объекта нам не хватает заполнить его свойствами и методами. Таблица будущего объекта должна быть локальной.

     

    3.Создадим свойства и методы к нему:

    function class() --Объявление класса
    	local Me = {  --Таблица для методов и переменных
    		["Var"] = "HelloWorld"; --Публичная переменная
    	}
    	local Secret = "Cake = Lie"  --Скрытая переменная
    	function Me.PrintVar()
    		print(Me.Var)
    	end
    	function Me.PrintSecret()
    		print(Secret)
    	end
    	return Me --Возвращение объекта (производного класса)
    end --Конец класса
    

    Мы создали два свойства одно скрытое (Secret), а второе публичное (Me.Var) и два метода один для вывода на экран свойства Me.Var, а второй для вывода свойства Secret. Скрытые свойства обязательно должны быть локальными, а публичные находиться в таблице объекта. Также вы можете создать локальную функцию, которую смогут использовать только методы этого объекта.

     

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

    local class = require("имя_библиотеки").class -- загрузили класс из другого файла (если его нет в этом)
    local Object = class() -- Создание объекта на основе класса
    Object.PrintVar() --Вызов первого метода
    --> HelloWorld
    
    Object.PrintSecret() --Вызов второго метода
    --> Cake = Lie
    
    Object.Var = "BuyWorld" --Изменение значения свойства Var
    Object.PrintVar() --Вызов первого метода
    --> BuyWorld
    

    Здесь же я вызвал все методы объекта, поменял значение свойства Var и снова вызвал. Попробуйте сами, всё должно работать и с несколькими объектами тоже.

     

     


     

    Наследование

     

     

    Сначала необходимо познакомиться с самим термином. Наследование - это перенимание всех свойств и методов одного класса другим.

     

    Давайте напишем новый класс и назовём его parent.

    function parent() --Класс предок для будущего класса наследника
    	local Me = { }
            local private = {
                ["Secret"] = 42
            }
    	Me.Var = "HelloWorld"
    	function Me.PrintVar()
    		print(Me.Var)
    	end
    	return Me
    end 

    В этом классе есть свойство Var и метод PrintVar(), а также скрытое свойство в таблице private.

     

    Теперь пишем класс наследник:

    function class()
    	local Me = parent() --Перенимаем таблицу объекта из класса parent(), то есть наследуем.
    	return Me
    end 

    Всё! Поздравляю, вы наследовали класс! :D  Но на самом деле не полностью, т. к. остаётся наше скрытое свойство. Я не просто так засунул его в таблицу. Мы можем передать эту таблицу как и сам объект, но отдельно.

    function parent()--Класс предок
    	local Me = {
    		["Var"] = "HelloWorld" --Публичное свойство
    	}
    	local private = {
    		["Secret"] = 42 --Скрытое свойство
    	}
    	function Me.PrintVar() --Метод
    		print(Me.Var)
    	end
    	return Me, private --Возвращение объекта, а затем таблицы со скрытыми переменными
    end
    function class() --Класс наследник
    	local Me, private = parent() --Наследование
    	function Me.getVar() --Функция, возвращающая свойство Var из класса parent
    		return Me.Var
    	end
    	function Me.getSecret()
    		return private.Secret --Функция, возвращающая скрытое свойство Secret класса parent
    	end
    	return Me, private --Этот класс можно наследовать тоже, таким образом, получится двойное наследование
    end 

    Теперь тестим:

    local class = require("filename").class --Нужно, если вы разместили класс в другом файле
    --[[
    Если вы разместили классы в разных файлах, то следует загружать каждый отдельно, но так как они у меня в одном файле, я вызову только наследника, и это всё равно будет работать.
    ]]
    
    local object = class() --Создаём объект
    object.PrintVar() --Тестим метод из класса предка
    --> HelloWorld
    
    print(object.getVar()) --Тестим метод класса class, работающий с Var
    --> HelloWorld
    
    print(Me.getSecret()) --Получаем значение скрытого свойства
    --> 42
    

    Как видите, всё должно работать. Вы можете сами попробовать построить этот класс и вызывать его методы.

    В принципе тут больше нечего объяснять, я думаю. Если что-то не понятно, спрашивайте, отвечу.

     

     


     

    Экономия оперативной памяти

     

     

    Представим класс:

    function class()
        return {
            ["foo"] = function()
                --Здесь очень много кода, вычислений, инструкций и т.д.
            end;
            ["var"] = "какая-то переменная, для примера"
        }
        --Оформил тело объекта так, для разнообразия
    end 

    Главный минус таких "классов" в том, что они тратят оперативную память, бессмысленно создавая идентичные функции, которые сохраняются отдельно. Но этого можно избежать почти полностью. Почему почти, вы сейчас уведите.

    Представим класс в несколько ином виде, как блок do <тело класса> end.

    do --Начало класса
        local function class_foo(self) --Наша "тяжёлая" функция
            --Здесь очень много кода, вычислений, инструкций и т.д.
        end
        function class() --Функция для вызова класса
        return {
            ["foo"] = function()
                return class_foo(self) --Ссылаемся на локальную функцию
            end;
            ["var"] = "какая-то переменная, для примера"
        }

        end end --Конец класса 

    Вот и всё! Сложная функция записывается только один раз, а методы ссылаются на неё. Также вы можете не использовать блок do, но тогда функции будут доступны вне класса.

     

     


     

    Только читаемые свойства

     

     

    Это последнее, о чём стоит написать в этой теме. Только читаемые свойства могут понадобится для возвращения результатов объекта не используя функции, и при этом, не предоставляя возможность редактировать эти самые свойства. Это можно сделать используя магию метатаблиц. Не знаете, что это? Тогда бегом читать! Хотя сейчас можно обойтись и без этого  ;). Объяснить на словах, как это сделать, трудно, так что просто смотрите код:

    function class()
        local private = { } --Таблица со скрытыми свойствами
        private.__index = { --Таблица внутри таблицы скрытых свойств с читаемыми переменными. !!!Важно! Таблица должна сохраняться под ключом __index!!!
            ReadOnly = true; --Читаемое свойство
            Set = function( var ) --Читаемый метод, который изменяет значение читаемого свойства
                private.__index.ReadOnly = var
            end;
        }
        private.secret = 42823 --Скрытое свойство
        private.__newindex = function() end --Метаметод, непозволяющий менять значение таблицы объекта, если приравняете не к функции, а к таблице будет выводить в неё все попытки замены свойств.
        local Me = { } --Сам объект, да он пуст
        setmetatable( Me, private ) --Магия метатаблиц: устанавливает метатаблицу private для объекта
        return Me, private --Зачем я возвращаю таблицу со скрытыми свойствами, смотрите в наследовании
    end 

    Надеюсь комментарии к коду выше вполне понятны и всё объясняют. Так что мы можем перейти к тестированию.

    Тестируем:

    local class = require 'class'.class --Загрузка класса, если он в другом файле.
    
    local object = class() --Получаем объект на основе нашего класса
    object.Set( "test" ) --Устанавливаем значение для читаемого свойства читаемой функцией. Напрямую мы это сделать не сможем.
    print(object.ReadOnly) --Выводим значение ReadOnly
    --> test
    
    object.ReadOnly = "He he!"
    --Изменяем значение, надеясь, что это сработает
    
    print(object.ReadOnly) --Но он выводит старое значение
    --> test

    На этом всё. Теперь вы можете использовать читаемые свойства для того, чтобы не создавать специальные для этого методы.

     

     

     

    Вывод. Этот способ реализации ООП в Lua будет работать и в OC и в СС. "Классы" очень похожи на классы из других языков программирования. В моём варианте нет двоеточия, которое приносит странную возможность обработки одного объекта методом другого. Использовать ООП в игре можно для удобной разметки интерфейса в вашей программе (например для создания кнопок), и для экономии системных ресурсов в вашем компьютере внутри компьютера.

    • Нравится 6

  9. Код хороший, но подожди ка, а где же таблица и функции package? Это ведь специальный инструмент, что бы не забивать оперативную память, и ускорить работу программы при нескольких одинаковых вызовах require().

    Больше об этом написано здесь http://ilovelua.narod.ru/about_lua.html#Module_loaders

    Можешь посмотреть как require и package реализовано в ОС https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/src/main/resources/assets/opencomputers/loot/OpenOS/lib/package.lua

    Я изменил код теперь всё должно работать, как было написано в той статье. Спасибо за информацию. Моя программа вышла меньше чем OC. Хотя я её особо не смотрел

    • Нравится 2

  10. os.loadAPI чем не устраивал?Но за прошу лайк, часто когда с ок компа сажусь за кк комп, пишу половину функций неверно. Вот только проблемам есть. Кк не поддерживает полную вставку кода, только 1 строка, а смысл этого велосипеда, если придётся писать os.loadAPI? Хотя, можно её как глобальную функцию в стартап вставить

    Просто, используя эту функцию, можно загружать библиотеки в локальную переменную, не трогая глобальную, а также использовать shell API. Кроме способа, который ты описал, можно использовать функцию dofile("fileName"), если хочешь хранить её в отдельном от программы файле.


  11. Пока я писал свою систему для ComputerCraft, мне пришла мысль изобрести велосипед в виде функции require(), которая была удалена из мода по неизвестным мне причинам. Собственно вот код:

    function require(...)
    	local i
    	local libs = { }
    	for i=1, #arg do
    		arg[i] = fs.combine("", arg[i]) --В кавычки можно написать путь к директории с вашими библиотеками.
    		if not fs.exists(arg[i]) or fs.isDir(arg[i]) then
    			error("Couldn't find a file by the path #"..i, 2)
    		end
    		local g = getfenv()
    		local t = { }
    		setmetatable(t, {__index = _G})
    		t.shell = shell
    		t.multishell = multishell
    		setfenv(1, t)
    		local f=function() dofile(arg[i]) end
    		local ok, err = pcall(f)
    		setfenv(1, g)
    		if not ok then error(err..", in #"..i, 2) end
    		libs[i] = t
    	end
    	return unpack(libs)
    end
    

    ,,Что-же эта функция делает?"- может кто-то спросить, а тоже что и раньше. Она загружает библиотеку по выбранному вами пути в таблицу (или правильнее будет сказать, в окружение). Самое главное - это то, что вы сможете загружать любое API в любую переменную, в том числе и локальную. Выглядит это примерно так:

    local firstVariable, secondVariable = require("APIs/HelloWorld.api", "APIs/Object.lua")
    

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

    Особенности:

    • загрузка нескольких переменных одновременно;
    • возможность не захламлять глобальное окружение;
    • использование библиотек в любой другой таблице;
    • пропуск shell API и multishell API в окружение вашего API*;
    • запуск вашего файла с библиотекой во время загрузки (ну это я из пальца выжимаю);
    • в отличии от стандартной функции, вы не можете использовать require()для поиска библиотеки среди файлов, но по-моему это лишнее в CC, но вы можете указать одну папку (заметка на счёт этого в коде);
    • вы можете убедится в том, что окружение, куда вы запихнули свою библиотеку, не содержит копию всех функций и переменных из глобального окружения (что хорошо сказывается на производительности).

     


    ​Для того, чтобы использовать эту функцию, просто вставьте её код в вашу программу. Надеюсь, что это кому-нибудь пригодится.

     

    Дополнение.

    Я переделал функцию и добавил взаимодействие с глобальной таблицей package, этот вариант намного лучше предыдущего. Чтобы использовать его скачайте файл с помощью команды:

    pastebin get naxXwUey package 

    Далее загрузите в глобальное окружение с помощью функции dofile("package"). Теперь рассмотрим, что же я изменил. :)

    Во-первых, при повторном вызове функции с одним и тем же API, вы получаете ту же самую таблицу, то-есть:

    local var1 = require("lib1")
    local var2 = require("lib1")
    print(var1 == var2)
    
    -->Вывод: true 

    Так получается, потому что каждая новая загруженная библиотека сохраняется в таблице package.loaded, а при повторном вызове, вам выдаётся значение из этой таблицы. Я также внес все стандартные API ComputerCraft'а в эту таблицу.

    Во-вторых, я добавил значение package.path, оно работает точно также, как и в оригинале. Просто перечисляете директории с библиотеками в током виде:

    package.path = "/APIs/?.lua;/Lib/?;/?" 

    Вы можете изменить это значение в самом файле, я там оставил комментарий.

    Также я добавил таблицу package.preload, которая содержит специальные пользовательские функции для загрузки конкретного API, по стандарту я её оставил пустой (что логично). Ключи таких функций являются названиями API, а возвращать они должны функции, которые возвращают само API (правда не знаю, кому это может понадобиться).

    И наконец, package.loaders, в этом массиве, расположены функции для загрузки всех API. Их пока две. Аргументом этой функции должно быть имя модуля, а возвращать она должна функцию, загружающую API.

    Для тех, кто ничего не понял, просто знайте второй вариант этой функции с дополнением лучше.)))

    *Да-да, теперь вам не придётся мучиться и придумывать изощрённые способы получения допуска к функциям этого API в вашей библиотеке!

    • Нравится 5
×
×
  • Создать...