In theory that should work…
Ah, I see the problem, @ccann. The :duct.core/requires
key wasn’t designed to be used outside of Duct core, so it’s being overwritten. I need to create a proper public key for requirements.
Try creating a key: :<http://your.app/requires|your.app/requires>
. Since it won’t be automatically removed, you can make it derive from :duct/const
to have Integrant ignore it.
I’ll create a proper requires key that’s designed for public use.
In the next Duct version. Feel free to add an issue to remind me.
@weavejester: I think I ran into the same problem as @ccann after our chat yesterday; but I’d tried it in our app rather than a minimal test case. However I’ve now got it failing in a minimal test case; and it seems to fail even with the solution you’re suggesting. Here’s my minimal example:
(require '[duct.core :as duct])
(derive :example.profile/b-one :duct/profile)
(derive :example.profile/a-two :duct/profile)
(derive :<http://my.app/requires|my.app/requires> :duct/const)
(duct/prep-config {:example.profile/b-one {:a {:replace-me :init}
:b [:b-one]}
:example.profile/a-two {:a {:replace-me :replaced}
:b [:b-two]
:c [:c-two]
:<http://my.app/requires|my.app/requires> (ig/ref :example.profile/b-one)}}
#{:example.profile/b-one :example.profile/a-two})
The profiles are named b-one
a-two
to guarantee the sort ordering is the opposite to the dependency order; and I’d like to see the order be [one two]
(where two
) takes precedence.
I expect to see the result contain {:a {replace-me :replaced}
rather than {:a replace-me :init}
which is what I get.
complete result output is:
{:a {:replace-me :init},
:b [:b-two :b-one],
:c [:c-two],
:<http://my.app/requires|my.app/requires> {:key :example.profile/b-one}}
Did I understand correctly what you meant by derive your own requires key?
It looks like duct/prep-config
doesn’t walk in dependency order. duct/build-config
seems to yield the same too.
hmmm something must be up; possibly with my example… build-config calls ig/init
so not sure why it’s not obeying the dependency order.
the result of ig/prep
inside build-config is:
#:example.profile{:b-one
{:a {:replace-me :init},
:b [:b-one],
:duct.core/requires {:key :duct.profile/base}},
:a-two
{:a {:replace-me :replaced},
:b [:b-two],
:c [:c-two],
:<http://my.app/requires|my.app/requires> {:key :example.profile/b-one},
:duct.core/requires {:key :duct.profile/base}}}
Ok, I think I see what the problem is. When we call fold-modules
we’ve forgotten the dependencies between profiles/modules. So the functions then evaluate in key-comparator
order 😞
We lose that info at ig/init
in build-config
.
So to summarise I think the profiles are initialised in the right order; but aren’t folded/applied to the meta-system in the right order in fold-modules
.
@rickmoynihan The dependencies should be held in the metadata of the system, so when ig/fold
is called in fold-modules
, the dependency order should be correct. I’ll look into this and try to figure out what’s going wrong, but I won’t have much time until Sunday. Feel free to open an issue to remind me.
ahh thanks for that James, that’s helpful… I’ll take a look and try and see if I can see what’s going on… I’ll open an issue when I’ve done a bit more digging for sure :thumbsup:
Oh, and while you’re here, just to get some feedback - do you use any Duct modules, or just profiles and components?
Yeah we use the following:
:duct.module/logging {}
:duct.module.web/api {}
:duct.module.web/site {}
:app.module.project/inject-all {}
The final one is the only module we have that is ours at the minute… it essentially injects an identifier/slug for the project into every component.Though I don’t think any of the above are configured through the module config… they’re just used to bring in the defaults; and then we override the bits we need but at a component level, rather than module level.
ataraxy might use the module config… though no I think even with that we strayed out of the easy config, and use the component layer to configure it.
yeah all ataraxy keys are configured through :duct.router/ataraxy
Thanks; that’s pretty useful.
I think with ataraxy we moved away from the module config primarily because it enforced a convention of having handlers in a handler namespace. And we prefer to have a project structured by feature rather than layer. I think we’ve spoken about that before.
@weavejester Ok I think I see the problem now… Which is I think essentially what you said earlier about :duct.core/requires
not being designed to be used outside of duct… however the reason that creating your own :<http://your.app/requires|your.app/requires>
key doesn’t work is because it’s not the requires key that’s special; but anything deriving deriving from :duct/profile
gets all of its refs deactivated and made into InertRef’s.
This happens in the postwalk here:
I’ll write this up on an issue after I’ve got some (late) lunch.
Ah, that makes sense.
Because the refs need to be merged as well, and not resolved right away.
@weavejester: I’ve written up the profile issue here: https://github.com/duct-framework/core/issues/31
Thanks for the writeup, @rickmoynihan. I’m interested in your opinions about the possible solution I outlined.