I'm new to CLojure and running a simple piece of code to test out the data.csv package. I'm using Leiningen and running on Windows 7 (having no choice). Leiningen was installed with the Windows installer. JDE 1.7 is installed and available.
Here is my source file:
(ns testcsv.core
(:gen-class))
(:require [clojure.data.csv :as csv])
(:require [clojure.java.io :as io]))
(defn add-data-store []
(let [csv-records (csv/parse-csv (slurp "census_data_growth.csv")) ;field-names (nthnext (second csv-records) 3)
]
;; more code to come when this works
))
Here is my project.clj:
(defproject testcsv "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.6.0"]
[org.clojure/data.csv "0.1.2"]]
:main ^:skip-aot powernoodle1.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}})
I've run lein deps and lein classpath and lein compile in many combinations. The error from lein compile is:
java.lang.ClassNotFoundException: clojure.data.csv, compiling:(testcsv/core.clj:4:1)
Which would seem to imply that it is not finding the data.csv jar, which would in turn seem to imply a classpath problem.
Is there a step I've missed?
I've also heard that Leiningen has classpath issues on Windows. Does anyone have specifics?
:require needs to be part of your ns declaration. Also the declaration should have only one :require clause.
(ns testcsv.core
(:gen-class)
(:require [clojure.data.csv :as csv]
[clojure.java.io :as io]))
require (the function, not the keyword) can be used outside an ns declaration, mostly for repl usage. It would look like (require '[clojure.data.csv :as csv]).
Because of an implementation detail of keywords being overloaded to be usable as functions to perform lookup, (:foo x) is never an error if :foo is some keyword, and x exists, no matter what x is.
Related
I'm using
[ics#steamboy util]$ lein version
Leiningen 2.5.1 on Java 1.7.0_91 OpenJDK Server VM
with Clojure 1.6
In lein repl I used to be able to call a function from within repl.
util.core=> (load-file "src/util/core.clj")
#'util.core/-main
util.core=> (bldg-sqft-test)
And execute a function from within the repl.
(defn ret-val-from-sos
"Takes a value, a map key, an s-o-s, and returns first match."
[in-val map-key-1 map-key-2 s-o-s]
(doseq [x s-o-s]
(println (str (first x)))))
(defn bldg-sqft-test
[& args]
(let [bldg-cols (fetch-csv-data "bldg_sqft_cols.csv")
bldg-data (fetch-csv-data "Buildingsqft.csv")
mapped-data (xform-sos-in bldg-data bldg-cols)
my-bldg-sqft (ret-val-from-sos (str 70782) (keyword "Bill#") (keyword "Fin. Area") mapped-data)]
my-bldg-sqft))
Debugging was easier, when I could examine variables in repl. As a workaround, I've converted a library to run with a main, but it's not as effective as repl debugging
What settings/configuration do I need to do call functions from within the repl?
When you run $ lein repl a JVM instance is started and it loads all the namespaces in your classpath, so (load-file "example.clj") isn't necessary.
The correct sequence for what you're trying to do is:
$ lein repl
user=>(require 'util.core)
nil
user=>(in-ns 'my-ns.core)
nil
my-ns.core=>(bldg-sqft-test)
or
$ lein repl
user=>(require '[util.core :refer :all])
nil
user=>(bldg-sqft-test)
If you somehow need to load a external .clj file then (load-file "external.clj") will add the file to the classpath and then you can require the namespace as above.
I have a small Clojure webapp built with ring and compojure. Although the webapp runs find locally on my laptop, when I push to Heroku the app crashes. The specific error from the logs is
Starting process with command `java $JVM_OPTS lein ring server-headless 3000`
app[web.1]: Error: Could not find or load main class lein
app[web.1]: Picked up JAVA_TOOL_OPTIONS: -Xmx384m -Djava.rmi.server.useCodebaseOnly=true
heroku[web.1]: State changed from starting to crashed
My project.clj look like
(defproject hn-clj "0.1.1"
:description "foo"
:url "http://foo"
:min-lein-version "2.0.0"
:dependencies [[org.clojure/clojure "1.6.0"]
[compojure "1.3.1"]
[ring/ring-defaults "0.1.2"]
[clj-http-lite "0.2.0"]
[cheshire "5.4.0"]
[hiccup "1.0.5"]]
:plugins [[lein-ring "0.8.13"]]
:ring {:handler hn-clj.core.handler/app}
:profiles
{:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
[ring-mock "0.1.5"]]}}
)
The entry-point for the application is in src/core/handler.clj
(ns hn-clj.core.handler
(:require [compojure.core :refer :all]
[compojure.route :as route]
[compojure.handler :as handler]
[ring.middleware.defaults :refer [wrap-defaults site-defaults]]
[hn-clj.core.controllers.story :as story]
[hn-clj.core.controllers.users :as users]
))
(defroutes app-routes
(GET "/" [limit] (story/index limit))
(GET "/stories/:id" [id] (story/show-story id))
(GET "/users/:username" [username] (users/show username)))
(def app
(wrap-defaults app-routes site-defaults))
Locally the app runs find with lein ring server-headless 3000 and in my Procfile I have put
web: java $JVM_OPTS lein ring server-headless 3000
Although I haven't created a main- function, this doesn't prohibit the app from running locally, I don't understand why the app won't run when deployed to Heroku. How should I refactor the handler.clj or the Procfile?
Your procfile should be something like this:
web: lein ring server-headless $PORT
To check your application can run properly on heroku, you can use a foreman port, which makes use of the procfile.
These days I am using gaffer, and the documentation on Procfile for Heroku is here.
I am working on the Heroku tutorial to get started with Clojure but I am having difficulty with the names and locations of my files.
I put the source file world.clj in src: src/hello/world.clj as instructed. This is my directory now
C:\Users\a\CLOJURE\P2\helloworld\src\hello\world.clj
This is my project.clj
(defproject helloworld "1.0.0-SNAPSHOT"
:description "helloworld project to test heroku and clojure"
:url "http://helloworld.herokuapp.com"
:license {:name "license1"
:url "http://example.com/FIXME"}
:dependencies [[org.clojure/clojure "1.4.0"]
[compojure "1.1.1"]
[ring/ring-jetty-adapter "1.1.0"]
[ring/ring-devel "1.1.0"]
[ring-basic-authentication "1.0.1"]
[environ "0.2.1"]
[com.cemerick/drawbridge "0.0.6"]]
:min-lein-version "2.0.0"
:plugins [[environ/environ.lein "0.2.1"]]
:hooks [environ.leiningen.hooks]
:profiles {:production {:env {:production true}}})
When I try to run this locally with lein run -m hello.world 5000
I get the following error
C:\Users\a\CLOJURE\P2>lein run -m hello.world 5000
java.io.FileNotFoundException: Could not locate hello/world__init.class or
hello/world.clj on classpath:
....
Can you explain what is the best way to organize my files and naming conventions?
EDIT
I created a CLASSPATH as Environment Variable and added C:\Users\a\CLOJURE\P2\helloworld\src\hello but I still get the same error.
Here is:
$ cd clojure_project
$ lein run -m hello.world 5000
http://pastie.org/8379858
So, I'm a clojure n00b, and I'm missing something when trying to get the routes for a project I'm building working.
I had some issues with circular dependencies, and after working with Django, I think it's much better to have routes all defined in one place, rather than peppered all over the codebase as seems to be done with defpage.
Onto the code:
This is my core.clj file:
(ns blktechies-home.core
(:use compojure.core
hiccup.middleware)
(:require [compojure.route :as route]
[blktechies-home.routes :as site-routes]
[compojure.handler :as handler]
[compojure.response :as response]))
(def app
(-> (handler/site site-routes/app)
(wrap-base-url)))
Then in my routes file I have the following:
(ns blktechies-home.routes
(:use compojure.core
noir.core
hiccup.middleware)
(:require [compojure.route :as route]
[compojure.handler :as handler]
[compojure.response :as response]
[blktechies-home.views.common :as common]))
(defroutes app
(GET "/" [] (common/main-layout
(welcome/index-page)))
(route/resources "/")
(route/not-found "<h1>NOPE</h1>"))
Everything is 404'ing, and I'm not even sure where to go from here. I was able to use the site with defpage, but it just seemed ugly and not extensible as the number of routes grows.
So
What am I doing wrong here? Any insight into the underlying compojure/clojure/ring layers would be awesome
If this isn't the best way to define routes, what is?
Are there any good examples of big clj-noir sites on github? (My google-fu has failed me.)
In Noir you can put all your defpage's in the same namespace, one after another if you want to have them all in the same place. They can be as simple as delegating to other functions to do the "real" work, the same way you have defined the (GET "/" ...) route in your example.
What am I doing wrong here? Any insight into the underlying compojure/clojure/ring layers would be awesome
Not sure what are you doing wrong, your code works for me with a couple of minimal changes:
The core with just adding the ring.adapter.jetty to start a jetty server when loading the file:
(ns blktechies-home.core
(:use compojure.core
hiccup.middleware
[ring.adapter.jetty :only [run-jetty]])
(:require [compojure.route :as route]
[blktechies-home.routes :as site-routes]
[compojure.handler :as handler]
[compojure.response :as response]))
(def app
(-> (handler/site site-routes/app)
(wrap-base-url)))
(run-jetty app {:port 8080 :join? false})
Your routes file, without "views.common" namespace:
(ns blktechies-home.routes
(:use compojure.core
noir.core
hiccup.middleware)
(:require [compojure.route :as route]
[compojure.handler :as handler]
[compojure.response :as response]))
(defroutes app
(GET "/" [] "the root path")
(route/resources "/")
(route/not-found "<h1>NOPE</h1>"))
Now starting the repl:
lein repl
And loading the core:
user=> (load-file "src/blktechies_home/core.clj")
#<Server Server#9ae1ab>
And wgetting the root:
wget http://localhost:8080/ -O - -q
the root path
Maybe you would find this page helpful Global Noir Routes (implementation of a defpage macro variant that allows defining routes in one place).
I'm playing around with deploying Clojure/Noir apps on Heroku and I've got my app mostly working. However, one final piece I need is to figure out the hostname of my app when deployed on Heroku. Ideally, I want to do this dynamically instead of hard-coding it.
So, if for example, my app's URL is 'http://freez-windy-1800.herokuapp.com', I want to be able to dynamically get this within my clojure code.
I know that I can look at the incoming request to figure this out, but ideally, I'd like to have some sort of 'setting' where I evaluate an expression once and save the value in a variable that I can then use (coming from the Python/Django world, I'm thinking of the settings.py equivalent in Clojure).
For reference, the code I'm deploying is available at https://github.com/rmanocha/cl-short.
You could set an environment variable in Heroku by
heroku config:add BASE_IRI=http://freez-windy-1800.herokuapp.com
and read it back in Clojure
(defn- base-iri []
(or (System/getenv "BASE_IRI") "http://localhost/"))
Heroku already sets the PORT you can use
(defn -main []
(let [port (Integer. (or (System/getenv "PORT") 8080))]
(run-jetty #'app {:port port})))
Works for me in different environments.
You would typically do this with InetAddress from the Java standard library.
(.getCanonicalHostName (java.net.InetAddress/getLocalHost))
This, however, does not do a DNS lookup.
3 ways to get the hostname. Use as you wish.
(ns service.get-host-name
(require [clojure.java.shell :as shell]
[clojure.string :as str])
(:import [java.net InetAddress]))
(defn- hostname []
(try
(-> (shell/sh "hostname") (:out) (str/trim))
(catch Exception _e
(try
(str/trim (slurp "/etc/hostname"))
(catch Exception _e
(try
(.getHostName (InetAddress/getLocalHost))
(catch Exception _e
nil)))))))