Как преобразовать каталог в пакет? - PullRequest
12 голосов
/ 12 апреля 2011

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

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


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

Ответы [ 2 ]

15 голосов
/ 12 апреля 2011

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

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

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

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

function name = packagename

  % Get full path of calling function:
  callerPath = evalin('caller', 'mfilename(''fullpath'')');

  % Parse the path string to get package directories:
  name = regexp(callerPath, '\+(\w)+', 'tokens');

  % Format the output:
  name = strcat([name{:}], [repmat({'.'}, 1, numel(name)-1) {''}]);
  name = [name{:}];

end

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

import([packagename '.*']);

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

'mainpack.subpack.subsubpack'

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

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

3 голосов
/ 16 сентября 2015

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

Скажем, у вас есть

+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

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

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

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