Puny GUI – A tiny cross platform GUI Kit in Janet
Puny GUI Puppy Finder


Well, if you've made it this far, I suppose we should start creating
an app.



First, go here https://github.com/ahungry/puny-gui and clone the repo,
or jump to the Releases section and download the one for your host OS.



In the future, if you invent something new, you'd likely repeat this
same process in a fresh directory.



There are two main executable files to take note of, they are:



app.bin/app.exe
super-repl.bin/super-repl.exe



Essentially, they are pre-compiled Janet runtimes, packed full of
useful C libraries that provide the features outlined for Puny GUI
above.



"app" is the one you'd tend to distribute to users, and simply loads
app.janet and calls it's (main) to start the application.



"super-repl" is the Janet runtime + Janet shell - if you've installed
"janet" locally, it will seem very familiar (its just the "janet"
binary with those C libs as builtins).



You can test out the dynamic nature of the REPL by making a new file
such as "hello.janet"



Add this to it:



(defn main [x] (print "Hello from Janet"))




Now run (in a terminal/CMD prompt):



./super-repl.bin hello.janet




See the pretty output?  Neat right?



Next up, we'll try invoking the GUI.  app.janet is already chock-full
of GUI goodness, so just try running it:





Thats the kitchen-sink.  It demos a lot of stuff at once (peek at
app.janet if you're curious - you can see it imports from some other
files).



Ok, back to this app.  First off, if we're going to find cute puppies,
we need a way to pull in their pics.



Lets implement that first.



Create yourself a file called dog-sdk.janet, and lets add some code.



First, we will implement a convenience wrapper written in Janet that
makes working with C curl bindings more convenient:



(import lib/net/curl :as client)




Janet's module system is similar to the nodejs commonjs system.  Had I
not aliased it at the end, it would be under the "curl/" prefix.



Now, lets define some stuff:



# The remote endpoint we will request from - it returns a dog link
(def random-host "https://dog.ceo/api/breeds/image/random")

(defn get-random-dog [host]
  (-> (client/json-get host)
      (get "message")))




If you've used Clojure, that thread macro will not look very odd - if
you haven't, it may be jarring.  You can see the macro expansion in
Janet via the macex call (similar to macro-expand-1 in Common Lisp).



Anyways, this small function will invoke json-get on the host
argument, then use the Janet accessor to pull out the key in the json
titled "message" (thats where the random dog image URL is stored).



Go ahead, try executing the code to make sure it works (if you use
Emacs, you could set up inf-janet mode + janet-mode for a good REPL
based workflow by now - if not, no big deal, you can do this all in
Notepad even).



./super-repl.bin dog-sdk.janet




Oops!  Nothing happened - that's because there is no 'main' in this
file.



Ok, so you have two options - add a main, or call super-repl.bin
without any arguments to have the REPL active.



If you chose to use the REPL, try this out next:



janet:1:> (use dog-sdk)
nil
janet:2:> (get-random-dog random-host)
"https://images.dog.ceo/breeds/saluki/n02091831_3760.jpg"




Neat, it worked!  If you wanted to add a main, you may have done so
like this:



(defn main [_ ]
  (-> (get-random-dog random-host)
      pp))




Now when you run it with './super-repl.bin ./dog-sdk.janet', you see
it prints out a URL.



Now lets get to the point of saving this as an image.



Fortunately, this is a trivial addition to what we already have.



Modify your code to look like this:



# Small SDK to get a random dog picture and save it to disk
(import lib/net/curl :as client)

(def random-host "https://dog.ceo/api/breeds/image/random")

(defn get-random-dog [host]
  (-> (client/json-get host)
      (get "message")))

(defn get-image-content
  "Fetches remote dog picture and saves to disk."
  [url]
  (def img (client/http-get url))
  (spit "dog.jpg" img))

(defn main [_ ]
  (-> (get-random-dog random-host)
      get-image-content))





If you messed up or got confused, just peek at the "examples/dog-sdk.janet"
file in the release you downloaded.



So, get-image-content is a new function - its job is to invoke the
random url endpoint, and make a basic http request to the resultant
image URL, then "spit" the code into a new file named dog.jpg.



Run this file and observe your new dog picture in dog.jpg

