Skip to content

Commit

Permalink
Improve code readability.
Browse files Browse the repository at this point in the history
  • Loading branch information
Oleg-Melnik committed Nov 24, 2023
1 parent 6f6e5dd commit de3f52f
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public class SizeOptionView : View<SizeOptionId,
event.option.value,
ArrayOfSizeOption::class.java
)
builder().setSizeExpression(value.value)
builder().setValidationExpression(value.value)
}
}

Expand All @@ -86,9 +86,9 @@ private class SizeOptionViewRepository : ViewRepository<SizeOptionId,
{ message: FieldOptionDiscovered, _: EventContext? ->
EventRoute.withId(
SizeOptionId.newBuilder()
.setFile(message.file)
.setType(message.type)
.setField(message.field)
.setFilePath(message.file)
.setTypeName(message.type)
.setFieldName(message.field)
.build()
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2023, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and/or binary forms, with or without
* modification, must retain the above copyright notice and the following
* disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package io.spine.protodata.hello

import com.google.protobuf.StringValue
import io.spine.protobuf.AnyPacker
import io.spine.protodata.ProtobufSourceFile

internal fun ProtobufSourceFile.javaPackage(): String {

val optionName = "java_package"

val option = file.optionList.find {
it.name == optionName
}
check(option != null) { "Cannot find option '$optionName'" }

return AnyPacker.unpack(
option.value,
StringValue::class.java
).value
}

internal fun ProtobufSourceFile.fieldNames(typeName: String): Iterable<String> {

val type = typeMap.values.find {
it.name.simpleName == typeName
}
check(type != null) { "Cannot find type '$typeName' in $filePath" }
return type.fieldList.map { it.name.value }
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@
*/
package io.spine.protodata.hello

import com.google.protobuf.StringValue
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import io.spine.protobuf.AnyPacker
import io.spine.protodata.ProtobufSourceFile
import io.spine.protodata.renderer.Renderer
import io.spine.protodata.renderer.SourceFileSet
Expand All @@ -55,33 +53,33 @@ public class ValidateSizeOptionRenderer : Renderer<Kotlin>(Kotlin.lang()) {
sizeOption: SizeOption,
sources: SourceFileSet
) {
val protoFile = select<ProtobufSourceFile>().all().find {
it.file.path.value == sizeOption.id.file.value
val protobufSourceFile = select<ProtobufSourceFile>().all().find {
it.file.path.value == sizeOption.id.filePath.value
}
check(protoFile != null) {
"Cannot find file: " + sizeOption.id.file.value
check(protobufSourceFile != null) {
"Cannot find 'ProtobufSourceFile' for " +
sizeOption.id.filePath.value
}

val className = sizeOption.id.type.simpleName
val fieldName = propertyName(sizeOption.id.field.value)
val packageName = javaPackageOption(protoFile)
val protoFieldNames = collectFieldNamesForType(className, protoFile)
val expression = buildExpression(
sizeOption.sizeExpression,
protoFieldNames
val packageName = protobufSourceFile.javaPackage()
val typeName = sizeOption.id.typeName.simpleName
val fieldName = sizeOption.id.fieldName.value.camelCase()
val validationExpression = buildExpression(
sizeOption.validationExpression,
protobufSourceFile.fieldNames(typeName)
)
val filePath = Path.of(
packageName.replace('.', '/'),
className + "Ext.kt"
typeName + "Ext.kt"
)

sources.createFile(
filePath,
generateFileContent(
packageName,
className,
typeName,
fieldName,
expression
validationExpression
)
)
}
Expand All @@ -95,13 +93,15 @@ private fun generateFileContent(
) = FileSpec.builder(ClassName(packageName, typeName))
.indent(" ")
.addFunction(
FunSpec.builder("validate" + fieldName.camelCase() + "Count")
FunSpec.builder("validate" + fieldName + "Count")
.receiver(ClassName(packageName, typeName, "Builder"))
.beginControlFlow(
"check(%LCount == %L)", fieldName, expression
"check(%LCount == %L)",
fieldName.propertyName(),
expression
)
.addStatement(
"\"'%L' count does not match the validation expression.\"",
"\"%L count does not match the validation expression.\"",
fieldName
)
.endControlFlow()
Expand All @@ -112,41 +112,12 @@ private fun generateFileContent(

private fun buildExpression(
expression: String,
protoFieldNames: List<String>
): String {
var result = expression
protoFieldNames.forEach { result = result.replace(it, propertyName(it)) }
return result
}

private fun javaPackageOption(protoFile: ProtobufSourceFile): String {

val optionName = "java_package"

val option = protoFile.file.optionList.find {
it.name == optionName
snakeCaseFieldNames: Iterable<String>
) = mutableListOf(expression)
.plus(snakeCaseFieldNames)
.reduce { result, snakeCaseName ->
result.replace(snakeCaseName, snakeCaseName.propertyName())
}
check(option != null) { "Cannot find option: $optionName" }

return AnyPacker.unpack(
option.value,
StringValue::class.java
).value
}

private fun collectFieldNamesForType(
simpleTypeName: String,
protoFile: ProtobufSourceFile
): List<String> {

val type = protoFile.typeMap.values.find {
it.name.simpleName == simpleTypeName
}
check(type != null) {
"Cannot find type '$simpleTypeName' in $protoFile"
}
return type.fieldList.map { it.name.value }
}

private fun propertyName(protoFieldName: String) =
protoFieldName.camelCase().replaceFirstChar { it.lowercase() }
private fun String.propertyName() =
camelCase().replaceFirstChar { it.lowercase() }
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import "spine/options.proto";

option (type_url_prefix) = "type.spine.io";
option java_package = "io.spine.protodata.hello";
option java_outer_classname = "SizeOptionProjectionProto";
option java_outer_classname = "SizeOptionProto";
option java_multiple_files = true;

import "spine/protodata/ast.proto";
Expand All @@ -42,14 +42,14 @@ message SizeOption {

SizeOptionId id = 1;

string size_expression = 2;
string validation_expression = 2;
}

message SizeOptionId {

spine.protodata.FilePath file = 1;
spine.protodata.FilePath file_path = 1;

spine.protodata.TypeName type = 2;
spine.protodata.TypeName type_name = 2;

spine.protodata.FieldName field = 3;
spine.protodata.FieldName field_name = 3;
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,14 @@ class `Board builder extension should` {
@Test
fun `validate cell count`() {

Board.newBuilder()
.setSideSize(3)
val sideSize = 3
val builder = Board.newBuilder()
.setSideSize(sideSize)

.addCell(Cell.newBuilder())
.addCell(Cell.newBuilder())
.addCell(Cell.newBuilder())

.addCell(Cell.newBuilder())
.addCell(Cell.newBuilder())
.addCell(Cell.newBuilder())

.addCell(Cell.newBuilder())
.addCell(Cell.newBuilder())
.addCell(Cell.newBuilder())

.validateCellCount()
repeat(sideSize * sideSize) {
builder.addCell(Cell.newBuilder())
}
builder.validateCellCount()
}

@Test
Expand Down

0 comments on commit de3f52f

Please sign in to comment.