Чи можу я перезавантажити бібліотеку та мати значення defvar повторно призначити?


10

Я розробляю бібліотеку і хотів би перезавантажити її після редагування, не виходячи з Emacs (припустимо, що вона включена load-path):

(load-library "myname")

Коли я це роблю, Emacs не збирає зміни defvarзмінних -bound.

Я не хочу телефонувати eval-defun( C-M-x) вручну на кожній формі верхнього рівня. Чи M-x eval-bufferповажає defvar/ defcustom?


1
Може, (unload-feature 'myname)спочатку?
npostavs

Просто спробував це, і ні, на відміну від eval-defunнього, зміни не відбулися defvar.
ЖанП'єр

1
@KaushalModi: Я не думаю, що це дублікат. Це питання стосується дії всіх defvarфайлів у файлі чи буфері, якщо я правильно розумію.
Дрю

1
Зазвичай ніколи не потрібно буде оцінювати лише дефаварів. Також використання ОП load-fileозначає, що він хоче оцінити весь файл, переконавшись, що девальватори переоцінені.
Каушал Моді

2
Мій власний підхід - це eval-defun, коли я змінюю значення. Це досить рідко, щоб бути корисним для мене. YMMV.
ЯнгФрог

Відповіді:


3

(progn (unload-feature 'your-lib) (load-library "your-lib"))

Це буде працювати до тих пір , як ви завантажили перший defvars шляхом завантаження бібліотеки через Emacs, а не з допомогою eval-defun, і eval-bufferт.д.

При використанні require, і load-libraryт.д. Emacs буде відслідковувати , які змінні і функції є частиною бібліотеки, і видалити їх повністю для вас , коли ви використовуєте unload-feature.

Під час написання пакетів я вважаю, що використання коду вище - це краще рішення, ніж запуск, eval-defunколи ви пишете новий код, щоб ви не потрапляли в проміжні стани.


(info "(elisp) Loading"), (info "(elisp) Unloading")і unload-featureвимагають forceаргументу, якщо бібліотека є залежністю для іншої бібліотеки. Чудова відповідь! Мені цікаво, яка версія Emacs починає забезпечувати розвантаження ...
gavenkoa

3

defvarне перепризначає значення змінної так само, як, скажімо, setqабо setf. Коли змінна має значення, defvar її не торкнеться.

З defvar's docstring:

(defvar SYMBOL &optional INITVALUE DOCSTRING)

Визначте SYMBOL як змінну та поверніть SYMBOL.

...

Необов'язковий аргумент INITVALUE оцінюється та використовується для встановлення SYMBOL, лише якщо значення SYMBOL недійсне . Якщо SYMBOL буферно-локальний, його значенням за замовчуванням є те, що встановлено; локальні значення буфера не впливають. Якщо INITVALUE відсутня, значення SYMBOL не встановлено.

...

Оскільки ви, ймовірно, defvarредагували вказані змінні, щоб надати їм значення під час першого завантаження бібліотеки, повторна завантаження бібліотеки не змінить значення.

Дивіться також вузол посібника elisp щодо визначення глобальних змінних .

Замість того, щоб покладатися на це defvar, ви завжди можете перепризначити значення за допомогою setq. Як альтернатива, незграбний варіант, ви можете uninternвикористовувати символи, щоб defvars не знайшов їх при перезавантаженні:

(defvar test-1 "test this")
(defvar test-2 "test this one, too")

test-1                                  ; => "test this"
test-2                                  ; => "test this one, too"

(defvar test-1 "trying to redefine")
(defvar test-2 "trying to redefine, too")

test-1                                  ; => "test this"
test-2                                  ; => "test this one, too"

(mapc #'unintern '(test-1 test-2))

test-1                                  ; => error!
test-2                                  ; => error!

(defvar test-1 "trying to redefine")
(defvar test-2 "trying to redefine, too")

test-1                                  ; => "trying to redefine"
test-2                                  ; => "trying to redefine, too"

2
У цьому контексті, тобто, розробляючи пакет elisp, defvarце правильно використовувати. setqможе налаштувати налаштування індивідуальних користувачів. OP просить спосіб примусити перезапис defvarзмінних під час розробки пакету . Для setqпереходу defvarна пакет потрібно буде повернутися до, коли пакет буде випущений.
Тайлер

@Tyler, так, я згоден, що defvarпідходить для розробки пакунків. Я лише вказую, що defvarне переназначає значення, тоді setqяк.
Дан

2

Спробуйте це:

(defun foo ()
  "(Re-)evaluate all `defvar's in the buffer (or its restriction)."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while (not (eobp))
      (when (re-search-forward "\\s-*(defvar \\([^ \t\n(\"]+\\)[ \t\n]+[^)]" nil 'MOVE)
        (let ((old-value (make-symbol "t"))
              new-value value)
          (let ((debug-on-error old-value))
            (setq value (eval-defun-2))
            (setq new-value debug-on-error))
          (unless (eq old-value new-value)
            (setq debug-on-error new-value))
          value)))))

Він просто використовує той самий код, який eval-defunвикористовується для defvar. Він обходить буфер (або його обмеження звуженням), зупиняючись на кожному defvarі використовуючи eval-defunкод на ньому.


1

Після того як я почув, що не існує зручного рішення для переоцінки буфера з перепризначенням defvars, я зробив просту функцію, яка ретранслюється на eval-defun:

(defun my/eval-buffer ()
  "Evaluate entire buffer with re-assigning values to `defvar' / `defcustom'.
Useful during package development."
  (interactive)
  (save-excursion
    (beginning-of-buffer)
    (while (not (eobp))
      (eval-defun nil)
      (end-of-defun))))

Структура коду, натхненна eval-defun-2реалізацією. Це схоже на Як змусити переоцінити дефавар? рішення.

Спочатку я хочу, щоб функція високого рівня переоцінила бібліотеку, яка перевстановлена ​​через сценарій збірки, щоб:

(defun my/load-library (library)
  "Evaluate entire library with re-assigning values to `defvar' / `defcustom'.
Useful during package development."
  (interactive
   (list (completing-read "Load library: "
                          (apply-partially 'locate-file-completion-table
                                           load-path
                                           '("" ".el")))))
  (with-temp-buffer
    (insert-file-contents (locate-file library load-path '("" ".el")))
    (my/eval-buffer)))

Рішення Drew працює навіть на вкладених, defvarале код важко повністю зрозуміти.

Я також думаю про uninternвсі символи на основі префіксу / регексу символів (як запропонував Ден ), але я лінивий щоразу вводити префікс ... Див. Як я можу відв'язати всі визначення символів певним префіксом?

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.