My Monster! It lives!
This commit is contained in:
parent
77cfb32bb2
commit
ad0e992000
141
README.md
141
README.md
|
@ -1,23 +1,140 @@
|
|||
# mw-ui
|
||||
## What this is about
|
||||
|
||||
FIXME
|
||||
MicroWorld is a rule driven cellular automaton. What does that mean? Well, it's
|
||||
a two dimensional world made up of squares called **cells**. The world develops
|
||||
in steps, and at each step, each cell is modified by applying the rules.
|
||||
|
||||
## Prerequisites
|
||||
[Go and watch](world) it running for a few moments, then come back here.
|
||||
|
||||
You will need [Leiningen][1] 2.0 or above installed.
|
||||
The demonstration world is a mountain, with snow at the top and the sea at the
|
||||
bottom. as you watched, you probably saw the bright green of grass on the lower
|
||||
slopes of the mountain turn to the darker green of forest. You may have seen
|
||||
some forest fires break out.
|
||||
|
||||
## Running
|
||||
That's all controlled by rules. You make the rules. To start Noah's flood,
|
||||
[go to the rules page](rules) now, and add this rule at the very top:
|
||||
|
||||
To start a web server for the application, run:
|
||||
if altitude is less than 200 then state should be water
|
||||
|
||||
then, [go and watch the world](world) again. What happens? You should see water
|
||||
spread across everywhere except the very top of the mountain. But after the
|
||||
flood, the waters should drain away again. Go back to [rules](rules) and add
|
||||
this rule at the very top:
|
||||
|
||||
if altitude is more than 9 and state is water then state should be grassland
|
||||
|
||||
Now the world alternates between *new* and *grassland*. That's no good! Go back to
|
||||
[rules](rules) and delete the rule that you first added - the one that says
|
||||
|
||||
if altitude is less than 200 then state should be water
|
||||
|
||||
And see! The world starts growing again.
|
||||
|
||||
## What you can do next
|
||||
|
||||
### Change some rules
|
||||
|
||||
Change some of the other rules and see what happens. Very likely, one of the
|
||||
first things that will happen is that you will get a message like this:
|
||||
|
||||
I did not understand 'if state is grassland then 1 chance in 10 state will be heath'
|
||||
|
||||
That means that you changed a rule in a way that the engine could no longer
|
||||
understand it. To find out what the engine will understand, have a look at the
|
||||
[documentation](docs#grammar).
|
||||
|
||||
### Invent some rules of your own!
|
||||
|
||||
What happens when people come into the world? Where would they make their first
|
||||
camp? Would they want to be near the water, so they could fish? Would they want
|
||||
be near fertile grassland, to graze their sheep and cattle?
|
||||
|
||||
__Write a rule which adds some camps to the world__
|
||||
|
||||
What happens to the land around a camp? Do the people burn down forest to make
|
||||
new grassland? Do they convert the grassland into meadow, or into crop?
|
||||
|
||||
Does growing crops reduce the soil fertility? What makes people decide that their
|
||||
camp is a good enough place to build a proper house?
|
||||
|
||||
__Write some rules which describe this__
|
||||
|
||||
How many squares of meadow or crop does it take to feed each house full of people?
|
||||
What happens when there are too many houses and not enough fields? Can houses
|
||||
catch fire? What happens to a house which is next to a fire?
|
||||
|
||||
How many houses do you need for a market place? Where would people build a
|
||||
harbour?
|
||||
|
||||
### Change the rules completely
|
||||
|
||||
I've provided rules which use the MicroWorld cellular automaton to make a simple
|
||||
model of the changes to land in Europe after the ice age. But you don't have to
|
||||
use it like that, at all.
|
||||
|
||||
[Conway's Game of Life](http://en.wikipedia.org/wiki/Conway's_Game_of_Life) is one
|
||||
of the famous uses of a cellular automaton. The rules for the Game of Life are
|
||||
very simple. To set up your game of life you'll need some initialisation rules,
|
||||
one for every cell you want to start live (we'll use _black_ for live, and
|
||||
_white_ for dead):
|
||||
|
||||
if x is equal to 4 and y is equal to 4 and state is new then state should be black
|
||||
|
||||
Add as many of these as you need for your starting pattern. Then add a rule, after
|
||||
all those:
|
||||
|
||||
if state is new then state should be white
|
||||
|
||||
I'll leave you to work out what the rules of life are for yourself, from the
|
||||
Wiki page I linked to.
|
||||
|
||||
### Change the engine
|
||||
|
||||
If you want to modify the engine itself, you will need
|
||||
[Leiningen](https://github.com/technomancy/leiningen) 2.0 or above installed on
|
||||
your own computer, and you'll need to download the source, and unpack it.
|
||||
|
||||
You will find that there are three packages:
|
||||
|
||||
+ __mw-engine__ deals with creating worlds, and transforming them;
|
||||
+ __mw-parser__ deals with turning the rule language into something the engine can work on;
|
||||
+ __mw-ui__ is the web site which provides you with a user interface.
|
||||
|
||||
For each of these packages, you need to run, in the root directory of the package,
|
||||
the following command:
|
||||
|
||||
lein install
|
||||
|
||||
Once you've done that, you'll have everything built. To start a web server for
|
||||
the application, run the following command in the _mw-ui_ directory:
|
||||
|
||||
lein ring server
|
||||
|
||||
Now you have it working, you can start changing things.
|
||||
|
||||
#### Add states
|
||||
|
||||
Adding new states is easy:
|
||||
just add new tiles in _mw-ui/resources/public/img/tiles_. The tiles should be
|
||||
png (Portable Network Graphics) files, and should be 32 pixels square. The name
|
||||
of the tile should be the name of your new state. It's good to also edit the file
|
||||
_mw-ui/resources/public/css/states.css_ to add a class for your new state.
|
||||
|
||||
#### Change the code
|
||||
|
||||
Once you've done all that, you're ready to be really ambitious. Change the code.
|
||||
Implement some new feature I haven't thought of, or fix bugs I've accidentally
|
||||
left in.
|
||||
|
||||
You'll need an editor. I recommend either [NightCode](https://nightcode.info/),
|
||||
which is quite small and will run on a Raspberry Pi, or
|
||||
[LightTable](http://www.lighttable.com/), which is extremely helpful but needs
|
||||
a more powerful computer.
|
||||
|
||||
Have fun!
|
||||
|
||||
## License
|
||||
|
||||
Copyright © 2014 Simon Brooke
|
||||
Copyright © 2014 [Simon Brooke](mailto:simon@journeyman.cc)
|
||||
|
||||
Distributed under the terms of the [GNU General Public License v2][2]
|
||||
|
||||
|
||||
[1]: https://github.com/technomancy/leiningen
|
||||
[2]: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
Distributed under the terms of the [GNU General Public License v2](http://www.gnu.org/licenses/gpl-2.0.html)
|
|
@ -3029,7 +3029,7 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
};
|
||||
})(SyntaxHighlighter);
|
||||
</script><title>mw-ui -- Marginalia</title></head><body><table><tr><td class="docs"><div class="header"><h1 class="project-name">mw-ui</h1><h2 class="project-version">0.1.0-SNAPSHOT</h2><br /><p>Web-based user interface for MicroWorld</p>
|
||||
</div><div class="dependencies"><h3>dependencies</h3><table><tr><td class="dep-name">org.clojure/clojure</td><td class="dotted"><hr /></td><td class="dep-version">1.6.0</td></tr><tr><td class="dep-name">mw-engine</td><td class="dotted"><hr /></td><td class="dep-version">0.1.0-SNAPSHOT</td></tr><tr><td class="dep-name">mw-parser</td><td class="dotted"><hr /></td><td class="dep-version">0.1.0-SNAPSHOT</td></tr><tr><td class="dep-name">lib-noir</td><td class="dotted"><hr /></td><td class="dep-version">0.8.4</td></tr><tr><td class="dep-name">ring-server</td><td class="dotted"><hr /></td><td class="dep-version">0.3.1</td></tr><tr><td class="dep-name">selmer</td><td class="dotted"><hr /></td><td class="dep-version">0.6.8</td></tr><tr><td class="dep-name">com.taoensso/timbre</td><td class="dotted"><hr /></td><td class="dep-version">3.2.1</td></tr><tr><td class="dep-name">com.taoensso/tower</td><td class="dotted"><hr /></td><td class="dep-version">2.0.2</td></tr><tr><td class="dep-name">markdown-clj</td><td class="dotted"><hr /></td><td class="dep-version">0.9.44</td></tr><tr><td class="dep-name">environ</td><td class="dotted"><hr /></td><td class="dep-version">0.5.0</td></tr><tr><td class="dep-name">noir-exception</td><td class="dotted"><hr /></td><td class="dep-version">0.2.2</td></tr></table></div></td><td class="codes" style="text-align: center; vertical-align: middle;color: #666;padding-right:20px"><br /><br /><br />(this space intentionally left almost blank)</td></tr><tr><td class="docs"><div class="toc"><a name="toc"><h3>namespaces</h3></a><ul><li><a href="#mw-ui.handler">mw-ui.handler</a></li><li><a href="#mw-ui.layout">mw-ui.layout</a></li><li><a href="#mw-ui.middleware">mw-ui.middleware</a></li><li><a href="#mw-ui.render-world">mw-ui.render-world</a></li><li><a href="#mw-ui.repl">mw-ui.repl</a></li><li><a href="#mw-ui.routes.home">mw-ui.routes.home</a></li><li><a href="#mw-ui.util">mw-ui.util</a></li></ul></div></td><td class="codes"> </td></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#mw-ui.handler" name="mw-ui.handler"><h1 class="project-name">mw-ui.handler</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||||
</div><div class="dependencies"><h3>dependencies</h3><table><tr><td class="dep-name">org.clojure/clojure</td><td class="dotted"><hr /></td><td class="dep-version">1.6.0</td></tr><tr><td class="dep-name">mw-engine</td><td class="dotted"><hr /></td><td class="dep-version">0.1.0-SNAPSHOT</td></tr><tr><td class="dep-name">mw-parser</td><td class="dotted"><hr /></td><td class="dep-version">0.1.0-SNAPSHOT</td></tr><tr><td class="dep-name">lib-noir</td><td class="dotted"><hr /></td><td class="dep-version">0.8.4</td></tr><tr><td class="dep-name">ring-server</td><td class="dotted"><hr /></td><td class="dep-version">0.3.1</td></tr><tr><td class="dep-name">selmer</td><td class="dotted"><hr /></td><td class="dep-version">0.6.8</td></tr><tr><td class="dep-name">com.taoensso/timbre</td><td class="dotted"><hr /></td><td class="dep-version">3.2.1</td></tr><tr><td class="dep-name">com.taoensso/tower</td><td class="dotted"><hr /></td><td class="dep-version">2.0.2</td></tr><tr><td class="dep-name">markdown-clj</td><td class="dotted"><hr /></td><td class="dep-version">0.9.44</td></tr><tr><td class="dep-name">environ</td><td class="dotted"><hr /></td><td class="dep-version">0.5.0</td></tr><tr><td class="dep-name">noir-exception</td><td class="dotted"><hr /></td><td class="dep-version">0.2.2</td></tr></table></div></td><td class="codes" style="text-align: center; vertical-align: middle;color: #666;padding-right:20px"><br /><br /><br />(this space intentionally left almost blank)</td></tr><tr><td class="docs"><div class="toc"><a name="toc"><h3>namespaces</h3></a><ul><li><a href="#mw-ui.handler">mw-ui.handler</a></li><li><a href="#mw-ui.layout">mw-ui.layout</a></li><li><a href="#mw-ui.middleware">mw-ui.middleware</a></li><li><a href="#mw-ui.render-world">mw-ui.render-world</a></li><li><a href="#mw-ui.repl">mw-ui.repl</a></li><li><a href="#mw-ui.routes.home">mw-ui.routes.home</a></li><li><a href="#mw-ui.routes.rules">mw-ui.routes.rules</a></li><li><a href="#mw-ui.util">mw-ui.util</a></li></ul></div></td><td class="codes"> </td></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#mw-ui.handler" name="mw-ui.handler"><h1 class="project-name">mw-ui.handler</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(ns mw-ui.handler
|
||||
(:require [compojure.core :refer [defroutes]]
|
||||
[mw-ui.routes.home :refer [home-routes]]
|
||||
|
@ -3208,18 +3208,16 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
(.stop @server)
|
||||
(reset! server nil))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#mw-ui.routes.home" name="mw-ui.routes.home"><h1 class="project-name">mw-ui.routes.home</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(ns mw-ui.routes.home
|
||||
(:use compojure.core)
|
||||
(:use compojure.core
|
||||
[mw-ui.routes.rules :as rules])
|
||||
(:require [hiccup.core :refer [html]]
|
||||
[mw-parser.bulk :as compiler]
|
||||
[mw-ui.layout :as layout]
|
||||
[mw-ui.util :as util]
|
||||
[mw-ui.render-world :as world]
|
||||
[noir.session :as session]))</pre></td></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn home-page []
|
||||
(layout/render "world.html" {:title "Watch your world grow"
|
||||
:content (html (world/render-world-table))
|
||||
:seconds (or (session/get :seconds) 5)
|
||||
:maybe-refresh "refresh"}))</pre></td></tr><tr><td class="docs">
|
||||
(layout/render "home.html" {:title "Welcome to MicroWorld"
|
||||
:content (util/md->html "/md/mw-ui.md")}))</pre></td></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn world-page []
|
||||
(layout/render "world.html" {:title "Watch your world grow"
|
||||
:content (html (world/render-world-table))
|
||||
|
@ -3237,29 +3235,58 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
:parser (util/md->html "/md/mw-parser.md")
|
||||
:states (list-states)
|
||||
:components ["mw-engine" "mw-parser" "mw-ui"]}))</pre></td></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn rules-page
|
||||
([request]
|
||||
(let [rule-text (:src request)
|
||||
error
|
||||
(try
|
||||
(do
|
||||
(if rule-text
|
||||
(session/put! :rules (compiler/compile-string rule-text)))
|
||||
(session/put! :rule-text rule-text)
|
||||
nil)
|
||||
(catch Exception e (.getMessage e)))]
|
||||
(layout/render "rules.html" {:title "Edit Rules"
|
||||
:rule-text (or (session/get :rule-text) (slurp "resources/public/rulesets/basic.txt"))
|
||||
:error error})))
|
||||
([]
|
||||
(rules-page nil)))</pre></td></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(defroutes home-routes
|
||||
(GET "/" [] (home-page))
|
||||
(GET "/about" [] (about-page))
|
||||
(GET "/docs" [] (docs-page))
|
||||
(GET "/world" [] (world-page))
|
||||
(GET "/rules" request (rules-page request))
|
||||
(POST "/rules" request (rules-page request)))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#mw-ui.util" name="mw-ui.util"><h1 class="project-name">mw-ui.util</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||||
(GET "/rules" request (rules/rules-page request))
|
||||
(POST "/rules" request (rules/rules-page request)))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#mw-ui.routes.rules" name="mw-ui.routes.rules"><h1 class="project-name">mw-ui.routes.rules</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(ns mw-ui.routes.rules
|
||||
(:use clojure.walk
|
||||
compojure.core)
|
||||
(:require [hiccup.core :refer [html]]
|
||||
[mw-parser.bulk :as compiler]
|
||||
[mw-ui.layout :as layout]
|
||||
[mw-ui.util :as util]
|
||||
[mw-ui.render-world :as world]
|
||||
[noir.session :as session]))</pre></td></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn process-rules-request
|
||||
[request]
|
||||
(let [src (:src (keywordize-keys (:form-params request)))]
|
||||
(try
|
||||
(cond src
|
||||
(let [rules (compiler/compile-string src)]
|
||||
{:rule-text src
|
||||
:rules rules
|
||||
:message (str "Successfully compiled "
|
||||
(count rules)
|
||||
" rules") })
|
||||
true {:rule-text (or
|
||||
(session/get :rule-text)
|
||||
(slurp "resources/rulesets/basic.txt"))
|
||||
:message "No rules found in request; loading defaults"})
|
||||
(catch Exception e
|
||||
{:rule-text src
|
||||
:message "An error occurred during compilation"
|
||||
:error (str (.getName (.getClass e)) ": " (.getMessage e))}))))</pre></td></tr><tr><td class="docs"><p>Request handler for the <code>rules</code> request. If the <code>request</code> contains a value
|
||||
for <code>:src</code>, treat that as rule source and try to compile it. If compilation
|
||||
succeeds, stash the compiled rules and the rule text on the session, and
|
||||
provide feedback; if not, provide feedback. </p>
|
||||
|
||||
<p> If <code>request</code> doesn't contain a value for <code>:src</code>, load basic rule source from
|
||||
the session or from <code>resources/rulesets/basic.txt</code> and pass that back.</p>
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn rules-page
|
||||
([request]
|
||||
(let [processed (process-rules-request request)]
|
||||
(if (:rules processed)
|
||||
(session/put! :rules (:rules processed)))
|
||||
(if (:rule-text processed)
|
||||
(session/put! :rule-text (:rule-text processed)))
|
||||
(layout/render "rules.html"
|
||||
(merge {:title "Edit Rules"} processed))))
|
||||
([]
|
||||
(rules-page nil)))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#mw-ui.util" name="mw-ui.util"><h1 class="project-name">mw-ui.util</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(ns mw-ui.util
|
||||
(:require [noir.io :as io]
|
||||
[markdown.core :as md]))</pre></td></tr><tr><td class="docs"><p>reads a markdown file from public/md and returns an HTML string</p>
|
||||
|
|
|
@ -33,6 +33,11 @@
|
|||
</div>
|
||||
|
||||
<div id="main-container" class="container">
|
||||
{% if message %}
|
||||
<div id="announcement">
|
||||
<p class="message">{{message}}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if error %}
|
||||
<div id="announcement">
|
||||
<p class="error">{{error}}</p>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<a name="top"/>
|
||||
<menu>
|
||||
<li><a href="#top">Top</a></li>
|
||||
<li><a href="#parser">Rule language</a></li>
|
||||
<li><a href="#grammar">Rule language</a></li>
|
||||
<li><a href="#states">Implemented states</a></li>
|
||||
<li><a href="#api">API documentation</a></li>
|
||||
</menu>
|
||||
|
@ -14,7 +14,7 @@
|
|||
<hr/>
|
||||
<menu>
|
||||
<li><a href="#top">Top</a></li>
|
||||
<li><a href="#parser">Rule language</a></li>
|
||||
<li><a href="#grammar">Rule language</a></li>
|
||||
<li><a href="#states">Implemented states</a></li>
|
||||
<li><a href="#api">API documentation</a></li>
|
||||
</menu>
|
||||
|
@ -39,7 +39,7 @@
|
|||
<hr/>
|
||||
<menu>
|
||||
<li><a href="#top">Top</a></li>
|
||||
<li><a href="#parser">Rule language</a></li>
|
||||
<li><a href="#grammar">Rule language</a></li>
|
||||
<li><a href="#states">Implemented states</a></li>
|
||||
<li><a href="#api">API documentation</a></li>
|
||||
</menu>
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
<textarea name="src" id="src" rows="10" cols="80">
|
||||
{{rule-text}}
|
||||
</textarea>
|
||||
{% if error %}
|
||||
<p class="error">{{error}}</p>
|
||||
{% endif %}
|
||||
<p class="widget">
|
||||
<label for="submit">When you have finished editing</label>
|
||||
<input name="submit" id="submit" type="submit" value="Save your rules"/>
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
(ns mw-ui.routes.home
|
||||
(:use compojure.core)
|
||||
(:use compojure.core
|
||||
[mw-ui.routes.rules :as rules])
|
||||
(:require [hiccup.core :refer [html]]
|
||||
[mw-parser.bulk :as compiler]
|
||||
[mw-ui.layout :as layout]
|
||||
[mw-ui.util :as util]
|
||||
[mw-ui.render-world :as world]
|
||||
[noir.session :as session]))
|
||||
|
||||
(defn home-page []
|
||||
(layout/render "world.html" {:title "Watch your world grow"
|
||||
:content (html (world/render-world-table))
|
||||
:seconds (or (session/get :seconds) 5)
|
||||
:maybe-refresh "refresh"}))
|
||||
(layout/render "home.html" {:title "Welcome to MicroWorld"
|
||||
:content (util/md->html "/md/mw-ui.md")}))
|
||||
|
||||
(defn world-page []
|
||||
(layout/render "world.html" {:title "Watch your world grow"
|
||||
|
@ -34,27 +32,10 @@
|
|||
:states (list-states)
|
||||
:components ["mw-engine" "mw-parser" "mw-ui"]}))
|
||||
|
||||
(defn rules-page
|
||||
([request]
|
||||
(let [rule-text (:src request)
|
||||
error
|
||||
(try
|
||||
(do
|
||||
(if rule-text
|
||||
(session/put! :rules (compiler/compile-string rule-text)))
|
||||
(session/put! :rule-text rule-text)
|
||||
nil)
|
||||
(catch Exception e (.getMessage e)))]
|
||||
(layout/render "rules.html" {:title "Edit Rules"
|
||||
:rule-text (or (session/get :rule-text) (slurp "resources/public/rulesets/basic.txt"))
|
||||
:error error})))
|
||||
([]
|
||||
(rules-page nil)))
|
||||
|
||||
(defroutes home-routes
|
||||
(GET "/" [] (home-page))
|
||||
(GET "/about" [] (about-page))
|
||||
(GET "/docs" [] (docs-page))
|
||||
(GET "/world" [] (world-page))
|
||||
(GET "/rules" request (rules-page request))
|
||||
(POST "/rules" request (rules-page request)))
|
||||
(GET "/rules" request (rules/rules-page request))
|
||||
(POST "/rules" request (rules/rules-page request)))
|
||||
|
|
48
src/mw_ui/routes/rules.clj
Normal file
48
src/mw_ui/routes/rules.clj
Normal file
|
@ -0,0 +1,48 @@
|
|||
(ns mw-ui.routes.rules
|
||||
(:use clojure.walk
|
||||
compojure.core)
|
||||
(:require [hiccup.core :refer [html]]
|
||||
[mw-parser.bulk :as compiler]
|
||||
[mw-ui.layout :as layout]
|
||||
[mw-ui.util :as util]
|
||||
[mw-ui.render-world :as world]
|
||||
[noir.session :as session]))
|
||||
|
||||
(defn process-rules-request
|
||||
[request]
|
||||
(let [src (:src (keywordize-keys (:form-params request)))]
|
||||
(try
|
||||
(cond src
|
||||
(let [rules (compiler/compile-string src)]
|
||||
{:rule-text src
|
||||
:rules rules
|
||||
:message (str "Successfully compiled "
|
||||
(count rules)
|
||||
" rules") })
|
||||
true {:rule-text (or
|
||||
(session/get :rule-text)
|
||||
(slurp "resources/rulesets/basic.txt"))
|
||||
:message "No rules found in request; loading defaults"})
|
||||
(catch Exception e
|
||||
{:rule-text src
|
||||
:message "An error occurred during compilation"
|
||||
:error (str (.getName (.getClass e)) ": " (.getMessage e))}))))
|
||||
|
||||
(defn rules-page
|
||||
"Request handler for the `rules` request. If the `request` contains a value
|
||||
for `:src`, treat that as rule source and try to compile it. If compilation
|
||||
succeeds, stash the compiled rules and the rule text on the session, and
|
||||
provide feedback; if not, provide feedback.
|
||||
|
||||
If `request` doesn't contain a value for `:src`, load basic rule source from
|
||||
the session or from `resources/rulesets/basic.txt` and pass that back."
|
||||
([request]
|
||||
(let [processed (process-rules-request request)]
|
||||
(if (:rules processed)
|
||||
(session/put! :rules (:rules processed)))
|
||||
(if (:rule-text processed)
|
||||
(session/put! :rule-text (:rule-text processed)))
|
||||
(layout/render "rules.html"
|
||||
(merge {:title "Edit Rules"} processed))))
|
||||
([]
|
||||
(rules-page nil)))
|
13
test/mw_ui/test/rules.clj
Normal file
13
test/mw_ui/test/rules.clj
Normal file
|
@ -0,0 +1,13 @@
|
|||
(ns mw-ui.test.rules
|
||||
(:use clojure.test
|
||||
ring.mock.request
|
||||
mw-ui.routes.rules))
|
||||
|
||||
;; Test file specifically to test the helper function in rules handler
|
||||
(deftest test-rules-processor
|
||||
(testing "Rules processor"
|
||||
(let [request {:src "if state is new and altitude is less than 10 then state should be water"}
|
||||
response (process-rules-request request)]
|
||||
(is (= (:message response) "Successfully compiled 1 rules"))
|
||||
(is (= (count (:rules response)) 1))
|
||||
(is (= (:rule-text response) (:src request))))))
|
Loading…
Reference in a new issue