shrubbery icon indicating copy to clipboard operation
shrubbery copied to clipboard

Stubs with record semantics?

Open danielcompton opened this issue 7 years ago • 4 comments

In my service I create components, and then they have config assoc'd onto them before they are started. The components adhere to the component Lifecycle, and also implement protocols for their behaviour.

Shrubbery is great for implementing the protocols, but when my system tries to assoc config into them, it fails because they are not records. Would it be possible to make an option where stubs behave like records?

danielcompton avatar Jul 19 '17 08:07 danielcompton

That use case makes a lot of sense to me, but I haven't had a chance to think it through yet. I'm not opposed to the idea in principle—I'll take a look.

bguthrie avatar Jul 23 '17 03:07 bguthrie

Here's an extremely minimal reify implementation which can handle associng, but doesn't actually keep the keys. This is useful if you don't actually care about the config being assoc'd on, which happens in some cases, especially no-op components.

(defn new-null-reporter []
  (reify
    ErrorReporter
    (-report-error [_ m]
      nil)

    ;; Maplike impl follows
    IPersistentCollection
    (cons [this obj]
      this)
    (count [this]
      0)
    (empty [this]
      this)
    (equiv [this obj]
      (identical? this obj))
    Associative
    (assoc [this k v]
      this)
    (containsKey [this k]
      false)
    (entryAt [this v]
      nil)
    ILookup
    (valAt [this obj]
      nil)
    (valAt [this obj obj2]
      nil)))

danielcompton avatar Oct 11 '17 20:10 danielcompton

Oh that's extremely helpful, thank you!

From where you stand, do you think there's an argument to be made for making all stubs maplike, or should the library expose a secondary stub-record function? If there's no harm in it—and particularly if it'd be non-breaking—I'm leaning towards the former.

bguthrie avatar Oct 12 '17 01:10 bguthrie

I think it would be a pretty good default behaviour to have too. Part of me has a niggling fear that this could lead to latent bugs, where the stub accepts arguments that the real object wouldn't, if the user is stubbing something that isn't a record.

However I think using records is the more common scenario, and also a good design pattern. It could be good to have the default make a record-like, and then give people the option of creating the stub without record semantics if they really want it.

danielcompton avatar Oct 12 '17 07:10 danielcompton