This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-10-04
Channels
- # aleph (10)
- # announcements (2)
- # babashka (2)
- # beginners (101)
- # calva (17)
- # cider (11)
- # clara (6)
- # clj-kondo (25)
- # cljsrn (33)
- # clojure (181)
- # clojure-dev (15)
- # clojure-europe (3)
- # clojure-italy (4)
- # clojure-nl (8)
- # clojure-uk (22)
- # clojurescript (111)
- # clojutre (58)
- # cursive (31)
- # data-science (1)
- # datomic (10)
- # emacs (6)
- # ethereum (1)
- # fulcro (20)
- # graalvm (3)
- # jackdaw (5)
- # leiningen (5)
- # off-topic (31)
- # re-frame (2)
- # reitit (10)
- # shadow-cljs (9)
- # spacemacs (16)
- # sql (8)
- # tools-deps (16)
- # vim (17)
I'm not sure what that question means in the context of Clojure @deleted-user
When you ask for a dependency, it is fetched and cached into the local Maven repository cache in your home directory. After that, any process you run under your account can reuse that dependency without fetching it again.
You can use an environment variable or command-line option I think to specify a different location for that cache... so I guess you could use a shared location across multiple accounts -- if that's what you mean by "global"?
If you have a dependency cached, you can use it from any project.
The JVM doesn't have "executables" -- it has class files on the classpath which java
"executes".
That's just a matter of having lein
on your PATH
tho'...
And that's nothing to do with Clojure/JVM's view of the world.
lein
(and boot
and clojure
/`clj`) are shell scripts/executables that are outside the Clojure/JVM ecosystem.
Maven Central and Clojars are those "shared package repo"s.
But there are no "executables", just libraries that the JVM can use.
i don't know of a way to install clojure "apps" that way from maven, but if you have a need for it
The JVM -- the java
command -- is the executable.
When you do gem install rake
, is rake
a native machine binary, or is it a file containing Ruby source code with a #! as the first line?
So it requires the ruby
executable already installed
So if that command after the #! doesn't exist on your system, then it can't run.
Just like Clojure requires the java
executable already installed
You can write similar things with Clojure source code if you want, using a first line like #! /usr/bin/env clj ...
Those will work anywhere on your path, as long as clj and a JVM are also on your path.
And here is another variation of that: https://github.com/jafingerhut/dotfiles/blob/master/bin/clj-check-added-metadata
The syntax gets a bit weird for that one.
@deleted-user but clj-kondo
is an executable
Like I said: lein
and other things are not Clojure
I believe @borkdude creates native executables from Clojure source using GraalVM, or some such wizardry I haven't looked into
So, yeah, you can use homebrew or similar to install scripts and executables... but that's completely independent of Clojure.
you'll need to come up with some way to define that for lein/boot if you were to do it
I mean, there is brew install clojure
, so presumably one could create Homebrew things that depend upon the Homebrew thing named clojure
also being installed.
Sorry, I'm new to Homebrew, and don't know the lingo there yet.
@deleted-user what does "for clojure" mean in your sentence above?
a tool that produces an "executable" (from the user's point of view) from clojure source code
e.g. creates an Uberjar with a one-line shell script that runs java
with that uberjar named?
If you don't mind the Clojure source code being in the "executable", that seems to achieve the effect, one one way (there are others)
just as rake includes all or most of its source code in its executable.
clj / clojure just do the late binding one more step -- they find the deps over the network after you invoke the command?
Bear in mind that you already have clojure -Sdeps '{:deps {somegroup/someartifact {:mvn/version "RELEASE"}}}' -m some.thing
which will fetch that library (if not already cached) and then run it's some.thing/main
function.
What I mean by "outside the Clojure ecosystem" is that what you need/what is to be able to install a shell script that runs clojure
with specific arguments.
I have about 3 tiny shell scripts in my path that do nothing but run a clojure
command with long args I don't want to type twice.
We already have plenty of package managers (outside Clojure) that can find and install shell scripts -- just like brew install lein
or brew install clojure
-- and all you need to write are the shell scripts to invoke libraries.
But we already have such tools.
They're just "outside the Clojure ecosystem".
Homebrew, Scoop, Chocolatey, etc.
Are you trying to make something where you can guarantee that after step X, you can disconnect from the Internet and the program is all local?
Because if working after disconnecting from the Internet is not a requirement for you, I don't see why shell scripts a handful of lines long that invoke long clojure
commands don't do what you want.
i'd lein uberjar
standalone it then make a shell script that does java -jar uberjar
and puts it somewhere on the PATH
And even if working after disconnecting is a requirement, you could say "run the program once and let it download the rest of itself before disconnecting from the network"
g'nite
Given clojure
's user-level deps.edn
and "global" aliases in that, I can't say I find the need for what Nate is talking about...
It would only automate such a tiny step in the process (basically adding a new alias to deps.edn
and perhaps a shell script that invokes clojure
with that new alias).
At least from one perspective, mvn/lein/boot/clj are Clojure package managers, if you consider JAR files in your $HOME/.m2 directory as installed packages.
They just don't have "uninstall" or "list installed packages" commands
"list installed packages" = ls -d ~/.m2/repository/*/*
🙂
ls -d ~/.m2/repository/*/*/[0-9]*
if you want all the installed versions 🙂
For years I resisted installing homebrew on my Mac -- too much "magic"... And for years I installed stuff manually because that's what I'd been used to for decades of using computers.
Yeah, I got tired of that some time around 2000 🙂
Loved MacPorts
Partly because I figured out that if things got weird or seemed broken, and I had a couple hours to kill, I could rm -fr /opt/local
and start over from scratch.
Hi everyone, do you have some tips how to make uberjar small as it can be? Is there some Lein plugin that will tell that this required namespace is not used etc? Thank you
I use https://github.com/snoe/clojure-lsp which can tell me when required namespaces aren't referenced. I doubt you'd actually shed libraries like that though unless the code is Extremely Legacy.
Otherwise I'd follow Java JAR minimisation techniques - reduce the # of classes you create etc
Most of the bloat actually comes from dependencies so I'd cut out stuff you don't really need or is available via another simpler libs.
Morning all, I remember once encountering a convention when writing Clojure... something along the lines of when
should not be the final form in a function, it should be substituted with a single branch if
...but I don't remember the reasoning for this. Does anyone recall this or what on Earth I'm talking about?
never heard of such a thing @U052SB76M. I could imagine someone arguing for using (if test then-branch nil)
to be explicit about the return value, but honestly I think when
is just as clear, and more clear then a single branch if
Maybe I am misremembering it and that was the point being made, as that would certainly be a reasonable argument. Cheers, I'll think I'll go with this 😛
FWIW: I understand @deleted-user’s desire, to essentially package tooling with a project. Though we just use aliases in our deps.edn
that specify a :main-opts
and :extra-deps
for pulling in java/clojure tools and services. And this works really well.
However it doesn’t work for stuff that is compiled with graalvm, e.g. clj-kondo
… I’d also like to package, compile with graalvm and ship as downstream executables some of our custom tooling in a similar way.
I did notice that mvn repos can in principle store arbitrary artifacts (not just jars) — so that might be one such mechanism.
@rickmoynihan you can also put your binaries in a Github release and use bash. this is what I do for several projects, next to brew. if you want to keep those binaries private, you could store them in s3 behind some credentials and use bash.
I feel old now. I'm happy with apt-get
or tarballs. Still figuring out what "snap releases" are.
getting a binary into the apt-get system is way way harder than brew. I haven't been able to do this for clj-kondo
snap is a system by canonical which basically runs your binary in a protected/managed system where the user has to give explicit permission to access the filesystem, network etc.
yeah getting stuff into Debian/Ubuntu is far from trivial, big kudos for the people working on having Clojure and Leiningen in there. It all has its reasons but it's not something I want to navigate for fun. which is why I'm quite content with a tarball
I think arch linux might have a similar model to brew, it's much more accessible for people just wanting to share their binaries
@borkdude indeed. It’s simple enough in principle it’s just a lot of of extra setup you need to do… each package manager etc requires its own installation in CI or locally in dev. They each need different keys / auth methods etc, on both the production and consumption side, and this needs to be repeated in each downstream project. It’d be nice if you only had to do that for one of them, and then everything could be resolved. i.e. leveraging maven/tools.deps for other artifacts.
Though I also understand the desire to keep things simple. i.e. I’m not requesting this as tools.deps feature… it’d just be nice to leverage the same auth paths / transport mechanisms it uses.
@rickmoynihan this is what my brew repo looks like: https://github.com/borkdude/homebrew-brew I host several binaries there now
I don't need to push anything into the "main" brew package system, it's just a git repo
Thanks. I’ll take a look.
I got this idea from @roman.bataev, so credits go to him 🙂
Don’t get me wrong I think your setup is great… it’d just be nice if it were easier though; without having to involve external tooling.
I was just wondering if it would possible to essentially just put a tar ball in a maven repo; and unpack it out of the repo into a local ./bin
directory. Then you could manage it with tools deps, and the addition of a single -A:install-executables
alias… in theory.
it doesn’t even need to be a jar.
You could put the statically linked binaries in their directly if you wanted.
and perhaps have a separete repo for each platform you need to support.
or use classifiers
yeah, that's what brew is also doing for mac and linux. so I'm just going for that right now
which totally makes sense btw! I’m just thinking outloud about tooling I wish we had 🙂
and how it might work.
it reminds me of https://github.com/magnars/optimus which bundles clj-v8 to run JavaScript
interesting… though I guess that’s using v8 as a native lib rather than an executable
Does anyone know if it’s possible to make a phraser for a spec, which has set as a predicate? Eg.
(s/def ::operator #{"a" "b"})
what's a phraser?
maybe not the best place to ask
@dmytro.bunin in this area there's also https://github.com/bhb/expound
Re: phrase & expound. The key difference is that phrase is specifically intended to enable the construction of 'end user' level error messages while expound is specifically targeting developers. In it's niche/space, phrase is impressive.
Howdy y'all I am having trouble to troubleshoot a NullPointerException that is caused when a Clara Rule is fired on a Record. The record contains no null values, but it tells me it has null values
I don't want to post the whole long exception trace. I posted my issue in clara-rules github, https://github.com/cerner/clara-rules/issues/437
record lookup can return null for a key that doesn't exist
Can you elaborate more?
I can't help right now with the clara specific stuff - I know nothing about their DSL, but clojure lets you look up any key on a record, with a null value if the key isn't present
also, as a nitpick, idiomatically _
means "a value that must be assigned but isn't used", so intentionally using it as a binding in as-> is confusing
(update _ :volume #(/ v 42))
- I would expect an arity exception here - this function doesn't accept any args
My bad yes, I saw the typo
fixed
what guarantee do you have that both rate
and volume
will be present and non-nil?
100% guarantee every entity passing through that rule will have rate and volume. They are added before even going through the rate
I would start by looking to see what is returned by (get @evnts "733B772B94101049D1C8520FF8A9FB109CBC66BDB6A577E8A0E6311698837E12")
I will look in to this probably you are right
You were right. The Event was not in the atom @evnts
. I can't really tell what happened.
However, now it is there and I still get the same error!
the question then is, is it always there, or is it just there when you are checking and not there when the rule runs
The event is not always there. But when the event is in the atom, the rule runs saying there is no event with that id.
are you sure it is the same id? if it is not always there, how do you know that rule only runs when it is there?
you pass in an immutable collection of events to clara to start with, and those are the events clara is basing its decisions on
so if the event is in the immutable collection you pass in to start, then you remove it, things will break when that rule fires
which is why I was suggesting that having your atom off to the side was a bad idea. clara internally manages its own database of facts based on the initial stuff you pass in, and you should use that and manage it with assertions and retractions, the atom thing off to the side without anyway to keep it in sync with clara's view is a bad idea
So I noticed that the Event is there, with different id!
You are saying I should not use the atom at all?
How should I apply changes to my event? directly to the ?event?
I would ask in #clara my immediate thought is to retract the old event from clara's database and assert the new event, but that will actually cause problems because of clara's truth maintenance.
truth maintenance is something like, clara keeps track of which facts cause which new facts to be asserted, and if a fact is retracted all dependent facts are retracted as well
I think the architecture that makes the most sense for a rules engine program is something: 1. gather information about the world 2. feed that information in to the rules engine 3. the rules engine runs until it reaches a stable state and decides on some actions 4. query the rules engine for the actions, do them, and loop to 1
so instead of changing the properties of the event, you might assert some fact which describes the action of changing the event, then the rules engine exits, then you query its db for actions, then you perform those actions on the events, then you feed the new events into a new iteration of the rules engine
Wow, haha I have a hard time understanding what you just said. Maybe a visual example?
so like, instead of swaping or associng whatever directly manipulating the event, you have your rule assert a fact like (->Action event-id some-function-that-makes-the-change-you-want)
, then once the rules engine exits, you run a query on its database to return all the actions, you loop over all the actions applying the function to the event with the given id, and then you take your updated events and feed them back in to the rules engine again and you do that until you get no actions to run out of the rules engine
the confusing thing the exception shows an event with a volume and rate, but your rule ignores that event and uses its id to look up another value in @evnts and actually uses that
#clara isn't super busy but usually pretty helpful. I have only played with clara a little, so don't have too much experience, but I think you are asking for a bad time if you pass in an immutable collection of events, and then sort of ignore that and fiddle around with your atom of events
that sounds right - also the fact this happens under load means this could be one of those "don't deref inside the thing already using the atom" situations - it could be a condition that happens when something failed a swap! and retried for example
it sounds like you are trying to multithread the thing too, which likely means you are running multiple independent clara rules engines all banging on the atom, and likely doing it in a none safe way
I suspect the best thing to do is to restructure your rules to not do anything, but generate some kind of job specifications of what is to be done, run the rules single threaded, and then take the job specs and do whatever parallel stuff you want to do
user=> (apply distinct? [1])
true
user=> (apply distinct? [])
Execution error (ArityException) at user/eval7 (REPL:1).
😕seems like that's what you should expect from the docstring
but it's kinda inconvenient that you should check for non-empty when using this with apply
Given that (distinct [])
works and produces ()
it does seem a little odd that (distinct?)
is not allowed /cc @U064X3EF3
(and the docstring talks about "no two of the arguments" but it already allows a single argument)
Those seem like very different functions to me, but I would have no problem with a no-arg arity
I must admit, I've never felt the need to check whether a bunch of things are distinct from each other so up until @borkdude mentioned it, I didn't actually know there was a distinct?
testing function. And, from the name alone, I think I would have expected it to work on a collection anyway (distinct? coll)
rather than (distinct? x y & more)
I haven't used distinct? that much, but it was used in a custom EDN reader which first checks if all keys are distinct before actually creating a hash-map. It crashed on the empty map 😕
One argument not to change it is that it's consistent with =. (apply = [])
also excepts.
Yeah, I think it's one of those edge cases where there are good arguments on both sides.
You could argue that it shouldn't accept a single argument, given the docstring 🙂
I think one line of reasoning behind throwing an exception is that both the statements (apply distinct? [])
and (apply = [])
would be vacuously true
ie. any assertion you can make about the members of an empty set, the opposite assertion is also true - probably not a good situation to have
I am using (json/read-str "{\":id\" : \"ebc7b483-1558-4b9c-8f8c-c9af3d1d37eb\"}")
which returns a map that looks like {":id" "ebc7b483-1558-4b9c-8f8c-c9af3d1d37eb"}
. How can I get that to be :id
instead of ":id"
? Should I manually (keyword ":id")
afterwords? (I'd just pass in "id" instead of ":id" if I keyworded it manually)
@brian.rogers Which library are you using for json
? Most of them have an option to "keywordize" keys.
that would give you ::id
as a key
Oh, no. I see what you mean. Well, ":id"
is a string containing :
already
So, whatever produced that string is doing the wrong thing.
you can use a custom key generating function
you might want that string to be coerced to uuid as well
I would expect you to start with "{\"id\" : \"...\"}"
instead.
Yes @seancorfield I think you've given me the solution. I will pass in "id"
and then use (`clojure.walk.keywordize-keys ...)`
there's an optional arg, you don't need to walk afterward https://github.com/clojure/data.json#converting-keyvalue-types
(json/read-str "{\"a\":1,\"b\":2}"
:key-fn keyword)
;;=> {:a 1, :b 2}
and your :value-fn
could check for uuids :D
Oh wow! That's even more perfect thank you @noisesmith!