Skip to content

Instantly share code, notes, and snippets.

@hikaMaeng
Created June 19, 2024 05:45
Show Gist options
  • Save hikaMaeng/4a58151f256d9af7480f4bcff54d15bb to your computer and use it in GitHub Desktop.
Save hikaMaeng/4a58151f256d9af7480f4bcff54d15bb to your computer and use it in GitHub Desktop.
@file:Suppress("NOTHING_TO_INLINE")
package kore.rule
import kore.rule.Rule.Item
import kore.vo.task.Task
import kore.wrap.W
import kore.wrap.Wrap
class Rule @PublishedApi internal constructor(){
companion object {
inline operator fun invoke(block:Group.()->Unit): Rule = Rule().also{it.group.block()}
}
sealed interface R{
operator fun DSL.invoke(value:Any, param:Array<out Any>):Any
}
object DSL{
fun fail(value:Any, msg:String):Throwable = Throwable("$msg : value:$value")
fun any(value:Any, param:Array<out Any>, vararg items:Item):Any{
var result:Any = value
items.any{
result = it.run{invoke(value, param)}
result !is Throwable
}
return result
}
fun all(value:Any, param:Array<out Any>, vararg items:Item):Any{
var result:Any = value
items.all{
result = it.run{invoke(value, param)}
result !is Throwable
}
return result
}
}
fun interface Item:R
data object Or:R{override fun DSL.invoke(value:Any, param:Array<out Any>):Any = value}
class Group:R{
@PublishedApi internal val rules:ArrayList<R> = arrayListOf()
override fun DSL.invoke(value:Any, param:Array<out Any>):Any{
return DSL.run{
var result:Any = value
var i = 0
while(i < rules.size){
val it:R = rules[i]
if(it == Or) break
val prev:Any = result
result = it.run{invoke(result, param)}
if(result is Throwable){
if(i < rules.size - 2 && rules[i + 1] == Or){
result = prev
i++
} else break
}
i++
}
result
}
}
inline val or:Boolean get() = rules.add(Or)
inline fun rule(noinline block:DSL.(Any, Array<out Any>)->Any){rules.add(Item(block))}
inline fun rule(item:Item){rules.add(item)}
inline fun group(block:Group.()->Unit){rules.add(Group().also{it.block()})}
inline fun add(item:R){rules.add(item)}
}
@PublishedApi internal val group:Group = Group()
operator fun invoke(value:Any, vararg param:Any):Wrap<Any>{
val result:Any = DSL.run{
group.run{DSL.invoke(value, param)}
}
return if(result is Throwable) W(result) else W(result)
}
}
inline fun Task.ruleItem(rule:Rule.R){
rule(Rule{
rules.add(rule)
})
}
inline fun Task.anyRuleItem(vararg rules:Rule.R){
rule(Rule{
rules.forEach{
add(it)
add(Rule.Or)
}
})
}
inline fun Task.allRuleItem(vararg rules:Rule.R){
rule(Rule{
rules.forEach{add(it)}
})
}
inline fun Task.rule(rule:Rule){
addSetTask { vo, _, v ->
rule(v,vo).getOrFailEffect { err -> throw err }
}
}
inline fun Task.anyRule(vararg rules: Rule) {
addSetTask { vo, _, v ->
var value: Any? = v
val result = rules.any { rule ->
value = rule(v)()
value != null
}
/**or이기 때문에 만약 실패한다면 rules의 마지막 요소의 error를 표시해준다.*/
if (!result) rules.last()(v,vo).getOrFailEffect { throw it }
else result
}
}
inline fun Task.allRule(vararg rules: Rule) {
addSetTask{_, _, v ->
rules.fold(v){acc, it->
it(acc).getOrFailEffect { throw it } //실패 시 바로 종료
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment