How to Access Environment Variables In Clojure - Luminus Web Framework - clojure

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".

Related

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.

Where should I save simple configuration settings?

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))

How to access clojure reagent atom map variable?

I am new to Clojure and Reagent. Kindly tell how to print the variable first inside the atom variable contacts?
(def app-state
(r/atom
{:contacts [{:first "Ben" :last "Lem" :middle "Ab"}]}))
First of all: the reagent tutorial is a really good place to start. It even gives you examples to solve exactly this problem.
Since reagents atom can be treated just as a regular Clojurescript atom, you can use all your normal sequence operations. Keep in mind that in order to access the current value, you have to dereference the atom via #.If you really just want to access the first :first in your atom:
(:first (first (:contacts #app-state))) or (get (first (get #app-state :contacts)) :first)
Or, if you think it's more readable
(-> #app-state
:contacts
first
:first)
I guess what you might want to do is define a few functions to make the access more easy such as:
(defn get-contacts!
"Returns the current vector of contacts stored in the app-state."
[]
(:contacts #app-state))
(defn get-first-names!
"Return a vector of all first names in the current list of contacts in the
app-state."
[]
(mapv :first (get-contacts!)))
Please keep in mind that in reagent (and in general really) you might want to dereference that atom as fiew times as possible, so look for a good place to dereference it and just use regular functions that operate on a simple sequence instead of an atom.
Still, I would really suggest you go read the aforementioned reagent tutorial.
Here is a concise way to access the value that you are looking for using Clojure's (get-in m ks) function:
(get-in #app-state [:contacts 0 :first])
Just as an extra, you may see this often written as
(->> #app-state
:contacts
(mapv :first)
first
and it's useful to understand what's going on here.
->> is a macro called thread-last which will re-write the code above to be
(first (mapv :first (:contacts #app-state)))
Thread last is a bit weird at first but it makes the code more readable when lots of things are going on. I suggest that on top of the reagent tutorial mentioned in the other comments, you read this.
#app-state will give you whatever is inside the r/atom and (:first (first (:contacts #app-state))) will return the first element and (println (:first (first (:contacts #app-state)))) will print output to the browser console (so you need to have the developer tools console open to see it).
Note that for println to output to the browser developer tools console you need to have this line in your code:
(enable-console-print!)

How can I use *data-readers* with edn?

I tried to follow the documentation for clojure.instant/read-instant-timestamp, which reads:
clojure.instant/read-instant-timestamp
To read an instant as a java.sql.Timestamp, bind *data-readers* to a
map with this var as the value for the 'inst key. Timestamp preserves
fractional seconds with nanosecond precision. The timezone offset will
be used to convert into UTC.`
The following result was unexpected:
(do
(require '[clojure.edn :as edn])
(require '[clojure.instant :refer [read-instant-timestamp]])
(let [instant "#inst \"1970-01-01T00:00:09.999-00:00\""
reader-map {'inst #'read-instant-timestamp}]
;; This binding is not appearing to do anything.
(binding [*data-readers* reader-map]
;; prints java.util.Date -- unexpected
(->> instant edn/read-string class println)
;; prints java.sql.Timestamp -- as desired
(->> instant (edn/read-string {:readers reader-map}) class println))))
How can I use the *data-readers* binding? Clojure version 1.5.1.
clojure.edn functions by default only use data readers stored in clojure.core/default-data-readers which, as of Clojure 1.5.1, provides readers for instant and UUID literals. If you want to use custom readers, you can do that by passing in a :readers option; in particular, you can pass in *data-readers*. This is documented in the docstring for clojure.edn/read (the docstring for clojure.edn/read-string refers to that for read).
Here are some examples:
(require '[clojure.edn :as edn])
;; instant literals work out of the box:
(edn/read-string "#inst \"2013-06-08T01:00:00Z\"")
;= #inst "2013-06-08T01:00:00.000-00:00"
;; custom literals can be passed in in the opts map:
(edn/read-string {:readers {'foo identity}} "#foo :asdf")
;= :asdf
;; use current binding of *data-readers*
(edn/read-string {:readers *data-readers*} "...")
(The following section added in response to comments made by Richard Möhn in this GitHub issue's comment thread. The immediate question there is whether it is appropriate for a reader function to call eval on the data passed in. I am not affiliated with the project in question; please see the ticket for details, as well as Richard's comments on the present answer.)
It is worth adding that *data-readers* is implicitly populated from any data_readers.{clj,cljc} files that Clojure finds at the root of the classpath at startup time. This can be convenient (it allows one to use custom tagged literals in Clojure source code and at the REPL), but it does mean that new data readers may appear in there with a change to a single dependency. Using an explicitly constructed reader map with clojure.edn is a simple way to avoid surprises (which could be particularly nasty when dealing with untrusted input).
(Note that the implicit loading process does not result in any code being loaded immediately, or even when a tag mentioned in *data-readers* is first encountered; the process which populates *data-readers* creates empty namespaces with unbound Vars as placeholders, and to actually use those readers one still has to require the relevant namespaces in user code.)
The *data-readers* dynamic var seems to apply to the read-string and read functions from clojure.core only.
(require '[clojure.instant :refer [read-instant-timestamp]])
(let [instant "#inst \"1970-01-01T00:00:09.999-00:00\""
reader-map {'inst #'read-instant-timestamp}]
;; This will read a java.util.Date
(->> instant read-string class println)
;; This will read a java.sql.Timestamp
(binding [*data-readers* reader-map]
(->> instant read-string class println)))
Browsing through the source code for clojure.edn reader here, I couldn't find anything that would indicate that the same *data-readers* var is used at all there.
clojure.core's functions read and read-string use LispReader (which uses the value from *data-readers*), while the functions from clojure.edn use the EdnReader.
This edn library is relatively new in Clojure so that might be the reason why the documentation string is not specific enough regarding edn vs. core reader, which can cause this kind of confusion.
Hope it helps.

Multilingual doc support for Clojure

Is there any kind of multilingual documentation support for functions? I am from Turkey. I want people to write in Clojure and I dream a line like
(doc hello-world "Turkish")
As of today there's no such feature built into the language. You can attach arbitrary metadata to vars, though:
(defn ^{:docs {:en "Prints and returns its argument"
:es "Imprime y devuelve su argumento"}}
debug [x]
(println x)
x)
Recall that Clojure's documentation system uses the :doc metadata keyword name. So you'd have to pick another name (e.g. :docs).
Then you could redefine functions such as clojure.repl/doc so they take into account your metadata.