Recide、二人目の特異な現在のrecidereの命令: - フォールバックするには、無駄になります。削減する
assoc / RECIDE ERRORSのEx-DATAへのupdatedeferrordeferror-groupgetCurrentSanitizationLevel()createSuppressionMap(...)sanitize(Throwable) 、 sanitize(Throwable, IPersistentMap)ErrorFormClojureのex-infoは非常に便利な構成要素です。任意のデータのマップをスローされた例外に添付することができ、例外をキャッチしたコードがこのex-dataを調べ、ログ、または処理することを可能にします。
たとえば、 assertステートメントはビジネスロジックに貴重な正気チェックを提供しますが、失敗すると、どのように失敗したかを知ることは通常非常に望ましいことです。この情報を例外文字列に挿入しようとすることもできますが、関連するデータが非常に大きすぎる場合があります。代わりに、希望のプロパティをチェックし、関連するすべてのデータを添付したex-infoをスローすることで、特にREPLでデバッグするときに、開発者に膨大な時間を節約しながら、エラーメッセージの簡潔さを維持できます。
ex-infoの主な弱点の1つは、その使用が標準のないアドホックの例外を促進できることです。ex-INFOをキャッチすると、そのタイプは他のすべてのex-infosと同じであり、その文字列は任意であり、 ex-dataに表示される特定のキーを頼りにすることができない場合のみ、マップが完全に空である可能性は十分にあります。
大規模なプロジェクトでex-info広く使用することのメリットを享受したい場合は、保持したい場合も正気の尺度明確に定義されたエラーの利点は、普遍的なClojureイディオムを破るか、 ex-info使用する「スロー機能」の標準セットを定義する独自の定義のいずれかで、アプリケーションの各論理コンポーネントに最終的に頼る可能性があります。 ex-infoですが、特定の剛性を保証します。おそらく、例外文字列の一般的な接頭辞、おそらくex-dataマップの特定の保証キーです。
このライブラリの主な目的であるRecideは、このプロセスを容易にするツールを提供することです。標準のEX-INFOフォームを定義するためのユーティリティと、コンパイル時間で使用されているとおりに使用されていることを確認する能力を提供します。
recideのツールによって生成されたすべてのex-infoマップには、少なくとも2つのキーが含まれています。
:recide/error 。その値はErrorFormのインスタンスです。ErrorFormで定義された「タイプキー」(Recideのデフォルトは:recide/type )です。 Clojure APIドキュメントはこちらをご覧ください。 Java APIドキュメントはこちらをご覧ください。
recide.core/insist assertに類似しています。その署名は同じであり、 assertのように、 clojure.core/*assert*がTrueの場合にのみ実行されます。
しかし、 AssertionErrorを投げる代わりに、フォームの説明文字列を使用してex-info投げます。 ex-dataのタイプは:recide/assertionです。 insistことによって使用される他の2つのキーがあります。
:expression 、その価値はinsistに含まれる実際の表現です:values 。その値は、失敗時に式で使用される各変数からのマップです。 :values recide.impl/*capture-insists*が真である場合にのみ存在しますが、デフォルトでは誤りです。ライブラリの読み込み時に、少なくとも次のうち1つが真である場合、それは真実に設定されています。
insistの署名は[[expr] [expr message]]であり、結果のEx-infoのex-dataには次の形式があります。
{ :recide/type :recide/assertion ,
:expression <expr>
:values { ... }}使用している例:
( let [y not
x true ]
( insist ( y x)))
; ; Unhandled clojure.lang.ExceptionInfo
; ; Assertion failed: (y x)
; ; {:expression (y x),
; ; :values {y #function[clojure.core/not],
; ; x true},
; ; :recide/type :recide/assertion} recide.core/errorには2つのアリティがあります: ([type msg data] [type msg data cause]) 。 error 、MAP dataが添付されたex-infoを構築します。そのタイプ(繰り返しますが、デフォルトで:recide/type )がtypeです。 causeは、Java Idiomによると、例外に原因を単に与えるだけです。
( let [x " not b! haha " ]
( raise :my-type
" my explanation! "
{ :a " a "
:b x}))
; ; #error {
; ; :cause "my explanation!"
; ; :data {:a "a",
; ; :b "not b! haha",
; ; :recide/type :my-type, :recide/error #object[...]}
; ; :via
; ; [{:type clojure.lang.ExceptionInfo
; ; :message "my explanation!"
; ; :data {:a "a",
; ; :b "not b! haha",
; ; :recide/type :my-type, :recide/error #object[...]}
; ; :at [clojure.core$ex_info invokeStatic "core.clj" 4725]}]
; ; :trace ... } recide.core/raise同じ2つのアリティがあります。 raiseスローは、 errorによって作成された例外をスローします。
assoc / RECIDE ERRORSのEx-DATAへのupdate利便性関数: recide.core/assoc-errorおよびassoc update recide.core/update-error各元のタイプの新しい例外を返します。
エラーを元に戻してスローする前に、エラーのマップ表現を渡して操作するのが便利な場合があります。この目的のために、 recide.core/error->map and recide.core/error-map->throwableがあります。
さらに、マップフォームを返すエラーと、対応する述語error-map?場合の代替error-map 「コンストラクター」を提供しますか? 。
メッセージmsg 、ex-data data 、およびcauseのあるタイプtypeのエラーの場合、永続的なマップは次のようになります。
{ :recide/error <ErrorForm>,
:recide/type type,
:recide/msg msg,
:recide/cause cause,
:recide/data data}これらのすべてのキーを除く:recide/error 、カスタマイズされたErrorFormを提供することで変更できます(詳細については以下を参照)。
raiseとerror標準の例外タイプを提供するためにほとんど何もしません。これにさらに対処するために、Recideはdeferrorおよびdeferror-group提供します。
deferror deferrorは、エラー名、タイプ、およびこのタイプのすべてのエラーのメッセージに接頭する「一般的な」文字列を撮影するマクロです。また、オプションで、必要なキーのコレクションを採用します。必要なキーが指定されている場合、コンパイル時間エラーは、ソースコードで明示的にこれらのキーを指定せずにdeferrorによって定義されたツールが使用されるときにいつでもスローされます。
使用例:
( deferror storage-timeout
:storage/timeout
" A storage operation timed out "
[ :method-at-fault :timeout-ms ])この例では、このdeferrorへの呼び出しは、 storage-timeoutとraise-storage-timeout 2つの新しいマクロを定義します。あなたの便利さのために、有能なIDEは、これらの新しいVARの詳細なドキュメントにアクセスできます。
> ( clojure.repl/doc storage-timeout)
; ; -------------------------
; ; my-ns/storage-timeout
; ; [[detail-str data] [detail-str data cause]]
; ; Macro
; ; Records this raise-site under :storage/timeout in recide, and expands into the equivalent of:
; ;
; ; (ex-info (str "A storage operation timed out: " detail-str)
; ; (assoc data :recide/type :storage/timeout)
; ; cause)
; ;
; ; The following keys are required in the data-map:
; ; #{:method-at-fault,
; ; :timeout-ms}
> ( clojure.repl/doc raise-storage-timeout)
; ; -------------------------
; ; [[detail-str data] [detail-str data cause]]
; ; Macro
; ; Records this raise-site under :storage/timeout in recide, and expands into:
; ;
; ; (raise :storage/timeout
; ; (str "A storage operation timed out: " detail-str)
; ; data
; ; cause)
; ;
; ; The following keys are required in the data-map:
; ; #{:method-at-fault,
; ; :timeout-ms}これらのいずれかをデータマップで使用しようとすると、必要な各キーを指定しようとすると、Clojureコンパイラが例外をスローします。
> ( raise-storage-timeout " blah " { :method-at-fault 'not-really-a-method})
; ; Unhandled clojure.lang.ExceptionInfo
; ; Assertion failed: storage-timeout requires the following missing
; ; keys in its data: :timeout-msdeferror-group deferror-groupエラーの家族全員を定義するマクロです。エラー名、ベースタイプの宣言、およびいくつかのサブタイプ宣言が必要です。
各ベースタイプの宣言は、このエラーグループの共通名前空間を表すキーワードであるか、最初の要素がそのようなキーワードであり、2番目の要素が必要なキーのシーケンスであるタプルでなければなりません。ここで指定されているキーは、すべてのサブタイプで必要です。
各サブタイプ宣言は、最初の用語がシンボルであるシーケンスで構成され、第2用語はエラーの汎用文字列であり、3番目(オプション)項はそのサブタイプに必要なキーのシーケンスです。
例:
( deferror-group parse-err
( :query.invalid [ :expression ])
( find-spec " Invalid find spec " )
( inputs " Invalid inputs " [ :invalid ]))この例では、定義された2つのエラータイプがあります。 :query.invalid/find-specおよび:query.invalid/inputs 。 1つ目は次のとおりです。データマップでの:expressionですが、2番目は:expressionと:invalid両方を必要とします。
deferrorと同様に、 deferror-groupによって生成されたユーティリティには詳細なドキュストリングがあります。
> ( clojure.repl/doc parse-err)
; ; -------------------------
; ; recide/parse-err
; ; [[subtype detail-str data] [subtype detail-str data cause]]
; ; Macro
; ; Records this raise-site under :query.invalid/<subtype> in recide, and expands into the
; ; equivalent of:
; ;
; ; (ex-info (str "<subtype-generic-str>: " detail-str)
; ; (assoc data
; ; :recide/type
; ; :query.invalid/<subtype>)
; ; cause)
; ;
; ; The following map shows, for each subtype, what keywords are required in
; ; the data map, and what the generic portion of the string will be:
; ;
; ; {:find-spec {:required #{:expression},
; ; :generic-str "Invalid find spec"},
; ; :inputs {:required #{:expression :invalid},
; ; :generic-str "Invalid inputs"}}
> ( clojure.repl/doc raise-parse-err)
; ; -------------------------
; ; recide/raise-parse-err
; ; [[subtype detail-str data] [subtype detail-str data cause]]
; ; Macro
; ; Records this raise-site under :query.invalid/<subtype> in recide, and expands into:
; ;
; ; (raise :query.invalid/<subtype>
; ; (str "<subtype-generic-str>: " detail-str)
; ; data
; ; cause)
; ;
; ; The following map shows, for each subtype, what keywords are required in
; ; the data map, and what the generic portion of the string will be:
; ;
; ; {:find-spec {:required #{:expression},
; ; :generic-str "Invalid find spec"},
; ; :inputs {:required #{:expression :invalid},
; ; :generic-str "Invalid inputs"}}前に見たように、必要なキーは省略されたときにコンパイル時間エラーを生成します。
> ( raise-parse-err :inputs " detailed this, detailed that " { :expression nil })
; ; Unhandled clojure.lang.ExceptionInfo
; ; Assertion failed: parse-err called with subtype :inputs requires
; ; the following missing keys in its data: :invalid キーワードを使用してエラータイプを指定している場合、これらのキーワードを使用してエラーをcatchできると便利です。 Recideはこの目的のためにtry*を提供します。 try*は、Clojureのtryに拡張されるマクロです。これは、Clojureの数少ない特別な形式の1つです。ほとんどの場合、 try* tryてみてください。拡張されたcatch機能を公開するという点で異なります。キャッチできます:
instance?チェック。ErrorFormに関係なく)recide.core/try*
[( try* expr* catch-clause* finally-clause?)]
Macro
Expands to Clojure's try Special Form, allowing for enhanced `catch` clauses:
You can catch:
* Classes/Interfaces ( represents an instance? check)
`( catch RuntimeException e ...)`
* keywords ( recide error types ; fully-qualified: :namspace/name, wildcard: :namespace/*)
`( catch :library/error e ...)`
* arbitrary predicates
`( catch bad-error? e ...)`
You can also catch conjunctions/disjunctions of these:
* conjunction
`( catch :and [RuntimeException :library/error bad-error?] e ...)`
* disjunction
`( catch :or [IllegalArgumentException :library/error bad-error?] e ...)`
You can also negate each of these:
`( catch ( :not RuntimeException) e ...)`
`( catch :and [( :not RuntimeException) :library/* ] e ...)`
Otherwise, behavior should match 'normal' catch clauses in `clojure.core/try`.フォームのキーワードを使用できることに注意してください:namespace/* 、 deferror-groupで定義されているものなど、再生エラーのファミリーをキャッチするためのワイルドカードとして使用できます。
> ( try* ( raise :genus/species-1
" went extinct "
{ :year -1839421 })
( catch :genus/* e
( println ( :year ( ex-data e)))))
; ; -1839421 Recideは、ログを安全に検討する必要がある(ただし、結果として役に立たない場合がある)と考えられる例外バージョンを取得するためのツールのコレクションを提供します。
このクラスには、一握りの静的ユーティリティ方法が含まれています。
getCurrentSanitizationLevel() Deref'ing recide.sanex/*sanitization-level*に相当します。
createSuppressionMap(...)ブールアラウンドに対応する適切なキーワードを使用して、IPERSISTENTMAPを作成します。
sanitize(Throwable) 、 sanitize(Throwable, IPersistentMap) Clojure IFN recide.sanex/sanitizeへのショートカット。
ErrorFormデフォルトでは、このライブラリによって提起されたエラーは、 ex-infoをコンストラクター、 recide.utils/serialize-throwable :recide/msg recide.utils/deserialize-throwable (de)serialization、およびMap形式で使用します:recide/type :recide/msg 、 :recide/data 、および:recide/cause 。
新しいErrorFormを定義することにより、この動作をすべて独自のライブラリに変更できます。キーワードを変更することにより、ライブラリから「ブランド」エラーが発生する可能性があります。 IExceptionInfoを返すと予想される、同じarityの別のコンストラクターにex-info交換できます。たとえば、Java Interopに関連する懸念は、新しい例外クラスの作成をやる気にさせる可能性がありますが、Clojure Idiomsは元のINFOの互換性を維持する動機付けになる可能性があります。
recide.core/def-error-formでカスタマイズを簡単に定義でき、オーバーライドする方法のみをオーバーライドできます。指定されていないメソッドはデフォルトでライブラリのデフォルトを再生するためにデフォルトです。
recide.coreのエラー処理方法は、使用される特定のErrorFormに不可知論されます。カスタムErrorFormを使用してエラーを作成するには、 recide.core/generate-library!を使用してカスタマイズに特化した一連のRecideメソッドを簡単に生成できます。 。
( ns my-library.error
( :require [recide.core :as rc]))
( rc/def-error-form custom-error-form
( type-kw [_] :my-library/type )
( constructor [_] my-library/error-constructor)
; ; all other methods are filled out with recide defaults.
( def ^:dynamic *capture-insists?* true )
( rc/generate-library! custom-error-form *capture-insists?*)
; ; recide.core/generate-library!
; ; [custom-error capture-flag]
; ; Macro
; ; Generates and defs custom versions of the following recide.core methods, tailored specifically
; ; to custom-error, with variable capture in the generated insist subject to capture-flag.
; ; * error
; ; * error?
; ; * error-map
; ; * error-map?
; ; * throwable->error-map
; ; * raise
; ; * insist
; ; * deferror
; ; * deferror-group
; ;
; ; custom-error should be an instance of recide.error/ErrorForm (see def-error-form).
; ; capture-flag must be resolvable to a dynamic var.