Подтвердить что ты не робот

Как конвертировать каталог в пакет?

У меня есть каталог с некоторыми вспомогательными функциями, которые нужно поместить в пакет. Первый шаг, очевидно, называет каталог чем-то вроде +mypackage\, поэтому я могу вызывать функции с помощью mypackage.somefunction. Проблема в том, что некоторые функции зависят друг от друга, и, по-видимому, MATLAB требует, чтобы функции пакета вызывали функции в одном пакете, явно указывая имя пакета, поэтому мне пришлось бы переписать все вызовы функций. Хуже того, если я решил переименовать пакет, все вызовы функций также должны быть переписаны. Эти функции даже не работают корректно, когда я cd в каталог, как только его имя начинается с +.

Есть ли более легкое решение, чем переписывание? Или, по крайней мере, что-то самореферентное, например import this.*, чтобы облегчить переименование будущего пакета?


edit Я заметил, что то же самое касается классов и статических методов, поэтому я поместил самореферентную часть в этот отдельный вопрос.

4b9b3361

Ответ 1

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

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

... (пауза, чтобы подумать, что то, что я собираюсь предложить, - хорошая идея;))...

Однако, если вы действительно хотите избежать необходимости проходить через свой пакет и добавить ваши вызовы функций с новым именем пакета, одним из подходов было бы использовать функцию MFILENAME, чтобы получить полный путь к текущей функции пакета, проанализируйте строку пути, чтобы найти родительские каталоги пакетов (которые начинаются с "+" ), затем передайте результат в IMPORT функция импорта родительских пакетов. Вы можете даже разместить эти шаги в отдельной функции packagename (требуя, чтобы вы также использовали функцию EVALIN):

function name = packagename
  callerPath = evalin('caller','mfilename(''fullpath'')');  %# Get full path of
                                                            %#   calling function
  name = regexp(callerPath,'\+(\w)+','tokens');  %# Parse the path string to get
                                                 %#   package directories
  name = strcat([name{:}],...                           %# Format the output
                [repmat({'.'},1,numel(name)-1) {''}]);
  name = [name{:}];
end

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

import([packagename '.*']);

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

'mainpack.subpack.subsubpack'

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

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

Ответ 2

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

Скажите, что у вас

+mypackage\intfc1.m
+mypackage\intfc2.m
+mypackage\private\foo1.m
+mypackage\private\foo2.m
+mypackage\private\foo3.m

Затем из intfc1, foo1, foo2 и foo3 доступны все без каких-либо спецификаторов пакетов или операторов импорта, а foo1, foo2 и foo3 также могут звонить друг другу без каких-либо спецификаторов пакетов или операторов импорта. Если foo1, foo2 или foo3 необходимо вызвать intfc1 или intfc2, то для этого требуется квалификация как mypackage.intfc1 или оператор импорта.

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

Чтобы идти еще дальше, вы можете создавать новые функции-обертки на уровне пакета с тем же именем, что и частные функции

+mypackage\foo1.m          <--- new interface layer wraps private foo1
+mypackage\private\foo1.m  <--- original function

где, например, +mypackage\foo1.m может быть:

function answer = foo1(some_parameter)
    answer = foo1(some_parameter);  % calls private function, not itself
end

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

В этой конфигурации все функции, включая обертки уровня пакета, не обращают внимания на имя пакета, поэтому переименование пакета является не чем иным, как переименованием папки.