0
\$\begingroup\$

I'm learning Clojure and I'm doing a little thing that reads direct messages from Twitter using twitter-api wrapper. The code doing that is below.

(ns twitterbot.my-twitter
    (:require [twitter.oauth :refer [make-oauth-creds]]
              [twitter.api.restful :refer [direct-messages]]
              [clojure.edn :as edn]
              [clojure.string :as string]))

(defn- load-credentials [filename]
  (edn/read-string (slurp filename)))

(def ^:private credentials-from-file (load-credentials "credentials.edn"))

(def ^:private oauth-credentials
  (make-oauth-creds (credentials-from-file :consumerkey)
                    (credentials-from-file :consumersecret)
                    (credentials-from-file :usertoken)
                    (credentials-from-file :usersecret)))

(defn- has-url? [message]
  (seq (:urls (:entities message))))

(defn- trusted-user? [message]
  (= (credentials-from-file :trusteduser) (:sender_screen_name message)))

(defn- get-url [message]
  (:expanded_url (nth (:urls (:entities message)) 0)))

(defn links-from-direct-messages []
  (let [messages (direct-messages :oauth-creds oauth-credentials)]
    (map get-url (filter has-url? (filter trusted-user? (:body messages))))))

As I'm new to Clojure, I would like to know whether I'm doing things in the correct way and how to do them better. I feel like the coding style and layout is off at least in links-from-direct-messages, but I even though I tried to follow this style guide, I'm not sure how it should be. Also as the data structure from Twitter is quite nested, I wonder how I should be going through them.

\$\endgroup\$
2
\$\begingroup\$

Your get-url function could just use get-in:

(defn- get-url [message]
  (get-in message [:entities :urls 0 :expanded_url]))

links-from-direct-messages has quite a lot of nested calls. When you've got a bunch of nested operations like that it can be nice to re-write them using one of the threading macros (-> and ->>). These take an input, and then "thread" it through a series of forms as the first (in the case of ->) or last (in the case of ->>) argument. By doing this, they allow you to rewrite nested calls sequentially.

This is mentioned in the style guide you linked.

In the case of links-from-direct-messages you're calling map and filter, which both accept the collection as their last argument, so you can use ->>:

(defn links-from-direct-messages []
  (->> (direct-messages :oauth-creds oauth-credentials)
       :body
       (filter trusted-user?)
       (filter has-url?)
       (map get-url)))
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.