Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
梦境迷离
Scala Macro Tools
提交
dc6bcee1
S
Scala Macro Tools
项目概览
梦境迷离
/
Scala Macro Tools
上一次同步 1 年多
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
Scala Macro Tools
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
dc6bcee1
编写于
5月 14, 2022
作者:
梦境迷离
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
support read/write file
上级
c62edcd9
变更
11
显示空白变更内容
内联
并排
Showing
11 changed file
with
238 addition
and
87 deletion
+238
-87
.gitignore
.gitignore
+1
-0
build.sbt
build.sbt
+1
-1
smt-csv-core/src/main/scala/org/bitlap/csv/core/CsvableBuilder.scala
...e/src/main/scala/org/bitlap/csv/core/CsvableBuilder.scala
+11
-0
smt-csv-core/src/main/scala/org/bitlap/csv/core/FileUtils.scala
...v-core/src/main/scala/org/bitlap/csv/core/FileUtils.scala
+82
-0
smt-csv-core/src/main/scala/org/bitlap/csv/core/ScalableBuilder.scala
.../src/main/scala/org/bitlap/csv/core/ScalableBuilder.scala
+11
-1
smt-csv-core/src/main/scala/org/bitlap/csv/core/ScalableHelper.scala
...e/src/main/scala/org/bitlap/csv/core/ScalableHelper.scala
+7
-16
smt-csv-core/src/main/scala/org/bitlap/csv/core/macros/DeriveCsvableBuilder.scala
...ala/org/bitlap/csv/core/macros/DeriveCsvableBuilder.scala
+49
-31
smt-csv-core/src/main/scala/org/bitlap/csv/core/macros/DeriveScalableBuilder.scala
...la/org/bitlap/csv/core/macros/DeriveScalableBuilder.scala
+42
-28
smt-csv-core/src/main/scala/org/bitlap/csv/core/macros/DeriveToCaseClass.scala
.../scala/org/bitlap/csv/core/macros/DeriveToCaseClass.scala
+3
-5
smt-csv-core/src/main/scala/org/bitlap/csv/core/macros/DeriveToString.scala
...ain/scala/org/bitlap/csv/core/macros/DeriveToString.scala
+4
-5
smt-csv-core/src/test/scala/org/bitlap/csv/core/test/CsvableAndScalableTest.scala
...ala/org/bitlap/csv/core/test/CsvableAndScalableTest.scala
+27
-0
未找到文件。
.gitignore
浏览文件 @
dc6bcee1
...
@@ -13,6 +13,7 @@
...
@@ -13,6 +13,7 @@
.idea/
.idea/
*.iml
*.iml
.bsp
.bsp
*.csv
examples/scala2-11/target/
examples/scala2-11/target/
examples/scala2-12/target/
examples/scala2-12/target/
examples/scala2-13/target/
examples/scala2-13/target/
...
...
build.sbt
浏览文件 @
dc6bcee1
...
@@ -11,7 +11,7 @@ ThisBuild / resolvers ++= Seq(
...
@@ -11,7 +11,7 @@ ThisBuild / resolvers ++= Seq(
lazy
val
scala212
=
"2.12.14"
lazy
val
scala212
=
"2.12.14"
lazy
val
scala211
=
"2.11.12"
lazy
val
scala211
=
"2.11.12"
lazy
val
scala213
=
"2.13.8"
lazy
val
scala213
=
"2.13.8"
lazy
val
lastVersionForExamples
=
"0.
4
.2"
lazy
val
lastVersionForExamples
=
"0.
5
.2"
lazy
val
scalatestVersion
=
"3.2.12"
lazy
val
scalatestVersion
=
"3.2.12"
lazy
val
zioVersion
=
"1.0.14"
lazy
val
zioVersion
=
"1.0.14"
...
...
smt-csv-core/src/main/scala/org/bitlap/csv/core/CsvableBuilder.scala
浏览文件 @
dc6bcee1
...
@@ -31,6 +31,8 @@ import org.bitlap.csv.core.macros.DeriveCsvableBuilder
...
@@ -31,6 +31,8 @@ import org.bitlap.csv.core.macros.DeriveCsvableBuilder
*/
*/
class
CsvableBuilder
[
T
]
{
class
CsvableBuilder
[
T
]
{
import
java.io.File
/**
/**
* Convert this CSV column string to any Scala types.
* Convert this CSV column string to any Scala types.
*
*
...
@@ -70,6 +72,15 @@ class CsvableBuilder[T] {
...
@@ -70,6 +72,15 @@ class CsvableBuilder[T] {
*/
*/
def
convert
(
ts
:
List
[
T
])
:
String
=
macro
DeriveCsvableBuilder
.
convertDefaultImpl
[
T
]
def
convert
(
ts
:
List
[
T
])
:
String
=
macro
DeriveCsvableBuilder
.
convertDefaultImpl
[
T
]
/**
* Convert the sequence of Scala case class to CSV string and write to file.
*
* @param ts The sequence of Scala case class.
* @param file File to save CSV string.
* @return
*/
def
writeTo
(
ts
:
List
[
T
],
file
:
File
)
:
Boolean
=
macro
DeriveCsvableBuilder
.
writeToFileImpl
[
T
]
}
}
object
CsvableBuilder
{
object
CsvableBuilder
{
...
...
smt-csv-core/src/main/scala/org/bitlap/csv/core/FileUtils.scala
0 → 100644
浏览文件 @
dc6bcee1
/*
* Copyright (c) 2022 bitlap
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package
org.bitlap.csv.core
import
java.io._
import
scala.io.Source
import
scala.language.reflectiveCalls
import
scala.util.control.Exception.ignoring
import
scala.collection.mutable.ListBuffer
/**
* @author 梦境迷离
* @version 1.0,5/13/22
*/
object
FileUtils
{
type
Closable
=
{
def
close
()
:
Unit
}
def
using
[
R
<:
Closable
,
T
](
resource
:
=>
R
)(
f
:
R
=>
T
)
:
T
=
try
f
(
resource
)
finally
ignoring
(
classOf
[
Throwable
])
apply
{
resource
.
close
()
}
def
writer
(
file
:
File
,
lines
:
List
[
String
])
:
Boolean
=
{
checkFile
(
file
)
val
bufferedOutputStream
=
new
BufferedOutputStream
(
new
FileOutputStream
(
file
))
try
using
(
new
PrintWriter
(
bufferedOutputStream
,
true
))
{
r
=>
lines
.
foreach
(
r
.
println
)
}
finally
bufferedOutputStream
.
close
()
true
}
def
reader
(
file
:
InputStream
,
charset
:
String
=
"UTF-8"
)
:
List
[
String
]
=
try
using
(
Source
.
fromInputStream
(
new
BufferedInputStream
(
file
),
charset
))
{
lines
=>
lines
.
getLines
().
toList
}
finally
file
.
close
()
def
checkFile
(
file
:
File
)
:
Unit
=
{
if
(
file
.
isDirectory
)
{
throw
new
Exception
(
s
"File path: $file is a directory."
)
}
if
(!
file
.
exists
())
{
file
.
createNewFile
()
}
}
def
readFileFunc
[
T
](
reader
:
BufferedReader
,
func
:
String
=>
Option
[
T
])
:
List
[
Option
[
T
]]
=
{
val
ts
=
ListBuffer
[
Option
[
T
]]()
var
line
:
String
=
null
FileUtils
.
using
(
new
BufferedReader
(
reader
))
{
input
=>
while
({
line
=
input
.
readLine
()
line
!=
null
})
ts
.
append
(
func
(
line
))
}
ts
.
result
()
}
}
smt-csv-core/src/main/scala/org/bitlap/csv/core/ScalableBuilder.scala
浏览文件 @
dc6bcee1
...
@@ -22,6 +22,7 @@
...
@@ -22,6 +22,7 @@
package
org.bitlap.csv.core
package
org.bitlap.csv.core
import
org.bitlap.csv.core.macros.DeriveScalableBuilder
import
org.bitlap.csv.core.macros.DeriveScalableBuilder
import
java.io.InputStream
/**
/**
* Builder to create a custom Csv Decoder.
* Builder to create a custom Csv Decoder.
...
@@ -70,6 +71,15 @@ class ScalableBuilder[T] {
...
@@ -70,6 +71,15 @@ class ScalableBuilder[T] {
*/
*/
def
convert
(
lines
:
List
[
String
])
:
List
[
Option
[
T
]]
=
macro
DeriveScalableBuilder
.
convertDefaultImpl
[
T
]
def
convert
(
lines
:
List
[
String
])
:
List
[
Option
[
T
]]
=
macro
DeriveScalableBuilder
.
convertDefaultImpl
[
T
]
/**
* Read all CSV lines of the file and convert them to the sequence of Scala case class.
*
* @param file InputStream of the CSV file.
* @param charset String charset of the CSV file content.
* @return
*/
def
readFrom
(
file
:
InputStream
,
charset
:
String
)
:
List
[
Option
[
T
]]
=
macro
DeriveScalableBuilder
.
readFromFileImpl
[
T
]
}
}
object
ScalableBuilder
{
object
ScalableBuilder
{
...
...
smt-csv-core/src/main/scala
-2.13
/org/bitlap/csv/core/ScalableHelper.scala
→
smt-csv-core/src/main/scala/org/bitlap/csv/core/ScalableHelper.scala
浏览文件 @
dc6bcee1
...
@@ -21,32 +21,23 @@
...
@@ -21,32 +21,23 @@
package
org.bitlap.csv.core
package
org.bitlap.csv.core
import
java.io.
{
BufferedReader
,
InputStreamReader
}
import
java.io.
{
BufferedReader
,
File
,
FileReader
,
InputStreamReader
}
import
scala.collection.mutable.ListBuffer
import
scala.util.Using
/**
/**
* Tool class for parsing CSV files.
* Tool class for parsing CSV files.
*
*
* @author 梦境迷离
* @author 梦境迷离
* @version 1.0,2022/5/
2
* @version 1.0,2022/5/
13
*/
*/
object
ScalableHelper
{
object
ScalableHelper
{
def
readCsvFromClassPath
[
T
<:
Product
](
fileName
:
String
)(
func
:
String
=>
Option
[
T
])
:
List
[
Option
[
T
]]
=
{
def
readCsvFromClassPath
[
T
<:
Product
](
fileName
:
String
)(
func
:
String
=>
Option
[
T
])
:
List
[
Option
[
T
]]
=
{
val
ts
=
ListBuffer
[
Option
[
T
]]()
val
reader
=
new
InputStreamReader
(
ClassLoader
.
getSystemResourceAsStream
(
fileName
))
val
reader
=
new
InputStreamReader
(
ClassLoader
.
getSystemResourceAsStream
(
fileName
))
val
bufferedReader
=
new
BufferedReader
(
reader
)
FileUtils
.
readFileFunc
[
T
](
new
BufferedReader
(
reader
),
func
)
var
line
:
String
=
null
Using
.
resource
(
bufferedReader
)
{
input
=>
while
({
line
=
input
.
readLine
()
line
!=
null
})
ts
.
append
(
func
(
line
))
}
}
ts
.
result
()
def
readCsvFromFile
[
T
<:
Product
](
file
:
File
)(
func
:
String
=>
Option
[
T
])
:
List
[
Option
[
T
]]
=
{
val
reader
=
new
BufferedReader
(
new
FileReader
(
file
))
FileUtils
.
readFileFunc
[
T
](
reader
,
func
)
}
}
}
}
smt-csv-core/src/main/scala/org/bitlap/csv/core/macros/DeriveCsvableBuilder.scala
浏览文件 @
dc6bcee1
...
@@ -25,6 +25,7 @@ import org.bitlap.csv.core.{ Csvable, CsvableBuilder }
...
@@ -25,6 +25,7 @@ import org.bitlap.csv.core.{ Csvable, CsvableBuilder }
import
scala.collection.mutable
import
scala.collection.mutable
import
scala.reflect.macros.whitebox
import
scala.reflect.macros.whitebox
import
java.io.File
/**
/**
* @author 梦境迷离
* @author 梦境迷离
...
@@ -44,10 +45,8 @@ class DeriveCsvableBuilder(override val c: whitebox.Context) extends AbstractMac
...
@@ -44,10 +45,8 @@ class DeriveCsvableBuilder(override val c: whitebox.Context) extends AbstractMac
private
val
csvableImplClassNamePrefix
=
"_CsvAnno$"
private
val
csvableImplClassNamePrefix
=
"_CsvAnno$"
private
val
funcArgsTempTermName
=
TermName
(
"temp"
)
private
val
funcArgsTempTermName
=
TermName
(
"temp"
)
def
setFieldImpl
[
T:
WeakTypeTag
,
SF:
WeakTypeTag
](
// scalafmt: { maxColumn = 400 }
scalaField
:
Expr
[
T
=>
SF
],
def
setFieldImpl
[
T:
WeakTypeTag
,
SF:
WeakTypeTag
](
scalaField
:
Expr
[
T
=>
SF
],
value
:
Expr
[
SF
=>
String
])
:
Expr
[
CsvableBuilder
[
T
]]
=
{
value
:
Expr
[
SF
=>
String
]
)
:
Expr
[
CsvableBuilder
[
T
]]
=
{
val
Function
(
_
,
Select
(
_
,
termName
))
=
scalaField
.
tree
val
Function
(
_
,
Select
(
_
,
termName
))
=
scalaField
.
tree
val
builderId
=
getBuilderId
(
annoBuilderPrefix
)
val
builderId
=
getBuilderId
(
annoBuilderPrefix
)
MacroCache
.
builderFunctionTrees
.
getOrElseUpdate
(
builderId
,
mutable
.
Map
.
empty
).
update
(
termName
.
toString
,
value
)
MacroCache
.
builderFunctionTrees
.
getOrElseUpdate
(
builderId
,
mutable
.
Map
.
empty
).
update
(
termName
.
toString
,
value
)
...
@@ -70,6 +69,9 @@ class DeriveCsvableBuilder(override val c: whitebox.Context) extends AbstractMac
...
@@ -70,6 +69,9 @@ class DeriveCsvableBuilder(override val c: whitebox.Context) extends AbstractMac
def
convertDefaultImpl
[
T:
WeakTypeTag
](
ts
:
Expr
[
List
[
T
]])
:
Expr
[
String
]
=
def
convertDefaultImpl
[
T:
WeakTypeTag
](
ts
:
Expr
[
List
[
T
]])
:
Expr
[
String
]
=
deriveFullCsvableImpl
[
T
](
ts
,
c
.
Expr
[
Char
](
q
"','"
))
deriveFullCsvableImpl
[
T
](
ts
,
c
.
Expr
[
Char
](
q
"','"
))
def
writeToFileImpl
[
T:
WeakTypeTag
](
ts
:
Expr
[
List
[
T
]],
file
:
Expr
[
File
])
:
Expr
[
Boolean
]
=
deriveFullIntoFileCsvableImpl
[
T
](
ts
,
file
,
c
.
Expr
[
Char
](
q
"','"
))
private
def
deriveBuilderApplyImpl
[
T:
WeakTypeTag
]
:
Expr
[
CsvableBuilder
[
T
]]
=
{
private
def
deriveBuilderApplyImpl
[
T:
WeakTypeTag
]
:
Expr
[
CsvableBuilder
[
T
]]
=
{
val
className
=
TypeName
(
annoBuilderPrefix
+
MacroCache
.
getBuilderId
)
val
className
=
TypeName
(
annoBuilderPrefix
+
MacroCache
.
getBuilderId
)
val
caseClazzName
=
TypeName
(
weakTypeOf
[
T
].
typeSymbol
.
name
.
decodedName
.
toString
)
val
caseClazzName
=
TypeName
(
weakTypeOf
[
T
].
typeSymbol
.
name
.
decodedName
.
toString
)
...
@@ -93,17 +95,43 @@ class DeriveCsvableBuilder(override val c: whitebox.Context) extends AbstractMac
...
@@ -93,17 +95,43 @@ class DeriveCsvableBuilder(override val c: whitebox.Context) extends AbstractMac
customTrees
->
preTrees
customTrees
->
preTrees
}
}
private
def
deriveFullCsvableImpl
[
T:
WeakTypeTag
](
// scalafmt: { maxColumn = 400 }
ts
:
Expr
[
List
[
T
]],
private
def
deriveFullIntoFileCsvableImpl
[
T:
WeakTypeTag
](
ts
:
Expr
[
List
[
T
]],
file
:
Expr
[
File
],
columnSeparator
:
Expr
[
Char
])
:
Expr
[
Boolean
]
=
{
columnSeparator
:
Expr
[
Char
]
val
clazzName
=
resolveClazzTypeName
[
T
]
)
:
Expr
[
String
]
=
{
val
(
customTrees
,
preTrees
)
=
getCustomPreTress
val
tree
=
q
"""
..$preTrees
..${getAnnoClassObject[T](customTrees, columnSeparator)}
$packageName.FileUtils.writer($file, $ts.map { ($innerTName: $clazzName) =>
$csvableInstanceTermName.$innerTmpTermName = $innerTName
$csvableInstanceTermName.toCsvString
}
)
"""
exprPrintTree
[
Boolean
](
force
=
false
,
tree
)
}
// scalafmt: { maxColumn = 400 }
private
def
deriveFullCsvableImpl
[
T:
WeakTypeTag
](
ts
:
Expr
[
List
[
T
]],
columnSeparator
:
Expr
[
Char
])
:
Expr
[
String
]
=
{
val
clazzName
=
resolveClazzTypeName
[
T
]
val
clazzName
=
resolveClazzTypeName
[
T
]
val
(
customTrees
,
preTrees
)
=
getCustomPreTress
val
(
customTrees
,
preTrees
)
=
getCustomPreTress
val
annoClassName
=
TermName
(
csvableImplClassNamePrefix
+
MacroCache
.
getIdentityId
)
val
separator
=
q
"$columnSeparator"
val
tree
=
val
tree
=
q
"""
q
"""
..$preTrees
..$preTrees
..${getAnnoClassObject[T](customTrees, columnSeparator)}
$ts.map { ($innerTName: $clazzName) =>
$csvableInstanceTermName.$innerTmpTermName = $innerTName
$csvableInstanceTermName.toCsvString
}.mkString("\n")
"""
exprPrintTree
[
String
](
force
=
false
,
tree
)
}
private
def
getAnnoClassObject
[
T:
WeakTypeTag
](
customTrees
:
mutable.Map
[
String
,
Any
],
columnSeparator
:
Expr
[
Char
])
:
Tree
=
{
val
clazzName
=
resolveClazzTypeName
[
T
]
val
annoClassName
=
TermName
(
csvableImplClassNamePrefix
+
MacroCache
.
getIdentityId
)
val
separator
=
q
"$columnSeparator"
q
"""
object $annoClassName extends $packageName.Csvable[$clazzName] {
object $annoClassName extends $packageName.Csvable[$clazzName] {
var $innerTmpTermName: $clazzName = _
var $innerTmpTermName: $clazzName = _
...
@@ -115,13 +143,7 @@ class DeriveCsvableBuilder(override val c: whitebox.Context) extends AbstractMac
...
@@ -115,13 +143,7 @@ class DeriveCsvableBuilder(override val c: whitebox.Context) extends AbstractMac
}
}
final lazy private val $csvableInstanceTermName = $annoClassName
final lazy private val $csvableInstanceTermName = $annoClassName
$ts.map { ($innerTName: $clazzName) =>
$csvableInstanceTermName.$innerTmpTermName = $innerTName
$csvableInstanceTermName.toCsvString
}.mkString("\n")
"""
"""
exprPrintTree
[
String
](
force
=
false
,
tree
)
}
}
private
def
deriveCsvableImpl
[
T:
WeakTypeTag
](
t
:
Expr
[
T
],
columnSeparator
:
Expr
[
Char
])
:
Expr
[
Csvable
[
T
]]
=
{
private
def
deriveCsvableImpl
[
T:
WeakTypeTag
](
t
:
Expr
[
T
],
columnSeparator
:
Expr
[
Char
])
:
Expr
[
Csvable
[
T
]]
=
{
...
@@ -146,16 +168,13 @@ class DeriveCsvableBuilder(override val c: whitebox.Context) extends AbstractMac
...
@@ -146,16 +168,13 @@ class DeriveCsvableBuilder(override val c: whitebox.Context) extends AbstractMac
exprPrintTree
[
Csvable
[
T
]](
force
=
false
,
tree
)
exprPrintTree
[
Csvable
[
T
]](
force
=
false
,
tree
)
}
}
private
def
fieldsToString
[
T:
WeakTypeTag
](
// scalafmt: { maxColumn = 400 }
innerVarTermName
:
TermName
,
private
def
fieldsToString
[
T:
WeakTypeTag
](
innerVarTermName
:
TermName
,
customTrees
:
mutable.Map
[
String
,
Any
])
:
List
[
Tree
]
=
{
customTrees
:
mutable.Map
[
String
,
Any
]
)
:
List
[
Tree
]
=
{
val
clazzName
=
resolveClazzTypeName
[
T
]
val
clazzName
=
resolveClazzTypeName
[
T
]
val
(
fieldNames
,
indexTypes
)
=
checkCaseClassZip
val
(
fieldNames
,
indexTypes
)
=
checkCaseClassZip
val
indexByName
=
(
i
:
Int
)
=>
TermName
(
fieldNames
(
i
))
val
indexByName
=
(
i
:
Int
)
=>
TermName
(
fieldNames
(
i
))
indexTypes
.
map
{
idxType
=>
indexTypes
.
map
{
idxType
=>
val
customFunction
=
()
=>
val
customFunction
=
()
=>
q
"${TermName(builderFunctionPrefix + fieldNames(idxType._1))}.apply($innerVarTermName.${indexByName(idxType._1)})"
q
"${TermName(builderFunctionPrefix + fieldNames(idxType._1))}.apply($innerVarTermName.${indexByName(idxType._1)})"
idxType
.
_2
match
{
idxType
.
_2
match
{
case
t
if
t
<:<
typeOf
[
List
[
_
]]
=>
case
t
if
t
<:<
typeOf
[
List
[
_
]]
=>
if
(
customTrees
.
contains
(
fieldNames
(
idxType
.
_1
)))
{
if
(
customTrees
.
contains
(
fieldNames
(
idxType
.
_1
)))
{
...
@@ -180,11 +199,10 @@ class DeriveCsvableBuilder(override val c: whitebox.Context) extends AbstractMac
...
@@ -180,11 +199,10 @@ class DeriveCsvableBuilder(override val c: whitebox.Context) extends AbstractMac
if
(
customTrees
.
contains
(
fieldNames
(
idxType
.
_1
)))
{
if
(
customTrees
.
contains
(
fieldNames
(
idxType
.
_1
)))
{
customFunction
()
customFunction
()
}
else
{
}
else
{
// scalafmt: { maxColumn = 400 }
q
"""
q
"""
$packageName.Csvable[${genericType.typeSymbol.name.toTypeName}]._toCsvString {
$packageName.Csvable[${genericType.typeSymbol.name.toTypeName}]._toCsvString {
if ($innerVarTermName.${indexByName(idxType._1)}.isEmpty) "" else $innerVarTermName.${indexByName(
if ($innerVarTermName.${indexByName(idxType._1)}.isEmpty) "" else $innerVarTermName.${indexByName(idxType._1)}.get
idxType._1
)}.get
}
}
"""
"""
}
}
...
...
smt-csv-core/src/main/scala/org/bitlap/csv/core/macros/DeriveScalableBuilder.scala
浏览文件 @
dc6bcee1
...
@@ -23,6 +23,7 @@ package org.bitlap.csv.core.macros
...
@@ -23,6 +23,7 @@ package org.bitlap.csv.core.macros
import
org.bitlap.csv.core.
{
Scalable
,
ScalableBuilder
}
import
org.bitlap.csv.core.
{
Scalable
,
ScalableBuilder
}
import
java.io.InputStream
import
scala.collection.mutable
import
scala.collection.mutable
import
scala.reflect.macros.whitebox
import
scala.reflect.macros.whitebox
...
@@ -39,16 +40,13 @@ class DeriveScalableBuilder(override val c: whitebox.Context) extends AbstractMa
...
@@ -39,16 +40,13 @@ class DeriveScalableBuilder(override val c: whitebox.Context) extends AbstractMa
private
val
builderFunctionPrefix
=
"_ScalableBuilderFunction$"
private
val
builderFunctionPrefix
=
"_ScalableBuilderFunction$"
private
val
innerColumnFuncTermName
=
TermName
(
"_columns"
)
private
val
innerColumnFuncTermName
=
TermName
(
"_columns"
)
private
val
innerLName
=
q
"_l"
private
val
innerLName
=
q
"_l"
private
val
innerTempTermName
=
TermName
(
"_line"
)
private
val
innerTempTermName
=
TermName
(
"_line"
)
private
val
scalableInstanceTermName
=
TermName
(
"_scalableInstance"
)
private
val
scalableInstanceTermName
=
TermName
(
"_scalableInstance"
)
private
val
scalableImplClassNamePrefix
=
"_ScalaAnno$"
private
val
scalableImplClassNamePrefix
=
"_ScalaAnno$"
def
setFieldImpl
[
T:
WeakTypeTag
,
SF:
WeakTypeTag
](
// scalafmt: { maxColumn = 400 }
scalaField
:
Expr
[
T
=>
SF
],
def
setFieldImpl
[
T:
WeakTypeTag
,
SF:
WeakTypeTag
](
scalaField
:
Expr
[
T
=>
SF
],
value
:
Expr
[
String
=>
SF
])
:
Expr
[
ScalableBuilder
[
T
]]
=
{
value
:
Expr
[
String
=>
SF
]
)
:
Expr
[
ScalableBuilder
[
T
]]
=
{
val
Function
(
_
,
Select
(
_
,
termName
))
=
scalaField
.
tree
val
Function
(
_
,
Select
(
_
,
termName
))
=
scalaField
.
tree
val
builderId
=
getBuilderId
(
annoBuilderPrefix
)
val
builderId
=
getBuilderId
(
annoBuilderPrefix
)
MacroCache
.
builderFunctionTrees
.
getOrElseUpdate
(
builderId
,
mutable
.
Map
.
empty
).
update
(
termName
.
toString
,
value
)
MacroCache
.
builderFunctionTrees
.
getOrElseUpdate
(
builderId
,
mutable
.
Map
.
empty
).
update
(
termName
.
toString
,
value
)
...
@@ -79,6 +77,11 @@ class DeriveScalableBuilder(override val c: whitebox.Context) extends AbstractMa
...
@@ -79,6 +77,11 @@ class DeriveScalableBuilder(override val c: whitebox.Context) extends AbstractMa
deriveScalableImpl
[
T
](
clazzName
,
line
,
c
.
Expr
[
Char
](
q
"','"
))
deriveScalableImpl
[
T
](
clazzName
,
line
,
c
.
Expr
[
Char
](
q
"','"
))
}
}
def
readFromFileImpl
[
T:
WeakTypeTag
](
file
:
Expr
[
InputStream
],
charset
:
Expr
[
String
])
:
Expr
[
List
[
Option
[
T
]]]
=
{
val
clazzName
=
resolveClazzTypeName
[
T
]
deriveFullFromFileScalableImpl
[
T
](
clazzName
,
file
,
charset
,
c
.
Expr
[
Char
](
q
"','"
))
}
private
def
deriveBuilderApplyImpl
[
T:
WeakTypeTag
]
:
Expr
[
ScalableBuilder
[
T
]]
=
{
private
def
deriveBuilderApplyImpl
[
T:
WeakTypeTag
]
:
Expr
[
ScalableBuilder
[
T
]]
=
{
val
className
=
TypeName
(
annoBuilderPrefix
+
MacroCache
.
getBuilderId
)
val
className
=
TypeName
(
annoBuilderPrefix
+
MacroCache
.
getBuilderId
)
val
caseClazzName
=
TypeName
(
weakTypeOf
[
T
].
typeSymbol
.
name
.
decodedName
.
toString
)
val
caseClazzName
=
TypeName
(
weakTypeOf
[
T
].
typeSymbol
.
name
.
decodedName
.
toString
)
...
@@ -102,24 +105,28 @@ class DeriveScalableBuilder(override val c: whitebox.Context) extends AbstractMa
...
@@ -102,24 +105,28 @@ class DeriveScalableBuilder(override val c: whitebox.Context) extends AbstractMa
preTrees
preTrees
}
}
private
def
deriveFullScalableImpl
[
T:
WeakTypeTag
](
// scalafmt: { maxColumn = 400 }
clazzName
:
TypeName
,
private
def
deriveFullFromFileScalableImpl
[
T:
WeakTypeTag
](
clazzName
:
TypeName
,
file
:
Expr
[
InputStream
],
charset
:
Expr
[
String
],
columnSeparator
:
Expr
[
Char
])
:
Expr
[
List
[
Option
[
T
]]]
=
{
lines
:
Expr
[
List
[
String
]],
columnSeparator
:
Expr
[
Char
]
)
:
Expr
[
List
[
Option
[
T
]]]
=
{
val
annoClassName
=
TermName
(
scalableImplClassNamePrefix
+
MacroCache
.
getIdentityId
)
// NOTE: preTrees must be at the same level as Scalable
// NOTE: preTrees must be at the same level as Scalable
val
tree
=
val
tree
=
q
"""
q
"""
..$getPreTree
..$getPreTree
..${getAnnoClassObject[T](clazzName, columnSeparator)}
object $annoClassName extends $packageName.Scalable[$clazzName] {
$packageName.FileUtils.reader($file, $charset).map { ($innerLName: String) =>
var $innerTempTermName: String = _
$scalableInstanceTermName.$innerTempTermName = ${TermName(innerLName.toString())}
private val $innerColumnFuncTermName = () => _root_.org.bitlap.csv.core.StringUtils.splitColumns(${annoClassName.toTermName}.$innerTempTermName, $columnSeparator)
$scalableInstanceTermName.toScala
..${scalableBody[T](clazzName, innerColumnFuncTermName)}
}
"""
exprPrintTree
[
List
[
Option
[
T
]]](
force
=
false
,
tree
)
}
}
private final lazy val $scalableInstanceTermName = $annoClassName
// scalafmt: { maxColumn = 400 }
private
def
deriveFullScalableImpl
[
T:
WeakTypeTag
](
clazzName
:
TypeName
,
lines
:
Expr
[
List
[
String
]],
columnSeparator
:
Expr
[
Char
])
:
Expr
[
List
[
Option
[
T
]]]
=
{
// NOTE: preTrees must be at the same level as Scalable
val
tree
=
q
"""
..$getPreTree
..${getAnnoClassObject[T](clazzName, columnSeparator)}
$lines.map { ($innerLName: String) =>
$lines.map { ($innerLName: String) =>
$scalableInstanceTermName.$innerTempTermName = ${TermName(innerLName.toString())}
$scalableInstanceTermName.$innerTempTermName = ${TermName(innerLName.toString())}
$scalableInstanceTermName.toScala
$scalableInstanceTermName.toScala
...
@@ -128,18 +135,27 @@ class DeriveScalableBuilder(override val c: whitebox.Context) extends AbstractMa
...
@@ -128,18 +135,27 @@ class DeriveScalableBuilder(override val c: whitebox.Context) extends AbstractMa
exprPrintTree
[
List
[
Option
[
T
]]](
force
=
false
,
tree
)
exprPrintTree
[
List
[
Option
[
T
]]](
force
=
false
,
tree
)
}
}
private
def
deriveScalableImpl
[
T:
WeakTypeTag
](
private
def
getAnnoClassObject
[
T:
WeakTypeTag
](
clazzName
:
TypeName
,
columnSeparator
:
Expr
[
Char
])
:
Tree
=
{
clazzName
:
TypeName
,
val
annoClassName
=
TermName
(
scalableImplClassNamePrefix
+
MacroCache
.
getIdentityId
)
line
:
Expr
[
String
],
q
"""
columnSeparator
:
Expr
[
Char
]
object $annoClassName extends $packageName.Scalable[$clazzName] {
)
:
Expr
[
Scalable
[
T
]]
=
{
var $innerTempTermName: String = _
private val $innerColumnFuncTermName = () => $packageName.StringUtils.splitColumns(${annoClassName.toTermName}.$innerTempTermName, $columnSeparator)
..${scalableBody[T](clazzName, innerColumnFuncTermName)}
}
private final lazy val $scalableInstanceTermName = $annoClassName
"""
}
// scalafmt: { maxColumn = 400 }
private
def
deriveScalableImpl
[
T:
WeakTypeTag
](
clazzName
:
TypeName
,
line
:
Expr
[
String
],
columnSeparator
:
Expr
[
Char
])
:
Expr
[
Scalable
[
T
]]
=
{
val
annoClassName
=
TermName
(
scalableImplClassNamePrefix
+
MacroCache
.
getIdentityId
)
val
annoClassName
=
TermName
(
scalableImplClassNamePrefix
+
MacroCache
.
getIdentityId
)
// NOTE: preTrees must be at the same level as Scalable
// NOTE: preTrees must be at the same level as Scalable
val
tree
=
val
tree
=
q
"""
q
"""
..$getPreTree
..$getPreTree
object $annoClassName extends $packageName.Scalable[$clazzName] {
object $annoClassName extends $packageName.Scalable[$clazzName] {
final lazy private val $innerColumnFuncTermName = () =>
_root_.org.bitlap.csv.cor
e.StringUtils.splitColumns($line, $columnSeparator)
final lazy private val $innerColumnFuncTermName = () =>
$packageNam
e.StringUtils.splitColumns($line, $columnSeparator)
..${scalableBody[T](clazzName, innerColumnFuncTermName)}
..${scalableBody[T](clazzName, innerColumnFuncTermName)}
}
}
$annoClassName
$annoClassName
...
@@ -147,10 +163,8 @@ class DeriveScalableBuilder(override val c: whitebox.Context) extends AbstractMa
...
@@ -147,10 +163,8 @@ class DeriveScalableBuilder(override val c: whitebox.Context) extends AbstractMa
exprPrintTree
[
Scalable
[
T
]](
force
=
false
,
tree
)
exprPrintTree
[
Scalable
[
T
]](
force
=
false
,
tree
)
}
}
private
def
scalableBody
[
T:
WeakTypeTag
](
// scalafmt: { maxColumn = 400 }
clazzName
:
TypeName
,
private
def
scalableBody
[
T:
WeakTypeTag
](
clazzName
:
TypeName
,
innerFuncTermName
:
TermName
)
:
Tree
=
{
innerFuncTermName
:
TermName
)
:
Tree
=
{
val
customTrees
=
MacroCache
.
builderFunctionTrees
.
getOrElse
(
getBuilderId
(
annoBuilderPrefix
),
mutable
.
Map
.
empty
)
val
customTrees
=
MacroCache
.
builderFunctionTrees
.
getOrElse
(
getBuilderId
(
annoBuilderPrefix
),
mutable
.
Map
.
empty
)
val
params
=
getCaseClassParams
[
T
]()
val
params
=
getCaseClassParams
[
T
]()
val
fieldNames
=
params
.
map
(
_
.
name
.
decodedName
.
toString
)
val
fieldNames
=
params
.
map
(
_
.
name
.
decodedName
.
toString
)
...
...
smt-csv-core/src/main/scala/org/bitlap/csv/core/macros/DeriveToCaseClass.scala
浏览文件 @
dc6bcee1
...
@@ -34,10 +34,8 @@ object DeriveToCaseClass {
...
@@ -34,10 +34,8 @@ object DeriveToCaseClass {
class
Macro
(
override
val
c
:
blackbox.Context
)
extends
AbstractMacroProcessor
(
c
)
{
class
Macro
(
override
val
c
:
blackbox.Context
)
extends
AbstractMacroProcessor
(
c
)
{
import
c.universe._
import
c.universe._
def
macroImpl
[
T
<:
Product:
c.WeakTypeTag
](
// scalafmt: { maxColumn = 400 }
line
:
c.Expr
[
String
],
def
macroImpl
[
T
<:
Product:
c.WeakTypeTag
](
line
:
c.Expr
[
String
],
columnSeparator
:
c.Expr
[
Char
])
:
c.Expr
[
Option
[
T
]]
=
{
columnSeparator
:
c.Expr
[
Char
]
)
:
c.Expr
[
Option
[
T
]]
=
{
val
clazzName
=
c
.
weakTypeOf
[
T
].
typeSymbol
.
name
val
clazzName
=
c
.
weakTypeOf
[
T
].
typeSymbol
.
name
val
innerFuncTermName
=
TermName
(
"_columns"
)
val
innerFuncTermName
=
TermName
(
"_columns"
)
val
fields
=
(
columnsFunc
:
TermName
)
=>
val
fields
=
(
columnsFunc
:
TermName
)
=>
...
@@ -72,7 +70,7 @@ object DeriveToCaseClass {
...
@@ -72,7 +70,7 @@ object DeriveToCaseClass {
}
}
val
tree
=
val
tree
=
q
"""
q
"""
lazy val $innerFuncTermName = () =>
_root_.org.bitlap.csv.cor
e.StringUtils.splitColumns($line, $columnSeparator)
lazy val $innerFuncTermName = () =>
$packageNam
e.StringUtils.splitColumns($line, $columnSeparator)
Option(${TermName(clazzName.decodedName.toString)}(..${fields(innerFuncTermName)}))
Option(${TermName(clazzName.decodedName.toString)}(..${fields(innerFuncTermName)}))
"""
"""
exprPrintTree
[
T
](
force
=
false
,
tree
)
exprPrintTree
[
T
](
force
=
false
,
tree
)
...
...
smt-csv-core/src/main/scala/org/bitlap/csv/core/macros/DeriveToString.scala
浏览文件 @
dc6bcee1
...
@@ -43,10 +43,9 @@ object DeriveToString {
...
@@ -43,10 +43,9 @@ object DeriveToString {
val
fieldsToString
=
indexTypes
.
map
{
idxType
=>
val
fieldsToString
=
indexTypes
.
map
{
idxType
=>
if
(
idxType
.
_2
<:<
typeOf
[
Option
[
_
]])
{
if
(
idxType
.
_2
<:<
typeOf
[
Option
[
_
]])
{
val
genericType
=
c
.
typecheck
(
q
"${idxType._2}"
,
c
.
TYPEmode
).
tpe
.
typeArgs
.
head
val
genericType
=
c
.
typecheck
(
q
"${idxType._2}"
,
c
.
TYPEmode
).
tpe
.
typeArgs
.
head
// scalafmt: { maxColumn = 400 }
q
"""$packageName.Converter[${genericType.typeSymbol.name.toTypeName}].toCsvString {
q
"""$packageName.Converter[${genericType.typeSymbol.name.toTypeName}].toCsvString {
if ($innerVarTermName.${indexByName(idxType._1)}.isEmpty) "" else $innerVarTermName.${indexByName(
if ($innerVarTermName.${indexByName(idxType._1)}.isEmpty) "" else $innerVarTermName.${indexByName(idxType._1)}.get
idxType._1
)}.get
}
}
"""
"""
}
else
{
}
else
{
...
...
smt-csv-core/src/test/scala/org/bitlap/csv/core/test/CsvableAndScalableTest.scala
浏览文件 @
dc6bcee1
...
@@ -28,6 +28,7 @@ import org.scalatest.matchers.should.Matchers
...
@@ -28,6 +28,7 @@ import org.scalatest.matchers.should.Matchers
import
org.bitlap.csv.core.ScalableBuilder
import
org.bitlap.csv.core.ScalableBuilder
import
org.bitlap.csv.core.CsvableBuilder
import
org.bitlap.csv.core.CsvableBuilder
import
org.bitlap.csv.core.ScalableHelper
import
org.bitlap.csv.core.ScalableHelper
import
java.io.File
/**
/**
* Complex use of common tests
* Complex use of common tests
...
@@ -212,6 +213,7 @@ class CsvableAndScalableTest extends AnyFlatSpec with Matchers {
...
@@ -212,6 +213,7 @@ class CsvableAndScalableTest extends AnyFlatSpec with Matchers {
object _ScalaAnno$1 extends _root_.org.bitlap.csv.core.Scalable[Metric2] {
object _ScalaAnno$1 extends _root_.org.bitlap.csv.core.Scalable[Metric2] {
var _line: String = _;
var _line: String = _;
private val _columns = (() => _root_.org.bitlap.csv.core.StringUtils.splitColumns(_ScalaAnno$1._line, ','));
private val _columns = (() => _root_.org.bitlap.csv.core.StringUtils.splitColumns(_ScalaAnno$1._line, ','));
override def toScala: Option[Metric2] = Option(
override def toScala: Option[Metric2] = Option(
Metric2(
Metric2(
_root_.org.bitlap.csv.core.Scalable[Long]._toScala(_columns()(0)).getOrElse(0L),
_root_.org.bitlap.csv.core.Scalable[Long]._toScala(_columns()(0)).getOrElse(0L),
...
@@ -266,6 +268,7 @@ class CsvableAndScalableTest extends AnyFlatSpec with Matchers {
...
@@ -266,6 +268,7 @@ class CsvableAndScalableTest extends AnyFlatSpec with Matchers {
)
)
.mkString(','.toString)
.mkString(','.toString)
});
});
override def toCsvString: String = toCsv(_CsvAnno$2._tt)
override def toCsvString: String = toCsv(_CsvAnno$2._tt)
};
};
lazy val _csvableInstance = _CsvAnno$2;
lazy val _csvableInstance = _CsvAnno$2;
...
@@ -280,4 +283,28 @@ class CsvableAndScalableTest extends AnyFlatSpec with Matchers {
...
@@ -280,4 +283,28 @@ class CsvableAndScalableTest extends AnyFlatSpec with Matchers {
println(csv)
println(csv)
}
}
"CsvableAndScalable8" should "ok when reading from file" in {
val metrics =
ScalableBuilder[Metric2]
.setField[Seq[Dimension3]](
_.dimensions,
dims => StringUtils.extractJsonValues[Dimension3](dims)((k, v) => Dimension3(k, v))
)
.readFrom(ClassLoader.getSystemResourceAsStream("simple_data.csv"), "utf-8")
println(metrics)
assert(metrics.nonEmpty)
val file = new File("./simple_data.csv")
CsvableBuilder[Metric2]
.setField[Seq[Dimension3]](
_.dimensions,
ds => s"""
\
"{${ds.map(kv => s"""
\
"\"${kv.key}\"\":\"\"${kv.value}\"\""""
).
mkString
(
","
)}}\
""""
)
.
writeTo
(
metrics
.
filter
(
_
.
isDefined
).
map
(
_
.
get
),
file
)
file
.
delete
()
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录