Skip to content

implementation of option to blacklist rules when creating sessions. #445

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ Community
[@dgoeke]: https://github.com/dgoeke
[@sparkofreason]: https://github.com/sparkofreason
[@bfontaine]: https://github.com/bfontaine
[@sunilgunisetty]: https://github.com/sunilgunisetty
[@sunilgunisetty]: https://github.com/sunilgunisetty
[@bartuka]: https://github.com/wandersoncferreira
4 changes: 3 additions & 1 deletion src/main/clojure/clara/rules.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@
information might prove useful for debugging compilation errors within the rulebase, eg. rulebase serialization
(ie. via Clara's durability support).
Defaults to true, see clara.rules.compiler/omit-compile-ctx-default for more information.
* :blacklist, a vector of qualified namespace rules that will be blacklisted from the created session.
Defaults to [], all the rules provided will be considered.

This is not supported in ClojureScript, since it requires eval to dynamically build a session. ClojureScript
users must use pre-defined rule sessions using defsession."
Expand Down Expand Up @@ -425,4 +427,4 @@ See the [query authoring documentation](http://www.clara-rules.org/docs/queries/
(map first) ; Take the symbols for the rule/query vars
)]
(doseq [psym production-syms]
(ns-unmap *ns* psym))))))
(ns-unmap *ns* psym))))))
9 changes: 9 additions & 0 deletions src/main/clojure/clara/rules/compiler.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2036,6 +2036,14 @@
(vary-meta production assoc ::rule-load-order (or n 0)))
(range) productions))


(defn remove-blacklisted-rules
"If an option :blacklist was provided by the user, we filter out the rules indicated."
[options rules]
(let [blacklist (set (map str (:blacklist options)))
not-contains? (complement contains?)]
(filter #(not-contains? blacklist (:name %)) rules)))

(defn mk-session
"Creates a new session using the given rule source. The resulting session
is immutable, and can be used with insert, retract, fire-rules, and query functions."
Expand All @@ -2047,6 +2055,7 @@
(mapcat #(if (satisfies? IRuleSource %)
(load-rules %)
%))
(remove-blacklisted-rules options)
add-production-load-order
;; Ensure that we choose the earliest occurrence of a rule for the purpose of rule order.
;; There are Clojure core functions for distinctness, of course, but none of them seem to guarantee
Expand Down
107 changes: 107 additions & 0 deletions src/test/common/clara/test_blacklist.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#?(:clj
(ns clara.test-blacklist
(:require [clara.tools.testing-utils :refer [def-rules-test] :as tu]
[clara.rules :refer [fire-rules
insert
insert!
query]]

[clara.rules.testfacts :refer [->Temperature
->Cold
->Hot
->TemperatureHistory
->ColdAndWindy]]
[clojure.test :refer [is]]
[clara.rules.accumulators])
(:import [clara.rules.testfacts
Temperature
Cold
Hot
ColdAndWindy
TemperatureHistory]))

:cljs
(ns clara.test-blacklist
(:require [clara.rules :refer [fire-rules
insert
insert!
query]]
[clara.rules.testfacts :refer [->Temperature Temperature
->Cold Cold
->Hot Hot
->ColdAndWindy ColdAndWindy
->TemperatureHistory TemperatureHistory]]
[clara.rules.accumulators]
[cljs.test])
(:require-macros [clara.tools.testing-utils :refer [def-rules-test]]
[cljs.test :refer [is]])))

(def-rules-test test-blacklist-a-rule
{:rules [cold-rule [[[Temperature (< temperature 20) (= ?t temperature)]]
(insert! (->Cold ?t))]
history-rule [[[Temperature (< temperature 20) (= ?t temperature)]]
(insert! (->TemperatureHistory [?t]))]]

:queries [cold-query [[] [[Cold (= ?c temperature)]]]
history-query [[] [[TemperatureHistory (= ?t temperatures)]]]]

:sessions [empty-session [cold-rule cold-query history-rule history-query] {:blacklist ['cold-rule]}]}

(let [session (-> empty-session
(insert (->Temperature 10 "MCI"))
(fire-rules))]

(is (empty? (query session cold-query))) ;removed rule

(is (= #{{:?t [10]}}
(set (query session history-query))))))

(def-rules-test test-blacklist-many-rules
{:rules [cold-rule [[[Temperature (< temperature 20) (= ?t temperature)]]
(insert! (->Cold ?t))]
history-rule [[[Temperature (< temperature 20) (= ?t temperature)]]
(insert! (->TemperatureHistory [?t]))]
hot-rule [[[Temperature (> temperature 50) (= ?t temperature)]]
(insert! (->Hot ?t))]
cold-and-windy-rule [[[Cold (> temperature 30) (= ?t temperature)]]
(insert! (->ColdAndWindy ?t 60))]]

:queries [cold-query [[] [[Cold (= ?c temperature)]]]
history-query [[] [[TemperatureHistory (= ?ht temperatures)]]]
hot-query [[] [[Hot (= ?h temperature)]]]
cold-windy-query [[] [[ColdAndWindy (= ?cw temperature)]]]]

:sessions [empty-session [cold-rule cold-query
history-rule history-query
hot-rule hot-query
cold-and-windy-rule cold-windy-query] {:blacklist ['history-rule
'hot-rule
'cold-and-windy-rule]}]}

(let [session (-> empty-session
(insert (->Temperature 10 "MCI"))
(insert (->Cold 40))
(insert (->Temperature 70 "MCI"))
(fire-rules))]

(is (empty? (query session history-query)))
(is (empty? (query session hot-query)))
(is (empty? (query session cold-windy-query)))

(is (= #{{:?c 10} {:?c 40}}
(set (query session cold-query))))))


(def-rules-test test-blacklist-a-query
{:rules [cold-rule [[[Temperature (< temperature 20) (= ?t temperature)]]
(insert! (->Cold ?t))]]

:queries [cold-query [[] [[Cold (= ?c temperature)]]]]

:sessions [empty-session [cold-rule cold-query] {:blacklist ['cold-query]}]}

(let [session (-> empty-session
(insert (->Temperature 10 "MCI"))
(fire-rules))]
(is (thrown? java.lang.IllegalArgumentException
(query session cold-query)))))