aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/restquery/utils/Utils.scala
blob: 827f2a05d02aee4918a65cdd20eda599b2693b8d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package xyz.driver.restquery.utils

import java.time.LocalDateTime
import java.util.regex.{Matcher, Pattern}

object Utils {

  implicit val localDateTimeOrdering: Ordering[LocalDateTime] = Ordering.fromLessThan(_ isBefore _)

  /**
    * Hack to avoid scala compiler bug with getSimpleName
    * @see https://issues.scala-lang.org/browse/SI-2034
    */
  def getClassSimpleName(klass: Class[_]): String = {
    try {
      klass.getSimpleName
    } catch {
      case _: InternalError =>
        val fullName      = klass.getName.stripSuffix("$")
        val fullClassName = fullName.substring(fullName.lastIndexOf(".") + 1)
        fullClassName.substring(fullClassName.lastIndexOf("$") + 1)
    }
  }

  def toSnakeCase(str: String): String =
    str
      .replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2")
      .replaceAll("([a-z\\d])([A-Z])", "$1_$2")
      .toLowerCase

  def toCamelCase(str: String): String = {
    val sb = new StringBuffer()
    def loop(m: Matcher): Unit = if (m.find()) {
      m.appendReplacement(sb, m.group(1).toUpperCase())
      loop(m)
    }
    val m: Matcher = Pattern.compile("_(.)").matcher(str)
    loop(m)
    m.appendTail(sb)
    sb.toString
  }

  object Whitespace {
    private val Table: String =
      "\u2002\u3000\r\u0085\u200A\u2005\u2000\u3000" +
        "\u2029\u000B\u3000\u2008\u2003\u205F\u3000\u1680" +
        "\u0009\u0020\u2006\u2001\u202F\u00A0\u000C\u2009" +
        "\u3000\u2004\u3000\u3000\u2028\n\u2007\u3000"

    private val Multiplier: Int = 1682554634
    private val Shift: Int      = Integer.numberOfLeadingZeros(Table.length - 1)

    def matches(c: Char): Boolean = Table.charAt((Multiplier * c) >>> Shift) == c
  }

  def isSafeWhitespace(char: Char): Boolean = Whitespace.matches(char)

  // From Guava
  def isSafeControl(char: Char): Boolean =
    char <= '\u001f' || (char >= '\u007f' && char <= '\u009f')

  def safeTrim(string: String): String = {
    def shouldKeep(c: Char): Boolean = !isSafeControl(c) && !isSafeWhitespace(c)

    if (string.isEmpty) {
      ""
    } else {
      val start = string.indexWhere(shouldKeep)
      val end   = string.lastIndexWhere(shouldKeep)

      if (start >= 0 && end >= 0) {
        string.substring(start, end + 1)
      } else {
        ""
      }
    }
  }
}