Fork me on GitHub
#beginners
<
2021-03-23
>
SoV401:03:43

is there a way to query the duration of a sound file such as an mp3 that has metadata and know the time-duration of the mp3 ? java interop probably?

blak3mill3r02:03:38

or this https://github.com/Raynes/conch instead of clojure.java.shell

SoV403:03:40

Oh my ... ask the shell... this opens up a whole new world

prit01:03:18

I have the following namespace declaration that I’m trying to evaluate:

(ns foo.events
  (:require
   [re-frame.core :as rf :refer [reg-event-fx reg-event-db after reg-sub reg-cofx inject-cofx reg-fx]]
   [cljs.core.async :refer [<!]]
   [goog.style :as gs]
   [reagent.core :as r]
   [re-frame.core :refer [subscribe dispatch]]
   [ajax.edn :as edn]
   [ajax.core :refer [json-response-format raw-response-format json-request-format] :as ajax]
   [humboi.db :refer [app-db]]
   [day8.re-frame.http-fx]
   [cljs.core.async :refer [go]]
   [cljs.core.async.interop :refer-macros [<p!]]
   ["@react-native-async-storage/async-storage" :default AsyncStorage]
   ["@react-native-community/cameraroll" :as CameraRoll]
   ["expo-media-library" :as MediaLibrary] ;; register error ;; doesn't work on simulator
   ["react-native-image-picker" :refer [launchImageLibrary]]
   ["@react-navigation/native" :refer [useNavigation]]
   [cognitect.transit :as t]
   ["@segment/analytics-react-native" :default analytics]
   ["@segment/analytics-react-native-mixpanel" :default mixpanel]
   ["@segment/analytics-react-native-google-analytics" :default google-analytics]
   [react-native-background-actions :default BackgroundService]
   [react-native-background-upload :default Upload]

   ))
However, upon evaluating it, I’m getting the following error:
2. Unhandled clojure.lang.Compiler$CompilerException
   Error compiling src/humboi/events.cljs at (1:1)
   #:clojure.error{:phase :macro-syntax-check,
                   :line 1,
                   :column 1,
                   :source
                   "/Users/prikshetsharma/Desktop/Humboi/src/humboi/events.cljs",
                   :symbol clojure.core/ns}
             Compiler.java: 6971  clojure.lang.Compiler/checkSpecs
             Compiler.java: 6987  clojure.lang.Compiler/macroexpand1
             Compiler.java: 7074  clojure.lang.Compiler/macroexpand
             Compiler.java: 7160  clojure.lang.Compiler/eval
             Compiler.java: 7131  clojure.lang.Compiler/eval
                  core.clj: 3214  clojure.core/eval
                  core.clj: 3210  clojure.core/eval
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn/fn
                  AFn.java:  152  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  core.clj:  665  clojure.core/apply
                  core.clj: 1973  clojure.core/with-bindings*
                  core.clj: 1973  clojure.core/with-bindings*
               RestFn.java:  425  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn
                  main.clj:  414  clojure.main/repl/read-eval-print/fn
                  main.clj:  414  clojure.main/repl/read-eval-print
                  main.clj:  435  clojure.main/repl/fn
                  main.clj:  435  clojure.main/repl
                  main.clj:  345  clojure.main/repl
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   84  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   56  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  152  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  202  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  201  nrepl.middleware.session/session-exec/main-loop
                  AFn.java:   22  clojure.lang.AFn/run
               Thread.java:  748  java.lang.Thread/run

1. Caused by clojure.lang.ExceptionInfo
   Call to clojure.core/ns did not conform to spec.
   #:clojure.spec.alpha{:problems
                        [{:path [],
                          :reason "Extra input",
                          :pred
                          (clojure.spec.alpha/cat
     ...

prit01:03:26

Why is this?

seancorfield02:03:55

You’ve omitted the piece of the error that actually tells you why it was rejected by the compiler. What does the rest of this Spec failure say:

#:clojure.spec.alpha{:problems
                        [{:path [],
                          :reason "Extra input",
                          :pred
                          (clojure.spec.alpha/cat

hiredman02:03:11

Is :default a thing?

seancorfield02:03:14

Also, why change (ns humboi.events to (ns foo.events in your code paste when your error messages still show the full filename?

😅 2
seancorfield02:03:23

It’s ClojureScript so I dunno.

dpsutton02:03:42

in cljs yeah.

dpsutton02:03:06

or at least in shadow. i'm not sure if that's an extension to work with npm deps

seancorfield02:03:07

But looking at the failure, I think it’s getting evaluated as Clojure and it’s illegal in Clojure?

dpsutton02:03:57

this didn't pass validation for me on a bare cljs repl. are you using shadow cljs?

dpsutton02:03:29

Unexpected error (ExceptionInfo) compiling at (<cljs repl>:1:1).
Only :as, :refer and :rename options supported in :require / :require-macros; offending spec: ["@react-native-async-storage/async-storage" :default AsyncStorage] at line 1 <cljs repl>
in cljs.main

prit02:03:11

yes I’m using shadow cljs

prit02:03:59

but the repl I’m running is shadow-cljs so why does it complain about :default? This is the error I get when I evaluate in cider

prit02:03:26

Show: Project-Only All Hide: Clojure Java REPL Tooling Duplicates (15 frames hidden) 2. Unhandled clojure.lang.Compiler$CompilerException Error compiling src/humboi/events.cljs at (1:1) #:clojure.error{:phase :macro-syntax-check, :line 1, :column 1, :source “/Users/prikshetsharma/Desktop/Humboi/src/humboi/events.cljs”, :symbol clojure.core/ns} Compiler.java: 6971 clojure.lang.Compiler/checkSpecs Compiler.java: 6987 clojure.lang.Compiler/macroexpand1 Compiler.java: 7074 clojure.lang.Compiler/macroexpand Compiler.java: 7160 clojure.lang.Compiler/eval Compiler.java: 7131 clojure.lang.Compiler/eval core.clj: 3214 clojure.core/eval core.clj: 3210 clojure.core/eval interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn/fn AFn.java: 152 clojure.lang.AFn/applyToHelper AFn.java: 144 clojure.lang.AFn/applyTo core.clj: 665 clojure.core/apply core.clj: 1973 clojure.core/with-bindings* core.clj: 1973 clojure.core/with-bindings* RestFn.java: 425 clojure.lang.RestFn/invoke interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn main.clj: 414 clojure.main/repl/read-eval-print/fn main.clj: 414 clojure.main/repl/read-eval-print main.clj: 435 clojure.main/repl/fn main.clj: 435 clojure.main/repl main.clj: 345 clojure.main/repl RestFn.java: 1523 clojure.lang.RestFn/invoke interruptible_eval.clj: 84 nrepl.middleware.interruptible-eval/evaluate interruptible_eval.clj: 56 nrepl.middleware.interruptible-eval/evaluate interruptible_eval.clj: 152 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn AFn.java: 22 clojure.lang.AFn/run session.clj: 202 nrepl.middleware.session/session-exec/main-loop/fn session.clj: 201 nrepl.middleware.session/session-exec/main-loop AFn.java: 22 clojure.lang.AFn/run Thread.java: 748 java.lang.Thread/run 1. Caused by clojure.lang.ExceptionInfo Call to clojure.core/ns did not conform to spec. #:clojure.spec.alpha{:problems [{:path [], :reason “Extra input”, :pred (clojure.spec.alpha/cat :docstring (clojure.spec.alpha/? clojure.core/string?) :attr-map (clojure.spec.alpha/? clojure.core/map?) :ns-clauses :clojure.core.specs.alpha/ns-clauses), :val ((:require [re-frame.core :as rf :refer [reg-event-fx reg-event-db after reg-sub reg-cofx inject-cofx reg-fx]] [cljs.core.async :refer [<!]] [goog.style :as gs] [reagent.core :as r] [re-frame.core :refer [subscribe dispatch]] [ajax.edn :as edn] [ajax.core :refer [json-response-format raw-response-format json-request-format] :as ajax] [humboi.db :refer [app-db]] [day8.re-frame.http-fx] [cljs.core.async :refer [go]] [cljs.core.async.interop :refer-macros [<p!]] [“@react-native-async-storage/async-storage” :default AsyncStorage] [“@react-native-community/cameraroll” :as CameraRoll] [“expo-media-library” :as MediaLibrary] [“react-native-image-picker” :refer [launchImageLibrary]] [“@react-navigation/native” :refer [useNavigation]] [cognitect.transit :as t] [“@segment/analytics-react-native” :default analytics] [“@segment/analytics-react-native-mixpanel” :default mixpanel] [“@segment/analytics-react-native-google-analytics” :default google-analytics] [react-native-background-actions :default BackgroundService] [react-native-background-upload :default Upload])), :via [:clojure.core.specs.alpha/ns-form], :in [1]}], :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2509 0x21a7b90c “[email protected]”], :value (humboi.events (:require [re-frame.core :as rf :refer [reg-event-fx reg-event-db after reg-sub reg-cofx inject-cofx reg-fx]] [cljs.core.async :refer [<!]] [goog.style :as gs] [reagent.core :as r] [re-frame.core :refer [subscribe dispatch]] [ajax.edn :as edn] [ajax.core :refer [json-response-format raw-response-format json-request-format] :as ajax] [humboi.db :refer [app-db]] [day8.re-frame.http-fx] [cljs.core.async :refer [go]] [cljs.core.async.interop :refer-macros [<p!]] [“@react-native-async-storage/async-storage” :default AsyncStorage] [“@react-native-community/cameraroll” :as CameraRoll] [“expo-media-library” :as MediaLibrary] [“react-native-image-picker” :refer [launchImageLibrary]] [“@react-navigation/native” :refer [useNavigation]] [cognitect.transit :as t] [“@segment/analytics-react-native” :default analytics] [“@segment/analytics-react-native-mixpanel” :default mixpanel] [“@segment/analytics-react-native-google-analytics” :default google-analytics] [react-native-background-actions :default BackgroundService] [react-native-background-upload :default Upload])), :args (humboi.events (:require [re-frame.core :as rf :refer [reg-event-fx reg-event-db after reg-sub reg-cofx inject-cofx reg-fx]] [cljs.core.async :refer [<!]] [goog.style :as gs] [reagent.core :as r] [re-frame.core :refer [subscribe dispatch]] [ajax.edn :as edn] [ajax.core :refer [json-response-format raw-response-format json-request-format] :as ajax]

prit02:03:27

[humboi.db :refer [app-db]] [day8.re-frame.http-fx] [cljs.core.async :refer [go]] [cljs.core.async.interop :refer-macros [<p!]] [“@react-native-async-storage/async-storage” :default AsyncStorage] [“@react-native-community/cameraroll” :as CameraRoll] [“expo-media-library” :as MediaLibrary] [“react-native-image-picker” :refer [launchImageLibrary]] [“@react-navigation/native” :refer [useNavigation]] [cognitect.transit :as t] [“@segment/analytics-react-native” :default analytics] [“@segment/analytics-react-native-mixpanel” :default mixpanel] [“@segment/analytics-react-native-google-analytics” :default google-analytics] [react-native-background-actions :default BackgroundService] [react-native-background-upload :default Upload]))} alpha.clj: 705 clojure.spec.alpha/macroexpand-check alpha.clj: 697 clojure.spec.alpha/macroexpand-check AFn.java: 156 clojure.lang.AFn/applyToHelper AFn.java: 144 clojure.lang.AFn/applyTo Var.java: 705 clojure.lang.Var/applyTo Compiler.java: 6969 clojure.lang.Compiler/checkSpecs Compiler.java: 6987 clojure.lang.Compiler/macroexpand1 Compiler.java: 7074 clojure.lang.Compiler/macroexpand Compiler.java: 7160 clojure.lang.Compiler/eval Compiler.java: 7131 clojure.lang.Compiler/eval core.clj: 3214 clojure.core/eval core.clj: 3210 clojure.core/eval interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn/fn AFn.java: 152 clojure.lang.AFn/applyToHelper AFn.java: 144 clojure.lang.AFn/applyTo core.clj: 665 clojure.core/apply core.clj: 1973 clojure.core/with-bindings* core.clj: 1973 clojure.core/with-bindings* RestFn.java: 425 clojure.lang.RestFn/invoke interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn main.clj: 414 clojure.main/repl/read-eval-print/fn main.clj: 414 clojure.main/repl/read-eval-print main.clj: 435 clojure.main/repl/fn main.clj: 435 clojure.main/repl main.clj: 345 clojure.main/repl RestFn.java: 1523 clojure.lang.RestFn/invoke interruptible_eval.clj: 84 nrepl.middleware.interruptible-eval/evaluate interruptible_eval.clj: 56 nrepl.middleware.interruptible-eval/evaluate interruptible_eval.clj: 152 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn AFn.java: 22 clojure.lang.AFn/run session.clj: 202 nrepl.middleware.session/session-exec/main-loop/fn session.clj: 201 nrepl.middleware.session/session-exec/main-loop AFn.java: 22 clojure.lang.AFn/run Thread.java: 748 java.lang.Thread/run

blak3mill3r02:03:04

@ps what is :default ? Is this something specific to shadow-cljs? I couldn't find any documentation for it, and I've never seen it in a require form before, and as dpsutton pointed out it does not pass the validation with plain cljs

blak3mill3r02:03:53

also slack snippets are great for long blocks of code or stacktraces

blak3mill3r02:03:04

v-- that lightning bolt lets you make snippets

seancorfield02:03:31

Looking at that stack trace, I’m fairly certain this is getting evaluated as either regular Clojure or regular ClojureScript rather than actually evaluating into Shadow-cljs’s REPL. I was hoping for more of a clue in the full Spec failure but I don’t see anything that nails it down further.

prit02:03:17

so this is a problem with cider?

blak3mill3r02:03:25

:default seems like the obvious culprit, it is specific to shadow-cljs

blak3mill3r02:03:45

@ps can you try it from shadow-cljs's repl in the terminal?

prit02:03:00

yeah, it’s still giving the error

blak3mill3r02:03:12

odd... since the error message unfortunately doesn't have much to narrow it down, I would try commenting out or removing parts of the namespace form, and pasting it into the shadow-cljs repl until you identify the part that breaks it

prit02:03:26

wait, it won’t be exactly the same right?

blak3mill3r02:03:36

what if you remove all these :default requires?

blak3mill3r02:03:21

well it might help identify the problem (not fix it)

blak3mill3r02:03:38

the problem you have now is that the clojurescript compiler doesn't consider your ns form valid

prit02:03:44

(ns humboi.events
  (:require
   [re-frame.core :as rf :refer [reg-event-fx reg-event-db after reg-sub reg-cofx inject-cofx reg-fx]]
   [cljs.core.async :refer [<!]]
   [goog.style :as gs]
   [reagent.core :as r]
   [re-frame.core :refer [subscribe dispatch]]
   [ajax.edn :as edn]
   [ajax.core :refer [json-response-format raw-response-format json-request-format] :as ajax]
   [humboi.db :refer [app-db]]
   [day8.re-frame.http-fx]
   [cljs.core.async :refer [go]]
   [cljs.core.async.interop :refer-macros [<p!]]
   ;;["@react-native-async-storage/async-storage" :default AsyncStorage]
   ["@react-native-community/cameraroll" :as CameraRoll]
   ["expo-media-library" :as MediaLibrary] ;; register error ;; doesn't work on simulator
   ["react-native-image-picker" :refer [launchImageLibrary]]
   ["@react-navigation/native" :refer [useNavigation]]
   ;;["@segment/analytics-react-native" :default analytics]
   ;;["@segment/analytics-react-native-mixpanel" :default mixpanel]
   ;;["@segment/analytics-react-native-google-analytics" :default google-analytics]
   ;;[react-native-background-actions :default BackgroundService]
   ;;[react-native-background-upload :default Upload]

   ))
still doesn’t work. Same error

blak3mill3r02:03:15

I don't see the problem. I'll try it in a shadow-cljs repl.

prit02:03:00

yes shadow-cljs repl too gives the same error

dpsutton02:03:10

Is this a web app

prit02:03:28

In fact just doing this:

(ns humboi.events
  (:require
   [re-frame.core :as rf :refer [reg-event-fx reg-event-db after reg-sub reg-cofx inject-cofx reg-fx]] 
   [reagent.core :as r]
   [re-frame.core :refer [subscribe dispatch]]
   [ajax.edn :as edn]
   [ajax.core :refer [json-response-format raw-response-format json-request-format] :as ajax]
   [day8.re-frame.http-fx]
   [cljs.core.async :refer [go]]
   ))
gives:
1. Unhandled java.io.FileNotFoundException
   Could not locate day8/re_frame/http_fx__init.class, day8/re_frame/http_fx.clj
   or day8/re_frame/http_fx.cljc on classpath. Please check that namespaces with
   dashes use underscores in the Clojure file name.

dpsutton02:03:48

Yeah. You’re in a clojure repl

prit02:03:53

this is web I think since it’s react native

blak3mill3r02:03:03

it would be trying to locate a .cljs file

blak3mill3r02:03:05

if it were cljs

blak3mill3r02:03:19

instead it is looking for a .clj file which definitely indicates it is a jvm clojure repl

dpsutton02:03:32

You need to read the documentation for shadow about how to get your repl going

blak3mill3r02:03:16

can you share any more of this project? the shadow-cljs.edn file and package.json list all these library dependencies, right?

blak3mill3r02:03:50

I generated a new shadow-cljs project using npx create-cljs-project xyz

blak3mill3r02:03:01

and I can get a clojurescript Node.js repl like this

blak3mill3r02:03:14

from that xyz directory: shadow-cljs node-repl

blak3mill3r02:03:57

and the prompt looks like this: cljs.user=>

prit02:03:11

{:deps true
  :builds
 {:test
  {:target    :npm-module
   :output-dir "test-out"
   :entries [humboi.core-test]}
  :dev
  {:target     :react-native
   :init-fn    humboi.core/init
   :output-dir "app"
   :compiler-options {:closure-defines
                      {"re_frame.trace.trace_enabled_QMARK_" true}}
   ;;:devtools {:preloads [devtools.preload]}
   }}}

andy.fingerhut17:03:26

@ps Please put longer messages like this inside of a "reply thread" on Slack, to avoid having large blocks of text at the top level that some people might not want to see. Another technique is to publish such text on Github, perhaps as a "Gist", and paste only a link to it in Slack.

prit02:03:34

{
  "name": "Humboi",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "lint": "eslint ."
  },
  "dependencies": {
    "@react-native-async-storage/async-storage": "^1.13.2",
    "@react-native-community/art": "^1.2.0",
    "@react-native-community/cameraroll": "^4.0.1",
    "@react-native-community/cli": "^4.13.1",
    "@react-native-community/datetimepicker": "^3.0.9",
    "@react-native-community/geolocation": "^2.0.2",
    "@react-native-community/google-signin": "^5.0.0",
    "@react-native-community/masked-view": "^0.1.10",
    "@react-navigation/bottom-tabs": "^5.11.3",
    "@react-navigation/material-top-tabs": "^5.3.13",
    "@react-navigation/native": "^5.9.0",
    "@react-navigation/stack": "^5.14.2",
    "@segment/analytics-react-native": "^1.4.3",
    "@segment/analytics-react-native-google-analytics": "^1.4.3",
    "@segment/analytics-react-native-mixpanel": "^1.4.3",
    "@unimodules/core": "^7.0.0",
    "@unimodules/react-native-adapter": "^6.1.0",
    "create-react-class": "^15.7.0",
    "expo-camera": "^9.1.1",
    "expo-media-library": "^10.0.0",
    "lottie-ios": "^3.1.8",
    "lottie-react-native": "^3.5.0",
    "metro-react-native-babel-transformer": "^0.64.0",
    "react": "^16.13.1",
    "react-dom": "^16.13.0",
    "react-native": "0.63.4",
    "react-native-background-actions": "^2.6.0",
    "react-native-background-upload": "^6.2.0",
    "react-native-beautiful-video-recorder": "^2.0.1",
    "react-native-camera": "^3.42.0",
    "react-native-camera-roll-picker": "^2.0.0",
    "react-native-elements": "^3.1.0",
    "react-native-fade-in-image": "^1.5.0",
    "react-native-gesture-handler": "^1.9.0",
    "react-native-google-place-picker": "^1.2.1",
    "react-native-google-places-autocomplete": "^2.1.3",
    "react-native-google-signin": "^2.1.1",
    "react-native-image-picker": "^3.1.4",
    "react-native-image-resizer": "^1.4.2",
    "react-native-image-to-blob": "0.0.6",
    "react-native-modal": "^11.7.0",
    "react-native-modal-datetime-picker": "^9.2.0",
    "react-native-paper": "^4.7.2",
    "react-native-progress": "^4.1.2",
    "react-native-really-awesome-button": "^1.6.0",
    "react-native-reanimated": "^1.13.2",
    "react-native-safe-area-context": "^3.1.9",
    "react-native-screens": "^2.16.1",
    "react-native-splash-screen": "^3.2.0",
    "react-native-tab-view": "^2.15.2",
    "react-native-unimodules": "^0.12.0",
    "react-native-vector-icons": "^8.1.0",
    "react-native-video": "^4.3.0",
    "unimodules-permissions-interface": "^5.4.0"
  },
  "devDependencies": {
    "@babel/core": "^7.8.4",
    "@babel/runtime": "^7.8.4",
    "@react-native-community/eslint-config": "^1.1.0",
    "@testing-library/react-native": "^7.1.0",
    "babel-jest": "^25.1.0",
    "eslint": "^6.5.1",
    "jest": "^25.5.4",
    "metro-react-native-babel-preset": "^0.59.0",
    "react-test-renderer": "16.13.1"
  },
  "jest": {
    "preset": "react-native",
    "testPathIgnorePatterns": [
      "/node_modules/",
      "/.shadow-cljs/"
    ],
    "testMatch": [
      "**/test-out/**/*_test.js"
    ],
    "snapshotResolver": "<rootDir>/customSnapshotResolver.js"
  }
}

prit02:03:20

Btw, the project shadow/watch is running smoothly, i.e., the project is compiling smoothly but just the repl and the evaluation isn’t working

prit02:03:46

It probably has something to do with how cider works

dpsutton02:03:53

if you type (help) in that repl you'll probably get some helpful popup

dpsutton02:03:09

(shadow/repl :foo) - Switches the current REPL to that of :foo in particular this

prit02:03:11

Unable to resolve symbol: help in this context

dpsutton02:03:17

try (shadow/watch :dev) and then (shadow/repl :dev)

prit02:03:05

I don’t know why but the repl is in humboi.events namespace and not in the shadow namespace

prit02:03:13

it was in the shadow namespace before

prit02:03:30

so cannot run shadow/watch

prit02:03:01

i don’t know how to go back

prit03:03:33

oh yeah because I had done this: (ns humboi.events (:require [reagent.core :as r]))

prit03:03:41

which had worked and changed the namespace

prit03:03:19

yes I went back to (ns shadow.user) and (help) works

dpsutton03:03:43

(doto 'shadow.cljs.devtools.api require in-ns)

prit03:03:23

The strange thing is that I’m getting a java error in the shadow repl

Umar Daraz10:03:08

Hi fellow clojurians Im deploying clojure deps.edn app to heroku. and it deployed successful. But heroku dyno restart (happens once every day automatically ) fails with

Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 150 seconds of launch
Here my Procfile command
web: java -cp ps.jar clojure.main -m reviews.system
and here is my main system file, Locally it takes around 30 seconds to start up server
(ns reviews.system
  (:require [integrant.core :as ig]
            [ring.adapter.jetty :as jetty]
            [reviews.server :as server]
            [migratus.core :as migratus]
            [migrations :as migrations]
            [reviews.db :as db]))

(def system-config
  {:shop/jetty {:handler (ig/ref :shop/handler)
           :port (Integer. (or (System/getenv "PORT") "3000"))}
   :shop/handler {:db (ig/ref :shop/postgres)}
   :shop/migrations {:db (ig/ref :shop/postgres)}
   :shop/postgres nil})

(defmethod ig/init-key :shop/jetty [_ {:keys [handler port] }]
  (println "server running on port 3000")
  (jetty/run-jetty handler {:port port :join? false}))


(defmethod ig/init-key :shop/migrations [_ {:keys [db] }]
  (let [config {:db {:datasource {:datasource db}}}]
    (migratus/migrate migrations/config)))

(defmethod ig/init-key :shop/handler [_ {:keys [db] }]
  (server/create-app db))

(defmethod ig/init-key :shop/postgres [_ _]
  db/spec)

(defmethod ig/halt-key! :shop/jetty [_  jetty]
  (.stop jetty))


(defn -main []
  (println "Running main!")
  (println "PORT: " (Integer. (or (System/getenv "PORT") "3000")))
  (ig/init system-config))

(comment 
  (def system (ig/init system-config))
  (ig/halt! system))

javahippie11:03:30

Can you see the “PORT:” message from your main function? What does it say?

Umar Daraz11:03:36

in case of successful run message is

2021-03-22T22:45:57.094366+00:00 app[web.1]: PORT:  38440
on restart timeout error, this message is not printed

andy.fingerhut17:03:45

@U9S1URQ4T Please put longer messages like this inside of a "reply thread" on Slack, to avoid having large blocks of text at the top level that some people might not want to see. Another technique is to publish such text on Github, perhaps as a "Gist", and paste only a link to it in Slack.

☝️ 2
pez11:03:07

If I evaluate something like (range) then the sequence is realized, right? Is that because the REPL wants to print it, or why is it happening? When I do it through Calva (nrepl) I get no printing, but the CPU is exercised. Doing it from a clojure prompt it starts to print the sequence.

jkxyz12:03:08

Yes, it’s realized in order to print it out at the REPL. Calva probably doesn’t print anything because it’s waiting until the sequence has been realized so it can show the result. If you eval (def foo (range)) , because def just returns the var #'foo , it will return immediately and not realize the sequence

pez12:03:45

Thanks! Good with the tips about defining it. I'm going to demo Clojure to some people and want to mention the lazyness, but struggled with a good example since the cpu was telling a non-lazy story. 😀

jkxyz13:03:29

I had a good case for a lazy infinite sequence recently: I had some fn that went from a number n to a string (in this case it was a table column heading: A, B, C, … AA, AB etc.) I used that fn to create an infinite sequence, as (def column-labels (map column-label (iterate inc 0)) such that (nth column-labels n) returns the right label. My view does something like (for [label (take max-columns column-labels)] [:th label]) . Because I def’d column-labels, it will only ever call column-label once per n and the sequence will realize for as many values as I need. (Of course this comes at the cost of memory as with any memoization, but I thought it was neat that I could do this 🙂). Then again 5 minutes later I also spent an hour debugging why I was getting unexpected values and it was because a lazy sequence wasn’t being realized at the right time.

pez14:03:11

Awesome case. Also no free lunches for anyone. 😃

Franco Gasperino17:03:11

hello all. Curious as to the difference here: => (int? 0) true => (filter #((% 0)) [int?]) class java.lang.Boolean cannot be cast to class clojure.lang.IFn (java.lang.Boolean is in module java.base.loader 'bootstrap'; clojure.lang.IFn is in unnamed module of loader 'app')

grazfather17:03:05

you hade extra parens in your # func

wevrem17:03:10

Your anonymous function is being expanded into (fn [x] ((x 0))) and when you then pass int? into that function, you have ((int? 0)) which becomes (true) which results in trying to call true as a function and produces the error you received

Franco Gasperino17:03:18

that makes sense. howevere, i would like the result of (int? 0) to be returned. a single parens set returns the function, not the eval of the expression

wevrem18:03:52

Your filter is returning everything in the original sequence, everything in [int?], that passes the filter. int? passes the filter, so that is what is being returned.

Franco Gasperino18:03:34

the recommended route is to map -> filter, then?

wevrem18:03:53

Try this alternate to get a feel for what is happening: (filter (fn [x] (x 0)) [int? zero?])

wevrem18:03:19

Is your goal to start with a sequence of functions and filter them in some way, so that you end up with a possibly smaller seq of functions?

Franco Gasperino18:03:41

somewhat. let me provide the test here i've gotten working, and then will be happy to get a more idiomatic suggestion

wevrem18:03:06

I’d still be happy to see your test case and offer suggestions if you think it might be made more idiomatic. It is sort of odd looking what you are doing, but then again, I’m seeing it completely out of context.

wevrem18:03:15

You might want to look at the keep function. You pass it a function f and a sequence, and unlike filter, it doesn’t return elements of the original seq, it returns the result of calling f on the elements of the seq, as long as the results are ‘truthy’.

(keep #(% 0) [int?])
=> (true)

Franco Gasperino18:03:55

great. that reduces the preceeding map call i would need to make

wevrem18:03:05

Correct. Keep is often a replacement for a combination of map and filter.

wevrem18:03:35

One more example with keep:

(keep #(% 0) [int? zero? pos?])
=> (true true false)

Franco Gasperino18:03:19

(let [tests [int? pos?] value-under-test 5] (= (count tests) (count (keep #(% value-under-test) tests)))) => true

wevrem18:03:40

You could maybe use juxt and every? as an alternative:

(let [tests (juxt int? pos?)
      v-u-t 5]
  (every? true? (tests v-u-t)))

wevrem18:03:17

It feels like juxt is the more appropriate function for what it looks like you are doing.

seancorfield18:03:08

Using three backticks around your code will make it easier to read:

(let [tests [int? pos?]
        value-under-test 5]
  (= (count tests) (count (keep #(% value-under-test) tests))))
=> true
or
(let [tests (juxt int? pos?)
      v-u-t 5]
  (every? true? (tests v-u-t)))
(you may need to change a Slack setting to not submit the message on ENTER when you’re inside the backticks — or just use shift-enter for newlines)

wevrem18:03:49

Thanks. That does look much better.

Franco Gasperino18:03:36

had never known juxt was available

wevrem18:03:18

I feel like I’m always discovering a new function in the core library that does exactly what I needed. Fun discoveries!

Franco Gasperino18:03:16

i was about to say it's similar to finding old gnu tools on your installations that had been around for decades

Franco Gasperino18:03:49

i ended up with:

(defn value-passes-checks? [schema value]
  (let [{checks :checks :or {checks []}} schema]
    (every? true? (keep #(% value) checks))))

Franco Gasperino18:03:15

(value-passes-checks? {:checks [int? pos?]} 5)
true

Franco Gasperino18:03:47

(value-passes-checks? {:checks [int? pos?]} 0) false

seancorfield18:03:04

every? on [] and every? on nil should be the same so you could just use (:checks schema) directly, without the destructuring.

wevrem18:03:15

That looks good. I wondered if you needed to parameterize your tests (which it looks like you did). I was going to recommend using (apply juxt checks) if that were the case.

Franco Gasperino18:03:58

i have a case where an in-flight event (map) needs some basic parameter checking, defined by edn (or json). So leveraging spec in this case is a bit heavy as it's user-driven

Franco Gasperino18:03:48

thanks, @U04V70XH6 ill check that too

Franco Gasperino18:03:07

im working largely off the (somewhat dated) clojure 4 the brave

seancorfield18:03:43

Ah, I suspect it errs on the side of very explicit code rather than more concise, more idiomatic code.

Franco Gasperino18:03:21

yea, its a good entry point for transitioning

Franco Gasperino18:03:44

and i'ts appreciated as i'm moving from python + pycharm -> clojure + emacs. so ill refactor some of this later

Franco Gasperino18:03:44

tested some cljs + reagent + re-frame and..wow, impressed. now working on some backend jvm stuff

seancorfield18:03:01

Learning Emacs at the same time as learning Clojure is a big hill to climb. What editor is pycharm based on?

seancorfield18:03:48

Looks maybe IntelliJ? If you’re finding Emacs frustrating, you could try Cursive for IntelliJ and it might be more familiar…

seancorfield18:03:41

After 20+ years of using Emacs on and off, I eventually switched to Atom and last year to VS Code. A lot of folks like VS Code with Calva.

wevrem18:03:52

Not to gang up here, but I echo Sean’s comments. I’ve been using VS Code since before I learned Clojure, and it works great.

Franco Gasperino20:03:27

ill take a look at atom. right now, im on ubuntu desktop and my projects largely use docker

seancorfield20:03:12

@U01RGC7177E The only issue with Atom is that ProtoREPL is no longer supported/maintained and Chlorine (which is very well supported and maintained) primarily uses a Socket REPL, not nREPL. It can connect to nREPL but that is not its primarily function. I would recommend VS Code over Atom because of that: and use Calva for nREPL (although I use Clover for Socket REPL because I prefer that setup — Clover is Chlorine, ported to VS Code).

seancorfield20:03:48

I have Calva installed on VS Code and just have its nREPL UI disabled so I can use Clover for my (socket) REPL connections but Calva (and LSP) for everything else.

Franco Gasperino20:03:51

does VScode require a windows environment?

seancorfield20:03:00

No, VS Code runs on Mac, Linux, and Windows.

seancorfield20:03:03

I do all my Clojure development on macOS for work and Ubuntu outside of work — the latter on WSL2 on Windows 10, so I run VS Code on Windows there: it has a really nice “Remote-WSL2” feature that lets you run the editor on Windows but access all of the files and run all of the extensions on Linux via WSL2.

Franco Gasperino20:03:35

ok im checking it out. thanks for the tip

seancorfield20:03:55

There’s a really helpful #calva channel if you need help with it.

Franco Gasperino18:03:27

thats exactly what i was looking for. thanks again

Franco Gasperino18:03:12

well almost, slight omission above, but the flow is correct 😃

Endre Bakken Stovner18:03:09

I cannot for the life of me remember the name of the function that let you pair up elements of a seq:

(aaaaargh [1 2 3 4] 2) ; ([1 2] [3 4])

Endre Bakken Stovner18:03:46

Should have tried that Hoogle for Clojure

wevrem18:03:22

I like to use http://clojuredocs.org. I seem to always have that open in a tab somewhere.

🙏 1
Endre Bakken Stovner18:03:57

This function is so simple I almost want to create a lambda:

(def add-dep [graph [node dep]] (dep/depend graph node dep))
However, it needs to be used like this:
(reduce add-dep (dep/graph) (partition 2 (range 10)))
Therefore I would need to destructure the pair in the reducing function. Is that possible?

dpsutton18:03:55

look at apply

👍 1
Endre Bakken Stovner18:03:50

Neat:

(reduce #(apply dep/depend %1 %2)  (dep/graph) (partition 2 (range 10)))

NoahTheDuke20:03:35

is it possible for a given file to be "loaded" when i use in-ns to switch to the file's namespace? or do I have to use (load "path/to/file.clj") each time?

dpsutton20:03:46

Sets *ns* to the namespace named by the symbol, creating it if needed. A common thing to do is (doto 'the-ns require in-ns)

dpsutton20:03:21

your editor should have keybinding to require a ns and then load it

NoahTheDuke20:03:53

cool, thank you

seancorfield20:03:25

And you should pretty much never use load or load-filerequire is the way to go.

seancorfield20:03:39

I’m curious as to why you feel the need to use in-ns?

NoahTheDuke02:03:27

When I open the repl, it’s not in the namespace that has all of the functions I want to use, so I gotta switch (or require them) to use them

seancorfield02:03:59

You’re typing directly into the REPL?

seancorfield02:03:21

(if you’re working from an editor, the REPL integration takes care of changing the REPL to the namespace you’re working in so code being evaluated has access to whatever is in that namespace — when you’re working with exploratory code in a Rich Comment Form (comment ..) for example)

Franco Gasperino02:03:32

using your prior suggestion of vscode, that only occurs once i have performed a form eval from the target namespace. otherwise, the nrepl is sitting in clj.user

Franco Gasperino02:03:52

if i eval a form in the editor, the namespace switches to the form's current ns

seancorfield02:03:58

In the (very rare) cases that I’m typing directly into a REPL, I tend to stay in the user ns and require things in with an alias — following the same pattern as I would in code.

seancorfield02:03:03

@U01RGC7177E Yeah, most integrations assume you will eval the file before you start editing (some variant on “load file”, “evaluate file”, or whatever)

Franco Gasperino02:03:32

thats a reasonable default, but it can be what i'll call a tooling snag for newcomers

Franco Gasperino02:03:26

i iterate quite a lot at the repl with form evals, and use those sessions as a basis for deftest later

seancorfield02:03:26

If I’m writing a new file from scratch, the first thing I write is the ns form and it’s so habitual for me to hit the key to “eval top-level form” as I’m editing that the namespace is known to the REPL before I write any other code. For an existing file, I tend to just hit the key to load the file into the REPL as soon as I open it, if I think it hasn’t already been required. Depends on where I start editing.

seancorfield02:03:51

But my REPLs run for days so they tend to accumulate my entire codebase fairly quickly.

seancorfield02:03:36

The REPL I’ve been using to work on HoneySQL v2:

user=> (dev/up-since)
#inst "2021-01-31T00:34:03.572-00:00"

Franco Gasperino02:03:13

if the ns is re-bound in the repl, a load-file / top-level eval will discard to the on-file state?

seancorfield02:03:33

I almost never type into a REPL — even exploratory eval I do inside a (comment ..) form in a source file. And then the code is already in my editor if I want to turn it into a test.

seancorfield02:03:49

@U01RGC7177E Not sure what you’re asking?

Franco Gasperino02:03:04

if in-file i have:

Franco Gasperino02:03:27

(ns my-ns)
(def myvar 1)

Franco Gasperino02:03:04

and at the repl, after eval'ing those 2 forms, i perform the following:

Franco Gasperino02:03:27

clj:my-ns:> (def myvar 2)

Franco Gasperino02:03:56

reloading / re-eval the in-file forms will rebind myvar to it's original state, yes?

Franco Gasperino02:03:20

e.g. discarding my in-repl binds

seancorfield02:03:44

Namespaces are mutable. Only one instance of each namespace exists.

seancorfield02:03:25

And your editor “REPL” and your console REPL are both clients into the same JVM and the same Clojure process.

seancorfield02:03:35

An example from work: we run Socket REPLs in many of our production processes. If I VPN in and set up an ssh tunnel and then telnet into a production Socket REPL, I get a regular user=> prompt. If I do stuff in that session and then exit telnet and shut down the tunnel and VPN, then come back days later and connect back into that production process, everything I did in the past REPL session is still there in the user namespace.

Franco Gasperino02:03:55

following that rabbit hole, can the prod jvm process link live to a repl, and you as the remote user to the repl, and then fiddle (view, update, ...) an atom ref which the process is using?

Franco Gasperino02:03:27

e.g. dump current application state (atom ref) to disk?

seancorfield02:03:31

Yes, you have full access in the REPL to any global state in the running application.

seancorfield02:03:32

(and depending on how you built & deployed the app, you may even be able to redefine functions on the fly and have them have effect immediately — we’ve done that quite a few times with one of our internal apps to fix problems without needing downtime)

seancorfield02:03:23

When I’m developing locally, I have a REPL running, I connect my editor to it, and I build the app via the REPL — by eval’ing code in the editor — while the app is running.

seancorfield02:03:32

I did presentations to both London Clojurians and Clojure Provo in the last few months showing how I build a web app directly via the REPL, modifying it while it is running. Even adding new libraries without restarting the REPL.

Franco Gasperino02:03:29

you know, i watched you give that on youtube a few days ago

Franco Gasperino02:03:48

with the cottage backdrop

seancorfield02:03:17

My mum’s house in England 🙂

seancorfield02:03:00

This shows a window where I started a REPL at the top. Then I connected to the same REPL in another window (below) and listed the available public vars. In the original REPL, I defined a var, then in the other REPL I referenced it. Just to show that even with multiple REPL clients, they “share” user:

seancorfield02:03:28

OK, time to go feed the cats. I’ll be back online later!

Franco Gasperino02:03:34

thanks for the tips

NoahTheDuke04:03:21

Through habit or whatever, I’m tied to debugging/developing using println. I like being able to see the changes to data over time which I don’t get when only seeing output from evaluating forms in a comment block

seancorfield04:03:28

Take a look at tap> which lets you debug by sending values to specific "listeners" such as Portal or Reveal (or Cognitect's REBL).

seancorfield04:03:55

Or you can just (add-tap println) and it'll behave like print debugging.

seancorfield04:03:14

But the nice thing is that you can leave tap> in your code and add and remove listeners any time you need to debug.

Franco Gasperino05:03:44

tap> is pretty slick

Franco Gasperino05:03:45

would be great if tap> returned its argument

Franco Gasperino05:03:14

would compose a bit better

seancorfield05:03:38

There's probably a tap-> coming in 1.11.

seancorfield05:03:10

You can use (doto tap>) today for that.

seancorfield05:03:36

(-> 42 (doto tap>) inc (doto tap>)) will tap 42, increment it, and then tap 43.

Franco Gasperino05:03:17

another discovery. only had seen (do)

seancorfield05:03:27

doto applies functions to its argument and then returns the argument itself. Mostly used for mutable (Java) objects, but I've often dropped (doto println) into a -> expression to print an intermediate value and also returns it (`println` returns nil).

seancorfield05:03:23

dev=> (doto 42 (println 1) (println 2))
42 1
42 2
42
So 42 becomes the first argument to each println call, like -> threading.

Franco Gasperino05:03:52

i wanted to (tap>) in a thread-after series

Franco Gasperino05:03:55

->> col 
(work)
(tap>)
(work)
(tap>)
doto should work for that

seancorfield05:03:21

You can always start with -> and use ->> inside it as needed...

seancorfield05:03:29

dev=> (-> [1 2 3 4]
 #_=>     (doto tap>)
 #_=>     (->> (map inc))
 #_=>     (doto tap>)
 #_=>     (->> (filter even?))
 #_=>     (doto tap>))
(2 4)

Franco Gasperino06:03:04

i immediately ran into the thread after

defn node-valid? [schema event]
  (->> schema
    (map (fn [[k v]] (leaf-valid? k v event)))
    (filter false?)
    (first)
    (nil?)))

Franco Gasperino06:03:25

attempting a decending map validator

seancorfield06:03:57

or do this:

dev=> (->> [1 2 3 4]
 #_=>      (#(doto % tap>))
 #_=>      (map inc)
 #_=>      (#(doto % tap>))
 #_=>      (filter even?)
 #_=>      (#(doto % tap>)))
(2 4)

Franco Gasperino06:03:05

i have a map that's the allowed schema, and an event which i'm validating against the schema

Franco Gasperino06:03:20

yea thats useful

Franco Gasperino06:03:59

now looking at tail recursion and how do decend to N child nodes

Franco Gasperino06:03:47

oh the (comment) tip is great

Franco Gasperino06:03:06

next i want to get the repl into debug mode so i can use line breaks

Franco Gasperino06:03:31

i was pleasantly surprised when i read that i could run a socket repl on a container. That will allow me to design a cljs UI, allow input from the user as edn, have the cljs ship that to a socket repl to load-file or eval for correctness

Franco Gasperino06:03:37

crossing hosted runtime

Franco Gasperino06:03:19

can then validate the user-supplied edn, display some feedback on the ui, and optionally save the edn to a loadable file for later

Franco Gasperino06:03:03

code = data, data = code really is powerful

seancorfield06:03:15

“next i want to get the repl into debug mode so i can use line breaks” — not sure what you mean by this?

Franco Gasperino06:03:27

vscode claims it can support line breaks during form evaluation. not sure how much its needed now with tap>

seancorfield16:03:20

If you want nice visualization of data structures while working in the REPL and/or debugging, I recommend Reveal. It makes a great client for tap>.

seancorfield20:03:07

(I pretty much never use it but I see a lot of beginners trying to use it so I’m curious where that is coming from)

andy.fingerhut20:03:50

I don't do a lot of Clojure dev these days, and have not optimized my IDE setup by any means, but when I do, I sometimes use in-ns to switch the REPL to a different namespace, before re'defn'ing a function.

andy.fingerhut20:03:01

I believe a lot of IDE setups will automatically do the in-ns for you?

dpsutton20:03:31

i'm kinda curious about this one. in nrepl based tooling there's no reason to sweat this as the ns is sent and handled for you. in socket based repls manual management of ns seems far more important

andy.fingerhut20:03:33

I have a very bare-bones setup with Emacs, no Cider, socket REPLs to JVM processes started at terminal outside of Emacs, inf-clojure for connecting to that socket REPL, and one hot key for "send previous form to REPL". The hot-key I use doesn't currently try to auto-detect the namespace of the buffer my cursor is in, so manual in-ns is useful there.

andy.fingerhut20:03:10

If I were doing Clojure for hours per day, I'd invest more time to find something less manual.

dpsutton20:03:05

yes i've switched over to this exactly. (and landed a couple patches to inf-clojure to make this better)

andy.fingerhut20:03:20

Cool on the patches you've landed. You probably replicated one or two that I did locally but didn't bother to try to publish elsewhere.

dpsutton20:03:31

and i'm surprised i need to watch the ns so much. i'm pretty curious what @U04V70XH6 does. He's been in socket land much longer than i have. I remember him evaluating ns forms each time in a new file which sets the ns. But i don't remember how he easily bounced between files and evaluated in different namespaces

seancorfield20:03:02

@U11BV7MTK Clover automatically wraps expressions in code to select the ns when you eval anything, which I think is what CIDER does too.

seancorfield20:03:17

Chlorine/Clover (Atom/VS Code).

andy.fingerhut20:03:56

That makes a lot of sense. It probably wouldn't be terribly difficult to enhance inf-clojure to do that, too, by parsing the first ns form in the current buffer

dpsutton20:03:03

the ns to evaluate in is a first class concept in nrepl.

dpsutton20:03:17

i can see the convenience but i very much like that there's no real munging of things sent to the repl

noisesmith22:03:08

@U0CMVHBL2 for that workflow, you might also appreciate monroe

NoahTheDuke02:03:27

When I open the repl, it’s not in the namespace that has all of the functions I want to use, so I gotta switch (or require them) to use them