3

I often find myself typing (ns user) and pressing C+c M+n repeatedly when I work on clojure source code. The problem is that I often use functions like source and doc and they are in clojure.repl and I don't want to :require them to my namespaces. What are experienced clojurians doing in this case?

Clarification: I know how clojure's namespacing works. What I want to achieve is to be able to call (source myfunc),(doc myfunc) etc. without the need to use fully qualified names in the REPL and without the need to require the functions from clojure.repl in each of my namespaces.

Adam Arold
  • 29,285
  • 22
  • 112
  • 207
  • 1
    In [my workflow](http://codereview.stackexchange.com/q/126376/82369), I like to keep a separate source file to hold my `user` namespace and all its dependencies. For instance, when I'm not using [Component](https://github.com/stuartsierra/component), the contents of my `dev/user.clj` file usually look something like this: `(ns user (:require [clojure.pprint :refer [pprint]] [clojure.repl :refer [doc source]]))` – Sam Estep Jul 07 '16 at 19:31
  • 2
    You mentioned `C-c M-n`. If you're using CIDER in Emacs, `M-.` does the equivalent of `source`. And `C-d d d` `doc`. You don't need to type `myfunc` is point is already on that text. – Greg Hendershott Jul 10 '16 at 15:18

2 Answers2

4

Thanks for clearing up what you are asking for.

Leiningen has a feature called :injections which you can combine with vinyasa to get this effect If you put something like this in your leiningen profile:

~/lein/profiles.clj:

{:user {:plugins []
        :dependencies [[im.chit/vinyasa "0.1.8"]]
        :injections [(require 'vinyasa.inject)
                      (vinyasa.inject/inject
                       'clojure.core '>
                       '[[clojure.repl doc source]
                         [clojure.pprint pprint pp]])]}}

Because this is in your profiles.clj it only affects you. Other people who work on the project won't be affected.


Because injecting into clojure.core strikes me as a little iffy, I follow the vinyasa author's advice and inject into a namespace called . which is crated by my profile for every project I work on. This namespace always exists which makes these function work even in newly created namespaces that don't yet refer clojure.core.

My ~/.lein/profiles.clj:

{:user
  {:plugins []
   :dependencies [[spyscope "0.1.4"]
                  [org.clojure/tools.namespace "0.2.4"]
                  [io.aviso/pretty "0.1.8"]
                  [im.chit/vinyasa "0.4.7"]]
   :injections
   [(require 'spyscope.core)
    (require '[vinyasa.inject :as inject])
    (require 'io.aviso.repl)
    (inject/in ;; the default injected namespace is `.`

               ;; note that `:refer, :all and :exclude can be used
               [vinyasa.inject :refer [inject [in inject-in]]]
               [clojure.pprint :refer [pprint]]
               [clojure.java.shell :refer [sh]]
               [clojure.repl :refer [doc source]]
               [vinyasa.maven pull]
               [vinyasa.reflection .> .? .* .% .%> .& .>ns .>var])]}}

which works like this:

hello.core> (./doc first)
-------------------------
clojure.core/first
([coll])
  Returns the first item in the collection. Calls seq on its
    argument. If coll is nil, returns nil.
nil
hello.core> (in-ns 'new-namespace)
#namespace[new-namespace]
new-namespace> (./doc first)
nil
new-namespace> (clojure.core/refer-clojure)
nil
new-namespace> (./doc first)
-------------------------
clojure.core/first
([coll])
  Returns the first item in the collection. Calls seq on its
    argument. If coll is nil, returns nil.
nil
Arthur Ulfeldt
  • 90,827
  • 27
  • 201
  • 284
1

To achieve this, you may use vinyasa library, in particular its inject functionality. Basically you need to add needed functions from clojure.repl namespace to clojure.core namespace. After you won't need to require them explicitly. See the following:

user> (require '[vinyasa.inject :refer [inject]])
nil

;; injecting `source` and `doc` symbols to clojure.core
user> (inject '[clojure.core [clojure.repl source doc]]) 
[]

;; switching to some other namespace
user> (require 'my-project.core)
nil
user> (in-ns 'my-project.core)
#namespace[my-project.core]

;; now those functions are accessible w/o qualifier
my-project.core> (doc vector) 
-------------------------
clojure.core/vector
([] [a] [a b] [a b c] [a b c d] [a b c d e] [a b c d e f] [a b c d e f & args])
  Creates a new vector containing the args.
nil
OlegTheCat
  • 4,443
  • 16
  • 24