Can I start Gorilla REPL from an uberjar? - clojure

I play with this great Gorilla REPL powered project ( https://bitbucket.org/probprog/anglican-examples/ to be specific), and want to use it under certain restricted circumstances.
Is there a way to produce an uberjar that can be started using only a JVM?
Well, I know how to create an uberjar for this project, but can I start a Gorilla REPL from it? If not what do I have to add and how do I start it?
EDITED Note on Juraj's answer:
I added a start file src/gorillaproxy/gorillaproxy.clj with the following content:
(ns gorillaproxy.gorillaproxy
(:use [gorilla-repl.core :only [run-gorilla-server]])
(:gen-class))
(defn -main
[& args]
(run-gorilla-server {:port 8990}))
Then I added [gorilla-repl "0.4.0"] to the dependency list (in project.clj), and the line
:main gorillaproxy.gorillaproxy
In that way the uberjar started the Gorilla REPL, and when I put the worksheets (and data, resources, .. if needed) into the same directory, everything worked fine.

Gorilla is typically run via the lein-gorilla plugin and thus isn't a part of an uberjar.
If you really want to create a bundle containing gorilla repl dependencies, then you need to add it this capability manually to your project.
The question is why would you want to do that.
Do you want to distribute these samples to somebody else? If that's the case, you'll still need to have all those worksheets in the current directory from where your uberjar is run because that's how gorilla repl discovers worksheets.
You can look at lein-gorilla source code to see how gorilla repl can be started.
I'd then at the same code to your project (create new src/core.clj file or whatever) and configure it in your project.clj as :main.
You'll also need to add gorilla-repl as a dependency to your project.clj
Notice however, that you'll need to run that uberjar from a directory where your anglican worksheets are (or a parent directory of such a directory).

Related

Load clj files through a leinigen-based repl

I'm trying to run snake.clj from the Programming Clojure (3rd ed) book examples. Said file starts with this declaration:
(ns examples.snake
(:import (java.awt Color Dimension)
(javax.swing JPanel JFrame Timer JOptionPane)
(java.awt.event ActionListener KeyListener))
(:require [examples.import-static :refer :all]))
(import-static java.awt.event.KeyEvent VK_LEFT VK_RIGHT VK_UP VK_DOWN)
; actual program omitted, see above link
Because I'm trying to run this on Windows, and the Clojure CLI Getting Started (recommended by the book) isn't yet available on Windows, I'm using leinigen instead. I've used these instructions to run:
lein repl from the examples folder containing my snake.clj file
=> (load-file "snake.clj")
But this gives me an error:
CompilerException java.io.FileNotFoundException: Could not locate examples/import_static__init.class or examples/import_static.clj on class path...
Somehow my setup with a repl through leinigen fails to let me use import-static like that.
As a workaround, I've used WSL Ubuntu to install the Clojure CLI and run it in the root of the book's source code folder, loading the snake file directly using the suggested code in the book ((require '[examples.snake :refer :all])). That loads just fine, I can even run (game) from the loaded file, but of course that crashes because WSL Ubuntu has no GUI options (it crashes on an "No X11 DISPLAY..." error).
I would assume that the leinigen-based setup I used failed because I had to do (load-file "import_static.clj") first. In fact, doing so is a fine workaround because then it all works (after also doing (use examples.snake)), but this doesn't scale very well for multiple/recursive imports.
What is the proper way to use leinigen (on Windows) to run such scripts? Should I've created a leinigen project file? Or is there a repl-trick to do this?
This isn't a direct answer to your question, but it'll help you get up and running.
The problem is that the files aren't on the class path because the author seems have decided to neglect using projects altogether, so leiningen can't help you. The/A solution is to create a new project, and stick everything in there.
How to get it working:
Go to a directory, start up a command prompt there, and run lein new snake. This will create a "snake" folder containing the barebones structure of a project, complete with a "project.clj".
From the files you downloaded, copy the entire "src" folder (that contains the examples folder), and paste it into the new "snake" folder so it overwrites the generated "src". You should now have a path "snake/src/examples/".
Now that "snake/src" is on the class path, it can be referenced as expected. Go to the root "snake" folder, start up a command prompt, and run
lein repl
(require '[examples.snake :as s])
(s/game)
The game window should pop up as expected.

access library functions in leiningen REPL

For the development of a library I started from a lein project, invoked like so:
lein new mylib
if I call lein install now, I can access my library in other projects. But trying to immidiately test the functions I wrote failed:
lein repl
...
(dir mylib.core)
Exception No namespace: mylib.core found clojure.core/the-ns (core.clj:4008)
Do I have to add something to the project.clj file maybe?
In order to use a library you must cause the code to be loaded - that it be on the classpath is not sufficient.
You can do this easily in an ns declaration in a file of course, but in the repl it can be easier to use (require '[my-lib.whatever :as w]) after which one can call (w/foo) (w/bar) etc. as expected. You can also use (in-ns 'my-lib.whatever) in order to switch to the namespace, but this will not give you a good result unless you have previously used require or use or load-file etc. to get the definitions first.
Let's say you created a new library named clj-foo.
% lein new clj-foo
Start your repl.
% cd clj-foo
% lein repl
In the repl, load the main entry point to your library and switch to its namespace.
(load-file "src/clj_foo/core.clj")
(ns clj-foo.core)
Now you're in the clj-foo.core namespace, make sure to add back in the repl ns to get things like doc available.
(use 'clojure.repl)
That's it. You're all set to start calling functions in your library. Note that other library files will be available from the clj-foo.core namespace if they were loaded by namespace declaration at the top of clj_foo/core.clj. If not, then you'll need to invoke load-file with their path as well.
If you make changes in core.clj. You can invoke load-file again to pick up the new code. As you progress, you can use cider to facilitate loading of individual functions and files. But that's for another question. :)
You need to add a dependency to use your library from another project. To do this add a vector (a tuple-2) to the vector that is the value of the :dependencies key in the project.clj file. Here's an example:
:dependencies [[org.clojure/clojure "1.7.0"]
[org.clojure/clojurescript "1.7.170"]
[org.clojure/core.async "0.2.371"]
[default-db-format "0.1.0-SNAPSHOT"]
[com.andrewmcveigh/cljs-time "0.3.14"]]
My own local library is called default-db-format. Its really no different to adding a dependency for com.andrewmcveigh/cljs-time.
As you say you can already do this, but are having trouble getting a REPL connection to the project of the library itself. When you go (in-ns 'some-path), you need the single quote in front of some-path. Note that some-path is a different thing to the name of your library.
Rather than use lein repl you can use the figwheel repl - if your project is setup with figwheel. My library has only one entry point and that is lein figwheel devcards. After that I had no problem going to a namespace and trying out a function:
cljs.user=> (in-ns 'default-db-format.core)
nil
default-db-format.core=> (check 1 2)
As noisesmith mentioned having a REPL in your IDE is the best setup. No fiddly typing just bring up pre-configured REPLs (per namespace) with the click of a button (or keystroke). Figwheel/Cursive setup instructions here.
I was also facing the same issue with the following configuration:
Leiningen 2.9.0 on Java 1.8.0_201 Java HotSpot(TM) 64-Bit Server VM
My file looks like this, and from the repl I desired to invoke the foo function
(ns cljtest.test
(:gen-class))
(defn foo [input]
(assoc {} "a" 123))
Both these approaches worked fine for me on the repl.
1)Switch to the appropriate name space:
cljtest.core=> (in-ns 'cljtest.test)
#object[clojure.lang.Namespace 0x90175dd "cljtest.test"]
cljtest.test=> (foo nil)
{"a" 123}
cljtest.test=>
2)Require the appropriate name space:
cljtest.core=> (require '[cljtest.test :as test])
nil
cljtest.core=> (test/foo nil)
{"a" 123}
cljtest.core=>

leinigen repl with profile

This question is a follow up to How does one pre-load a clojure file in the leiningen repl?.
My ~/.lein/profiles.clj looks as follows:
{
:user {:source-paths ["C:/Users/username/.lein/src"] }
}
My ~/.lein/src/user.clj might look as follows:
(ns user)
(println "user file loaded")
When I run lein repl within a folder containing a project.clj, then the user.clj file is executed, but when I run lein repl from another folder it doesn't load my user profile. Is there a workaround for this or is this behavior by design? In fact, I know that Leinigen is indeed loading my profile.clj (even when there is no project.clj) because there are also other things inside (taken from the excellent pimp my repl article). Leinigen is just having problems with my additional source-paths setting.
One other question related to this is the fact that I need to specify the full path of the folder for my user.clj file : "C:/Users/username/.lein/src". When I change that to "~/.lein/src" leiningen fails to load my file.
It sounds like you just want some code loaded for your lein repl sessions. This is done with the :init key of the :repl-options in your profiles.clj. You can load-file other files in init if you want to organize in that fashion.
{:user
{:repl-options
{:init (load-file "path-to-file/user.clj")}
...}}
Note: If you are using Windows-style path delimiters /, you'll need to escape them //.

Any way to add dependency to lein project without REPL restart?

What I do now is open project.clj, add dependency there, run lein deps restart repl, then use, require and so on.
The thing is that I don't really like to restart repl because the startup time is slow and I have to reload my files again.
So is there a better way to add dependency to lein project? without restarting the repl?
You can use Alembic, a dynamic classpath loader and dependencies resolver. The good thing is that it doesn't load all pomegranate dependencies.
Add the following to your .lein/profiles.clj:
{:user
{:dependencies [[alembic "0.3.2"]]}}
Then in your Repl just load the classpaths you need, they will be pulled from the repositories by leinif need:
(require 'alembic.still)
(alembic.still/distill '[enlive "1.1.5"])
(require 'net.cgrand.enlive-html) should now work.
for quick testing you can use pomegranate to add dependencies on the fly
=> (use '[cemerick.pomegranate :only (add-dependencies)])
nil
=> (add-dependencies :coordinates '[[incanter "1.2.3"]])
for actually adding a dependency I ususally hit
Alt-x nrepl-restart
ctrl-cctrl-k to reload the file,
ctrl-calt-n to get back to the namespace i in the buffer
The whole process takes the jvm startup time (which i agree is a touch painful) plus five seconds. It helps to keep your project in a state where loading a file does all the require initialization.

How to run/debug compojure web app via counterclockwise (or la clojure)

I'm trying to write my first web app in compojure. I'm using ccw, and I File-New-Project, Clojure Project and use the "compojure" leiningen template. End up with project.clj looking like
(defproject asdf "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:dependencies [[org.clojure/clojure "1.4.0"]
[compojure "1.1.5"]]
:plugins [[lein-ring "0.8.2"]]
:ring {:handler asdf.handler/app}
:profiles
{:dev {:dependencies [[ring-mock "0.1.3"]]}})
src/asdf/handler.clj looks like
(ns asdf.handler
(:use compojure.core)
(:require [compojure.handler :as handler]
[compojure.route :as route]))
(defroutes app-routes
(GET "/" [] "Hello World")
(route/not-found "Not Found"))
(def app
(handler/site app-routes))
I found I can run this using lein ring server from the command line, but I'm not sure how to run this from eclipse. I'm of course hoping to be able not only to run it, but also to debug it and set breakpoints and such. Is there a way to do this in eclipse? Or, if not, how about IntelliJ/La-Clojure? (I'm a bit afraid of emacs, for now, but maybe if it's super-simple I'd give it a try).
Or, is this just not the typical development process for a compojure app? (If not, what is? Just run lein ring server and pray?)
If it makes a difference this is on Win7.
Here's a recipe that's work great for me while developing Ring applications:
Ensure you have leiningen support properly configured for your projet (do it once if in doubt):
in the package explorer, select the project, and invoke the contextual command Leiningen > Reset configuration
then also invoke the Leiningen > Update dependencies command
you should see a Leiningen Dependencies virtual node in your project, referencing the direct and transitive dependencies of your project
Select the asdf.handler file, right click and then Debug as > Clojure Application
Open the asdf.handler namespace in an editor
With the cursor currently still in the editor, type Ctrl+Alt+N to jump to the REPL and switch the REPL's current namespace to asdf.handler at the same time
Start the app by typing (app) + Enter (or Ctrl+Enter if your cursor is not at the end of the line)
You can now navigate between the editors and the REPL.
To send editor content to the REPL, select it, and hit Ctrl+Enter
If you hit Ctrl+Enter without a selection, the whole 'top level expression' (e.g. a defn) will be sent to the REPL
To resend the whole file to the REPL, type Ctrl+Alt+S
the whole list of keyboard shortcuts specific to CCW is here: http://code.google.com/p/counterclockwise/wiki/EditorKeyBindingsFeatures
Note that a future version of Counterclockwise will integrate a little bit more with Leiningen 2, but as it currently stands, the very nature of developing ring applications make it not so painful to bootstrap things as described above, IMHO
You can run Compojure/Ring apps on IntelliJ IDEA and La Clojure with the following steps:
Generate pom.xml from leiningen's project.clj using lein pom command.
Import maven project with IntelliJ IDEA as usual. You might want to make sure that you have Clojure jar in classpath.
Once the project is loaded, you can start Clojure REPL using Tools -> Start Clojure Console.
To load a Clojure file to REPL, select Tools -> Clojure REPL -> Load file to REPL.
After that, to start a Ring app you can just load a Clojure file that invokes ring.adapter.jetty/run-jetty.
The code to run a simple route on http://localhost:4004/ would look like this:
(require 'compojure.core)
(require 'ring.adapter.jetty)
(ring.adapter.jetty/run-jetty
(compojure.core/routes (compojure.core/ANY "/" [] "Hello world!"))
{:port 4004 :join? false})
:join? option is important, if it would be set to true (the default), the REPL would not accept more commands. Your routes will usually be more complex and compojure.core/defroutes or other means should be used.
You can put such file in test path, so it wouldn't be loaded when running the project outside of IDEA.
If Clojure facet is not added to your module, you can add it in File -> Project Structure -> Modules.
A complete sample (with jetty reloading) is available here: https://github.com/tlipski/ganelon-demo - development is done with IDEA and real site runs on Heroku: http://ganelon.herokuapp.com.
Debugging Clojure apps run with the technique above is possible as well - you just have to:
Create Remote debugging Run profile in IntelliJ IDEA
Add apropriate JVM options from a profile above (e.g. agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005) to REPL settings in File -> Project Structure -> Modules -> [your module] -> Clojure facet -> JVM Arguments field.
Start REPL with Tools -> Start Clojure Console.
Start Remote debugging profile.
After that, you can add breakpoints, inspect variables, etc.