-
Notifications
You must be signed in to change notification settings - Fork 20
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
Dynamic rulesets #12
Comments
I haven't tried it with more input data than the first example, but it might be doable with less macro: (defmacro ->fn
([fn-name body]
`(fn ~fn-name [] ~body))
([fn-name arg body]
`(fn ~fn-name [~arg] ~body)))
(defn parsed->rule
[{:keys [rule-name fn-name conditions when-body then-body then-finally-body arg]}]
(o/->Rule rule-name
(mapv o/map->Condition conditions)
(when (some? when-body) ;; need some? because it could be `false`
(->fn fn-name arg when-body))
(when then-body
(->fn fn-name arg (first then-body)))
(when then-finally-body
(->fn fn-name (first then-finally-body)))))
(defn ->rule
[rule-key rule]
(parsed->rule (o/->rule [rule-key (o/parse ::o/rule rule)])))
(defn ->ruleset
"Returns a vector of rules after transforming the given map."
[rules]
(->> (map o/->rule
(o/parse ::o/rules rules))
(mapv parsed->rule)))
|
@rwstauner did not work with my example data. I like its less macroey but need to debut why it did not work for me |
i get [{:id "1", :x 3, :y 1}]
[{:id "1", :x 3, :y 1}] |
the first code was limiting then bodies to 1 which i didn't realize was incorrect. (defn parsed->rule
[{:keys [rule-name fn-name conditions when-body then-body then-finally-body arg]}]
(o/->Rule rule-name
(mapv o/map->Condition conditions)
(when (some? when-body) ;; need some? because it could be `false`
(eval `(fn ~fn-name [~arg] ~when-body)))
(when then-body
(eval `(fn ~fn-name [~arg] ~@then-body)))
(when then-finally-body
(eval `(fn ~fn-name [] ~@then-finally-body)))))
(defn ->rule
[rule-key rule]
(parsed->rule (o/->rule [rule-key (o/parse ::o/rule rule)])))
(defn ->ruleset
"Returns a vector of rules after transforming the given map."
[rules]
(->> (map o/->rule
(o/parse ::o/rules rules))
(mapv parsed->rule)))
|
Really neat. I think @rwstauner's solution is good, but you don't actually even need eval, if you're willing to give up some syntactic convenience. The macro or eval is really just saving you from having to explicitly make (require '[odoyle.rules :as o])
(defn parsed->rule
[{:keys [rule-name fn-name conditions when-body then-body then-finally-body arg]}]
(o/->Rule rule-name
(mapv o/map->Condition conditions)
when-body
(first then-body)
(first then-finally-body)))
(defn ->rule
[rule-key rule]
(parsed->rule (o/->rule [rule-key (o/parse ::o/rule rule)])))
(defn ->ruleset
"Returns a vector of rules after transforming the given map."
[rules]
(->> (map o/->rule
(o/parse ::o/rules rules))
(mapv parsed->rule)))
(def generated-rule
[:what
'[id :player/x x]
'[id :player/y y]
:when
(fn [{:keys [x y] :as match}]
(and (pos? x) (pos? y)))
:then
(fn [{:keys [id] :as match}]
(o/insert! id :session/player match))
:then-finally
(fn []
(println "Query from inside: " (o/query-all o/*session* :session/player)))])
(println "Query from outside: "
(-> (o/->session)
(o/add-rule (->rule :session/player generated-rule))
(o/insert 1 {:player/x 3 :player/y 1})
(o/insert 2 {:player/x 5 :player/y 2})
(o/insert 3 {:player/x 7 :player/y -1})
o/fire-rules
(o/query-all :session/player)))
; => Query from inside: [{:id 1, :x 3, :y 1} {:id 2, :x 5, :y 2}]
; => Query from outside: [{:id 1, :x 3, :y 1} {:id 2, :x 5, :y 2}] |
I just added this if you want to give it a shot. It is a new arity of (require '[odoyle.rules :as o])
(def generated-rule
[:what
'[id :player/x x]
'[id :player/y y]
:when
(fn [{:keys [x y] :as match}]
(and (pos? x) (pos? y)))
:then
(fn [{:keys [id] :as match}]
(o/insert! id :session/player match))
:then-finally
(fn []
(println "Query from inside: " (o/query-all o/*session* :session/player)))])
(println "Query from outside: "
(-> (o/->session)
(o/add-rule (o/->rule :session/player generated-rule))
(o/insert 1 {:player/x 3 :player/y 1})
(o/insert 2 {:player/x 5 :player/y 2})
(o/insert 3 {:player/x 7 :player/y -1})
o/fire-rules
(o/query-all :session/player))) |
Thanks Zach! I’ll check it out later today! We are gearing up to using this
lib :) we are stoked. Thanks again
…On Tue, Jun 1, 2021 at 7:48 AM Zach Oakes ***@***.***> wrote:
I just added this if you want to give it a shot. It is a new arity of
odoyle.rules/->rule so the code above is now just this:
(require '[odoyle.rules :as o])
(def generated-rule
[:what
'[id :player/x x]
'[id :player/y y]
:when
(fn [{:keys [x y] :as match}]
(and (pos? x) (pos? y)))
:then
(fn [{:keys [id] :as match}]
(o/insert! id :session/player match))
:then-finally
(fn []
(println "Query from inside: " (o/query-all o/*session* :session/player)))])
(println "Query from outside: "
(-> (o/->session)
(o/add-rule (o/->rule :session/player generated-rule))
(o/insert 1 {:player/x 3 :player/y 1})
(o/insert 2 {:player/x 5 :player/y 2})
(o/insert 3 {:player/x 7 :player/y -1})
o/fire-rules
(o/query-all :session/player)))
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#12 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAB75WOUJIOGDICDO4GRBLTQTXNPANCNFSM45JXYY6Q>
.
|
I ended up cutting a new release because why not :D I also wrote a new section in the readme about it: Defining rules dynamically |
Very nice !
…On Tue, Jun 1, 2021 at 11:23 AM Zach Oakes ***@***.***> wrote:
I ended up cutting a new release because why not :D
I also wrote a new section in the readme about it: Defining rules
dynamically
<https://github.com/oakes/odoyle-rules#defining-rules-dynamically>
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#12 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAB75QDV3NQJFOR4FANBELTQUQQ3ANCNFSM45JXYY6Q>
.
|
I am very excited to see this :) I've wanted to use odoyle rules in conjunction with home assistant to power my smart home. I had a basic prototype working but the inability to dynamically create rules made it difficult. Now I can dust that off and give it a go again. |
I've been evaluating this awesome project great work!
For my usecase I have to dynamically create rulesets. I think I have implementation for this but my macro fu is not the best I dont love I had to use
eval
. Is this something that you would like to make part of this project? I can submit a pr if so.The text was updated successfully, but these errors were encountered: