Как советовать примитивы в Emacs

Я пытался ответить на еще один вопрос SO когда я столкнулся с очень странным поведением. Вот мой небольшой тестовый пример:

(make-variable-buffer-local
 (defvar my-override-mode-on-save nil
   "Can be set to automatically ignore read-only mode of a file when saving."))

(defadvice file-writable-p (around my-overide-file-writeable-p act)
  "override file-writable-p if `my-override-mode-on-save' is set."
  (or
   my-override-mode-on-save
   ad-do-it))

(defun my-override-toggle-read-only ()
  "Toggle buffer's read-only status, keeping `my-override-mode-on-save' in sync."
  (interactive)
  (setq my-override-mode-on-save (not my-override-mode-on-save))
  (toggle-read-only))

(defun tester-fn ()
  (interactive)
  (let ((xxx (file-writable-p "/tmp/foofoo"))
        (yyy (file-writable-p "/tmp/fooxxfoo")))
    (message (concat "XXX: " (if xxx "yes" "no") "   -   YYY: " (if yyy "yes" "no")))))

где:

  • /tmp/foofoo — это файл только для чтения, который я посетил и запустил my-override-toggle-read-only.
  • /tmp/fooxxfoo не существует.
  • /tmp доступен для записи пользователю, под которым я зарегистрирован.

Если я запускаю tester-fn в буфере, где my-override-mode-on-save установлено на t, я получаю неожиданный результат: XXX: no - YYY: no. Если я запускаю tester-fn, находясь в другом буфере (например, scratch), я получаю ожидаемый ответ в минибуфере: XXX: no - YYY: yes. Отслеживание совета через отладчик показывает, что он делает именно то, что, по моему мнению, он должен делать, выполняя части, которые я от него ожидаю, пропуская части, которые я от него ожидаю, возвращая значение, которое я от него ожидаю. Однако отслеживание tester-fn с помощью отладчика показывает, что возвращаются очень разные значения (nil и t, если переменная оценивается как ноль, nil и nil, если переменная оценивается как ненулевая). Возврат nil и nil действительно кажется мне странным.

Я понятия не имею, что здесь происходит. Кто-нибудь знает, почему я не получаю ожидаемых результатов?


person Joe Casadonte    schedule 19.06.2010    source источник


Ответы (1)


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

(defadvice file-writable-p (around my-overide-file-writeable-p act)
  "override file-writable-p if `my-override-mode-on-save' is set."
  (setq ad-return-value
        (or
         my-override-mode-on-save
         ad-do-it)))

Это описано в советах.

person Trey Jackson    schedule 19.06.2010
comment
Я всегда думал, что ad-return-value используется для переопределения возвращаемого значения, а не для его установки (об этом говорится в руководстве). Но это действительно была недостающая часть — спасибо! - person Joe Casadonte; 20.06.2010
comment
разница (для меня) заключается в предположении, что возвращаемое значение будет нормальным (т. е. последнее оцененное выражение), и для его изменения будет использоваться ad-return-value. - person Joe Casadonte; 20.06.2010
comment
@JoeCasadonte Ах, я всегда интерпретировал совет как предоставление вам крючков для изменения поведения, но это (цитирование) After-advice и around-advice может переопределить возвращаемое значение, установив ad-return-value. Но я вижу твой POV. - person Trey Jackson; 21.06.2010