I think someone shared a class to build plugins wh...
# plugin-development
j
I think someone shared a class to build plugins which includes a lambda where the context is the project, instead of having to use
target: Project
everywhere, but I am not able to find it
v
Copy code
target.apply {
    ...
}
?
c
something like this for Kotlin?
Copy code
abstract class MyPlugin : Plugin<Project> {
	override fun apply(project: Project): Unit = project.run {
	}
}
v
What's the benefit of
run
over
apply
here?
c
conventional, following how many of Gradle’s plugins are written. run and apply are mostly equivalent, except for the return value (run allows for flexible returns), but that isn’t relevant here.
👌 1
j
yeah, I know it, but there is aa class which does that without having to use apply or run
v
Copy code
abstract class BasePlugin(private val action: Project.() -> Unit) : Plugin<Project> {
    override fun apply(project: Project): Unit = project.action()
}
?
j
exactly
thank you!
v
yw, just made this up 🙂
j
I think that, or one similar to that is already available in Gradle
v
At least not that I know of, but that means nothing 🙂
c
Gradle’s plugins follow this convention:
Copy code
class KotlinDslPlugin : Plugin<Project> {

    override fun apply(project: Project): Unit = project.run {
@Vampire haven’t tried that snippet yet - wondering how the lambda get’s passed into the constructor? the various ways of applying plugins don’t appear to take a parameter that could be injected.
perhaps something like this. interesting. Can’t say I’m thrilled with stuff in a superclass constructor parameter.
Copy code
public abstract class FooPlugin(private val action : (Project).() -> Unit) : Plugin<Project> {
    override fun apply(project: Project): Unit = project.action()
}

public abstract class BarPlugin : FooPlugin( {
    tasks.named("build") {
        dependsOn(tasks.named("blah"))
    }
})
j
not sure if with delegation it is possible to have something like
Plugin<Project>, Project by project
so you can get the context is
Project
directly
c
what’s the goal here - reduced code footprint for declaring a plugin?
j
yeah, avoiding to do
target.apply
and so on, because with some formatters, you get a ugly format and/or a worse indentation. If the context of the class is already the project, it shouldn't be necessary
c
haven’t experienced formatting issues w/
target.run
(presumably `target.apply`would format the same), using IntelliJ and Spotless/ktlint. It in fact reduces the indentation when used in the method declaration.
Copy code
public abstract class Plugin1 : Plugin<Project> {
    override fun apply(target: Project) {
        target.run {
            tasks {
                named("build") {
                    dependsOn("something")
                }
            }
        }

        // can't use apply as it's already defined on the Project object
        target.apply {
            tasks {
                named("build") {
                    dependsOn("something")
                }
            }
        }
    }
}

public abstract class Plugin2 : Plugin<Project> {
    override fun apply(project: Project): Unit = project.run {
        tasks {
            named("build") {
                dependsOn("something")
            }
        }
    }
}
g
override fun apply(project: Project): Unit = project.apply { .. }
wouldn't work since kotlin's
T.apply(T.() -> Unit)
returns
T
and it would bind to
Project#apply(Action)
that applies gradle plugin.
👍 1
😱 1
e
stylistically I would tend to prefer
Copy code
with(target) { ... }
over
Copy code
target.run { ... }
but they're equivalent
and yes, with the explicit
Unit
return type, the type of the expression doesn't matter
you could also write
Copy code
override fun apply(target: T) {
    target._apply()
}
private fun T._apply() {
    ...
}
although sadly you can't avoid having some bridge method