Created
September 8, 2018 14:04
-
-
Save Nicofisi/74fe58bbab4d7770393fb3b619862bd8 to your computer and use it in GitHub Desktop.
Kotlin vs Scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package me.nicofisi.spigot.common.commands | |
import arrow.core.Either | |
import arrow.core.Left | |
import arrow.core.None | |
import arrow.core.Option | |
import arrow.core.Right | |
import arrow.core.Some | |
import arrow.core.Try | |
import arrow.core.getOrElse | |
import arrow.core.orElse | |
import arrow.core.toOption | |
import me.nicofisi.spigot.common.colored | |
import org.bukkit.Bukkit | |
import org.bukkit.GameMode | |
import org.bukkit.OfflinePlayer | |
import org.bukkit.World | |
import org.bukkit.entity.Player | |
import java.math.BigInteger | |
import java.util.UUID | |
typealias ParseFailReason = String | |
typealias ParseResult<A> = Either<A, ParseFailReason> | |
interface CType<A> { | |
fun parse(string: String): ParseResult<A> | |
/** | |
* Returns a list of suggestions to send to the player when they press the tab key with the given | |
* string typed, in a place where an object of this type is expected | |
* | |
* @param mustStartWith the string; implementations are allowed to return an empty list when | |
* the length of this string is lower than some given small number | |
*/ | |
fun tabSuggestions(mustStartWith: String): List<String> = emptyList() | |
} | |
object TypeBoolean : CType<Boolean> { | |
override fun parse(string: String): ParseResult<Boolean> = when (string) { | |
"yes", "true", "y", "t" -> Left(true) | |
"no", "false", "n", "f" -> Left(false) | |
else -> Right("&sYou typed &p$string in a place where only &pyes &sor &pno &sshould be used".colored) | |
} | |
} | |
object TypeGameMode : CType<GameMode> { | |
override fun parse(string: String): ParseResult<GameMode> = when (string) { | |
"0", "survival", "s" -> Left(GameMode.SURVIVAL) | |
"1", "creative", "c" -> Left(GameMode.CREATIVE) | |
"2", "adventure", "a" -> Left(GameMode.ADVENTURE) | |
"3", "spectator", "sp" -> Left(GameMode.SPECTATOR) | |
else -> Right("&sGame mode called &p$string &sdoesn't exist".colored) | |
} | |
override fun tabSuggestions(mustStartWith: String) = | |
listOf("survival", "creative", "adventure", "spectator") | |
.filter { it.startsWith(mustStartWith.toLowerCase()) } | |
} | |
object TypeInt : CType<Int> { | |
override fun parse(string: String): ParseResult<Int> { | |
return Try { Left(string.toInt()) }.getOrElse { | |
if (Try { BigInteger(string) }.isSuccess()) { | |
Right("&sThe number &p$string &sis too big, it should be at most ${Int.MAX_VALUE}") | |
} else { | |
Right("&p$string &sis not an integer") | |
} | |
} | |
} | |
} | |
object TypeLong : CType<Long> { | |
override fun parse(string: String): ParseResult<Long> { | |
return Try { Left(string.toLong()) }.getOrElse { | |
if (Try { BigInteger(string) }.isSuccess()) { | |
Right("&sThe number &p$string &sis too big, it should be at most ${Long.MAX_VALUE}") | |
} else { | |
Right("&p$string &sis not an integer".colored) | |
} | |
} | |
} | |
} | |
object TypeDouble : CType<Double> { | |
override fun parse(string: String): ParseResult<Double> { | |
return Try { Left(string.toDouble()) }.getOrElse { | |
Right("&p$string is not a floating-point number".colored) | |
} | |
} | |
} | |
object TypeOfflinePlayer : CType<OfflinePlayer> { | |
override fun parse(string: String): ParseResult<OfflinePlayer> { | |
@Suppress("DEPRECATION") // needed here | |
return Option(Bukkit.getOfflinePlayer(string)) | |
.orElse { Try { UUID.fromString(string) }.toOption().flatMap { Option(Bukkit.getOfflinePlayer(it)) } } | |
.map { Left(it) }.getOrElse { Right("&sNo player named &p$string &scould be found".colored) } | |
} | |
// TODO find a way faster way | |
// than Bukkit.getOfflinePlayers.asScala.map(_.getName).filter(_.startsWith(mustStartWith)) | |
} | |
object TypePlayer : CType<Player> { | |
override fun parse(string: String): ParseResult<Player> { | |
return Option(Bukkit.getPlayerExact(string)) | |
.orElse { Try { UUID.fromString(string) }.toOption().flatMap { Option(Bukkit.getPlayer(it)) } } | |
.map { Left(it) }.getOrElse { | |
val players = Bukkit.getOnlinePlayers().filter { it.name.startsWith(string, ignoreCase = true) } | |
when { | |
players.isEmpty() -> | |
Right("&sNo online player could be found whose name starts with &p$string") | |
players.size > 1 -> | |
Right("&sThere are currently a few players online whose names start with &p$string") | |
else -> | |
Left(players.first()) | |
} | |
} | |
} | |
} | |
object TypeString : CType<String> { | |
override fun parse(string: String) = Left(string) | |
} | |
object TypeWorld : CType<World> { | |
override fun parse(string: String): ParseResult<World> { | |
return Option(Bukkit.getWorld(string)).map { Left(it) }.getOrElse { | |
val worlds = Bukkit.getWorlds().filter { it.name.startsWith(string, ignoreCase = true) } | |
when { | |
worlds.isEmpty() -> | |
Right("&sThere aren't any loaded worlds whose names start with &p$string") | |
worlds.size > 1 -> | |
Right("&sThere are currently a few loaded worlds whose names start with &p$string") | |
else -> | |
Left(worlds.first()) | |
} | |
} | |
} | |
override fun tabSuggestions(mustStartWith: String) = | |
Bukkit.getWorlds().map { it.name }.filter { it.startsWith(mustStartWith, ignoreCase = true) } | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package me.nicofisi.commonspigotstuff | |
import java.util.UUID | |
import org.bukkit.{Bukkit, GameMode, OfflinePlayer, World} | |
import org.bukkit.entity.Player | |
import scala.collection.JavaConverters._ | |
import scala.util.Try | |
trait CType[A] { | |
type ParseFailReason = String | |
type ParseResult = Either[A, ParseFailReason] | |
def parse(string: String)(implicit info: PluginInfo): ParseResult | |
/** Returns a list of suggestions to send to the player when they press the tab key with the given | |
* string typed, in a place where an object of this type is expected | |
* | |
* @param mustStartWith the string; implementations are allowed to return an empty list when | |
* the length of this string is lower than some given small number | |
*/ | |
def tabSuggestions(mustStartWith: String): List[String] = Nil | |
} | |
object TypeBoolean extends CType[Boolean] { | |
override def parse(string: String)(implicit info: PluginInfo): ParseResult = string match { | |
case "yes" | "true" | "y" | "t" => Left(true) | |
case "no" | "false" | "n" | "f" => Left(false) | |
case _ => Right(s"&sYou typed &p$string in a place where only &pyes &sor &pno &sshould be used".colored) | |
} | |
} | |
object TypeGameMode extends CType[GameMode] { | |
override def parse(string: String)(implicit info: PluginInfo): ParseResult = string match { | |
case "0" | "survival" | "s" => Left(GameMode.SURVIVAL) | |
case "1" | "creative" | "c" => Left(GameMode.CREATIVE) | |
case "2" | "adventure" | "a" => Left(GameMode.ADVENTURE) | |
case "3" | "spectator" | "sp" => Left(GameMode.SPECTATOR) | |
case _ => Right(s"&sGame mode called &p$string &sdoesn't exist") | |
} | |
override def tabSuggestions(mustStartWith: String): List[String] = | |
List("survival", "creative", "adventure", "spectator").filter(_.startsWith(mustStartWith.toLowerCase)) | |
} | |
object TypeInt extends CType[Int] { | |
override def parse(string: String)(implicit info: PluginInfo): ParseResult = | |
Try(Left(string.toInt)).getOrElse( | |
if (Try(BigInt(string)).isSuccess) | |
Right(s"&sThe number &p$string &sis too big, it should be at most ${Int.MaxValue}") | |
else | |
Right(s"&p$string &sis not an integer") | |
) | |
} | |
object TypeLong extends CType[Long] { | |
override def parse(string: String)(implicit info: PluginInfo): ParseResult = | |
Try(Left(string.toLong)).getOrElse( | |
if (Try(BigInt(string)).isSuccess) | |
Right(s"&sThe number &p$string &sis too big, it should be at most ${Long.MaxValue}") | |
else | |
Right(s"&p$string &sis not an integer") | |
) | |
} | |
object TypeDouble extends CType[Double] { | |
override def parse(string: String)(implicit info: PluginInfo): ParseResult = | |
Try(Left(string.toDouble)).getOrElse( | |
Right(s"&p$string &scouldn't be interpreted as a floating-point number") | |
) | |
} | |
object TypeOfflinePlayer extends CType[OfflinePlayer] { | |
override def parse(string: String)(implicit info: PluginInfo): ParseResult = { | |
// noinspection ScalaDeprecation | |
Option(Bukkit.getOfflinePlayer(string)) // deprecated but not going to be removed, and we do need it here | |
.orElse(Try(UUID.fromString(string)).toOption.flatMap(uuid => Some(Bukkit.getOfflinePlayer(uuid)))) | |
.map(Left(_)).getOrElse(Right(s"&sNo player named &p$string &scould be found")) | |
} | |
// TODO find a way faster way | |
// than Bukkit.getOfflinePlayers.asScala.map(_.getName).filter(_.startsWith(mustStartWith)) | |
override def tabSuggestions(mustStartWith: String): List[String] = Nil | |
} | |
object TypePlayer extends CType[Player] { | |
override def parse(string: String)(implicit info: PluginInfo): ParseResult = { | |
Option(Bukkit.getPlayerExact(string)) | |
.orElse(Try(UUID.fromString(string)).toOption.flatMap(uuid => Some(Bukkit.getPlayer(uuid)))) | |
.map(Left(_)).getOrElse { | |
val players = Bukkit.getOnlinePlayers.asScala.filter(_.getName.toLowerCase.startsWith(string)) | |
if (players.isEmpty) | |
Right(s"&sNo online player could be found whose name starts with &p$string") | |
else if (players.size > 1) | |
Right(s"&sThere are currently a few players online whose names start with &p$string") | |
else | |
Left(players.head) | |
} | |
} | |
override def tabSuggestions(mustStartWith: String): List[String] = | |
Bukkit.getOnlinePlayers.asScala.toList.map(_.getName).filter(_.toLowerCase.startsWith(mustStartWith.toLowerCase)) | |
} | |
object TypeString extends CType[String] { | |
override def parse(string: String)(implicit info: PluginInfo): ParseResult = Left(string) | |
} | |
object TypeWorld extends CType[World] { | |
override def parse(string: String)(implicit info: PluginInfo): ParseResult = { | |
Option(Bukkit.getWorld(string)).map(Left(_)).getOrElse { | |
val worlds = Bukkit.getWorlds.asScala.filter(_.getName.toLowerCase.startsWith(string)) | |
if (worlds.isEmpty) | |
Right(s"&sThere aren't any loaded worlds whose names start with &p$string") | |
else if (worlds.size > 1) | |
Right(s"&sThere are currently a few loaded worlds whose names start with &p$string") | |
else | |
Left(worlds.head) | |
} | |
} | |
override def tabSuggestions(mustStartWith: String): List[String] = | |
Bukkit.getWorlds.asScala.toList.map(_.getName).filter(_.toLowerCase.startsWith(mustStartWith.toLowerCase)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment