Skip to content

Commit

Permalink
Implement factory to create directive objects (#80)
Browse files Browse the repository at this point in the history
* Add factory class to create directives

* Add directive type enum

* Update constructor definition from the directive implementations

* Add test for the new factory

* Update directive usage

* Remove wildcard import

* Fix test class
  • Loading branch information
theEvilReaper authored Jan 16, 2024
1 parent ea94c85 commit 48f3255
Show file tree
Hide file tree
Showing 15 changed files with 261 additions and 65 deletions.
18 changes: 13 additions & 5 deletions src/main/kotlin/net/theevilreaper/dartpoet/DartFile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import net.theevilreaper.dartpoet.clazz.ClassSpec
import net.theevilreaper.dartpoet.code.CodeWriter
import net.theevilreaper.dartpoet.code.buildCodeString
import net.theevilreaper.dartpoet.code.writer.DartFileWriter
import net.theevilreaper.dartpoet.directive.*
import net.theevilreaper.dartpoet.directive.DartDirective
import net.theevilreaper.dartpoet.directive.ExportDirective
import net.theevilreaper.dartpoet.directive.LibraryDirective
import net.theevilreaper.dartpoet.directive.PartDirective
import net.theevilreaper.dartpoet.directive.RelativeDirective
import net.theevilreaper.dartpoet.extension.ExtensionSpec
import net.theevilreaper.dartpoet.function.FunctionSpec
import net.theevilreaper.dartpoet.util.*
Expand All @@ -32,12 +36,16 @@ class DartFile internal constructor(

private val directives = builder.directives.toImmutableList()

internal val dartImports = DirectiveOrdering.sortDirectives<DartDirective>(DartDirective::class, directives) { it.contains("dart:") }
internal val packageImports = DirectiveOrdering.sortDirectives<DartDirective>(DartDirective::class, directives) { it.contains("package:")}
internal val dartImports =
DirectiveOrdering.sortDirectives<DartDirective>(DartDirective::class, directives) { it.contains("dart:") }
internal val packageImports =
DirectiveOrdering.sortDirectives<DartDirective>(DartDirective::class, directives) { it.contains("package:") }
internal val partImports = DirectiveOrdering.sortDirectives<PartDirective>(PartDirective::class, directives)
internal val libImport = DirectiveOrdering.sortDirectives<LibraryDirective>(LibraryDirective::class, directives)
internal val exportDirectives = DirectiveOrdering.sortDirectives<ExportDirective>(ExportDirective::class, directives)
internal val relativeImports = DirectiveOrdering.sortDirectives<RelativeDirective>(RelativeDirective::class, directives)
internal val exportDirectives =
DirectiveOrdering.sortDirectives<ExportDirective>(ExportDirective::class, directives)
internal val relativeImports =
DirectiveOrdering.sortDirectives<RelativeDirective>(RelativeDirective::class, directives)

internal val typeDefs = builder.typeDefs.toImmutableList()
internal val hasTypeDefs = typeDefs.isNotEmpty()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import net.theevilreaper.dartpoet.util.SEMICOLON
*
* @constructor Creates a Dart import directive with the specified path as [String], a cast type as [CastType], and a importCast a [String].
*/
class DartDirective(
class DartDirective internal constructor(
private val path: String,
private val castType: CastType? = null,
private val importCast: String? = null,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package net.theevilreaper.dartpoet.directive

/**
* The [DirectiveFactory] should be used to create a new instance of different [Directive] implementations.
* It's required to use this factory to create a new instance because it will check if the given [DirectiveType].
* The usage of the constructor of each implementation is not possible.
* @author theEvilReaper
* @version 1.0.0
* @since 1.0.0
**/
object DirectiveFactory {

/**
* Creates a new instance from a [Directive] implementation depends on the given [DirectiveType].
* @param directive the type of the directive
* @param path the path to the file
* @return the created [Directive] instance
*/
@Throws(IllegalStateException::class)
fun create(
directive: DirectiveType,
path: String,
): Directive {
check(directive != DirectiveType.LIBRARY) {
"The library directive doesn't support a cast type or import cast. Please use #createLibDirective method instead"
}
return create(directive, path, false, null, null)
}

/**
* Creates a new instance from a [Directive] implementation depends on the given [DirectiveType].
* If the [Directive] implementation doesn't support the given [CastType] or [importCast] option.
* It will throw an [IllegalStateException].
* @param directive the type of the directive
* @param path the path to the file
* @param castType the [CastType] to use
* @param importCast the import cast to use
* @return the created [Directive] instance
*/
@Throws(IllegalStateException::class)
fun create(
directive: DirectiveType,
path: String,
castType: CastType? = null,
importCast: String? = null,
): Directive {
check(directive != DirectiveType.LIBRARY) {
"The library directive doesn't support a cast type or import cast. Please use #createLibDirective method instead"
}
return create(directive, path, false, castType, importCast)
}

@Throws(IllegalStateException::class)
fun createLib(
path: String,
partOf: Boolean = false,
) = create(DirectiveType.LIBRARY, path, partOf, null, null)

/**
* Creates a new instance from a [Directive] implementation depends on the given [DirectiveType].
* If the [Directive] implementation doesn't support the given [CastType] or [importCast] option.
* It will throw an [IllegalStateException].
* @param directive the type of the directive
* @param path the path to the file
* @param castType the [CastType] to use
* @param importCast the import cast to use
* @return the created [Directive] instance
*/
@Throws(IllegalStateException::class)
private fun create(
directive: DirectiveType,
path: String,
partOf: Boolean = false,
castType: CastType? = null,
importCast: String? = null,
): Directive {
return when (directive) {
DirectiveType.IMPORT -> DartDirective(path, castType, importCast)
DirectiveType.RELATIVE -> RelativeDirective(path, castType, importCast)
DirectiveType.PART -> PartDirective(path)
DirectiveType.LIBRARY -> LibraryDirective(path, partOf)
DirectiveType.EXPORT -> ExportDirective(path, castType, importCast)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package net.theevilreaper.dartpoet.directive


/**
* The [DirectiveType] enum represents the different types of directives.
* @since 1.0.0
* @version 1.0.0
* @author theEvilReaper
*/
enum class DirectiveType {
IMPORT,
RELATIVE,
PART,
LIBRARY,
EXPORT
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import net.theevilreaper.dartpoet.util.SEMICOLON
* @since 1.0.0
* @author theEvilReaper
*/
class ExportDirective(
class ExportDirective internal constructor(
private val path: String,
private val castType: CastType? = null,
private val importCast: String? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import net.theevilreaper.dartpoet.util.SEMICOLON
* @since 1.0.0
* @author theEvilReaper
*/
class LibraryDirective(
class LibraryDirective internal constructor(
private val path: String,
private val asPartOf: Boolean = false
) : BaseDirective(path) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.theevilreaper.dartpoet.directive

import net.theevilreaper.dartpoet.code.CodeWriter
import net.theevilreaper.dartpoet.directive.BaseDirective
import net.theevilreaper.dartpoet.util.SEMICOLON

/**
Expand All @@ -9,7 +10,7 @@ import net.theevilreaper.dartpoet.util.SEMICOLON
* @since 1.0.0
* @author theEvilReaper
*/
class PartDirective(
class PartDirective internal constructor(
private val path: String
) : BaseDirective(path) {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package net.theevilreaper.dartpoet.directive

import net.theevilreaper.dartpoet.code.CodeWriter
import net.theevilreaper.dartpoet.directive.BaseDirective
import net.theevilreaper.dartpoet.directive.CastType
import net.theevilreaper.dartpoet.util.SEMICOLON

/**
Expand All @@ -9,7 +11,7 @@ import net.theevilreaper.dartpoet.util.SEMICOLON
* @since 1.0.0
* @author theEvilReaper
*/
class RelativeDirective(
class RelativeDirective internal constructor(
private val path: String,
private val castType: CastType? = null,
private val importCast: String? = null,
Expand Down
26 changes: 13 additions & 13 deletions src/test/kotlin/net/theevilreaper/dartpoet/DartFileImportTest.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package net.theevilreaper.dartpoet

import com.google.common.truth.Truth.*
import com.google.common.truth.Truth.assertThat
import net.theevilreaper.dartpoet.annotation.AnnotationSpec
import net.theevilreaper.dartpoet.clazz.ClassSpec
import net.theevilreaper.dartpoet.code.buildCodeBlock
import net.theevilreaper.dartpoet.directive.CastType
import net.theevilreaper.dartpoet.directive.DartDirective
import net.theevilreaper.dartpoet.directive.ExportDirective
import net.theevilreaper.dartpoet.directive.PartDirective
import net.theevilreaper.dartpoet.directive.DirectiveFactory
import net.theevilreaper.dartpoet.directive.DirectiveType
import net.theevilreaper.dartpoet.function.FunctionSpec
import net.theevilreaper.dartpoet.type.ClassName
import net.theevilreaper.dartpoet.type.ParameterizedTypeName.Companion.parameterizedBy
Expand All @@ -22,10 +21,10 @@ class DartFileImportTest {
val reduxAction = ClassName("ReduxAction").parameterizedBy(appState)
val dartFile = DartFile.builder("Test")
.directives(
DartDirective("dart:io"),
DartDirective("dart:math"),
DartDirective("async_redux/async_redux.dart"),
DartDirective("model/${model.name}.dart"),
DirectiveFactory.create(DirectiveType.IMPORT, "dart:io"),
DirectiveFactory.create(DirectiveType.IMPORT, "dart:math"),
DirectiveFactory.create(DirectiveType.IMPORT, "async_redux/async_redux.dart"),
DirectiveFactory.create(DirectiveType.IMPORT, "model/${model.name}.dart"),
)
.type(
ClassSpec.builder("TestAction")
Expand Down Expand Up @@ -74,10 +73,10 @@ class DartFileImportTest {
fun `test directives with an export directive`() {
val classFile = DartFile.builder("House")
.directives(
DartDirective("dart:io"),
DartDirective("door"),
PartDirective("house_part.dart"),
ExportDirective("garden.dart", CastType.SHOW, "garden"),
DirectiveFactory.create(DirectiveType.IMPORT, "dart:io"),
DirectiveFactory.create(DirectiveType.IMPORT, "door"),
DirectiveFactory.create(DirectiveType.PART, "house_part.dart"),
DirectiveFactory.create(DirectiveType.EXPORT, "garden.dart", CastType.SHOW, "garden"),
)
.type(
ClassSpec.builder("House")
Expand All @@ -102,6 +101,7 @@ class DartFileImportTest {
@immutable
class House {}
""".trimIndent())
""".trimIndent()
)
}
}
30 changes: 15 additions & 15 deletions src/test/kotlin/net/theevilreaper/dartpoet/DartFileTest.kt
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
package net.theevilreaper.dartpoet

import com.google.common.truth.Truth.*
import com.google.common.truth.Truth.assertThat
import net.theevilreaper.dartpoet.annotation.AnnotationSpec
import net.theevilreaper.dartpoet.clazz.ClassSpec
import net.theevilreaper.dartpoet.code.buildCodeBlock
import net.theevilreaper.dartpoet.directive.CastType
import net.theevilreaper.dartpoet.directive.DirectiveFactory
import net.theevilreaper.dartpoet.directive.DirectiveType
import net.theevilreaper.dartpoet.enum.EnumPropertySpec
import net.theevilreaper.dartpoet.function.FunctionSpec
import net.theevilreaper.dartpoet.function.constructor.ConstructorSpec
import net.theevilreaper.dartpoet.directive.DartDirective
import net.theevilreaper.dartpoet.directive.CastType
import net.theevilreaper.dartpoet.directive.LibraryDirective
import net.theevilreaper.dartpoet.directive.PartDirective
import net.theevilreaper.dartpoet.function.typedef.TypeDefSpec
import net.theevilreaper.dartpoet.property.consts.ConstantPropertySpec
import net.theevilreaper.dartpoet.parameter.ParameterSpec
import net.theevilreaper.dartpoet.property.PropertySpec
import net.theevilreaper.dartpoet.property.consts.ConstantPropertySpec
import net.theevilreaper.dartpoet.type.ClassName
import net.theevilreaper.dartpoet.type.DYNAMIC
import net.theevilreaper.dartpoet.type.ParameterizedTypeName.Companion.parameterizedBy
import net.theevilreaper.dartpoet.type.asTypeName
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.Test
import kotlin.test.assertContentEquals

Expand Down Expand Up @@ -89,9 +89,9 @@ class DartFileTest {
}
val versionFile = DartFile.builder("version.dart")
.directives(
DartDirective("freezed_annotation/freezed_annotation.dart"),
PartDirective("version.freezed.dart"),
PartDirective("version.g.dart")
DirectiveFactory.create(DirectiveType.IMPORT, "freezed_annotation/freezed_annotation.dart"),
DirectiveFactory.create(DirectiveType.PART, "version.freezed.dart"),
DirectiveFactory.create(DirectiveType.PART, "version.g.dart")
)
.type(
versionFreezedClass
Expand Down Expand Up @@ -133,9 +133,9 @@ class DartFileTest {
.build()
)
.directives(
DartDirective("dart:html"),
LibraryDirective("testLib"),
DartDirective("dart:math", CastType.AS, "math"),
DirectiveFactory.create(DirectiveType.IMPORT, "dart:html"),
DirectiveFactory.createLib("testLib"),
DirectiveFactory.create(DirectiveType.IMPORT, "dart:math", CastType.AS, "math"),
)
.build()
assertThat(libClass.toString()).isEqualTo(
Expand Down Expand Up @@ -251,7 +251,7 @@ class DartFileTest {
.build()

val file = DartFile.builder("${className}Handler")
.directive(LibraryDirective("testLibrary", true))
.directive(DirectiveFactory.createLib("testLibrary", true))
.type(handlerApiClass)
.build()
assertThat(file.toString()).isEqualTo(
Expand Down Expand Up @@ -336,7 +336,7 @@ class DartFileTest {
fun `test class write with constant values`() {
val name = "environment"
val classFile = DartFile.builder(name)
.directive(DartDirective("dart:html"))
.directive(DirectiveFactory.create(DirectiveType.IMPORT, "dart:html"))
.constants(
ConstantPropertySpec.fileConst("typeLive").initWith("1").build(),
ConstantPropertySpec.fileConst("typeTest").initWith("10").build(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package net.theevilreaper.dartpoet.directive

import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.MethodSource
import java.util.stream.Stream

class DirectiveFactoryTest {

companion object {

@JvmStatic
private fun invalidFactoryUsage() = Stream.of(
Arguments.of(
{ DirectiveFactory.create(DirectiveType.LIBRARY, "") },
"The library directive doesn't support a cast type or import cast. Please use #createLibDirective method instead"
),
Arguments.of(
{ DirectiveFactory.create(DirectiveType.LIBRARY, "", castType = CastType.HIDE) },
"The library directive doesn't support a cast type or import cast. Please use #createLibDirective method instead"
),
)
}

@ParameterizedTest
@MethodSource("invalidFactoryUsage")
fun `test invalid factory usage`(current: () -> Directive, expectedMessage: String) {
val exception = assertThrows<IllegalStateException> { current() }
assertEquals(IllegalStateException::class.java, exception.javaClass)
assertEquals(expectedMessage, exception.message)
}
}
Loading

0 comments on commit 48f3255

Please sign in to comment.