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.
Related
What is the sane way to go from a Module object to a path to the file in which it was declared?
To be precise, I am looking for the file where the keyword module occurs.
The indirect method is to find the location of the automatically defined eval method in each module.
moduleloc(mm::Module) = first(functionloc(mm.eval, (Symbol,)))
for example
moduleloc(mm::Module) = first(functionloc(mm.eval, (Symbol,)))
using DataStructures
moduleloc(DataStructures)
Outputs:
/home/oxinabox/.julia/v0.6/DataStructures/src/DataStructures.jl
This indirect method works, but it feels like a bit of a kludge.
Have I missed some inbuilt function to do this?
I will remind answered that Modules are not the same thing as packages.
Consider the existence of submodules, or even modules that are being loaded via includeing some abolute path that is outside the package directory or loadpath.
Modules simply do not store the file location where they were defined. You can see that for yourself in their definition in C. Your only hope is to look through the bindings they hold.
Methods, on the other hand, do store their file location. And eval is the one function that is defined in every single module (although not baremodules). Slightly more correct might be:
moduleloc(mm::Module) = first(functionloc(mm.eval, (Any,)))
as that more precisely mirrors the auto-defined eval method.
If you aren't looking for a programmatic way of doing it you can use the methods function.
using DataFrames
locations = methods(DataFrames.readtable).ms
It's for all methods but it's hardly difficult to find the right one unless you have an enormous number of methods that differ only in small ways.
There is now pathof:
using DataStructures
pathof(DataStructures)
"/home/ederag/.julia/packages/DataStructures/59MD0/src/DataStructures.jl"
See also: pkgdir.
pkgdir(DataStructures)
"/home/ederag/.julia/packages/DataStructures/59MD0"
Tested with julia-1.7.3
require obviously needs to perform that operation. Looking into loading.jl, I found that finding the module path has changed a bit recently: in v0.6.0, there is a function
load_hook(prefix::String, name::String, ::Void)
which you can call "manually":
julia> Base.load_hook(Pkg.dir(), "DataFrames", nothing)
"/home/philipp/.julia/v0.6/DataFrames/src/DataFrames.jl"
However, this has changed to the better in the current master; there's now a function find_package, which we can copy:
macro return_if_file(path)
quote
path = $(esc(path))
isfile(path) && return path
end
end
function find_package(name::String)
endswith(name, ".jl") && (name = chop(name, 0, 3))
for dir in [Pkg.dir(); LOAD_PATH]
dir = abspath(dir)
#return_if_file joinpath(dir, "$name.jl")
#return_if_file joinpath(dir, "$name.jl", "src", "$name.jl")
#return_if_file joinpath(dir, name, "src", "$name.jl")
end
return nothing
end
and add a little helper:
find_package(m::Module) = find_package(string(module_name(m)))
Basically, this takes Pkg.dir() and looks in the "usual locations".
Additionally, chop in v0.6.0 doesn't take these additional arguments, which we can fix by adding
chop(s::AbstractString, m, n) = SubString(s, m, endof(s)-n)
Also, if you're not on Unix, you might want to care about the definitions of isfile_casesensitive above the linked code.
And if you're not so concerned about corner cases, maybe this is enough or can serve as a basis:
function modulepath(m::Module)
name = string(module_name(m))
Pkg.dir(name, "src", "$name.jl")
end
julia> Pkg.dir("DataStructures")
"/home/liso/.julia/v0.7/DataStructures"
Edit: I now realized that you want to use Module object!
julia> m = DataStructures
julia> Pkg.dir(repr(m))
"/home/liso/.julia/v0.7/DataStructures"
Edit2: I am not sure if you are trying to find path to module or to object defined in module (I hope that parsing path from next result is easy):
julia> repr(which(DataStructures.eval, (String,)))
"eval(x) in DataStructures at /home/liso/.julia/v0.7/DataStructures/src/DataStructures.jl:3"
May be it is a really dumb question, but after playing around with all built-in pathname-family functions and cl-fad/pathname-utils packages I still can't figure out how to convert a relative path to absolute (with respect to $PWD):
; let PWD be "/very/long/way"
(abspath "../road/home"); -> "/very/long/road/home"
Where the hypothetical function abspath works just like os.path.abspath() in Python.
The variable *DEFAULT-PATHNAME-DEFAULTS* usually contains your initial working directory, you can merge the pathname with that;
(defun abspath (pathname)
(merge-pathnames pathname *default-pathname-defaults*))
And since this is the default for the second argument to merge-pathnames, you can simply write:
(defun abspath (pathname)
(merge-pathnames pathname))
UIOP
Here is what the documentation of UIOP says about cl-fad :-)
UIOP completely replaces it with better design and implementation
A good number of implementations ship with UIOP (used by ASDF3), so it's basically already available when you need it (see "Using UIOP" in the doc.). One of the many functions defined in the library is uiop:parse-unix-namestring, which understands the syntax of Unix filenames without checking if the path designates an existing file or directory. However the double-dot is parsed as :back or :up which is not necessarily supported by your implementation. With SBCL, it is the case and the path is simplified. Note that pathnames allows to use both :back and :up components; :back can be simplified easily by looking at the pathname only (it is a syntactic up directory), whereas :up is the semantic up directory, meaning that it depends on the actual file system. You have a better chance to obtain a canonical file name if the file name exists.
Truename
You can also call TRUENAME, which will probably get rid of the ".." components in your path. See also 20.1.3 Truenames which explains that you can point to the same file by using different pathnames, but that there is generally one "canonical" name.
Here's the final solution (based on the previous two answers):
(defun abspath
(path-string)
(uiop:unix-namestring
(uiop:merge-pathnames*
(uiop:parse-unix-namestring path-string))))
uiop:parse-unix-namestring converts the string argument to a pathname, replacing . and .. references; uiop:merge-pathnames* translates a relative pathname to absolute; uiop:unix-namestring converts the pathname back to a string.
Also, if you know for sure what kind of file the path points to, you can use either:
(uiop:unix-namestring (uiop:file-exists-p path))
or
(uiop:unix-namestring (uiop:directory-exists-p path))
because both file-exists-p and directory-exists-p return absolute pathnames (or nil, if file does not exist).
UPDATE:
Apparently in some implementations (like ManKai Common Lisp) uiop:merge-pathnames* does not prepend the directory part if the given pathname lacks ./ prefix (for example if you feed it #P"main.c" rather than #P"./main.c"). So the safer solution is:
(defun abspath
(path-string &optional (dir-name (uiop:getcwd)))
(uiop:unix-namestring
(uiop:ensure-absolute-pathname
(uiop:merge-pathnames*
(uiop:parse-unix-namestring path-string))
dir-name)))
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!
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]))
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Aliasing a java package name in clojure
If I have a Java API like this:
com.very.long.and.boring.names.Abc
com.very.long.and.boring.names.Def
com.very.long.and.boring.names.Ghi
Can I use it from Clojure (1.4.0) with a "fake" namespace like this:
(foo/Abc)
(foo/Def)
(foo/Ghi)
I don't want to (use 'com.very.long.and.boring.names) because Abc / Def / Ghi may clash with my Clojure functions. So basically I want to "map" "com.very.long.and.boring.names" to "foo".
I tried several things at the REPL but couldn't make it work.
I don't believe that this functionality exists as yet.
However if the purpose is to use the Class object at runtime, you can always just do:
(def s java.lang.String)
(.newInstance s)
=> ""
I think you're basically asking this same question:
Aliasing a java package name in clojure
Apparently the functionality doesn't actually exist yet...
However, class names usually start with capital letters, whereas function names are lower-case by convention. Unless the Java classes or your functions aren't following these conventions then you shouldn't have any conflicts.