Skip to content
marick edited this page Jan 16, 2013 · 4 revisions

The compendium stores facts after they've been loaded. It stores two other pieces of information:

  • the fact most recently checked.
  • the working set, which describes the subset of the compendium that you're working with.

These commands work on the compendium:

  • load-facts: Load namespaces and check facts.
  • check-facts: Check some or all of the loaded facts again (without reloading them)
  • forget-facts: Forget some or all of the loaded facts
  • fetch-facts: Return a sequence of some or all of the loaded facts.
  • recheck-fact: Check the last fact checked again.
  • last-checked-fact: Provide previous fact as a value.
  • source-of-last-checked-fact: Show source of previous fact.

See [repl tools] for brief example of each. Read on for the details.

About the working set

The working set is intended to track your focus of attention in an intuitive way such that giving commands with no arguments works on the facts you currently care about. In case what's intuitive to me isn't to you, here are the basic rules. Individual commands may vary them slightly.

At the beginning, Midje assumes you're interested in all facts in all namespaces. Therefore, these two ways of loading facts are equivalent:

user=> (load-facts :all)    ;; `:all` is shorthand for "all project test and source namespaces"
user=> (load-facts)

The first changes the working set to what it already was. The second uses the original working set.

If you give arguments to load-facts, you also change the working set. So consider these commands:

(load-facts 'scratch.util.* :core)
(check-facts)
(load-facts)

The first command loads a particular set of facts (the "core" facts in the scratch.util namespaces). Thereafter, both the argument-free check-facts and load-facts will act as if you'd repeated the arguments.

As another example, consider the following:

(load-facts :all)  ;; 
(check-facts 'scratch.util.fun)
(check-facts)

The first check-facts restricts the working set to one namespace. The following check-facts will keep working on that namespace.

Print levels (verbosity)

Midje allows you to adjust its print level to adjust the verbosity of output. The new print levels are given as keyword arguments to compendium functions. For example, the following loads all namespaces and prints each namespace as it's loaded:

user=> (load-facts :all :print-namespaces)
= Namespace as-documentation.t-assumptions
= Namespace as-documentation.t-defining-checkers
= Namespace as-documentation.t-prerequisites
...

The print level is remembered by the different commands. So, suppose you use check-facts to narrow the working set:

user=> (check-facts 'midje.util.t-laziness)
= Namespace midje.util.t-laziness
All claims (23) have been confirmed.
true

Note that the namespace was printed even though the specific argument wasn't given.

Filtering facts

The compendium is organized by namespace. Except for the commands that work on a specific fact (such as recheck-last-fact), a command can take one or more namespace arguments. Its attention becomes restricted to those namespaces and, except for forget-facts, the working set is changed to match.

Namespaces can be either true namespace values (like that pointed to by *ns*) or symbols naming namespaces. As a special case, load-facts can take a wildcard namespace like midje.util.*. That refers to all namespaces whose names begin with "midje.util.".

Within those namespaces, facts can also be filtered by metadata. There are five types of filters:

  • keywords select any fact whose metadata contains a truthy value for that key.

    (load-facts 'proj.util.* :integration)
  • strings select any fact whose name contains the string. (It needn't be an exact match.)

    (load-facts :all "compendi")  ;; Would match facts with either "compendium" or "compendia"
  • regular expressions select any fact whose name contains a substring that matches the regular expression.

    (check-facts #"bug-\d+")     ;; Check facts whose name contains a bug report number.
  • functions are passed a fact's metadata. If the function returns a truthy value, the fact is included.

    (fetch-facts #(> (:midje/name %) 33))  ;; fetch facts with really long names
    (load-facts :all (complement :slow))   ;; load facts that are not slow.
    
  • multiple filters select facts that match any of the filters.

    (load-facts (complement :slow) :core)   ;; Load facts that are not slow or are core.

Redefining facts in the compendium.

Suppose you have a namespace that contains this fact:

(fact (+ 1 1) => 2)

If you reload that namespace (whether via load-facts, load-file, require, or – for that matter – cutting and pasting the contents into the repl), you don't want to get two copies of it in the compendium. For that reason, a fact is only added to the compendium if it has a different body than a fact that's already there. This check is namespace-specific. If you have the same fact in two different namespaces, you'll get two copies, one under each namespace.

Now let's suppose you have a fact like this:

(fact "the `throws` checker accepts many varieties of arglists"
  (throw-exception "msg") => (throws Error)
  (throw-exception "msg") => (throws "msg")
  (throw-exception "msg") => (throws #(= "msg" (.getMessage %)))
  ...)

... and you want to add a new check inside the fact. You want the new version to replace the old one. That will happen provided the name (the doc string) remains unchanged.

What if the fact doesn't have a name? (They're not required.) Will loading changed versions lead to many variants cluttering up the compendium? Not if you work in two steps:

  1. Redefine the fact by giving it a name. That redefinition will replace the old one because the check for redefinition works on the body of the fact, which does not include its metadata.
  2. Now that the fact has a stable name, change the body.

The individual functions

This section describes how the individual functions vary from the description above. See their doc strings for self-contained descriptions.

load-facts: move facts from disk into the compendium

load-facts can take wildcard arguments, unlike all the other functions: prog.util.*.

When load-facts is given no arguments, it repeats the working set of the previous load-facts. That is, its working set is not affected by commands like (check-facts).

Before loading new namespaces, load-facts clears them from the compendium. It leaves unmentioned namespaces alone.

check-facts: check compendium facts

When check-facts is given no arguments, it repeats the working set of the previous load-facts, check-facts, or `fetch-facts. (This is the normal behavior.)

fetch-facts: fetch, but do not execute, compendium facts

A sequence of facts is returned. They may be checked with check-one-fact. Otherwise, this behaves exactly like check-facts.

forget-facts: forget facts in the compendium

Forget facts does not change the working set. So, you can do the following:

user=> (load-facts 'proj.util.*)
...
# try some on-the-fly facts:
user=> (fact ...)
# get rid of all the facts cluttering up the compendium
user=> (forget-facts :all)
# redo the original `load-facts`
user=> (load-facts)

last-fact-checked: return whichever fact was last checked.

user=> (fact "fred" 1 => 1)
true
user=> (:midje/name (meta (last-fact-checked)))
"fred"

recheck-fact: recheck the last fact checked

The same as (check-one-fact (last-fact-checked)), but with a little additional verbiage:

user=> (recheck-fact)
All claims (1) have been confirmed.
true

source-of-last-fact-checked

The same as (:midje/source (meta (last-fact-checked))).

user=> (source-of-last-fact-checked)
(fact "fred" 1 => 1)
Clone this wiki locally