the store(in: self.cancelables) is not the problem. Making sure cancellable exists, is.
I wanted to check if the class has a cancellables property, otherwise add it. But this is not possible as I only have inspection capabilities to the member somePublisher and not the container it's included on.
in these cases, I would need to know what the requirements for the protocols are. (I would be thankfull with @Mock(ProtocolA.self, ProtocolB.self) too. :D
So the question is, will this ever be possible? Sorry if I don't use proper terminology.
Thank you
Just came across your question and I think I have an answer that might be beneficial to you. However, I've previously detailed this answer in another thread that addresses the same issue.
Here is the link to that thread: Introducing Spyable: A Swift Macro for Automatic Spies Generation - #10 by Matejkob. I strongly recommend you go through the comment as it contains a thorough explanation which I believe will shed light on your problem. It's quite comprehensive and should give you a deeper understanding of the matter at hand.
I hope you find it useful. Feel free to comment if you have further questions or need additional clarification on anything.
It's a fundamental property of macros that the compiler only exposes certain information to them. While it's in theory possible for us to add APIs to the MacroExpansionContext to expose more information, this takes a lot of careful engineering, and the more information we expose, the more it impacts the efficiency of tools (particularly features like code completion). As of yet, there's no way to just query an arbitrary type—even an enclosing type—and see all of its contents.
This means you often have to either figure out a place where you can attach a macro so that it can see what it needs, or you need to make assumptions about the environment and let the compiler diagnose a normal error if those assumptions are wrong.
What I would recommmend is that you make @Cancelable be an attached member macro you apply to the type. It will add both the cancellables property and an addCancelable(_:) method that you can use like this:
An ordinary method should work at the use site because there's really nothing special or macro-y that needs to happen when you add a cancelable to the property.
You can write a macro that generates a mock for one protocol as long as it's attached to the protocol:
But there's no way for a macro to see the declarations of more than one type at a time unless you do something disgusting like passing in a chunk of code as a string literal:
// Please don't do this
#Mockable("""
protocol ProtocolA {
func fromProtocolA()
}
protocol ProtocolB {
func fromProtocolB()
}
""")
Thank you very much! That was really insightful and exactly they answer I was waiting for (not what I wanted though :D, but I completely understand the reasons!).
I had considered the alternatives but they all have shortcomings that my "dreamy" ones didn't.
Creating a mock for a protocol is very useful indeed but often we have more than one. :)
As for addCancelable… it is a nice idea. Not sure I prefer to use it over the regular approach though.
As for the string literal approach… don't you worry ahah!
For the cancellable stuff you could try doing something similar to what RxSwift did and create some sort of cancellable container like their DisposeBag and extend cancellable to have a cancelled(by: cancelContainer). Your macro could simple add the container as an attribute to the type owning the Publishers. It’s not perfect but will save a bunch of repetition with redeclaring the cancellable variables a the time.