{"id":22039282,"url":"https://github.com/scgilardi/slingshot","last_synced_at":"2025-05-15T05:05:37.533Z","repository":{"id":61593636,"uuid":"1888836","full_name":"scgilardi/slingshot","owner":"scgilardi","description":"Enhanced try and throw for Clojure leveraging Clojure's capabilities","archived":false,"fork":false,"pushed_at":"2019-10-21T14:06:32.000Z","size":403,"stargazers_count":655,"open_issues_count":13,"forks_count":28,"subscribers_count":22,"default_branch":"release","last_synced_at":"2025-05-03T07:48:20.974Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/scgilardi.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-06-13T13:35:20.000Z","updated_at":"2025-04-05T22:49:27.000Z","dependencies_parsed_at":"2022-10-19T15:30:40.501Z","dependency_job_id":null,"html_url":"https://github.com/scgilardi/slingshot","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scgilardi%2Fslingshot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scgilardi%2Fslingshot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scgilardi%2Fslingshot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scgilardi%2Fslingshot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/scgilardi","download_url":"https://codeload.github.com/scgilardi/slingshot/tar.gz/refs/heads/release","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254077107,"owners_count":22010665,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-30T11:10:11.084Z","updated_at":"2025-05-15T05:05:37.513Z","avatar_url":"https://github.com/scgilardi.png","language":"Clojure","funding_links":[],"categories":["Miscellaneous","\u003ca name=\"Clojure\"\u003e\u003c/a\u003eClojure"],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/scgilardi/slingshot.svg?branch=master)](https://travis-ci.org/scgilardi/slingshot) [![Dependency Status](https://www.versioneye.com/user/projects/54d57a7b3ca0840b1900063a/badge.svg?style=flat)](https://www.versioneye.com/user/projects/54d57a7b3ca0840b1900063a)\n\nslingshot\n=========\n\nEnhanced throw and catch for Clojure\n------------------------------------\n\n  Provides `try+` and `throw+`. Each is 100% compatible with Clojure\n  and Java's native `try` and `throw` both in source code and at\n  runtime. Each also provides additional capabilities intended to\n  improve ease of use by leveraging Clojure's features like maps,\n  records, and destructuring.\n\n  Clojure's native `try` and `throw` behave much like those of Java:\n  throw can accept objects derived from java.lang.Throwable and `try`\n  selects from among catch clauses based on the class of the thrown\n  object.\n\n  In addition to fully supporting those uses (whether they originate\n  from Clojure code or from Java code via interop), `try+` and\n  `throw+` provide these enhanced capabilities:\n\n  - `throw+` can throw any Java object, not just those whose class is\n    derived from `java.lang.Throwable`.\n\n    Clojure maps or records become an easy way to represent custom\n    exceptions without requiring `gen-class`.\n\n  - `catch` clauses within `try+` can catch:\n    - any Java object thrown by `throw+`,\n    - any map passed to `ex-info` and thrown by `throw` or `throw+`, or\n    - any `Throwable` thrown by Clojure's `throw`, or Java's `throw`.\n\n    The first catch clause whose **selector** matches the thrown\n    object will execute.\n\n    a selector can be:\n\n    - a **class name**: (e.g., `RuntimeException`, `my.clojure.record`),\n      matches any instance of that class, or\n\n    - a **key-values** vector: (e.g., `[key val \u0026 kvs]`), matches\n      objects where `(and (= (get object key) val) ...)`, or\n\n    - a **predicate**: (function of one argument like `map?`, `set?`),\n      matches any Object for which the predicate returns a truthy\n      value, or\n\n    - a **selector form**: a form containing one or more instances of\n      `%` to be replaced by the thrown object, matches any object for\n      which the form evaluates to truthy.\n\n    - the class name, key-values, and predicate selectors are\n      shorthand for these selector forms:\n\n          `\u003cclass name\u003e  =\u003e (instance? \u003cclass name\u003e %)`\n\n          `[\u003ckey\u003e \u003cval\u003e \u0026 \u003ckvs\u003e] =\u003e (and (= (get % \u003ckey\u003e) \u003cval\u003e) ...)`\n\n          `\u003cpredicate\u003e   =\u003e (\u003cpredicate\u003e %)`\n\n  - the binding to the caught exception in a catch clause is not\n    required to be a simple symbol. It is subject to destructuring so\n    the body of the catch clause can use the contents of a thrown\n    collection easily.\n\n  - in a catch clause, the context at the throw site is accessible via\n    the hidden argument `\u0026throw-context`.\n\n  - `\u0026throw-context` is a map containing:\n\n    for Throwable caught objects:\n\n        :object       the caught object;\n        :message      the message, from .getMessage;\n        :cause        the cause, from .getCause;\n        :stack-trace  the stack trace, from .getStackTrace;\n        :throwable    the caught object;\n\n    for non-Throwable caught objects (including maps passed to ex-info)\n\n        :object       the caught object;\n        :message      the message, from throw+ or ex-info;\n        :cause        the cause, from throw+ or ex-info, see below;\n        :stack-trace  the stack trace, captured by throw+ or ex-info;\n        :wrapper      the Throwable wrapper that carried the object;\n        :throwable    the outermost Throwable whose cause chain contains\n                      the wrapper, see below.\n\n  To throw a non-`Throwable` object, `throw+` wraps it in a\n  `Throwable` wrapper by calling `ex-info`. Every instance of\n  `IExceptionInfo` (whether generated by throw+ or by a direct call to\n  `ex-info`) is treated as a wrapper.\n\n  The wrapper is available via the `:wrapper` key in `\u0026throw-context`.\n\n  Between being thrown and caught, a wrapper may be further wrapped by\n  other Exceptions (e.g., instances of `RuntimeException` or\n  `java.util.concurrent.ExecutionException`). `try+` sees through all\n  such wrappers to find the thrown object. The outermost wrapper is\n  available within a catch clause a via the `:throwable` key in\n  `\u0026throw-context`.\n\n  When `throw+` throws a non-`Throwable` object from within a `try+`\n  catch clause, the outermost wrapper of the caught object being\n  processed is captured as the cause of the new `throw+`. This can be\n  overridden by providing an explicit `cause` argument to `throw+`.\n\n  - an optional `else` clause may appear after all `catch` clauses and\n    before any `finally` clause. Its contents will be executed (for\n    side effects) immediately after the code in the `try+` body\n    completes only if nothing was thrown.\n\nUsage\n-----\n\nproject.clj\n\n[![Clojars Project](http://clojars.org/slingshot/latest-version.svg)](http://clojars.org/slingshot)\n\ntensor/parse.clj\n\n```clojure\n(ns tensor.parse\n  (:use [slingshot.slingshot :only [throw+]]))\n\n(defn parse-tree [tree hint]\n  (if (bad-tree? tree)\n    (throw+ {:type ::bad-tree :tree tree :hint hint})\n    (parse-good-tree tree hint)))\n```\n\nmath/expression.clj\n\n```clojure\n(ns math.expression\n  (:require [tensor.parse]\n            [clojure.tools.logging :as log])\n  (:use [slingshot.slingshot :only [throw+ try+]]))\n\n(defn read-file [file]\n  (try+\n    [...]\n    (tensor.parse/parse-tree tree)\n    [...]\n    (catch [:type :tensor.parse/bad-tree] {:keys [tree hint]}\n      (log/error \"failed to parse tensor\" tree \"with hint\" hint)\n      (throw+))\n    (catch Object _\n      (log/error (:throwable \u0026throw-context) \"unexpected error\")\n      (throw+))))\n```\n\nCredits\n-------\n\n  Based on clojure.contrib.condition, data-conveying-exception,\n  discussions on the clojure mailing list and wiki and discussions and\n  implementations by Steve Gilardi, Phil Hagelberg, and Kevin Downey.\n  \nStatus\n-------\n\n  2019-10-21 Based on a recent request from a slingshot user, I am now\n  working toward a 1.0 release, evaluating and discussing existing issues\n  and PRs. Thank you for the continued interest. I'm particularly happy\n  to see the cljs support and look forward to integrating that.\n\n\nLicense\n-------\n\n  Copyright \u0026copy; 2011-2019 Stephen C. Gilardi, Kevin Downey, and\n  Phil Hagelberg\n\n  Distributed under the Eclipse Public License, the same as Clojure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscgilardi%2Fslingshot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fscgilardi%2Fslingshot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscgilardi%2Fslingshot/lists"}