Posso ricaricare una libreria e avere defvar riassegnare i valori?


10

Sto sviluppando una libreria e vorrei ricaricarla dopo averla modificata senza uscire da Emacs (supponiamo che sia attiva load-path):

(load-library "myname")

Quando lo faccio, Emacs non defvarrileva le modifiche alle variabili -bound.

Non voglio chiamare manualmente eval-defun( C-M-x) su ogni modulo di livello superiore. Fa M-x eval-bufferil rispetto defvar/ defcustom?


1
Forse (unload-feature 'myname)prima?
npostavs

Ho appena provato e no, al contrario eval-defun, non rileva le modifiche defvar.
JeanPierre,

1
@KaushalModi: non credo sia un duplicato. Questa domanda riguarda l'azione su tutti defvari messaggi in un file o buffer, se ho capito bene.
Estratto il

1
Normalmente non sarebbe mai necessario valutare solo i defvar. Anche l'utilizzo dell'OP load-fileimplica che vuole valutare l'intero file mentre si assicura che i defvar vengano rivalutati.
Kaushal Modi,

2
Il mio approccio è di eval-defun mentre cambio i valori. È abbastanza raro da essere utilizzabile per me. YMMV.
YoungFrog,

Risposte:


3

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

Funzionerà fintanto che hai caricato per la prima volta i defvars caricando la libreria tramite emacs e non usando eval-defun, eval-bufferecc.

Quando usi require, load-libraryecc. Emacs terrà traccia di quali variabili e funzioni fanno parte della tua libreria e le rimuoverà interamente per te quando lo usi unload-feature.

Quando scrivo i pacchetti, trovo che l'uso del codice sopra sia una soluzione migliore rispetto all'esecuzione eval-defunmentre scrivi un nuovo codice in modo da non entrare in stati intermedi.


(info "(elisp) Loading"), (info "(elisp) Unloading")E unload-featurerichiedono forcearg se libreria è dipendenza per un'altra libreria. Bella risposta! Mi chiedo quale versione di Emacs inizi a fornire lo scarico ...
gavenkoa

3

defvarnon riassegna il valore di una variabile nello stesso modo di, diciamo setqo setf. Una volta che una variabile ha un valore, defvar non la toccherà.

Dalla defvardotstring:

(defvar SYMBOL &optional INITVALUE DOCSTRING)

Definire SYMBOL come variabile e restituire SYMBOL.

...

L'argomento facoltativo INITVALUE viene valutato e utilizzato per impostare SYMBOL, solo se il valore di SYMBOL è nullo. Se SYMBOL è buffer-local, il suo valore predefinito è ciò che è impostato; i valori buffer-local non sono interessati. Se INITVALUE manca, il valore di SYMBOL non è impostato.

...

Dato che presumibilmente hai modificato defvarle variabili in questione per fornire loro i valori al primo caricamento della libreria, il nuovo caricamento della libreria non modificherà i valori.

Vedi anche il nodo manuale elisp su Definire variabili globali .

Invece di fare affidamento defvar, è sempre possibile riassegnare i valori con setq. In alternativa, è possibile utilizzare uninterni simboli in modo che gli defvars non li trovino al momento del ricaricamento:

(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
In questo contesto, vale a dire quando si sviluppa un pacchetto elisp, defvarè la cosa corretta da usare. setqbloccherebbe le personalizzazioni impostate dai singoli utenti. OP richiede un modo per forzare la sovrascrittura delle defvarvariabili durante lo sviluppo del pacchetto . Il passaggio a setqrichiederebbe il passaggio a defvarquando il pacchetto viene rilasciato.
Tyler,

@Tyler, sì, sono d'accordo che defvarè appropriato per lo sviluppo del pacchetto. Sto solo sottolineando che defvarnon riassegna i valori, mentre lo setqfa.
Dan

2

Prova questo:

(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)))))

Quello usa solo lo stesso codice che eval-defunusa su a defvar. Attraversa il buffer (o la sua limitazione restringendolo), fermandosi a ciascuno defvare usando il eval-defuncodice su di esso.


1

Dopo aver sentito che non esiste una soluzione conveniente per la rivalutazione del buffer con la riassegnazione di defvar'ho fatto una semplice funzione che si basa su 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))))

Struttura del codice ispirata eval-defun-2all'implementazione. È simile a Come forzare la rivalutazione di una defvar? soluzione.

Inizialmente voglio una funzione di alto livello per rivalutare la libreria che è stata reinstallata tramite lo script di build, quindi:

(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)))

La soluzione Drew funziona anche su nidificati defvarma è difficile comprendere completamente il codice.

Penso anche a uninterntutti i simboli basati sul prefisso / regex (come suggerito da Dan ) ma sono pigro nel digitare il prefisso ogni volta ... Vedi Come posso separare tutte le definizioni dei simboli con un certo prefisso?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.