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 clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
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 clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to