-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Oposite of try-all: try-all-failed and similar #36
Comments
Currently I do things like this: (ns user
(:require
[clojure.string :as str]
[failjure.core :as f])
(:import (java.time Duration)
(java.time.format DateTimeParseException)))
(defn try-parse-duration
"Try to parse a duration.
Return duration on success.
Return a Failure on exception."
[duration]
(f/try*
(Duration/parse duration)))
(defn parse-duration
"Parse a duration from string.
Return a ^java.lang.Duration on success.
Retun nil when string is blank or empty.
Throw exception on parse failure."
;;TODO: Attempt to accept go time.Duration string format.
[duration-str]
(f/when-let-failed?
[_duration (try-parse-duration duration-str)]
(f/when-let-failed?
[_duration (try-parse-duration (str "PT" duration-str))]
(f/when-let-failed?
[_duration (try-parse-duration (str "P" duration-str))]
(f/fail "Failed to parse duration %s" duration-str)))))
^:rct/test
(comment
(parse-duration nil)
;; => #failjure.core.Failure{:message "Failed to parse duration null"}
(parse-duration "")
;; => #failjure.core.Failure{:message "Failed to parse duration "}
(parse-duration "P")
;; => #failjure.core.Failure{:message "Failed to parse duration P"}
(parse-duration "1")
;; => #failjure.core.Failure{:message "Failed to parse duration 1"}
(parse-duration "1s")
;; => #object[java.time.Duration 0x586eb169 "PT1S"]
(parse-duration "1d")
;; => #object[java.time.Duration 0x7f2e8c60 "PT24H"]
(parse-duration "5d")
;; => #object[java.time.Duration 0x439b8dd9 "PT120H"]
(parse-duration "PT8760h0m0s")
;; => #object[java.time.Duration 0x7879db38 "PT8760H"]
) |
I managed to get the same behavior using filter and f/ok? (defn parse-duration
"Parse a duration from string.
Return a ^java.lang.Duration on success.
Retun nil when string is blank or empty.
Throw exception on parse failure."
[duration-str]
(let [duration-tries [duration-str
(str "PT" duration-str)
(str "P" duration-str)]
duration (filter f/ok? (map try-parse-duration duration-tries))]
(if (empty? duration)
(f/fail "Failed to parse duration %s" duration-str)
(first duration))) |
As an optimization, you can stop at the first success with (defn f/try-any [f xs]
(reduce
(fn [_ x] (f/attempt reduced (f x)))
xs)) |
hi, @ieugen you'll probably find this one interesting: (defn some-ok
"Like `clojure.core/some`, but returns the first non-failed value
of (pred x) for any x in coll, else the final Failure.
Usage:
(some-ok #(if (odd? %)
%
(fail \"no odds\"))
[2 4 8])"
{:added "2.3"}
[pred coll]
(when-let-ok? [s (seq coll)]
(or (pred (first s)) (recur pred (next s))))) I thought about posting a PR with it a while back, but wasn't sure if it was needed upstream. CC @adambard what do you think? With it, you can rewrite parse-duration as (defn parse-duration
[duration-str]
(let [duration-tries [duration-str
(str "PT" duration-str)
(str "P" duration-str)]]
(f/some-ok try-parse-duration duration-tries))) As a nice side effect, it returns an exception object on failure, so you get all your stacktraces, as mentioned in #37. Another function that I find useful is (defn ex->failure
[ex]
(let [data (ex-data ex)
cause (ex-cause ex)
msg (ex-message ex)]
(cond-> (fail msg)
data (assoc :data data)
cause (assoc :cause cause)))) It doesn't support stacktraces (mostly to simplify the code), but adds cause and ex-info data to the failure object. It's probably worth adding to failjure as well, but I'm not sure |
Thanks. IMO Clojure does not seem to have a good solution for this type of programming where you check for failure at every step. |
If clojure.core doesn't have it - just implement it yourself, I don't see a problem here :) |
I think
try-all-failed
and similar might also be useful.I am trying to parse some input from user (a time Duration) and trying to be forgiving.
In my case I need to try out all options and stop when I get a non-failure.
So my algorithm is :
I think code would look like this:
(beginner with Failjure, code might not be correct)
Some context
https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html#parse-java.lang.CharSequence-
The text was updated successfully, but these errors were encountered: