lucky
lucky copied to clipboard
Declaring "needs" for a component with a Proc fails to compile
Passing procs as parameters can be really helpful for named slots in Lucky components, as shown here: https://www.youtube.com/watch?v=KoiKOD63tRQ
This episode originated from a snippet provided by @paulcsmith here: https://gist.github.com/paulcsmith/01c1ced3e681de99d0ec343fdf57e2b7#gistcomment-3419386
Specifically, he wanted to be able to write something like:
class MyCustomComponent < BaseComponent
needs user : User
needs some_content : ->
needs some_user_content : User->
def render
div do
some_content.call
some_user_content.call(user)
end
end
end
However, when using any more than one needs
when any of them was a Proc, I kept getting a compile-time error of Error: undefined macro method 'ProcNotation#types
. Switching to using Proc
for the type worked, but Paul requested that an issue be opened to look into supporting the ->
syntax.
class MyCustomComponent < BaseComponent
needs user : User
needs some_content : Proc(Void)
needs some_user_content : Proc(User)
def render
div do
some_content.call
some_user_content.call(user)
end
end
end
I'm not sure if this would be allowed. needs
takes a type declaration, so the thing on the right of :
would have to be a Type, and ->
is a literal. Like doing needs password : ""
. But if needs content : Proc(Whatever)
doesn't work, then that is definitely an issue.
The Proc()
type definitely works and compiles fin! I just had this in my backlog to create at Paul's request in that Gist:
Can you open an issue about using it with the -> syntax? I like that a bit better so might be cool to add!
by chance, did he mean needs some_content = ->
? It makes more sense to me that he was referring to a default argument that does nothing
This is what I meant and I think it should work. The ->
is weird in that Crystal seems to get a type restriction from it too. For example https://play.crystal-lang.org/#/r/9r36/edit
I think this is one of the only things in Crystal where the literal works as a type restiction. It's kinda weird. Definitely not required to support it, but it would be nice IMO
oh wow. I had no idea. That's a strange one for sure, but yeah, if getter
supports it, I'm sure we can too!
Looking in to this, it seems that at the macro level, ->
is transformed in to (-> )
which is an instance of ProcNotation
. To get the input types, you call inputs
, and the return type is output
.
Where this gets tricky is that ->
returns an empty array for inputs
. Then you also have _->_
which is valid, but the _
returns this Underscore
object which I had trouble finding more info on.
So just for some pseudo code here, it seems like we'd have to do something like this:
if type_dec.type.is_a?(ProcNotation)
if type_dec.type.inputs.empty?
else
type_dec.type.inputs.each do |klass|
if klass.stringify == "_"
else
end
end
if type_dec.type.output.nil?
elsif type_dec.type.output.stringify == "_"
else
end
else
end
Then basically we have to manually build out a Proc(Whatever, Whatever)
and throw that inside of our needs... Then we have to consider that needs
is actually defined separately in Avram than in Lucky
This is something that can probably be done post 1.0. If anyone happens to land here and really hoping for this to work, let me know.