Commits

Steven! Ragnarök  committed dcba1c5

Add docs and move commands into separate namespace.

  • Participants
  • Parent commits b3f1df7

Comments (0)

Files changed (5)

 the program and how it works. The documentation was generated with
 [Marginalia][]
 
+To read it open `docs/uberdoc.html` in any modern browser.
+
 ## License
 
 Copyright (C) 2012 Steven! Ragnarök

File docs/uberdoc.html

 })
 </script><title>messageme -- Marginalia</title></head><body><table><tr><td class="docs"><div class="header"><h1 class="project-name">messageme</h1><h2 class="project-version">1.0.0-SNAPSHOT</h2><br /><p>A version of the messageme service
   written in Clojure.</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.3.0</td></tr></table></div><div class="dependencies"><h3>dev dependencies</h3><table></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="#messageme.core">messageme.core</a></li><li><a href="#messageme.console">messageme.console</a></li></ul></div></td><td class="codes">&nbsp;</td></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#messageme.core" name="messageme.core"><h1 class="project-name">messageme.core</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 messageme.core)</pre></tr><tr><td class="docs">
-</td><td class="codes" /><pre class="brush: clojure">(def message-box (agent ()))</pre></tr><tr><td class="docs">
-</td><td class="codes" /><pre class="brush: clojure">(def connected-users (agent []))</pre></tr><tr><td class="docs">
-</td><td class="codes" /><pre class="brush: clojure">(defn do-connect-user [user]
-  (send-off connected-users (fn [connected-users]
-                              (conj connected-users user))))</pre></tr><tr><td class="docs">
-</td><td class="codes" /><pre class="brush: clojure">(defn do-insert-message [message]
-  (send-off message-box (fn [box]
-                          (conj box message))))</pre></tr><tr><td class="docs">
-</td><td class="codes" /><pre class="brush: clojure">(defn do-notify-recipient [msg]
-  (send-off connected-users
+</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.3.0</td></tr></table></div><div class="dependencies"><h3>dev dependencies</h3><table><tr><td class="dep-name">lein-marginalia</td><td class="dotted"><hr /></td><td class="dep-version">0.6.0</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="#messageme.core">messageme.core</a></li><li><a href="#messageme.commands">messageme.commands</a></li><li><a href="#messageme.console">messageme.console</a></li></ul></div></td><td class="codes">&nbsp;</td></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#messageme.core" name="messageme.core"><h1 class="project-name">messageme.core</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 messageme.core)</pre></tr><tr><td class="docs"><p>Agent for the list of messages in the system.</p>
+</td><td class="codes" /><pre class="brush: clojure">(def message-box (agent ()))</pre></tr><tr><td class="docs"><p>Agent for the vector of currently connected users in the system.</p>
+</td><td class="codes" /><pre class="brush: clojure">(def connected-users (agent []))</pre></tr><tr><td class="docs"><p>Print the exception from the asyncrhonous agent</p>
+</td><td class="codes" /><pre class="brush: clojure">(defn print-agent-error
+  [agent-name exception]
+  (println &quot;Exception:&quot; exception &quot;occured in agent:&quot; @agent-name))</pre></tr><tr><td class="docs"><p>Print errors for debugging purposes.</p>
+</td><td class="codes" /><pre class="brush: clojure">(set-error-handler! message-box print-agent-error)
+(set-error-handler! connected-users print-agent-error)</pre></tr><tr><td class="docs"><p>Add user to the vector of connected users. This will cause new message
+  notifications to be printed for this user.</p>
+</td><td class="codes" /><pre class="brush: clojure">(defn do-connect-user
+  [user]
+  (send connected-users (fn [connected-users]
+                              (conj connected-users user))))</pre></tr><tr><td class="docs"><p>Remove user from the vector of connected users, thus preventing notifications
+  from displaying.</p>
+</td><td class="codes" /><pre class="brush: clojure">(defn do-disconnect-user
+  [user]
+  (send connected-users (fn [connected-users]
+                          (vec (remove #(= % user) connected-users)))))</pre></tr><tr><td class="docs"><p>Add a new message to the list of messages in the system</p>
+</td><td class="codes" /><pre class="brush: clojure">(defn do-insert-message
+  [message]
+  (send message-box (fn [box]
+                          (conj box message))))</pre></tr><tr><td class="docs"><p>Print a new message notification if the recipient user is connected.</p>
+</td><td class="codes" /><pre class="brush: clojure">(defn do-notify-recipient
+  [msg]
+  (send connected-users
             (fn [users]
               (if (some #{(:recipient msg)} users)
                 (println &quot; ** Notification:&quot; (:recipient msg)
-                         &quot;has a new message from&quot; (:sender msg))) users)))</pre></tr><tr><td class="docs">
-</td><td class="codes" /><pre class="brush: clojure">(defn inbox-data [user]
-  (filter (fn [msg] (= (:recipient msg) user)) @message-box))</pre></tr><tr><td class="docs">
-</td><td class="codes" /><pre class="brush: clojure">(defn send-message [sender recipient body]
+                         &quot;has a new message from&quot; (:sender msg))) users)))</pre></tr><tr><td class="docs"><p>Build a map representing the new message then send it to the message-box
+  agent. Also triggers a new message notification.</p>
+</td><td class="codes" /><pre class="brush: clojure">(defn send-message
+  [sender recipient body]
   (let [msg {:sender sender, :recipient recipient, :body body :read false}]
     (do-insert-message msg)
-    (do-notify-recipient msg)))</pre></tr><tr><td class="docs">
-</td><td class="codes" /><pre class="brush: clojure">(defn display-msg [msg]
-  (println (str &quot;  From: &quot; (:sender msg) &quot; | Message: &quot; (:body msg))))</pre></tr><tr><td class="docs">
-</td><td class="codes" /><pre class="brush: clojure">(defn display-inbox [user msgs]
-  (println (str &quot;Inbox for &quot; user &quot; contains &quot; (count msgs) &quot; messages:&quot;))
-  (loop [[msg &amp; remaining] msgs]
-    (if msg
-      (do (display-msg msg) (recur remaining))
-      (println))))</pre></tr><tr><td class="docs">
-</td><td class="codes" /><pre class="brush: clojure">(defn display-unread [usr]
-  (let [unread (filter #(% :read) (inbox-data usr))]
-    (println (count unread) &quot;messages arrived since you last connected:&quot;)
-    (loop [[msg &amp; remaining] unread]
-      (if msg
-        (do (display-msg msg) (recur remaining))
-        (println)))))</pre></tr><tr><td class="docs">
+    (do-notify-recipient msg)))</pre></tr><tr><td class="docs"><p>Return a function which filters messages belonging to the given user.</p>
+</td><td class="codes" /><pre class="brush: clojure">(defn filter-user-messages
+  [user]
+  (fn [message-box] (filter (fn [msg] (= (:recipient msg) user)) message-box)))</pre></tr><tr><td class="docs"><p>Displays a message and returns a map representing the read message</p>
+</td><td class="codes" /><pre class="brush: clojure">(defn read-msg
+  [msg]
+  (println &quot;  From:&quot; (:sender msg) &quot;| Message:&quot; (:body msg))
+  (assoc msg :read true))</pre></tr><tr><td class="docs"><p>Search the message-box for messages belonging to user.
+  If messages are found, read and display them.
+  Returns a complete message-box with the user's messages marked read.</p>
+</td><td class="codes" /><pre class="brush: clojure">(defn display-inbox
+  [message-box user]
+  (let [msgs (filter #(= (:recipient %) user) message-box)
+        other-mail (remove #(= (:recipient %) user) message-box)]
+    (println &quot;Inbox for&quot; user &quot;contains&quot; (count msgs) &quot;messages:&quot;)
+    (concat (map read-msg msgs) other-mail)))</pre></tr><tr><td class="docs"><p>Search the message-box for unread messages belonging to user.
+  If messages are found, read and display them.
+  Returns a complete message-box with the user's messages marked read.</p>
+</td><td class="codes" /><pre class="brush: clojure">(defn display-unread
+  [message-box user]
+  (let [msgs (filter #(= (:recipient %) user) message-box)
+        unread-msgs (remove #(:read %) msgs)
+        read-msgs (filter #(:read %) msgs)
+        other-mail (remove #(= (% :recipient) user) message-box)]
+    (println (count unread-msgs) &quot;arrived since you last connected:&quot;)
+    (concat (map read-msg unread-msgs) read-msgs other-mail)))</pre></tr><tr><td class="docs"><p>Display a brief header, then display each message, marking it as read.</p>
+</td><td class="codes" /><pre class="brush: clojure">(defn do-display-inbox
+  [user]
+  (send message-box display-inbox user))</pre></tr><tr><td class="docs"><p>Display a header with the number of unread messages followed by each unread
+  message. This function marks all messages the user's messages read.</p>
+</td><td class="codes" /><pre class="brush: clojure">(defn do-display-unread
+  [user]
+  (send message-box display-unread user))</pre></tr><tr><td class="spacer docs">&nbsp;</td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#messageme.commands" name="messageme.commands"><h1 class="project-name">messageme.commands</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 messageme.commands
+  (:use messageme.core))</pre></tr><tr><td class="docs">
 </td><td class="codes" /><pre class="brush: clojure">(defn connect [arg-str]
   (do-display-unread arg-str)
   (do-connect-user arg-str))</pre></tr><tr><td class="docs">
+</td><td class="codes" /><pre class="brush: clojure">(defn disconnect [arg-str]
+  (do-disconnect-user arg-str))</pre></tr><tr><td class="docs">
 </td><td class="codes" /><pre class="brush: clojure">(defn send [arg-str]
   (let [[sender recipient body] (seq (.split arg-str &quot; &quot; 3))
         stripped-body (.replace body &quot;'&quot; )]
     (send-message sender recipient stripped-body)))</pre></tr><tr><td class="docs">
 </td><td class="codes" /><pre class="brush: clojure">(defn inbox [arg-str]
-  (display-inbox arg-str (inbox-data arg-str)))</pre></tr><tr><td class="docs">
+  (do-display-inbox arg-str))</pre></tr><tr><td class="docs">
 </td><td class="codes" /><pre class="brush: clojure">(defn exit []
   (java.lang.System/exit 0))</pre></tr><tr><td class="spacer docs">&nbsp;</td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#messageme.console" name="messageme.console"><h1 class="project-name">messageme.console</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 messageme.console
-  (:require [messageme.core :as mm]))</pre></tr><tr><td class="docs">
+  (:require [messageme.commands :as cmd]))</pre></tr><tr><td class="docs">
 </td><td class="codes" /><pre class="brush: clojure">(def prompt-string &quot;&gt; &quot;)</pre></tr><tr><td class="docs">
 </td><td class="codes" /><pre class="brush: clojure">(def commands
-  {&quot;send&quot; mm/send
-   &quot;inbox&quot; mm/inbox
-   &quot;connect&quot; mm/connect
-   &quot;exit&quot; mm/exit})</pre></tr><tr><td class="docs">
+  {&quot;send&quot; cmd/send
+   &quot;inbox&quot; cmd/inbox
+   &quot;connect&quot; cmd/connect
+   &quot;exit&quot; cmd/exit})</pre></tr><tr><td class="docs">
 </td><td class="codes" /><pre class="brush: clojure">(defn execute [[command &amp; arg-str]]
   (if (commands command)
     (apply (commands command) arg-str)
     (print prompt-string) (flush)
     (let [input (vec (.split (read-line) &quot; &quot; 2))]
       (execute input))
-  (recur)))</pre></tr><tr><td class="spacer docs">&nbsp;</td><td class="codes" /></tr></table><div class="footer">Generated by <a href="https://github.com/fogus/marginalia">Marginalia</a>.&nbsp;&nbsp;Syntax highlighting provided by Alex Gorbatchev's <a href="http://alexgorbatchev.com/SyntaxHighlighter/">SyntaxHighlighter</a><div id="floating-toc"><ul><li class="floating-toc-li" id="floating-toc_messageme.core">messageme.core</li><li class="floating-toc-li" id="floating-toc_messageme.console">messageme.console</li></ul></div></div><script type="text/javascript">SyntaxHighlighter.defaults['gutter'] = false;
+  (recur)))</pre></tr><tr><td class="spacer docs">&nbsp;</td><td class="codes" /></tr></table><div class="footer">Generated by <a href="https://github.com/fogus/marginalia">Marginalia</a>.&nbsp;&nbsp;Syntax highlighting provided by Alex Gorbatchev's <a href="http://alexgorbatchev.com/SyntaxHighlighter/">SyntaxHighlighter</a><div id="floating-toc"><ul><li class="floating-toc-li" id="floating-toc_messageme.core">messageme.core</li><li class="floating-toc-li" id="floating-toc_messageme.commands">messageme.commands</li><li class="floating-toc-li" id="floating-toc_messageme.console">messageme.console</li></ul></div></div><script type="text/javascript">SyntaxHighlighter.defaults['gutter'] = false;
        SyntaxHighlighter.all()</script></body></html>

File src/messageme/commands.clj

+(ns messageme.commands
+  (:use messageme.core))
+
+(defn connect [arg-str]
+  (do-display-unread arg-str)
+  (do-connect-user arg-str))
+
+(defn disconnect [arg-str]
+  (do-disconnect-user arg-str))
+
+(defn send [arg-str]
+  (let [[sender recipient body] (seq (.split arg-str " " 3))
+        stripped-body (.replace body "'" "")]
+    (send-message sender recipient stripped-body)))
+
+(defn inbox [arg-str]
+  (do-display-inbox arg-str))
+
+(defn exit []
+  (java.lang.System/exit 0))
+

File src/messageme/console.clj

 (ns messageme.console
-  (:require [messageme.core :as mm]))
+  (:require [messageme.commands :as cmd]))
 
 (def prompt-string "> ")
 
 (def commands
-  {"send" mm/send
-   "inbox" mm/inbox
-   "connect" mm/connect
-   "exit" mm/exit})
+  {"send" cmd/send
+   "inbox" cmd/inbox
+   "connect" cmd/connect
+   "exit" cmd/exit})
 
 (defn execute [[command & arg-str]]
   (if (commands command)

File src/messageme/core.clj

 (ns messageme.core)
 
+;; Agent for the list of messages in the system.
 (def message-box (agent ()))
 
+;; Agent for the vector of currently connected users in the system.
 (def connected-users (agent []))
 
-(defn do-connect-user [user]
-  (send-off connected-users (fn [connected-users]
+(defn print-agent-error
+  "Print the exception from the asyncrhonous agent"
+  [agent-name exception]
+  (println "Exception:" exception "occured in agent:" @agent-name))
+
+;; Print errors for debugging purposes.
+(set-error-handler! message-box print-agent-error)
+(set-error-handler! connected-users print-agent-error)
+
+(defn do-connect-user
+  "Add user to the vector of connected users. This will cause new message
+  notifications to be printed for this user."
+  [user]
+  (send connected-users (fn [connected-users]
                               (conj connected-users user))))
 
-(defn do-insert-message [message]
-  (send-off message-box (fn [box]
+(defn do-disconnect-user
+  "Remove user from the vector of connected users, thus preventing notifications
+  from displaying."
+  [user]
+  (send connected-users (fn [connected-users]
+                          (vec (remove #(= % user) connected-users)))))
+
+(defn do-insert-message
+  "Add a new message to the list of messages in the system"
+  [message]
+  (send message-box (fn [box]
                           (conj box message))))
 
-(defn do-notify-recipient [msg]
-  (send-off connected-users
+(defn do-notify-recipient
+  "Print a new message notification if the recipient user is connected."
+  [msg]
+  (send connected-users
             (fn [users]
               (if (some #{(:recipient msg)} users)
                 (println " ** Notification:" (:recipient msg)
                          "has a new message from" (:sender msg))) users)))
 
-(defn mark-inbox-read
-  "Takes a message box and a user ands the message box with the user's messages
-  marked read."
-  [box user]
-  (let [other-msgs (remove #(= (% :recipent) user) box)
-        user-inbox (filter #(= (% :recipient) user) box)]
-    (concat other-msgs (map
-                         #({:sender (:sender %), :recipient (:recipient %),
-                            :body (:body %), :read true}) user-inbox))))
-
-(defn inbox-data [user]
-  (send-off message-box mark-inbox-read)
-  (filter (fn [msg] (= (:recipient msg) user)) @message-box))
-
-(defn send-message [sender recipient body]
+(defn send-message
+  "Build a map representing the new message then send it to the message-box
+  agent. Also triggers a new message notification."
+  [sender recipient body]
   (let [msg {:sender sender, :recipient recipient, :body body :read false}]
     (do-insert-message msg)
     (do-notify-recipient msg)))
 
-(defn display-msg [msg]
-  (println (str "  From: " (:sender msg) " | Message: " (:body msg))))
+(defn filter-user-messages
+  "Return a function which filters messages belonging to the given user."
+  [user]
+  (fn [message-box] (filter (fn [msg] (= (:recipient msg) user)) message-box)))
 
-(defn display-inbox [user msgs]
-  (println (str "Inbox for " user " contains " (count msgs) " messages:"))
-  (loop [[msg & remaining] msgs]
-    (if msg
-      (do (display-msg msg) (recur remaining))
-      (println))))
+(defn read-msg
+  "Displays a message and returns a map representing the read message"
+  [msg]
+  (println "  From:" (:sender msg) "| Message:" (:body msg))
+  (assoc msg :read true))
 
-(defn do-display-unread [usr]
-  (let [unread (filter #(% :read) (inbox-data usr))]
-    (println (count unread) "messages arrived since you last connected:")
-    (loop [[msg & remaining] unread]
-      (if msg
-        (do (display-msg msg) (recur remaining))
-        (println)))))
+(defn display-inbox
+  "Search the message-box for messages belonging to user.
+  If messages are found, read and display them.
+  Returns a complete message-box with the user's messages marked read."
+  [message-box user]
+  (let [msgs (filter #(= (:recipient %) user) message-box)
+        other-mail (remove #(= (:recipient %) user) message-box)]
+    (println "Inbox for" user "contains" (count msgs) "messages:")
+    (concat (map read-msg msgs) other-mail)))
 
-(defn connect [arg-str]
-  (do-display-unread arg-str)
-  (do-connect-user arg-str))
+(defn display-unread
+  "Search the message-box for unread messages belonging to user.
+  If messages are found, read and display them.
+  Returns a complete message-box with the user's messages marked read."
+  [message-box user]
+  (let [msgs (filter #(= (:recipient %) user) message-box)
+        unread-msgs (remove #(:read %) msgs)
+        read-msgs (filter #(:read %) msgs)
+        other-mail (remove #(= (% :recipient) user) message-box)]
+    (println (count unread-msgs) "arrived since you last connected:")
+    (concat (map read-msg unread-msgs) read-msgs other-mail)))
 
-(defn send [arg-str]
-  (let [[sender recipient body] (seq (.split arg-str " " 3))
-        stripped-body (.replace body "'" "")]
-    (send-message sender recipient stripped-body)))
+(defn do-display-inbox
+  "Display a brief header, then display each message, marking it as read."
+  [user]
+  (send message-box display-inbox user))
 
-(defn inbox [arg-str]
-  (display-inbox arg-str (inbox-data arg-str)))
+(defn do-display-unread
+  "Display a header with the number of unread messages followed by each unread
+  message. This function marks all messages the user's messages read."
+  [user]
+  (send message-box display-unread user))
 
-(defn exit []
-  (java.lang.System/exit 0))
-