Giter Club home page Giter Club logo

dire's Introduction

dire

Decomplect error logic. Error handling, pre/post conditions and general hooks for Clojure functions.

Ships with two flavors:

  1. The drop-in style, using functions ending in '!'
  2. Erlang-style inspired by the work of Joe Armstrong using a supervisor

Installation

Available on Clojars:

[dire "0.4.2"]

API

Check out the Codox API docs here.

Relevant Blog Posts

Evaluation Order

  1. Eager Prehooks
  2. Preconditions
  3. Prehooks
  4. The target function
  5. Exception handlers
  6. Postconditions
  7. Finally clause

Usage: Drop-in Flavor

Simple Example

(ns mytask
  (:require [dire.core :refer [with-handler!]]))

;;; Define a task to run. It's just a function.
(defn divider [a b]
  (/ a b))

;;; For a task, specify an exception that can be raised and a function to deal with it.
(with-handler! #'divider
  "Here's an optional docstring about the handler."
  java.lang.ArithmeticException
  ;;; 'e' is the exception object, 'args' are the original arguments to the task.
  (fn [e & args] (println "Cannot divide by 0.")))

(divider 10 0) ; => "Cannot divide by 0."

Try/Catch/Finally Semantics

(ns mytask
  (:require [dire.core :refer [with-handler! with-finally!]]))

;;; Define a task to run. It's just a function.
(defn divider [a b]
  (/ a b))

(with-handler! #'divider
  java.lang.ArithmeticException
  (fn [e & args] (println "Catching the exception.")))

(with-finally! #'divider
  "An optional docstring about the finally function."
  (fn [& args] (println "Executing a finally clause.")))

(divider 10 0) ; => "Catching the exception.\nExecuting a finally clause.\n"

Preconditions

(ns mytask
  (:require [dire.core :refer [with-precondition! with-handler!]]))

(defn add-one [n]
  (inc n))

(with-precondition! #'add-one
  "An optional docstring."
  ;;; Name of the precondition
  :not-two
  (fn [n & args]
    (not= n 2)))
    
(with-handler! #'add-one
  {:precondition :not-two}
  (fn [e & args] (apply str "Precondition failure for argument list: " (vector args))))

(add-one 2) ; => "Precondition failure for argument list: (2)"

Postconditions

(ns mytask
  (:require [dire.core :refer [with-postcondition! with-handler!]]))

(defn add-one [n]
  (inc n))

(with-postcondition! #'add-one
  "An optional docstring."
  ;;; Name of the postcondition
  :not-two
  (fn [n & args]
    (not= n 2)))
    
(with-handler! #'add-one
  {:postcondition :not-two}
  (fn [e result] (str "Postcondition failed for result: " result)))

(add-one 1) ; => "Precondition failure for reault: (2)"

Pre-hooks

(ns mydire.prehook
  (:require [dire.core :refer [with-pre-hook!]]))

(defn times [a b]
  (* a b))

(with-pre-hook! #'times
  "An optional docstring."
  (fn [a b] (println "Logging something interesting.")))

(times 21 2) ; => "Logging something interesting."

Eager Pre-hooks

(ns mydire.prehook
  (:require [dire.core :refer [with-eager-pre-hook!]]))

(defn times [a b]
  (* a b))

(with-eager-pre-hook! #'times
  "An optional docstring."
  (fn [a b] (println "Logging something before preconditions are evaluated.")))

(times 21 2) ; => "Logging something before preconditions are evaluated."

Usage: Erlang Style with supervise

Simple Example

(ns mytask
  (:require [dire.core :refer [with-handler supervise]]))

;;; Define a task to run. It's just a function.
(defn divider [a b]
  (/ a b))

;;; For a task, specify an exception that can be raised and a function to deal with it.
(with-handler #'divider
  "An optional docstring."
  java.lang.ArithmeticException
  ;;; 'e' is the exception object, 'args' are the original arguments to the task.
  (fn [e & args] (println "Cannot divide by 0.")))

(with-handler #'divider
  java.lang.NullPointerException
  (fn [e & args] (println "Ah! A Null Pointer Exception! Do something here!")))

;;; Invoke with the task name and it's arguments.
(supervise #'divider 10 0)   ; => "Cannot divide by 0."
(supervise #'divider 10 nil) ; => "Ah! A Null Pointer Exception! Do something here!"

Self-Correcting Error Handling

(ns mytask
  (:require [dire.core :refer [with-handler supervise]]
            [fs.core :refer [touch]]))

(defn read-file [file-name]
  (slurp file-name))

(with-handler #'read-file
  java.io.FileNotFoundException
  (fn [exception file-name & _]
    (touch file-name)
    (supervise #'read-file file-name)))

(supervise #'read-file "my-file")

Try/Catch/Finally Semantics

(defn add-one [n]
  (inc n))

(with-handler #'add-one
  java.lang.NullPointerException
  (fn [e & args] (println "Catching the exception.")))

(with-finally #'add-one
  (fn [& args] (println "Executing a finally clause.")))

(with-out-str (supervise #'add-one nil)) ; => "Catching the exception.\nExecuting a finally clause.\n"

Preconditions

(defn add-one [n]
  (inc n))

(with-precondition #'add-one
  ;;; Name of the precondition
  :not-two
  (fn [n & args]
    (not= n 2)))

(with-handler #'add-one
  ;;; Pair of exception-type (:precondition) to the actual precondition (:not-two)
  {:precondition :not-two}
  (fn [e & args] (apply str "Precondition failure for argument list: " (vector args))))

(supervise #'add-one 2) ; => "Precondition failure for argument list: (2)"

Postconditions

(defn add-one [n]
  (inc n))

(with-postcondition #'add-one
  :not-two
  (fn [n & args]
    (not= n 2)))

(with-handler #'add-one
  {:postcondition :not-two}
  (fn [e result] (str "Postcondition failed for result: " result)))

(supervise #'add-one 1) ; => "Postcondition failed for result: 2"

Pre-hooks

(defn times [a b]
  (* a b))

(with-pre-hook #'times
  (fn [a b] (println "Logging something interesting."))

(supervise #'times 1 2) ; => "Logging something interesting.", 2

Eager Pre-hooks

(defn times [a b]
  (* a b))

(with-eager-pre-hook #'times
  "An optional docstring."
  (fn [a b] (println "Logging something before preconditions are evaluated.")))

(supervise #'times 21 2) ; => "Logging something before preconditions are evaluated."

Etc

  • If an exception is raised that has no handler, it will be raised up the stack like normal.
  • Multiple pre-hooks evaluate in arbitrary order.
  • There's no with-post-hook. You have with-finally for that.

Contributors

License

Copyright © 2012 Michael Drogalis

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

dire's People

Contributors

edlich avatar thinkeden avatar

Watchers

ken restivo avatar James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.