Skip to content

Turns the standard AST JNumber into a safe constructor #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 5, 2017
Merged
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,19 @@ Implementation is in `scalajson.ast.JValue`
of a number (http://stackoverflow.com/a/13502497/1519631)
- Equals will properly detect if two numbers are equal, i.e. `scalajson.ast.JNumber("34.00") == scalajson.ast.JNumber("34")`
- Hashcode has been designed to provide consistent hash for numbers of unlimited precision.
- If you construct a JNumber with `Float.NaN`/`Float.PositiveInfinity`/`Float.NegativeInfinity`/`Double.NaN`/`Double.PositiveInfinity`/`Double.NegativeInfinity` it will return a `JNull`
- You can construct an unlimited precision number using a string, i.e. `JNumber("34324")`. Returns an `Option[JNumber]` (will return `None` if `String` isn't a valid number)
- Note that this doesn't work for Scala 2.10 due to a restriction with how private constructor case classes are handled. For this reason a `JNumber.fromString` method is provided which compiles on all platforms and scala versions
- `scalajson.ast.JObject` is an actual `Map[String,JValue]`. This means that it doesn't handle duplicate keys for a `scalajson.ast.JObject`,
nor does it handle key ordering.
- `scalajson.ast.JArray` is an `Vector`.
- Library does not allow invalid JSON in the representation and hence we can guarantee that a `scalajson.ast.JValue` will
always contain a valid structure that can be serialized/rendered into [JSON](https://en.wikipedia.org/wiki/JSON).
- Note that you can lose precision when using `scalajson.ast.JNumber` in `Scala.js` (see `Scala.js`
section for more info).
- The `.copy` method of `scalajson.ast.JNumber` has been overridden to make sure you can't replace the internal `String`
with an incorrect number
- Will throw a `NumberFormatException` if you use `.copy` with an invalid JSON number
- Due to the above, has properly implemented deep equality for all types of `scalajson.ast.JValue`

## Unsafe AST
Expand Down Expand Up @@ -106,11 +112,13 @@ before creating a `scalajson.unsafe.JNumber`).
```scala
import scalajson.jNumberRegex

"3535353".matches(jNumberRegex) // true
"3535353" match {
case jNumberRegex(_ *) => true
case _ => false
}
```

Code of Conduct
===============
## Code of Conduct
ScalaJSON uses the [Scala Code of Conduct](https://www.scala-lang.org/conduct.html)
for all communication and discussion. This includes both GitHub, Gitter chat and
other more direct lines of communication such as email.
Expand Down
124 changes: 73 additions & 51 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ name := "scalajson"

import PgpKeys.publishSigned

// shadow sbt-scalajs' crossProject and CrossType until Scala.js 1.0.0 is released
import sbtcrossproject.crossProject

val currentScalaVersion = "2.11.11"
val scala210Version = "2.10.6"
val scala212Version = "2.12.2"
Expand All @@ -10,8 +13,8 @@ val specs2Version = "3.9.1"

scalaVersion in ThisBuild := currentScalaVersion
crossScalaVersions in ThisBuild := Seq(currentScalaVersion,
scala210Version,
scala212Version)
scala212Version,
scala210Version)

autoAPIMappings := true

Expand All @@ -26,7 +29,8 @@ val flagsFor11 = Seq(
"-Yconst-opt",
"-Ywarn-infer-any",
"-Yclosure-elim",
"-Ydead-code"
"-Ydead-code",
"-Xsource:2.12" // required to build case class construction
)

val flagsFor12 = Seq(
Expand All @@ -44,62 +48,72 @@ lazy val root = project
publishSigned := {}
)

lazy val scalaJson = crossProject
lazy val commonSettings = Seq(
name := "scalajson",
version := "1.0.0-M3",
organization := "org.scala-lang.platform",
scalacOptions ++= Seq(
"-encoding",
"UTF-8",
"-deprecation", // warning and location for usages of deprecated APIs
"-feature", // warning and location for usages of features that should be imported explicitly
"-unchecked", // additional warnings where generated code depends on assumptions
"-Xlint", // recommended additional warnings
"-Xcheckinit", // runtime error when a val is not initialized due to trait hierarchies (instead of NPE somewhere else)
"-Ywarn-adapted-args", // Warn if an argument list is modified to match the receiver
"-Ywarn-value-discard", // Warn when non-Unit expression results are unused
"-Ywarn-inaccessible",
"-Ywarn-dead-code"
),
publishMavenStyle := true,
publishTo := {
val nexus = "https://oss.sonatype.org/"
if (isSnapshot.value)
Some("snapshots" at nexus + "content/repositories/snapshots")
else
Some("releases" at nexus + "service/local/staging/deploy/maven2")
},
publishArtifact in Test := false,
pomIncludeRepository := (_ => false),
homepage := Some(url("https://github.com/mdedetrich/scalajson")),
scmInfo := Some(
ScmInfo(url("https://github.com/mdedetrich/scalajson"),
"[email protected]:mdedetrich/scalajson.git")),
developers := List(
Developer("mdedetrich",
"Matthew de Detrich",
"[email protected]",
url("https://github.com/mdedetrich"))
),
licenses += ("BSD 3 Clause", url(
"https://opensource.org/licenses/BSD-3-Clause"))
)

lazy val scalaJson = crossProject(JSPlatform, JVMPlatform)
.in(file("."))
.settings(
name := "scalajson",
version := "1.0.0-M3",
organization := "org.scala-lang.platform",
scalacOptions ++= Seq(
"-encoding",
"UTF-8",
"-deprecation", // warning and location for usages of deprecated APIs
"-feature", // warning and location for usages of features that should be imported explicitly
"-unchecked", // additional warnings where generated code depends on assumptions
"-Xlint", // recommended additional warnings
"-Xcheckinit", // runtime error when a val is not initialized due to trait hierarchies (instead of NPE somewhere else)
"-Ywarn-adapted-args", // Warn if an argument list is modified to match the receiver
"-Ywarn-value-discard", // Warn when non-Unit expression results are unused
"-Ywarn-inaccessible",
"-Ywarn-dead-code"
),
publishMavenStyle := true,
publishTo := {
val nexus = "https://oss.sonatype.org/"
if (isSnapshot.value)
Some("snapshots" at nexus + "content/repositories/snapshots")
else
Some("releases" at nexus + "service/local/staging/deploy/maven2")
commonSettings,
// In our build, implementations are specific due to use using sealed traits so a build defined
// in scala-2.10 can't use the same sources as the generic 'scala' build. This removes the 'scala'
// directory from sources when building for Scala 2.10.x
(unmanagedSourceDirectories in Compile) := {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, n)) if n >= 11 =>
(unmanagedSourceDirectories in Compile).value
case Some((2, n)) if n == 10 =>
(unmanagedSourceDirectories in Compile).value.filter { x =>
!x.getName.endsWith("scala")
}
}
},
publishArtifact in Test := false,
pomIncludeRepository := (_ => false),
homepage := Some(url("https://github.com/mdedetrich/scalajson")),
scmInfo := Some(ScmInfo(url("https://github.com/mdedetrich/scalajson"),
"[email protected]:mdedetrich/scalajson.git")),
developers := List(
Developer("mdedetrich",
"Matthew de Detrich",
"[email protected]",
url("https://github.com/mdedetrich"))
),
licenses += ("BSD 3 Clause", url(
"https://opensource.org/licenses/BSD-3-Clause")),
scalacOptions += {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, n)) if n >= 12 =>
"-target:jvm-1.8"
case _ =>
"-target:jvm-1.6"
}
}
)
.jvmSettings(
// Add JVM-specific settings here
libraryDependencies ++= Seq(
"org.specs2" %% "specs2-core" % specs2Version % Test,
"org.specs2" %% "specs2-scalacheck" % specs2Version % Test,
"org.scalacheck" %% "scalacheck" % scalaCheckVersion % Test
),
},
scalacOptions ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, n)) if n >= 12 =>
Expand All @@ -109,7 +123,15 @@ lazy val scalaJson = crossProject
case Some((2, n)) if n == 10 =>
flagsFor10
}
},
}
)
.jvmSettings(
// Add JVM-specific settings here
libraryDependencies ++= Seq(
"org.specs2" %% "specs2-core" % specs2Version % Test,
"org.specs2" %% "specs2-scalacheck" % specs2Version % Test,
"org.scalacheck" %% "scalacheck" % scalaCheckVersion % Test
),
scalacOptions in Test ++= Seq("-Yrangepos"),
mimaPreviousArtifacts := Set(
"org.scala-lang.platform" %% "scalajson" % "1.0.0-M2")
Expand All @@ -123,7 +145,7 @@ lazy val scalaJson = crossProject
testFrameworks += new TestFramework("utest.runner.Framework")
)

lazy val benchmark = crossProject
lazy val benchmark = crossProject(JSPlatform, JVMPlatform)
.in(file("benchmark"))
.jvmSettings(
testFrameworks += new TestFramework("org.scalameter.ScalaMeterFramework"),
Expand Down
Loading