I am trying to write a domain-specific production rule language which is
compiled down at run-time into Clojure code. It's intended that the rule
language should be usable by primary school children with little help.
So far it's going extremely well, except for one problem. If I run it in
the REPL, like this, it works:
user=> (use 'mw-parser.core :reload)
nil
user=> (use 'mw-engine.utils)
nil
user=> (parse-rule "if state is forest and fertility is between 55 and 75
then state should be climax")
(fn [cell world] (if (and (= (:state cell) :forest) (or (< 55 (get-int cell
:fertility) 75) (> 55 (get-int cell :fertility) 75))) (merge cell {:state
:climax})))
user=> (eval *1)
#<user$eval1839$fn__1840 user$eval1839$fn__1840@7a52b16b>
user=> (apply *1 (list {:state :forest :fertility 60} nil))
{:state :climax, :fertility 60}
user=>
However, I have a test as follows:
ns mw-parser.core-test
(:use mw-engine.utils)
(:require [clojure.test :refer :all]
[mw-parser.core :refer :all]))
(deftest rules-tests
(testing "if altitude is less than 100 and state is forest then state
should be climax and deer should be 3"
(is (parse-rule "if altitude is less than 100 and state is
forest then state should be climax and deer should be 3"))
(is (let [cell (apply (eval (parse-rule "if altitude is less
than 100 and state is forest then state should be climax and deer should be
3"))
(list {:state :forest :altitude 99} nil))]
(and (= (:state cell) :climax) (= (:deer cell) 3))))
))
This fails as follows:
simon@engraver:~/workspace/mw-parser$ lein test
lein test mw-parser.core-test
lein test :only mw-parser.core-test/rules-tests
ERROR in (rules-tests) (Compiler.java:6380)
if altitude is less than 100 and state is forest then state should be
climax and deer should be 3
expected: (let [cell (apply (eval (parse-rule "if altitude is less than 100
and state is forest then state should be climax and deer should be 3"))
(list {:state :forest, :altitude 99} nil))] (and (= (:state cell) :climax)
(= (:deer cell) 3)))
actual: clojure.lang.Compiler$CompilerException:
java.lang.RuntimeException: Unable to resolve symbol: get-int in this
context, compiling:(/tmp/form-init4592216274934008360.clj:1:6384)
The function get-int is in mw-engine.utils, and is:
(defn get-int
"Get the value of a property expected to be an integer from a map; if not
present (or not an integer) return 0.
* `map` a map;
* `key` a symbol or keyword, presumed to be a key into the `map`."
[map key]
(cond map
(let [v (map key)]
(cond (and v (integer? v)) v
true 0))
true (throw (Exception. "No map passed?"))))
I'm trying to understand why this function is not available in the test
environment when the anonymous function generated from the rule text is
compiled and applied. This matters, because I expect the users of the
system to add rules via a web form, so they won't have a REPL.
As you can see I've specified that mw-engine.utils is used by the test
file, but that does not apparently make the namespace available in eval. It
is the eval step, not the apply step, that fails, I've verified that by
trying:
user=> (use 'mw-parser.core :reload)
nil
user=> (parse-rule "if state is forest and fertility is between 55 and 75
then state should be climax")
(fn [cell world] (if (and (= (:state cell) :forest) (or (< 55 (get-int cell
:fertility) 75) (> 55 (get-int cell :fertility) 75))) (merge cell {:state
:climax})))
user=> (eval *1)
CompilerException java.lang.RuntimeException: Unable to resolve symbol:
get-int in this context,
compiling:(/tmp/form-init2345285067501587397.clj:1:1)
user=>
(Note that on this occasion I didn't include the (use 'mw-engine.utils)
step)
Any assistance gratefully received!
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.