Skip to content

Commit

Permalink
Merge pull request #177 from som-snytt/topic/3
Browse files Browse the repository at this point in the history
Use dotty style
  • Loading branch information
SethTisue authored Jul 19, 2022
2 parents 2fac88a + 5e3ace9 commit 67a95d8
Show file tree
Hide file tree
Showing 14 changed files with 1,285 additions and 13 deletions.
1 change: 1 addition & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ maxColumn = 100
newlines.source = keep
rewrite.trailingCommas.style = keep
docstrings.style = Asterisk
project.layout = StandardConvention
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ scala> "yay".emoji
res1: com.lightbend.emoji.Emoji = 😃
```

## Scala 3

Imports for extension methods are slightly shorter in Scala 3.

The default `ShortCodes` is `given` in `ShortCodes`.
```
scala> import com.lightbend.emoji.Emoji.*
scala> import com.lightbend.emoji.ShortCodes.{given, *}
```

## Similar Works

These libraries have not been evaluated, and they may work or not:
Expand Down
10 changes: 1 addition & 9 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ scalaVersion := crossScalaVersions.value.head
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest-wordspec" % "3.2.12" % Test,
"org.scalatest" %% "scalatest-shouldmatchers" % "3.2.12" % Test,
"org.scalameta" %% "munit" % "1.0.0-M1" % Test,
)

scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature", "-Xfatal-warnings") ++ (
Expand All @@ -46,15 +47,6 @@ Test / scalacOptions ~= (_ filterNot Set(
"-Xfatal-warnings"
))

Compile / unmanagedSourceDirectories += {
val sourceDir = (Compile / sourceDirectory).value
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, n)) if n >= 13 => sourceDir / "scala-2.13+"
case Some((3, _)) => sourceDir / "scala-2.13+"
case _ => sourceDir / "scala-2.13-"
}
}

console / initialCommands := {
"""import com.lightbend.emoji._
|import com.lightbend.emoji.Emoji.Implicits._
Expand Down
100 changes: 100 additions & 0 deletions src/main/scala-3/com/lightbend/emoji/Emoji.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright (C) 2015-2022 Lightbend Inc. <http://www.lightbend.com>
*/
package com.lightbend.emoji

import scala.util.Try

/** The value class representing a codepoint in the Emoji set.
*
* @param codePoint the codepoint representing the Emoji character
*/
class Emoji private (val codePoint: Int) extends AnyVal:

/** Returns the sequence of characters (usually surrogate pairs).
*/
def chars: Array[Char] = Character.toChars(codePoint)

/** Returns the emoji's Unicode name.
*/
def name: String = Emoji.name(this.codePoint)

/** Returns the hexadecimal code.
*/
def toHexString: String = Emoji.toHexString(this.codePoint)

/** A convenience method that prepends "0x" before toHexString
*/
def hex: String = "0x" + toHexString

/** Returns the emoji as a String. Use this if you want smiley faces.
*/
override def toString = new String(chars)

/** This is the singleton object for Emoji.
*/
object Emoji:

// Don't want this to conflict with shortCode.emoji
extension (string: String) def codePointEmoji: Emoji = Emoji(
Try(Integer.parseInt(string, 16)).recover {
case e: NumberFormatException =>
val stripped = string.replace("0x", "")
Integer.parseInt(stripped, 16)
}.getOrElse {
throw new EmojiNotFound("Cannot parse emoji from hexadecimal string")
}
)

extension (codePoint: Int) def emoji: Emoji = Emoji(codePoint)

/** Returns the emoji for the given array of characters, throws EmojiNotFound
*/
def apply(chars: Array[Char]): Emoji = apply(Character.codePointAt(chars, 0))

/** Returns the emoji given a string containing the codepoint.
*/
def apply(string: String): Emoji = apply(string.codePointAt(0))

/** Returns the emoji for this codepoint if found, throws EmojiNotFound otherwise.
*/
def apply(codePoint: Int): Emoji = new Emoji(validated(codePoint))

/** Returns Some(emoji) if found, None otherwise.
*/
def get(codePoint: Int): Option[Emoji] =
if isEmoji(codePoint) then Some(new Emoji(codePoint)) else None

/** Returns true if this is a valid Unicode codepoint, false otherwise.
*/
def isEmoji(codePoint: Int): Boolean =
// there is no codeblock for unicode.
// val block = UnicodeBlock.of(codePoint)
// block == Character.UnicodeBlock.MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS ||
// block == Character.UnicodeBlock.EMOTICONS ||
// block == Character.UnicodeBlock.TRANSPORT_AND_MAP_SYMBOLS ||
// block == Character.UnicodeBlock.MISCELLANEOUS_SYMBOLS ||
// block == Character.UnicodeBlock.DINGBATS
Character.isValidCodePoint(codePoint)

/** Throws an exception if this is not a valid Unicode codepoint.
*/
def validated(codePoint: Int): Int =
if isEmoji(codePoint) then codePoint else throw new EmojiNotFound("Code point is not emoji!")

/** Returns the unicode name for this codePoint. Throws EmojiNotFound if this is not a valid codepoint.
*
* @param codePoint the codePoint.
* @return the unicode description of the emoji.
*/
def name(codePoint: Int): String =
Option(Character.getName(codePoint)).getOrElse {
throw new EmojiNotFound("No name found for this codePoint")
}

/** Returns the hexadecimal string of the code point.
*/
def toHexString(codePoint: Int): String = codePoint.toHexString
end Emoji

class EmojiNotFound(msg: String) extends RuntimeException(msg)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright (C) 2015-2022 Lightbend Inc. <http://www.lightbend.com>
*/
package com.lightbend.emoji

object ScalaVersionSpecific:
def checkLengths(sc: StringContext, args: Seq[Any]): Unit =
StringContext.checkLengths(args, sc.parts)
Loading

0 comments on commit 67a95d8

Please sign in to comment.