I'm using Clojure to write a small test framework.
(ns pvt.core.runner
(use
[pvt.tests.deployment]
[pvt.tests.files]
[pvt.tests.jms]))
(defn- run-test
[test-name]
{test-name (test-and-log test-name)})
(defn- run-all-tests-in-namespace
[namespace-name]
(map
run-test
(vals (ns-publics (symbol namespace-name))))
)
(defn run-all-tests
[namespace-list]
(map run-all-tests-in-namespace namespace-list))
My run-all-tests function accepts a list of clojure scripts, loads all the public functions in those scripts and runs them. This is great, only that i have to actually import those scripts. I call my function like this (run-all-tests ["pvt.tests.deployment" "pvt.tests.files" "pvt.tests.jms"]), but this only works if I import each of these scripts as seen at the beginning of my code excerpt. This is not ok, since I hvae no idea who will call run-all-tests, and what parameters will be used.
I was wondering if there's a way of importing these scripts at runtime. I already know the namespace of each script, so I have all the required information. Can this be done?
Thanks
Yes, you can import Clojure source files from arbitrary file paths using load-file. If the source file contains a namespace declaration, those namespaces are now available to your Clojure application (framework).
Obviously, at a minimum you'll have to write some code that either takes names of Clojure source files from the command-line, or points to directories where the source files are located. Then your code will load the files using (load-file).
Your stated problem is that you want to execute some tests from the namespace without knowing the namespace names in advance. There are two ways to achieve this:
1) Use a naming convention. i.e. run your tests for each namespace that has the name matching your convention, i.e.
user=> (load-file "/home/noahlz/foo.clj")
#<Var#1e955d29: #<core$foo foo.test.core$foo#48a7a9bd>>
user=> (filter #(re-matches #".*\.test\..*" %) (map str (all-ns)))
("foo.test.core")
Using code like the above, you've obtained a list of namespaces upon which you can execute your framework code.
2) Use metadata. Rather than follow a naming convention, require users of your framework to add metadata to their namespaces. This reduces the chance of accidentally testing a namespace that accidentally followed your convention.
(See: What are some uses of Clojure metadata?)
Note that this is the approach used by Clojure's own clojure.test/deftest macro.
Here is an example of finding namespaces with your custom metadata. Your namespace declaration in a source file defining tests:
(ns ^{:doc "some documentation" :my-framework-tests true}
foo.test.core)
At the REPL, an example of how you can obtain these programmatically:
user=> (load-file "foo.clj")
user=> (filter (fn [[n m]] (:my-framework-tests m))
(map #(vector (str %) (meta %)) (all-ns)))
(["foo.test.core" {:my-framework-tests true, :doc "some documentation"}])
Now you have a list of namespaces that have been flagged as containing tests for your custom test framework. You could even use metadata in the namespace functions to avoid needing a naming convention for those as well.
There might be a more concise way to obtain namespaces having certain metadata (if someone knows of it, by all means, comment!)
Another important note: I'm loading arbitrary files to demonstrate it's possible, buy you really should consider following conventions followed by Leiningen, Maven or other build frameworks. For example, see lein-perforate
Good luck!
Thanks for helping me out. I managed to find what I was looking for. It was actually simpler than I thought. Didn't know that use is actually a function. Now i simply do this:
(defn- run-all-tests-in-namespace
[namespace-name]
(use (symbol namespace-name))
(map
run-test
(vals (ns-publics (symbol namespace-name))))
)
I create a symbol from the namespace name and then pass it to the use function. Works great!
Related
My lisp file contains about 50 function and macro definitions. At the head of the file is:
(defpackage :utils
(:use :common-lisp))
(in-package :utils)
; ... ~50 defuns/defmacros follow along with some other code
I want to export all these 50 definitions. But no other symbols.
To write them all out in :export clauses inside defpackage seems very tedious.
I tried getting the necessary symbols by using loop's facility for listing symbols in a package. But both "symbol" and "present-symbol" don't output the needed definition symbols. I could somehow subtract "external-symbols" and inherited symbols. But this seems like the kind of thing everyone would need and there should be an established easy solution. I looked around and haven't found a straightforward answer.
How do I export all the definition symbols without having to write them out individually and manually?
scan symbols
You can scan all symbols and export all that have a function binding (this includes macro names):
(defun export-fbound-symbols (package)
"export symbols with function bindings"
(do-symbols (s package)
(when (fboundp s)
(export s package))))
This is usually not a very good idea: good software engineering practice is to limit the set of public interfaces.
be more selective
You can redefine defun and defmacro so that they automatically export their definienda.
See exporting.lisp in CLISP. E.g.,
(defmacro define-function (name lambda-list &body body)
`(progn
(export ',name)
(defun ,name ,lambda-list ,#body)))
Note that this ignores the possibility of (defun (setf foo) (...) ...).
No, this is not something everyone needs. Usually, you'd export them as you write (and actually need) them.
I'd probably use an ad hoc keyboard macro for this. You could also write a little Lisp function to read your file form by form and output the relevant symbols for copy-paste.
Lisp is said to enable redefinitions of its core functions.
I want to define an alias to the function cl:documentation function, such that
(doc 'write 'function) === (documentation 'write 'function)
How can this be done and made permanent in SBCL?
Creating an Alias
You are not trying to redefine (i.e., change the definition of) the system function documentation, you want to define your own function with a shorter name which would do the same thing as the system function.
This can be done using fdefinition:
(setf (fdefinition 'doc) #'documentation)
How to make your change "permanent" in common lisp
There is no standard way, different implementation may do it differently, but, generally speaking, there are two common ways.
Add code to an init file - for beginners and casual users
SBCL
CLISP
Clozure
ECL
The code in question will be evaluated anew every time lisp starts.
Pro:
Easy to modify (just edit file)
Takes little disk space
Normal lisp invocation captures the change
Con:
Evaluated every time you start lisp (so, slows start up time if the code is slow)
Save image - for heavy-weight professionals
SBCL
CLISP
Clozure
ECL - not supported
The modified lisp world is saved to disk.
Pro:
Start uptime is unaffected
Con:
Requires re-dumping the world on each change
Lisp image is usually a large file (>10MB)
Must specify the image at invocation time
Even though #sds has already answered pretty thoroughly I just wanted to add that the utility library serapeum has defalias
I use a simple macro for this:
(defmacro alias (to fn)
`(setf (fdefinition ',to) #',fn))
e.g.
(alias neg -) => #<Compiled-function ... >
(neg 10) => -10
Other answers include detail about how to make this permanent.
I've been using noir in a web project and I came up to the point of restricting access to users, depending on their access level (and sublevel) to all possible routes defined by a defpage macro. So originally I had
(defpage [:post "/mysite"] {:as input}
(if-not (has-reqd-user-level? :levelX :sublevelY "/grantedRoute")
(noir.response/redirect "/insufficientRights")
...))
And then I thought this would get rid of boilerplate code:
(defmacro defpage-with-user-level [level sublevel granted-route route data expr]
`(defpage ~route ~data
(if-not (has-reqd-user-level? ~level ~sublevel ~granted-route)
(noir.response/redirect "/insufficientRights")
~expr)))
Finally, we use it as follows:
(defpage-with-user-level :levelX :sublevelY "/grantedRoute"
[:post "/mysite"] {:as input}
(html
[:body [:h1 (str "Hello " (:name input) "!")]]))
But as mentioned in this post made by Rich Hickey, https://groups.google.com/forum/#!msg/clojure/4II-HKr_Pu0/2IcKit99cagJ , it feels a little bit awkward because of positional binding, which is not idiomatic when there already exist maps.
However, I've been looking for some examples or discussions regarding the use of destructuring bindings in macros, and sadly, I hadn't found any clear use of them, because of its unevaluated expressions being passed through all along.
So, the following solution came to my mind:
(defmacro defpage-with-user-level [dts expr]
`(defpage (:route ~dts) (:data ~dts)
(if-not (has-reqd-user-level? (:level ~dts) (:sublevel ~dts) (:granted-route ~dts))
(noir.response/redirect "/insufficientRights")
~expr)))
But now, it's not clear how to pass the data map that maps locals from :get and :post into a local as in the examples above.
Am I doing right leaving my first attempt untampered or do I really need to use the second approach? I hope not. Is there any other option? Please, let me know.
Your first solution is fine. What Rich was talking about was using plain old maps to passing data around rather then creating new types/classes for each type of data. Ex: you can represnt a user information using a simple map rather than creating a class to represent user data.
As far as your second attempt is concerned, you can use map de-structuring in macro as:
(defmacro defpage-with-user-level [{:keys [route data level sublevel granted-route]} expr]
`(defpage ~route ~data
(if-not (has-reqd-user-level? ~level ~sublevel ~granted-route)
(noir.response/redirect "/insufficientRights")
~expr)))
(defpage-with-user-level {:level :levelX
:sublevel :sublevelY
:granted-route "/grantedRoute"
:route [:post "/mysite"]
:data {:as input}}
(html
[:body [:h1 (str "Hello " (:name input) "!")]]))
In Clojure, if I want to pull in the clojure.inspector functions, I can go like this:
(use `[clojure.math.numeric-tower :include (expt)])
From the REPL, and I can now evaluate the function expt.
However, it seems to me that there should be (and probably is) another way to do it - pulling in the code using Leiningen dependencies.
I add this line to my project.clj:
[org.clojure/math.numeric-tower "0.0.2"]
And I restart the REPL to pull in the new dependency. I even do "lein deps" to be safe (there is no output for that command). When I try to evaluate expt, it gives me a RuntimeException, and says its Unable to resolve the symbol.
How can I access the expt function, only using Leiningen dependencies?
You can't. It doesn't work like that. Adding a dependency puts the code on your classpath, which merely means it is available for you to use. In order to actually use the things inside the namespaces, you need to use
(require '[the-namespace :refer [the things you want to use]])
or
(require '[the-namespace :as tn])
(tn/somevar)
or do either of those things in an ns declaration (when not in the REPL and working with a file)
(ns foo
(:require [the-namespace :as tn]))
I have a program that draws shapes on an image. I have a separate namespace for each shape, and they are in separate files.
com/name/box.clj --> has com.name.box namespace.
com/name/triangle.clj --> has com.name.triangle namespace.
They all share a common function called generate that draws them on screen, so if I use use, function names clash.
For now, I load them with load-file. Is there a better way of doing this? Looking through the Clojure API, it seems there are multiple ways of including files. Which one is a better option for a project with lots of files?
I too started by using load-file. According to the Clojure documentation on libs,
Clojure defines conventions for naming and structuring libs:
* A lib name is a symbol that will typically contain two or more parts separated by periods.
* A lib's container is a Java resource whose classpath-relative path is derived from the lib name:
o The path is a string
o Periods in the lib name are replaced by slashes in the path
o Hyphens in the lib name are replaced by underscores in the path
o The path ends with ".clj"
* A lib begins with an "ns" form that
o creates the Clojure namespace that shares its name, and
o declares its dependencies on Java classes, Clojure's core facilities, and/or other libs
The Clojure documentation further provides the following example namespace declaration (which I'm sure you already know, but I'm providing it here for completeness):
(ns com.my-company.clojure.examples.my-utils
(:import java.util.Date)
(:use [clojure.contrib.def :only (defvar-)])
(:require [clojure.contrib.shell-out :as shell]))
So, my answer would be to use libs for your project -- it'll help simplify all of those folders. To "include" a lib, you'll use require, like this:
(require 'clojure.contrib.def 'clojure.contrib.except 'clojure.contrib.sql)
(require '(clojure.contrib def except sql))
As long as the documentation is correct and your project is classpath-relative, everything should happily load. Hope that answers your question. :D
Along with using namespace libs as already has been suggested perhaps your common 'generate' function is a candidate for a multimethod? http://clojure.org/multimethods
This would help avoid the function name clash and add a common abstraction to your 'shapes', I guess it depends on whether an appropriate dispatch function can be found.