2010-09-23 13 views

Respuesta

19

Una alternativa a source (que debería estar disponible a través de clojure.repl/source al iniciar un REPL, a partir de 1.2.0. Si se trabaja con 1.1.0 o inferior, source está en clojure.contrib.repl-utils.), Para su uso REPL, en vez de mirar funciones definido en un archivo .clj:

(defmacro defsource 
    "Similar to clojure.core/defn, but saves the function's definition in the var's 
    :source meta-data." 
    {:arglists (:arglists (meta (var defn)))} 
    [fn-name & defn-stuff] 
    `(do (defn ~fn-name [email protected]) 
     (alter-meta! (var ~fn-name) assoc :source (quote ~&form)) 
     (var ~fn-name))) 

(defsource foo [a b] (+ a b)) 

(:source (meta #'foo)) 
;; => (defsource foo [a b] (+ a b)) 

un simple print-definition:

(defn print-definition [v] 
    (:source (meta v))) 

(print-definition #'foo) 

#' es sólo un reader macro, la expansión de #'foo a (var foo):

(macroexpand '#'reduce) 
;; => (var reduce) 
+0

Es mejor dejar caer la cabeza para deshacerse de la palabra clave defsource. (alter-meta! (Var ~ fn-name) assoc: source (drop 1 (quote ~ & form)) – haijin

18

Usted querrá importar el espacio de nombres repl, y utilizar la función source de ella:

(ns myns 
    (:use [clojure.repl :only (source)])) 
(defn foo [] (if true "true")) 
(source foo) 

=> (foo [] (if true "true")) 
    nil 

Aunque esto no funcionaría en el REPL, sólo cuando la función está definida en un archivo .clj en el classpath. Lo cual no responde a su pregunta, entonces: necesitará tener un defn que almacene, en los metadatos del fn que define, la fuente de la función. Luego escribirías una función que recuerde ese bit de metadatos. Eso no debería ser terriblemente difícil.

4

Recientemente hice esta pregunta en la lista de correo de Clojure y las respuestas incluyeron partes de la REPL para ocultar la entrada (y la salida) para referencia futura así como una anulación de defn para almacenar la fuente en metadatos (que luego podrías recuperar fácilmente en REPL).

Read the thread on the Clojure mailing list

+0

-1, Esta respuesta podría ser mejor si incluyó una explicación más detallada aquí, vea [meta] (http://meta.stackexchange.com/a/8259/180500). Esta respuesta realmente no proporciona una prescripción concreta. –

11

En REPL clojure de 1.2, la función source está disponible inmediatamente. Puede usarlo de esta manera:

$ java -cp clojure.jar clojure.main 
Clojure 1.2.0 
user=>(source slurp) 
(defn slurp 
    "Reads the file named by f using the encoding enc into a string 
    and returns it." 
    {:added "1.0"} 
    ([f & opts] 
    (let [opts (normalize-slurp-opts opts) 
      sb (StringBuilder.)] 
     (with-open [#^java.io.Reader r (apply jio/reader f opts)] 
     (loop [c (.read r)] 
      (if (neg? c) 
      (str sb) 
      (do 
       (.append sb (char c)) 
       (recur (.read r))))))))) 
nil 
user=>

Algunas otras funciones también se importan automáticamente en user espacio de nombres del REPL de la biblioteca clojure.repl. Consulte el documento API here.

Sin embargo, como se ha señalado en otras respuestas aquí, no se puede utilizar como source es imprimir volver funciones que se han definido en el REPL.

13

Clojure no tiene un descompilador, lo que significa que no hay forma de llegar a la fuente de una función arbitraria a menos que fuera un defn cargado desde el disco.Sin embargo, puede usar un truco limpio llamado serializable-fn para crear una función que tenga su forma fuente almacenada en sus metadatos: http://github.com/Seajure/serializable-fn

La respuesta defsource es muy similar a esto, pero esta solución funciona con fns arbitrarios, no solo nivel superior defns. También hace que los fns se impriman bellamente en el repl sin una función de impresión especial.

Cuestiones relacionadas