Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Commits on Apr 30, 2014
  1. @guns

    Bind *ns* to file's ns during read

    guns authored
    Commit 54cba5c introduced a method of
    detecting unqualified, unquoted symbols within syntax quotes that are
    consumed in-namespace.
    From the commit message:
    > We can avoid this situation by walking the body and de-qualifying only
    > the symbols that have been qualified in the current ns. This should
    > not be problematic since unknown symbols are qualified in the current
    > ns by default.
    Now, the "current ns" is determined by the reader to be the value of
    the *ns* var. When using Slamhound from an editor plugin, it can be
    assumed that *ns* is set to the namespace of the current open buffer.
    Unfortunately, when using Slamhound from a command line, *ns* is
    actually set to the `user` ns.
    This causes symbols that we expect to be qualified as `my.ns/foo` to
    actually be qualified as `user/foo`. There have been scattered reports
    of slamhound attempting to alias namespaces as `user`¹. In at least some
    of these cases, this problem is likely to blame.
    ¹ #65 comes to mind
Commits on Apr 23, 2014
  1. @guns

    Add support for definterface and gen-class

    guns authored
    Classes generated by definterface and gen-class don't have any reliable
    metadata that can be used to differentiate them from regular classes.
    Also, while defrecord and deftype implement clojure.lang.IType, nothing
    dictates that these must be created from a Clojure namespace. This is in
    contrast to definterface and gen-class, which have no utility outside of
    of a namespace.
    Therefore, we must fall back to naming conventions to infer
Commits on Apr 3, 2014
  1. @guns

    Prefer imports whose package name matches a project namespace

    guns authored
    A user who creates a logging deftype at
    org.mycompany.loggingservices.Logger probably doesn't want to import
    The slam.hound.regrow_test.UUID IRecord was changed to conflict with
    java.util.TreeSet as this change breaks other tests that did not
    anticipate this preference.
Commits on Mar 30, 2014
  1. @guns

    Export test string literals from prettify-test and stitch-test

    guns authored
    These changes, unlike 27d61ba, do not use `with-transform-test`, but
    they do make manipulating and reading the expected test output easier.
  2. @guns

    Add slam.hound.test.util/with-transform-test

    guns authored
    In order to accurately test Slamhound's interaction with files, we must
    test the output of the entire process:
        - Open a reader on a file
        - Receive Clojure forms from reader (with reader macros expanded)
        - Reconstruct namespace
        - Write the new namespace back to the file, but copy everything else
          back verbatim
    Many tests within Slamhound use (StringReader. (str '(literal forms)))
    in order to avoid the drudgery of doing a manual pr-str.
    Unfortunately, (str '[^{:my-metadata "value"} x]) outputs: "[x]", so any
    metadata on the forms is irretrievably lost.
    Since the interaction of Slamhound and metadata on forms is non-obvious,
    I think writing our integration tests as comparisons of input and output
    _files_ will help us detect these issues sooner in the future.¹
    I have placed with-transform-test and with-tempfile into a common
    testing namespace so that they can be used across all test files.
    RE: the name `with-transform-test`:
        - I read it as "With transform, test …"
        - Many editors commonly treat ^with-.* as a specially indented form
        - It's awkward, so if a better name is found, let's use it
    ¹ See issue #72, and commit 54cba5c for
      past issues with metadata
Commits on Mar 28, 2014
  1. @guns

    Run prettify tests with explicit *print-right-margin*

    guns authored
    I have that var globally rebound to `80`, for instance.
Commits on Mar 23, 2014
  1. @guns

    Style refactoring in asplode

    guns authored
    Notice the new compact :refer vector due to the changes to the prettify
  2. @guns

    Keywordize ns reference keys

    guns authored
    A common confusion regarding the ns macro is the use of symbols vs
    keywords for `:require`, `:import`, etc.
    The fact that both work just fine in the ns form does not help at all.
    Since one goal of Slamhound is to promote a single conventional style
    for ns forms, it is a good idea to be graceful on this issue.
    Closes #73
  3. @guns

    Add :rename failure type to regrow

    guns authored
    If an old ns contains a :rename entry for a missing refer, we attempt
    this rename before any others.
    If the old ns does not contain a possible :rename entry, the :rename
    path is __NEVER__ attempted since a missing reference could be
    hypothesized to be a rename of ANY public var.
    slam.hound.regrow/candidate has been made private as the function
    signature has changed, decreasing its suitability for public
  4. @guns

    Add asplode support for :rename option in :require libspecs

    guns authored
    Since both `require` and `use` both call `load-lib` internally, both
    functions can also be supplied a :rename option.
  5. @guns

    Allow certain libspecs to have keys on multiple lines

    guns authored
    The following require form fits nicely on one line:
        (:require [my.ns :as ns :refer [alpha beta gamma]])
    If the vector of refers is long, it overflows to the next line but the
    :refer key stays on the first line:
        (:require [my.ns :as ns :refer [alpha beta gamma delta epsilon
                                        zeta eta theta]])
    This may not work nicely when there are two libspecs options that are
        (:require [my.ns :as ns :refer [alpha beta gamma delta epsilon
                                        zeta eta theta] :rename {alpha α,
                                                                 beta β,
                                                                 gamma γ}])
    In this case, allow each option pair to start on a new line:
        (:require [my.ns :as ns
                   :refer [alpha beta gamma delta epsilon zeta eta theta]
                   :rename {alpha α, beta β, gamma γ}])
Commits on Mar 22, 2014
  1. @guns

    Don't insert :refer vector for mass referred namespaces

    guns authored
    e.g. (:require [my.ns :refer [foo] :refer :all]) is not valid.
  2. @guns

    Add namespaces beginning with "cljs." to the blacklist

    guns authored
    Many contrib libraries ship with Clojure ( and ClojureScript
    ( namespaces. Because the CLJS namespaces contain many
    of the same vars as their Clojure counterparts, these namespaces
    frequently appear in candidate lists. Furthermore, they often win the
    disambiguation process since "cljs" is shorter than "clojure".
    Slamhound does not currently support ClojureScript, so blacklisting
    these namespaces for the time being is quite convenient.
Commits on Mar 21, 2014
  1. @guns

    Identify aliases that conflict namespaces

    guns authored
    Slamhound erroneously returns the var portion of an ns-qualified
    namespace for a missing alias when the alias happens to correspond with
    an existing namespace.
    Closes #67
Commits on Mar 20, 2014
  1. @guns
Commits on Mar 18, 2014
  1. @guns

    Extend print-liblist to handle libspecs with multiple options

    guns authored
    This is what used to happen to some libspecs with both :alias and :refer
        (ns foo
          (:require [clojure.pprint :as pp :refer
    This now prints as:
        (ns foo
          (:require [clojure.pprint :as pp :refer [*print-miser-width*
                                                   cl-format code-dispatch
                                                   formatter-out pprint
    Note that libspecs with very long namespace names, aliases, or 3+
    options are unlikely to respect *print-right-margin* with the current
    implementation. In practice this does not seem like a problem.
  2. @guns

    Disable :miser mode during ns prettify

    guns authored
    *print-miser-width* -> 40
        (:require [my.very.sequipedalian.namespace :refer [alpha
                                                           delta epsilon]])
    *print-miser-width* -> nil
        (:require [my.very.sequipedalian.namespace :refer [alpha beta gamma
                                                           delta epsilon]])
Commits on Mar 14, 2014
  1. @guns

    Handle case where an alias is used to refer to private vars

    guns authored
        (ns alpha)
        (def ^:private foo)
        (def bar)
        (ns beta)
        (def foo #'a/foo)
        (def bar a/bar)
    The beta namespace uses the `a` alias to refer to both alpha/bar and the
    private var alpha/foo.
    Slamhound previously failed to find `alpha` -> `a` in this case since it
    attempts to find a ns that contains #{foo bar} in its set of _public_
    The solution implemented here is to try the alias search twice, once
    with all symbols, and again without (var symbol) forms.
    This does mean that Slamhound will be unable to find aliases that are
    used to refer to both public and private vars via #':
        (def foo #'b/private-var)
        (def foo #'a/public-var)    ; Just use a/public-var
Commits on Jan 30, 2014
  1. @guns

    Fix find-matching-ns for namespaces with underscores

    guns authored
    Problems fixed:
    1. find-matching-ns did not return a symbol when falling back to a
       linear search
    2. Namespaces with trailing underscores were undetectable
  2. @guns

    Remove unused test data

    guns authored
Commits on Jan 29, 2014
  1. @guns

    :require matching ns when importing classes created by deftype

    guns authored
    Classes created by deftype and defrecord are created on ns evaluation,
    therefore that ns must be required before referencing these classes.
    deftype and defrecord classes implement IType and IRecord in Clojure
    1.3.0+, so we can check the hierarchy to identify them.
    There is unfortunately no straightforward mapping of class package names
    to Clojure namespaces as deftype uses clojure.core/namespace-munge to
    simply change all \- to \_.
    Therefore a two step search for the matching ns is made:
        1. Try the simple case where all underscores are converted to dashes
        2. Search for the first namespace that matches the package name with
           dashes and/or underscores.
    Closes #64
Commits on Jan 4, 2014
  1. @guns

    Mirror LispReader when matching missing symbol names

    guns authored
    LispReader is very liberal about what characters may appear in a symbol:
        static Pattern symbolPat
            = Pattern.compile("[:]?([\\D&&[^/]].*/)?(/|[\\D&&[^/]][^/]*)");
    Therefore non-ASCII Unicode strings are also valid symbols:
        (def unicode-symbols
          '#{스람훈드 Σλαμηονδ ∧ ∨ ∩ ∪ ¬ ∀ ∅ ∴ ∫})
    The new sym-pat now covers this set of characters as well.
    Also from
        static boolean isWhitespace(int ch){
            return Character.isWhitespace(ch) || ch == ',';
    Happily, the symbol names in error messages are only ever surrounded by
    spaces and commas.
  2. @guns

    Fix reflection warnings

    guns authored
    Reflection can be a useful tool for achieving polymorphism when methods
    do not adhere to a well-defined interface or class hierarchy. It is also
    quite expensive (and the warnings generated with *warn-on-reflection*
    are very ugly) so its use should be justified.
    Slamhound's use of reflection is unnecessary, so this patch resolves all
    reflection warnings in the project.
    First, we replace .trim and .split calls to their clojure.string
    equivalents. This actually increases flexibility at no appreciable cost.
    Next we add type hints for static dispatch. Most of these hints are
    actually beneficial for clarity, but one function's type signature was
    implicitly changed:
    -(defn clj? [f]
    -  (.endsWith (.getName f) ".clj"))
    +(defn clj? [^String path]
    +  (.endsWith path ".clj"))
    I don't believe this will cause any problems as it is unlikely that
    anyone has been tempted to use this function outside of slamhound. This
    function, as well as most functions within, are good
    candidates for being made private.
    Most of the dynamic method calls dealt with organizing classes from
    jar files, so there has been a corresponding performance increase for
    reconstructing namespaces that use many imports.
    For instance, reconstructing is now ~20% faster. The
    function is a full ~100% faster.
    Preloading speed and alias/refer reconstruction performance has not been
    noticeably affected.
Commits on Nov 28, 2013
  1. @guns

    Add `=` to missing-sym-patterns

    guns authored
    Discovered while trying to refer cljs.core.logic.macros/==
Commits on Nov 26, 2013
  1. @guns

    Rank alias candidates by "alias" distance, then prefer initialisms

    guns authored
    Where "alias distance" is defined as the number of insertions between
    the first and last character of an alias necessary to create a
    front-anchored subsequence of the candidate string.
    This is meant to favor matching single-letter or straight subsequence
    aliases, even when other candidates are shorter. Two common examples
        s/replace should prefer clojure.string, not clojure.core
        st/join   should prefer clojure.string, not clojure.set
    Currently, dashes are not recognized as word separators, although they
    arguably should:
        (alias-distance "fbz" "foo-bar-zab") ; 6
        (alias-distance "fbz" "frobnobz")    ; 5
    It's clear that the intent is to alias foo-bar-zab; we should be able to
    address this in the future.
    A somewhat common convention for aliases are initialisms:
        juc -> java.util.concurrent
        cji ->
    We try to detect these as a last resort before falling to the default
  2. @guns

    Fix some tests for disambiguate

    guns authored
    Also clarify ranking functions with docstrings, even though they are
  3. @guns

    Move special handling of cljs.core to regrow/disambiguate

    guns authored
    While 'clojure.core needs to special handling in both parsing
    and emission because of :refer-clojure, removing cljs.core from
    consideration should strictly be the job of regrow.
Commits on Nov 25, 2013
  1. @guns

    Add support for aliasing clojure.core

    guns authored
    While :refer, :exclude, and :rename lists for clojure.core are handled
    by :refer-clojure, aliasing clojure.core is still handled in the
    :require clause.
    This is a valid tactic when replacing many vars from clojure.core from
    another namespace:
        (ns my.ns
          (:require [clojure.core :as core]
                    [my.clojure.impl :refer :all])
          (:refer-clojure :only []))
  2. @guns

    Prevent multiple aliases to a single namespace

    guns authored
    This is possible in Clojure:
        (ns my.ns
          (:require [ :as f]
                    [ :as foo]))
    This is, of course, due to the facile implementation of the ns macro.
    Revealingly, this version fails:
        (ns my.ns
          (:require [ :as f :as foo]))
    It fails due to a duplicate key exception; libspec arguments are made
    into a map via (apply hash-map libspec-args).
    Currently, if a body of expressions contains multiple aliases to a
    single namespace, Slamhound enters an infinite loop:
        (string/trimr (s/triml my-string))
        ;; 1. missing namespace "string" -> {:alias {clojure.string string}}
        ;; 2. missing namespace "s"      -> {:alias {clojure.string s}}
        ;; 3. missing namespace "string" -> {:alias {clojure.string string}}
        ;; …
    We could change the map entry for the :alias key to {ns-sym #{ns-sym}}
    to support this situation, but we would be forced to emit each alias in
    a separate libspec.
    Since both the idea of one-to-many aliases and the needed changes to
    slam.hound.stitch are repellent, we will enforce one alias per namespace
    during disambiguation.
Commits on Nov 24, 2013
  1. @guns

    Remove :slamhound-skip from regrow-test

    guns authored
    We call require directly in the body instead since it's a special case
    for testing.
  2. @guns

    Disjoin current ns from candidate namespaces

    guns authored
    If a user moves `myvar` from `my.ns.a` to `my.longer.ns.b` then runs
    slamhound on `my.ns.a` to refer the var from `my.longer.ns.b`m slamhound
    constructs the following ns:
    (ns my.ns.a
      (:require [my.ns.a :refer [myvar]]))
    This throws a circular dependency error and should be avoided.
Commits on Nov 18, 2013
  1. @guns

    Prefer candidates from project namespaces

    guns authored
    Addresses the greater half of the TODO item:
    ;; TODO: prefer things in src/classes to jars
  2. @guns

    Extract component functions from search/namespaces

    guns authored
    Three functions for extracting namespace symbols from classpaths:
    Each function has a unary version, primarily for easier testing, as well
    a constant version closed over the current classpath.
  3. @guns

    Merge branch 'experimental'

    guns authored
    The walk/replace of symbols qualified to the current *ns* does not seem
    It also addresses long time issue #14, so I am merging it in.
    * experimental:
      Escape ns qualifier within pattern
      Find consumed references within syntax-quotes
Commits on Nov 15, 2013
  1. @guns

    Always search dynamically generated classes for :import candidates

    guns authored
    Only including candidates from #'ns-import-candidates when the static
    class search fails does not cover the case where a dynamic class shares
    the same name as a static class.
    This meant a user that wants to import a deftype class
    my.very.long.namespace.UUID, it will never be found because of the
    existence of java.util.UUID.
Something went wrong with that request. Please try again.