blob: f24d19d618a40093d0af09f7ac3527aa41c0bdbf [file] [log] [blame] [view] [edit]
Functions
=========
All of the above functions have a code body. Use `KModifier.ABSTRACT` to get a function without any
body. This is only legal if it is enclosed by an abstract class or an interface.
```kotlin
val flux = FunSpec.builder("flux")
.addModifiers(KModifier.ABSTRACT, KModifier.PROTECTED)
.build()
val helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(KModifier.ABSTRACT)
.addFunction(flux)
.build()
```
Which generates this:
```kotlin
abstract class HelloWorld {
protected abstract fun flux()
}
```
The other modifiers work where permitted.
Methods also have parameters, varargs, KDoc, annotations, type variables, return type and receiver
type for extension functions. All of these are configured with `FunSpec.Builder`.
## Extension functions
Extension functions can be generated by specifying a `receiver`.
```kotlin
val square = FunSpec.builder("square")
.receiver(Int::class)
.returns(Int::class)
.addStatement("var s = this * this")
.addStatement("return s")
.build()
```
Which outputs:
```kotlin
fun Int.square(): Int {
val s = this * this
return s
}
```
## Single-expression functions
KotlinPoet can recognize single-expression functions and print them out properly. It treats
each function with a body that starts with `return` as a single-expression function:
```kotlin
val abs = FunSpec.builder("abs")
.addParameter("x", Int::class)
.returns(Int::class)
.addStatement("return if (x < 0) -x else x")
.build()
```
Which outputs:
```kotlin
fun abs(x: Int): Int = if (x < 0) -x else x
```
## Default function arguments
Consider the example below.
Function argument `b` has a default value of 0 to avoid overloading this function.
```kotlin
fun add(a: Int, b: Int = 0) {
print("a + b = ${a + b}")
}
```
Use the `defaultValue()` builder function to declare default value for a function argument.
```kotlin
FunSpec.builder("add")
.addParameter("a", Int::class)
.addParameter(
ParameterSpec.builder("b", Int::class)
.defaultValue("%L", 0)
.build()
)
.addStatement("print(\"a + b = ${a + b}\")")
.build()
```
## Spaces wrap by default!
In order to provide meaningful formatting, KotlinPoet would replace spaces, found in blocks of code,
with new line symbols, in cases when the line of code exceeds the length limit. Let's take this
function for example:
```kotlin
val funSpec = FunSpec.builder("foo")
.addStatement("return (100..10000).map { number -> number * number }.map { number -> number.toString() }.also { string -> println(string) }")
.build()
```
Depending on where it's found in the file, it may end up being printed out like this:
```kotlin
fun foo() = (100..10000).map { number -> number * number }.map { number -> number.toString() }.also
{ string -> println(string) }
```
Unfortunately this code is broken: the compiler expects `also` and `{` to be on the same line.
KotlinPoet is unable to understand the context of the expression and fix the formatting for you, but
there's a trick you can use to declare a non-breaking space - use the `·` symbol where you would
otherwise use a space. Let's apply this to our example:
```kotlin
val funSpec = FunSpec.builder("foo")
.addStatement("return (100..10000).map·{ number -> number * number }.map·{ number -> number.toString() }.also·{ string -> println(string) }")
.build()
```
This will now produce the following result:
```kotlin
fun foo() = (100..10000).map { number -> number * number }.map { number ->
number.toString()
}.also { string -> println(string) }
```
The code is now correct and will compile properly. It still doesn't look perfect - you can play with
replacing other spaces in the code block with `·` symbols to achieve better formatting.
Another common use case where you'd want to ensure spaces don't wrap is when emitting string
literals:
```kotlin
CodeBlock.of("""println("Class: $className")""")
```
If `$className` is long, KotlinPoet may wrap the space that precedes it, resulting in broken output:
```kotlin
println("Class:
very.long.class.name.Here")
```
KotlinPoet doesn't know that `"Class: $className"` is, in fact, a string literal, and that the space
inside of it should never be wrapped. To make sure this case is handled correctly, use the `%S`
modifier (as described in [%S for Strings](s-for-strings.md)):
```kotlin
CodeBlock.of("""println(%S)""", "Class: $className")
```
Now the library knows it's dealing with a string literal and can use appropriate line-wrapping rules.