Fork me on GitHub

im trying to use juxt/clip based on the docs, i was expecting that i will be able to use this in the :post-start expression, since it's receiving an implicit target, but it seems not to be the case:

(clip/start {:components {:a {:start 1}
                            :b {:start 2 
                                :post-start `(prn this (clip/ref :a))}}})
am i doing something wrong? what's the simplest way to get access to that implicit parameter? in other words, how can i explicitly refer to the implicit parameter in the :post-start expression?


You should be able to, definitely. Lemme refresh my memory, one sec :)


The code for this is in the post start function


Oh, is it because you're using backtick? And you're getting a namespaced this?


ok, so how should this situation look like then?


In the exact example above, you could use a single quote instead.

👍 4

now that im asking, i came up with this:

(clip/start {:components {:a {:start 1}
                            :b {:start 2 
                                :post-start `(prn (clip/ref :b) (clip/ref :a))}}})
while it works, im a bit concerned, because post-start is described as being run before the component is passed in to other components where its clip/refered. im wondering if it just works by accident or not? it would be good if the docs mention such a use-case or have some tests for it at least. what i was trying to achieve with this is to have a datomic seed data transaction, where the seed data (which is the datomic schema for new) is provided as a component too


I'm surprised this works. I'm using tarjans algorithm which I guess doesn't care about this? I wouldn't expect it to keep working forever if I changed the way the environment works or something.

👍 4

would it make sense to support something like this:

(with-open [sys (clip/start sys-config)]
  (work-with sys)
  ; exception happens
and the system is closed for sure. it feels like it would be a useful construct while developing a system config, which has a webserver in it for example...


That's an interesting idea. One problem is that I'd have to return an object so I could extend it to Closeable. One option is a with-system macro? What do you think?


for now i think i will just make something like this with-system:


Isn't the PersistentHashMap and object already?


but with-open is not the most intuitive name anyway, so probably a macro is better. it could be clip/with or clip/let ? and just keep the let-style options, so cursive can recognize it as a let


might even make sense to allow creating multiple systems, so you can test how they interact, without spawning them in separate processes... i remember i did something like this before. created 2 systems but reused the same database in them.


I don't own PersistentHashMap, so I shouldn't extend it to an interface I don't own, Closeable


With is what I'd expect I think.


sure, i was hoping that on a per-instance basis it's possible to sneak in some .close method. after all with-open doesn't care about the object types either, just tries to call .close on them..


btw, this implementation seems to work at 1st glance:

(defmacro with
  [[bound-var binding-expr] & body]
  `(let [system-config# ~binding-expr
         ~bound-var (clip/start system-config#)]
       [email protected]
         (clip/stop system-config# ~bound-var)))))


I don't know of any way to do that unfortunately. I'm not sure we should even if we could.


That macro looks good! If you wanted multiple bindings to be possible, maybe you could make it recursive?


i just tried to integrate it into a test suite as a before-each hook and im not sure if it's a good idea to make it recursive, because of that implicit clip/start. that would mean u can only start systems using this with construct, but intuitively i wrote the following code first:

(declare ^:dynamic q)

  :each (fn [test-case]
          (sys/with [sys {:components (merge sys/datomic sys/graphql)}
                     {:keys [graphql/schema-fn]} sys
                     schema (schema-fn)]
            (binding [q (fn [query] (gql/execute schema query {} {}))]


which wouldn't work, even if with would have handled multiple bindings... so currently i have this instead:

  :each (fn [test-case]
          (sys/with [sys {:components (merge sys/datomic sys/graphql)}]
            (let [{:keys [graphql/schema-fn]} sys
                  schema (schema-fn)]
              (binding [q (fn [query] (gql/execute schema query {} {}))]
which i think is not too bad... it raises the question though, how would u expose an api for tests, which are specialised for or tied to a specific system instance? it can help immensely to write concise tests, eg:
(deftest query-test
  (expect {:data {:txns [{:id "x" :tags ["tag-1"]}]}}
          (q "{ txns { id tags } }")))


For the record, before I started using clip, I had a macro, like this:

(defmacro in-tmp-db [& body]
  `(let [db-uri# (str (gensym "datomic:-"))]
     (d/create-database db-uri#)
     (let [~'conn (d/connect db-uri#)
           ~'tx! (fn [& ~'args] (apply d/transact ~'conn ~'args))
           ~'db! (fn [] (d/db ~'conn))
           ~'entity (fn [& ~'args] (apply d/entity (~'db!) ~'args))
           ~'entid (fn [& ~'args] (apply d/entid (~'db!) ~'args))
           ~'pull (fn [& ~'args] (apply d/pull (~'db!) ~'args))]
         @(~'tx! (datomic/schema))
         [email protected]
           (d/release ~'conn)
           (d/delete-database db-uri#))))))
so my tests looked something like this:
(deftest some-test
  (expecting "something"
      (some.datomic/transaction! conn {:entity "map"})
      (expect #{"data-1" "data-2"} (some.datomic/query (db!) [:lookup "ref"])))))


I don't understand the question, sorry