Where should I save simple configuration settings? - clojure

In my clojure Luminus/Compojure app I have this in routes.clj:
(def page-size 12)
(def images-path "/public/images/.....")
I need to move them to a config of some sort. Where is the best place? I'd like something simple and not to use any additional library on top on the ones that I'm already using which come with Luminus.

Luminus uses it's config library for configuration. You can put your configuration variables into appropriate config.edn files (per environment). Config values are available as a map stored in config.core/env. You can see an example in your <app>.core namespace:
(defn http-port [port]
;;default production port is set in
;;env/prod/resources/config.edn
(parse-port (or port (env :port))))

Ask yourself this question:
Would I ever want multiple deployments of my application where this setting differs?
If the answer to that question is "yes" then the configuration should be dictated by the environment running you application either by an edn file, Environ or other means.
If not... then you are talking about something I would categorize as an application constant, which helps avoiding magic numbers. In some situations it can improve readability by placing these in specific namespaces like so.
Constants namespace:
(ns my.app.constants)
(def page-size 12)
(def images-path "/public/images/.....")
Application:
(ns my.app.core
(:require [my.app.constants :as const)
;; now access the application constant like this
;; const/page-size
(defn image-url [image-name]
(str const/images-path "/" image-name))

Related

How to Access Environment Variables In Clojure - Luminus Web Framework

I need help accessing my environment variables. I have :my-variable "value" in dev-config.edn and I'm trying to access it in another place. I required [my-app.config :refer [env]] and trying the following:
(defn my-function []
(def variable (-> env :my-variable))
(println (str "my environment variable: " variable)))
I tried this and several other things... What's the right to do this?
Clojure can read environment variables via Java, so try this:
(System/getenv "my-variable")
Environment variables are strings, as far as Java is concerned. Whatever reads "dev-config.edn" converts your :my-variable keyword to a string. Perhaps this is it: https://github.com/yogthos/config . It mentions some details of the conversion, including "names lowercased, then _ and . characters converted to dashes".

How to properly set a timezone in a clojure REPL?

When running a query on a postgres database on a clojure REPL, the timestamps fields are presented in UTC and I need them to be in timezone America/Sao_Paulo (UTC-3)
So far I have tried the following on Intellij's REPL:
Set -Duser.timezone=America/Sao_Paulo inside the file idea.vmoptions (intellij's)
Add :jvm-opts ["-Duser.timezone=America/Sao_Paulo"] to project.clj
Add -Duser.timezone=America/Sao_Paulo in Intellij's REPL configuration
export JAVA_OPTS="-Duser.timezone=America/Sao_Paulo:$JAVA_OPTS" inside ~/.zshrc
and the following on Leiningen REPL:
Add :jvm-opts ["-Duser.timezone=America/Sao_Paulo"] to project.clj
export JAVA_OPTS="-Duser.timezone=America/Sao_Paulo:$JAVA_OPTS" inside ~/.zshrc
None worked so far!
Sample code
(ns experiments
(:require [next.jdbc :as jdbc]))
(def db
{:dbtype "postgres"
:dbname "<dbname>"
:host "<host>"
:port 5432
:user "<user>"
:password "<pass>"})
(def ds (jdbc/get-datasource db))
(jdbc/execute! ds ["select current_timestamp"])
You did not mention any Postgres options. Please study this page carefully for info and options.
If the above does not solve your problem, it may be easiest to use java.time to do the conversion. I also have some helper/convenience functions available here. Unit tests show them in action, and the source code provides examples of java.time interop from clojure.
I would avoid the older Joda Time libraries as they are obsolete (replaced by java.time). I think that Java interop is the easiest & most straightforward way to access java.time.

printing list values using let in clojure

how can I print list elements using let keyword in clojure language?
(defn build-headline-keywords-item [es-client conf common-item headline]
(let [headline headline]
(println (:headline))
(es/upsert es-client conf (merge common-item{:source ["headline"]
:type ["headline"]
:keywords headline}))))
Alan's answer covers the important parts of how to use Clojure to do this.
I'll take a different path and ask about whether this is an issue with your environment. Are you working in a REPL? Or running things in some other way? What is the actual thing you are running or evaluating?
Maybe you are using an editor where the console output is going someplace you're not seeing? For example, in Emacs the console output may go to a buffer that is not visible.
If I understand you correctly, it should look more like this:
(defn build-headline-keywords-item
[es-client conf common-item headline]
(println headline)
... )
UPDATE:
If you are still having trouble, make a test file and remove bits one-by-one until you get something that works. Then add the bits back in one at a time to build up the whole problem. It will work:
Code:
(defn build-headline [a b c headline]
(println headline))
(build-headline 1 2 3 "Space Aliens Invade!")
Result:
> lein run
Space Aliens Invade!
Please also see the online book Clojure for the Brave & True
for more information.

Clojurescript - Codox documentation for Om components

I am generating Codox documentation for a Clojurescript webapp. Here's an example function that I'll use to demonstrate my issue:
(defn breadcrumbs
"Render Breadcrumbs"
[app owner]
(om/component
(let [crumbs (:breadcrumbs app)]
(dom/div #js {:id "breadcrumbs"}
(when (> (count crumbs) 0)
(apply dom/ol #js {:className "breadcrumb os-border-default"}
(om/build-all breadcrumb crumbs)))))))
The problem is that using om/component causes Codox to generate documentation for four additional "hidden" functions (presumably these are the IRender, IDidUpdate, etc functions that can be defined for a component...but I'm not sure). In the documentation these functions look like this:
->t6127
(->t6127 crumb breadcrumb meta6128)
->t6130
(->t6130 crumb breadcrumb meta6131)
->t6133
(->t6133 owner app breadcrumbs meta6134)
->t6136
(->t6136 owner app breadcrumbs meta6137)
This unneeded documentation is greatly cluttering up the final product. I know individual functions can be skipped via "^:no-doc" but there doesn't seem to be a way to use that here.
Has anyone else experienced this and know how to get rid of the clutter?
Codox currently has problems with reify in ClojureScript, which is used internally by om/component.
David Nolen suggested that the information to distinguish these temporary values should be available in current versions of ClojureScript via the analyzer, but I haven't been able to find it, and no-one's been able to point me to it. See issue #72 on the Codox project page for more information.
om/component is a very simple macro that generates only render for IRender. It looks like Codox is giving you two functions for breadcumb (first two) and two for breadcumbs. One is probably the one you want and the other one is from render. You could either write your components like this:
(defn breadcrumbs
"Render Breadcrumbs"
[app owner]
(reify
om/IRender
(render ^:no-doc [_]
(let [crumbs (:breadcrumbs app)]
(dom/div #js {:id "breadcrumbs"}
(when (> (count crumbs) 0)
(apply dom/ol #js {:className "breadcrumb os-border- default"}
(om/build-all breadcrumb crumbs)))))))
or write your own no-doc-component macro:
(defmacro no-doc-component
[& body]
`(reify
om.core/IRender
(~(vary-meta 'render assoc :no-doc true) [this#]
~#body)))
Disclaimer: although I've tried the macro, I haven't tried it with Codox.
weevejester fixed this issue in version 0.8.11.
He also configured the ClojureScript analyzer to not analyze dependencies which allows me to generate docs for my Om projects. It should also reduce the number of namespaces in the :exclude configuration. Mine has been reduced to 0.

Clojure REPL and workflow

Coming from Haskell, my usual workflow would be to :l <file name.hs> on ghci and use the functions and ADT that I have there.
Right now I am using lein repl on a typical lein new app project context. I have created a testing.clj file next to my core.clj. There I defined a couple of functions, a protocol and a record implementing the protocol. I was able to use the function by (use 'testing.testing :reload) the problem is that I am not able to use the actual record:
(def c (Something. 0))
I get:
CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: Something
So, what would be the a "better" workflow in this case? Where I don't want to set the functions, protocols, records directly on the REPL, but also I don't want to rely on my core.cls file? I just want a file where I can dump a bunch of stuff and play with it.
PS: My env is Mac OSX Terminal + Sublime
Edit: After a couple of minutes I was able to load the record by:
(load-file <file name>)
(import 'testing.testing.Something)
I mean, for sure there is a better way than this... :/ I just want to load everything. On the other hand I am able to use the protocol methods the record implements.
Have you tried using the convenience function that is automatically defined for creating records? In this example it would be (->Something 0).
(Something. 0) is using the Java constructor, which requires importing the Java class separately. The Java class is created automatically when you define a record to allow Java interop with things you've defined in Clojure.
Using the (->Something 0) syntax is the correct way to go and should be possible after you (use 'testing.testing :reload).
Edit Given the above didn't seem to help, here's some step-by-step instructions to get a minimal working example
You have an app directory testing created with lein new app testing
In testing/src/testing you create testing.clj containing the following two lines
(ns testing.testing)
(defrecord Something [n])
Run lein repl from within your project directory
Use the namespace with (use 'testing.testing :reload)
(:n (->Something 42)) will create an instance of Something and retrieve the value of its n member - in this case 42.