2010-04-25 24 views
5

¿Sería posible anular el comando 'requerir' para que intente descargar cierto recurso si no se encuentra en la máquina local. Por ejemplo:Reemplazando 'requerir' en Clojure?

(require 'examples.introduction) 
; if not found => download from the net 
; (url: http://media.pragprog.com/titles/shcloj/code/examples/introduction.clj) 

Respuesta

4

Usted puede reemplazar la función require y por supuesto la variante overriden podría descargar cosas si el espacio de nombres que se le pidió no está disponible en la ruta de clase. Sobrescribir la forma en que :require funciona en formularios (ns ...) es, AFAIK, imposible por ahora debido a la forma en que se maneja ns.

Tenga en cuenta que una 'descarga de require' no sería muy útil si desea colocar nuevas rutas en la ruta de clase (incluidos nuevos archivos jar), ya que la inyección classpath no funciona de manera confiable en Clojure (debido a problemas de JVM) . Hay esclojure.core/add-classpath ... pero se ha marcado como obsoleto desde siempre, se desaconseja su uso, no hay garantías de que funcione para usted y esta situación probablemente no cambie pronto. Por otro lado, si desea poner nuevos archivos fuente en un directorio que ya estaba presente en el classpath, entonces debería funcionar bien.

En caso de que desea jugar con primordial require, si usted tiene un espacio de nombres foo, se podría hacer

(ns foo 
    (:refer-clojure :exclude [require]) 
    ; other stuff; any :requires here will work as usual! 
) 

A continuación, defina su propio requerir, mediante clojure.core/require cuando sea apropiado:

(defn require [ns-symbol] 
    (do-stuff-to-obtain-the-namespace)) 

clojure.contrib.find-namespaces espacio de nombres podría ser útil para saber qué hay disponible en el classpath. (O puede utilizar la función the-ns y ver si se produce una excepción después de un intento inicial que requiere el espacio de nombres a través clojure.core/require.)

Tenga en cuenta que el enfoque binding que podría venir a la mente primero ((binding [require ...] ...)) no funcionará, ya require normalmente resuelve a un Var interno en el espacio de nombres clojure.core y Vars de espacios de nombres cuyos nombres comienzan con clojure están directamente vinculados por el compilador (lo que significa que no se realiza una búsqueda Var real en tiempo de ejecución, por lo que volver a vincular esos Vars no tiene efecto en el código) .

El (:refer-clojure :exclude [require]) en forma ns para su espacio de nombres impide require de resolver a clojure.core/require y te deja libre para definir un VAR de ese nombre en su propio espacio de nombres. Como se mencionó anteriormente, eso no impide que el clojure.core/require Var sea accesible si escribe el símbolo completamente calificado.

+0

Interesante. Estoy pensando que puede ser mejor usar un nombre de función diferente como "requerimiento mejorado" para evitar el uso de las soluciones temporales del espacio de nombres. (Soy un novato total, así que corrígeme si estoy hablando tonterías. :)) – StackedCrooked

+0

Por el contrario, parece una mejor manera de hacerlo.Debo decir, sin embargo, que la * mejor * manera, en términos prácticos, sería hacer que Leiningen/Maven obtuviera cualquier dependencia de la biblioteca, y para cosas como el código fuente que acompaña a los libros, simplemente vaya y descárguelo a mano ...: -) ¡No se necesita algo de la diversión de escribir un funky requerir que lo haría por sí mismo! –

1

En realidad, (complemento ruta de clases "http://foo/bar/baz/src/ ") o (complemento ruta de clases" http://www.foo.com/bar.jar"), se permiten que requiere la materia remota.

Las advertencias de Michał se aplican sin embargo: solo utilícelas para jugar en la réplica ...