Skip to content

Commit b4739b9

Browse files
authored
Merge pull request #1029 from Kotlin/rename-to-camelcase-2
Rename to camelCase support in compiler plugin
2 parents b67c928 + cd5888c commit b4739b9

File tree

7 files changed

+161
-52
lines changed

7 files changed

+161
-52
lines changed

core/api/core.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7496,6 +7496,7 @@ public final class org/jetbrains/kotlinx/dataframe/api/RenameKt {
74967496
public static final fun rename (Lorg/jetbrains/kotlinx/dataframe/columns/ColumnReference;Lkotlin/reflect/KProperty;)Lorg/jetbrains/kotlinx/dataframe/columns/ColumnReference;
74977497
public static final fun rename (Lorg/jetbrains/kotlinx/dataframe/columns/ColumnReference;Lorg/jetbrains/kotlinx/dataframe/columns/ColumnAccessor;)Lorg/jetbrains/kotlinx/dataframe/columns/ColumnReference;
74987498
public static final fun renameToCamelCase (Lorg/jetbrains/kotlinx/dataframe/DataFrame;)Lorg/jetbrains/kotlinx/dataframe/DataFrame;
7499+
public static final fun renameToCamelCase (Lorg/jetbrains/kotlinx/dataframe/columns/ColumnReference;)Lorg/jetbrains/kotlinx/dataframe/columns/ColumnReference;
74997500
public static final fun toCamelCase (Lorg/jetbrains/kotlinx/dataframe/api/RenameClause;)Lorg/jetbrains/kotlinx/dataframe/DataFrame;
75007501
}
75017502

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/rename.kt

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ public class RenameClause<T, C>(internal val df: DataFrame<T>, internal val colu
5252
* and converting the first char to lowercase.
5353
* Even [DataFrames][DataFrame] inside [FrameColumns][FrameColumn] are traversed recursively.
5454
*/
55+
@Refine
56+
@Interpretable("RenameToCamelCase")
5557
public fun <T> DataFrame<T>.renameToCamelCase(): DataFrame<T> =
5658
// recursively rename all columns written with delimiters or starting with a capital to camel case
5759
rename {
@@ -83,17 +85,28 @@ public fun <T, C> RenameClause<T, C>.into(transform: (ColumnWithPath<C>) -> Stri
8385
* Renames the selected columns to `camelCase` by replacing all [delimiters][DELIMITERS_REGEX]
8486
* and converting the first char to lowercase.
8587
*/
86-
public fun <T, C> RenameClause<T, C>.toCamelCase(): DataFrame<T> =
87-
into {
88-
it.name()
89-
.toCamelCaseByDelimiters(DELIMITERS_REGEX)
90-
.replaceFirstChar { it.lowercaseChar() }
91-
}
88+
@Refine
89+
@Interpretable("RenameToCamelCaseClause")
90+
public fun <T, C> RenameClause<T, C>.toCamelCase(): DataFrame<T> = into { it.renameToCamelCase().name() }
9291

9392
// endregion
9493

9594
// region DataColumn
9695

96+
/**
97+
* ## Rename to camelCase
98+
*
99+
* Renames this column to `camelCase` by replacing all [delimiters][DELIMITERS_REGEX]
100+
* and converting the first char to lowercase.
101+
*/
102+
@Suppress("UNCHECKED_CAST")
103+
public fun <T, C : ColumnReference<T>> C.renameToCamelCase(): C =
104+
rename(
105+
this.name()
106+
.toCamelCaseByDelimiters(DELIMITERS_REGEX)
107+
.replaceFirstChar { it.lowercaseChar() },
108+
) as C
109+
97110
@Suppress("UNCHECKED_CAST")
98111
public fun <T, C : ColumnReference<T>> C.rename(column: KProperty<T>): C = rename(column.columnName) as C
99112

plugins/expressions-converter/tests-gen/org/jetbrains/kotlinx/dataframe/ExplainerBlackBoxCodegenTestGenerated.java

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import com.intellij.testFramework.TestDataPath;
66
import org.jetbrains.kotlin.test.util.KtTestUtil;
77
import org.jetbrains.kotlin.test.TestMetadata;
8-
import org.junit.jupiter.api.Nested;
98
import org.junit.jupiter.api.Test;
109

1110
import java.io.File;
@@ -16,26 +15,26 @@
1615
@TestMetadata("testData/box")
1716
@TestDataPath("$PROJECT_ROOT")
1817
public class ExplainerBlackBoxCodegenTestGenerated extends AbstractExplainerBlackBoxCodegenTest {
19-
@Test
20-
public void testAllFilesPresentInBox() throws Exception {
21-
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("testData/box"), Pattern.compile("^(.+)\\.kt$"), null, true);
22-
}
23-
24-
@Test
25-
@TestMetadata("any.kt")
26-
public void testAny() throws Exception {
27-
runTest("testData/box/any.kt");
28-
}
29-
30-
@Test
31-
@TestMetadata("df.kt")
32-
public void testDf() throws Exception {
33-
runTest("testData/box/df.kt");
34-
}
35-
36-
@Test
37-
@TestMetadata("test.kt")
38-
public void testTest() throws Exception {
39-
runTest("testData/box/test.kt");
40-
}
18+
@Test
19+
public void testAllFilesPresentInBox() {
20+
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("testData/box"), Pattern.compile("^(.+)\\.kt$"), null, true);
21+
}
22+
23+
@Test
24+
@TestMetadata("any.kt")
25+
public void testAny() {
26+
runTest("testData/box/any.kt");
27+
}
28+
29+
@Test
30+
@TestMetadata("df.kt")
31+
public void testDf() {
32+
runTest("testData/box/df.kt");
33+
}
34+
35+
@Test
36+
@TestMetadata("test.kt")
37+
public void testTest() {
38+
runTest("testData/box/test.kt");
39+
}
4140
}
Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
package org.jetbrains.kotlinx.dataframe.plugin.impl.api
22

3+
import org.jetbrains.kotlinx.dataframe.api.rename
4+
import org.jetbrains.kotlinx.dataframe.api.renameToCamelCase
5+
import org.jetbrains.kotlinx.dataframe.api.toCamelCase
6+
import org.jetbrains.kotlinx.dataframe.columns.toColumnSet
37
import org.jetbrains.kotlinx.dataframe.plugin.impl.AbstractInterpreter
48
import org.jetbrains.kotlinx.dataframe.plugin.impl.AbstractSchemaModificationInterpreter
59
import org.jetbrains.kotlinx.dataframe.plugin.impl.Arguments
610
import org.jetbrains.kotlinx.dataframe.plugin.impl.PluginDataFrameSchema
711
import org.jetbrains.kotlinx.dataframe.plugin.impl.SimpleCol
8-
import org.jetbrains.kotlinx.dataframe.plugin.impl.SimpleDataColumn
912
import org.jetbrains.kotlinx.dataframe.plugin.impl.SimpleColumnGroup
13+
import org.jetbrains.kotlinx.dataframe.plugin.impl.SimpleDataColumn
1014
import org.jetbrains.kotlinx.dataframe.plugin.impl.SimpleFrameColumn
15+
import org.jetbrains.kotlinx.dataframe.plugin.impl.asDataFrame
1116
import org.jetbrains.kotlinx.dataframe.plugin.impl.dataFrame
17+
import org.jetbrains.kotlinx.dataframe.plugin.impl.toPluginDataFrameSchema
1218

1319
class Rename : AbstractInterpreter<RenameClauseApproximation>() {
1420
private val Arguments.receiver by dataFrame()
1521
private val Arguments.columns: ColumnsResolver by arg()
16-
override fun Arguments.interpret(): RenameClauseApproximation {
17-
return RenameClauseApproximation(receiver, columns)
18-
}
22+
23+
override fun Arguments.interpret(): RenameClauseApproximation = RenameClauseApproximation(receiver, columns)
1924
}
2025

2126
class RenameClauseApproximation(val schema: PluginDataFrameSchema, val columns: ColumnsResolver)
@@ -28,55 +33,87 @@ class RenameInto : AbstractSchemaModificationInterpreter() {
2833
val columns = receiver.columns.resolve(receiver.schema)
2934
require(columns.size == newNames.size)
3035
var i = 0
31-
return receiver.schema.map(columns.mapTo(mutableSetOf()) { it.path.path }, nextName = { newNames[i].also { i += 1 } })
36+
return receiver.schema.map(
37+
selected = columns.mapTo(mutableSetOf()) { it.path.path },
38+
nextName = { newNames[i].also { i += 1 } },
39+
)
3240
}
3341
}
3442

35-
internal fun PluginDataFrameSchema.map(selected: ColumnsSet, nextName: () -> String): PluginDataFrameSchema {
36-
return PluginDataFrameSchema(
37-
f(columns(), nextName, selected, emptyList())
43+
internal fun PluginDataFrameSchema.map(selected: ColumnsSet, nextName: () -> String): PluginDataFrameSchema =
44+
PluginDataFrameSchema(
45+
f(columns(), nextName, selected, emptyList()),
3846
)
39-
}
4047

41-
internal fun f(columns: List<SimpleCol>, nextName: () -> String, selected: ColumnsSet, path: List<String>): List<SimpleCol> {
42-
return columns.map {
48+
internal fun f(
49+
columns: List<SimpleCol>,
50+
nextName: () -> String,
51+
selected: ColumnsSet,
52+
path: List<String>,
53+
): List<SimpleCol> =
54+
columns.map {
4355
val fullPath = path + listOf(it.name)
4456
when (it) {
4557
is SimpleColumnGroup -> {
4658
val group = if (fullPath in selected) {
4759
it.rename(nextName())
48-
} else {
60+
} else {
4961
it
5062
}
5163
group.map(selected, fullPath, nextName)
5264
}
65+
5366
is SimpleFrameColumn -> {
5467
val frame = if (fullPath in selected) {
5568
it.rename(nextName())
56-
} else {
69+
} else {
5770
it
5871
}
5972
frame.map(selected, fullPath, nextName)
6073
}
74+
6175
is SimpleDataColumn -> if (fullPath in selected) {
6276
it.rename(nextName())
6377
} else {
6478
it
6579
}
6680
}
6781
}
68-
}
6982

70-
internal fun SimpleColumnGroup.map(selected: ColumnsSet, path: List<String>, nextName: () -> String): SimpleColumnGroup {
71-
return SimpleColumnGroup(
72-
name,
73-
f(columns(), nextName, selected, path)
83+
internal fun SimpleColumnGroup.map(
84+
selected: ColumnsSet,
85+
path: List<String>,
86+
nextName: () -> String,
87+
): SimpleColumnGroup =
88+
SimpleColumnGroup(
89+
name = name,
90+
columns = f(columns(), nextName, selected, path),
7491
)
75-
}
7692

77-
internal fun SimpleFrameColumn.map(selected: ColumnsSet, path: List<String>, nextName: () -> String): SimpleFrameColumn {
78-
return SimpleFrameColumn(
79-
name,
80-
f(columns(), nextName, selected, path)
93+
internal fun SimpleFrameColumn.map(
94+
selected: ColumnsSet,
95+
path: List<String>,
96+
nextName: () -> String,
97+
): SimpleFrameColumn =
98+
SimpleFrameColumn(
99+
name = name,
100+
columns = f(columns(), nextName, selected, path),
81101
)
102+
103+
class RenameToCamelCase : AbstractSchemaModificationInterpreter() {
104+
val Arguments.receiver by dataFrame()
105+
106+
override fun Arguments.interpret(): PluginDataFrameSchema =
107+
receiver.asDataFrame().renameToCamelCase().toPluginDataFrameSchema()
108+
}
109+
110+
class RenameToCamelCaseClause : AbstractSchemaModificationInterpreter() {
111+
val Arguments.receiver: RenameClauseApproximation by arg()
112+
113+
override fun Arguments.interpret(): PluginDataFrameSchema {
114+
val selectedPaths = receiver.columns.resolve(receiver.schema).map { it.path }
115+
return receiver.schema.asDataFrame()
116+
.rename { selectedPaths.toColumnSet() }.toCamelCase()
117+
.toPluginDataFrameSchema()
118+
}
82119
}

plugins/kotlin-dataframe/src/org/jetbrains/kotlinx/dataframe/plugin/loadInterpreter.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ import org.jetbrains.kotlinx.dataframe.plugin.impl.api.TrimMargin
102102
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.Update0
103103
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.UpdateWith0
104104
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.ValueCounts
105+
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.RenameToCamelCase
106+
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.RenameToCamelCaseClause
105107
import org.jetbrains.kotlinx.dataframe.plugin.utils.Names
106108

107109
internal fun FirFunctionCall.loadInterpreter(session: FirSession): Interpreter<*>? {
@@ -251,6 +253,8 @@ internal inline fun <reified T> String.load(): T {
251253
"Aggregate" -> Aggregate()
252254
"DataFrameOf3" -> DataFrameOf3()
253255
"ValueCounts" -> ValueCounts()
256+
"RenameToCamelCase" -> RenameToCamelCase()
257+
"RenameToCamelCaseClause" -> RenameToCamelCaseClause()
254258
else -> error("$this")
255259
} as T
256260
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import org.jetbrains.kotlinx.dataframe.*
2+
import org.jetbrains.kotlinx.dataframe.annotations.*
3+
import org.jetbrains.kotlinx.dataframe.api.*
4+
import org.jetbrains.kotlinx.dataframe.io.*
5+
6+
fun box(): String {
7+
// Test DataFrame.renameToCamelCase()
8+
val df = dataFrameOf("first_name", "last_name", "user_age")(
9+
"John", "Doe", 30
10+
)
11+
val renamed = df.renameToCamelCase()
12+
13+
// Verify extension properties
14+
if (renamed.firstName[0] != "John") return "DataFrame.renameToCamelCase: 'firstName' failed"
15+
if (renamed.lastName[0] != "Doe") return "DataFrame.renameToCamelCase: 'lastName' failed"
16+
if (renamed.userAge[0] != 30) return "DataFrame.renameToCamelCase: 'userAge' failed"
17+
18+
// Test RenameClause.toCamelCase()
19+
val df2 = dataFrameOf("first_name", "last_name", "user_age")(
20+
"Jane", "Smith", 25
21+
)
22+
val renamed2 = df2.rename { first_name and last_name and user_age }.toCamelCase()
23+
24+
// Verify extension properties for RenameClause.toCamelCase
25+
if (renamed2.firstName[0] != "Jane") return "RenameClause.toCamelCase: 'firstName' failed"
26+
if (renamed2.lastName[0] != "Smith") return "RenameClause.toCamelCase: 'lastName' failed"
27+
if (renamed2.userAge[0] != 25) return "RenameClause.toCamelCase: 'userAge' failed"
28+
29+
// Test nested DataFrame with both methods
30+
val nestedDf = dataFrameOf("user_info")(
31+
dataFrameOf("first_name", "last_name")(
32+
"John", "Doe"
33+
)
34+
)
35+
36+
// Test DataFrame.renameToCamelCase with nested
37+
val renamedNested = nestedDf.renameToCamelCase()
38+
val nestedData = renamedNested.userInfo[0]
39+
if (nestedData.firstName[0] != "John") return "Nested DataFrame.renameToCamelCase: 'firstName' failed"
40+
if (nestedData.lastName[0] != "Doe") return "Nested DataFrame.renameToCamelCase: 'lastName' failed"
41+
42+
// Test RenameClause.toCamelCase with nested, only uses selection
43+
val renamedNested2 = nestedDf.rename { all() }.toCamelCase()
44+
val nestedData2 = renamedNested2.userInfo[0]
45+
if (nestedData2.first_name[0] != "John") return "Nested RenameClause.toCamelCase: 'first_name' failed"
46+
if (nestedData2.last_name[0] != "Doe") return "Nested RenameClause.toCamelCase: 'last_name' failed"
47+
48+
return "OK"
49+
}

plugins/kotlin-dataframe/tests-gen/org/jetbrains/kotlin/fir/dataframe/DataFrameBlackBoxCodegenTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,12 @@ public void testRename() {
406406
runTest("testData/box/rename.kt");
407407
}
408408

409+
@Test
410+
@TestMetadata("renameToCamelCase.kt")
411+
public void testRenameToCamelCase() {
412+
runTest("testData/box/renameToCamelCase.kt");
413+
}
414+
409415
@Test
410416
@TestMetadata("Schema.kt")
411417
public void testSchema() {

0 commit comments

Comments
 (0)