• This repository has been archived on 02/Oct/2020
  • Stars
    star
    473
  • Rank 92,832 (Top 2 %)
  • Language
    Clojure
  • License
    Other
  • Created over 13 years ago
  • Updated about 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Slamhound rips your namespace form apart and reconstructs it.

Slamhound

They sent a slamhound on Turner's trail in New Delhi, slotted it
to his pheromones and the color of his hair. It caught up with him
on a street called Chandni Chauk and came scrambling for his
rented BMW through a forest of bare brown legs and pedicab
tires. Its core was a kilogram of recrystallized hexogene and
flaked TNT. He didn't see it coming. The last he saw of India was
the pink stucco facade of a place called the Khush-Oil Hotel.

Because he had a good agent, he had a good contract. Because he
had a good contract, he was in Singapore an hour after the
explosion. Most of him, anyway. The Dutch surgeon liked to joke
about that, how an unspecified percentage of Turner hadn't made it
out of Palam International on that first flight and had to spend
the night there in a shed, in a support vat.

It took the Dutchman and his team three months to put Turner
together again. They cloned a square meter of skin for him, grew
it on slabs of collagen and shark-cartilage polysaccharides. They
bought eyes and genitals on the open market. The eyes were green.

-- Count Zero, page 1. By William Gibson

Slamhound rips your ns form apart and reconstructs it. No Dutch surgeon required.

Add [slamhound "1.5.5"] to the :dependencies of your :user profile.

This project is no longer under active development.

Screencast

http://vimeo.com/80650659

Leiningen Usage

Make an alias for run -m slam.hound in your :user profile:

  :aliases {"slamhound" ["run" "-m" "slam.hound"]}

Take a namespace with a sparse ns form that won't compile:

$ cat src/my/namespace.clj # before: ns form is missing clauses

(ns my.namespace
  "I have a doc string.")

(defn -main [& args]
  (pprint args)
  (io/copy (ByteArrayInputStream. (.getBytes "hello"))
           (first args)))

Then run slamhound on it:

$ lein slamhound src/my/namespace.clj # [... thinking ...]

$ cat src/my/namespace.clj  # after: spits out new ns form
(ns my.namespace
  "I have a doc string."
  (:require [clojure.java.io :as io]
            [clojure.pprint :refer [pprint]])
  (:import (java.io ByteArrayInputStream)))

Like magic.

Running on a directory will perform the same operation on every .clj file inside.

Repl Usage

You can reconstruct namespaces from a repl to avoid the slow startup time:

user=> (require '[slam.hound :refer [reconstruct]])
nil
user=> (println (reconstruct "src/my/namespace.clj"))
(ns my.namespace
  "I have a doc string."
  (:require [clojure.java.io :as io]
            [clojure.pprint :refer [pprint]])
  (:import (java.io ByteArrayInputStream)))

Or to reconstruct files in place:

user=> (slam.hound/swap-in-reconstructed-ns-form "src/my/namespace.clj")
nil
;; Reload the file in your editor to pick up changes

Emacs Usage

The included slamhound.el allows for convenient access within nREPL or SLIME sessions via M-x slamhound. Install manually or via Marmalade.

Vim Usage

Install vim-slamhound for use of the :Slamhound command within Clojure buffers.

Light Table Usage

Install slamhound-lt from the central plugin repository.

Shortcomings

Syntax-quoted references

Slamhound will only find references in a namespace that are consumed within the namespace itself. For example, if you have a macro that refers to a var inside syntax-quote (backtick), but the macro is only called from other namespaces, then Slamhound won't detect the reference and will instead report the failure in the namespace in which the macro is called.

You can work around this problem by attaching dummy metadata to the defmacro form to prevent it from compiling without the necessary references being present:

(defmacro defexample
  "Metadata can be attached to a macro by specifying an `attr-map`
  between the docstring and the params vector."
  {:requires [AClass a-var an/aliased-var #'a-macro]}
  [name & args]
  `(do (def ~(str name \*) (AClass. ~@args))
       (def ~(str name \-) (a-var ~@args))
       (def ~(str name \+) (an/aliased-var ~@args))
       (def ~(str name \!) (a-macro ~@args))))

Notice that macros must be referenced with #' to avoid a Can't take the value of a macro error.

If the syntax quoted references refer to functions, classes, or constant data, unquoting them will work as well:

(defmacro defexample
  {:requires [#'a-macro]}
  [name & args]
  `(do (def ~(str name \*) (new ~AClass ~@args))
       (def ~(str name \-) (~a-var ~@args))
       (def ~(str name \+) (~an/aliased-var ~@args))
       (def ~(str name \!) (a-macro ~@args))))

In this case Aclass, a-var, and an/aliased-var must be resolved at compile time, so Slamhound will successfully find these references.

Note that the shorter reader macro form (AClass. ~@args) must be expanded to (new ~AClass ~@args) and that macros cannot be unquoted.

Fully qualified and dynamically resolved Vars

Slamhound will also not find references to fully-qualified vars or vars resolved at runtime since it relies on detecting compilation failures to determine when it's done.

PermGen memory pressure

Slamhound aggressively creates and destroys namespaces during reconstruction. This taxes the class loading system, so there is a possibility that the JVM may run out of PermGen space in large projects. If this happens, try running your JVM with the following option to enable garbage collection of discarded classes:

-XX:+CMSClassUnloadingEnabled

Side effects during namespace evaluation

As namespaces may potentially be reloaded many times during reconstruction, it is important that no side-effects (aside from var definition) occur during namespace evaluation.

Leiningen 1.x

The lein-slamhound plugin is deprecated, and the :aliases approach above is recommended for users of Leiningen 2. However, if you are still using Leiningen 1.x you can use the run task:

$ lein run -m slam.hound src/foo

Since Leiningen 1.x doesn't support partially-applied aliases, you would have to make a shell alias if you don't want to type the full invocation out every time.

License

Copyright © 2011-2012 Phil Hagelberg and contributors

Distributed under the Eclipse Public License, the same as Clojure.

More Repositories

1

leiningen

Moved to Codeberg; this is a convenience mirror
Clojure
7,293
star
2

emacs-starter-kit

[ARCHIVED] this is ancient history
2,865
star
3

robert-hooke

Hooke your Clojure functions!
Clojure
359
star
4

grenchman

Sorry about the name
OCaml
217
star
5

mire

Mire is a simple MUD written in Clojure
Shell
171
star
6

syme

Instant collaboration on GitHub projects.
Clojure
146
star
7

atreus-firmware

Firmware for the Atreus keyboard
Emacs Lisp
92
star
8

serializable-fn

Serializable functions in Clojure
Clojure
85
star
9

clojure-http-client

An HTTP client for Clojure (DEPRECATED)
Clojure
84
star
10

Garrett

A playground for Android Mirah development
Mirah
84
star
11

rinari

Rinari Is Not A Rails IDE (no longer updated; see eschulte's fork)
Emacs Lisp
66
star
12

lein-scalac

Clojure
54
star
13

conspire

A real-time collaborative editing platform built on Git.
Ruby
46
star
14

lein-licenses

List the license of each of your dependencies.
Clojure
44
star
15

skaro

comparative lispology
Scheme
42
star
16

lein-heroku

Experimental Leiningen plugin for managing Heroku apps
Clojure
42
star
17

radagast

Radagast is a simplistic test coverage tool.
Clojure
41
star
18

cooper

HyperCard-ish in Racket
Racket
39
star
19

erythrina

Basically ido for X, I guess?
OCaml
39
star
20

bludgeon

Bludgeon is a tool which will tell you if a given library is so large that you could bludgeon someone to death with a printout of it.
Ruby
37
star
21

bus-scheme

a Scheme written in Ruby, but implemented on the bus!
Ruby
37
star
22

nrepl-discover

proof-of-concept middleware for auto-discovery of nrepl ops
Clojure
36
star
23

lein.el

A no-startup-delay eshell replacement for the `lein` bash script.
Emacs Lisp
30
star
24

zossima

Jump to definition in Ruby driven by a live process
Emacs Lisp
30
star
25

lein-tar

Create tarballs from Leiningen projects.
Clojure
25
star
26

calandria

Unix in voxel-world
Lua
25
star
27

limit-break

Basic REPL breakpoints.
Clojure
25
star
28

javert

inspector
Clojure
24
star
29

orestes

the ultimate yak shave
C
23
star
30

relax.el

Interact with CouchDB databases from within Emacs, with ease!
Emacs Lisp
21
star
31

ri.el

An interface to RI (Ruby documentation) for Emacs
Emacs Lisp
19
star
32

circleci.el

Show build output from CircleCI builds inside Emacs
Emacs Lisp
19
star
33

lein-xml

All those parentheses got you down? How about some XML?
Clojure
17
star
34

ferrante

Locative Android app in Mirah
Shell
16
star
35

harker

Rails deployments via RubyGems. Because a package manager is a terrible thing to waste.
Ruby
14
star
36

lein-release

Tar up a Leiningen project along with some other handy directories
Clojure
13
star
37

corkscrew

Proof-of-concept build system for Clojure.
Clojure
12
star
38

seajure

The web site for Seajure, the Seattle Clojure Group
Clojure
12
star
39

metaverse

Parallel universes for namespaces
Clojure
12
star
40

lein-play

Play a sound when your tests pass or fail.
Clojure
12
star
41

super-explorer

2D tile exploring game
Racket
12
star
42

chortles

Calculate the magnitude of a given laugh
Clojure
12
star
43

lein-precate

You know, the opposite of deprecate.
Clojure
12
star
44

concourse

A web app for coordinating gatherings. Written in Compojure.
Clojure
10
star
45

paredit-screencast

9
star
46

server-socket

Clojure server-socket library spun off from monolithic contrib
Clojure
9
star
47

pindah

Moved to mirah organization
Ruby
7
star
48

lein-retest

Run only the test namespaces which failed last time around.
Clojure
5
star
49

lein-thrush

I guess technically it should be lein-comp; oops
Clojure
4
star
50

prometheus

XMPP heater
Erlang
4
star
51

lein-clean-m2

A Leiningen plugin to clean the local repository of unused artifacts.
Clojure
3
star
52

sokoban

push
Ruby
3
star
53

quickbeam

Access git trees.
Clojure
3
star
54

sketchbook

Some Processing sketches
Clojure
3
star
55

thai-type

Typing tutor for Thai
Racket
3
star
56

commodore-night-vision

Emacs Lisp
2
star
57

drainbot

Drain Heroku apps to IRC channels
Clojure
2
star
58

lein-blacklist

A Leiningen plugin to blacklist specific namespaces from being required.
Clojure
2
star
59

lein-survey

A survey of Leiningen users as a web app
Clojure
2
star
60

rcirc-ucomplete

Unambiguous completion for rcirc
Emacs Lisp
1
star
61

ss-calandria

A game using the minetest engine to teach programming and other technical skills
Lua
1
star
62

lein-standalone-repl

Clojure
1
star
63

swarm-go

Go, written by swarming
Clojure
1
star
64

squisserks

squisserks
Racket
1
star
65

clojars-verify

Verify checksums of Clojars artifacts
Clojure
1
star
66

lein-profiles

Profiles, backported from Leiningen 2 for your enjoyment.
Clojure
1
star
67

rodney-leonard-stubbs

The simplest stubs
Clojure
1
star
68

lein-assoc

A higher-order Leiningen task to run tasks with ad-hoc project keys.
Clojure
1
star