doc: Add pk debugging section.
[8sync.git] / doc / 8sync-new-manual.org
index e2bb333c22e8153493c597f72b243f16221d3ad1..f825e3c0e38014626c36470d34a5a9063be34026 100644 (file)
@@ -173,7 +173,7 @@ special kind of actor that runs all the other actors.
 Actors can spawn other actors, but before we start the hive we use
 this special "hive-create-actor*" method.
 It takes the hive as its first argument, the actor class as the second
-argument, a decoraive "cookie" as the third argument (this is
+argument, a decorative "cookie" as the third argument (this is
 optional, but it helps with debugging... you can skip it by setting it
 to #f if you prefer), and the rest are initialization arguments to the
 actor.  hive-create-actor* passes back not the actor itself (we don't
@@ -343,14 +343,7 @@ To implement it, we're going to pull out Guile's pattern matcher.
          ;; Default
          (_
           (<- irc-bot (actor-id irc-bot) 'send-line channel
-              "*stupid puppy look*"))))
-      ;; Otherwise... just spit the output to current-output-port or whatever
-      (_
-       (if emote?
-           (format #t "~a emoted ~s in channel ~a\n"
-                   speaker line channel)
-           (format #t "~a said ~s in channel ~a\n"
-                   speaker line channel)))))
+              "*stupid puppy look*"))))))
 #+END_SRC
 
 Parsing the pattern matcher syntax is left as an exercise for the
@@ -386,14 +379,7 @@ you're right:
 
          ;; Default
          (_
-          (respond "*stupid puppy look*"))))
-      ;; Otherwise... just spit the output to current-output-port or whatever
-      (_
-       (if emote?
-           (format #t "~a emoted ~s in channel ~a\n"
-                   speaker line channel)
-           (format #t "~a said ~s in channel ~a\n"
-                   speaker line channel)))))
+          (respond "*stupid puppy look*"))))))
 #+END_SRC
 
 Okay, that looks pretty good!
@@ -405,6 +391,167 @@ What cool commands can you add?
 
 ** An intermission: about live hacking
 
+This section is optional, but highly recommended.
+It requires that you're a user of GNU Emacs.
+If you aren't, don't worry... you can forge ahead and come back in case
+you ever do become an Emacs user.
+(If you're more familiar with Vi/Vim style editing, I hear good things
+about Spacemacs...)
+
+So you may have noticed while updating the last section that the
+start/stop cycle of hacking isn't really ideal.
+You might either edit a file in your editor, then run it, or
+type the whole program into the REPL, but then you'll have to spend
+extra time copying it to a file.
+Wouldn't it be nice if it were possible to both write code in a
+file and try it as you go?
+And wouldn't it be even better if you could live edit a program
+while it's running?
+
+Luckily, there's a great Emacs mode called Geiser which makes
+editing and hacking and experimenting all happen in harmony.
+And even better, 8sync is optimized for this experience.
+8sync provides easy drop-in "cooperative REPL" support, and
+most code can be simply redefined on the fly in 8sync through Geiser
+and actors will immediately update their behavior, so you can test
+and tweak things as you go.
+
+Okay, enough talking.  Let's add it!
+Redefine run-bot like so:
+
+#+BEGIN_SRC scheme
+  (define* (run-bot #:key (username "examplebot")
+                    (server "irc.freenode.net")
+                    (channels '("##botchat"))
+                    (repl-path "/tmp/8sync-repl"))
+    (define hive (make-hive))
+    (define irc-bot
+      (hive-create-actor* hive <my-irc-bot> "irc-bot"
+                          #:username username
+                          #:server server
+                          #:channels channels))
+    (define repl-manager
+      (hive-create-actor* hive <repl-manager> "repl"
+                          #:path repl-path))
+
+    (run-hive hive (list (bootstrap-message hive irc-bot 'init)
+                         (bootstrap-message hive repl-manager 'init))))
+#+END_SRC
+
+If we put a call to run-bot at the bottom of our file we can call it,
+and the repl-manager will start something we can connect to automatically.
+Horray!
+Now when we run this it'll start up a REPL with a unix domain socket at
+the repl-path.
+We can connect to it in emacs like so:
+
+: M-x geiser-connect-local <RET> guile <RET> /tmp/8sync-repl <RET>
+
+Okay, so what does this get us?
+Well, we can now live edit our program.
+Let's change how our bot behaves a bit.
+Let's change handle-line and tweak how the bot responds to a botsnack.
+Change this part:
+
+#+BEGIN_SRC scheme
+  ;; From this:
+  ("botsnack"
+   (respond "Yippie! *does a dance!*"))
+
+  ;; To this:
+  ("botsnack"
+   (respond "Yippie! *catches botsnack in midair!*"))
+#+END_SRC
+
+Okay, now let's evaluate the change of the definition.
+You can hit "C-M-x" anywhere in the definition to re-evaluate.
+(You can also position your cursor at the end of the definition and press
+"C-x C-e", but I've come to like "C-M-x" better because I can evaluate as soon
+as I'm done writing.)
+Now, on IRC, ask your bot for a botsnack.
+The bot should give the new message... with no need to stop and start the
+program!
+
+Let's fix a bug live.
+Our current program works great if you talk to your bot in the same
+IRC channel, but what if you try to talk to them over private message?
+
+#+BEGIN_SRC text
+IRC> /query examplebot
+<foo-user> examplebot: hi!
+#+END_SRC
+
+Hm, we aren't seeing any response on IRC!
+Huh?  What's going on?
+It's time to do some debugging.
+There are plenty of debugging tools in Guile, but sometimes the simplest
+is the nicest, and the simplest debugging route around is good old
+fashioned print debugging.
+
+It turns out Guile has an under-advertised feature which makes print
+debugging really easy called "pk", pronounced "peek".
+What pk accepts a list of arguments, prints out the whole thing,
+but returns the last argument.
+This makes wrapping bits of our code pretty easy to see what's
+going on.
+So let's peek into our program with pk.
+Edit the respond section to see what channel it's really sending
+things to:
+
+#+BEGIN_SRC scheme
+  (define-method (handle-line (irc-bot <my-irc-bot>) speaker channel
+                              line emote?)
+    ;; [... snip ...]
+    (define (respond respond-line)
+      (<- irc-bot (actor-id irc-bot) 'send-line (pk 'channel channel)
+          respond-line))
+    ;; [... snip ...]
+    )
+#+END_SRC
+
+Re-evaluate.
+Now let's ping our bot in both the channel and over PM.
+
+#+BEGIN_SRC text
+;;; (channel "##botchat")
+
+;;; (channel "sinkbot")
+#+END_SRC
+
+Oh okay, this makes sense.
+When we're talking in a normal multi-user channel, the channel we see
+the message coming from is the same one we send to.
+But over PM, the channel is a username, and in this case the username
+we're sending our line of text to is ourselves.
+That isn't what we want.
+Let's edit our code so that if we see that the channel we're sending
+to looks like our own username that we respond back to the sender.
+(We can remove the pk now that we know what's going on.)
+
+#+BEGIN_SRC scheme
+  (define-method (handle-line (irc-bot <my-irc-bot>) speaker channel
+                              line emote?)
+    ;; [... snip ...]
+    (define (respond respond-line)
+      (<- irc-bot (actor-id irc-bot) 'send-line
+          (if (looks-like-me? channel)
+              speaker    ; PM session
+              channel)   ; normal IRC channel
+          respond-line))
+    ;; [... snip ...]
+    )
+#+END_SRC
+
+Re-evaluate and test.
+
+#+BEGIN_SRC text
+IRC> /query examplebot
+<foo-user> examplebot: hi!
+<examplebot> Oh hi foo-user!
+#+END_SRC
+
+Horray!
+
 ** Battle bot!
 
 ** Adding a "rankings" web page