Repository: propensive/rapture
Branch: dev
Commit: bbd9234337dc
Files: 219
Total size: 974.3 KB
Directory structure:
gitextract_x7qdv63e/
├── .gitignore
├── .jvmopts
├── .scalafmt
├── .travis.yml
├── README.md
├── base/
│ └── shared/
│ └── src/
│ └── main/
│ ├── scala/
│ │ └── Dummy.scala
│ ├── scala_2.10/
│ │ └── compat.scala
│ ├── scala_2.11/
│ │ └── compat.scala
│ └── scala_2.12/
│ └── compat.scala
├── build.sbt
├── cli/
│ └── shared/
│ └── src/
│ ├── main/
│ │ └── scala/
│ │ └── rapture/
│ │ └── cli/
│ │ ├── cli.scala
│ │ ├── glob.scala
│ │ ├── macros.scala
│ │ ├── params.scala
│ │ ├── params2.scala
│ │ ├── process.scala
│ │ ├── tabulate.scala
│ │ └── zsh.scala
│ └── test/
│ └── scala/
│ └── rapture/
│ └── cli/
│ └── tests.scala
├── codec/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── codec/
│ ├── base64.scala
│ ├── bytes.scala
│ └── encodings.scala
├── core/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── core/
│ ├── actor.scala
│ ├── alloc.scala
│ ├── app.scala
│ ├── core.scala
│ ├── default.scala
│ ├── functor.scala
│ ├── macros.scala
│ ├── med.scala
│ ├── modes.scala
│ ├── package.scala
│ ├── parser.scala
│ ├── pool.scala
│ ├── result.scala
│ ├── serializer.scala
│ ├── threads.scala
│ └── time.scala
├── core-scalaz/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── core-scalaz/
│ ├── modes.scala
│ └── transformers.scala
├── core-test/
│ └── shared/
│ └── src/
│ └── test/
│ └── scala/
│ └── rapture/
│ └── core/
│ └── tests.scala
├── crypto/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── crypto/
│ ├── aes.scala
│ └── digest.scala
├── css/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── css/
│ ├── context.scala
│ ├── css.scala
│ ├── model.scala
│ ├── package.scala
│ ├── properties.scala
│ └── validator.scala
├── css-test/
│ └── shared/
│ └── src/
│ └── test/
│ └── scala/
│ └── rapture/
│ └── css-test/
│ └── tests.scala
├── csv/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── csv/
│ ├── csv.scala
│ └── macros.scala
├── currency/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── currency/
│ ├── currency.scala
│ └── iso.scala
├── data/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── data/
│ ├── ast.scala
│ ├── context.scala
│ ├── data.scala
│ ├── exceptions.scala
│ ├── extractors.scala
│ ├── macros.scala
│ └── serializers.scala
├── doc/
│ ├── core-scalaz.md
│ ├── core.md
│ ├── html.md
│ ├── i18n.md
│ ├── json.md
│ └── m4-release.md
├── dom/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── dom/
│ ├── dom.scala
│ ├── format.scala
│ └── macro.scala
├── etc/
│ ├── header
│ └── updateheader.sh
├── fs/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── fs/
│ └── files.scala
├── google-translate/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── google-translate/
│ └── package.scala
├── html/
│ └── shared/
│ └── src/
│ ├── main/
│ │ └── scala/
│ │ └── rapture/
│ │ └── html/
│ │ ├── doc.scala
│ │ ├── phantom.scala
│ │ └── syntax.scala
│ └── test/
│ └── scala/
│ └── rapture/
│ └── html/
│ └── tests.scala
├── http/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── http/
│ ├── extractors.scala
│ ├── forms.scala
│ ├── handlers.scala
│ ├── http.scala
│ ├── page.scala
│ ├── request.scala
│ ├── response.scala
│ └── widgets.scala
├── http-jetty/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── http-jetty/
│ ├── http.scala
│ └── servlet.scala
├── http-json/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── http-json/
│ └── handler.scala
├── i18n/
│ └── shared/
│ └── src/
│ ├── main/
│ │ └── scala/
│ │ └── rapture/
│ │ └── i18n/
│ │ ├── i18n.scala
│ │ ├── languages.scala
│ │ └── package.scala
│ └── test/
│ └── scala/
│ └── rapture/
│ └── i18n/
│ └── tests.scala
├── io/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── io/
│ ├── contenttype.scala
│ ├── copy.scala
│ ├── delete.scala
│ ├── guid.scala
│ ├── io.scala
│ ├── move.scala
│ ├── multipart.scala
│ ├── name.scala
│ ├── package.scala
│ ├── size.scala
│ ├── slurp.scala
│ ├── streams.scala
│ ├── strings.scala
│ └── wrappers.scala
├── java8-support/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── core/
│ └── java8/
│ └── time.scala
├── js/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── js/
│ ├── context.scala
│ ├── js.scala
│ ├── package.scala
│ └── validator.scala
├── json/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── json/
│ ├── ast.scala
│ ├── context.scala
│ ├── extractors.scala
│ ├── formatters.scala
│ ├── json.scala
│ ├── macros.scala
│ ├── package.scala
│ ├── serializers.scala
│ ├── validator.scala
│ └── verifier.scala
├── json-argonaut/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── json-argonaut/
│ ├── ast.scala
│ ├── extractors.scala
│ ├── package.scala
│ ├── parse.scala
│ └── serializers.scala
├── json-circe/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── json-circe/
│ ├── ast.scala
│ ├── extractors.scala
│ ├── package.scala
│ ├── parse.scala
│ └── serializers.scala
├── json-jackson/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── json-jackson/
│ ├── ast.scala
│ ├── extractors.scala
│ ├── package.scala
│ ├── parse.scala
│ └── serializers.scala
├── json-jawn/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── json-jawn/
│ ├── ast.scala
│ ├── extractors.scala
│ ├── package.scala
│ ├── parse.scala
│ └── serializers.scala
├── json-json4s/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── json-json4s/
│ ├── ast.scala
│ ├── extractors.scala
│ ├── package.scala
│ ├── parse.scala
│ └── serializers.scala
├── json-lift/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── json-lift/
│ ├── ast.scala
│ ├── extractors.scala
│ ├── package.scala
│ ├── parse.scala
│ └── serializers.scala
├── json-play/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── json-play/
│ ├── ast.scala
│ ├── extraction.scala
│ ├── package.scala
│ ├── parse.scala
│ └── serializers.scala
├── json-spray/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── json-spray/
│ ├── ast.scala
│ ├── extraction.scala
│ ├── package.scala
│ ├── parse.scala
│ └── serializers.scala
├── json-test/
│ └── shared/
│ └── src/
│ └── test/
│ └── scala/
│ └── rapture/
│ └── json-test/
│ ├── java8TimeTests.scala
│ └── tests.scala
├── latex/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── latex/
│ └── latex.scala
├── log/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── log/
│ ├── levels.scala
│ ├── log.scala
│ └── parts.scala
├── mail/
│ ├── lib/
│ │ └── javamail.jar
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── mail/
│ ├── javamail.scala
│ ├── mail.scala
│ └── plaintext.scala
├── mime/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── mime/
│ └── mime.scala
├── net/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── net/
│ ├── browser.scala
│ ├── exceptions.scala
│ ├── http.scala
│ ├── ip.scala
│ ├── net.scala
│ ├── package.scala
│ ├── services.scala
│ └── sockets.scala
├── net-test/
│ └── shared/
│ └── src/
│ └── test/
│ └── scala/
│ └── rapture/
│ └── net/
│ └── test/
│ ├── DockerHttpBinServerSpec.scala
│ ├── HttpClientSpec.scala
│ └── helper/
│ └── DockerContainer.scala
├── project/
│ ├── build.properties
│ └── plugins.sbt
├── test/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── test/
│ ├── macros.scala
│ ├── report.scala
│ ├── scalatest.scala
│ └── test.scala
├── text/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── text/
│ ├── ansi.scala
│ └── text.scala
├── time/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── time/
│ └── time.scala
├── unixsocket/
│ └── jvm/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── unixsocket/
│ ├── UnixSocketHttpClient.scala
│ ├── UnixSocketHttpUrl.scala
│ └── package.scala
├── uri/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── uri/
│ ├── classpath.scala
│ ├── macros.scala
│ ├── nav.scala
│ ├── package.scala
│ ├── paths.scala
│ └── uri.scala
├── version.sbt
├── xml/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── xml/
│ ├── ast.scala
│ ├── context.scala
│ ├── extractors.scala
│ ├── formatters.scala
│ ├── macros.scala
│ ├── package.scala
│ ├── serializers.scala
│ ├── validator.scala
│ └── xml.scala
├── xml-stdlib/
│ └── shared/
│ └── src/
│ └── main/
│ └── scala/
│ └── rapture/
│ └── xml-stdlib/
│ ├── ast.scala
│ ├── extractors.scala
│ ├── package.scala
│ ├── parse.scala
│ └── serializers.scala
└── xml-test/
└── shared/
└── src/
└── test/
└── scala/
└── rapture/
└── xml-test/
├── java8TimeTests.scala
└── tests.scala
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
project/boot
target
.ensime
.ensime_lucene
TAGS
\#*#
*~
.#*
.lib
.history
.*.swp
.idea
.idea/*
.idea_modules
.DS_Store
.cache
.settings
.classpath
.project
================================================
FILE: .jvmopts
================================================
# see https://weblogs.java.net/blog/kcpeppe/archive/2013/12/11/case-study-jvm-hotspot-flags
-Dfile.encoding=UTF8
-Xms2G
-Xmx4G
-Xss6M
-XX:MaxPermSize=512M
-XX:ReservedCodeCacheSize=250M
-XX:+TieredCompilation
-XX:-UseGCOverheadLimit
# effectively adds GC to Perm space
-XX:+CMSClassUnloadingEnabled
# must be enabled for CMSClassUnloadingEnabled to work
-XX:+UseConcMarkSweepGC
================================================
FILE: .scalafmt
================================================
--maxColumn 120
================================================
FILE: .travis.yml
================================================
language: scala
services:
- docker
sudo: required
git:
depth: 50
scala:
- 2.10.6
- 2.11.8
- 2.12.1
jdk:
- oraclejdk8
script:
- if [[ "$TRAVIS_PULL_REQUEST" == "false" && "$TRAVIS_BRANCH" == "dev" && $(cat version.sbt) =~ "-SNAPSHOT" ]] ; then sbt ++$TRAVIS_SCALA_VERSION test publish gitSnapshots publish ; else sbt ++$TRAVIS_SCALA_VERSION test ; fi
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/NX9T51sqZ7a2U3zE8Thm
- https://webhooks.gitter.im/e/42e709a53fb8e39472d3
on_success: always
on_failure: always
on_start: true
env:
global:
- secure: DyrwS40Re2KfnuEMXNDkrWHDLeXzBsM1pCUBWy8ApexKEwI2SuO4at2th6yC8QvvLMmOkvDkheRVg1yENYTtUjerx4HATEoQcQ6RFjAfw4RmQLuUYWZFomGJ/q0KQ2EZmCCljbXM1q9vnhETuCgOcAMS5IRYOJf0EPYPFNArt8A=
- secure: c5OZn0AALmuPiZz8VYDqUNfJzxoUJ6dO/i1J3QQ/b9DQd2gWkdpAvpgqLX7SdyL26IssWPMJ4Zc6utMd8ONLrCdoPaFJr1arflwpSuP+tadxJEl2H0EBjSL2WFsce8j7HbhwGtoVwee2bKJ5gAMilInQXSoMqm9b5EBIN0JA2Ks=
cache:
directories:
- $HOME/.sbt/0.13/dependency
- $HOME/.sbt/boot/
- $HOME/.sbt/launchers
- $HOME/.ivy2/cache
before_cache:
- du -h -d 1 $HOME/.ivy2/cache
- du -h -d 2 $HOME/.sbt/
- find $HOME/.sbt -name "*.lock" -type f -delete
- find $HOME/.ivy2/cache -name "ivydata-*.properties" -type f -delete
================================================
FILE: README.md
================================================
# Rapture
[](https://travis-ci.org/propensive/rapture)
[](https://maven-badges.herokuapp.com/maven-central/com.propensive/rapture-core_2.11)
[](http://www.apache.org/licenses/LICENSE-2.0.txt)
[](https://gitter.im/propensive/rapture)
[](https://javadoc.io/doc/com.propensive/rapture-core_2.12)
Rapture is an evolving collection of *useful* libraries for solving common,
everyday programming tasks, using advanced features of Scala to offer better
type-safety through powerful APIs that all Scala developers, beginners and
advanced users, should find intuitive.
Rapture consists of a number of modules, the most notable of which are:
- Core (`core`) — a library of common utilities for other projects, notably
*modes* and the `Result` type
- [JSON](doc/json.md) (`json`) — comprehensive support for working with JSON
data
- XML (`xml`) — comprehensive, but experimental, support for working with XML
data
- I/O (`io`) — I/O (network, filesystem) functionality and infrastructure
- I18n (`i18n`) — simple, typesafe representation of internationalized strings
- CLI (`cli`) — support for working with command-line applications and shell
interaction
# Themes in Rapture
The Rapture modules share a common philosophy that has evolved over time and
experience. Here are a few of the philosophical themes crosscutting all of the
Rapture modules.
- A primary goal of intuitive, readable APIs and minimal code repetition
- Extreme type-safety, with a goal to reduce the surface area of code exposed
to runtime exceptions
- Thoroughly typeclass-driven design, for extensibility
- Fearless exploitation of all Scala features, where (but only where) it is
appropriate
- Agnostic support for multiple, alternative implementations of many
operations with pluggable backends
- Extensive, but principled, usage of implicits to configure and constrain
operations
- Support for modes in most APIs; the ability to change how failures are
handled through return types
## Availability
Snapshots of Rapture are available for Scala 2.10 and 2.11 under the *Apache
2.0 License* in the [Sonatype Snapshots
repository](https://oss.sonatype.org/content/repositories/snapshots/com/propensive/),
with group ID `com.propensive` and artifact ID `rapture-[module]`, where module
is the name of the module, as taken from the list above.
Development work to get most Rapture modules working on
[Scala.JS](htp://www.scala-js.org/) is ongoing.
You can build and run Rapture locally by cloning this repository and running
`sbt publishLocal`.
## Contributing
Rapture openly welcomes contributions! We would love to receive pull requests
of bugfixes and enhancements from other developers. To avoid potential wasted
effort, bugs should first be reported on the Github issue tracker, and it's
normally a good idea to talk about enhancements on the [Gitter
channel](https://gitter.im/propensive/rapture) before embarking on any
development.
Alternatively, just send Jon Pretty
([@propensive](https://twitter.com/propensive/)) a tweet to start a
conversation.
Current contributors include:
- Jon Pretty
- Raúl Raja Martínez
- Alistair Johnson
## Documentation
Rapture's documentation is currently sparse, though we are working to improve
this.
================================================
FILE: base/shared/src/main/scala/Dummy.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
================================================
FILE: base/shared/src/main/scala_2.10/compat.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.base
import scala.reflect._
import macros._
object `package` {
type BlackboxContext = Context
type WhiteboxContext = Context
lazy val compatibility = new Compat210()
}
class Compat210() {
def termName(c: Context, s: String) = c.universe.newTermName(s)
def typeName(c: Context, s: String) = c.universe.newTypeName(s)
def constructor(c: Context) = c.universe.nme.CONSTRUCTOR
def wildcard(c: Context) = c.universe.nme.WILDCARD
def typeIntersection(c: Context)(xs: List[c.universe.Type]) = c.universe.intersectionType(xs)
def paramLists(c: Context)(t: c.universe.MethodSymbol) = t.paramss
def normalize(c: Context)(t: c.universe.Type) = t.normalize
def declarations(c: Context)(t: c.universe.Type) = t.declarations
def declaration(c: Context)(t: c.universe.Type, n: c.universe.Name) = t.declaration(n)
def readLine(): String = Console.readLine()
def typecheck(c: Context)(s: c.Tree) = c.typeCheck(s)
def freshName(c: Context)(s: String) = c.fresh(s)
def companion(c: Context)(x: c.universe.Symbol) = x.companionSymbol
def samePosition(c: Context)(p1: c.universe.Position, p2: c.universe.Position) = p1.isDefined && p1.point == p2.point
def enclosingDef(c: Context)(pos: c.universe.Position): Option[c.universe.Name] = {
import c.universe._
c.enclosingClass.collect { case DefDef(_, name, _, _, _, rhs) if samePosition(c)(rhs.pos, pos) => name }.headOption
}
def enclosingVals(c: Context)(pos: c.universe.Position, count: Int): Option[c.universe.Name] = {
import c.universe._
c.enclosingClass.collect { case ValDef(_, name, _, rhs) if samePosition(c)(rhs.pos, pos) => name }.drop(count).headOption
}
}
================================================
FILE: base/shared/src/main/scala_2.11/compat.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.base
import scala.reflect._
import macros._
object `package` {
type BlackboxContext = blackbox.Context
type WhiteboxContext = whitebox.Context
lazy val compatibility = new Compat211()
}
class Compat211() {
def termName[C <: blackbox.Context](c: C, s: String) = c.universe.TermName(s)
def typeName[C <: blackbox.Context](c: C, s: String) = c.universe.TypeName(s)
def constructor[C <: blackbox.Context](c: C) = c.universe.termNames.CONSTRUCTOR
def wildcard[C <: blackbox.Context](c: C) = c.universe.termNames.WILDCARD
def typeIntersection[C <: blackbox.Context](c: C)(xs: List[c.universe.Type]) =
c.universe.internal.intersectionType(xs)
def paramLists[C <: blackbox.Context](c: C)(t: c.universe.MethodSymbol) = t.paramLists
def normalize[C <: blackbox.Context](c: C)(t: c.universe.Type) = t.dealias
def declarations[C <: blackbox.Context](c: C)(t: c.universe.Type) = t.decls
def declaration[C <: blackbox.Context](c: C)(t: c.universe.Type, d: c.universe.Name) = t.decl(d)
def readLine(): String = scala.io.StdIn.readLine
def typecheck[C <: blackbox.Context](c: C)(t: c.Tree) = c.typecheck(t)
def freshName[C <: blackbox.Context](c: C)(s: String) = c.freshName(s)
def companion[C <: blackbox.Context](c: C)(s: c.universe.Symbol) = s.companion
def samePosition[C <: blackbox.Context](c: C)(p1: c.universe.Position, p2: c.universe.Position) = {
import c.universe._
p1 != NoPosition && p2 != NoPosition && p1.start == p2.start
}
def enclosingDef[C <: blackbox.Context](c: C)(pos: c.universe.Position): Option[c.universe.Name] =
Some(c.internal.enclosingOwner.asTerm.name)
def enclosingVals[C <: blackbox.Context](c: C)(pos: c.universe.Position, count: Int): Option[c.universe.Name] =
Some(c.internal.enclosingOwner.asTerm.name)
}
================================================
FILE: base/shared/src/main/scala_2.12/compat.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.base
import scala.reflect._
import macros._
object `package` {
type BlackboxContext = blackbox.Context
type WhiteboxContext = whitebox.Context
lazy val compatibility = new Compat212()
}
class Compat212() {
def termName[C <: blackbox.Context](c: C, s: String) = c.universe.TermName(s)
def typeName[C <: blackbox.Context](c: C, s: String) = c.universe.TypeName(s)
def constructor[C <: blackbox.Context](c: C) = c.universe.termNames.CONSTRUCTOR
def wildcard[C <: blackbox.Context](c: C) = c.universe.termNames.WILDCARD
def typeIntersection[C <: blackbox.Context](c: C)(xs: List[c.universe.Type]) =
c.universe.internal.intersectionType(xs)
def paramLists[C <: blackbox.Context](c: C)(t: c.universe.MethodSymbol) = t.paramLists
def normalize[C <: blackbox.Context](c: C)(t: c.universe.Type) = t.dealias
def declarations[C <: blackbox.Context](c: C)(t: c.universe.Type) = t.decls
def declaration[C <: blackbox.Context](c: C)(t: c.universe.Type, d: c.universe.Name) = t.decl(d)
def readLine(): String = scala.io.StdIn.readLine
def typecheck[C <: blackbox.Context](c: C)(t: c.Tree) = c.typecheck(t)
def freshName[C <: blackbox.Context](c: C)(s: String) = c.freshName(s)
def companion[C <: blackbox.Context](c: C)(s: c.universe.Symbol) = s.companion
def samePosition[C <: blackbox.Context](c: C)(p1: c.universe.Position, p2: c.universe.Position) = {
import c.universe._
p1 != NoPosition && p2 != NoPosition && p1.start == p2.start
}
def enclosingDef[C <: blackbox.Context](c: C)(pos: c.universe.Position): Option[c.universe.Name] =
Some(c.internal.enclosingOwner.asTerm.name)
def enclosingVals[C <: blackbox.Context](c: C)(pos: c.universe.Position, count: Int): Option[c.universe.Name] =
Some(c.internal.enclosingOwner.asTerm.name)
}
================================================
FILE: build.sbt
================================================
import com.typesafe.sbt.pgp.PgpKeys.publishSigned
import ReleaseTransformations._
enablePlugins(GitBranchPrompt)
lazy val buildSettings = Seq(
organization := "com.propensive",
scalaVersion := "2.12.1",
crossScalaVersions := Seq("2.12.2", "2.11.8", "2.10.6")
)
lazy val commonSettings = Seq(
// scalafmtConfig in ThisBuild := Some(file(".scalafmt")),
scalacOptions ++= Seq(
"-deprecation",
"-encoding", "UTF-8",
"-feature",
"-unchecked",
"-Xfatal-warnings",
"-Xlint",
"-language:existentials"
/* "-language:higherKinds",
"-language:implicitConversions",
"-language:experimental.macros",
"-Yinline-warnings",
"-Yno-adapted-args",
"-Ywarn-numeric-widen",
"-Ywarn-value-discard",
"-Xfuture" */
) ++ (CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, majorVersion)) if majorVersion >= 11 => Seq("-Ywarn-unused-import")
case _ => Seq.empty
}),
scalacOptions in (Compile, console) ~= (_ filterNot (_ == "-Ywarn-unused-import")),
scalacOptions in (Test, console) := (scalacOptions in (Compile, console)).value,
scalaJSStage in Test := FastOptStage,
concurrentRestrictions in Global ++= Seq(Tags.limitSum(2, Tags.CPU, Tags.Untagged), Tags.limit(Tags.Test, 1)),
scmInfo := Some(ScmInfo(url("https://github.com/propensive/rapture"),
"scm:git:git@github.com:propensive/rapture.git"))
) ++ scalaMacroDependencies
lazy val raptureSettings = buildSettings ++ commonSettings ++ publishSettings
lazy val rapture = project.in(file("."))
.settings(moduleName := "root")
.settings(raptureSettings)
.settings(noPublishSettings)
.settings(noSourceSettings)
.aggregate(raptureJVM, raptureJS, raptureExtrasJVM, raptureExtrasJS)
.dependsOn(raptureJVM, raptureJS, raptureExtrasJVM, raptureExtrasJS)
lazy val raptureJVM = project.in(file(".raptureJVM"))
.settings(moduleName := "rapture")
.settings(raptureSettings)
.aggregate(baseJVM, coreJVM, timeJVM, uriJVM, codecJVM, cryptoJVM, csvJVM, ioJVM, fsJVM, netJVM, httpJVM, mimeJVM, cliJVM, mailJVM, logJVM, i18nJVM, googleTranslateJVM, textJVM, latexJVM, testJVM, dataJVM, xmlJVM, jsJVM, cssJVM, currencyJVM, jsonJVM, htmlJVM, domJVM, coreScalazJVM, httpJsonJVM, java8SupportJVM, unixsocketJVM)
.dependsOn(baseJVM, coreJVM, timeJVM, uriJVM, codecJVM, cryptoJVM, csvJVM, ioJVM, fsJVM, netJVM, httpJVM, mimeJVM, cliJVM, mailJVM, logJVM, i18nJVM, googleTranslateJVM, textJVM, latexJVM, testJVM, dataJVM, xmlJVM, jsJVM, cssJVM, currencyJVM, jsonJVM, htmlJVM, domJVM, coreScalazJVM, httpJsonJVM, java8SupportJVMi, unixsocketJVM)
lazy val raptureJS = project.in(file(".raptureJS"))
.settings(moduleName := "rapture")
.settings(raptureSettings)
.aggregate(baseJS, coreJS, timeJS, uriJS, codecJS, cryptoJS, csvJS, ioJS, fsJS, netJS, httpJS, mimeJS, cliJS, mailJS, logJS, i18nJS, googleTranslateJS, textJS, latexJS, testJS, dataJS, jsonJS, htmlJS, domJS, coreScalazJS, httpJsonJS, xmlJS, jsJS, cssJS, currencyJS, java8SupportJS)
.dependsOn(baseJS, coreJS, timeJS, uriJS, codecJS, cryptoJS, csvJS, ioJS, fsJS, netJS, httpJS, mimeJS, cliJS, mailJS, logJS, i18nJS, googleTranslateJS, textJS, latexJS, testJS, dataJS, jsonJS, htmlJS, domJS, coreScalazJS, httpJsonJS, xmlJS, jsJS, cssJS, currencyJS, java8SupportJS)
.enablePlugins(ScalaJSPlugin)
lazy val raptureExtras = crossProject
.aggregate(`core-test`, `http-jetty`, `json-circe`, `xml-stdlib`, `json-jawn`, `json-play`, `json-json4s`, `json-spray`, `json-argonaut`, `json-jackson`, `json-test`, `xml-test`, `json-lift`, `net-test`, `java8-support`)
.dependsOn(`core-test`, `http-jetty`, `json-circe`, `xml-stdlib`, `json-jawn`, `json-play`, `json-json4s`, `json-spray`, `json-argonaut`, `json-jackson`, `json-test`, `xml-test`, `json-lift`, `net-test`, `java8-support`)
.settings(moduleName := "rapture-extras")
.settings(raptureSettings:_*)
.settings(crossVersionSharedSources():_*)
lazy val raptureExtrasJVM = raptureExtras.jvm
lazy val raptureExtrasJS = raptureExtras.js
// rapture-base
lazy val base = crossProject
.settings(moduleName := "rapture-base")
.settings(raptureSettings:_*)
.settings(crossVersionSharedSources():_*)
lazy val baseJVM = base.jvm
lazy val baseJS = base.js
// rapture-core
lazy val core = crossProject.dependsOn(base)
.settings(moduleName := "rapture-core")
.settings(raptureSettings:_*)
lazy val coreJVM = core.jvm
lazy val coreJS = core.js
// rapture-core-test
lazy val `core-test` = crossProject.dependsOn(test, `core-scalaz`)
.settings(moduleName := "rapture-core-test")
.settings(raptureSettings:_*)
lazy val coreTestJVM = `core-test`.jvm
lazy val coreTestJS = `core-test`.js
// rapture-uri
lazy val uri = crossProject.dependsOn(core)
.settings(moduleName := "rapture-uri")
.settings(raptureSettings:_*)
lazy val uriJVM = uri.jvm
lazy val uriJS = uri.js
// rapture-codec
lazy val codec = crossProject.dependsOn(core)
.settings(moduleName := "rapture-codec")
.settings(raptureSettings:_*)
lazy val codecJVM = codec.jvm
lazy val codecJS = codec.js
// rapture-crypto
lazy val crypto = crossProject.dependsOn(core, codec)
.settings(moduleName := "rapture-crypto")
.settings(raptureSettings:_*)
lazy val cryptoJVM = crypto.jvm
lazy val cryptoJS = crypto.js
// rapture-io
lazy val io = crossProject.dependsOn(codec, mime, uri)
.settings(moduleName := "rapture-io")
.settings(raptureSettings:_*)
lazy val ioJVM = io.jvm
lazy val ioJS = io.js
// rapture-mime
lazy val mime = crossProject.dependsOn()
.settings(moduleName := "rapture-mime")
.settings(raptureSettings:_*)
lazy val mimeJVM = mime.jvm
lazy val mimeJS = mime.js
// rapture-net
lazy val net = crossProject.dependsOn(io)
.settings(moduleName := "rapture-net")
.settings(raptureSettings:_*)
.settings(libraryDependencies += "commons-net" % "commons-net" % "2.0")
lazy val netJVM = net.jvm
lazy val netJS = net.js
// rapture-net-test
lazy val `net-test` = crossProject.dependsOn(net, test, json, `json-circe`)
.settings(moduleName := "rapture-net-test")
.settings(raptureSettings: _*)
.settings(
libraryDependencies ++= Seq(
"com.spotify" % "docker-client" % "5.0.2",
"org.scalatest" %% "scalatest" % "2.2.6"
)
)
lazy val netTestJVM = `net-test`.jvm
lazy val netTestJS = `net-test`.js
// rapture-unixsocket
// this is not a scala-js project - it may only be used on the jvm and on linux
lazy val unixsocketJVM = (project in file("unixsocket/jvm")).dependsOn(io.jvm, core.jvm, net.jvm, uri.jvm)
.settings(moduleName := "rapture-unixsocket")
.settings(raptureSettings: _*)
.settings(libraryDependencies ++= Seq(
"com.kohlschutter.junixsocket" % "junixsocket-native" % "2.0.4",
"com.kohlschutter.junixsocket" % "junixsocket-native-common" % "2.0.4",
"com.kohlschutter.junixsocket" % "junixsocket-common" % "2.0.4",
"org.apache.httpcomponents" % "httpclient" % "4.5.2"
))
// rapture-time
lazy val time = crossProject.dependsOn(core)
.settings(moduleName := "rapture-time")
.settings(raptureSettings:_*)
lazy val timeJVM = time.jvm
lazy val timeJS = time.js
// rapture-http
lazy val http = crossProject.dependsOn(net, uri, json, html, fs, log, time)
.settings(moduleName := "rapture-http")
.settings(raptureSettings:_*)
.settings(libraryDependencies += "javax.servlet" % "servlet-api" % "2.5")
.settings(libraryDependencies += "org.w3c.css" % "sac" % "1.3")
.settings(libraryDependencies += "net.sourceforge.cssparser" % "cssparser" % "0.9.20")
lazy val httpJVM = http.jvm
lazy val httpJS = http.js
// rapture-http-json
lazy val `http-json` = crossProject.dependsOn(http, json)
.settings(moduleName := "rapture-http-json")
.settings(raptureSettings:_*)
lazy val httpJsonJVM = `http-json`.jvm
lazy val httpJsonJS = `http-json`.js
// rapture-http-jetty
lazy val `http-jetty` = crossProject.dependsOn(http)
.settings(moduleName := "rapture-http-jetty")
.settings(raptureSettings:_*)
.settings(libraryDependencies += "org.eclipse.jetty" % "jetty-servlet" % "7.6.10.v20130312")
lazy val httpJettyJVM = `http-jetty`.jvm
lazy val httpJettyJS = `http-jetty`.js
// rapture-fs
lazy val fs = crossProject.dependsOn(io)
.settings(moduleName := "rapture-fs")
.settings(raptureSettings:_*)
lazy val fsJVM = fs.jvm
lazy val fsJS = fs.js
// rapture-csv
lazy val csv = crossProject.dependsOn(fs)
.settings(moduleName := "rapture-csv")
.settings(raptureSettings:_*)
lazy val csvJVM = csv.jvm
lazy val csvJS = csv.js
// rapture-cli
lazy val cli = crossProject.dependsOn(log, fs)
.settings(moduleName := "rapture-cli")
.settings(raptureSettings:_*)
lazy val cliJVM = cli.jvm
lazy val cliJS = cli.js
// rapture-mail
lazy val mail = crossProject.dependsOn(io, html, net)
.settings(moduleName := "rapture-mail")
.settings(raptureSettings:_*)
.settings(libraryDependencies += "javax.mail" % "mail" % "1.4")
lazy val mailJVM = mail.jvm
lazy val mailJS = mail.js
// rapture-log
lazy val log = crossProject.dependsOn(io)
.settings(moduleName := "rapture-log")
.settings(raptureSettings:_*)
lazy val logJVM = log.jvm
lazy val logJS = log.js
// rapture-i18n
lazy val i18n = crossProject.dependsOn(core, test)
.settings(moduleName := "rapture-i18n")
.settings(raptureSettings:_*)
lazy val i18nJVM = i18n.jvm
lazy val i18nJS = i18n.js
// rapture-google-translate
lazy val `google-translate` = crossProject.dependsOn(core, net, `json-jawn`, i18n)
.settings(moduleName := "rapture-google-translate")
.settings(raptureSettings:_*)
lazy val googleTranslateJVM = `google-translate`.jvm
lazy val googleTranslateJS = `google-translate`.js
// rapture-text
lazy val text = crossProject.dependsOn(core)
.settings(moduleName := "rapture-text")
.settings(raptureSettings:_*)
lazy val textJVM = text.jvm
lazy val textJS = text.js
// rapture-latex
lazy val latex = crossProject.dependsOn(text, cli)
.settings(moduleName := "rapture-latex")
.settings(raptureSettings:_*)
lazy val latexJVM = latex.jvm
lazy val latexJS = latex.js
// rapture-test
lazy val test = crossProject.dependsOn(cli, fs, text)
.settings(moduleName := "rapture-test")
.settings(raptureSettings:_*)
.settings(libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1")
lazy val testJVM = test.jvm
lazy val testJS = test.js
// rapture-dom
lazy val dom = crossProject.dependsOn(core)
.settings(moduleName := "rapture-dom")
.settings(raptureSettings:_*)
lazy val domJVM = dom.jvm
lazy val domJS = dom.js
// rapture-html
lazy val html = crossProject.dependsOn(net, mime, dom, test, js, css)
.settings(moduleName := "rapture-html")
.settings(raptureSettings:_*)
lazy val htmlJVM = html.jvm
lazy val htmlJS = html.js
// rapture-data
lazy val data = crossProject.dependsOn(core)
.settings(moduleName := "rapture-data")
.settings(raptureSettings:_*)
lazy val dataJVM = data.jvm
lazy val dataJS = data.js
// rapture-xml
lazy val xml = crossProject.dependsOn(data)
.settings(moduleName := "rapture-xml")
.settings(raptureSettings:_*)
lazy val xmlJVM = xml.jvm
lazy val xmlJS = xml.js
// rapture-js
lazy val js = crossProject.dependsOn(data)
.settings(moduleName := "rapture-js")
.settings(raptureSettings:_*)
lazy val jsJVM = js.jvm
lazy val jsJS = js.js
// rapture-css
lazy val css = crossProject.dependsOn(data, dom)
.settings(moduleName := "rapture-css")
.settings(raptureSettings:_*)
.settings(libraryDependencies += "net.sourceforge.cssparser" % "cssparser" % "0.9.20")
lazy val cssJVM = css.jvm
lazy val cssJS = css.js
// rapture-currency
lazy val currency = crossProject.dependsOn(data)
.settings(moduleName := "rapture-currency")
.settings(raptureSettings:_*)
lazy val currencyJVM = currency.jvm
lazy val currencyJS = currency.js
// rapture-json
lazy val json = crossProject.dependsOn(data)
.settings(moduleName := "rapture-json")
.settings(raptureSettings:_*)
lazy val jsonJVM = json.jvm
lazy val jsonJS = json.js
// rapture-java8-support
lazy val `java8-support` = crossProject.dependsOn(core)
.settings(moduleName := "rapture-java8-support")
.settings(raptureSettings:_*)
lazy val java8SupportJVM = `java8-support`.jvm
lazy val java8SupportJS = `java8-support`.js
// rapture-json-circe
lazy val `json-circe` = crossProject.dependsOn(json)
.settings(moduleName := "rapture-json-circe")
.settings(raptureSettings:_*)
.settings(libraryDependencies += "io.circe" %% "circe-core" % "0.7.0")
.settings(libraryDependencies += "io.circe" %% "circe-jawn" % "0.7.0")
lazy val jsonCirceJVM = `json-circe`.jvm
lazy val jsonCirceJS = `json-circe`.js
// rapture-xml-stdlib
lazy val `xml-stdlib` = crossProject.dependsOn(xml)
.settings(moduleName := "rapture-xml-stdlib")
.settings(raptureSettings:_*)
lazy val xmlStdlibJVM = `xml-stdlib`.jvm
lazy val xmlStdlibJS = `xml-stdlib`.js
// rapture-json-jawn
lazy val `json-jawn` = crossProject.dependsOn(json)
.settings(moduleName := "rapture-json-jawn")
.settings(raptureSettings:_*)
.settings(libraryDependencies += "org.spire-math" %% "jawn-parser" % "0.10.4")
.settings(libraryDependencies += "org.spire-math" %% "jawn-ast" % "0.10.4")
lazy val jsonJawnJVM = `json-jawn`.jvm
lazy val jsonJawnJS = `json-jawn`.js
lazy val playJsonDependencies: Seq[Setting[_]] = Seq(
libraryDependencies += (CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 10)) => "com.typesafe.play" %% "play-json" % "2.4.6"
case Some((2, 11)) => "com.typesafe.play" %% "play-json" % "2.5.3"
case Some((2, 12)) => "com.typesafe.play" %% "play-json" % "2.6.0-M1"
})
)
// rapture-json-play
lazy val `json-play` = crossProject.dependsOn(json)
.settings(moduleName := "rapture-json-play")
.settings(raptureSettings: _*)
.settings(playJsonDependencies: _*)
lazy val jsonPlayJVM = `json-play`.jvm
lazy val jsonPlayJS = `json-play`.js
// rapture-json-json4s
lazy val `json-json4s` = crossProject.dependsOn(json)
.settings(moduleName := "rapture-json-json4s")
.settings(raptureSettings:_*)
.settings(libraryDependencies += "org.json4s" %% "json4s-native" % "3.5.0")
lazy val jsonJson4sJVM = `json-json4s`.jvm
lazy val jsonJson4sJS = `json-json4s`.js
// rapture-json-spray
lazy val `json-spray` = crossProject.dependsOn(json)
.settings(moduleName := "rapture-json-spray")
.settings(raptureSettings:_*)
.settings(libraryDependencies += "io.spray" %% "spray-json" % "1.3.3")
lazy val jsonSprayJVM = `json-spray`.jvm
lazy val jsonSprayJS = `json-spray`.js
// rapture-json-argonaut
lazy val `json-argonaut` = crossProject.dependsOn(json)
.settings(moduleName := "rapture-json-argonaut")
.settings(raptureSettings:_*)
.settings(libraryDependencies += "io.argonaut" %% "argonaut" % "6.2-RC1")
lazy val jsonArgonautJVM = `json-argonaut`.jvm
lazy val jsonArgonautJS = `json-argonaut`.js
// rapture-json-jackson
lazy val `json-jackson` = crossProject.dependsOn(json)
.settings(moduleName := "rapture-json-jackson")
.settings(raptureSettings:_*)
.settings(libraryDependencies += "com.fasterxml.jackson.core" % "jackson-databind" % "2.7.2")
lazy val jsonJacksonJVM = `json-jackson`.jvm
lazy val jsonJacksonJS = `json-jackson`.js
// rapture-core-scalaz
lazy val `core-scalaz` = crossProject.dependsOn(core)
.settings(moduleName := "rapture-core-scalaz")
.settings(raptureSettings:_*)
.settings(libraryDependencies += "org.scalaz" %% "scalaz-core" % "7.2.8")
.settings(libraryDependencies += "org.scalaz" %% "scalaz-concurrent" % "7.2.8")
lazy val coreScalazJVM = `core-scalaz`.jvm
lazy val coreScalazJS = `core-scalaz`.js
// rapture-json-test
lazy val `json-test` = crossProject
.dependsOn(`json-jawn`, `json-lift`, `json-spray`, `json-argonaut`, `json-jackson`, `json-play`, `json-json4s`, `json-circe`, `java8-support`, test)
.settings(moduleName := "rapture-json-test")
.settings(raptureSettings:_*)
lazy val jsonTestJVM = `json-test`.jvm
lazy val jsonTestJS = `json-test`.js
// rapture-css-test
lazy val `css-test` = crossProject.dependsOn(css, html, test)
.settings(moduleName := "rapture-css-test")
.settings(raptureSettings:_*)
lazy val cssTestJVM = `css-test`.jvm
lazy val cssTestJS = `css-test`.js
// rapture-xml-test
lazy val `xml-test` = crossProject.dependsOn(`xml-stdlib`, `java8-support`, test)
.settings(moduleName := "rapture-xml-test")
.settings(raptureSettings:_*)
lazy val xmlTestJVM = `xml-test`.jvm
lazy val xmlTestJS = `xml-test`.js
// rapture-json-lift
lazy val `json-lift` = crossProject.dependsOn(json)
.settings(moduleName := "rapture-json-lift")
.settings(raptureSettings:_*)
.settings(libraryDependencies += (CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 10)) => "net.liftweb" %% "lift-json" % "2.6.3"
case Some((2, scalaMajor)) if scalaMajor >= 11 => "net.liftweb" %% "lift-json" % "3.0.1"
}))
lazy val jsonLiftJVM = `json-lift`.jvm
lazy val jsonLiftJS = `json-lift`.js
lazy val publishSettings = Seq(
homepage := Some(url("http://rapture.io/")),
licenses := Seq("Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt")),
autoAPIMappings := true,
publishMavenStyle := true,
publishArtifact in Test := false,
pomIncludeRepository := { _ => false },
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")
},
pomExtra := (
propensiveJon Pettyhttp://github.com/propensive/rapture
),
releaseProcess := Seq[ReleaseStep](
checkSnapshotDependencies,
inquireVersions,
runTest,
setReleaseVersion,
commitReleaseVersion,
tagRelease,
publishArtifacts,
setNextVersion,
commitNextVersion,
ReleaseStep(action = Command.process("sonatypeReleaseAll", _)),
pushChanges
),
releaseCrossBuild := true,
releasePublishArtifactsAction := PgpKeys.publishSigned.value
)
lazy val noPublishSettings = Seq(
publish := (),
publishLocal := (),
publishArtifact := false
)
lazy val noSourceSettings = Seq(
sources in Compile := Seq(),
sources in Test := Seq()
)
import java.io.File
def crossVersionSharedSources() = Seq(
(unmanagedSourceDirectories in Compile) ++= { (unmanagedSourceDirectories in Compile ).value.map {
dir:File => new File(dir.getPath + "_" + scalaBinaryVersion.value)}}
)
lazy val scalaMacroDependencies: Seq[Setting[_]] = Seq(
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value,
libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value,
libraryDependencies ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
// if scala 2.11+ is used, quasiquotes are merged into scala-reflect
case Some((2, scalaMajor)) if scalaMajor >= 11 => Seq()
// in Scala 2.10, quasiquotes are provided by macro paradise
case Some((2, 10)) =>
Seq(
compilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full),
"org.scalamacros" %% "quasiquotes" % "2.1.0" cross CrossVersion.binary
)
}
}
)
addCommandAlias("gitSnapshots", ";set version in ThisBuild := git.gitDescribedVersion.value.get + \"-SNAPSHOT\"")
// For Travis CI - see http://www.cakesolutions.net/teamblogs/publishing-artefacts-to-oss-sonatype-nexus-using-sbt-and-travis-ci
credentials ++= (for {
username <- Option(System.getenv().get("SONATYPE_USERNAME"))
password <- Option(System.getenv().get("SONATYPE_PASSWORD"))
} yield Credentials("Sonatype Nexus Repository Manager", "oss.sonatype.org", username, password)).toSeq
================================================
FILE: cli/shared/src/main/scala/rapture/cli/cli.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.cli
import rapture.io._
import rapture.codec._
import rapture.fs._
import rapture.core._
import rapture.uri._
import rapture.log._
import encodings.system._
import logLevels.trace._
import language.{higherKinds, implicitConversions}
import language.experimental.macros
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
object DebugModeConfig {
implicit val defaultDebugMode: DebugModeConfig = DebugModeConfig(false)
}
object debugMode {
def apply(): DebugModeConfig = implicitDebugMode
implicit val implicitDebugMode: DebugModeConfig = DebugModeConfig(true)
}
case class DebugModeConfig(on: Boolean)
object ShParam {
implicit def stringableToShParam[T: StringSerializer](t: T): ShParam =
ShParam(Vector(?[StringSerializer[T]].serialize(t)))
implicit def genSeqSerializer[T: StringSerializer, Coll[E] <: TraversableOnce[E]](ts: Coll[T]): ShParam =
ShParam(ts.map(?[StringSerializer[T]].serialize(_)).to[Vector])
implicit def processToShParam(process: Process): ShParam = ShParam(process.params)
implicit def fsUrlToShParam(fsUrl: FsUrl): ShParam = ShParam(Vector(fsUrl.elements.mkString("/", "/", "")))
}
case class ShParam(elems: Vector[String]) {
def asString = elems.mkString(" ")
}
object `package` {
implicit class ProcessStringContext(sc: StringContext) {
def sh(content: ShParam*): Process = macro CliMacros.shImplementation
}
object cliLogging {
import rapture.log.parts._
implicit val logger = Logger(uri"file:///tmp/rapture-cli/access.log")
implicit def implicitSpec(implicit severity: Severity, date: Date, time: Time, thread: Thread): Spec =
log"""$date $time $severity ${sourceFile(width = 12, Right)}:${lineNo(4)} ${thread(14)}"""
}
}
sealed class CliException(msg: String) extends Exception(msg)
case class ParamGetException(name: String) extends CliException(s"Missing parameter $name")
abstract class BackgroundCliApp(implicit debugMode: DebugModeConfig) extends CliApp with Completions[Zsh with Bash] {
val shellCompleter = new Bash with Zsh {}
private var lastExitStatus = 0
override def doExit(code: Int) = lastExitStatus = code
def shutdown(): Unit = ()
override def main(args: Array[String]) = {
import cliLogging._
val appName = args(0)
val fifo = File.parse(s"file:///tmp/rapture-cli/${appName}.sock")
var continue = true
var invocation = 0
while (continue) {
val msg = fifo.slurp[Char].trim
msg.split(",").to[List].map(_.urlDecode) match {
case "shutdown" :: Nil =>
log.info("Received shutdown command")
shutdown()
fifo.delete()
sys.exit(0)
case "sigint" :: file :: Nil =>
log.info("Received SIGINT for file " + file)
case "winch" :: file :: lines :: cols :: Nil =>
log.info(s"Received SIGWINCH for file $file $lines x $cols")
case "exec" :: file :: pwd :: rest =>
log.info(s"Using pwd = $pwd")
val ps = new java.io.PrintStream(new java.io.FileOutputStream(new java.io.File(file)))
invocation += 1
Future {
try {
System.setOut(ps)
try super.run(File.parse(s"file://$pwd"), rest.to[Array])
catch {
case e: Throwable => if (debugMode.on) e.printStackTrace()
}
} catch {
case e: Throwable =>
if (debugMode.on) e.printStackTrace()
} finally ps.close()
val ps2 = new java.io.PrintStream(new java.io.FileOutputStream(new java.io.File(s"$file.exit")))
try {
ps2.println(lastExitStatus.toString)
ps2.flush()
ps2.close()
System.setOut(sysOut)
} finally ps2.close()
}
case _ =>
}
}
}
}
case class ReturnEarly() extends Exception()
abstract class CliApp(implicit debugMode: DebugModeConfig) {
private val NoOutput = new java.io.PrintStream(new java.io.OutputStream() {
def write(x: Int) = ()
})
def exit(code: Int): Unit = throw Exit(code)
def exec(block: => Unit): Exec = Exec((out: java.io.PrintStream) => block)
def exec(block: java.io.PrintStream => Unit): Exec = Exec(block)
val sysOut = System.out
def doExit(code: Int): Unit = sys.exit(code)
def main(args: Array[String]): Unit = run(File.parse(s"file://${System.getenv("PWD")}"), args)
def run(pwd: FsUrl, args: Array[String]): Unit = {
val exitStatus: Exit = try {
Console.withOut(NoOutput) {
try {
val cmdLine: CmdLine = makeCmdLine(pwd, args.to[Vector])
val execution = handle(cmdLine)
if (cmdLine.completer.isEmpty) {
execution.exec(System.out)
Exit(0)
} else Exit(0)
} catch {
case ReturnEarly() =>
Exit(0)
case err: Throwable =>
Console.withOut(sysOut) {
println("Unexpected error")
if (debugMode.on) err.printStackTrace()
}
throw Exit(1)
}
}
} catch { case err @ Exit(_) => err }
doExit(exitStatus.code)
}
def makeCmdLine(pwd: FsUrl, args: Vector[String]) =
CmdLine(pwd, args map { s =>
Arg(s, None, false)
}, None)
def handle(cmdLine: CmdLine): Exec
}
trait Shell {
def makeCmdLine(pwd: FsUrl, cmdLine: Vector[String]): CmdLine =
CmdLine(pwd, cmdLine.map(Arg(_, None, false)), None)
}
trait Zsh extends Shell {
override def makeCmdLine(pwd: FsUrl, cmdLine: Vector[String]): CmdLine = cmdLine match {
case "---rapture-zsh" +: prefix +: cursor +: cols +: "--" +: rest =>
val colWidth = cols.substring(10).toInt
val cur = cursor.substring(9).toInt
val words = if (cur >= rest.length) rest.tail :+ "" else rest.tail
val completer = Completer(prefix.substring(9).urlDecode, zshCompleter(_, colWidth))
CmdLine(pwd, words.zipWithIndex map {
case (s, idx) =>
Arg(s, Some(completer), cur - 2 == idx)
}, Some(completer))
case _ =>
super.makeCmdLine(pwd, cmdLine)
}
def zshCompleter(suggestions: Suggestions, colWidth: Int): Nothing = {
suggestions.groups.foreach { g =>
val cmds = Compadd(g.title, g.suggestions.keys.to[Vector], true, v => g.suggestions(v), colWidth, g.hidden)
cmds foreach System.out.println
}
throw ReturnEarly()
}
}
trait Bash extends Shell {
override def makeCmdLine(pwd: FsUrl, cmdLine: Vector[String]): CmdLine = cmdLine match {
case "---rapture-bash" +: prefix +: cursor +: cols +: "--" +: rest =>
val colWidth = cols.substring(10).toInt
val words = if (cursor.toInt - 1 >= rest.length) rest.tail :+ "" else rest.tail
val completer = new Completer(prefix.urlDecode, bashCompleter)
CmdLine(pwd, words.zipWithIndex map {
case (s, idx) =>
Arg(s, Some(completer), cursor.toInt - 2 == idx)
}, Some(completer))
case _ =>
super.makeCmdLine(pwd, cmdLine)
}
def bashCompleter(suggestions: Suggestions): Nothing = {
System.out.println("Using bash")
throw ReturnEarly()
}
}
case class Exit(code: Int) extends Exception
case class Exec(exec: java.io.PrintStream => Unit)
================================================
FILE: cli/shared/src/main/scala/rapture/cli/glob.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.cli
import java.util.regex._
object globInterpreters {
/* This in an incomplete implementation as it does not support character classes enclosed
* by `[` and `]`.
*/
object unix {
def apply(): GlobInterpreter = implicitGlobInterpreter
implicit val implicitGlobInterpreter: GlobInterpreter = new GlobInterpreter {
def interpret(glob: String): Pattern = {
val sb = new StringBuilder
var start = true
glob foreach { c =>
start = false
sb.append(c match {
case '*' => if (start) "[^./][^/]*" else "[^/]*"
case '?' => if (start) "[^./][^/]*" else "[^/]*"
case '/' => start = true; "/"
case esc @ ('.' | '[' | '{' | '(' | '+' | '^' | '$' | '|') => "\\" + esc
case other => other.toString
})
}
Pattern.compile(sb.toString)
}
}
}
}
trait GlobInterpreter { def interpret(glob: String): Pattern }
case class Glob(globString: String)(implicit globInterpreter: GlobInterpreter) {
lazy val pattern: Pattern = globInterpreter.interpret(globString)
def matches(s: String) = pattern.matcher(s).matches
}
================================================
FILE: cli/shared/src/main/scala/rapture/cli/macros.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.cli
import rapture.base._
import rapture.core._
private[cli] object CliMacros {
def shImplementation(c: BlackboxContext)(content: c.Expr[ShParam]*): c.Expr[Process] = {
import c.universe._
val params = c.prefix.tree match {
case Apply(_, List(Apply(_, rawParts))) =>
val parts = rawParts.to[Vector].zip(content.map(_.tree).to[Vector]).flatMap {
case (x, y) => Vector(x, y)
} :+ rawParts.last
var params: Vector[c.Tree] = Vector()
var param: Vector[Either[String, c.Tree]] = Vector()
var inline: Boolean = false
var singleQuoted: Boolean = false
var doubleQuoted: Boolean = false
var escaped: Boolean = false
def add(chr: Char) = {
param =
if (param.isEmpty) Vector(Left(chr.toString))
else
param.last match {
case Right(_) =>
param :+ Left(chr.toString)
case Left(str) =>
param.init :+ Left(str + chr)
}
escaped = false
}
def nextParam() = if (!param.isEmpty) {
val next: c.Tree = if (inline) {
val strings = param.map {
case Left(str) =>
q"$str"
case Right(tr) =>
q"""$tr.elems.mkString(" ")"""
}
q"_root_.scala.Vector(_root_.scala.Vector(_root_.scala.Vector(..$strings).mkString))"
} else {
val values = param.map {
case Left(str) =>
q"_root_.scala.Vector($str)"
case Right(tr) =>
q"$tr.elems"
}
q"_root_.scala.Vector(..$values)"
}
params = params :+ next
param = Vector()
inline = false
}
parts.foreach {
case Literal(Constant(str: String)) =>
str.foreach {
case chr if escaped =>
add(chr)
case ' ' =>
if (singleQuoted || doubleQuoted) add(' ') else nextParam()
case '\\' =>
escaped = true
case '\'' if !doubleQuoted =>
singleQuoted = !singleQuoted
case '"' if !singleQuoted =>
doubleQuoted = !doubleQuoted
case chr =>
add(chr)
}
case tr =>
inline = inline || singleQuoted || doubleQuoted
param = param :+ Right(tr.asInstanceOf[c.Tree])
}
nextParam()
if (singleQuoted || doubleQuoted) c.abort(c.enclosingPosition, "unclosed quoted parameter")
if (params.isEmpty) c.abort(c.enclosingPosition, "no command specified")
q"_root_.scala.Vector(..$params).flatten.flatten"
}
c.Expr(q"""new _root_.rapture.cli.Process($params)""")
}
}
================================================
FILE: cli/shared/src/main/scala/rapture/cli/params.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.cli
import rapture.fs._
import rapture.core._
import annotation.tailrec
import scala.collection.immutable.ListMap
import language.higherKinds
object Optable {
implicit val stringOptable = new Optable[String] {
def name(t: String) = t
def description(t: String) = Vector()
def hidden(t: String): Boolean = false
}
implicit val OptOptable = new Optable[Opt] {
def name(t: Opt) = t.name
def description(t: Opt) = Vector(s"-- ${t.description}")
def hidden(t: Opt): Boolean = t.hidden
}
implicit val stringPairOptable = new Optable[(String, String)] {
def name(t: (String, String)) = t._1
def description(t: (String, String)) = Vector(t._2)
def hidden(t: (String, String)): Boolean = t._2 == ""
}
}
trait Optable[-T] {
def name(t: T): String
def description(t: T): Vector[String]
def hidden(t: T): Boolean
}
case class Opt(name: String, description: String, hidden: Boolean = false)(opts: => Opts[Opt]) {
def unapply(arg: Arg): Boolean = opts.unapply(arg) == Some(this)
}
case class Opts[T: Optable](options: T*) {
private val optable = implicitly[Optable[T]]
def unapply(arg: Arg): Option[T] = {
val p = arg(suggester)
options.to[List].find(optable.name(_) == p)
}
def suggester: Suggester = new Suggester {
override def suggest(prefix: String): Suggestions =
Suggestions(
SuggestionGroup(None,
options
.to[Vector]
.map { opt =>
(optable.name(opt), optable.description(opt))
}
.filter(_._1 startsWith prefix)
.toMap,
false))
}
}
object NoSuggestions extends Suggester
case class Param[+T: ParamParser](longName: String = null,
shortName: String = null,
description: String = null,
suggester: Suggester = NoSuggestions,
repeatable: Boolean = false) {
def parse(s: List[String]): Option[T] = implicitly[ParamParser[T]].parse(s)
}
trait ParamParser_1 {
implicit val intParamParser: ParamParser[Int] = new ParamParser[Int] {
def parse(s: List[String]) = s.headOption.map(_.toInt)
}
implicit val booleanParamParser: ParamParser[Boolean] = new ParamParser[Boolean] {
def parse(s: List[String]): Option[Boolean] = Some(true)
}
}
object ParamParser extends ParamParser_1 {
implicit val defaultParamParser: ParamParser[String] = new ParamParser[String] {
def parse(s: List[String]) = s.headOption
}
def of[T: ParamParser]: ParamParser[T] = implicitly[ParamParser[T]]
}
trait ParamParser[+T] { paramParser =>
def parse(s: List[String]): Option[T]
def map[S](fn: T => S): ParamParser[S] = new ParamParser[S] {
def parse(s: List[String]): Option[S] = paramParser.parse(s).map(fn)
}
}
object Paramable {
implicit def paramParamable[T]: Paramable[T, Param] = new Paramable[T, Param] {
def longName(p: Param[T]): String = Option(p.longName).map("--" + _).getOrElse("")
def shortName(p: Param[T]): String = Option(p.shortName).map("-" + _).getOrElse("")
def description(p: Param[T]): Vector[String] = Option(p.description).to[Vector]
def hidden(p: Param[T]): Boolean = false
def suggester(p: Param[T]): Suggester = p.suggester
def repeatable(p: Param[T]): Boolean = p.repeatable
def parse(p: Param[T], s: List[String]): Option[T] = p.parse(s)
}
}
trait Paramable[T, P[_]] {
def longName(t: P[T]): String
def shortName(t: P[T]): String
def description(t: P[T]): Vector[String]
def hidden(t: P[T]): Boolean
def suggester(t: P[T]): Suggester
def repeatable(t: P[T]): Boolean
def parse(p: P[T], s: List[String]): Option[T]
}
case class Params[T, P[_]](options: P[T]*)(implicit paramable: Paramable[T, P]) {
def suggester(exclusions: Set[String]): Suggester = new Suggester {
override def suggest(prefix: String): Suggestions = Suggestions(
SuggestionGroup(None, options.filterNot { opt =>
exclusions.contains(paramable.longName(opt).drop(2)) ||
exclusions.contains(paramable.shortName(opt).drop(1))
}.map { opt =>
(paramable.longName(opt), paramable.shortName(opt) +: paramable.description(opt))
}.filter(_._1 startsWith prefix).toMap, false),
SuggestionGroup(None, options.filterNot { opt =>
exclusions.contains(paramable.longName(opt).drop(2)) ||
exclusions.contains(paramable.shortName(opt).drop(1))
}.map { opt =>
paramable.shortName(opt) -> Vector()
}.filter(_._1 startsWith prefix).toMap, true)
)
}
private object LongOpt {
def unapply(arg: Arg): Option[String] =
if (arg.param.startsWith("--")) Some(arg(suggester(Set())).drop(2)) else None
}
private object ShortOpt {
def unapply(arg: Arg): Option[String] =
if (arg.param.startsWith("-")) Some(arg(suggester(Set())).slice(1, 2)) else None
}
@tailrec
private def organize(xs: Seq[Arg], acc: ListMap[String, List[Arg]] = ListMap()): Map[String, List[Arg]] = xs match {
case Seq() =>
acc
case LongOpt(dashParam) +: tail =>
organize(tail, acc + (dashParam -> Nil))
case (arg @ ShortOpt(dashParam)) +: tail =>
if (arg.param.length == 2) organize(tail, acc + (dashParam -> Nil))
else organize(arg.copy(param = "-" + arg.param.drop(2)) +: tail, acc + (dashParam.take(2) -> Nil))
case v +: tail =>
acc.lastOption match {
case Some((key, entry)) =>
organize(tail, acc + (key -> (entry :+ v)))
case None =>
val exclusions = acc.keys.to[Set]
v(suggester(exclusions))
organize(tail, acc)
}
}
def unapply(cmdLine: CmdLine): Option[ParamMap] =
Some(ParamMap(organize(cmdLine.params), cmdLine.completer))
}
case class ParamMap(params: Map[String, List[Arg]], completer: Option[Completer]) {
def get[T, P[_]](param: P[T], suggesters: Suggester*)(implicit paramable: Paramable[T, P]): Option[T] = {
params.find {
case (k, v) =>
k == implicitly[Paramable[T, P]]
.longName(param)
.substring(2) || k == implicitly[Paramable[T, P]].shortName(param).substring(1)
}.flatMap {
case (_, args) =>
val values = suggesters padTo (args.length, NoSuggestions) zip args map {
case (suggester, arg) => arg(suggester)
}
paramable.parse(param, values.to[List])
}
}
def apply[T, P[_]](param: P[T], suggesters: Suggester*)(implicit paramable: Paramable[T, P]): T =
get(param, suggesters: _*).getOrElse {
if (completer.isDefined) null.asInstanceOf[T] else throw ParamGetException(paramable.longName(param))
}
}
object -- {
def unapply(cmdLine: CmdLine): Option[(CmdLine, CmdLine)] = {
val left = cmdLine.params.takeWhile(_.param != "--")
Some(
if (cmdLine.params.length == left.length) (cmdLine, CmdLine(cmdLine.pwd, Vector(), cmdLine.completer))
else
(
CmdLine(cmdLine.pwd, left, cmdLine.completer),
CmdLine(cmdLine.pwd, cmdLine.params.drop(left.length + 1), cmdLine.completer)
)
)
}
}
case class Arg(param: String, completer: Option[Completer], current: Boolean) {
def apply(suggester: Suggester) = completer match {
case Some(c) if current =>
c.process(suggester.suggest(c.prefix))
case _ => param
}
}
case class CmdLine(pwd: FsUrl, params: Vector[Arg], completer: Option[Completer])
extends collection.SeqLike[Arg, CmdLine] {
def seq = params
def apply(idx: Int) = params(idx)
def length = params.length
def iterator: Iterator[Arg] = params.iterator
def newBuilder: collection.mutable.Builder[Arg, CmdLine] =
new collection.mutable.Builder[Arg, CmdLine] {
var vect: Vector[Arg] = Vector()
def clear(): Unit = vect = Vector()
def result(): CmdLine = CmdLine(pwd, vect, completer)
def +=(elem: Arg) = {
vect = vect :+ elem
this
}
}
override def toString =
params.map {
case Arg(p, _, false) => p
case Arg(p, _, true) => completer.get.prefix + "^" + p.drop(completer.get.prefix.length + 1)
}.mkString(" ")
}
class Suggester { def suggest(prefix: String): Suggestions = Suggestions() }
object Suggestions {
def from[T](it: Iterable[T])(fn: T => String, fns: (T => Any)*) = new Suggester {
override def suggest(prefix: String) =
Suggestions(SuggestionGroup(None, it.map { e =>
fn(e) -> ((if (fns.isEmpty) "" else "--") +: fns.to[Vector].map(_ (e).toString))
}.filter(_._1.startsWith(prefix)).toMap, false))
}
/*def from[T](fromPrefix: String => Iterable[T])(fn: T => String, fns: (T => Any)*) = new Suggester {
override def suggest(prefix: String) = Suggestions(SuggestionGroup(None,
fromPrefix(prefix).map { e =>
fn(e) -> ((if(fns.isEmpty) "" else "--") +: fns.to[Vector].map(_(e).toString))
}.toMap, false))
}*/
}
case class Suggestions(groups: SuggestionGroup*)
case class SuggestionGroup(title: Option[String], suggestions: Map[String, Vector[String]], hidden: Boolean)
case class Completer(prefix: String, shellCompleter: Suggestions => Nothing) {
def process(suggestions: Suggestions): Nothing = shellCompleter(suggestions)
}
trait Completions[ShellTypes <: Shell] {
this: CliApp =>
override def makeCmdLine(pwd: FsUrl, args: Vector[String]): CmdLine =
shellCompleter().makeCmdLine(pwd, args)
def shellCompleter(): ShellTypes
}
================================================
FILE: cli/shared/src/main/scala/rapture/cli/params2.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.cli
import scala.util.Try
import scala.annotation.tailrec
import rapture.core._
object New {
case class ParamUsage(map: ParamMap, used: Set[String]) {
def -(key: String): ParamUsage = copy(used = used + key)
def --(keys: Set[String]): ParamUsage = copy(used = used ++ keys)
def unexpected = map.groups.filterNot { p =>
used contains p.key()
}
}
case class ParamMap(args: String*) {
def ++(pm2: ParamMap) = ParamMap(pm2.args ++ args: _*)
case class Part(no: Int, start: Int, end: Int) {
def apply() = args(no).substring(start, end)
}
case class Parameter(key: Part, values: Vector[Part] = Vector()) {
override def toString = {
val prefix = if (key().length == 1) "-" else "--"
s"$prefix${key()} ${values.map(_ ()) mkString " "}"
}
}
val groups: Set[Parameter] = parseArgs().to[Set]
@tailrec
private def parseArgs(gs: List[Parameter] = Nil, n: Int = 0, off: Int = 0): List[Parameter] = {
if (n == args.length) gs
else if (args(n) startsWith "--") {
val idx = args(n).indexOf('=')
if (idx < off) parseArgs(Parameter(Part(n, 2, args(n).length)) :: gs, n + 1)
else parseArgs(Parameter(Part(n, 2, idx)) :: gs, n, idx + 1)
} else if (args(n) startsWith "-") {
if (off == 0) parseArgs(gs, n, 1)
else if (args(n).length == off + 1) parseArgs(Parameter(Part(n, off, off + 1)) :: gs, n + 1)
else parseArgs(Parameter(Part(n, off, off + 1)) :: gs, n, off + 1)
} else {
if (gs.isEmpty) parseArgs(gs, n + 1)
else parseArgs(gs.head.copy(values = gs.head.values :+ Part(n, 0, args(n).length)) :: gs.tail, n + 1)
}
}
def find(key: String): Option[Parameter] = groups.find(_.key() == key)
def apply(names: Vector[String]): Option[Parameter] = names match {
case Vector() => None
case h +: t => find(h) orElse apply(t)
}
def isEmpty = args.isEmpty
override def toString = groups.mkString
}
trait `Params.parse` extends MethodConstraint
sealed class ParamException(msg: String) extends Exception(msg)
case class MissingParam(name: String) extends ParamException(s"the parameter --$name was missing")
case class InvalidValue(value: String, name: String)
extends ParamException(s"the value '$value' is not valid for the parameter --$name")
case class UnexpectedParam(param: String) extends ParamException(s"found unexpected parameter '$param'")
@implicitNotFound("Can not combine elements of type ${A} and ${B}")
trait Construct[-A <: Params, -B <: Params] { construct =>
type And <: Params
type Or <: Params
def and(a: A, b: B): ProductParams[And]
def or(a: A, b: B): CoproductParams[Or]
def swap: Construct[B, A] { type And = construct.And; type Or = construct.Or } =
new Construct[B, A] {
type And = construct.And
type Or = construct.Or
def and(a: B, b: A): ProductParams[And] = construct.and(b, a)
def or(a: B, b: A): CoproductParams[Or] = construct.or(b, a)
}
}
trait Construct_1 {
implicit def general[A <: Params, B <: Params]: Construct[A, B] { type And = A with B; type Or = A with B } = {
new Construct[A, B] {
type And = A with B
type Or = A with B
def and(a: A, b: B) = ProductParams[A with B](Set(a, b))
def or(a: A, b: B) = CoproductParams[A with B](Vector(a, b))
}
}
}
object Construct extends Construct_1 {
implicit def leftProduct[A <: Params, B <: SimpleParam[_]]: Construct[ProductParams[A], B] {
type And = A with B; type Or = ProductParams[A] with B
} = {
new Construct[ProductParams[A], B] {
type And = A with B
type Or = ProductParams[A] with B
def and(a: ProductParams[A], b: B) = ProductParams[A with B](a.elements + b)
def or(a: ProductParams[A], b: B) =
CoproductParams[ProductParams[A] with B](Vector(a, b))
}
}
implicit def rightProduct[A <: SimpleParam[_], B <: Params]: Construct[A, ProductParams[B]] {
type And = B with A; type Or = ProductParams[B] with A
} = leftProduct[B, A].swap
implicit def leftCoproduct[A <: Params, B <: SimpleParam[_]]
: Construct[CoproductParams[A], B] { type And = CoproductParams[A] with B; type Or = A with B } = {
new Construct[CoproductParams[A], B] {
type And = CoproductParams[A] with B
type Or = A with B
def and(a: CoproductParams[A], b: B) =
ProductParams[CoproductParams[A] with B](Set(a, b))
def or(a: CoproductParams[A], b: B) = CoproductParams[A with B](a.elements :+ b)
}
}
implicit def rightCoproduct[A <: SimpleParam[_], B <: Params]
: Construct[A, CoproductParams[B]] { type And = CoproductParams[B] with A; type Or = B with A } =
leftCoproduct[B, A].swap
}
case class Suggestions(output: Option[Seq[Vector[String]]]) {
def orElse(ss: Suggestions) = Suggestions(output orElse ss.output)
}
object SuggestionOutput {
implicit val defaultOutput: SuggestionOutput = new SuggestionOutput {
def output(ss: Suggestions) = ()
}
}
trait SuggestionOutput { def output(ss: Suggestions): Unit }
trait Params { params =>
type Result
def parse(args: ParamMap, tabArg: Int = -1)(implicit suggestOutput: SuggestionOutput,
mode: Mode[`Params.parse`]): mode.Wrap[Result, ParamException] =
mode.wrap {
val (result, lastArgs, ss) = check(ParamUsage(args, Set()), mode, tabArg, Suggestions(None))
suggestOutput.output(ss)
lastArgs.unexpected foreach { p =>
mode.exception(UnexpectedParam(p.key()))
}
result
}
def check(args: ParamUsage, mode: Mode[_], tabArg: Int, ss: Suggestions): (Result, ParamUsage, Suggestions)
def &[B <: Params](b: B)(implicit con: Construct[params.type, b.type]): ProductParams[con.And] = {
con.and(this, b)
}
def |[B <: Params](b: B)(implicit con: Construct[params.type, b.type]): CoproductParams[con.Or] = {
con.or(this, b)
}
def unary_~ : OptionParams[this.type] = OptionParams(this)
def by[R](fn: Result => R): Param.Handler[this.type, R] =
new Param.Handler[this.type, R](this) {
type From = Result
def handle(v: From): R = fn(v)
}
}
case class OptionParams[Ps <: Params](params: Ps) extends Params {
type Result = Option[params.Result]
def check(args: ParamUsage, mode: Mode[_], tabArg: Int, ss: Suggestions): (Result, ParamUsage, Suggestions) =
try {
val (res, newArgs, newSs) = params.check(args, mode, tabArg, ss)
(Some(res), newArgs, newSs)
} catch { case e: Exception => (None, args, ss) }
override def toString = s"[$params]"
}
case class ProductParams[Ps <: Params](elements: Set[Params]) extends Params {
type ProductTypes = Ps
type Result = Product[ProductTypes]
def check(args: ParamUsage, mode: Mode[_], tabArg: Int, ss: Suggestions): (Result, ParamUsage, Suggestions) = {
val (finalArgs, finalElems, newSs) = elements.foldLeft((args, Set[(Params, Any)](), ss)) {
case ((args, es, ss), key) =>
val (res, nextArgs, newSs) = key.check(args, mode, tabArg, ss)
(nextArgs, es + (key -> res), ss orElse newSs)
}
(new Product[Ps](finalElems.toMap), finalArgs, newSs)
}
override def toString = elements.mkString("( ", " & ", " )")
}
case class CoproductParams[Ps <: Params](elements: Vector[Params]) extends Params {
type CoproductTypes = Ps
type Result = Coproduct[CoproductTypes]
def check(args: ParamUsage, mode: Mode[_], tabArg: Int, ss: Suggestions): (Result, ParamUsage, Suggestions) = {
val elems = elements.to[List].flatMap { k =>
Try(Option(k.check(args, mode, tabArg, ss)).get).toOption.map(k -> _)
}
elems match {
case (key, (res, args, newSs)) :: Nil => (Coproduct[CoproductTypes](key -> res), args, newSs)
case Nil => mode.exception(MissingParam(toString))
case _ :: (key, _) :: _ => mode.exception(UnexpectedParam(key.toString))
}
}
override def toString = elements.mkString("( ", " | ", " )")
}
object ToSuggestion {
implicit val stringSuggestion: ToSuggestion[String] = new ToSuggestion[String] {
def suggestion(value: String): Vector[String] = Vector(value)
}
}
trait ToSuggestion[T] {
def suggestion(value: T): Vector[String]
}
case class SimpleParam[T: Param.Extractor](keys: Vector[String]) extends Params { simpleParam =>
type Result = T
def toSuggestion(t: T): Vector[String] = Vector()
def suggestions(s: String): Seq[T] = Seq()
def checkValue: Option[T] = None
def suggest(suggestions: T*)(implicit sug: ToSuggestion[T]): SimpleParam[T] =
suggest { s =>
suggestions
}
def suggest(suggestions: String => Seq[T])(implicit sug: ToSuggestion[T]): SimpleParam[T] = {
val ss = suggestions
new SimpleParam[T](keys) {
override def toSuggestion(value: T): Vector[String] = sug.suggestion(value)
override def suggestions(s: String) = ss(s)
override def checkValue = simpleParam.checkValue
}
}
def filter(fn: T => Boolean): SimpleParam[T] = new SimpleParam[T](keys) {
override def toSuggestion(value: T): Vector[String] = simpleParam.toSuggestion(value)
override def suggestions(str: String) = simpleParam.suggestions(str).filter(fn)
override def checkValue = simpleParam.checkValue
}
protected val extractor = ?[Param.Extractor[T]]
def check(args: ParamUsage, mode: Mode[_], tabArg: Int, ss: Suggestions): (Result, ParamUsage, Suggestions) = {
val parameter = args.map(keys) getOrElse mode.exception(MissingParam(keys.head))
val res = extractor.extract(parameter.values.map(_ ())) getOrElse {
mode.exception(InvalidValue(parameter.key(), parameter.values.mkString(" ")))
}
checkValue.foreach { v =>
if (v != res) mode.exception(InvalidValue(keys.head, "invalid"))
}
val newSs = Suggestions(parameter.values.find(tabArg == _.no).map { p =>
suggestions(p()).map(toSuggestion)
})
(res, args -- keys.to[Set], ss orElse newSs)
}
// Also consider `extractor` in `hashCode` and `equals`
override def hashCode = keys.hashCode ^ extractor.hashCode
override def equals(that: Any) = that match {
case that: SimpleParam[_] =>
keys.to[Set] == that.keys.to[Set] && that.extractor == extractor
case _ =>
false
}
override def toString =
keys.map { k =>
if (k.length == 1) s"-$k" else s"--$k"
}.mkString("/")
def of(v: T): SimpleParam[T] = new SimpleParam[T](keys) {
override def toSuggestion(value: T): Vector[String] = simpleParam.toSuggestion(value)
override def suggestions(str: String) = simpleParam.suggestions(str)
override def checkValue = Some(v)
}
}
object Param {
object Extractor {
implicit val stringExtractor: Extractor[String] = new Extractor[String] {
// FIXME: Add mode parameter, and capture failure types
def extract(values: Vector[String]): Option[String] = Some(values.mkString(" "))
}
implicit val intExtractor: Extractor[Int] = new Extractor[Int] {
def extract(values: Vector[String]): Option[Int] = values match {
case Vector(v) =>
try Some(v.toInt)
catch { case e: Exception => None }
case _ => None
}
}
implicit val unitExtractor: Extractor[Unit] = new Extractor[Unit] {
def extract(values: Vector[String]): Option[Unit] = Some(())
}
}
trait Extractor[T] { def extract(values: Vector[String]): Option[T] }
abstract class Handler[-K, +H](val params: Params) {
type From
def handle(v: From): H
}
def apply[T: Extractor](shortName: Char, longName: Symbol): SimpleParam[T] =
alloc(Vector(shortName.toString, longName.name))
def apply[T: Extractor](shortName: Char): SimpleParam[T] =
alloc(Vector(shortName.toString))
def apply[T: Extractor](longName: Symbol): SimpleParam[T] = alloc(Vector(longName.name))
def flag(shortName: Char, longName: Symbol): SimpleParam[Unit] =
alloc(Vector(shortName.toString, longName.name))
def flag(shortName: Char): SimpleParam[Unit] = alloc(Vector(shortName.toString))
def flag(longName: Symbol): SimpleParam[Unit] = alloc(Vector(longName.name))
}
@implicitNotFound("product does not contain this value")
trait ProductContainsParam[V, T]
object ProductContainsParam extends ProductContainsParam_1 {
implicit def optional[V <: OptionParams[_ <: Params], P <: Params]: ProductContainsParam[V, P] = null
}
trait ProductContainsParam_1 {
implicit def generic[V, T <: V]: ProductContainsParam[V, T] = null
}
@implicitNotFound("coproduct cannot contain this value")
trait CoproductContainsParam[V, T]
object CoproductContainsParam {
implicit def acceptable[V, T <: V]: CoproductContainsParam[V, T] = null
}
case class Product[T <: Params](tmap: Map[Params, Any]) {
def apply[V <: Params](value: V)(implicit acc: ProductContainsParam[value.type, T]): value.Result =
tmap(value).asInstanceOf[value.Result]
override def toString = tmap.map { case (k, v) => s"$k: $v" }.mkString(", ")
}
case class Coproduct[T <: Params](value: (Params, Any)) {
def handle[K, R](handlers: Param.Handler[K, R]*)(implicit ev: K <:< T): R = {
val h = handlers.find(_.params == value._1).get
h.handle(value._2.asInstanceOf[h.From])
}
override def toString = s"${value._1}: ${value._2}"
}
}
================================================
FILE: cli/shared/src/main/scala/rapture/cli/process.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.cli
import rapture.io._
import rapture.core._
import rapture.codec._
import java.io.{Reader => _, _}
import encodings.system._
import language.higherKinds
trait `Process#exec` extends MethodConstraint
case class Process(params: Vector[String]) {
def exec[T: ProcessInterpreter](implicit mode: Mode[`Process#exec`], env: Environment): mode.Wrap[T, CliException] =
mode.wrap {
val javaProcess = Runtime
.getRuntime()
.exec(params.to[Array], env().map { case (k, v) => s"$k=$v" }
.to[Array], new File(env.workDir.getOrElse(System.getenv("HOME"))))
val stream = new ByteInput(new BufferedInputStream(javaProcess.getInputStream))
val stderr = new ByteInput(new BufferedInputStream(javaProcess.getErrorStream))
?[ProcessInterpreter[T]].interpret(stream, stderr, () => javaProcess.waitFor())
}
override def toString = {
val escaped = params.map(_.flatMap {
case '\'' => "\\'"
case '"' => "\\\""
case '\\' => "\\\\"
case ' ' => "\\ "
case chr => chr.toString
})
s"""sh"${escaped.mkString(" ")}""""
}
}
object Environment {
implicit val defaultEnvironment = new Environment {
def apply(): Map[String, String] = {
import scala.collection.JavaConverters._
mapAsScalaMapConverter(System.getenv()).asScala.toMap
}
def workDir: Option[String] = Option(System.getProperty("user.dir"))
}
}
trait Environment {
def apply(): Map[String, String]
def workDir: Option[String]
}
package environments {
object empty {
def apply(): Environment = implicitEnvironment
implicit val implicitEnvironment: Environment = new Environment {
def apply(): Map[String, String] = Map()
def workDir = None
}
}
object enclosing {
def apply(): Environment = implicitEnvironment
implicit val implicitEnvironment: Environment = Environment.defaultEnvironment
}
}
trait ProcessInterpreter_1 {
implicit def genSeqInterpreter[Coll[_], T](implicit cbf: collection.generic.CanBuildFrom[Nothing, T, Coll[T]],
stringParser: StringParser[T]): ProcessInterpreter[Coll[T]] =
new ProcessInterpreter[Coll[T]] {
def interpret(input: Input[Byte], stderr: Input[Byte], exitStatus: () => Int): Coll[T] = {
val out = input.slurp[Char]
exitStatus() match {
case 0 =>
val builder = cbf()
// FIXME: Reimplement this using a streaming method
out.split("\n").foreach { s =>
builder += stringParser.parse(s, modes.throwExceptions())
}
builder.result()
case n =>
throw ShellProcessException(n, out.trim)
}
}
}
}
object ProcessInterpreter extends ProcessInterpreter_1 {
implicit def stringProcessInterpreter[T](implicit stringParser: StringParser[T]): ProcessInterpreter[T] =
new ProcessInterpreter[T] {
def interpret(input: Input[Byte], stderr: Input[Byte], exitStatus: () => Int): T = {
val out = input.slurp[Char]
val err = stderr.slurp[Char]
exitStatus() match {
case n =>
stringParser.parse(if (out == "" || out.last != '\n') out else out.init, modes.throwExceptions())
//case n => throw ShellProcessException(n, out.trim)
}
}
}
implicit val bytesProcessInterpreter: ProcessInterpreter[Bytes] = new ProcessInterpreter[Bytes] {
def interpret(input: Input[Byte], stderr: Input[Byte], exitStatus: () => Int): Bytes = {
val out = input.slurp[Byte]
exitStatus() match {
case 0 => out
case n => throw ShellProcessException(n, "Binary data")
}
}
}
implicit val byteInputProcessInterpreter: ProcessInterpreter[Input[Byte]] = new ProcessInterpreter[Input[Byte]] {
def interpret(input: Input[Byte], stderr: Input[Byte], exitStatus: () => Int): Input[Byte] = input
}
implicit def inputProcessInterpreter[T](implicit rdr: Reader[Input[Byte], T]): ProcessInterpreter[Input[T]] =
new ProcessInterpreter[Input[T]] {
def interpret(input: Input[Byte], stderr: Input[Byte], exitStatus: () => Int): Input[T] =
input.input[T]
}
implicit val exitStatusProcessInterpreter: ProcessInterpreter[ExitStatus] = new ProcessInterpreter[ExitStatus] {
def interpret(input: Input[Byte], stderr: Input[Byte], exitStatus: () => Int): ExitStatus =
ExitStatus(exitStatus())
}
}
trait ProcessInterpreter[T] {
def interpret(input: Input[Byte], stderr: Input[Byte], exitStatus: () => Int): T
}
case class ShellProcessException(exitStatus: Int, output: String)
extends Exception("Shell process returned non-zero exit status: " + exitStatus)
case class ExitStatus(value: Int)
================================================
FILE: cli/shared/src/main/scala/rapture/cli/tabulate.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.cli
import language.implicitConversions
import language.higherKinds
object Tabulation {
sealed trait Position
case object Right extends Position
case object Left extends Position
trait Col_1 {
implicit def anyToCol(s: Any): Col = Col(s.toString, Left)
}
object Col extends Col_1 {
implicit def intToCol(s: Int): Col = Col(s.toString, Right)
implicit def stringToCol(s: String): Col = Col(s, Left)
}
case class Col(content: String, position: Position = Left)
def tabulate[C[E] <: Seq[E], T](collection: Seq[T], titles: Option[Seq[Col]] = None)(
cols: (T => Col)*): Seq[String] = {
val contents = collection.map { e =>
cols.map(_ (e))
}
val contentsWithTitles = titles.map { ts =>
ts +: ts.map { case Col(s, p) => Col(s.map(c => '-'), p) } +: contents
}.getOrElse(contents)
val widths = contentsWithTitles.map { _.map(_.content.length) }.reduce(_ zip _ map { case (a, b) => a max b })
contentsWithTitles.map(_.zip(widths).map {
case (Col(s, Right), w) => " " * (w - s.length) + s + " "
case (Col(s, Left), w) => s + (" " * (w - s.length)) + " "
}.mkString)
}
}
================================================
FILE: cli/shared/src/main/scala/rapture/cli/zsh.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.cli
import rapture.core._
object Encoder {
private val Translations = "<>#{}|\\^~[]`/?:@=&$!*:; ".to[Vector]
def encode(s: String): String = s flatMap { c =>
if (Translations contains c) {
"%" + (c / 16 + c / 160 * 7 + 48).toChar + (c % 16 + c % 16 / 10 * 7 + 48).toChar
} else c.toString
}
}
object Compadd {
def maxWidths(lists: Vector[Vector[String]]): Vector[Int] =
lists.map(_.map(_.length)).reduce(_ zip _ map (Math.max _).tupled)
def padRows(lists: Vector[Vector[String]]): Vector[String] = {
val widths = maxWidths(lists)
lists.map(_.zip(widths).map { case (s, w) => s.padTo(w, ' ') }.mkString(" "))
}
def apply(groupTitle: Option[String] = None,
completions: Vector[String] = Vector(),
columns: Boolean = true,
descriptions: String => Vector[String] = _ => Vector(),
colWidth: Int = 1000,
hidden: Boolean): Vector[String] = {
val display: Option[Vector[String]] = {
val ds: Vector[Vector[String]] = completions map descriptions
if (ds.forall(_.isEmpty)) None
else Some(padRows(completions zip ds map { case (c, d) => c +: d }))
}
display.toVector.flatten.map(s => "let " + Encoder.encode(s.take(colWidth - 1))) :+ Vector
.strap(
"compadd",
groupTitle.to[Vector].flatMap(Seq("-J", _)),
if (columns) Some("-l") else None,
if (hidden) None else Some("-d matches"),
if (hidden) Some("-n") else None,
"--",
completions.map(Encoder.encode)
)
.mkString(" ")
}
}
================================================
FILE: cli/shared/src/test/scala/rapture/cli/tests.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.cli.test
/*import rapture.core._
import rapture.cli._
import rapture.test._
import scala.util
class TestRun extends Programme {
include(CliTests)
}
object CliTests extends TestSuite {
import New._
implicit object Captured extends SuggestionOutput {
private var suggestions: Seq[Vector[String]] = Seq()
def output(ss: Suggestions) = ss.output.foreach(suggestions = _)
def last() = suggestions
}
val Alpha = Param[String]('a', 'alpha)
val Beta = Param[Int]('b', 'beta)
val Gamma = Param.flag('c', 'gamma)
val Delta = Param[String]('d', 'delta)
val alpha = ParamMap("-a", "alpha")
val alphaIsBeta = ParamMap("-a", "beta")
val alphaIsGamma = ParamMap("-a", "gamma")
val beta = ParamMap("-b", "0")
val gamma = ParamMap("-c")
val delta = ParamMap("-d", "delta")
val empty = ParamMap()
val `Parse short flag` = test {
ParamMap("-a").find("a").map(_.values.map(_()))
} returns Some(Vector())
val `Parse short param with value` = test {
ParamMap("-a", "alpha").find("a").map(_.values.map(_()))
} returns Some(Vector("alpha"))
val `Parse multiple short params` = test {
ParamMap("-abc").find("b").map(_.values.map(_()))
} returns Some(Vector())
val `Parse multiple short params with value` = test {
ParamMap("-abc", "gamma").find("c").map(_.values.map(_()))
} returns Some(Vector("gamma"))
val `Parse long flag` = test {
ParamMap("--alpha").find("alpha").map(_.values.map(_()))
} returns Some(Vector())
val `Parse long param` = test {
ParamMap("--alpha", "value").find("alpha").map(_.values.map(_()))
} returns Some(Vector("value"))
val `Parse long param (multiple args)` = test {
ParamMap("--alpha", "one", "two", "three").find("alpha").map(_.values.map(_()))
} returns Some(Vector("one", "two", "three"))
val `Parse last of multiple long flags` = test {
ParamMap("--alpha", "--beta", "--gamma", "--delta").find("delta").map(_.values.map(_()))
} returns Some(Vector())
val `Parse first of multiple long flags` = test {
ParamMap("--alpha", "--beta", "--gamma", "--delta").find("alpha").map(_.values.map(_()))
} returns Some(Vector())
val `Parse first of multiple long params` = test {
ParamMap("--alpha", "one", "--beta", "--gamma",
"--delta").find("alpha").map(_.values.map(_()))
} returns Some(Vector("one"))
val `Parse last of multiple long params` = test {
ParamMap("--alpha", "one", "--beta", "--gamma", "--delta", "a", "b",
"c").find("delta").map(_.values.map(_()))
} returns Some(Vector("a", "b", "c"))
val `Extract simple param` = test {
Alpha.parse(ParamMap("-a", "alpha"))
} returns "alpha"
val `Extract int` = test {
Beta.parse(ParamMap("-b", "1"))
} returns 1
val `Simple coproduct 1` = test {
val parsed = (Alpha | Beta).parse(alpha)
parsed.handle(
Alpha by identity,
Beta by { b => "beta" }
)
} returns "alpha"
val `Simple coproduct 2` = test {
val parsed = (Alpha | Beta).parse(beta)
parsed.handle(
Alpha by identity,
Beta by { b => "beta" }
)
} returns "beta"
val `Coproduct handler is total 1` = test {
typeMismatch {
val parsed = (Alpha | Beta).parse(beta)
import deferTypeErrors._
parsed.handle(
Alpha by identity
)
}
} returns true
val `Coproduct handler is total 2` = test {
typeMismatch {
val parsed = (Alpha | Beta).parse(beta)
import deferTypeErrors._
parsed.handle(
Beta by { b => "beta" },
Alpha by identity
)
}
} returns false
val `Can't access invalid field` = test {
typeMismatch {
val parsed = (Alpha & Beta).parse(beta)
import deferTypeErrors._
parsed(Gamma)
}
} returns true
//val `Refuse coproduct duplicates` = test {
// import modes.returnOption._
// (Alpha | Beta).parse(alpha ++ beta)
//} returns None
val `Simple product` = test {
val parsed = (Alpha & Beta).parse(alpha ++ beta)
parsed(Alpha) -> parsed(Beta)
} returns ("alpha", 0)
//val `Missing product value fails 1` = test {
// import modes.returnOption._
// (Alpha & Beta).parse(alpha)
//} returns None
//val `Missing product value fails 2` = test {
// import modes.returnOption._
// (Alpha & Beta).parse(beta)
//} returns None
//val `Missing product value fails 3` = test {
// import modes.returnOption._
// (Alpha & Beta).parse(empty)
//} returns None
val `Coproduct and product 1` = test {
val parsed = (Alpha & Beta | Delta).parse(alpha ++ beta)
parsed.handle(
Alpha & Beta by { p => p(Alpha) -> p(Beta) },
Delta by { d => ("delta", -1) }
)
} returns ("alpha", 0)
val `Coproduct and product 2` = test {
val parsed = (Alpha & Beta | Delta).parse(delta)
parsed.handle(
Alpha & Beta by { p => p(Alpha) -> p(Beta) },
Delta by { d => ("delta", -1) }
)
} returns ("delta", -1)
val `Coproduct and product failure 1` = test {
import modes.returnOption._
val parsed = (Alpha & Beta | Delta).parse(alpha)
} returns None
val `Coproduct and product failure 2` = test {
import modes.returnOption._
val parsed = (Alpha & Beta | Delta).parse(beta)
} returns None
//val `Coproduct and product failure 3` = test {
// import modes.returnOption._
// (Alpha & Beta | Delta).parse(alpha ++ delta)
//} returns None
//val `Coproduct and product failure 4` = test {
// import modes.returnOption._
// (Alpha & Beta | Delta).parse(beta ++ delta)
//} returns None
val `Optional value 1` = test {
(~Alpha).parse(alpha)
} returns Some("alpha")
val `Optional value 2` = test {
(~Alpha).parse(empty)
} returns None
val `Optional Product 1` = test {
val parsed = (~Alpha & ~Beta).parse(empty)
(parsed(~Alpha), parsed(~Beta))
} returns (None, None)
val `Optional Product 2` = test {
val parsed = (~Alpha & ~Beta).parse(alpha)
(parsed(~Alpha), parsed(~Beta))
} returns (Some("alpha"), None)
val `Optional Product 3` = test {
val parsed = (~Alpha & ~Beta).parse(beta)
(parsed(~Alpha), parsed(~Beta))
} returns (None, Some(0))
val `Optional Product 4` = test {
val parsed = (~Alpha & ~Beta).parse(beta ++ alpha)
(parsed(~Alpha), parsed(~Beta))
} returns (Some("alpha"), Some(0))
val `Complex extraction successes` = test {
import modes.returnOption._
val pattern = (Alpha & ~Beta | Beta & (Gamma | Delta))
val successes = List(alpha, alpha ++ beta, beta ++ gamma, beta ++ delta)
successes.map(pattern.parse(_)).forall(_.isDefined)
} returns true
val `Complex extraction failures` = test {
import modes.returnOption._
val pattern = (Alpha & ~Beta | Beta & (Gamma | Delta))
val failures = List(beta, gamma, delta, beta ++ gamma ++ delta, alpha ++ gamma, alpha ++
delta)
failures.map(pattern.parse(_)).forall(_ == None)
} returns true
val `Neither or both` = test {
import modes.returnOption._
val pattern = ~(Alpha & Beta)
val successes = List(alpha ++ beta, empty)
val failures = List(alpha, beta, gamma)
successes.map(pattern.parse(_)).forall(_.isDefined) &&
failures.map(pattern.parse(_)).forall(_ == None)
} returns true
val `Check param value` = test {
Alpha.of("alpha").parse(alpha)
} returns "alpha"
val `Check param value 2` = test {
val parsed = (Alpha.of("beta") | Alpha.of("alpha")).parse(alpha)
parsed.handle(
Alpha by identity
)
} returns "alpha"
val `Check param value 3` = test {
import modes.returnOption._
(Alpha.of("beta") | Alpha.of("gamma")).parse(alpha)
} returns None
val `Check param values combined` = test {
import modes.returnOption._
val pattern = Alpha.of("beta") & Beta | Alpha.of("gamma") & Gamma
val successes = List(alphaIsGamma ++ gamma, alphaIsBeta ++ beta)
val failures = List(alpha, beta, gamma, alphaIsGamma ++ beta, alphaIsBeta ++ gamma,
alpha ++ beta, alpha ++ gamma)
successes.map(pattern.parse(_)).forall(_.isDefined) &&
failures.map(pattern.parse(_)).forall(_ == None)
} returns true
val `Check suggestions` = test {
val Color = Param[String]('c', 'color).suggest("red", "green", "blue")
Color.parse(ParamMap("--color", ""), 1)
Captured.last()
} returns Vector(Vector("red"), Vector("green"), Vector("blue"))
}
*/
================================================
FILE: codec/shared/src/main/scala/rapture/codec/base64.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.codec
import rapture.core._
/** RFC2045 base-64 codec, based on http://migbase64.sourceforge.net/. */
class Base64Codec[C <: CodecType](val char62: Char = '+',
val char63: Char = '/',
val padChar: Char = '=',
val lineBreaks: Boolean = false,
val endPadding: Boolean = false)
extends ByteCodec[C] {
private val alphabet =
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + char62 + char63).toCharArray
private lazy val decodabet = {
val x: Array[Int] = alloc(256)
for (i <- 0 until alphabet.length) x(alphabet(i)) = i
x
}
/** Non-RFC-compliant encoder. */
/** Encoder. The RFC requires that line breaks be added every 76 chars, and
* that the data be padded to a multiple of 4 chars, but we do these things
* optionally. */
def encode(in: Array[Byte]): String = {
var inLen = in.length
if (inLen == 0) ""
else {
val evenLen = (inLen / 3) * 3
val outDataLen = if (endPadding) ((inLen - 1) / 3 + 1) << 2 else ((inLen << 2) + 2) / 3
val outLen = if (lineBreaks) outDataLen + (outDataLen - 1) / 76 << 1 else outDataLen
val out: Array[Char] = alloc(outLen)
var inPos = 0
var outPos = 0
var blockCount = 0
while (inPos < evenLen) {
val block = (in(inPos) & 0xFF) << 16 | (in(inPos + 1) & 0xFF) << 8 | (in(inPos + 2) &
0xFF)
inPos += 3
out(outPos) = alphabet((block >>> 18) & 0x3F)
out(outPos + 1) = alphabet((block >>> 12) & 0x3F)
out(outPos + 2) = alphabet((block >>> 6) & 0x3F)
out(outPos + 3) = alphabet(block & 0x3F)
outPos += 4
if (lineBreaks) {
blockCount += 1
if (blockCount == 19 && outPos < outLen - 2) {
out(outPos) = '\r'
out(outPos + 1) = '\n'
outPos += 2
blockCount = 0
}
}
}
val left = inLen - evenLen
if (left > 0) {
val block =
((in(evenLen) & 0xFF) << 10) | (if (left == 2) (in(inLen - 1) & 0xFF) << 2 else 0)
out(outPos) = alphabet(block >>> 12)
out(outPos + 1) = alphabet((block >>> 6) & 0x3F)
if (left == 2) out(outPos + 2) = alphabet(block & 0x3F)
else if (endPadding) out(outPos + 2) = padChar
if (endPadding) out(outPos + 3) = padChar
}
alloc(out)
}
}
/** Decoder. Supports all the variants produced by the encoder above, but
* does not tolerate any other illegal characters, including line breaks at
* positions other than 76-char boundaries, in which case the result will
* be garbage. */
def decode(data: String): Either[Int, Array[Byte]] = {
val in = data.toCharArray()
val inLen = in.length
if (inLen == 0) Right(alloc(0))
else {
val padding = if (in(inLen - 1) == padChar) (if (in(inLen - 2) == padChar) 2 else 1) else 0
// FIXME: This doesn't seem to accommodate different kinds of linebreak
val lineBreaks = if (inLen > 76) (if (in(76) == '\r') inLen / 78 else 0) << 1 else 0
val outLen = ((inLen - lineBreaks) * 6 >> 3) - padding
val out: Array[Byte] = alloc(outLen)
var inPos = 0
var outPos = 0
var blockCount = 0
val evenLen = (outLen / 3) * 3
while (outPos < evenLen) {
val block = decodabet(in(inPos)) << 18 | decodabet(in(inPos + 1)) << 12 |
decodabet(in(inPos + 2)) << 6 | decodabet(in(inPos + 3))
inPos += 4
out(outPos) = (block >> 16).toByte
out(outPos + 1) = (block >> 8).toByte
out(outPos + 2) = block.toByte
outPos += 3
if (lineBreaks > 0) {
blockCount += 1
if (blockCount == 19) {
inPos += 2
blockCount = 0
}
}
}
if (outPos < outLen) {
val block = decodabet(in(inPos)) << 18 | decodabet(in(inPos + 1)) << 12 |
(if (inPos + 2 < inLen - padding) decodabet(in(inPos + 2)) << 6 else 0)
out(outPos) = (block >> 16).toByte
if (outPos + 1 < outLen) out(outPos + 1) = (block >> 8).toByte
}
Right(out)
}
}
}
================================================
FILE: codec/shared/src/main/scala/rapture/codec/bytes.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.codec
import rapture.core._
import scala.collection.generic.CanBuildFrom
import language.higherKinds
object `package` {
implicit def bytesParser(implicit enc: Encoding): StringParser[Bytes] { type Throws = Nothing } =
new StringParser[Bytes] {
type Throws = Nothing // We would like to throw an EncodingException if we try to decode an invalid byte
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Bytes, Nothing] = mode.wrap {
Bytes(s.getBytes("UTF-8"))
}
}
}
trait FromBytes[T] { def build(bytes: Array[Byte]): T }
object FromBytes {
implicit def stringFromBytes(implicit enc: Encoding): FromBytes[String] = new FromBytes[String] {
def build(bytes: Array[Byte]): String = new String(bytes, enc.name)
}
implicit def bytesFromBytes = new FromBytes[Array[Byte]] {
def build(bytes: Array[Byte]): Array[Byte] = bytes
}
}
trait `decode.apply` extends MethodConstraint
case class DecodeException(position: Option[Int]) extends Exception
trait CodecType
trait Hex extends CodecType
trait Base64 extends CodecType
trait Base64Url extends CodecType
trait Base32 extends CodecType
trait Binary extends CodecType
object decode {
def apply[C <: CodecType: ByteCodec](s: String)(
implicit mode: Mode[`decode.apply`]): mode.Wrap[Bytes, DecodeException] =
mode wrap {
try {
implicitly[ByteCodec[C]].decode(s) match {
case Left(pos) => mode.exception(DecodeException(Some(pos)))
case Right(res) => Bytes(res)
}
} catch { case e: Exception => mode.exception(DecodeException(None)) }
}
}
object ByteCodec {
implicit val base64Url: ByteCodec[Base64Url] = new Base64Codec('-', '_', '=', false, false)
implicit val base64: ByteCodec[Base64] = new Base64Codec('+', '/', '=', false, false)
implicit val hex: ByteCodec[Hex] = new ByteCodec[Hex] {
def encode(array: Array[Byte]): String =
alloc(array flatMap { n =>
Array((n & 255) >> 4 & 15, n & 15)
} map { _ + 48 } map { i =>
(if (i > 57) i + 39 else i).toChar
})
def decode(s: String): Either[Int, Array[Byte]] =
Right((if (s.length % 2 == 0) s else "0" + s).to[Array].grouped(2).to[Array] map {
case Array(l, r) =>
(((l - 48) % 39 << 4) + (r - 48) % 39).toByte
})
}
implicit val binary: ByteCodec[Binary] = new ByteCodec[Binary] {
def encode(array: Array[Byte]): String =
alloc(Array.range(0, array.length * 8) map { i =>
if ((array(i / 8) & (1 << (7 - i % 8))) > 0) 49.toByte else 48.toByte
})
def decode(s: String): Either[Int, Array[Byte]] = {
null
}
}
}
trait ByteCodec[Codec <: CodecType] {
def encode(bytes: Array[Byte]): String
def decode(string: String): Either[Int, Array[Byte]]
}
object Bytes {
implicit def arrayBytes(bytes: Array[Byte]): Bytes = Bytes(bytes)
}
case class Bytes(bytes: Array[Byte]) {
def encode[Codec <: CodecType: ByteCodec]: String =
implicitly[ByteCodec[Codec]].encode(bytes)
override def toString = encode[Hex]
def ++(that: Bytes): Bytes = Bytes(bytes ++ that.bytes)
override def equals(that: Any) = that match {
case Bytes(bs) =>
bs.length == bytes.length && (bs zip bytes forall { case (a, b) => a == b })
case _ =>
false
}
override def hashCode = bytes.foldLeft(bytes.length)(_ * 131 + _)
/** Sets all values in the underlying byte array to zeroes. This is useful if the `Bytes`
* instance was storing sensitive data, such as a private key. */
def zero() = bytes.indices foreach { bytes(_) = 0 }
def as[T: FromBytes](implicit mode: Mode[_ <: MethodConstraint]): mode.Wrap[T, DecodeException] = mode.wrap {
try ?[FromBytes[T]].build(bytes)
catch {
case e: Exception => mode.exception[T, DecodeException](DecodeException(None))
}
}
def apply(index: Int): Byte = bytes(index)
def slice(start: Int, end: Int) = Bytes(bytes.slice(start, end))
def length: Int = bytes.length
def to[Coll[_]](implicit cbf: CanBuildFrom[Nothing, Byte, Coll[Byte]]): Coll[Byte] =
bytes.to[Coll]
}
================================================
FILE: codec/shared/src/main/scala/rapture/codec/encodings.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.codec
import rapture.core._
@implicitNotFound(
"Character encoding has not been provided. Please specify an implicit " +
"Encoding value, e.g. import encodings.system._ or import encodings.`UTF-8`._.")
case class Encoding(name: String) { def index = name }
case class EncodingImplicit(name: String) {
implicit val implicitEncoding: Encoding = Encoding(name)
def apply() = implicitEncoding
}
/** Provides references to standard character encodings provided by Java. Encodings are
* represented by instances of the Encoding case class, which is a simple wrapper over a String
* of the encoding's name. Several standard encodings are provided and identified by the
* encoding's canonical name for the avoidance of ambiguity. These instances will typically
* require escaping with backticks in order to be referenced, however type safety will be
* ensured. */
object encodings {
implicit val `US-ASCII` = EncodingImplicit("US-ASCII")
implicit val `windows-1250` = EncodingImplicit("windows-1250")
implicit val `windows-1251` = EncodingImplicit("windows-1251")
implicit val `windows-1252` = EncodingImplicit("windows-1252")
implicit val `windows-1253` = EncodingImplicit("windows-1253")
implicit val `windows-1254` = EncodingImplicit("windows-1254")
implicit val `windows-1257` = EncodingImplicit("windows-1257")
implicit val `ISO-8859-1` = EncodingImplicit("ISO-8859-1")
implicit val `ISO-8859-2` = EncodingImplicit("ISO-8859-2")
implicit val `ISO-8859-4` = EncodingImplicit("ISO-8859-4")
implicit val `ISO-8859-5` = EncodingImplicit("ISO-8859-5")
implicit val `ISO-8859-7` = EncodingImplicit("ISO-8859-7")
implicit val `ISO-8859-9` = EncodingImplicit("ISO-8859-9")
implicit val `ISO-8859-13` = EncodingImplicit("ISO-8859-13")
implicit val `ISO-8859-15` = EncodingImplicit("ISO-8859-15")
implicit val `KOI8-R` = EncodingImplicit("KOI8-R")
implicit val `UTF-8` = EncodingImplicit("UTF-8")
implicit val `UTF-16` = EncodingImplicit("UTF-16")
implicit val `UTF-16BE` = EncodingImplicit("UTF-16BE")
implicit val `UTF-16LE` = EncodingImplicit("UTF-16LE")
/** The default file system encoding for this system */
implicit lazy val system = EncodingImplicit(System.getProperty("file.encoding"))
private val allEncodings: Map[String, Encoding] = Map(
("US-ASCII", `US-ASCII`()),
("windows-1250", `windows-1250`()),
("windows-1251", `windows-1251`()),
("windows-1252", `windows-1252`()),
("windows-1253", `windows-1253`()),
("windows-1254", `windows-1254`()),
("windows-1257", `windows-1257`()),
("ISO-8859-1", `ISO-8859-1`()),
("ISO-8859-2", `ISO-8859-2`()),
("ISO-8859-4", `ISO-8859-4`()),
("ISO-8859-5", `ISO-8859-5`()),
("ISO-8859-7", `ISO-8859-7`()),
("ISO-8859-9", `ISO-8859-9`()),
("ISO-8859-13", `ISO-8859-13`()),
("ISO-8859-15", `ISO-8859-15`()),
("KOI8-R", `KOI8-R`()),
("UTF-8", `UTF-8`()),
("UTF-16", `UTF-16`()),
("UTF-16BE", `UTF-16BE`()),
("UTF-16LE", `UTF-16LE`())
)
def lookup(enc: String): Encoding = allEncodings(enc)
}
================================================
FILE: core/shared/src/main/scala/rapture/core/actor.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
import scala.concurrent._
import scala.util._
sealed trait ActorResponse[+T, +S]
case class Reply[+T](reply: T) extends ActorResponse[T, Nothing] {
def andUpdate[S](state: S) = Update[T, S](reply, state)
}
case class Update[+T, +S](reply: T, state: S) extends ActorResponse[T, S]
case object Ignore extends ActorResponse[Nothing, Nothing]
object Actor {
class ActorOf[Msg] {
def apply[Res, State](init: State)(fn: Transition[Msg, State] => ActorResponse[Res, State])(
implicit ec: ExecutionContext): Actor[Msg, Res, State] =
new Actor[Msg, Res, State](init) {
def handle(trans: Transition[Msg, State]): ActorResponse[Res, State] = fn(trans)
}
}
def of[Msg] = new ActorOf[Msg]
}
case class IgnoredException() extends Exception("Message was ignored")
abstract class Actor[Msg, Res, State](init: State)(implicit executionContext: ExecutionContext) {
private var future: Future[Res] = Future.successful(null.asInstanceOf[Res])
private var stateVar: State = init
protected def enqueue(fn: => ActorResponse[Res, State]): Future[Res] = future.synchronized {
val promise = Promise[Res]
future = future.andThen {
case _ =>
val result = Try(fn) match {
case Success(Ignore) =>
promise.failure(IgnoredException())
case Success(Update(r, s)) =>
promise.success(r)
stateVar = s
case Success(Reply(r)) =>
promise.success(r)
case Failure(err) =>
promise.failure(err)
}
}
promise.future
}
def state: State = stateVar
def cue(msg: Msg): Future[Res] = enqueue { handle(Transition(msg, stateVar)) }
def handle(trans: Transition[Msg, State]): ActorResponse[Res, State]
}
case class Transition[Msg, State](msg: Msg, state: State)
================================================
FILE: core/shared/src/main/scala/rapture/core/alloc.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
import language.experimental.macros
import scala.reflect._
import annotation.unchecked._
class AllocApply[T](val unit: Int) extends AnyVal {
def apply()(implicit inst: Alloc0.Invariant[T]): T = inst.instantiate()
def apply[P1](p1: P1)(implicit inst: Alloc1.Invariant[T, P1]): T = inst.instantiate(p1)
def apply[P1, P2](p1: P1, p2: P2)(implicit inst: Alloc2.Invariant[T, P1, P2]): T = inst.instantiate(p1, p2)
def apply[P1, P2, P3](p1: P1, p2: P2, p3: P3)(implicit inst: Alloc3.Invariant[T, P1, P2, P3]): T =
inst.instantiate(p1, p2, p3)
def apply[P1, P2, P3, P4](p1: P1, p2: P2, p3: P3, p4: P4)(implicit inst: Alloc4.Invariant[T, P1, P2, P3, P4]): T =
inst.instantiate(p1, p2, p3, p4)
}
object Alloc0 {
implicit def alloc0[T]: Alloc0[T] = macro CoreMacros.allocMacro[T]
type Invariant[+T] = Alloc0[T @uncheckedVariance]
}
object Alloc1 {
implicit def alloc1[T, P1]: Alloc1[T, P1] = macro CoreMacros.allocMacro1[T, P1]
type Invariant[+T, P1] = Alloc1[T @uncheckedVariance, P1]
}
object Alloc2 {
implicit def alloc2[T, P1, P2]: Alloc2[T, P1, P2] = macro CoreMacros.allocMacro2[T, P1, P2]
type Invariant[+T, P1, P2] = Alloc2[T @uncheckedVariance, P1, P2]
}
object Alloc3 {
implicit def alloc3[T, P1, P2, P3]: Alloc3[T, P1, P2, P3] = macro CoreMacros.allocMacro3[T, P1, P2, P3]
type Invariant[+T, P1, P2, P3] = Alloc3[T @uncheckedVariance, P1, P2, P3]
}
object Alloc4 {
implicit def alloc4[T, P1, P2, P3, P4]: Alloc4[T, P1, P2, P3, P4] = macro CoreMacros.allocMacro4[T, P1, P2, P3, P4]
type Invariant[+T, P1, P2, P3, P4] = Alloc4[T @uncheckedVariance, P1, P2, P3, P4]
}
@implicitNotFound("No constructor exists for instantiating an object of this type")
trait Alloc0[T] { def instantiate(): T }
@implicitNotFound("No constructor exists for instantiating an object of this type")
trait Alloc1[T, P1] { def instantiate(p1: P1): T }
@implicitNotFound("No constructor exists for instantiating an object of this type")
trait Alloc2[T, P1, P2] { def instantiate(p1: P1, p2: P2): T }
@implicitNotFound("No constructor exists for instantiating an object of this type")
trait Alloc3[T, P1, P2, P3] { def instantiate(p1: P1, p2: P2, p3: P3): T }
@implicitNotFound("No constructor exists for instantiating an object of this type")
trait Alloc4[T, P1, P2, P3, P4] { def instantiate(p1: P1, p2: P2, p3: P3, p4: P4): T }
================================================
FILE: core/shared/src/main/scala/rapture/core/app.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
object Main extends App {
Console.println("Running this JAR file does nothing. To use it, please include it on your classpath.")
}
================================================
FILE: core/shared/src/main/scala/rapture/core/core.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
import language.experimental.macros
import language.higherKinds
object AssignedName {
implicit def assignedNameImplicit: AssignedName = macro CoreMacros.assignedNameMacro
}
case class AssignedName(name: String) extends AnyVal {
override def toString = s"`$name`"
}
object MethodName {
implicit def assignedMethodNameImplicit: MethodName = macro CoreMacros.assignedMethodNameMacro
}
class MethodName(val name: String) extends AnyVal
trait Cell[T] {
def apply(): T
def update(t: T): Unit
}
object Cell {
def apply[T](get: => T)(set: T => Unit): Cell[T] = new Cell[T] {
def apply() = get
def update(t: T) = set(t)
}
}
object Var {
def apply[T](t: T) = new Cell[T] {
private var value = t
def apply(): T = value
def update(t: T) = value = t
}
}
object OptionalParameter {
implicit def autoWrapSpecifiedParameter[T](value: T): OptionalParameter[T] = SpecifiedParameter[T](value)
}
sealed trait OptionalParameter[+T] { def apply(): Option[T] }
object SeqParameter {
implicit def listToSeqParameter[T](seq: Seq[T]): SeqParameter[T] =
SeqParameter(seq: _*)
implicit def optionToSeqParameter[T](opt: Option[T]): SeqParameter[T] =
SeqParameter(opt.to[Seq]: _*)
implicit def anyToSeqParameter[T](value: T): SeqParameter[T] = SeqParameter(value)
}
case class SeqParameter[T](elements: T*)
case class SpecifiedParameter[+T] (value: T) extends OptionalParameter[T] {
def apply(): Option[T] = Some(value)
}
case object UnspecifiedParameter extends OptionalParameter[Nothing] {
def apply(): Option[Nothing] = None
}
object Annex {
implicit def annexValueWithTypeclass[V, Tc[_]](v: V)(implicit tc: Tc[V]): Annex[Tc] =
new Annex[Tc] {
type Value = V
def value: Value = v
def typeclass: Tc[Value] = tc
}
}
abstract class Annex[Typeclass[_]] {
type Value
def value: Value
def typeclass: Typeclass[Value]
def apply[Return](fn: Typeclass[Value] => Value => Return): Return = fn(typeclass)(value)
}
================================================
FILE: core/shared/src/main/scala/rapture/core/default.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
private[core] trait DefaultsTo_1 {
implicit def fallbackDefaultsTo[T, S]: DefaultsTo[T, S] = null.asInstanceOf[DefaultsTo[T, S]]
}
object DefaultsTo extends DefaultsTo_1 {
implicit def defaultDefaultsTo[T]: DefaultsTo[T, T] = null.asInstanceOf[DefaultsTo[T, T]]
}
trait DefaultsTo[T, S]
================================================
FILE: core/shared/src/main/scala/rapture/core/functor.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
import scala.reflect.ClassTag
import language.higherKinds
trait Functor[+F[x] <: Functor[F, x], A] { functor =>
type Throws <: Exception
protected def rawMap[B](fn: (A, Mode[_ <: MethodConstraint]) => B): F[B]
def map[B](fn: A => B): F[B] { type Throws = functor.Throws with Exception } =
emap[Exception](fn)
def emap[E <: Exception]: Emap[E] = new Emap[E]()
def smap[B](fn: A => B): F[B] { type Throws = functor.Throws } =
emap[Nothing](fn).asInstanceOf[F[B] { type Throws = functor.Throws }]
// FIXME: Make this a value class
class Emap[E <: Exception]() {
def apply[B](fn: A => B)(implicit tt: ClassTag[E]): F[B] { type Throws = functor.Throws with E } =
functor.rawMap {
case (a, m) =>
try fn(a)
catch { case e: Exception => m.exception[B, E](e.asInstanceOf[E]) }
}.asInstanceOf[F[B] { type Throws = functor.Throws with E }]
}
}
================================================
FILE: core/shared/src/main/scala/rapture/core/macros.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
import rapture.base._
import scala.reflect._
private[core] object CoreMacros {
def enumerateMacro[Cls: c.WeakTypeTag, T: c.WeakTypeTag](c: BlackboxContext)(value: c.Expr[Cls]): c.Expr[List[T]] = {
import c.universe._
import compatibility._
val cls = weakTypeOf[Cls]
val allMethods = weakTypeOf[Cls].members.to[List].filter(_.isMethod).map(_.asMethod)
val matchingMethods = allMethods filter { m =>
paramLists(c)(m).isEmpty && m.returnType.weak_<:<(weakTypeOf[T])
}
val methodNames = matchingMethods map { m =>
Select(value.tree, termName(c, m.name.toString))
}
val listApply = Select(reify(List).tree, termName(c, "apply"))
c.Expr[List[T]](Apply(listApply, methodNames))
}
def assignedMethodNameMacro(c: BlackboxContext): c.Expr[MethodName] = {
import c.universe._
import compatibility._
val name = enclosingDef(c)(c.macroApplication.pos).map { name =>
c.Expr[MethodName](q"new _root_.rapture.core.MethodName(${name.decodedName.toString.trim})")
}
name getOrElse c.abort(c.enclosingPosition, "this method invocation must be assigned to a named identifier.")
}
object AssignedNameMacroState {
var lastPoint: Option[api.Position] = None
var assignmentCount: Int = 0
}
def assignedNameMacro(c: BlackboxContext): c.Expr[AssignedName] = {
import c.universe._
import AssignedNameMacroState._
import compatibility._
val currentPoint = c.macroApplication.pos
if(Some(currentPoint) != lastPoint) assignmentCount = 0
val name = enclosingVals(c)(currentPoint, assignmentCount).map { name =>
c.Expr[AssignedName](q"_root_.rapture.core.AssignedName(${name.decodedName.toString.trim})")
}
lastPoint = Some(currentPoint)
assignmentCount += 1
name getOrElse c.abort(c.enclosingPosition, "this method invocation must be assigned to a named identifier.")
}
def allocMacro[T: c.WeakTypeTag](c: BlackboxContext): c.Expr[Alloc0[T]] = {
import c.universe._
import compatibility._
val construction = c.Expr[T](Apply(Select(New(TypeTree(weakTypeOf[T])), constructor(c)), List()))
reify { new Alloc0[T] { def instantiate(): T = construction.splice } }
}
def allocMacro1[T: c.WeakTypeTag, P1: c.WeakTypeTag](c: BlackboxContext): c.Expr[Alloc1[T, P1]] = {
import c.universe._
import compatibility._
val construction =
c.Expr[T](Apply(Select(New(TypeTree(weakTypeOf[T])), constructor(c)), List(Ident(termName(c, "p1")))))
reify { new Alloc1[T, P1] { def instantiate(p1: P1): T = construction.splice } }
}
def allocMacro2[T: c.WeakTypeTag, P1: c.WeakTypeTag, P2: c.WeakTypeTag](
c: BlackboxContext): c.Expr[Alloc2[T, P1, P2]] = {
import c.universe._
import compatibility._
val construction = c.Expr[T](
Apply(Select(New(TypeTree(weakTypeOf[T])), constructor(c)),
List(Ident(termName(c, "p1")), Ident(termName(c, "p2")))))
reify { new Alloc2[T, P1, P2] { def instantiate(p1: P1, p2: P2): T = construction.splice } }
}
def allocMacro3[T: c.WeakTypeTag, P1: c.WeakTypeTag, P2: c.WeakTypeTag, P3: c.WeakTypeTag](
c: WhiteboxContext): c.Expr[Alloc3[T, P1, P2, P3]] = {
import c.universe._
import compatibility._
val construction = c.Expr[T](
Apply(Select(New(TypeTree(weakTypeOf[T])), constructor(c)),
List(Ident(termName(c, "p1")), Ident(termName(c, "p2")), Ident(termName(c, "p3")))))
reify { new Alloc3[T, P1, P2, P3] { def instantiate(p1: P1, p2: P2, p3: P3): T = construction.splice } }
}
def allocMacro4[T: c.WeakTypeTag, P1: c.WeakTypeTag, P2: c.WeakTypeTag, P3: c.WeakTypeTag, P4: c.WeakTypeTag](
c: WhiteboxContext): c.Expr[Alloc4[T, P1, P2, P3, P4]] = {
import c.universe._
import compatibility._
val construction = c.Expr[T](
Apply(Select(New(TypeTree(weakTypeOf[T])), constructor(c)),
List(Ident(termName(c, "p1")),
Ident(termName(c, "p2")),
Ident(termName(c, "p3")),
Ident(termName(c, "p4")))))
reify {
new Alloc4[T, P1, P2, P3, P4] { def instantiate(p1: P1, p2: P2, p3: P3, p4: P4): T = construction.splice }
}
}
}
================================================
FILE: core/shared/src/main/scala/rapture/core/med.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
object MinimumEditDistance {
def difference(a: String, b: String): Int = {
var d = Vector.fill(a.length + 1)(Vector.fill(b.length + 1)(0))
(0 to b.length).foreach { j =>
(0 to a.length).foreach { i =>
if (i == 0 || j == 0) d = d.updated(i, d(i).updated(j, i + j))
else if (a(i - 1) == b(j - 1)) d = d.updated(i, d(i).updated(j, d(i - 1)(j - 1)))
else d = d.updated(i, d(i).updated(j, List(d(i - 1)(j), d(i)(j - 1), d(i - 1)(j - 1)).min + 1))
}
}
d(a.length)(b.length)
}
def filterStrings(words: Array[String], word: String, limit: Int): List[String] = {
val arr = new Array[Int](256)
val results = new collection.mutable.ListBuffer[String]
for (i <- 0 to 15) {
arr(i) = i
arr(16 * i) = i
}
def difference(d: Array[Int], a: String): Int = {
val amax = math.min(a.length, 15)
val t = amax + word.length
var i, j, n = 0
var min = Int.MaxValue
var cont = true
while (n <= t && cont) {
val r =
if (i == 0 || j == 0) i + j
else if (a(i - 1) == word(j - 1)) d(16 * (i - 1) + j - 1)
else math.min(math.min(d(16 * (i - 1) + j), d(16 * i + j - 1)), d(16 * (i - 1) + j - 1)) + 1
min = math.min(min, r)
d(16 * i + j) = r
if (j == 0 || i == amax) {
n += 1
if (n <= word.length) { j = n; i = 0 } else { i = n - word.length; j = word.length }
if (min > limit) cont = false
min = Int.MaxValue
} else {
i += 1
j -= 1
}
}
if (cont) d(16 * amax + word.length) else Int.MaxValue
}
val len = word.length
words.filter { w =>
difference(arr, w.take(len)) <= limit
}.to[List]
}
}
================================================
FILE: core/shared/src/main/scala/rapture/core/modes.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
import language.{existentials, higherKinds}
import scala.reflect._
import scala.util._
import scala.concurrent._
trait MethodConstraint
object Mode extends Mode_1 {
abstract class Import[M[G <: MethodConstraint] <: Mode[G]] {
def apply[G <: MethodConstraint](): M[G] = modeImplicit[G]
implicit def modeImplicit[G <: MethodConstraint]: M[G] = mode[G]
protected def mode[G <: MethodConstraint]: M[G]
}
}
@implicitNotFound(
msg = "No implicit mode was available for $"+"{Group} methods. " +
"Please import a member of rapture.core.modes, e.g. modes.throwExceptions.")
trait Mode[+Group <: MethodConstraint] { mode =>
type Wrap[+_, _ <: Exception]
def wrap[Res, E <: Exception](blk: => Res): Wrap[Res, E]
def flatWrap[Res, E <: Exception: ClassTag](blk: => Wrap[Res, E]): Wrap[Res, E] =
wrap(unwrap(blk))
var callPath = "_"
def unwrap[Res](value: => Wrap[Res, _ <: Exception]): Res
def unwrap[Res](value: => Wrap[Res, _ <: Exception], path: String): Res = {
val oldCallPath = callPath
callPath += path
val res = unwrap[Res](value)
callPath = oldCallPath
res
}
def generic[C <: MethodConstraint]: Mode[C] { type Wrap[+T, E <: Exception] = mode.Wrap[T, E] } =
this.asInstanceOf[Mode[C] { type Wrap[+T, E <: Exception] = mode.Wrap[T, E] }]
def compose[Group2 <: MethodConstraint](mode2: Mode[Group2]) = new Mode[Group] {
type Wrap[+Res, E <: Exception] = mode.Wrap[mode2.Wrap[Res, E], E]
def wrap[Res, E <: Exception](blk: => Res): Wrap[Res, E] =
mode.wrap(mode2.wrap(blk))
def unwrap[Return](value: => Wrap[Return, _ <: Exception]): Return =
mode2.unwrap(mode.unwrap(value))
}
def catching[E <: Exception: ClassTag, T](blk: => T) =
try blk
catch {
case e: E => exception(e)
case e: Exception => throw e
}
def safe[T](blk: => T): T = {
try blk
catch { case e: Exception => exception(e) }
}
def exception[T, E <: Exception: ClassTag](e: E, continue: Boolean = true): T = throw e
def wrapEither[Res, E <: Exception: ClassTag](blk: => Either[E, Res]): Wrap[Res, E] =
wrap {
blk match {
case Left(e) => throw e
case Right(r) => r
}
}
def wrapOption[Res](blk: => Option[Res]): Wrap[Res, Exception] = wrap(blk.get)
def wrapTry[Res, E <: Exception: ClassTag](blk: => Try[Res]): Wrap[Res, E] =
wrap(blk.get)
}
object repl {
var showStackTraces: Boolean = false
private var lastExceptionValue: Throwable = new SilentException
def lastException: Nothing = throw lastExceptionValue
implicit def modeImplicit[Group <: MethodConstraint] = new Repl[Group]
class SilentException extends Throwable {
override def printStackTrace(pw: java.io.PrintWriter) = ()
}
class Repl[+Group <: MethodConstraint] extends Mode[Group] {
type Wrap[+Return, E <: Exception] = T2 forSome { type T2 <: Return }
def wrap[Return, E <: Exception](blk: => Return): Return =
try blk
catch {
case e: Exception =>
if (showStackTraces) throw e
else {
Console.println("Execution failed with exception: " + e.toString)
Console.print("For the full stacktrace, see repl.lastException.")
lastExceptionValue = e
throw new SilentException()
}
}
def unwrap[Return](value: => Wrap[Return, _ <: Exception]): Return = value
}
}
package modes {
object throwExceptions extends Mode.Import[ThrowExceptionsMode] {
protected def mode[G <: MethodConstraint] = new ThrowExceptionsMode[G]
}
object explicit extends Mode.Import[ExplicitMode] {
protected def mode[G <: MethodConstraint] = new ExplicitMode[G]
}
/*object returnEither extends Mode.Import[ReturnEitherMode] {
protected def mode[G <: MethodConstraint] = new ReturnEitherMode[G]
}*/
object returnResult extends Mode.Import[ReturnResultMode] {
protected def mode[G <: MethodConstraint] = new ReturnResultMode[G]
}
object returnTry extends Mode.Import[ReturnTryMode] {
protected def mode[G <: MethodConstraint] = new ReturnTryMode[G]
}
object exponentialBackoff extends Mode.Import[ExponentialBackoffMode] {
protected def mode[G <: MethodConstraint] = new ExponentialBackoffMode[G]()
}
object keepCalmAndCarryOn extends Mode.Import[KeepCalmAndCarryOnMode] {
protected def mode[G <: MethodConstraint] = new KeepCalmAndCarryOnMode[G]()
}
object returnOption extends Mode.Import[ReturnOptionMode] {
protected def mode[G <: MethodConstraint] = new ReturnOptionMode[G]()
}
object returnFuture {
implicit def modeImplicit[G <: MethodConstraint](implicit ec: ExecutionContext) =
new ReturnFutureMode[G]
def apply[G <: MethodConstraint](implicit ec: ExecutionContext) = modeImplicit[G]
}
object timeExecution {
implicit def modeImplicit[D: TimeSystem.ByDuration, G <: MethodConstraint] =
new TimeExecution[D, G]
def apply[D: TimeSystem.ByDuration, G <: MethodConstraint] = modeImplicit[D, G]
}
class Explicitly[+Res, E <: Exception](blk: => Res) {
def get: Res = blk
def opt: Option[Res] = returnOption[Nothing].wrap(blk)
def getOrElse[Res2 >: Res](t: Res2): Res2 = opt.getOrElse(blk)
//def either: Either[E, Res] = returnEither[Nothing].wrap(blk)
def attempt: Try[Res] = returnTry[Nothing].wrap(blk)
def backoff(maxRetries: Int = 10, initialPause: Long = 1000L, backoffRate: Double = 2.0): Res =
new ExponentialBackoffMode(maxRetries, initialPause, backoffRate).wrap(blk)
def time[D: TimeSystem.ByDuration] = timeExecution[D, Nothing].wrap(blk)
def future(implicit ec: ExecutionContext): Future[Res] = returnFuture[Nothing].wrap(blk)
override def toString = ""
}
}
private[core] trait Mode_1 {
implicit def defaultMode: ThrowExceptionsMode[Nothing] = new ThrowExceptionsMode
}
private[core] class ThrowExceptionsMode[+G <: MethodConstraint] extends Mode[G] {
type Wrap[+T, E <: Exception] = T2 forSome { type T2 <: T }
def wrap[T, E <: Exception](t: => T): T = t
def unwrap[Return](value: => Wrap[Return, _ <: Exception]): Return = value
}
private[core] class ExplicitMode[+G <: MethodConstraint] extends Mode[G] {
type Wrap[+T, E <: Exception] = modes.Explicitly[T, E]
def wrap[T, E <: Exception](t: => T): modes.Explicitly[T, E] =
new modes.Explicitly[T, E](t)
def unwrap[Return](value: => Wrap[Return, _ <: Exception]): Return = value.get
}
private[core] class ReturnTryMode[+G <: MethodConstraint] extends Mode[G] {
type Wrap[+T, E <: Exception] = Try[T]
def wrap[T, E <: Exception](t: => T): Try[T] = Try(t)
def unwrap[Return](value: => Wrap[Return, _ <: Exception]): Return = value.get
override def toString = "[modes.returnTry]"
}
private[core] class ExponentialBackoffMode[+G <: MethodConstraint](maxRetries: Int = 10,
initialPause: Long = 1000L,
backoffRate: Double = 2.0)
extends Mode[G] {
type Wrap[+T, E <: Exception] = T2 forSome { type T2 <: T }
def wrap[T, E <: Exception](t: => T): T = {
var multiplier = 1.0
var count = 1
var result: T = null.asInstanceOf[T]
var exception: Exception = null.asInstanceOf[Exception]
while (result == null && count < maxRetries) try { result = t } catch {
case e: Exception =>
exception = e
import timeSystems.numeric._
Thread.sleep((multiplier * initialPause).toLong)
multiplier *= backoffRate
count += 1
}
if (result != null) result else throw exception
}
def unwrap[Return](value: => Wrap[Return, _ <: Exception]): Return = value
}
private[core] class KeepCalmAndCarryOnMode[+G <: MethodConstraint] extends Mode[G] {
type Wrap[+T, E <: Exception] = T2 forSome { type T2 <: T }
def wrap[T, E <: Exception](t: => T): T =
try t
catch { case e: Exception => null.asInstanceOf[T] }
def unwrap[Return](value: => Wrap[Return, _ <: Exception]): Return = Option[Return](value).get
override def toString = "[modes.kcaco]"
}
private[core] class ReturnOptionMode[+G <: MethodConstraint] extends Mode[G] {
type Wrap[+T, E <: Exception] = Option[T]
def wrap[T, E <: Exception](t: => T): Option[T] =
try Some(t)
catch { case e: Exception => None }
def unwrap[Return](value: => Wrap[Return, _ <: Exception]): Return = value.get
override def toString = "[modes.returnOption]"
}
private[core] class ReturnFutureMode[+G <: MethodConstraint](implicit ec: ExecutionContext) extends Mode[G] {
type Wrap[+T, E <: Exception] = Future[T]
def wrap[T, E <: Exception](t: => T): Future[T] = Future { t }
def unwrap[Return](value: => Wrap[Return, _ <: Exception]): Return =
Await.result(value, duration.Duration.Inf)
override def flatWrap[Res, E <: Exception: ClassTag](blk: => Wrap[Res, E]): Wrap[Res, E] = blk
override def toString = "[modes.returnFuture]"
}
private[core] class TimeExecution[D: TimeSystem.ByDuration, +G <: MethodConstraint] extends Mode[G] {
val ts = ?[TimeSystem.ByDuration[D]]
type Wrap[+T, E <: Exception] = (T, D)
def wrap[T, E <: Exception](r: => T): (T, D) = {
val t0 = System.currentTimeMillis
(r, ts.duration(t0, System.currentTimeMillis))
}
def unwrap[Return](value: => Wrap[Return, _ <: Exception]): Return = value._1
override def toString = "[modes.timeExecution]"
}
================================================
FILE: core/shared/src/main/scala/rapture/core/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
import language.higherKinds
import language.experimental.macros
import reflect.runtime.universe._
import reflect.ClassTag
object `package` {
type CanBuildFrom[-From, -Elem, +To] = collection.generic.CanBuildFrom[From, Elem, To]
def alloc[T] = new AllocApply[T](0)
def each[E <: Exception] = EachUnapplied[E]()
implicit class EnrichedString(val string: String) extends AnyVal {
def as[T](implicit parser: StringParser[T], mode: Mode[`String#as`]): mode.Wrap[T, parser.Throws] =
parser.parse(string, mode)
}
def indentTree(s: String): String = {
var indent = 0
s flatMap {
case '(' => indent += 1; s"(\n${" " * indent}"
case ')' => indent -= 1; s"\n${" " * indent})"
case ',' => s",\n${" " * (indent - 1)}"
case ' ' => ""
case o => o.toString
}
}
implicit class EnrichedCollection[Coll[X] <: Seq[X]](val coll: Coll[String]) extends AnyVal {
def mapAs[T](implicit parser: StringParser[T],
cbf: CanBuildFrom[Coll[String], T, Coll[T]],
mode: Mode[`Seq#mapAs`]): mode.Wrap[Coll[T], parser.Throws] = mode.wrap[Coll[T], parser.Throws] {
val b = cbf(coll)
coll foreach { x =>
b += mode.unwrap(parser.parse(x, mode))
}
b.result
}
}
private[rapture] type implicitNotFound = annotation.implicitNotFound
private[rapture] implicit val implicitConversions: languageFeature.implicitConversions = language.implicitConversions
@inline
final def ?[T](implicit t: T) = t
def modally[G <: MethodConstraint, E <: Exception] = new Modal[G, E]
def yCombinator[A, B](fn: (A => B) => (A => B)): A => B = fn(yCombinator(fn))(_)
/** Times how long it takes to perform an operation, returning a pair of the result and the
* duration of the operation in milliseconds. */
def time[T, D: TimeSystem.ByDuration](blk: => T): (T, D) = {
val t = System.currentTimeMillis
(blk, ?[TimeSystem.ByDuration[D]].duration(t, System.currentTimeMillis))
}
def enumerateMembers[T] = new Enumerator[T]
@inline
implicit class SeqExtras[A, C[A] <: Seq[A]](val xs: C[A]) {
/** Inserts an element between each of the elements of the sequence. */
def intersperse[B >: A, That](between: B)(implicit bf: CanBuildFrom[C[A], B, That]): That = {
val b = bf(xs)
xs.init foreach { x =>
b += x
b += between
}
b += xs.last
b.result
}
/** Inserts an element between each of the elements of the sequence, and additionally
* prepends and affixes the sequence with `before` and `after`. */
def intersperse[B >: A, That](before: B, between: B, after: B)(implicit bf: CanBuildFrom[C[A], B, That]): That = {
val b = bf(xs)
b += before
xs.init foreach { x =>
b += x
b += between
}
b += xs.last
b += after
b.result
}
/** Convenience method for zipping a sequence with a value derived from each element. */
def zipWith[T](fn: A => T)(implicit bf: CanBuildFrom[C[A], (A, T), C[(A, T)]]): C[(A, T)] = {
val b = bf(xs)
xs.foreach { x =>
b += ((x, fn(x)))
}
b.result
}
}
implicit class EnrichedCollectionCompanion[+C[X] <: collection.GenTraversable[X]](
val cc: collection.generic.GenericCompanion[C])
extends AnyVal {
def strap[T](xs: Strapped[T]*): C[T] = {
val b = cc.newBuilder[T]
xs foreach { b ++= _.elems }
b.result()
}
}
implicit class EnrichedArrayCompanion(val arr: Array.type) extends AnyVal {
def strap[T: ClassTag](xs: Strapped[T]*): Array[T] = {
val b = Array.newBuilder[T]
xs foreach { b ++= _.elems }
b.result()
}
}
implicit class EitherExtras[L, R](either: Either[L, R]) {
def bimap[T](leftFn: L => T, rightFn: R => T) = either match {
case Left(left) => leftFn(left)
case Right(right) => rightFn(right)
}
}
}
trait `Seq#mapAs` extends MethodConstraint
trait `String#as` extends MethodConstraint
private[core] object Strapped {
implicit def basicStrapping[T](t: T): Strapped[T] = Strapped(List(t))
implicit def iterableStrapping[T](elems: Iterable[T]): Strapped[T] = Strapped(elems)
implicit def optionStrapping[T](opt: Option[T]): Strapped[T] = Strapped(opt.toList)
}
private[core] case class Strapped[+T](elems: Iterable[T]) extends AnyVal
private[core] class Enumerator[T] {
def apply[Cls](value: Cls): List[T] = macro CoreMacros.enumerateMacro[Cls, T]
}
private[core] class Modal[G <: MethodConstraint, E <: Exception] {
def apply[T](fn: => T)(implicit mode: Mode[G], typeTag: TypeTag[E]): mode.Wrap[T, E] = mode.wrap(fn)
}
================================================
FILE: core/shared/src/main/scala/rapture/core/parser.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
import scala.util.Try
object ParseException
case class ParseException(bad: String, typ: String) extends Exception(s"could not parse '$bad' as $typ")
package booleanParsing {
object strict {
def apply() = implicitBooleanParsing
implicit def implicitBooleanParsing(implicit br: BooleanRepresentation): BooleanParser =
new BooleanParser {
def parse(s: String, mode: Mode[_]): mode.Wrap[Boolean, InvalidBoolean] = mode.wrap {
if (s == br.trueValue) true
else if (s == br.falseValue) false
else mode.exception(InvalidBoolean(s))
}
}
}
object permissive {
def apply(): BooleanParser = implicitBooleanParsing
private val trueValues = List("true", "yes", "on", "1")
private val falseValues = List("false", "no", "off", "0")
implicit val implicitBooleanParsing: BooleanParser = new BooleanParser {
def parse(b: String, mode: Mode[_]): mode.Wrap[Boolean, InvalidBoolean] = mode.wrap {
if (trueValues.contains(b.toLowerCase)) true
else if (falseValues.contains(b.toLowerCase)) false
else mode.exception(ParseException(b, "boolean using permissive parser"))
}
}
}
}
object BooleanParser { implicit val implicitBooleanParser: BooleanParser = booleanParsing.permissive() }
trait BooleanParser { def parse(s: String, mode: Mode[_]): mode.Wrap[Boolean, InvalidBoolean] }
abstract class StringParser[T] extends Functor[StringParser, T] { strp =>
type Throws <: Exception
def parse(string: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[T, Throws]
def rawMap[T2](fn: (T, Mode[_ <: MethodConstraint]) => T2): StringParser[T2] { type Throws = strp.Throws } =
new StringParser[T2] {
type Throws = strp.Throws
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[T2, Throws] =
mode.wrap(fn(mode.unwrap(strp.parse(s, mode)), mode))
}
}
case class InvalidBoolean(value: String) extends Exception(s"""The value "$value" is not a valid boolean.""")
case class InvalidNumber(value: String, numberType: String)
extends Exception(s"""The value "$value" is not a valid $numberType.""")
trait StringParser_1 {
implicit def optParser[T: StringParser]: StringParser[Option[T]] { type Throws = Nothing } =
new StringParser[Option[T]] {
type Throws = Nothing
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Option[T], Nothing] = mode.wrap {
try Some(mode.unwrap(?[StringParser[T]].parse(s, mode)))
catch {
case e: Exception => None
}
}
}
implicit def tryParser[T: StringParser]: StringParser[Try[T]] { type Throws = Nothing } = new StringParser[Try[T]] {
type Throws = Nothing
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Try[T], Nothing] = mode.wrap {
?[StringParser[T]].parse(s, modes.returnTry())
}
}
}
object StringParser extends StringParser_1 {
def apply[T](f: String => T): StringParser[T] { type Throws = ParseException } = {
new StringParser[T] {
type Throws = ParseException
def parse(str: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[T, ParseException] = mode.wrap {
try f(str)
catch {
case e: Exception => mode.exception(ParseException(str, e.getMessage))
}
}
}
}
implicit def booleanParser(implicit bp: BooleanParser): StringParser[Boolean] { type Throws = InvalidBoolean } =
new StringParser[Boolean] {
type Throws = InvalidBoolean
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Boolean, InvalidBoolean] =
bp.parse(s, mode.generic)
}
implicit val byteParser: StringParser[Byte] { type Throws = InvalidNumber } = new StringParser[Byte] {
type Throws = InvalidNumber
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Byte, InvalidNumber] = mode.wrap {
try java.lang.Byte.parseByte(s)
catch {
case e: NumberFormatException => mode.exception(InvalidNumber(s, "byte"))
}
}
}
implicit val charParser: StringParser[Char] { type Throws = InvalidNumber } = new StringParser[Char] {
type Throws = InvalidNumber
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Char, InvalidNumber] = mode.wrap {
if (s.length == 1) s.charAt(0) else mode.exception(InvalidNumber(s, "character"))
}
}
implicit val shortParser: StringParser[Short] { type Throws = InvalidNumber } = new StringParser[Short] {
type Throws = InvalidNumber
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Short, InvalidNumber] = mode.wrap {
try java.lang.Short.parseShort(s)
catch {
case e: NumberFormatException => mode.exception(InvalidNumber(s, "short"))
}
}
}
implicit val intParser: StringParser[Int] { type Throws = InvalidNumber } = new StringParser[Int] {
type Throws = InvalidNumber
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Int, InvalidNumber] = mode.wrap {
try java.lang.Integer.parseInt(s)
catch {
case e: NumberFormatException => mode.exception(InvalidNumber(s, "integer"))
}
}
}
implicit val longParser: StringParser[Long] { type Throws = InvalidNumber } = new StringParser[Long] {
type Throws = InvalidNumber
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Long, InvalidNumber] = mode.wrap {
try java.lang.Long.parseLong(s)
catch {
case e: NumberFormatException => mode.exception(InvalidNumber(s, "long"))
}
}
}
implicit val stringParser: StringParser[String] { type Throws = Nothing } = new StringParser[String] {
type Throws = Nothing
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[String, Nothing] = mode.wrap(s)
}
implicit val doubleParser: StringParser[Double] = new StringParser[Double] {
type Throws = InvalidNumber
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Double, InvalidNumber] = mode.wrap {
try java.lang.Double.parseDouble(s)
catch {
case e: NumberFormatException => mode.exception(ParseException(s, "double"))
}
}
}
implicit val floatParser: StringParser[Float] = new StringParser[Float] {
type Throws = InvalidNumber
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Float, InvalidNumber] = mode.wrap {
try java.lang.Float.parseFloat(s)
catch {
case e: NumberFormatException => mode.exception(InvalidNumber(s, "float"))
}
}
}
}
================================================
FILE: core/shared/src/main/scala/rapture/core/pool.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
import scala.collection.mutable
/** Implements a dynamic pool of some resource, e.g. database connections. */
abstract class Pool[Resource] {
/** Implement to make new resources. */
protected def make(): Resource
/** Implement to dispose of surplus resources. */
protected def dispose(x: Resource): Unit
/** Implement to check resource is still usable. */
protected def check(x: Resource): Boolean
/** Number of resource to always keep in reserve, if we have them. */
protected def spare = 5
/** How long to leave surplus resources unused before discarding them. */
protected def timeout = 10 * 60000L
private val pool = new mutable.Queue[Resource]
private var poolCount = 0
private var lastLow = 0L
/** Acquire a resource for the duration of the body. */
def acquireFor[A](body: Resource => A): A = {
val res = acquireDirect()
try body(res)
finally releaseDirect(res)
}
/** Acquire a resource without any nesting guarantees. Avoid this method. */
def acquireDirect(): Resource = pool.synchronized {
if (poolCount == 0) make()
else {
val r = pool.dequeue
poolCount = poolCount - 1
if (check(r)) r
else {
dispose(r)
make()
}
}
}
/** Release a directly-acquired resource. */
def releaseDirect(r: Resource): Unit = pool.synchronized {
val now = System.currentTimeMillis()
if (poolCount < spare) lastLow = now
if (lastLow > now - timeout) {
pool.enqueue(r)
poolCount = poolCount + 1
} else dispose(r)
}
/** Dispose of all resources not currently in use. */
def disposeAll() = pool.synchronized {
while (poolCount > 0) {
dispose(pool.dequeue)
poolCount = poolCount - 1
}
}
}
================================================
FILE: core/shared/src/main/scala/rapture/core/result.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
import scala.language.higherKinds
import scala.reflect.ClassTag
import scala.annotation.unchecked._
object Result {
private[core] def apply[T, E <: Exception](result: => T, errors: Seq[(ClassTag[_], (String, Exception))]) =
try {
if (errors.isEmpty) Answer[T, E](result) else Errata[T, E](errors)
} catch { case e: Throwable => if (errors.isEmpty) Unforeseen[T, E](e) else Errata[T, E](errors) }
def apply[T](result: => T): Result[T, Nothing] =
try Answer[T, Nothing](result)
catch { case e: Throwable => Unforeseen[T, Nothing](e) }
def catching[E <: Exception]: Catching[E] = new Catching[E]()
/** Construct an answer. */
def answer[T, E <: Exception](a: T): Result[T, E] = Answer[T, E](a)
/** Construct an errata. */
def errata[T, E <: Exception](e: E)(implicit cte: ClassTag[E]) = Errata[T, E](e)
}
class Catching[E <: Exception]() {
def apply[T](blk: => T)(implicit classTag: ClassTag[E]): Result[T, E] =
try Answer(blk)
catch {
case e: E => Errata(Vector((?[ClassTag[E]], ("", e))))
case e: Throwable => Unforeseen(e)
}
}
sealed abstract class Result[+T, E <: Exception](val answer: T,
val errors: Seq[(ClassTag[_], (String, Exception))],
val unforeseen: Option[Throwable] = None) {
def errata[E2 >: E: ClassTag]: Seq[E2] =
errors.filter(_._1 == ?[ClassTag[E2]]).map(_._2.asInstanceOf[E2])
def exceptions: Seq[Exception] = errors.map(_._2._2)
def get: T = {
unforeseen.foreach(throw _)
errors.foreach { case (k, (p, e)) => throw e }
answer
}
def flatMap[T2, E2 <: Exception](fn: T => Result[T2, E2]): Result[T2, E with E2] =
try {
val res = fn(answer)
val probs = res.errors ++ errors
Result[T2, E with E2](res.get, probs)
} catch {
case e: NullPointerException if errors.nonEmpty => Errata[T2, E with E2](errors)
case e: Throwable => Unforeseen[T2, E with E2](e)
}
def map[T2](fn: T => T2) = Result[T2, E](fn(answer), errors)
def resolve[E2, T2 >: T](handlers: Each[E2, T2]*)(implicit ev: E2 <:< E): Resolved[T2, Nothing] = this match {
case Unforeseen(e) =>
Unforeseen[T2, Nothing](e)
case Answer(a) =>
Answer[T2, Nothing](a)
case Errata((t, (_, err)) +: _) =>
Answer[T2, Nothing](handlers.find { case Each(fn, ct) => ct == t }.get.fn(err.asInstanceOf[E2]))
}
def reconcile[E2, E3 <: Exception](handlers: Each[E2, E3]*) = {
val hs = handlers.map { case Each(e, typ) => typ -> e }.toMap[ClassTag[_], E2 => E3]
errors.map { case (t, (p, e)) => hs(t)(e.asInstanceOf[E2]) }
}
/** Return `true` if this result contains errors. */
def isErrata: Boolean =
this match {
case Errata(_) => true
case _ => false
}
/** Return `true` if this result is an Answer. */
def isAnswer: Boolean =
this match {
case Answer(_) => true
case _ => false
}
/** Return `true` if this result is Unforeseen. */
def isUnforeseen: Boolean =
this match {
case Unforeseen(_) => true
case _ => false
}
/** Catamorphism. Run the first given function if answer, otherwise, the second given function over the errata. */
def fold[X](l: T => X, r: Seq[(ClassTag[_], (String, Exception))] => X): X =
this match {
case Answer(a) => l(a)
case Errata(e) => r(e)
case Unforeseen(e) => throw e
}
/** Return `true` if this result is an answer satisfying the given predicate. */
def exists(p: T => Boolean): Boolean =
this match {
case Answer(b) => p(b)
case _ => false
}
/** Return `true` if this result is an errata or the answer satisfies the given predicate. */
def forall(p: T => Boolean): Boolean =
this match {
case Answer(b) => p(b)
case _ => true
}
/** Return a collection containing -- if the result was successful -- the answer. */
def to[Col[_]](implicit cbf: CanBuildFrom[Nothing, T, Col[T @uncheckedVariance]]): Col[T @uncheckedVariance] =
this match {
case Answer(ans) =>
val builder = cbf()
builder += ans
builder.result
case _ =>
cbf().result
}
/** Return `None` or a `Some` of the answer. Useful to sweep errors under the carpet. */
def toOption: Option[T] =
this match {
case Answer(b) => Some(b)
case _ => None
}
/** Convert to a core `scala.Either` at your own peril. blows up if an unforeseen exception is found */
def toEither: Either[Seq[(ClassTag[_], (String, Exception))], T] =
this match {
case Answer(b) => Right(b)
case Errata(a) => Left(a)
case Unforeseen(e) => throw e
}
/** Return the answer of this result or the given default if errata. Alias for `|` */
def getOrElse[T2 >: T](x: => T2): T2 =
this match {
case Answer(b) => b
case _ => x
}
/** Return the answer value of this result or the given default if errata. Alias for `getOrElse` */
def |[T2 >: T](x: => T2): T2 =
getOrElse(x)
/** Return the answer of this result or run the given function on the errata. */
def valueOr[T2 >: T](x: Seq[(ClassTag[_], (String, Exception))] => T2): T2 =
this match {
case Answer(b) => b
case Errata(a) => x(a)
case Unforeseen(e) => throw e
}
/** Filter on the answer of this result. */
def filter(p: T => Boolean): Result[T, E with NotMatchingFilter] =
this match {
case Answer(b) =>
val t = this.get
if (p(b))
Answer(t)
else
Errata[T, E with NotMatchingFilter](
Seq((implicitly[ClassTag[NotMatchingFilter]], ("", NotMatchingFilter(t)))))
case Errata(e) => Errata[T, E with NotMatchingFilter](e)
case Unforeseen(e) => Unforeseen[T, E with NotMatchingFilter](e)
}
/** Alias for filter */
def withFilter(p: T => Boolean): Result[T, E with NotMatchingFilter] = filter(p)
}
object Resolved {
def unapply[T, E <: Exception](res: Result[T, E]): Option[(T, Option[Throwable])] =
Some(res.answer -> res.unforeseen)
def apply[T, E <: Exception](answer: T, unforeseen: Option[E]) =
if (unforeseen.isEmpty) Answer(answer) else Unforeseen(unforeseen.get)
}
sealed abstract class Resolved[+T, E <: Exception](answer: T, unforeseen: Option[Throwable])
extends Result[T, E](answer, Seq(), unforeseen) {
override def equals(that: Any) = that match {
case that: Resolved[_, _] => that.answer == answer && that.unforeseen == unforeseen
case _ => false
}
override def hashCode = answer.hashCode ^ unforeseen.hashCode
}
case class Answer[T, E <: Exception](override val answer: T) extends Resolved[T, E](answer, None)
case class Errata[T, E <: Exception](override val errors: Seq[(ClassTag[_], (String, Exception))])
extends Result[T, E](null.asInstanceOf[T], errors) {
override def toString =
"Errata(\n " + errors.map { case (t, (p, e)) => s"$t: ${e.getMessage} [$p]" }.mkString(",\n ") + "\n)"
}
object Errata {
def apply[T, E <: Exception](e: => E)(implicit classTag: ClassTag[E]): Result[T, E] =
Errata(Vector((?[ClassTag[E]], ("", e))))
}
case class Unforeseen[T, E <: Exception](e: Throwable) extends Resolved[T, E](null.asInstanceOf[T], Some(e))
case class AbortException() extends Exception
private[core] class ReturnResultMode[+Group <: MethodConstraint] extends Mode[Group] {
type Wrap[+R, E <: Exception] = Result[R, E]
def wrap[R, E <: Exception](blk: => R): Result[R, E] = {
try {
val res = blk
Result[R, E](res, accumulated)
} catch {
case AbortException() =>
Result[R, E](null.asInstanceOf[R], accumulated)
case e: Throwable =>
if (accumulated.isEmpty) Unforeseen[R, E](e)
else Errata(accumulated)
}
}
private var accumulated: Vector[(ClassTag[_], (String, Exception))] = Vector()
override def exception[T, E <: Exception: ClassTag](e: E, continue: Boolean = true): T = {
accumulated :+= ((?[ClassTag[E]], (callPath, e)))
if (continue) null.asInstanceOf[T] else throw AbortException()
}
override def catching[E <: Exception: ClassTag, T](blk: => T) =
try blk
catch {
case e: E =>
exception(e)
case e: Exception =>
throw e
}
override def flatWrap[R, E <: Exception: ClassTag](blk: => Wrap[R, E]): Wrap[R, E] = blk
def unwrap[Return](value: => Wrap[Return, _ <: Exception]): Return = value match {
case Answer(a) => a
case Errata(xs) => null.asInstanceOf[Return]
case Unforeseen(e) => throw e
case _ => ???
}
override def toString = "[modes.returnResult]"
}
case class Each[-E, +T](fn: E => T, classTag: ClassTag[_])
case class EachUnapplied[E]() {
def apply[R](fn: E => R)(implicit classTag: ClassTag[E]): Each[E, R] = Each(fn, classTag)
}
case class NotMatchingFilter(value: Any) extends Exception(s"value '$value' did not match filter")
================================================
FILE: core/shared/src/main/scala/rapture/core/serializer.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
package decimalFormats {
object to0dp {
def apply() = implicitDecimalFormat
implicit val implicitDecimalFormat: DecimalFormat = DecimalPlaces(0)
}
object to1dp {
def apply() = implicitDecimalFormat
implicit val implicitDecimalFormat: DecimalFormat = DecimalPlaces(1)
}
object to2dp {
def apply() = implicitDecimalFormat
implicit val implicitDecimalFormat: DecimalFormat = DecimalPlaces(2)
}
object to3dp {
def apply() = implicitDecimalFormat
implicit val implicitDecimalFormat: DecimalFormat = DecimalPlaces(3)
}
object to4dp {
def apply() = implicitDecimalFormat
implicit val implicitDecimalFormat: DecimalFormat = DecimalPlaces(4)
}
object to5dp {
def apply() = implicitDecimalFormat
implicit val implicitDecimalFormat: DecimalFormat = DecimalPlaces(5)
}
object to6dp {
def apply() = implicitDecimalFormat
implicit val implicitDecimalFormat: DecimalFormat = DecimalPlaces(6)
}
object to1sf {
def apply() = implicitDecimalFormat
implicit val implicitDecimalFormat: DecimalFormat = SignificantFigures(1)
}
object to2sf {
def apply() = implicitDecimalFormat
implicit val implicitDecimalFormat: DecimalFormat = SignificantFigures(2)
}
object to3sf {
def apply() = implicitDecimalFormat
implicit val implicitDecimalFormat: DecimalFormat = SignificantFigures(3)
}
object to4sf {
def apply() = implicitDecimalFormat
implicit val implicitDecimalFormat: DecimalFormat = SignificantFigures(4)
}
object to5sf {
def apply() = implicitDecimalFormat
implicit val implicitDecimalFormat: DecimalFormat = SignificantFigures(5)
}
object to6sf {
def apply() = implicitDecimalFormat
implicit val implicitDecimalFormat: DecimalFormat = SignificantFigures(6)
}
object exact {
def apply() = implicitDecimalFormat
implicit val implicitDecimalFormat: DecimalFormat = ExactDecimal
}
}
package integerFormats {
object exact {
def apply() = implicitIntegerFormat
implicit val implicitIntegerFormat: IntegerFormat = ExactInteger
}
object to1sf {
def apply() = implicitIntegerFormat
implicit val implicitIntegerFormat: IntegerFormat = IntegerSignificantFigures(1)
}
object to2sf {
def apply() = implicitIntegerFormat
implicit val implicitIntegerFormat: IntegerFormat = IntegerSignificantFigures(2)
}
object to3sf {
def apply() = implicitIntegerFormat
implicit val implicitIntegerFormat: IntegerFormat = IntegerSignificantFigures(3)
}
object to4sf {
def apply() = implicitIntegerFormat
implicit val implicitIntegerFormat: IntegerFormat = IntegerSignificantFigures(4)
}
object to5sf {
def apply() = implicitIntegerFormat
implicit val implicitIntegerFormat: IntegerFormat = IntegerSignificantFigures(5)
}
object to6sf {
def apply() = implicitIntegerFormat
implicit val implicitIntegerFormat: IntegerFormat = IntegerSignificantFigures(6)
}
}
package booleanRepresentations {
object trueFalse {
def apply() = implicitBooleanRepresentation
implicit val implicitBooleanRepresentation: BooleanRepresentation = BooleanRepresentation("true", "false")
}
object digital {
def apply() = implicitBooleanRepresentation
implicit val implicitBooleanRepresentation: BooleanRepresentation = BooleanRepresentation("1", "0")
}
object yesNo {
def apply() = implicitBooleanRepresentation
implicit val implicitBooleanRepresentation: BooleanRepresentation = BooleanRepresentation("yes", "no")
}
object onOff {
def apply() = implicitBooleanRepresentation
implicit val implicitBooleanRepresentation: BooleanRepresentation = BooleanRepresentation("on", "off")
}
}
object BooleanRepresentation {
implicit val defaultBooleanRepresentation: BooleanRepresentation = BooleanRepresentation("true", "false")
}
case class BooleanRepresentation(trueValue: String, falseValue: String)
object DecimalFormat { implicit val defaultRounding: DecimalFormat = SignificantFigures(4) }
trait DecimalFormat { def format(bigDecimal: BigDecimal): String }
case class DecimalPlaces(n: Int) extends DecimalFormat {
def format(bigDecimal: BigDecimal): String = {
val integral = bigDecimal.toBigInt.toString.length
bigDecimal.round(new java.math.MathContext(integral + n)).setScale(n).toString
}
}
case class SignificantFigures(n: Int) extends DecimalFormat {
def format(bigDecimal: BigDecimal) = bigDecimal.round(new java.math.MathContext(n)).toString
}
case object ExactDecimal extends DecimalFormat {
def format(bigDecimal: BigDecimal) = bigDecimal.toString
}
object IntegerFormat { implicit val defaultRounding: IntegerFormat = ExactInteger }
trait IntegerFormat { def format(bigInt: BigInt): String }
case object ExactInteger extends IntegerFormat {
def format(bigInt: BigInt) = bigInt.toString
}
case class IntegerSignificantFigures(n: Int) extends IntegerFormat {
def format(bigInt: BigInt) =
BigDecimal(bigInt).round(new java.math.MathContext(n)).toString
}
object StringSerializer {
def apply[T](f: T => String): StringSerializer[T] = new StringSerializer[T]{
override def serialize(ser: T): String = f(ser)
}
implicit def booleanSerializer(implicit bs: BooleanRepresentation): StringSerializer[Boolean] =
StringSerializer{s => if (s) bs.trueValue else bs.falseValue}
implicit val charSerializer: StringSerializer[Char] = StringSerializer(_.toString)
implicit def byteSerializer(implicit df: IntegerFormat): StringSerializer[Byte] =
StringSerializer{s => df.format(BigInt(s)) }
implicit def shortSerializer(implicit df: IntegerFormat): StringSerializer[Short] =
StringSerializer{s => df.format(BigInt(s)) }
implicit def longSerializer(implicit df: IntegerFormat): StringSerializer[Long] =
StringSerializer{s => df.format(BigInt(s)) }
implicit def intSerializer(implicit df: IntegerFormat): StringSerializer[Int] =
StringSerializer{s => df.format(BigInt(s)) }
implicit val stringSerializer: StringSerializer[String] = StringSerializer(identity)
implicit def doubleSerializer(implicit df: DecimalFormat): StringSerializer[Double] =
StringSerializer{s => df.format(BigDecimal(s)) }
implicit def floatSerializer(implicit df: DecimalFormat): StringSerializer[Float] =
StringSerializer{f => df.format(BigDecimal(f.toDouble)) }
implicit def bigDecimalSerializer(implicit df: DecimalFormat): StringSerializer[BigDecimal] =
StringSerializer{s => df.format(s) }
implicit def bigIntSerializer(implicit df: IntegerFormat): StringSerializer[BigInt] =
StringSerializer{s => df.format(s) }
}
/** A generic string serializer */
@implicitNotFound(
"It is not possible to serialize a value of type $"+"{T} to a String without a" +
" valid StringSerializer instance in scope.")
trait StringSerializer[-T] { stringSerializer =>
def serialize(string: T): String
def contramap[S](fn: S => T): StringSerializer[S] = new StringSerializer[S] {
def serialize(string: S): String = stringSerializer.serialize(fn(string))
}
}
object String {
def apply[T: StringSerializer](t: T): String =
?[StringSerializer[T]].serialize(t)
// Proxied from java.lang.String
def format(str: String, any: AnyRef*) = java.lang.String.format(str, any: _*)
def format(locale: java.util.Locale, str: String, any: AnyRef*) =
java.lang.String.format(locale, str, any: _*)
def copyValueOf(arr: Array[Char]): String = java.lang.String.copyValueOf(arr)
def vauleOf(x: Array[Char]): String = java.lang.String.valueOf(x)
def vauleOf(x: Boolean): String = java.lang.String.valueOf(x)
def vauleOf(x: Double): String = java.lang.String.valueOf(x)
def vauleOf(x: Int): String = java.lang.String.valueOf(x)
def vauleOf(x: Any): String = java.lang.String.valueOf(x)
def vauleOf(x: Array[Char], a: Int, b: Int): String = java.lang.String.valueOf(x, a, b)
def vauleOf(x: Char): String = java.lang.String.valueOf(x)
def vauleOf(x: Float): String = java.lang.String.valueOf(x)
def vauleOf(x: Long): String = java.lang.String.valueOf(x)
val CASE_INSENSITIVE_ORDER = java.lang.String.CASE_INSENSITIVE_ORDER
}
================================================
FILE: core/shared/src/main/scala/rapture/core/threads.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
import java.lang.{ClassLoader => JClassLoader, Thread => JThread}
object ClasspathUrlItem {
implicit def toClasspathUrlItem[T: ClasspathUrlable](t: T): ClasspathUrlItem =
?[ClasspathUrlable[T]].toClasspathUrlItem(t)
}
case class ClasspathUrlItem(javaUrl: List[java.net.URL])
object ClasspathUrlable {
implicit def seqUrlable[T](implicit urlable: ClasspathUrlable[T]): ClasspathUrlable[List[T]] =
new ClasspathUrlable[List[T]] {
def toClasspathUrlItem(xs: List[T]): ClasspathUrlItem =
ClasspathUrlItem(xs.flatMap(urlable.toClasspathUrlItem(_).javaUrl))
}
}
trait ClasspathUrlable[T] { def toClasspathUrlItem(t: T): ClasspathUrlItem }
object ClassLoader {
implicit def defaultClassLoader: ClassLoader =
new ClassLoader(JThread.currentThread.getContextClassLoader)
def apply(urls: ClasspathUrlItem*): ClassLoader =
new ClassLoader(new java.net.URLClassLoader(urls.flatMap(_.javaUrl).to[Array]))
}
class ClassLoader(val javaClassLoader: JClassLoader) {
def applyTo[T](blk: => T): T = {
val cur = java.lang.Thread.currentThread().getContextClassLoader
java.lang.Thread.currentThread().setContextClassLoader(javaClassLoader)
val result = blk
java.lang.Thread.currentThread().setContextClassLoader(cur)
result
}
}
object Thread {
def fork(threadName: String, daemon: Boolean = false)(blk: => Unit)(implicit cl: ClassLoader): Thread =
ThreadSpec(threadName, daemon)(blk).spawn()
def sleep[D: TimeSystem.ByDuration](duration: D) =
JThread.sleep(?[TimeSystem.ByDuration[D]].fromDuration(duration))
}
case class ThreadSpec(name: String, daemon: Boolean = false)(blk: => Unit)(implicit cl: ClassLoader) {
def spawn(): Thread = {
val parentThread = JThread.currentThread
val javaThread = new JThread(name) {
override def run() = {
blk
parentThread.join()
}
}
javaThread.setDaemon(daemon)
javaThread.setContextClassLoader(cl.javaClassLoader)
javaThread.start()
new Thread(this, javaThread) {
def parentAlive = javaThread.isAlive
}
}
}
abstract class Thread(spec: ThreadSpec, javaThread: JThread) {
def daemon: Boolean = spec.daemon
def name: String = spec.name
def alive: Boolean = javaThread.isAlive
def interrupt(): Unit = javaThread.interrupt()
def join(): Unit = javaThread.join()
def priority = javaThread.getPriority
def priority_=(p: Int) = javaThread.setPriority(p)
override def toString = s"[$name]"
}
================================================
FILE: core/shared/src/main/scala/rapture/core/time.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core
object TimeSystem {
type ByInstant[T] = TimeSystem[T, _]
type ByDuration[T] = TimeSystem[_, T]
}
@implicitNotFound(
"an implicit TimeSystem is required; please import timeSystems.numeric._ or " +
"timeSystems.javaUtil._")
trait TimeSystem[Instant, Duration] {
def instant(millis: Long): Instant
def duration(from: Long, to: Long): Duration
def fromInstant(inst: Instant): Long
def fromDuration(dur: Duration): Long
}
package timeSystems {
object numeric {
def apply(): TimeSystem[Long, Long] = timeSystemImplicit
implicit val timeSystemImplicit: TimeSystem[Long, Long] = new TimeSystem[Long, Long] {
def instant(millis: Long): Long = millis
def duration(from: Long, to: Long): Long = to - from
def fromInstant(inst: Long): Long = inst
def fromDuration(dur: Long): Long = dur
}
}
object javaUtil {
def apply(): TimeSystem[java.util.Date, Long] = timeSystemImplicit
implicit val timeSystemImplicit = new TimeSystem[java.util.Date, Long] {
import java.util.Date
def instant(millis: Long) = new Date(millis)
def duration(from: Long, to: Long): Long = to - from
def fromInstant(inst: Date): Long = inst.getTime
def fromDuration(dur: Long): Long = dur
}
}
}
================================================
FILE: core-scalaz/shared/src/main/scala/rapture/core-scalaz/modes.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core.scalazInterop
import rapture.core._
import java.util.concurrent.ExecutorService
import scalaz._
import scalaz.concurrent._
class ReturnTasks[+Group <: MethodConstraint](implicit pool: ExecutorService) extends Mode[Group] {
type Wrap[+T, E <: Exception] = Task[T]
def wrap[T, E <: Exception](t: => T): Task[T] = Task.delay(t)
def unwrap[T](t: => Wrap[T, _ <: Exception]): T = t.unsafePerformSyncAttempt.valueOr { throw _ }
}
class ReturnValidation[+Group <: MethodConstraint] extends Mode[Group] {
type Wrap[+T, E <: Exception] = Validation[E, T]
def wrap[T, E <: Exception](t: => T): Validation[E, T] =
try Success(t)
catch { case e: Exception => Failure(e.asInstanceOf[E]) }
def unwrap[T](t: => Validation[_ <: Exception, T]): T = t.valueOr { throw _ }
}
class ReturnDisjunction[+Group <: MethodConstraint] extends Mode[Group] {
type Wrap[+T, E <: Exception] = \/[E, T]
def wrap[T, E <: Exception](t: => T): \/[E, T] =
try \/-(t)
catch { case e: Exception => -\/(e.asInstanceOf[E]) }
def unwrap[T](t: => \/[_ <: Exception, T]): T = t.valueOr { throw _ }
}
class ScalazExplicits[+T, E <: Exception](explicit: modes.Explicitly[T, E]) {
def task(implicit pool: ExecutorService): Task[T] = returnTasks.wrap(explicit.get)
def validation: Validation[E, T] = returnValidations.wrap(explicit.get)
}
object `package` {
implicit def scalazExplicits[T, E <: Exception](explicit: modes.Explicitly[T, E]): ScalazExplicits[T, E] =
new ScalazExplicits[T, E](explicit)
implicit def returnTasks[Group <: MethodConstraint](implicit pool: ExecutorService) = new ReturnTasks[Group]
// FIXME: This should be modified to collect multiple failures
implicit def returnValidations[Group <: MethodConstraint] = new ReturnValidation[Group]
implicit def returnDisjunction[Group <: MethodConstraint] = new ReturnDisjunction[Group]
}
================================================
FILE: core-scalaz/shared/src/main/scala/rapture/core-scalaz/transformers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core.scalazInterop
import rapture.core.{Errata, NotMatchingFilter, Result}
import scala.reflect.ClassTag
import scalaz.{Functor, _}
import language.higherKinds
/**
* ResultT monad transformer
*
* Represents a computation of type `Result[A,B]`.
*
* Example:
* {{{
* val x: Option[Result[String, E]] = Some(Answer(1))
* ResultT(x).map(1+).run // Some(Answer(2))
* }}}
**/
sealed trait ResultT[F[_], T, E <: Exception] {
val run: F[Result[T, E]]
/** Map on the answer of this result. */
def map[C](f: T => C)(implicit functor: Functor[F], cte: ClassTag[E]): ResultT[F, C, E] =
ResultT(functor.map(run)(_.map(f)))
/** Bind through the answer of this result accumulating errors in the contents and type signature. */
def flatMap[C, E2 <: Exception](f: T => ResultT[F, C, E2])(implicit monad: Monad[F],
cte: ClassTag[E2]): ResultT[F, C, E with E2] = {
ResultT(monad.bind[Result[T, E], Result[C, E with E2]](run) { result =>
result.fold[F[Result[C, E with E2]]]({ a =>
monad.map(f(a).run)(r2 => Result[C, E with E2](r2.get, r2.errors ++ result.errors))
}, { e =>
monad.point(Errata[C, E with E2](e))
})
})
}
/** Filter on the answer of this result. */
def filter(p: T => Boolean)(implicit functor: Functor[F],
cte: ClassTag[E]): ResultT[F, T, E with NotMatchingFilter] =
ResultT(functor.map(run)(_.filter(p)))
/** Alias for `filter` */
def withFilter(p: T => Boolean)(implicit functor: Functor[F],
cte: ClassTag[E]): ResultT[F, T, E with NotMatchingFilter] =
filter(p)
}
object ResultT extends ResultTFunctions {
/** Construct a result value. */
def apply[F[_], T, E <: Exception: ClassTag](a: F[Result[T, E]]): ResultT[F, T, E] =
resultT[F, T, E](a)
/** Construct an answer value. */
def answer[F[_], T, E <: Exception: ClassTag](a: F[T])(implicit functor: Functor[F]): ResultT[F, T, E] =
apply[F, T, E](functor.map(a)(Result.answer[T, E]))
/** Construct an errata value. */
def errata[F[_], T, E <: Exception: ClassTag](a: F[E])(implicit functor: Functor[F]): ResultT[F, T, E] =
apply[F, T, E](functor.map(a)(Result.errata[T, E]))
}
private[scalazInterop] trait ResultTFunctions {
def resultT[F[_], T, E <: Exception](a: F[Result[T, E]]): ResultT[F, T, E] = new ResultT[F, T, E] {
val run = a
}
}
================================================
FILE: core-test/shared/src/test/scala/rapture/core/tests.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core.test
import rapture.core._
import rapture.core.scalazInterop.ResultT
import rapture.test._
import scalaz.Scalaz._
class TestRun extends Programme {
include(CoreTests)
}
object CoreTests extends TestSuite {
case class AlphaException() extends Exception
case class BetaException() extends Exception
case class MiscException() extends Exception
def alpha(x: Int)(implicit mode: Mode[_]): mode.Wrap[Int, AlphaException] = mode.wrap {
if(x == 0) mode.exception(AlphaException())
else if(x == 1) throw MiscException()
else 0
}
def beta(x: Int)(implicit mode: Mode[_]): mode.Wrap[Int, BetaException] = mode.wrap {
if(x == 0) mode.exception(BetaException())
else if(x == 1) throw MiscException()
else 0
}
val `Successful Result` = test {
import modes.returnResult._
alpha(2)
} returns Answer(0)
val `Unforeseen Result` = test {
import modes.returnResult._
alpha(1)
} returns Unforeseen(MiscException())
val `Expected error Result` = test {
import modes.returnResult._
alpha(0)
} satisfies { case Errata(_) => true case _ => false }
val `FlatMapped Successful Result` = test {
import modes.returnResult._
for {
a <- alpha(2)
b <- beta(2)
} yield a + b
} returns Answer(0)
val `FlatMapped first fails` = test {
import modes.returnResult._
for {
a <- alpha(0)
b <- beta(2)
} yield a + b
} satisfies (_.exceptions == Vector(AlphaException()))
val `FlatMapped second fails` = test {
import modes.returnResult._
for {
a <- alpha(2)
b <- beta(0)
} yield a + b
} satisfies (_.exceptions == Vector(BetaException()))
val `Resolving errata 1` = test {
import modes.returnResult._
val result = for(a <- alpha(2); b <- beta(0)) yield a + b
result.resolve(
each[AlphaException] { e => 10 },
each[BetaException] { e => 20 }
)
} returns Answer(20)
val `Resolving errata 2` = test {
import modes.returnResult._
val result = for(a <- alpha(0); b <- beta(2)) yield a + b
result.resolve(
each[AlphaException] { e => 10 },
each[BetaException] { e => 20 }
)
} returns Answer(10)
val `Catching success` = test {
Result.catching[AlphaException] {
"success"
}
} returns Answer("success")
val `Catching failure` = test {
Result.catching[AlphaException] {
throw AlphaException()
}
} satisfies (_.exceptions == Vector(AlphaException()))
val `Catching unforeseen` = test {
Result.catching[AlphaException] {
throw BetaException()
}
} returns Unforeseen(BetaException())
val `Checking isErrata with errata` = test {
Result.errata(AlphaException()).isErrata
} returns true
val `Checking isErrata with answer` = test {
Result.answer(1).isErrata
} returns false
val `Checking isAnswer with errata` = test {
Result.errata(AlphaException()).isAnswer
} returns false
val `Checking isAnswer with answer` = test {
Result.answer(1).isAnswer
} returns true
val `Checking isUnforeseen with answer` = test {
Result.answer(1).isUnforeseen
} returns false
val `Checking isUnforeseen with errata` = test {
Result.errata(AlphaException()).isUnforeseen
} returns false
val `Checking isUnforeseen with unforeseen` = test {
Result.catching[AlphaException] {
throw BetaException()
}.isUnforeseen
} returns true
val `Fold answer` = test {
Result.answer(1).fold(
a => a + 1,
e => 0
)
} returns 2
val `Fold errata` = test {
Result.errata[Int, AlphaException](AlphaException()).fold(
a => a + 1,
e => 0
)
} returns 0
val `Exists answer` = test {
Result.answer(1).exists(_ == 1)
} returns true
val `Exists answer none found` = test {
Result.answer(1).exists(_ == 0)
} returns false
val `Exists errata` = test {
Result.errata[Int, AlphaException](AlphaException()).exists(_ == 1)
} returns false
val `Forall answer` = test {
Result.answer(1).forall(_ == 1)
} returns true
val `Forall answer none found` = test {
Result.answer(1).forall(_ == 0)
} returns false
val `Forall errata` = test {
Result.errata[Int, AlphaException](AlphaException()).forall(_ == 1)
} returns true
val `toList answer` = test {
Result.answer(1).to[List]
} returns List(1)
val `toList errata` = test {
Result.errata[Int, AlphaException](AlphaException()).to[List]
} returns Nil
val `toStream answer` = test {
Result.answer(1).to[Stream]
} returns Stream(1)
val `toStream errata` = test {
Result.errata[Int, AlphaException](AlphaException()).to[Stream]
} returns Stream.empty[Int]
val `toOption answer` = test {
Result.answer(1).toOption
} returns Some(1)
val `toOption errata` = test {
Result.errata[Int, AlphaException](AlphaException()).toOption
} returns None
val `toEither answer` = test {
Result.answer(1).toEither
} returns Right(1)
val `toEither errata` = test {
Result.errata[Int, AlphaException](AlphaException()).toEither
} satisfies (v => v.isLeft)
val `getOrElse answer` = test {
Result.answer(1).getOrElse(0)
} returns 1
val `getOrElse errata` = test {
Result.errata[Int, AlphaException](AlphaException()).getOrElse(0)
} returns 0
val `| answer` = test {
Result.answer(1) | 0
} returns 1
val `| errata` = test {
Result.errata[Int, AlphaException](AlphaException()) | 0
} returns 0
val `valueOr answer` = test {
Result.answer(1).valueOr(_ => 0)
} returns 1
val `valueOr errata` = test {
Result.errata[Int, AlphaException](AlphaException()).valueOr(_ => 0)
} returns 0
val `filter answer` = test {
Result.answer(1) filter (_ == 1)
} returns Answer(1)
/*val `filter answer 2` = test {
Result.answer(1) filter (_ == 0)
} returns Errata(Nil)*/
val `filter errata` = test {
Errata[String, Nothing](Nil) filter (_.isEmpty)
} returns Errata(Nil)
/*val `withFilter errata monadic` = test {
for {
x <- Answer(1)
if x == 0
y = x + 1
} yield y
} returns Errata(Nil)*/
val `withFilter answer monadic` = test {
for {
x <- Answer(1)
if x == 1
y = x + 1
} yield y
} returns Answer(2)
val `ResultT Checking isErrata with errata` = test {
ResultT.errata(Option(AlphaException())).run.get.isErrata
} returns true
val `ResultT Checking isErrata with answer` = test {
ResultT.answer(Option(1)).run.get.isErrata
} returns false
val `ResultT Checking isAnswer with errata` = test {
ResultT.errata(Option(AlphaException())).run.get.isAnswer
} returns false
val `ResultT Checking isAnswer with answer` = test {
ResultT.answer(Option(1)).run.get.isAnswer
} returns true
val `ResultT Checking isUnforeseen with answer` = test {
ResultT.answer(Option(1)).run.get.isUnforeseen
} returns false
val `ResultT Checking isUnforeseen with errata` = test {
ResultT.errata(Option(AlphaException())).run.get.isUnforeseen
} returns false
val `ResultT withFilter accumulating exceptions` = test {
val z: ResultT[Option, Int, NumberFormatException with IllegalArgumentException] = for {
x <- ResultT(Option(Result.catching[NumberFormatException]("1".toInt)))
y <- ResultT(Option(Result.catching[IllegalArgumentException]("1".toInt)))
} yield x + y
z.run.get.get
} returns 2
}
================================================
FILE: crypto/shared/src/main/scala/rapture/crypto/aes.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.crypto
import rapture.core._
import javax.crypto.spec._
import java.util._
import digests._
trait `AesEncryption#decrypt` extends MethodConstraint
trait `Key#decrypt` extends MethodConstraint
/** Provides a simple interface for AES encryption with SHA-256 digest
* verification. This class is stateless. */
abstract class AesEncryption {
/** Must be 16, 24 or 32 bytes long. */
protected def secretKey: Array[Byte]
private val keySpec = new SecretKeySpec(secretKey, "AES")
def encrypt(clearText: Array[Byte], iv: Array[Byte] = null): Array[Byte] = {
val cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding")
if (iv == null) cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, keySpec)
else cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv))
val digest = Hash.digest[Sha256](clearText).bytes
val paddedLength = (clearText.length >> 4) + 1 << 4
val cipherText = new Array[Byte](paddedLength + (if (iv == null) 48 else 0))
if (iv == null) {
Array.copy(cipher.getIV, 0, cipherText, 0, 16)
cipher.update(digest, 0, 32, cipherText, 16)
}
cipher.doFinal(clearText, 0, clearText.length, cipherText, if (iv == null) 48 else 0)
cipherText
}
def decrypt(cipherText: Array[Byte], iv: Array[Byte] = null)(
implicit mode: Mode[`AesEncryption#decrypt`]): mode.Wrap[Array[Byte], DecryptionException] = mode.wrap {
if (iv == null && cipherText.length < 48) mode.exception(DecryptionException())
val cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding")
val ips = if (iv == null) new IvParameterSpec(cipherText, 0, 16) else new IvParameterSpec(iv)
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, keySpec, ips)
val n = if (iv == null) 64 else 0
val digest1 = if (iv == null) cipher.update(cipherText, 16, 48) else Array[Byte]()
val clearText = cipher.doFinal(cipherText, n, cipherText.length - n)
if (iv == null) {
val digest2 = Hash.digest[Sha256](clearText).bytes
var i = 0
var r = true
while (i < 32) {
if (digest1(i) != digest2(i)) r = false
i += 1
}
if (!r) {
Arrays.fill(digest1, 0.toByte)
Arrays.fill(digest2, 0.toByte)
Arrays.fill(clearText, 0.toByte)
mode.exception(DecryptionException())
}
}
clearText
}
def apply(clearText: Array[Byte]): Array[Byte] = encrypt(clearText)
def unapply(cipherText: Array[Byte]): Option[Array[Byte]] =
try Some(decrypt(cipherText))
catch { case DecryptionException() => None }
}
================================================
FILE: crypto/shared/src/main/scala/rapture/crypto/digest.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.crypto
import rapture.core._
import rapture.codec._
import java.security._
import javax.crypto.Mac
trait DigestType
trait Sha1 extends DigestType
trait Sha256 extends DigestType
trait Sha384 extends DigestType
trait Sha512 extends DigestType
trait Md2 extends DigestType
trait Md5 extends DigestType
class Digest[T <: DigestType](bytes: Array[Byte]) extends Bytes(bytes)
package ciphers {
object des {
implicit def desGenerator: KeyGenerator[Des] = Des.keyGenerator
implicit def desDecryption = Des.decryption
implicit def desEncryption = Des.encryption
}
object blowfish {
implicit def blowfishGenerator: KeyGenerator[Blowfish] = Blowfish.keyGenerator
implicit def blowfishDecryption = Blowfish.decryption
implicit def blowfishEncryption = Blowfish.encryption
}
object aes {
implicit def aesGenerator: KeyGenerator[Aes] = Aes.keyGenerator
implicit def aesDecryption = Aes.decryption
implicit def aesEncryption = Aes.encryption
}
}
class EncryptedData[C <: CipherType](bytes: Array[Byte]) extends Bytes(bytes)
object Hash {
def digest[D <: DigestType: Digester](msg: Bytes): Digest[D] =
new Digest[D](?[Digester[D]].digest(msg.bytes))
}
object Digester {
implicit val sha1: Digester[Sha1] = digests.sha1
implicit val sha256: Digester[Sha256] = digests.sha256
implicit val sha512: Digester[Sha512] = digests.sha512
implicit val sha384: Digester[Sha384] = digests.sha384
implicit val md5: Digester[Md5] = digests.md5
implicit val md2: Digester[Md2] = digests.md2
}
abstract class Digester[D <: DigestType] {
/** Digests the array of bytes. */
def digest(msg: Array[Byte]): Array[Byte]
}
case class Salt(value: String)
object Password {
def apply(value: String)(implicit salt: Salt) = new HashedPassword(value)(salt)
}
class Password(private val value: String)(implicit salt: Salt) {
def digest: String = Bytes(Digester.sha256.digest((value + salt).getBytes("UTF-8"))).encode[Hex]
override def toString = s"password:$digest"
def check(password: String) = new Password(password).digest == digest
}
class HashedPassword(hash: String)(implicit salt: Salt) extends Password(null)(salt) {
override def digest: String = hash
}
object digests {
implicit val sha1: Digester[Sha1] = new Digester[Sha1] {
def digest(msg: Array[Byte]): Array[Byte] =
MessageDigest.getInstance("SHA-1").digest(msg)
}
/** SHA-256 digester, with additional methods for secure password encoding. */
implicit val sha256: Digester[Sha256] = new Digester[Sha256] {
/** Digests the given bytes. */
def digest(msg: Array[Byte]): Array[Byte] =
MessageDigest.getInstance("SHA-256").digest(msg)
}
/** SHA-512 digester, with additional methods for secure password encoding. */
implicit val sha512: Digester[Sha512] = new Digester[Sha512] {
def digest(msg: Array[Byte]): Array[Byte] =
MessageDigest.getInstance("SHA-512").digest(msg)
}
/** SHA-384 digester, with additional methods for secure password encoding. */
implicit val sha384: Digester[Sha384] = new Digester[Sha384] {
def digest(msg: Array[Byte]): Array[Byte] =
MessageDigest.getInstance("SHA-384").digest(msg)
}
/** MD5 Digester. This is included for backwards compatibility. MD5 is no
* longer considered future-proof and new designs should prefer SHA-256. */
implicit val md5: Digester[Md5] = new Digester[Md5] {
def digest(msg: Array[Byte]): Array[Byte] =
MessageDigest.getInstance("MD5").digest(msg)
}
implicit val md2: Digester[Md2] = new Digester[Md2] {
def digest(msg: Array[Byte]): Array[Byte] =
MessageDigest.getInstance("MD2").digest(msg)
}
}
trait CipherType
trait Blowfish extends CipherType
class JavaxCryptoImplementations[Codec <: CipherType](codec: String) {
implicit def encryption: Encryption[Codec, Bytes] = new Encryption[Codec, Bytes] {
def encrypt(key: Array[Byte], message: Bytes) = {
val cipher = javax.crypto.Cipher.getInstance(codec)
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, new javax.crypto.spec.SecretKeySpec(key, codec))
cipher.doFinal(message.bytes)
}
}
implicit def decryption = new Decryption[Codec] {
def decrypt(key: Array[Byte], message: Array[Byte]) = {
val cipher = javax.crypto.Cipher.getInstance(codec)
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, new javax.crypto.spec.SecretKeySpec(key, codec))
cipher.doFinal(message)
}
}
implicit def keyGenerator: KeyGenerator[Codec] = new KeyGenerator[Codec] {
def generate(): Array[Byte] = {
val keyGen = javax.crypto.KeyGenerator.getInstance(codec)
keyGen.generateKey().getEncoded
}
}
}
trait Aes extends CipherType
object Aes extends JavaxCryptoImplementations[Aes]("AES")
object Des extends JavaxCryptoImplementations[Des]("DES")
object Blowfish extends JavaxCryptoImplementations[Blowfish]("Blowfish")
trait TripleDes extends CipherType
trait Des extends CipherType
trait KeyGenerator[K <: CipherType] {
type KeyType = K
def generate(): Array[Byte]
}
trait Encryption[-C <: CipherType, Msg] {
def encrypt(key: Array[Byte], message: Msg): Array[Byte]
}
case class DecryptionException() extends Exception
trait Decryption[C <: CipherType] {
def decrypt(key: Array[Byte], message: Array[Byte]): Array[Byte]
}
object Key {
def generate[K <: CipherType]()(implicit gen: KeyGenerator[K]): Key[gen.KeyType] =
new Key[gen.KeyType](?[KeyGenerator[K]].generate())
def read[K <: CipherType](key: Bytes): Key[K] =
new Key[K](key.bytes)
}
class Key[C <: CipherType](bytes: Array[Byte]) extends Bytes(bytes) {
def encrypt[Msg](message: Msg)(implicit encryption: Encryption[C, Msg]): EncryptedData[C] =
new EncryptedData[C](encryption.encrypt(bytes, message))
def decrypt(message: EncryptedData[C])(implicit mode: Mode[`Key#decrypt`],
decryption: Decryption[C]): mode.Wrap[Bytes, DecryptionException] =
mode wrap {
try Bytes(decryption.decrypt(bytes, message.bytes))
catch {
case e: Exception => mode.exception(DecryptionException())
}
}
}
case class HmacSigner(key: Bytes) {
type Sha256Hmac <: DigestType
implicit val hmac: Digester[Sha256Hmac] = new Digester[Sha256Hmac] {
def digest(msg: Array[Byte]): Array[Byte] = {
val mac = Mac.getInstance("HmacSHA256")
val secretKey = new javax.crypto.spec.SecretKeySpec(key.bytes, "HmacSHA256")
mac.init(secretKey)
mac.doFinal(msg)
}
}
}
================================================
FILE: css/shared/src/main/scala/rapture/css/context.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.css
import rapture.base._
import rapture.core._
import rapture.data._
import language.experimental.macros
private[css] object CssMacros {
def parseSource(s: List[String], substitutions: List[String], stylesheet: Boolean): Option[(Int, Int, String)] =
try {
if(stylesheet) CssParser.parseStylesheet(s, substitutions)
else CssParser.parse(s, substitutions)
None
} catch {
case CssParser.ValidationException(strNo, pos, msg) =>
Some((strNo, pos, s"failed to parse Css literal: $msg"))
}
// FIXME: Unify these three implementations, and use quasiquotes
def cssClassContextMacro(c: BlackboxContext)(
exprs: c.Expr[ForcedConversion[CssClass]]*): c.Expr[CssClass] = {
import c.universe._
c.prefix.tree match {
case Select(Apply(_, List(Apply(_, rawPart :: Nil))), _) =>
val Literal(Constant(className: String)) = rawPart
if(!className.matches("-?[_a-zA-Z]+[_a-zA-Z0-9-]*"))
c.abort(c.enclosingPosition, "this is not a valid CSS class identifier")
c.Expr(q"_root_.rapture.css.CssClass(_root_.scala.collection.immutable.Set($rawPart))")
}
}
def stylesheetContextMacro(c: BlackboxContext)(
exprs: c.Expr[Embed[CssStylesheet]]*): c.Expr[CssStylesheet] = {
import c.universe._
c.prefix.tree match {
case Select(Apply(_, List(Apply(_, rawParts))), _) =>
val text = rawParts.map { case Literal(Constant(part: String)) => part }
val listExprs = c.Expr[List[Embed[CssStylesheet]]](q"_root_.scala.List(..${exprs.map(_.tree).to[List]})")
def resolveEmbeddableName(name: String) = name match {
case "domId" => "#foo"
case "css" => "color: red;"
case "cssClass" => ".foo"
case "int" => "1"
case "double" => "1.0"
case _ => "null"
}
val substitutions: List[String] = listExprs.tree match {
case Apply(_, applications) =>
applications.map {
case Apply(Apply(TypeApply(Select(_, _), _), _), List(Select(_, name))) => resolveEmbeddableName(name.toString)
}
}
parseSource(text, substitutions, true).foreach {
case (n, offset, msg) =>
val oldPos = rawParts(n).asInstanceOf[Literal].pos
val newPos = oldPos.withPoint(oldPos.start + offset)
c.error(newPos, msg)
}
val listParts = c.Expr[List[String]](q"_root_.scala.List(..$rawParts)")
reify {
val sb = new StringBuilder
val textParts = listParts.splice.iterator
val expressions: Iterator[Embed[CssStylesheet]] = listExprs.splice.iterator
sb.append(textParts.next())
while (textParts.hasNext) {
sb.append(expressions.next.content)
sb.append(textParts.next)
}
CssParser.parseStylesheet(List(sb.toString), Nil)
}
}
}
def cssContextMacro(c: BlackboxContext)(
exprs: c.Expr[Embed[Css]]*): c.Expr[Css] = {
import c.universe._
import compatibility._
c.prefix.tree match {
case Select(Apply(_, List(Apply(_, rawParts))), _) =>
val text = rawParts.map { case Literal(Constant(part: String)) => part }
val listExprs = c.Expr[List[Embed[Css]]](
Apply(
Select(reify(List).tree, termName(c, "apply")),
exprs.map(_.tree).to[List]
))
def resolveEmbeddableName(name: String) = name match {
case "cssCss" => "color: red;"
case "cssInt" => "1"
case "cssDouble" => "1.0"
case _ => "null"
}
val substitutions: List[String] = listExprs.tree match {
case Apply(_, applications) =>
applications.map {
case Apply(Apply(TypeApply(Select(_, _), _), _), List(Select(_, name))) => resolveEmbeddableName(name.toString)
}
}
parseSource(text, substitutions, false).foreach {
case (n, offset, msg) =>
val oldPos = rawParts(n).asInstanceOf[Literal].pos
val newPos = oldPos.withPoint(oldPos.start + offset)
c.error(newPos, msg)
}
val listParts = c.Expr[List[String]](q"_root_.scala.List(..$rawParts)")
reify {
val sb = new StringBuilder
val textParts = listParts.splice.iterator
val expressions: Iterator[Embed[Css]] = listExprs.splice.iterator
sb.append(textParts.next())
while (textParts.hasNext) {
sb.append(expressions.next.content)
sb.append(textParts.next)
}
CssParser.parse(List(sb.toString), Nil)
}
}
}
}
private[css] class CssStrings(sc: StringContext) {
class CssContext() {
def apply(exprs: Embed[Css]*): Css = macro CssMacros.cssContextMacro
}
class CssClassContext() {
def apply(exprs: Nothing*): CssClass = macro CssMacros.cssClassContextMacro
}
class StylesheetContext() {
def apply(exprs: Embed[CssStylesheet]*): CssStylesheet = macro CssMacros.stylesheetContextMacro
}
val css = new CssContext()
val cls = new CssClassContext()
val cssStylesheet = new StylesheetContext()
}
================================================
FILE: css/shared/src/main/scala/rapture/css/css.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.css
import rapture.dom._
import rapture.core._
import scala.collection.immutable.ListMap
object Css {
implicit def stringSerializer: StringSerializer[Css] = new StringSerializer[Css] {
def serialize(css: Css): String = css.content
}
}
case class Css(properties: ListMap[String, String]) {
def content = properties.map { case (k, v) => s"$k: $v;" }.mkString(" ")
override def toString = s"""css${"\"" * 3}$content${"\"" * 3}"""
def +(css: Css) = Css(properties ++ css.properties)
}
object CssStylesheet {
implicit def stringSerializer: StringSerializer[CssStylesheet] = new StringSerializer[CssStylesheet] {
def serialize(css: CssStylesheet): String = css.content
}
}
case class CssStylesheet(rules: List[CssRule]) {
override def toString = s"""cssStylesheet${"\"" * 3}$content${"\"" * 3}"""
def content = rules.mkString("\n")
}
object DomId {
def auto(implicit assignedName: AssignedName) = DomId(assignedName.name)
}
case class DomId(id: String) {
override def toString = s"#$id"
}
object CssClass {
def auto(implicit assignedName: AssignedName) = CssClass(Set(assignedName.name))
val empty = CssClass(Set())
}
case class CssClass(classes: Set[String]) {
def +(cssClass: CssClass): CssClass = CssClass(classes ++ cssClass.classes)
def asString = classes.mkString(" ")
override def toString = classes.mkString(".", ".", "")
}
object CssEmbed {
implicit def embedCssClass(cssClass: CssClass): CssEmbed = CssEmbed(cssClass.classes.mkString(".", ".", ""))
implicit def embedDomId(domId: DomId): CssEmbed = CssEmbed(s"#${domId.id}")
}
case class CssEmbed(content: String)
object Embeddable {
implicit val domId: Embeddable[DomId, CssStylesheet] = new Embeddable[DomId, CssStylesheet] { def embed(value: DomId): String = s"#${value.id}" }
implicit val cssClass: Embeddable[CssClass, CssStylesheet] = new Embeddable[CssClass, CssStylesheet] {
def embed(value: CssClass): String = value.classes.mkString(".", ".", "")
}
implicit val domTag: Embeddable[Tag[_, _, _], CssStylesheet] = new Embeddable[Tag[_, _, _], CssStylesheet] {
def embed(value: Tag[_, _, _]): String = value.tagName.toLowerCase
}
implicit val css: Embeddable[Css, CssStylesheet] = new Embeddable[Css, CssStylesheet] {
def embed(value: Css): String = value.content
}
implicit val string: Embeddable[String, CssStylesheet] = new Embeddable[String, CssStylesheet] {
def embed(value: String): String = value
}
implicit val int: Embeddable[Int, CssStylesheet] = new Embeddable[Int, CssStylesheet] {
def embed(value: Int): String = value.toString
}
implicit val double: Embeddable[Double, CssStylesheet] = new Embeddable[Double, CssStylesheet] {
def embed(value: Double): String = value.toString
}
implicit val cssString: Embeddable[String, Css] = new Embeddable[String, Css] {
def embed(value: String): String = value
}
implicit val cssInt: Embeddable[Int, Css] = new Embeddable[Int, Css] {
def embed(value: Int): String = value.toString
}
implicit val cssDouble: Embeddable[Double, Css] = new Embeddable[Double, Css] {
def embed(value: Double): String = value.toString
}
implicit val cssCss: Embeddable[Css, Css] = new Embeddable[Css, Css] {
def embed(value: Css): String = value.content
}
}
trait Embeddable[-From, +To] { def embed(value: From): String }
object Embed {
implicit def embed[From, To](value: From)(implicit embeddable: Embeddable[From, To]): Embed[To] = Embed(embeddable.embed(value))
}
case class Embed[To](content: String)
================================================
FILE: css/shared/src/main/scala/rapture/css/model.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.css
import rapture.core._
sealed trait CssRule
case class CssCharset(encoding: String) extends CssRule {
override def toString = s"@charset '$encoding';"
}
case class CssFontFace(properties: Css) extends CssRule {
override def toString = s"@font-face { ${properties.content} }"
}
case class CssImport(href: String, media: String) extends CssRule {
override def toString = s"@import url('$href') $media;"
}
case class CssMedia(cssRules: List[CssRule], media: String) extends CssRule {
override def toString = s"@media $media { ${cssRules.mkString(" ")} }"
}
case class CssPage(selectorText: String, properties: Css) extends CssRule {
override def toString = s"@page $selectorText { ${properties.content} }"
}
case class CssStyle(selectorText: String, properties: Css) extends CssRule {
override def toString = s"$selectorText { ${properties.content} }"
}
case class CssUnknown(text: String) extends CssRule {
override def toString = text
}
================================================
FILE: css/shared/src/main/scala/rapture/css/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.css
import language.implicitConversions
object `package` {
implicit def cssStringContext(sc: StringContext): CssStrings = new CssStrings(sc)
}
================================================
FILE: css/shared/src/main/scala/rapture/css/properties.scala
================================================
package rapture.css
object Properties {
// List of properties supported by Firefox
val all = Set(
"align-content",
"align-items",
"align-self",
"alignment-adjust",
"alignment-baseline",
"anchor-point",
"animation",
"animation-delay",
"animation-direction",
"animation-duration",
"animation-fill-mode",
"animation-iteration-count",
"animation-name",
"animation-play-state",
"animation-timing-function",
"appearance",
"azimuth",
"backface-visibility",
"background",
"background-attachment",
"background-blend-mode",
"background-clip",
"background-color",
"background-image",
"background-origin",
"background-position",
"background-repeat",
"background-size",
"baseline-shift",
"binding",
"bleed",
"bookmark-label",
"bookmark-level",
"bookmark-state",
"bookmark-target",
"border",
"border-bottom",
"border-bottom-color",
"border-bottom-left-radius",
"border-bottom-right-radius",
"border-bottom-style",
"border-bottom-width",
"border-collapse",
"border-color",
"border-image",
"border-image-outset",
"border-image-repeat",
"border-image-slice",
"border-image-source",
"border-image-width",
"border-left",
"border-left-color",
"border-left-style",
"border-left-width",
"border-radius",
"border-right",
"border-right-color",
"border-right-style",
"border-right-width",
"border-spacing",
"border-style",
"border-top",
"border-top-color",
"border-top-left-radius",
"border-top-right-radius",
"border-top-style",
"border-top-width",
"border-width",
"bottom",
"box-decoration-break",
"box-shadow",
"box-sizing",
"break-after",
"break-before",
"break-inside",
"caption-side",
"clear",
"clip",
"color",
"color-profile",
"column-count",
"column-fill",
"column-gap",
"column-rule",
"column-rule-color",
"column-rule-style",
"column-rule-width",
"column-span",
"column-width",
"columns",
"content",
"counter-increment",
"counter-reset",
"crop",
"cue",
"cue-after",
"cue-before",
"cursor",
"direction",
"display",
"dominant-baseline",
"drop-initial-after-adjust",
"drop-initial-after-align",
"drop-initial-before-adjust",
"drop-initial-before-align",
"drop-initial-size",
"drop-initial-value",
"elevation",
"empty-cells",
"fit",
"fit-position",
"flex",
"flex-basis",
"flex-direction",
"flex-flow",
"flex-grow",
"flex-shrink",
"flex-wrap",
"float",
"float-offset",
"flow-from",
"flow-into",
"font",
"font-feature-settings",
"font-family",
"font-kerning",
"font-language-override",
"font-size",
"font-size-adjust",
"font-stretch",
"font-style",
"font-synthesis",
"font-variant",
"font-variant-alternates",
"font-variant-caps",
"font-variant-east-asian",
"font-variant-ligatures",
"font-variant-numeric",
"font-variant-position",
"font-weight",
"grid",
"grid-area",
"grid-auto-columns",
"grid-auto-flow",
"grid-auto-position",
"grid-auto-rows",
"grid-column",
"grid-column-end",
"grid-column-start",
"grid-row",
"grid-row-end",
"grid-row-start",
"grid-template",
"grid-template-areas",
"grid-template-columns",
"grid-template-rows",
"hanging-punctuation",
"height",
"hyphens",
"icon",
"image-orientation",
"image-rendering",
"image-resolution",
"inline-box-align",
"justify-content",
"left",
"letter-spacing",
"line-break",
"line-height",
"line-stacking",
"line-stacking-ruby",
"line-stacking-shift",
"line-stacking-strategy",
"list-style",
"list-style-image",
"list-style-position",
"list-style-type",
"margin",
"margin-bottom",
"margin-left",
"margin-right",
"margin-top",
"marker-offset",
"marks",
"marquee-direction",
"marquee-loop",
"marquee-play-count",
"marquee-speed",
"marquee-style",
"max-height",
"max-width",
"min-height",
"min-width",
"move-to",
"nav-down",
"nav-index",
"nav-left",
"nav-right",
"nav-up",
"object-fit",
"object-position",
"opacity",
"order",
"orphans",
"outline",
"outline-color",
"outline-offset",
"outline-style",
"outline-width",
"overflow",
"overflow-style",
"overflow-wrap",
"overflow-x",
"overflow-y",
"padding",
"padding-bottom",
"padding-left",
"padding-right",
"padding-top",
"page",
"page-break-after",
"page-break-before",
"page-break-inside",
"page-policy",
"pause",
"pause-after",
"pause-before",
"perspective",
"perspective-origin",
"pitch",
"pitch-range",
"play-during",
"position",
"presentation-level",
"punctuation-trim",
"quotes",
"region-break-after",
"region-break-before",
"region-break-inside",
"region-fragment",
"rendering-intent",
"resize",
"rest",
"rest-after",
"rest-before",
"richness",
"right",
"rotation",
"rotation-point",
"ruby-align",
"ruby-overhang",
"ruby-position",
"ruby-span",
"shape-image-threshold",
"shape-inside",
"shape-margin",
"shape-outside",
"size",
"speak",
"speak-as",
"speak-header",
"speak-numeral",
"speak-punctuation",
"speech-rate",
"stress",
"string-set",
"tab-size",
"table-layout",
"target",
"target-name",
"target-new",
"target-position",
"text-align",
"text-align-last",
"text-decoration",
"text-decoration-color",
"text-decoration-line",
"text-decoration-skip",
"text-decoration-style",
"text-emphasis",
"text-emphasis-color",
"text-emphasis-position",
"text-emphasis-style",
"text-height",
"text-indent",
"text-justify",
"text-outline",
"text-overflow",
"text-shadow",
"text-size-adjust",
"text-space-collapse",
"text-transform",
"text-underline-position",
"text-wrap",
"top",
"transform",
"transform-origin",
"transform-style",
"transition",
"transition-delay",
"transition-duration",
"transition-property",
"transition-timing-function",
"unicode-bidi",
"vertical-align",
"visibility",
"voice-balance",
"voice-duration",
"voice-family",
"voice-pitch",
"voice-range",
"voice-rate",
"voice-stress",
"voice-volume",
"volume",
"white-space",
"widows",
"width",
"word-break",
"word-spacing",
"word-wrap",
"z-index"
)
}
================================================
FILE: css/shared/src/main/scala/rapture/css/validator.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.css
import rapture.core._
import com.steadystate.css.parser._
import org.w3c.css.sac._
import org.w3c.dom.css._
import java.io._
import scala.collection.immutable.ListMap
object CssParser {
case class ValidationException(strNo: Int, pos: Int, msg: String) extends Exception
def parseStylesheet(parts: List[String], substitutions: List[String]): CssStylesheet = {
val errHandler = new ErrorHandler {
def stringNo(c: Int): (Int, Int) =
parts.zip(substitutions).map { case (p, s) => p.length + s.length }.foldLeft(0 -> 0) { case ((sum, count), n) => if(sum > c) (sum, count) else (sum + n, count + 1) }
def error(e: CSSParseException) = {
val c = e.getColumnNumber - 1
val (sum, cnt) = stringNo(c)
throw ValidationException(cnt, c - sum, e.getMessage)
}
def fatalError(e: CSSParseException) = error(e)
def warning(e: CSSParseException) = error(e)
}
val source = new InputSource(new StringReader(parts.zip(substitutions :+ "").map { case (k, v) => k+v }.mkString))
val parser = new CSSOMParser(new SACParserCSS3())
parser.setErrorHandler(errHandler)
val stylesheet = CssStylesheet(convertStylesheet(parser.parseStyleSheet(source, null, null)))
stylesheet.rules.foreach(checkRule)
stylesheet
}
def checkRule(cssRule: CssRule): Unit = cssRule match {
case CssFontFace(css) => checkProperties(css)
case CssMedia(rules, _) => rules.foreach(checkRule)
case CssPage(_, css) => checkProperties(css)
case CssStyle(_, css) => checkProperties(css)
case _ => ()
}
def parse(parts: List[String], substitutions: List[String]): Css = {
val errHandler = new ErrorHandler {
def stringNo(c: Int): (Int, Int) =
parts.zip(substitutions).map { case (p, s) => p.length + s.length }.foldLeft(0 -> 0) { case ((sum, count), n) => if(sum > c) (sum, count) else (sum + n, count + 1) }
def error(e: CSSParseException) = {
val c = e.getColumnNumber - 1
val (sum, cnt) = stringNo(c)
throw ValidationException(cnt, c - sum, e.getMessage)
}
def fatalError(e: CSSParseException) = error(e)
def warning(e: CSSParseException) = error(e)
}
val source = new InputSource(new StringReader(parts.zip(substitutions :+ "").map { case (k, v) => k+v }.mkString))
val parser = new CSSOMParser(new SACParserCSS3())
parser.setErrorHandler(errHandler)
val styles = convertStyleDeclaration(parser.parseStyleDeclaration(source))
checkProperties(styles)
styles
}
def checkProperties(css: Css) = {
var prefixes = List("-webkit-", "-moz-", "-ms-", "-o-")
for((k, v) <- css.properties) if (!prefixes.exists(k.startsWith) && !Properties.all.contains(k)) throw ValidationException(0, 0, s"invalid CSS attribute '$k'")
}
def convertStylesheet(cssStylesheet: CSSStyleSheet): List[CssRule] = {
val rules = cssStylesheet.getCssRules()
(0 until rules.getLength).map { r => convertRule(rules.item(r)) }.to[List]
}
def convertRule(rule: CSSRule): CssRule = rule match {
case rule: CSSCharsetRule => CssCharset(rule.getEncoding)
case rule: CSSFontFaceRule => CssFontFace(convertStyleDeclaration(rule.getStyle))
case rule: CSSImportRule => CssImport(rule.getHref, rule.getMedia.getMediaText)
case rule: CSSMediaRule =>
val rules = rule.getCssRules
val convertedRules = (0 until rules.getLength).map { r => convertRule(rules.item(r)) }.to[List]
CssMedia(convertedRules, rule.getMedia.getMediaText)
case rule: CSSPageRule => CssPage(rule.getSelectorText, convertStyleDeclaration(rule.getStyle))
case rule: CSSStyleRule => CssStyle(rule.getSelectorText, convertStyleDeclaration(rule.getStyle))
case rule: CSSUnknownRule => CssUnknown(rule.getCssText)
}
def convertStyleDeclaration(styleDecl: CSSStyleDeclaration): Css = {
val decls = (0 until styleDecl.getLength).map(styleDecl.item(_)).map { p => p -> styleDecl.getPropertyValue(p) }
Css(ListMap(decls: _*))
}
}
================================================
FILE: css-test/shared/src/test/scala/rapture/css-test/tests.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.css.test
import rapture.core._
import rapture.css._
import rapture.html._
import rapture.test._
class TestRun extends Programme {
include(CssTests)
}
object CssTests extends TestSuite {
val `Embed ID in CSS` = test {
val identifier = DomId.auto
cssStylesheet"""$identifier { color: red; }"""
} returns cssStylesheet"""#identifier { color: red; }"""
val `Embed class in CSS` = test {
val identifier = CssClass.auto
cssStylesheet"""$identifier { color: red; }"""
} returns cssStylesheet""".identifier { color: red; }"""
val `Embed properties in CSS stylesheet` = test {
val properties = css"border-width: 1px; color: red"
cssStylesheet""".class { display: block; $properties }"""
} returns cssStylesheet""".class { display: block; border-width: 1px; color: red; }"""
val `Embed string in CSS` = test {
val color = "red"
css"color: $color"
}
val `Embed HTML tag in CSS stylesheet` = test {
import htmlSyntax._
cssStylesheet"""$Div { color: red; }"""
} returns cssStylesheet"""div { color: red; }"""
val `Check stylesheet well-formedness` = test {
cssStylesheet"""div { color: red; }"""
} returns cssStylesheet"""div { color: red; }"""
}
================================================
FILE: csv/shared/src/main/scala/rapture/csv/csv.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.csv
import rapture.core._
import rapture.io._
import rapture.uri._
import rapture.fs._
import rapture.codec._
import encodings.`UTF-8`._
import language.experimental.macros
object ReadCsvHeader {
implicit val readCsvHeader: ReadCsvHeader = ReadCsvHeader(true)
}
case class ReadCsvHeader(header: Boolean)
object CsvTest {
import csvBackends.simple._
def main(args: Seq[String]) = Csv.parse(uri"file:///home/jpretty/test.csv")
}
case class CsvParseException(line: Int, col: Int) extends RuntimeException {
override def getMessage = s"""parse error: expected `"`"""
}
sealed trait CsvGetException extends RuntimeException
case class CsvMissingValue(col: Int) extends CsvGetException {
override def getMessage = s"missing value: Column $col does not exist"
}
case class CsvTypeMismatch(typeName: String, col: Int) extends CsvGetException {
override def getMessage = s"type mismatch: Could not read value of type $typeName in column $col"
}
trait `Csv.parse` extends MethodConstraint
trait `CsvRow#as` extends MethodConstraint
trait `Csv#mapAs` extends MethodConstraint
trait `CsvCell#as` extends MethodConstraint
class KeyedCsvRow(val csvRow: CsvRow, val keys: Map[String, Int]) {
def apply(key: String): CsvCell = csvRow.apply(keys(key))
}
class CsvRow(val elems: Seq[String]) {
def apply(idx: Int): CsvCell = CsvCell(elems(idx), idx)
def as[T](implicit mode: Mode[`CsvRow#as`], extractor: CsvRowExtractor[T]): mode.Wrap[T, CsvGetException] =
extractor.extract(elems, mode)
override def toString = elems.mkString("\"", "\",\"", "\"")
}
object CsvRowExtractor {
implicit def generateExtractor[T]: CsvRowExtractor[T] = macro Macros.extractorMacro[T]
}
trait CsvRowExtractor[T] {
def extract(values: Seq[String], mode: Mode[_]): mode.Wrap[T, CsvGetException]
}
case class BadLength(len: Int) extends Exception("Bad length: " + len)
object CsvCellExtractor {
implicit val stringExtractor: CsvCellExtractor[String] = new CsvCellExtractor[String] {
type ExceptionType = CsvGetException
def extract(value: String, c: Int, mode: Mode[_]): mode.Wrap[String, CsvGetException] =
mode.wrap(value)
}
implicit val intExtractor: CsvCellExtractor[Int] = new CsvCellExtractor[Int] {
type ExceptionType = CsvGetException
def extract(value: String, c: Int, mode: Mode[_]): mode.Wrap[Int, CsvGetException] =
mode.wrap {
try value.toInt
catch { case e: Exception => mode.exception(CsvTypeMismatch("integer", c)) }
}
}
implicit val doubleExtractor: CsvCellExtractor[Double] = new CsvCellExtractor[Double] {
type ExceptionType = CsvGetException
def extract(value: String, c: Int, mode: Mode[_]): mode.Wrap[Double, CsvGetException] =
mode.wrap {
try value.toDouble
catch { case e: Exception => mode.exception(CsvTypeMismatch("double", c)) }
}
}
implicit val charExtractor: CsvCellExtractor[Char] = new CsvCellExtractor[Char] {
type ExceptionType = BadLength
def extract(value: String, c: Int, mode: Mode[_]): mode.Wrap[Char, CsvGetException with BadLength] = mode.wrap {
if (value.length == 1) value.head
else {
mode.exception(CsvTypeMismatch("character", c))
'\u0000'
}
}
}
}
trait CsvCellExtractor[T] {
type ExceptionType <: Exception
def extract(value: String, c: Int, mode: Mode[_]): mode.Wrap[T, CsvGetException with ExceptionType]
}
case class CsvCell(value: String, col: Int) {
def as[T](mode: Mode[`CsvCell#as`])(ext: CsvCellExtractor[T]): mode.Wrap[T, CsvGetException with ext.ExceptionType] =
ext.extract(value, col, mode)
override def toString = value
}
case class Csv(rows: Vector[CsvRow]) extends Seq[CsvRow] {
def iterator = rows.iterator
def apply(idx: Int) = rows(idx)
def length = rows.length
override def toString = rows.take(4).mkString("\n") + (if (rows.length > 4) "\n..." else "")
def mapAs[T: CsvRowExtractor](implicit mode: Mode[`Csv#mapAs`]): mode.Wrap[Seq[T], CsvGetException] = mode.wrap {
rows.map { row =>
mode.unwrap(?[CsvRowExtractor[T]].extract(row.elems, mode))
}
}
}
object Csv {
def parse[Res](resource: Res)(implicit mode: Mode[`Csv.parse`],
reader: Reader[Res, String],
backend: CsvBackend): mode.Wrap[Csv, CsvParseException] = mode.wrap {
Csv(reader.input(resource).to[Vector].zipWithIndex.map {
case (ln, idx) =>
new CsvRow(mode.unwrap(backend.parseRow(ln, idx, mode)))
})
}
def extractor[T: CsvCellExtractor] = ?[CsvCellExtractor[T]]
}
trait CsvBackend { def parseRow(s: String, line: Int, mode: Mode[_]): mode.Wrap[Seq[String], CsvParseException] }
object csvBackends {
object simple {
implicit val simpleBackend: CsvBackend = new CsvBackend {
def parseRow(s: String, line: Int, mode: Mode[_]): mode.Wrap[Seq[String], CsvParseException] = mode.wrap {
var cells: Vector[String] = Vector()
var cur = 0
var quoted = false
var expectingQuote = false
var sb = new StringBuilder
while (cur < s.length) {
s(cur) match {
case '"' =>
if (sb.isEmpty && !quoted) {
quoted = true
} else if (quoted) {
quoted = false
} else if (expectingQuote) {
sb.append('"')
expectingQuote = false
} else expectingQuote = true
cur += 1
case _ if expectingQuote =>
mode.exception(CsvParseException(line, cells.length))
case ',' if !quoted =>
cells = cells :+ sb.toString.trim
sb = new StringBuilder
cur += 1
case other =>
sb.append(other)
cur += 1
}
}
cells :+ sb.toString.trim
}
}
}
}
================================================
FILE: csv/shared/src/main/scala/rapture/csv/macros.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.csv
import rapture.core._
import rapture.base._
object Macros {
def extractorMacro[T: c.WeakTypeTag](c: BlackboxContext): c.Expr[CsvRowExtractor[T]] = {
import c.universe._
import compatibility._
val cellExtractor = typeOf[CsvCellExtractor[_]].typeSymbol.asType.toTypeConstructor
require(weakTypeOf[T].typeSymbol.asClass.isCaseClass)
val params = declarations(c)(weakTypeOf[T]).collect {
case m: MethodSymbol if m.isCaseAccessor => m.asMethod
}.zipWithIndex.map {
case (p, i) =>
val searchType = appliedType(cellExtractor, List(p.returnType))
val inferredImplicit = c.inferImplicitValue(searchType, false, false)
q"mode.unwrap($inferredImplicit.extract(values($i), $i, mode))"
}
val construction = c.Expr[T](q"new ${weakTypeOf[T]}(..$params)")
reify {
new CsvRowExtractor[T] {
def extract(values: Seq[String], mode: Mode[_]): mode.Wrap[T, CsvGetException] =
mode.wrap(construction.splice)
}
}
}
}
================================================
FILE: currency/shared/src/main/scala/rapture/currency/currency.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.currency
import rapture.core._
object Currency {
trait Key
case class Evidence[C <: Currency.Key](currency: Currency { type Key = C })
object Arithmetic extends Arithmetic_1 {
implicit def sameCurrencies[C <: Currency.Key]: Arithmetic[Money[C], Money[C]] { type Return = Money[C] } =
new Arithmetic[Money[C], Money[C]] {
type Return = Money[C]
def add(left: Money[C], right: Money[C]): Money[C] = Money(left.currency, left.amount + right.amount)
}
implicit def currencyBaskets[C <: Currency.Key, C2 <: Currency.Key]
: Arithmetic[CurrencyBasket[C], CurrencyBasket[C2]] { type Return = CurrencyBasket[C with C2] } =
new Arithmetic[CurrencyBasket[C], CurrencyBasket[C2]] {
type Return = CurrencyBasket[C with C2]
def add(left: CurrencyBasket[C], right: CurrencyBasket[C2]): CurrencyBasket[C with C2] =
CurrencyBasket[C with C2](left.amounts.foldLeft(right.amounts) {
case (acc, (k, v)) =>
acc.updated(k, acc.get(k).getOrElse(0.0) + v)
})
}
implicit def currencyBasketAndMoney[C <: Currency.Key, C2 <: Currency.Key]
: Arithmetic[CurrencyBasket[C], Money[C2]] { type Return = CurrencyBasket[C with C2] } =
new Arithmetic[CurrencyBasket[C], Money[C2]] {
type Return = CurrencyBasket[C with C2]
def add(left: CurrencyBasket[C], right: Money[C2]): CurrencyBasket[C with C2] =
CurrencyBasket[C with C2](
left.amounts.updated(right.currency, left.amounts.get(right.currency).getOrElse(0.0) + right.amount))
}
implicit def moneyAndCurrencyBasket[C <: Currency.Key, C2 <: Currency.Key]
: Arithmetic[Money[C], CurrencyBasket[C2]] { type Return = CurrencyBasket[C with C2] } =
new Arithmetic[Money[C], CurrencyBasket[C2]] {
type Return = CurrencyBasket[C with C2]
def add(left: Money[C], right: CurrencyBasket[C2]): CurrencyBasket[C with C2] =
CurrencyBasket[C with C2](
right.amounts.updated(left.currency, right.amounts.get(left.currency).getOrElse(0.0) + left.amount))
}
}
trait Arithmetic_1 {
implicit def differentCurrencies[C <: Currency.Key, C2 <: Currency.Key]
: Arithmetic[Money[C], Money[C2]] { type Return = CurrencyBasket[C with C2] } =
new Arithmetic[Money[C], Money[C2]] {
type Return = CurrencyBasket[C with C2]
def add(left: Money[C], right: Money[C2]): CurrencyBasket[C with C2] =
if (left.currency == right.currency)
CurrencyBasket[C with C2](Map(left.currency -> (left.amount + right.amount)))
else
CurrencyBasket[C with C2](Map(left.currency -> left.amount, right.currency -> right.amount))
}
}
trait Arithmetic[T1, T2] {
type Return
def add(left: T1, right: T2): Return
}
}
case class Currency(code: String, name: String, decimalPlaces: Int, prefix: String, suffix: String) {
type Key <: Currency.Key
override def hashCode = code.hashCode
override def toString = code
override def equals(that: Any) = that match {
case that: Currency if that.code == code => true
case _ => false
}
def apply[N: Numeric](amount: N): Money[Key] = Money[Key](this, implicitly[Numeric[N]].toDouble(amount))
}
case class InvalidMoney(currency: Currency)
extends Exception(s"this is not a valid money value of currency ${currency.code}")
object Money {
implicit def moneySerializer[C <: Currency.Key]: StringSerializer[Money[C]] = new StringSerializer[Money[C]] {
def serialize(m: Money[C]) = {
implicit val df: DecimalFormat = DecimalPlaces(m.currency.decimalPlaces)
s"${String(m.amount)}${m.currency.code}"
}
}
implicit def moneyParser[C <: Currency.Key](
implicit ev: Currency.Evidence[C]): StringParser[Money[C]] { type Throws = InvalidMoney } =
new StringParser[Money[C]] {
type Throws = InvalidMoney
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Money[C], InvalidMoney] = mode.wrap {
if (s.substring(s.length - 3) == ev.currency.code) {
try Money[C](ev.currency, s.dropRight(3).toDouble)
catch { case e: Exception => throw InvalidMoney(ev.currency) }
} else throw InvalidMoney(ev.currency)
}
}
}
case class Money[C <: Currency.Key](currency: Currency { type Key = C }, amount: Double) {
def unary_- = Money[C](currency, -amount)
def +[C2 <: Currency.Key](m: Money[C2])(
implicit arithmetic: Currency.Arithmetic[Money[C], Money[C2]]): arithmetic.Return =
arithmetic.add(this, m)
def -[C2 <: Currency.Key](m: Money[C2])(
implicit arithmetic: Currency.Arithmetic[Money[C], Money[C2]]): arithmetic.Return =
arithmetic.add(this, -m)
def *[N: Numeric](times: N): Money[C] = Money(currency, amount * implicitly[Numeric[N]].toDouble(times))
def /[N: Numeric](divisor: N): Money[C] = *(1.0 / implicitly[Numeric[N]].toDouble(divisor))
def <(m: Money[C]) = amount < m.amount
def <=(m: Money[C]) = amount <= m.amount
def >(m: Money[C]) = amount > m.amount
def >=(m: Money[C]) = amount >= m.amount
override def toString = {
implicit val df: DecimalFormat = DecimalPlaces(currency.decimalPlaces)
s"${currency.prefix}${String(amount)}${currency.suffix}"
}
}
case class CurrencyBasket[C <: Currency.Key](amounts: Map[Currency, Double]) {
def +[M](m: M)(implicit arithmetic: Currency.Arithmetic[CurrencyBasket[C], M]): arithmetic.Return =
arithmetic.add(this, m)
def unary_- = CurrencyBasket[C](amounts.mapValues(-_))
def *[N: Numeric](times: N): CurrencyBasket[C] =
CurrencyBasket(amounts.mapValues(_ * implicitly[Numeric[N]].toDouble(times)))
def /[N: Numeric](divisor: N): CurrencyBasket[C] = *(1.0 / implicitly[Numeric[N]].toDouble(divisor))
def apply[C2 >: C <: Currency.Key](implicit ev: Currency.Evidence[C2]): Money[C2] =
Money[C2](ev.currency, amounts(ev.currency))
override def toString =
amounts.map {
case (currency, value) =>
implicit val df: DecimalFormat = DecimalPlaces(currency.decimalPlaces)
s"${String(value)}${currency.code}"
}.mkString(", ")
}
================================================
FILE: currency/shared/src/main/scala/rapture/currency/iso.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.currency
/* Includes the twenty most-traded currencies, as listed on Wikipedia, with the exception of Turkish Lira, because
its ISO 4217 code is `TRY`, which is an inconvenient identifier. */
object currencies {
object Gbp extends Currency("GBP", "Pound sterling", 2, "£", "") {
type Key = Gbp
implicit val currencyEvidence: Currency.Evidence[Gbp] = Currency.Evidence(this)
}
trait Gbp extends Currency.Key
object Usd extends Currency("USD", "United States dollar", 2, "$", "") {
type Key = Usd
implicit val currencyEvidence: Currency.Evidence[Usd] = Currency.Evidence(this)
}
trait Usd extends Currency.Key
object Eur extends Currency("EUR", "Euros", 2, "€", "") {
type Key = Eur
implicit val currencyEvidence: Currency.Evidence[Eur] = Currency.Evidence(this)
}
trait Eur extends Currency.Key
object Jpy extends Currency("JPY", "Japanese yen", 2, "¥", "") {
type Key = Jpy
implicit val currencyEvidence: Currency.Evidence[Jpy] = Currency.Evidence(this)
}
trait Jpy extends Currency.Key
object Aud extends Currency("AUD", "Australian dollar", 2, "$", "") {
type Key = Aud
implicit val currencyEvidence: Currency.Evidence[Aud] = Currency.Evidence(this)
}
trait Aud extends Currency.Key
object Chf extends Currency("CHF", "Swiss franc", 2, "Fr", "") {
type Key = Chf
implicit val currencyEvidence: Currency.Evidence[Chf] = Currency.Evidence(this)
}
trait Chf extends Currency.Key
object Cad extends Currency("CAD", "Canadian dollar", 2, "$", "") {
type Key = Cad
implicit val currencyEvidence: Currency.Evidence[Cad] = Currency.Evidence(this)
}
trait Cad extends Currency.Key
object Mxn extends Currency("MXN", "Mexican peso", 2, "$", "") {
type Key = Mxn
implicit val currencyEvidence: Currency.Evidence[Mxn] = Currency.Evidence(this)
}
trait Mxn extends Currency.Key
object Cny extends Currency("CNY", "Chinese yuan", 2, "¥", "") {
type Key = Cny
implicit val currencyEvidence: Currency.Evidence[Cny] = Currency.Evidence(this)
}
trait Cny extends Currency.Key
object Nzd extends Currency("NZD", "New Zealand dollar", 2, "$", "") {
type Key = Nzd
implicit val currencyEvidence: Currency.Evidence[Nzd] = Currency.Evidence(this)
}
trait Nzd extends Currency.Key
object Sek extends Currency("SEK", "Swedish krona", 2, "kr", "") {
type Key = Sek
implicit val currencyEvidence: Currency.Evidence[Sek] = Currency.Evidence(this)
}
trait Sek extends Currency.Key
object Rub extends Currency("RUB", "Russian ruble", 2, "₽", "") {
type Key = Rub
implicit val currencyEvidence: Currency.Evidence[Rub] = Currency.Evidence(this)
}
trait Rub extends Currency.Key
object Hkd extends Currency("HKD", "Hong Kong dollar", 2, "$", "") {
type Key = Hkd
implicit val currencyEvidence: Currency.Evidence[Hkd] = Currency.Evidence(this)
}
trait Hkd extends Currency.Key
object Nok extends Currency("NOK", "Norwegian krone", 2, "kr", "") {
type Key = Nok
implicit val currencyEvidence: Currency.Evidence[Nok] = Currency.Evidence(this)
}
trait Nok extends Currency.Key
object Sgd extends Currency("SGD", "Singapore dollar", 2, "$", "") {
type Key = Sgd
implicit val currencyEvidence: Currency.Evidence[Sgd] = Currency.Evidence(this)
}
trait Sgd extends Currency.Key
object Krw extends Currency("KRW", "South Korean won", 2, "₩", "") {
type Key = Krw
implicit val currencyEvidence: Currency.Evidence[Krw] = Currency.Evidence(this)
}
trait Krw extends Currency.Key
object Zar extends Currency("ZAR", "South African Rand", 2, "R", "") {
type Key = Zar
implicit val currencyEvidence: Currency.Evidence[Zar] = Currency.Evidence(this)
}
trait Zar extends Currency.Key
object Brl extends Currency("BRL", "Brazilian real", 2, "R$", "") {
type Key = Brl
implicit val currencyEvidence: Currency.Evidence[Brl] = Currency.Evidence(this)
}
trait Brl extends Currency.Key
object Inr extends Currency("INR", "Indian rupee", 2, "₹", "") {
type Key = Inr
implicit val currencyEvidence: Currency.Evidence[Inr] = Currency.Evidence(this)
}
trait Inr extends Currency.Key
}
================================================
FILE: data/shared/src/main/scala/rapture/data/ast.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.data
import rapture.core._
object DataTypes {
sealed class DataType(val name: String)
case object Number extends DataType("number")
case object String extends DataType("string")
case object Null extends DataType("null")
case object Boolean extends DataType("boolean")
case object Array extends DataType("array")
case object Object extends DataType("object")
case object Scalar extends DataType("scalar")
case object Container extends DataType("container")
case object Any extends DataType("any")
}
@implicitNotFound(msg = "Cannot find ${Ast} parser for values of type ${Source}")
trait Parser[-Source, +Ast <: DataAst] {
val ast: Ast
def parse(s: Source): Option[Any]
}
trait DataAst {
/** Dereferences the named element within the JSON object. */
def dereferenceObject(obj: Any, element: String): Any =
getObject(obj)(element)
/** Returns at `Iterator[String]` over the names of the elements in the JSON object. */
def getKeys(obj: Any): Iterator[String] =
getObject(obj).keys.iterator
/** Gets the indexed element from the parsed JSON array. */
def dereferenceArray(array: Any, element: Int): Any =
getArray(array)(element)
/** Tests if the element represents an `Object` */
def isObject(any: Any): Boolean
/** Tests if the element represents an `Array` */
def isArray(any: Any): Boolean
def isNull(any: Any): Boolean
/** Extracts a JSON object as a `Map[String, Any]` from the parsed JSON. */
def getObject(obj: Any): Map[String, Any]
def getChildren(obj: Any): Seq[Any] = {
val m = getObject(obj)
getKeys(obj).to[List] map m
}
def fromObject(obj: Map[String, Any]): Any
/** Extracts a JSON array as a `Seq[Any]` from the parsed JSON. */
def getArray(array: Any): Seq[Any]
def fromArray(array: Seq[Any]): Any
def isScalar(any: Any): Boolean
def getString(any: Any): Any
def isString(any: Any): Boolean
def convert(any: Any, oldAst: DataAst): Any
}
trait MutableDataAst extends DataAst {
def setObjectValue(obj: Any, name: String, value: Any): Any
def setArrayValue(array: Any, index: Int, value: Any): Any
def removeObjectValue(obj: Any, name: String): Any
def addArrayValue(array: Any, value: Any): Any
}
================================================
FILE: data/shared/src/main/scala/rapture/data/context.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.data
import rapture.base._
import rapture.core._
object patternMatching {
object exactArrays {
implicit val implicitArrayMachingConfig = new ArrayMatchingConfig { def checkLengths = true }
}
object exactObjects {
implicit val implicitArrayMachingConfig = new ObjectMatchingConfig { def checkSizes = true }
}
object exact {
implicit val implicitArrayMachingConfig = new ObjectMatchingConfig with ArrayMatchingConfig {
def checkSizes = true
def checkLengths = true
}
}
}
object ArrayMatchingConfig {
implicit val ignoreByDefault = new ArrayMatchingConfig { def checkLengths = false }
}
object ObjectMatchingConfig {
implicit val ignoreByDefault = new ObjectMatchingConfig { def checkSizes = false }
}
trait ArrayMatchingConfig { def checkLengths: Boolean }
trait ObjectMatchingConfig { def checkSizes: Boolean }
abstract class DataContextMacros[+Data <: DataType[Data, DataAst], -AstType <: DataAst] {
def parseSource(s: List[String], stringsUsed: List[Boolean]): Option[(Int, Int, String)]
def dataCompanion(c: BlackboxContext): c.Expr[DataCompanion[Data, AstType]]
def contextMacro(c: BlackboxContext)(exprs: c.Expr[ForcedConversion[Data]]*)(
parser: c.Expr[Parser[String, AstType]]): c.Expr[Data] = {
import c.universe._
c.prefix.tree match {
case Select(Apply(Apply(_, List(Apply(_, rawParts))), _), _) =>
val ys = rawParts.to[List]
val text = rawParts map { case lit @ Literal(Constant(part: String)) => part }
val listExprs = c.Expr[List[ForcedConversion[Data]]](q"_root_.scala.List(..${exprs.map(_.tree).to[List]})")
val stringsUsed: List[Boolean] = listExprs.tree match {
case Apply(_, bs) =>
bs.map {
case Apply(Apply(TypeApply(Select(_, nme), _), _), _) => nme.toString == "forceStringConversion"
}
}
parseSource(text, stringsUsed) foreach {
case (n, offset, msg) =>
val oldPos = ys(n).asInstanceOf[Literal].pos
val newPos = oldPos.withPoint(oldPos.start + offset)
c.error(newPos, msg)
}
val listParts = c.Expr[List[ForcedConversion[Data]]](q"_root_.scala.List(..$rawParts)")
val comp = dataCompanion(c)
reify {
val sb = new StringBuilder
val textParts = listParts.splice.iterator
val expressions: Iterator[ForcedConversion[_]] = listExprs.splice.iterator
sb.append(textParts.next())
while (textParts.hasNext) {
sb.append(
comp.splice.construct(MutableCell(expressions.next.value), Vector())(parser.splice.ast).toBareString)
sb.append(textParts.next)
}
comp.splice.construct(MutableCell(parser.splice.parse(sb.toString).get), Vector())(parser.splice.ast)
}
}
}
}
class DataContext[+Data <: DataType[Data, DataAst], -AstType <: DataAst](companion: DataCompanion[Data, AstType],
sc: StringContext) {
protected def uniqueNonSubstring(s: String) = {
var cur, m = 0
s foreach { c =>
cur = if (c == '_') cur + 1 else 0
m = m max cur
}
"_" * (m + 1)
}
def unapplySeq[D <: DataType[D, DataAst]](data: D)(
implicit arrayMatching: ArrayMatchingConfig,
objectMatching: ObjectMatchingConfig,
parser: Parser[String, AstType]): Option[Seq[DataType[D, DataAst]]] =
try {
val placeholder = uniqueNonSubstring(sc.parts.mkString)
val PlaceholderNumber = (placeholder + "([0-9]+)" + placeholder).r
val count = Iterator.from(0)
val txt = sc.parts.reduceLeft(_ + s""""${placeholder}${count.next()}${placeholder}" """ + _)
val paths: Array[Vector[Either[Int, String]]] =
Array.fill[Vector[Either[Int, String]]](sc.parts.length - 1)(Vector())
val arrayLengths = new collection.mutable.HashMap[Vector[Either[Int, String]], Int]
val objectSizes = new collection.mutable.HashMap[Vector[Either[Int, String]], Int]
def extract(any: Any, path: Vector[Either[Int, String]]): Unit = {
// FIXME: Avoid using isScalar if possible
if (parser.ast.isScalar(any)) {
val ext = data.$extract(path).as[Any]
if (data.$extract(path).as[Any] != any) throw new Exception("Value doesn't match (1)")
} else if (parser.ast.isObject(any)) {
val obj = parser.ast.getObject(any)
objectSizes(path) = obj.size
obj foreach {
case (k, v) =>
if (parser.ast.isString(v)) parser.ast.getString(v) match {
case str: CharSequence =>
str match {
case PlaceholderNumber(n) =>
paths(n.toInt) = path :+ Right(k)
case _ => extract(v, path :+ Right(k))
}
} else extract(v, path :+ Right(k))
}
} else if (parser.ast.isArray(any)) {
val array = parser.ast.getArray(any)
if (arrayMatching.checkLengths) arrayLengths(path) = array.length
array.zipWithIndex foreach {
case (e, i) =>
if (parser.ast.isString(e)) parser.ast.getString(e) match {
case str: CharSequence =>
str match {
case PlaceholderNumber(n) =>
paths(n.toInt) = path :+ Left(i)
case _ => extract(e, path :+ Left(i))
}
} else extract(e, path :+ Left(i))
}
} else throw new Exception("Value doesn't match (2)")
}
extract(parser.parse(txt).get, Vector())
// Using a ListBuffer to work around SI-8947
val extractsBuffer = new collection.mutable.ListBuffer[D]
paths foreach { p =>
extractsBuffer += data.$extract(p)
}
val extracts = extractsBuffer.toList
extracts.foreach(_.$normalize)
val matchedArrayLengths = arrayLengths.forall {
case (p, len) =>
parser.ast.getArray(data.$extract(p).$normalize).length == len
}
val matchedObjectSizes = objectSizes.forall {
case (p, s) =>
if (objectMatching.checkSizes) parser.ast.getObject(data.$extract(p).$normalize).size == s
else parser.ast.getObject(data.$extract(p).$normalize).size >= 0
}
if (extracts.exists(_.$root.value == null) || !matchedArrayLengths || !matchedObjectSizes)
None
else Some(extracts)
} catch {
case e: Exception =>
None
}
}
================================================
FILE: data/shared/src/main/scala/rapture/data/data.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.data
import rapture.core._
import scala.util.Try
import language.dynamics
@implicitNotFound("Cannot find an implicit Formatter for ${AstType} data.")
trait Formatter[-AstType <: DataAst] {
type Out
def format(any: Any): Out
}
object DataCompanion { object Empty }
object serializedNames {
object inUnderscoreStyle {
def apply[V, D] = nameMapperImplicit[V, D]
implicit def nameMapperImplicit[V, D] = new NameMapper[V, D] {
def encode(name: String): String = name.flatMap {
case lower if lower.isLower => lower.toString
case upper if upper.isUpper => s"_$upper".toLowerCase
case other => other.toString
}
def decode(name: String): String = name.foldLeft(("", false)) {
case ((acc, _), '_') => (acc, true)
case ((acc, true), other) => (acc+other.toString.toUpperCase, false)
case ((acc, false), other) => (acc+other, false)
}._1
}
}
object inDashedStyle {
def apply[V, D] = nameMapperImplicit[V, D]
implicit def nameMapperImplicit[V, D] = new NameMapper[V, D] {
def encode(name: String): String = name.flatMap {
case lower if lower.isLower => lower.toString
case upper if upper.isUpper => s"-$upper".toLowerCase
case other => other.toString
}
def decode(name: String): String = name.foldLeft(("", false)) {
case ((acc, _), '-') => (acc, true)
case ((acc, true), other) => (acc+other.toString.toUpperCase, false)
case ((acc, false), other) => (acc+other, false)
}._1
}
}
object identical {
def apply[V, D] = nameMapperImplicit[V, D]
implicit def nameMapperImplicit[V, D] = new NameMapper[V, D] {
def encode(name: String): String = name
def decode(name: String): String = name
}
}
}
object NameMapper {
implicit def identityNameMapper[V, D]: NameMapper[V, D] = serializedNames.identical[V, D]
}
trait NameMapper[+Value, +Data] {
def encode(name: String): String
def decode(name: String): String
}
trait DataCompanion[+Type <: DataType[Type, DataAst], -AstType <: DataAst] {
type ParseMethodConstraint <: MethodConstraint
def empty(implicit ast: AstType) =
construct(MutableCell(ast.fromObject(Map())), Vector())
def construct(any: MutableCell, path: Vector[Either[Int, String]])(implicit ast: AstType): Type
def parse[Source: StringSerializer](s: Source)(implicit mode: Mode[ParseMethodConstraint],
parser: Parser[Source, AstType]): mode.Wrap[Type, ParseException] =
mode wrap {
construct(try MutableCell(parser.parse(s).get)
catch {
case e: NoSuchElementException => mode.exception(ParseException(String(s)))
},
Vector())(parser.ast)
}
def raw(value: Any)(implicit ast: AstType): Type =
construct(MutableCell(value), Vector())
def format[T <: DataType[T, AstType]](data: T)(implicit f: Formatter[_ <: AstType]): f.Out =
f.format(data.$normalize)
}
case class DynamicApplication[D](path: List[Either[Int, String]], application: ForcedConversion2[D])
object dictionaries {
object dynamic {
implicit val implicitDictionary: Dictionary[Nothing] = new Dictionary[Nothing](Nil)
}
}
object Dictionary {
implicit def stringToDefineParam[S <: String](s: S): DefineParam[s.type] = new DefineParam[s.type](s)
class DefineParam[-T <: String](val value: String)
def define[T <: String](params: DefineParam[T]*): Dictionary[T] = new Dictionary[T](params.map(_.value))
}
@implicitNotFound("the key ${S} is not in the dictionary")
class Dictionary[+S <: String](params: Seq[String])
case class DynamicPath[D](path: List[Either[Int, String]]) extends Dynamic {
def self = selectDynamic("self")(null)
def selectDynamic[S <: String](v: S)(implicit dictionary: Dictionary[v.type]) = DynamicPath[D](Right(v) :: path)
def applyDynamic[S <: String](v: String)(i: Int)(implicit dictionary: Dictionary[v.type]) = DynamicPath[D](Left(i) :: Right(v) :: path)
def apply(i: Int) = DynamicPath[D](Left(i) :: path)
def updateDynamic[S <: String](v: String)(value: ForcedConversion2[D])(implicit dictionary: Dictionary[v.type]) =
DynamicApplication(Right(v) :: path, value)
def update(i: Int, value: ForcedConversion2[D]) =
DynamicApplication(Left(i) :: path, value)
}
case class DynamicAccess[D](path: List[Either[Int, String]]) extends Dynamic {
def self = selectDynamic("self")
def selectDynamic(v: String) = DynamicAccess[D](Right(v) :: path)
def applyDynamic(v: String)(i: Int) = DynamicAccess[D](Left(i) :: Right(v) :: path)
def apply(i: Int) = DynamicAccess[D](Left(i) :: path)
}
case class MutableCell(var value: Any)
trait DynamicData[+T <: DynamicData[T, AstType], +AstType <: DataAst] extends Dynamic {
/** Assumes the Json object wraps a `Map`, and extracts the element `key`. */
def selectDynamic[S <: String](key: S)(implicit dictionary: Dictionary[key.type]): T = $deref(Right(key) +: $path)
def self = selectDynamic("self")(null)
//def applyDynamic(key: String)(i: Int = 0): T = $deref(Left(i) +: Right(key) +: $path)
def $deref($path: Vector[Either[Int, String]]): T
def $path: Vector[Either[Int, String]]
}
object DataType {
class DataClassOperations[T <: DataType[T, AstType], AstType <: DataAst](dataType: T) {
def ++[S <: DataType[S, Rep] forSome { type Rep }](b: S): T = {
val ast = dataType.$ast
def merge(a: Any, b: Any): Any = {
if (ast.isObject(a) && ast.isObject(b)) {
ast.fromObject(ast.getKeys(b).foldLeft(ast.getObject(a)) {
case (as, k) =>
as + (k -> {
if (as contains k) merge(as(k), ast.dereferenceObject(b, k)) else ast.dereferenceObject(b, k)
})
})
} else if (ast.isArray(a) && ast.isArray(b)) ast.fromArray(ast.getArray(a) ++ ast.getArray(b))
else b
}
val left = dataType.$normalize
val right = if (ast != b.$ast) ast.convert(b.$normalize, b.$ast.asInstanceOf[DataAst]) else b.$normalize
dataType.$wrap(merge(left, right), Vector())
}
def delete(pvs: (DynamicAccess[T] => DynamicAccess[_ <: DataType[T, _ <: AstType]])*): T = {
dataType.$wrap(pvs.foldLeft(dataType.$normalize) {
case (cur, pv) =>
val dPath = pv(DynamicAccess(Nil))
val ast = dataType.$ast
def nav(path: List[Either[Int, String]], dest: Any): Any = path match {
case Nil =>
???
case Right(next) :: Nil =>
ast.fromObject(ast.getObject(if(ast.isObject(dest)) dest else Map()) - next)
case Right(next) :: list =>
val d = try ast.dereferenceObject(dest, next)
catch { case e: Exception => ast.fromObject(Map()) }
val src = ast.getObject(if (ast.isObject(dest)) dest else Map())
ast.fromObject(src + ((next, nav(list, d))))
case Left(next) :: Nil =>
val src = if (ast.isArray(dest)) ast.getArray(dest) else Nil
ast.fromArray(src.slice(0, next) ++ src.slice(next + 1, src.length))
case Left(next) :: list =>
val d = try ast.dereferenceArray(dest, next)
catch { case e: Exception => ast.fromArray(List()) }
val src = if (ast.isArray(dest)) ast.getArray(dest) else Nil
ast.fromArray(src.padTo(next + 1, ast.fromObject(Map())).updated(next, nav(list, d)))
}
nav(dPath.path.reverse, cur)
})
}
def copy(pvs: (DynamicPath[T] => DynamicApplication[_ <: DataType[T, _ <: AstType]])*): T = {
dataType.$wrap(pvs.foldLeft(dataType.$normalize) {
case (cur, pv) =>
val dPath = pv(DynamicPath(Nil))
val ast = dataType.$ast
if (dPath.application.nothing) cur
else {
def nav(path: List[Either[Int, String]], dest: Any, v: Any): Any = path match {
case Nil =>
v
case Right(next) :: list =>
val d = try ast.dereferenceObject(dest, next)
catch { case e: Exception => ast.fromObject(Map()) }
val src = ast.getObject(if (ast.isObject(dest)) dest else Map())
ast.fromObject(src + ((next, nav(list, d, v))))
case Left(next) :: list =>
val d = try ast.dereferenceArray(dest, next)
catch { case e: Exception => ast.fromArray(List()) }
val src = if (ast.isArray(dest)) ast.getArray(dest) else Nil
ast.fromArray(src.padTo(next + 1, ast.fromObject(Map())).updated(next, nav(list, d, v)))
}
nav(dPath.path.reverse, cur, dPath.application.value)
}
})
}
}
}
trait DataType[+T <: DataType[T, AstType], +AstType <: DataAst] {
val $root: MutableCell
implicit def $ast: AstType
def $path: Vector[Either[Int, String]]
def $normalize: Any = doNormalize(false)
def $wrap(any: Any, $path: Vector[Either[Int, String]] = Vector()): T
def $deref($path: Vector[Either[Int, String]] = Vector()): T
def $extract($path: Vector[Either[Int, String]]): T
def \(key: String): T = $deref(Right(key) +: $path)
def \(index: Int): T = $deref(Left(index) +: $path)
def \\(key: String): T = $wrap($ast.fromArray(derefRecursive(key, $normalize)))
def toBareString: String
private def derefRecursive(key: String, any: Any): Seq[Any] =
if ($ast.isObject(any)) $ast.getKeys(any).to[Seq].flatMap {
case k if k == key => Seq($ast.dereferenceObject(any, k))
case k => derefRecursive(key, $ast.dereferenceObject(any, k))
} else if ($ast.isArray(any)) $ast.getArray(any).flatMap(derefRecursive(key, _))
else Nil
protected def doNormalize(orEmpty: Boolean): Any = {
yCombinator[(Any, Vector[Either[Int, String]]), Any] { fn =>
{
case (j, Vector()) => j: Any
case (j, t :+ e) =>
fn(({
if (e.bimap(x => $ast.isArray(j), x => $ast.isObject(j))) {
try e.bimap($ast.dereferenceArray(j, _), $ast.dereferenceObject(j, _))
catch {
case TypeMismatchException(exp, fnd) => throw TypeMismatchException(exp, fnd)
case exc: Exception =>
if (orEmpty) DataCompanion.Empty
else {
e match {
case Left(e) => throw MissingValueException(s"[$e]")
case Right(e) => throw MissingValueException(e)
}
}
}
} else
throw TypeMismatchException(
if ($ast.isArray(j)) DataTypes.Array else DataTypes.Object,
e.bimap(l => DataTypes.Array, r => DataTypes.Object)
)
}, t))
}
}($root.value -> $path)
}
/** Assumes the Json object is wrapping a `T`, and casts (intelligently) to that type. */
def as[S](implicit ext: Extractor[S, T], mode: Mode[`Data#as`]): mode.Wrap[S, ext.Throws] =
ext.extract(this.asInstanceOf[T], $ast, mode)
def is[S](implicit ext: Extractor[S, T]): Boolean =
try {
ext.extract(this.asInstanceOf[T], $ast, modes.throwExceptions())
true
} catch {
case e: Exception => false
}
def apply(i: Int = 0): T = $deref(Left(i) +: $path)
override def equals(any: Any) =
try {
any match {
case any: DataType[_, _] => $normalize == any.$normalize
case _ => false
}
} catch { case e: Exception => false }
override def hashCode = $root.value.hashCode ^ 3271912
}
trait MutableDataType[+T <: DataType[T, AstType], AstType <: MutableDataAst] extends DataType[T, AstType] {
def $updateParents(p: Vector[Either[Int, String]], newVal: Any): Unit =
p match {
case Vector() =>
$root.value = newVal
case Left(idx) +: init =>
val jb = $deref(init)
val newJb = $ast.setArrayValue(Try(jb.$normalize).getOrElse($ast.fromArray(Nil)), idx, newVal)
if (jb match {
case jb: AnyRef =>
newJb match {
case newJb: AnyRef => jb ne newJb
case _ => false
}
case jb => jb == newJb
}) $updateParents(init, newJb)
case Right(key) +: init =>
val jb = $deref(init)
val newJb = $ast.setObjectValue(Try(jb.$normalize).getOrElse($ast.fromObject(Map())), key, newVal)
if (jb match {
case jb: AnyRef =>
newJb match {
case newJb: AnyRef => jb ne newJb
case _ => false
}
case jb => jb == newJb
}) $updateParents(init, newJb)
}
/** Updates the element `key` of the JSON object with the value `v` */
def updateDynamic(key: String)(v: ForcedConversion2[T]): Unit =
if (!v.nothing)
$updateParents($path, $ast.setObjectValue(Try($normalize).getOrElse($ast.fromObject(Map())), key, v.value))
/** Updates the `i`th element of the JSON array with the value `v` */
def update[T2](i: Int, v: T2)(implicit ser: Serializer[T2, T]): Unit =
$updateParents($path, $ast.setArrayValue(Try($normalize).getOrElse($ast.fromArray(Nil)), i, ser.serialize(v)))
/** Removes the specified key from the JSON object */
def -=(k: String): Unit = $updateParents($path, $ast.removeObjectValue(doNormalize(true), k))
/** Adds the specified value to the JSON array */
def +=[T2](v: T2)(implicit ser: Serializer[T2, T]): Unit = {
val r = doNormalize(true)
val insert = if (r == DataCompanion.Empty) $ast.fromArray(Nil) else r
$updateParents($path, $ast.addArrayValue(insert, ser.serialize(v)))
}
}
trait `Data#as` extends MethodConstraint
trait `Data#normalize` extends MethodConstraint
object ForcedConversion2 extends ForcedConversion2_1 {
implicit def forceOptConversion[T, D](opt: Option[T])(implicit ser: Serializer[T, D]) =
opt.map(t => ForcedConversion2[D](ser.serialize(t), false)) getOrElse
ForcedConversion2[D](null, true)
}
trait ForcedConversion2_1 {
implicit def forceConversion[T, D](t: T)(implicit ser: Serializer[T, D]) =
ForcedConversion2[D](ser.serialize(t), false)
}
case class ForcedConversion2[-D](value: Any, nothing: Boolean)
object ForcedConversion extends ForcedConversion_1 {
implicit def forceOptConversion[T, D](opt: Option[T])(implicit ser: Serializer[T, D]) =
opt.map(t => ForcedConversion[D](ser.serialize(t), false)) getOrElse
ForcedConversion[D](null, true)
}
trait ForcedConversion_1 extends ForcedConversion_2 {
implicit def forceConversion[T, D](t: T)(implicit ser: Serializer[T, D]) =
ForcedConversion[D](ser.serialize(t), false)
}
trait ForcedConversion_2 {
// The name of this method is significant for some additional checking done in the macro `contextMacro`.
implicit def forceStringConversion[D, T: StringSerializer](value: T)(implicit ser: Serializer[String, D]) =
ForcedConversion[D](ser.serialize(?[StringSerializer[T]].serialize(value)), false)
}
case class ForcedConversion[-D](value: Any, nothing: Boolean)
case class ParseException(source: String, line: Option[Int] = None, column: Option[Int] = None)
extends Exception("Failed to parse source")
================================================
FILE: data/shared/src/main/scala/rapture/data/exceptions.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.data
sealed abstract class DataGetException(msg: String) extends RuntimeException(msg)
case class TypeMismatchException(found: DataTypes.DataType, expected: DataTypes.DataType)
extends DataGetException(s"type mismatch: Expected ${expected.name} but found ${found.name}")
case class MissingValueException(name: String = "")
extends DataGetException(
if (name.isEmpty)
"missing value"
else s"missing value: $name")
================================================
FILE: data/shared/src/main/scala/rapture/data/extractors.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.data
import rapture.core._
import scala.annotation._
import language.higherKinds
import scala.util._
case class FilterException() extends Exception("value was removed by filter")
case class NotEmptyException() extends Exception
object GeneralExtractors {
def tryExtractor[Data <: DataType[Data, _ <: DataAst], T](
implicit ext: Extractor[T, Data]): Extractor[Try[T], Data] { type Throws = Nothing } =
new Extractor[Try[T], Data] {
type Throws = Nothing
def extract(any: Data, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Try[T], Throws] = mode.wrap {
try ext.extract(any.$wrap(any.$normalize), any.$ast, modes.returnTry())
catch {
case e: Exception => Failure(e)
}
}
}
def optionExtractor[Data <: DataType[Data, _ <: DataAst], T](
implicit ext: Extractor[T, Data]): Extractor[Option[T], Data] { type Throws = Nothing } = {
new Extractor[Option[T], Data] {
type Throws = Nothing
def extract(any: Data, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Option[T], Throws] =
mode.wrap {
try ext.extract(any.$wrap(any.$normalize), any.$ast, modes.returnOption())
catch {
case e: Exception => None
}
}
}
}
def noneExtractor[Data <: DataType[_, DataAst]]
: Extractor[None.type, Data] { type Throws = DataGetException with NotEmptyException } =
new Extractor[None.type, Data] {
type Throws = DataGetException with NotEmptyException
def extract(value: Data, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[None.type, Throws] =
mode.wrap {
val v = value.$wrap(value.$normalize)
if (ast.isObject(v) && ast.getKeys(v).size == 0) None
else mode.exception[None.type, NotEmptyException](NotEmptyException())
}
}
def genSeqExtractor[T, Coll[_], Data <: DataType[Data, _ <: DataAst]](
implicit cbf: scala.collection.generic.CanBuildFrom[Nothing, T, Coll[T]],
ext: Extractor[T, Data]): Extractor[Coll[T], Data] { type Throws = ext.Throws } = {
new Extractor[Coll[T], Data] {
type Throws = ext.Throws
def extract(value: Data, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Coll[T], Throws] =
mode.wrap {
mode.catching[DataGetException, Coll[T]] {
val v = value.$wrap(value.$normalize)
v.$ast
.getArray(v.$root.value)
.to[List]
.zipWithIndex
.map {
case (e, i) =>
mode.unwrap(ext.safeExtract(v.$wrap(e), v.$ast, Some(Left(i)), mode), s"($i)")
}
.to[Coll]
}
}
}
}
def mapExtractor[K, T, Data <: DataType[Data, _ <: DataAst]](
implicit ext: Extractor[T, Data],
ext2: StringParser[K]): Extractor[Map[K, T], Data] { type Throws = ext.Throws with ext2.Throws } =
new Extractor[Map[K, T], Data] {
type Throws = ext.Throws with ext2.Throws
def extract(value: Data, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Map[K, T], Throws] =
mode.wrap {
value.$ast.getObject(value.$normalize) map {
case (k, v) =>
mode.unwrap(ext2.parse(k, mode)) -> mode.unwrap(
ext.safeExtract(value.$wrap(v), value.$ast, Some(Right(k)), mode))
}
}
}
}
object Extractor {
implicit def anyExtractor[Data <: DataType[_, DataAst]]: Extractor[Any, Data] { type Throws = Nothing } =
new Extractor[Any, Data] {
type Throws = Nothing
def extract(value: Data, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Any, Throws] =
mode.wrap(value.$normalize)
}
}
@implicitNotFound("cannot extract type ${T} from ${D}.")
abstract class Extractor[T, -D] extends Functor[({ type L[x] = Extractor[x, D] })#L, T] { ext =>
type Throws <: Exception
def safeExtract(any: D,
ast: DataAst,
prefix: Option[Either[Int, String]],
mode: Mode[_ <: MethodConstraint]): mode.Wrap[T, Throws] = mode.wrap {
try mode.unwrap(extract(any, ast, mode))
catch {
case e @ TypeMismatchException(_, _) => mode.exception(e)
case e @ MissingValueException(_) => mode.exception(e)
}
}
def extract(any: D, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[T, Throws]
def rawMap[T2](fn: (T, Mode[_ <: MethodConstraint]) => T2): Extractor[T2, D] = new Extractor[T2, D] {
def extract(any: D, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[T2, Throws] =
mode.wrap(fn(mode.unwrap(ext.extract(any, ast, mode)), mode.generic))
}
def filter(pred: T => Boolean): Extractor[T, D] { type Throws = ext.Throws with FilterException } =
new Extractor[T, D] {
type Throws = ext.Throws with FilterException
def extract(any: D, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[T, Throws] = mode.wrap {
val result = mode.unwrap(ext.extract(any, ast, mode))
if (pred(result)) result else mode.exception[T, FilterException](FilterException())
}
}
def orElse[TS >: T, T2 <: TS, D2 <: D](
ext2: => Extractor[T2, D2]): Extractor[TS, D2] { type Throws = DataGetException } =
new Extractor[TS, D2] {
type Throws = DataGetException
def extract(any: D2, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[TS, Throws] = mode.wrap {
try mode.unwrap(ext.extract(any, ast, mode))
catch {
case e: Exception => mode.unwrap(ext2.extract(any, ast, mode))
}
}
}
}
================================================
FILE: data/shared/src/main/scala/rapture/data/macros.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.data
import rapture.base._
import rapture.core._
object Macros {
// FIXME: Include enclosing position in the HashSet too
val emittedWarnings = new collection.mutable.HashSet[String]
def extractorMacro[T: c.WeakTypeTag, Data: c.WeakTypeTag, Th](
c: WhiteboxContext): c.Expr[Extractor[T, Data]] = {
import c.universe._
import compatibility._
val extractorType = typeOf[Extractor[_, _]].typeSymbol.asType.toTypeConstructor
val nameMapperType = typeOf[NameMapper[_, _]].typeSymbol.asType.toTypeConstructor
val implicitSearchFailures = collection.mutable.ListMap[String, List[String]]().withDefault(_ => Nil)
val extractionType = weakTypeOf[T].typeSymbol.asClass
if (weakTypeOf[T] <:< typeOf[AnyVal]) {
val param = paramLists(c)(declarations(c)(weakTypeOf[T]).collect {
case t: MethodSymbol => t.asMethod
}.find(_.isPrimaryConstructor).get).head.head
val paramType = param.typeSignature
val inferredExtractor =
c.inferImplicitValue(appliedType(extractorType, List(paramType, weakTypeOf[Data])), false, false)
c.Expr[Extractor[T, Data]](q"$inferredExtractor.map { new ${weakTypeOf[T]}(_) }")
}/* else if (extractionType.isSealed) {
val subclasses = extractionType.knownDirectSubclasses.to[List]
def tsort(todo: Map[Set[String], Symbol], done: List[Symbol] = Nil): List[Symbol] = if(todo.isEmpty) done else {
val move = todo.filter { case (key, v) => (todo - key).forall(!_._1.subsetOf(key)) }
tsort(todo -- move.map(_._1), move.map(_._2).to[List] ::: done)
}
val paramSets = subclasses.map { subclass =>
(declarations(c)(subclass.asType.toType).collect {
case m: MethodSymbol if m.isCaseAccessor => m.asMethod
}.map(_.name.decodedName.toString).to[Set], subclass)
}
val sortedExtractors = tsort(paramSets.toMap).map { subclass =>
val searchType = appliedType(extractorType, List(subclass.asType.toType, weakTypeOf[Data]))
c.inferImplicitValue(searchType, false, false)
}
val NothingType = weakTypeOf[Nothing]
val throwsType = sortedExtractors.last.tpe.member(typeName(c, "Throws")).typeSignature
val combinedExtractors = sortedExtractors.reduceLeft { (left, right) => q"$left.orElse($right)" }
c.Expr[Extractor[T, Data]](q"""
(new _root_.rapture.data.Extractor[${weakTypeOf[T]}, ${weakTypeOf[Data]}] {
def extract(data: ${weakTypeOf[Data]}, ast: _root_.rapture.data.DataAst, mode: _root_.rapture.core.Mode[_ <: _root_.rapture.core.MethodConstraint]): mode.Wrap[${weakTypeOf[
T]}, Throws] = mode.wrap { $combinedExtractors }
}).asInstanceOf[_root_.rapture.data.Extractor[${weakTypeOf[T]}, ${weakTypeOf[Data]}] {
type Throws = ${throwsType}
}]
""")
}*/ else {
require(weakTypeOf[T].typeSymbol.asClass.isCaseClass)
val typeDeclaration = companion(c)(weakTypeOf[T].typeSymbol).typeSignature
val valueParameters = paramLists(c)(declaration(c)(typeDeclaration, termName(c, "apply")).asMethod)
val defaults = valueParameters.flatten.map(_.asTerm.isParamWithDefault).zipWithIndex.filter(_._1).map(_._2 + 1).to[Set]
// FIXME integrate these into a fold
var throwsTypes: Set[Type] = Set(typeOf[DataGetException])
val params = declarations(c)(weakTypeOf[T]).collect {
case m: MethodSymbol if m.isCaseAccessor => m.asMethod
}.zipWithIndex map {
case (p, idx) =>
val nameMappingImplicit = c.inferImplicitValue(appliedType(nameMapperType, List(weakTypeOf[T], weakTypeOf[Data])), false, false)
val deref = q"""data.selectDynamic($nameMappingImplicit.encode(${p.name.decodedName.toString}))"""
val NothingType = weakTypeOf[Nothing]
val inferredImplicit =
try c.inferImplicitValue(appliedType(extractorType, List(p.returnType, weakTypeOf[Data])), false, false)
catch {
case e: Exception =>
implicitSearchFailures(p.returnType.toString) ::= p.name.decodedName.toString
null
}
val t = try {
inferredImplicit.tpe.member(typeName(c, "Throws")).typeSignature match {
case NothingType => List()
case refinedType: RefinedType => refinedType.parents
case typ: Type => List(typ)
case _ => ???
}
} catch {
case e: Exception => List()
}
if(!defaults.contains(idx + 1)) throwsTypes ++= t
// Borrowed from Shapeless
def companionRef(tpe: Type): Tree = {
val global = c.universe.asInstanceOf[scala.tools.nsc.Global]
val gTpe = tpe.asInstanceOf[global.Type]
val pre = gTpe.prefix
val sym = gTpe.typeSymbol
val cSym = sym.companionSymbol
if (cSym != NoSymbol) global.gen.mkAttributedRef(pre, cSym).asInstanceOf[Tree]
else Ident(tpe.typeSymbol.name.toTermName)
}
if (defaults.contains(idx + 1)) q"""
mode.unwrap(try $deref.as($inferredImplicit, mode.generic) catch { case e: Exception => mode.wrap(${companionRef(weakTypeOf[T])}.${termName(
c, "apply$default$" + (idx + 1))}.asInstanceOf[${p.returnType}]) }, ${"." + p.name.decodedName})
""" else q"""
mode.unwrap($deref.as($inferredImplicit, mode.generic), ${"." + p.name.decodedName})
"""
}
if (implicitSearchFailures.nonEmpty) {
val paramStrings = implicitSearchFailures map {
case (t, p1 :: Nil) =>
s"parameter `$p1' of type $t"
case (t, p1 :: ps) =>
s"parameters ${ps.map(v => s"`$v'").mkString(", ")} and `$p1' of type $t"
case (t, Nil) =>
??? // Doesn't happen
}
val errorString = paramStrings.to[List].reverse match {
case t1 :: Nil => t1
case t1 :: ts => s"${ts.mkString(", ")} and $t1"
case Nil => ??? // Doesn't happen
}
val plural =
if (implicitSearchFailures.flatMap(_._2).size > 1)
s"${weakTypeOf[Data].typeSymbol.name} extractors"
else
s"a ${weakTypeOf[Data].typeSymbol.name} extractor"
val err = s"Could not generate a ${weakTypeOf[Data].typeSymbol.name} extractor for case " +
s"class ${weakTypeOf[T].typeSymbol.name} because $plural for $errorString could not " +
s"be found"
if (!emittedWarnings.contains(err)) {
emittedWarnings += err
c.warning(NoPosition, err)
}
}
require(implicitSearchFailures.isEmpty)
val construction = c.Expr[T](q"""new ${weakTypeOf[T]}(..$params)""")
c.Expr[Extractor[T, Data]](q"""
(new _root_.rapture.data.Extractor[${weakTypeOf[T]}, ${weakTypeOf[Data]}] {
def extract(data: ${weakTypeOf[Data]}, ast: _root_.rapture.data.DataAst, mode: _root_.rapture.core.Mode[_ <: _root_.rapture.core.MethodConstraint]): mode.Wrap[${weakTypeOf[
T]}, Throws] = mode.wrap { ${construction} }
}).asInstanceOf[_root_.rapture.data.Extractor[${weakTypeOf[T]}, ${weakTypeOf[Data]}] {
type Throws = ${normalize(c)(typeIntersection(c)(throwsTypes.to[List]))}
}]
""")
}
}
def serializerMacro[T: c.WeakTypeTag, Data: c.WeakTypeTag](c: WhiteboxContext)(
ast: c.Expr[DataAst]): c.Expr[Serializer[T, Data]] = {
import c.universe._
import compatibility._
val tpe = weakTypeOf[T].typeSymbol.asClass
val nameMapperType = typeOf[NameMapper[_, _]].typeSymbol.asType.toTypeConstructor
val serializer = typeOf[Serializer[_, _]].typeSymbol.asType.toTypeConstructor
if (weakTypeOf[T] <:< typeOf[AnyVal]) {
val param = paramLists(c)(declarations(c)(weakTypeOf[T]).collect {
case t: MethodSymbol => t.asMethod
}.find(_.isPrimaryConstructor).get).head.head
val paramName = param.name.decodedName.toString
val paramType = param.typeSignature
val inferredSerializer =
c.inferImplicitValue(appliedType(serializer, List(paramType, weakTypeOf[Data])), false, false)
val newName = termName(c, freshName(c)("param$"))
c.Expr[Serializer[T, Data]](q"$inferredSerializer.contramap[${weakTypeOf[T]}](_.${termName(c, paramName)})")
} else {
if (tpe.isCaseClass) {
val params = declarations(c)(weakTypeOf[T]).collect {
case m: MethodSymbol if m.isCaseAccessor => m.asMethod
}.map { p =>
val imp = c.inferImplicitValue(appliedType(serializer, List(p.returnType, weakTypeOf[Data])), false, false)
val appliedSerializerType = appliedType(nameMapperType, List(weakTypeOf[T], weakTypeOf[Data]))
val nameMapperImplicit = c.inferImplicitValue(appliedSerializerType, false, false)
q"""($nameMapperImplicit.encode(${p.name.decodedName.toString}),
$imp.serialize(${termName(c, "t")}.${p}))"""
}
c.Expr[Serializer[T, Data]](q"""new _root_.rapture.data.Serializer[${weakTypeOf[T]}, ${weakTypeOf[Data]}] {
def serialize(t: ${weakTypeOf[T]}): _root_.scala.Any =
$ast.fromObject(_root_.scala.collection.immutable.ListMap(..$params).filterNot { v => $ast.isNull(v._2) })
}""")
} else if (tpe.isSealed) {
val cases = tpe.knownDirectSubclasses.to[List]
val caseClauses = cases.map { sc =>
val fullySpecifiedSerializer = appliedType(serializer, List(sc.asType.toType, weakTypeOf[Data]))
val caseSerializer = c.inferImplicitValue(fullySpecifiedSerializer, false, false)
val pattern = pq"v: ${sc.asClass}"
cq"${pattern} => $caseSerializer.serialize(v)"
}
c.Expr[Serializer[T, Data]](q"""new _root_.rapture.data.Serializer[${weakTypeOf[T]}, ${weakTypeOf[Data]}] {
def serialize(t: ${weakTypeOf[T]}): _root_.scala.Any = t match { case ..$caseClauses }
}""")
} else throw new Exception()
}
}
}
================================================
FILE: data/shared/src/main/scala/rapture/data/serializers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.data
import rapture.core._
import scala.annotation._
@implicitNotFound(
"Cannot serialize type $"+"{T} to $"+"{D}. Please provide an implicit Serializer " +
"of type $"+"{T}.")
trait Serializer[T, -D] { ser =>
def serialize(t: T): Any
def contramap[T2](fn: T2 => T) = new Serializer[T2, D] {
def serialize(t: T2): Any = ser.serialize(fn(t))
}
}
================================================
FILE: doc/core-scalaz.md
================================================
[](https://travis-ci.org/propensive/rapture-core-scalaz)
# Rapture Core/Scalaz
The Rapture Core/Scalaz project provides integration between Rapture Core and Scalaz 7. So far
this consists only of two additional return-type strategies:
- A validation return-type strategy for returning Scalaz `Validation`s
- A task return-type strategy, for returning Scalaz `Task`s
### Availability
#### Building from source
To build Rapture Core Scalaz from source, follow these steps:
```
git clone git@github.com:propensive/rapture-core-scalaz.git
cd rapture-core-scalaz
sbt package
```
If the compilation is successful, the compiled JAR file should be found in target/scala-2.10
### Return-Type Strategies
By importing `scalazStrategy.returnValidation`, every fallible method will return a result of
type `Validation[E, T]`.
```scala
> import scalazStrategy.returnValidation
> Json.parse("{}")
res: Validation[ParseException, Json] = {}
```
If using the standard `strategy.explicit` you can get a `Validation` by calling `.valid` on the
unexpanded result.
```scala
> import strategy.explicit
> Json.parse("{}").valid
res: Validation[ParseException, Json] = {}
```
Alternatively, by importing `scalazStrategy.returnTasks`, and providing a valid implicit
`ExecutorService`, every fallible method in Rapture will return a Scalaz `Task`.
```scala
> import scalazStrategy.returnTasks
> implicit val exec = scalaz.concurrent.Strategy.DefaultExecutorService
> Json.parse("{}")
res: Task[Json] = Task@7961b5f3
```
You can call `.task` on an unexpanded result when using `strategy.explicit` to get the same
effect.
See https://github.com/propensive/rapture-core#return-type-strategies for more information on
Rapture Core return-type strategies.
================================================
FILE: doc/core.md
================================================
[](https://travis-ci.org/propensive/rapture-core)
[](https://gitter.im/propensive/rapture?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
# Rapture Core
The Rapture Core project provides a common foundation upon which other Rapture projects are
based, however it provides utilities which may be useful in any project. Namely,
- Modes (previously called return-type strategies)
- A lightweight abstraction on time libraries, and implementations for Java time
- A tiny (but growing) collection of conveniences for working within the REPL
- An alias for `implicitly`
- A really simple implementation of actors, based on `scala.concurrent`
- Reusable string serializers and deserializers, with implicit-based configurable number formatting
- Miscellaneous other small tools and utilities
### Availability
Rapture Core 1.1.0 is available under the Apache 2.0 License from Maven Central with group ID `com.propensive` and artifact ID `rapture-core_2.10`.
#### SBT
You can include Rapture Core as a dependency in your own project by adding the following library dependency to your build file:
```scala
libraryDependencies ++= Seq("com.propensive" %% "rapture-core" % "1.1.0")
```
#### Maven
If you use Maven, include the following dependency:
```xml
com.propensiverapture-core_2.111.1.0
```
#### Download
You can download Rapture Core directly from the [Rapture website](http://rapture.io/)
Rapture Core depends on Scala 2.11, but has no other dependencies.
#### Building from source
To build Rapture Core from source, follow these steps:
```
git clone -b scala-2.11 git@github.com:propensive/rapture-core.git
cd rapture-core
sbt package
```
If the compilation is successful, the compiled JAR file should be found in target/scala-2.11.0-RC4
### Modes
Rapture's modes allow library methods to be written in such a way that they may
be wrapped in another function (and have a different return type) at the call site. This
pattern allows *users* of the library to choose the return type and additional pre- and
post-execution processing to be performed, depending on their needs. For example, using Rapture
JSON, given one of the imported modes,
```scala
import modes.returnEither._
Json.parse("[1, 2, 3]")
```
will have return type `Either[ParseException, Json]`. Hopefully the parsing succeeded, and the
return type will be `Right[Json]` rather than `Left[ParseException]`.
Alternatively, given a different imported mode, we will get a different return type.
```scala
import modes.returnFuture._
Json.parse("[1, 2, 3]")
```
This will immediately return a `Future[Json]`, from which the result can be obtained once
processing completes.
A selection of modes are provided:
- `modes.throwExceptions._` - does no additional processing, and simply returns the value,
leaving any thrown exceptions unhandled. This is the default.
- `modes.returnEither._` - captures successful results in the `Right` branch of an
`Either`, or exceptions in the `Left` branch.
- `modes.returnOption._` - returns an `Option` of the result, where the exceptional case
collapses to `None`.
- `modes.returnTry` - wraps the result in a `scala.util.Try`.
- `modes.returnFuture._` - wraps the result in a `scala.concurrent.Future`; requires an
implicit ExecutionContext.
- `modes.timeExecution._` - times the duration of carrying out the execution, returning a tuple
of the return value and the time taken; requires an implicit `rapture.core.TimeSystem`.
- `modes.keepCalmAndCarryOn._` - catches exceptions and silently returns them as
null; this is strongly discouraged!
- `modes.explicit._` - returns an instance of `Explicit` which requires the mode
to be explicitly specified at the call site every time.
Multiple modes can be composed, should this be required, for example,
```scala
implicit val handler = modes.returnTry compose modes.timeExecution
```
#### The `modally` method
The `modally` method takes a lambda and evaluates it in the current mode, e.g.
```scala
import modes.returnTry._
modally { Class.forName(className) }
// Returns a Try[Class[_]]
```
This may provide a convenient (and adaptive) alternative to `try`/`catch`.
#### Writing methods to use modes
To transform a method like this,
```scala
def doSomething[T](arg: String, arg2: T): Double = {
// method body
}
```
into one which offers end-users a choice of mode, include an implicit
Mode parameter, and wrap your method body and return type, like this,
```scala
def doSomething[T](arg: String, arg2: T)(implicit mode: Mode[_]):
mode.Wrap[Double, Exception] = mode wrap {
// method body
}
```
If you know that your method body will only throw exceptions of a certain type, you can
specify this in the method return type in place of `Exception`, which may make processing
exceptions easier when using a mode which captures them (e.g. `modes.returnEither`).
#### Conveniences for existing methods
You may already have existing implementations of methods you would like to modify to utilize
modes, but which already have a return type which captures (or discards) the exception
rather than throwing it. The `wrapEither`, `wrapTry` and `wrapOption` methods are provided
as alternatives to `wrap` to transform methods which already return `Either`, `Try` or
`Option` respectively. Note, however, that because `wrapOption` loses its exception in the
return type, that there is no way to recover it. This means that when using it with modes
such as `returnEither`, that the exceptional cases will always return as a
`java.util.NoSuchElementException`.
### REPL utilities
When working within the REPL, it is useful to receive the immediate feedback that a fallible
operation has failed (as the `throwExceptions` mode provides), but seeing large and unwieldy
stack traces can be annoying. By including the following import,
```scala
import rapture.core.repl._
```
stack traces from fallible Rapture methods will be suppressed, and a short error message
will be displayed instead. If you would like to view the stack trace, it can be rethrown by
calling `repl.lastException`.
### Time System Abstraction
Many APIs take parameters or return values which represent time. Unfortunately, there is no
standard for representing entities like instants and durations. Rapture Core provides a general
type class for defining these types and methods for creating them, and provides two simple
implementations:
- `timeSystems.numeric` - uses `Long`s to represent both instants and durations.
- `timeSystems.javaUtil` - uses `java.util.Date`s to represent instants, and `Long`s to
represent durations.
### Alias for `implicitly`
Context-bounds provide a nice, lightweight syntax for working with type classes in Scala,
however while explicitly specifying an implicit parameter necessarily provides a named handle
for that implicit, context-bounds force us to make repeated use of the `implicitly` method in
order to use the type class. This can make using context-bounds more cumbersome than they
deserve.
Rapture Core introduces an alias for `implicitly` named `?`. Generally speaking, any occurrence
of `implicitly` can be replaced by a `?`. This is particularly useful when calling methods which
take multiple implicit parameters and you would like to specify one of these explicitly. For
example, a method like this:
```scala
def performAction[T](v: Int)(implicit alpha: Alpha[T], beta: Beta, gamma: Gamma) = { ... }
```
may now be called quite concisely using
```scala
performAction(42)(?, ?, myGamma)
```
if we only wanted to specify the parameter `myGamma` explicitly.
================================================
FILE: doc/html.md
================================================
# Rapture HTML
Rapture HTML provides simple but typesafe support for working with HTML5
documents in Scala, enforcing the constraints of the document object model.
It is a small library which works independently of any other web framework.
Rapture HTML is part of the [Rapture](http://rapture.io/) project.
## Features
- Clean, elegant and intuitive DSL for creating HTML tree structures
- Nesting constraints on HTML nodes are enforced by the type system
- HTML attributes may only be applied to appropriate elements
- Customized explanatory error messages given for badly-nested elements and
mismatched attributes
- Attributes generally use rich Scala types, not `String`s
- HTML Document object model specification is concise, extensible and
maintainable
- Lightweight, typesafe accessors for navigating elements and attributes
## Availability
Rapture HTML 0.1.0 is available under the *Apache 2.0 License* from Maven Central
with group ID `com.propensive` and artifact ID `rapture-html_2.10`.
### SBT
You can include Rapture HTML as a dependency in your own project by adding the
following library dependency to your build file:
```scala
libraryDependencies ++= Seq("com.propensive" %% "rapture-html" % "0.1.0")
```
### Maven
If you use Maven, include the following dependency:
```xml
com.propensiverapture-html_2.100.1.0
```
### Building from source with SBT
To build Rapture HTML from source, follow these steps:
```
git clone git@github.com:propensive/rapture-html.git
cd rapture-html
sbt package
```
If the compilation is successful, the compiled JAR file should be found in the
directory for the appropriate Scala version in the `target` directory.
## Status
Rapture HTML is *experimental*. This means that the API is undergoing change,
and new features may be added or removed without changes being documented.
## Contributing
Rapture HTML -- like all the Rapture projects -- openly welcomes contributions!
We would love to receive pull requests of bugfixes and enhancements from other
developers. To avoid potential wasted effort, bugs should first be reported on
the Github issue tracker, and it's normally a good idea to talk about
enhancements on the Rapture mailing list before embarking on any development.
Alternatively, just send Jon Pretty (@propensive) a tweet to start a
conversation.
# Using Rapture HTML
First of all, import the following:
```
import rapture.html._
import htmlSyntax._
```
The `htmlSyntax` package comprises a large namespace containing all HTML tag
and attribute names, so it is recommended to import this only into scopes where
it is to be immediately used.
## HTML Elements
A simple HTML element, with no attributes or child elements is as simple as
writing the tag name, with its first letter capitalized, for example,
```
//
val html = Form
```
To add attributes to an empty tag, list them like named parameters to the element, like this,
```
//
val html = Form(id = 'signup, method = Post)
```
Note that the types of the attribute values are not, in general, `String`s.
Each attribute is typed according to the values it allows to be assigned.
A later version of Rapture HTML will offer multiple alternative types
(originating from third-party projects) for HTML attribute values.
Mostly, attribute names in Rapture HTML are identical to their native HTML5
counterparts, but in several cases it has been necessary to tweak the names.
- Any attribute containing a `-` is converted to camel case, for example
`http-equiv` becomes `httpEquiv`
- The `class` attribute becomes `classes`
- The `type` attrubute becomes `typeName`
- The `for` attribute becomes `forName`
- Custom `data-` attributes become `data.`
Better suggestions for more consistent handling of these attributes would be
very welcome.
An HTML element may also have child elements, by adding them as parameters in a
second parameter block, like so,
```
//
val html = Form(id = 'signup, method = Post)(Label, Input)
```
Remember, `Label` and `Input` are just empty elements.
The first parameter block of any HTML element, however, is completely optional
and can be omitted if no attributes are required. For example,
```
//
val html = Form(Label, Input)
```
## Cautionary notice
Scala does not offer any native support for an optional initial parameter
block, and the complex machinery necessary to offer this, whilst maintaining
idiomatic-looking syntax may be best described as "baroque". Until this
approach has been extensively tested, users should be aware that it may be an
imperfect abstraction.
This syntax would not have been possible without help from *all* of the
following Scala features, mostly as a workaround for overloading interacting
badly with type inference:
- Implicit parameters and conversions
- Getters and setters
- Dependent method types
- Higher-kinded types
- Macros
- Dynamic type
- Singleton types
- Inheritance and variance
Bug reports around this approach would be very welcome.
## Example HTML document
A slightly more complete HTML document may look like this:
```
val html = Html(
Head(
Title("Hello world!")
),
Body(
H1("Hello World!"),
Ul(
Li(id = 'first)("Apple"),
Li("Orange"),
Li("Pear")
)
)
)
```
This works because each HTML element has been correctly placed within another
element that allows it as a child.
## Nesting rules
Almost all of HTML5's rules on nesting elements, as specified in the working
draft, are enforced by Rapture HTML.
Whilst it is possible to write `Table(Tbody(Tr(Td)))`, a compile error would be
produced by `Html(Head(Table))`, because in HTML, a `
` element cannot
appear inside a `` element.
The following custom error is produced at compile time:
```
error: Attempted to nest a Flow node in a position where only Metadata nodes are permitted
Html(Head(Table))
^
```
The terms `Flow` and `Metadata` correspond to the terms used to describe
element types in the HTML5 Working Draft.
## Attribute rules
Likewise, attributes may only be applied to those elements which support them,
for example the `max` attribute is not valid on `Textarea` elements, so the
following line will result in a compile error.
```
Textarea(max = 100.0)
```
Unfortunately, possibly due to a type inference bug in Scalac, this error
currently presents itself as less friendly type error.
## Navigating an HTML document
Given an `Html` node, `html`, containing a document, nodes within that document
can be easily accessed using the `\` operator and named tags, for example,
```
val rows = html \ Body \ Div \ Div \ Table \ Tbody \ Tr
val firstRow = rows(0)
```
and the attributes of an existing HTML node may be accessed by dereferencing it
with the attribute name, for example, `firstRow.id` or `firstRow.style`. If the
attribute is present, it will be returned as the original type it was set as,
i.e. not necessarily a `String`.
The `\\` operator will select all descendants (not just immediate children)
matching the specified tag.
```
val rows = html \\ Tr
val firstRow = rows(0)
```
All of these access methods take advantage of Rapture's
[modes](https://github.com/propensive/rapture-core), to give a choice about how
missing elements or attributes should be handled.
## Outputting HTML
The `toString` method on HTML elements will generate pretty-printed strings
which neatly indent the HTML source into a readable form, and by default the
`format` method will do the same. As an alternative, HTML may be output in
"compact" form, without any additional whitespace, by importing an alternative
formatter from the `rapture.dom` package, for example,
```
import rapture.dom._
import domFormatters.compact._
println(myHtml.format)
```
Formatters are pluggable, so it is easy to write a custom formatter which
outputs the HTML in a different form, not necessarily to a `String`.
## The HTML Document Object Model
The rules governing how HTML elements may be nested are defined in the [syntax
file](https://github.com/propensive/rapture-html/blob/master/src/syntax.scala)
based on some very simple [phantom
types](https://github.com/propensive/rapture-html/blob/master/src/phantom.scala)
which determine the name, basic types, child types and attribute types of each
tag.
The current implementation is based on a version from an HTML5 working draft
from 2013. It is likely that the current implementation is incomplete or
incorrect in places, so corrections and additions to these files are very
welcome.
Attribute definitions follow after the Tag definitions in the syntax file, but
are currently more verbose. Hopefully it will be possible to improve the
tersity of these definitions in a later release.
## Tests
There is currently no test suite for Rapture HTML, though implementing a
selection of tests is a medium-term priority.
## Other DOMs
The Rapture DOM project, a dependency of Rapture HTML, is designed to support
other HTML-like languages, just by defining tags, attributes and their
associated phantom types. Rapture HTML should serve as a reasonable starting
point for anyone looking to implement an alternative DOM language.
Additionally, for DOM-like languages which do not serialize to an SGML-like
syntax, but do follow the same basic structure, custom formatters may be
written to produce the appropriate output.
================================================
FILE: doc/i18n.md
================================================
[](https://travis-ci.org/propensive/rapture-i18n)
[](https://gitter.im/propensive/rapture?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
# Rapture Internationalization (I18N)
Rapture I18N is a very simple library for working with typesafe localized
strings in Scala. It is part of the [Rapture](http://rapture.io/) project.
## Features
- Simple format for writing language-specific string literals
- Internationalized Strings' types reflect the languages they support
- Strings are typechecked to ensure that strings for all languages are provided
- Support for language-dependent string substitution
- Internationalized strings may be treated as normal strings by specifying a
default language
- Convenient trait provided for writing
## Tests
Tests for Rapture I18N are in their own project, [Rapture I18N
Tests](https://github.com/propensive/rapture-i18n-test)
## Availability
Rapture I18N 2.0.0-M5 is available under the *Apache 2.0 License* from Maven Central
with group ID `com.propensive` and artifact ID `rapture-i18n_2.10`.
### SBT
You can include Rapture I18N as a dependency in your own project by adding the
following library dependency to your build file:
```scala
libraryDependencies ++= Seq("com.propensive" %% "rapture-i18n" % "latest.integration")
```
### Maven
If you use Maven, include the following dependency:
```xml
com.propensiverapture-i18n_2.112.0.0-M5
```
### Building from source with SBT
To build Rapture I18N from source, follow these steps:
```
git clone git@github.com:propensive/rapture-i18n.git
cd rapture-i18n
sbt package
```
If the compilation is successful, the compiled JAR file should be found in the
directory for the appropriate Scala version in the `target` directory.
## Status
Rapture I18N is *experimental*. This means that the API is undergoing change,
and new features may be added or removed without changes being documented.
## Contributing
Rapture I18N -- like all the Rapture projects -- openly welcomes contributions!
We would love to receive pull requests of bugfixes and enhancements from other
developers. To avoid potential wasted effort, bugs should first be reported on
the Github issue tracker, and it's normally a good idea to talk about
enhancements on the Rapture mailing list before embarking on any development.
Alternatively, just send Jon Pretty (@propensive) a tweet to start a
conversation.
# Using Rapture I18N
First of all, import the following:
```scala
import rapture.i18n._
```
You can write an internationalized string by writing `en"Hello"` or
`fr"Bonjour"`. These have types I18n[String, En] and I18n[String, Fr], representing
English and French strings, respectively.
More importantly, you can define a single value representing an
internationalized string using the alternation operator (`&`), like this:
```scala
val greeting = en"Hello" & fr"Bonjour" & de"Guten Tag"
```
The value `greeting` here represents a string in three different languages, and
has the type `I18n[String, En with Fr with De]`. Note that the `with` combinator
represents a type intersection, which is the chosen implementation for
combining multiple language types in a single type parameter.
Given a value such as `greeting`, we can access the string for a language of
our choice, simply by applying it as a type parameter to the identifier, e.g.
`greeting[En]` will produce `"Hello"`, whereas `greeting[De]` will produce
`"Guten Tag"`.
## Subtyping
Types for internationalized strings behave such that a value may not overspecify
language strings for a given type, for example
```scala
val msgs: I18n[String, En with Fr] = fr"Bonjour" & en"Hello" & de"Guten Tag"
```
will result in compile errors.
```scala
Error: Some language translations were not provided: language
lazy val msgs: I18n[String, En with Fr] = fr"Bonjour" & en"Hello" & de"Guten Tag"
^
```
```
Error:type mismatch;
found : rapture.i18n.I18n[String,rapture.i18n.De]
required: rapture.i18n.I18n[String,rapture.i18n.Language]
Note: rapture.i18n.De <: rapture.i18n.Language, but class I18n is invariant in type Languages.
You may wish to define Languages as +Languages instead. (SLS 4.5)
lazy val msgs: I18n[String, En with Fr] = fr"Bonjour" & en"Hello" & de"Guten Tag"
^
```
and also may not underspecify language strings, so this is not valid:
```scala
val msgs: I18n[String, En with Fr] = en"Hello"
```
and will result in compile errors.
```scala
Error: Some language translations were not provided: fr
lazy val msgs2: I18n[String, En with Fr] = en"Hello"
^
```
```
Error: type mismatch;
found : rapture.i18n.I18n[String,rapture.i18n.En]
required: rapture.i18n.I18n[String,rapture.i18n.En with rapture.i18n.Fr]
Note: rapture.i18n.En >: rapture.i18n.En with rapture.i18n.Fr, but class I18n is invariant in type Languages.
You may wish to define Languages as -Languages instead. (SLS 4.5)
lazy val msgs2: I18n[String, En with Fr] = en"Hello"
^
```
This helpfully indicates the missing language.
## Substitution
Internationalized strings may be specified with interpolated substitutions,
which can themselves be either ordinary `String`s or other internationalized
strings. In the latter case, the internationalized string must provide the
language of the internationalized string it is being substituted into, for
example this is valid:
```scala
val greeting = en"Hello" & fr"Bonjour"
en"In England we greet people with '$greeting'."
```
but not this,
```scala
val greeting = en"Hello" & fr"Bonjour"
de"In Deutschland sagen wir '$greeting'"
```
which is another compile error.
## Default languages
It is often useful to pick a single language for use within some scope, and use
internationalized strings as if they are ordinary `String`s. This is achievable
by importing a default language, e.g.
```scala
import languages.es._
```
An internationalized string may then be used in place of an ordinary `String`,
like so:
```scala
import languages.de._
val errorMsg = en"Oh no!" & de"Ach nein!"
throw new Exception(errorMsg)
```
which will throw an exception with the German error message.
Without the import of a default language, this would produce a type error at
compile time. Beware, though, of methods like `+` on `String` which simply call
`toString` on the operand, and consequently do not enforce the typesafe
conversion to the correct language string. These methods should be avoided.
## Standard methods
The `toString` method on `I18nString`s is implemented such that it should
quickly be obvious that the string is an internationalized, rather than an
ordinary, string. For a given internationalized string, `toString` will display
two-letter codes for all the languages it provides, followed by the contents of
the string in English, if available, or in some other language, if not.
For example,
```scala
scala> fr"Bonjour" & en"Hello"
res: I18n[String, Fr with En] = fr&en:"Hello"
```
Additionally `hashCode` and `equals` are implemented such that `I18nString`s
can be usefully compared. Internationalized strings are treated as sets, so
reorderings are not significant.
## Using I18N in your own projects
A multilingual application, or even a module within a multilingual application
will usually make a decision about what languages it should support throughout.
This decision can be represented as a type, such as `En with Fr with Es`, and
for convenience, we can give this type an alias.
Then, as the project develops, its choice of supported languages may change, so
the type alias becomes a useful way to change the supported languages globally,
and enforce typechecking to ensure that every internationalized string in scope
provides every language. For example, define
```scala
package object app {
type AppLangs = En with Fr with Es
}
```
or alternatively,
```scala
package object app {
type IString = I18n[String, En with Fr with Es]
}
```
and then it is never necessary to refer to the application languages (`En`,
`Fr`, `Es`) explicitly, but every string parameterized on `AppLangs` will
nevertheless be typechecked to ensure all languages are provided.
It would then be easy to add an additional language, just by changing the type
alias, and recompiling (which would produce a type error every time the
newly-added language has not been provided.
It is often convenient to store all user messages in a single place, to avoid
littering source code with strings. Using internationalized strings, you may
put all your application messages in a single object, like this:
```scala
object Messages {
val cart = en"Shopping cart" & fr"Panier"
def items(n: Int) = if(n == 1) en"$n item" & fr"$n article" else en"$n items" & fr"$n articles"
// more words and phrases
}
```
Throughout your application internationalized strings may be passed around as a
single value which represents several strings in different languages, however
at some point the application will need to present a single string to an
end-user, in a language determined by some runtime value, such as the string
`"EN"` or `"FR"`, "English (US)" or "Deutsch".
This runtime value may come from a user request, from a session or a
configuration file; this is a design choice for the application, and Rapture
I18N imposes no constraints on recommendations on how it should be provided,
except that the application must, at some point, resolve the runtime value
representing the language to its compile-time type representation, and use this
to extract a standard `java.lang.String` from an `I18nString`.
An example may look like this:
```scala
def resolve(msg: I18n[String, AppLangs], lang: String): String = lang match {
case "EN" => msg[En]
case "FR" => msg[Fr]
case "ES" => msg[De]
}
```
This logic, which derives a `String` from the runtime values of an `I18nString`
representing a message and a `String` representing a language, is implemented
just once for the entire application, and corresponds to the small surface area
in which runtime errors may occur; all other logic relating to language strings
has been safely typechecked.
================================================
FILE: doc/json.md
================================================
# Rapture JSON
## Features
- Clean, intuitive, unintrusive, boilerplate-free Scala API
- Trivial extraction and serialization to/from primitives, collections and case classes
- Consistent and typesafe type-class-based interfaces
- Works with a choice of JSON parsers and backends
- Simple, efficient conversion between different backends
- Support for both immutable and mutable JSON
- Flexible choice of error handling strategies using
[modes](https://github.com/propensive/rapture-core)
- Can be easily extended using composable user-defined extractors and
serializers
# Using Rapture JSON
## JSON Representation
Rapture JSON is designed to be agnostic about the JSON parser and choice of AST
representation used throughout the library. This means that a choice of JSON
backend must be made in order to use Rapture JSON. Whilst different backend
libraries provide different features, all features of Rapture JSON are
available with every backend (with the exception of Jackson, which does not yet
support mutable JSON operations).
The choice of backend should therefore depend on other characteristics such as
performance, memory usage, required dependencies, integration with existing
libraries, licensing and policy choices.
The following backends are available:
- Argonaut (`argonaut`)
- Jackson (`jackson`) [1]
- Jawn (`jawn`)
- JFC (`jfc`)
- JSON4S (`json4s`)
- Lift (`lift`)
- Play (`play`)
- Scala standard library JSON (`scalaJson`) [2]
- Spray (`spray`)
Notes:
[1] Jackson (`jackson`) is a read-only backend (does not support mutable JSON, i.e. `JsonBuffer` is not supported).
[2] Scala standard library JSON (`scalaJson`) backend got removed in v2.0.0 because it is deprecated.
It is also possible to integrate with other JSON backends, though this is not
covered by this document. Anyone interested should look at the existing
integration type classes, and contact the Rapture mailing list or the Gitter
channel.
In the source code, you should import `rapture.json.jsonBackends.._`.
## The Json type
A JSON value, whether an array, object, boolean, number or string, is
represented by an instance of type `Json`. As JSON is inherently
dynamically-typed, the `Json` type is used to provide a safe and immutable
wrapper around the JSON tree, whose type is not known at compile time.
Instances of `Json` consist of three things:
- a reference to the root of a dynamically-typed JSON tree
- a path into a node within the JSON tree
- a reference to the parser used to create, modify and read the JSON tree
Although using `Json` objects should seem very intuitive, it is important to
understand the purpose of this state.
```json
{
"fruits": [
{
"name": "apple",
"color": "red"
},
{
"name": "banana",
"color": "yellow"
}
]
}
```
If we were to parse the above JSON source, we should get a tree consisting of
an object containing an array under the key "fruits", with two elements, each
of which is an object containing two fields, "name" and "color", both of which
are strings. Given this tree, we can refer to an element within with a path of
strings for indexing JSON objects, and integers for indexing JSON arrays, for
example, `fruits / 0 / name`, which would refer to the string `"apple"`.
We could also look into the same tree with the path `fruits / 3 / mass`, though
this wouldn't exist on account of there being only two elements in the `fruits`
list, but we would not know this until we attempted it at runtime.
A `Json` instance represents both the JSON tree, and a lazily-evaluated path
into that tree, which may or may not point to a value. If we assume the full
JSON tree is a starting point (most likely originating from being parsed from
source), `Json` instances can be created which hold the same reference to the
original tree, but point -- by means of a path -- to any subtree of the
original, without the performance cost of navigating the tree, or the
requirement to safely handle missing-value or type-mismatch errors which arise
because the path attempts to access a value which isn't available.
At some later point, if the JSON is to yield some useful data which we can do
interesting things with, we will need to perform the access, and assign a Scala
type to it, as it passes from the dynamic to the static world. It is at this
point that all access failures will arise, so by deferring them to a single
point, they can be handled just once.
Additionally, every `Json` instance stores a reference to the backend which was
used to create it, and which will be used to access it. As Rapture JSON permits
multiple different parsers to be used alongside each other, it is important
that the AST within each `Json` instance is always handled using the right
backend.
## Accessing JSON values
`Json` instances implement Scala's `Dynamic` trait, providing a very natural
way to refer to object fields within a `Json` value just by calling that field
name as if it were a method on the `Json` instance. Additionally, integers may
be applied to index into arrays.
For example, using the example JSON above, we can create a new `Json` instance
pointing to the string `"yellow"` as follows:
```scala
json.fruits(1).color
```
Remember, this is just creating a pointer into the `"yellow"` value; it's not
been accessed yet. To extract a value from a `Json` value, the `as` method is
used. `as` takes a single type parameter, and is the single point at which a
JSON type-mismatch or missing-value exception can occur.
```scala
json.fruits(1).color.as[String]
```
Rapture JSON uses Rapture Core's modes on the `as` method, thus allowing
failure cases to be handled using the preferred exception-handling strategy,
for example by throwing an exception or returning a `Try`. See the section on
error messages below.
Note that calling `toString`, as happens automatically after every evaluation
in the Scala REPL, *will* cause the AST to be accessed, but any errors will be
suppressed, and the `toString` method will return the string `"undefined"`.
A variety of types may be extracted from a `Json` value, including the
following:
- Primitive types, such as `String`, `Int`, `Double` and `Boolean`
- Scala collections of other extractable types, e.g. `List[Int]` or `Set[Int]`
- Case classes, extracted by the names of their parameters, provided the type
of every parameter is extractable
- `Option`s, where `None` will be extracted if the element is missing or the
wrong type
- `Json` types -- the no-op extractor
- Any other type for which an implicit `Extractor` exists in scope
These types compose, so it is possible to extract values of complex types like
`Option[Vector[MyCaseClass]]`.
## Creating JSON values
JSON values can be created in a number of different ways. If starting with a
JSON source, which will often be a `String` (but may be another type -- the
Jawn backend can parse directly from ByteBuffers, for example), we can call
`Json.parse(src)` to attempt to parse the source `src`.
`Json` values can also be created directly in code, using the `json` string
context, like so:
```scala
json"""{
"fruit": "apple",
"variants": ["cox", "braeburn"]
}"""
```
Much like an interpolated string, Scala expressions may be substituted into a
`json` string context, provided the expressions evaluate to a type which is
serializable to Json. Generally speaking, all types which can be extracted from
a `Json` value (primitives, collections, case classes, Json) can also be serialized,
like so:
```scala
val f = "apple"
json"""{
"fruit": $f,
"variants": ${List("cox", "braeburn")}
}"""
```
Any serializable type can also be converted to `Json` by applying it to the
`Json` object, for example this,
```scala
case class Fruit(name: String, variants: Set[String])
Json(Fruit("apple", Set("cox", "braeburn")))
```
will produce the same JSON as the previous examples.
An instructive compile error will be displayed in the event of an attempt to
serialize a type which cannot be serialized to `Json`.
## Pattern matching on JSON
An alternative way of extracting values from `Json` types in to use pattern
matching. A `Json` value can be pattern matched against JSON literals defined
inline in the case clause, like this:
```scala
val json: Json = Json.parse(src)
json match {
case json""" { "fruit": $name }""" =>
name.as[String]
case json""" { "vegetable": $name }""" =>
name.as[String]
}
```
This will first attempt to match any JSON object which contains a key called
`fruit`, and bind the value to the identifier `name`. If that match fails, it
will attempt to match any JSON object which contains a key called `vegetable`,
and likewise bind its value to `name`. In each case, we return the name as a
`String`. The call to `.as[String]` is necessary because, as before, the
compiler will no know nothing about the nature of the type at compile time, so
it must be explicitly specified.
Literal match values may also be explicitly specified, for example:
```scala
val json: Json = Json.parse(src)
json match {
case json""" { "fruit": "apple", "variety": $vs }""" =>
vs.as[Set[String]]
case json""" { "fruit": "lemon" }""" =>
Set()
}
```
Multiple values may be extracted, and the pattern match expression may involve
arbitrarily-deep object and array nesting.
The examples above use the default configuration for structural pattern
matching, however three configuration explicits control the strictness of
structural pattern matching.
- `patternMatching.exactObjects._`
- `patternMatching.exactArrays._`
- `patternMatching.exact._`
If it is required that pattern matching on JSON objects should match the entire
object, i.e. the existence of any keys in the object which are not specified in
the pattern should result in failure to match, then include the following
import somewhere within the scope of the pattern match:
```scala
import patternMatching.exactObjects._
```
By default, array elements specified in a pattern are matched positionally, and
superfluous array elements in the tail of the array are ignored, and the match
will be successful. If strict array matching is required, include:
```scala
import patternMatching.exactArrays._
```
If exact matching of both arrays and objects is required, then it is sufficient
to import
```scala
import patternMatching.exact._
```
## Modifying `Json`
Whatever underlying backend is used, the `Json` type is immutable. A small
number of methods are provided to create new `Json` values from existing
values. Given a `Json` value, a new key may be added using the following
syntax:
```scala
val j = json"""{ "fruit": "plum" }"""
j.copy(_.color = "purple")
```
This syntax is designed to resemble the syntax for adding a value to a
`scala.collection.Map`, whereby the tuple passed to the `+` operator contains a
key and a value, resulting in the addition of this value to the map. However,
with `Json` types, the "key" is a path into the `Json` structure, and the
"value" is the value to be serialized to JSON and stored at that position in
the JSON tree.
The `++` operator can be used to combine two JSON structures, like so:
```scala
val j1 = json"""{ "fruit": { "name": "grape" } }"""
val j2 = json"""{ "fruit": { "color": "white" } }"""
val json = j1 ++ j2
```
The resultant `json` value would be
```json
{
"fruit": {
"name": "grape",
"color": "white"
}
}
```
Currently, when merging, object keys from both sides will be merged, favoring
the right side in the event of a clash, and arrays will be concatenated. If the
types of corresponding values do not match, the value from the right side will
clobber that from the left. In a later version of Rapture JSON, more control
over mechanisms for combining and merging `Json` values may be provided through
configuration implicits.
## Error messages
By default, failures in Rapture JSON operations will result in an exception
being thrown, however, alternative exception handling methods can be used with
a simple import from the Rapture Core project which will determine the return
type of all fallible methods such as `Json.parse` and `as`. For example,
```scala
import rapture.core._
import modes.returnTry._
Json.parse(src)
```
will result in the return type of `Json.parse` changing from `Json` to
`Try[Json]`, safely capturing any failures which may result from the operation.
All Rapture JSON methods will throw a limited set of possible exceptions, which
are implemented as case classes inheriting from a sealed trait. If choosing to
use the `captureExceptions` mode, or another mode which captures the exception
and tracks the exception type in its signature, this allows exhaustivity
checking to be performed on errors, for example:
```scala
import modes.returnEither._
json.fruit.as[String] match {
case Right(f) =>
s"Found fruit $f"
case Left(TypeMismatchException(found, _, _)) =>
s"Fruit was the wrong type: $found"
case Left(MissingValueException(path)) =>
s"Fruit value was missing at path $path"
}
```
If either of the final two case clauses were omitted from this pattern match,
the compiler will issue a warning that the match may not be exhaustive.
## Mutable JSON
In the same way that the `List` type from the Scala collections library has a
corresponding mutable `ListBuffer` type, the `Json` type has a corresponding
`JsonBuffer` type, which supports mutability in addition to the operations
described above. The functionality of `JsonBuffer` is a strict superset of the
functionality of `Json`.
An empty `JsonBuffer` may be created with
```scala
val jb = JsonBuffer.empty
```
and can be mutated with instructions such as
```scala
jb.fruit.name = "apple"
jb.fruit.color = "green"
jb.fruit.varieties = List("cox")
```
resulting in
```json
{
"fruit": {
"name": "apple",
"color": "green",
"varieties": ["cox"]
}
}
```
Note that the top-level `fruit` object gets automatically created by the first
instruction, and that the right-hand side of the assignment is serialized to
JSON using Rapture's standard serialization scheme, causing a compile-time
error if the type cannot be serialized.
It is additionally possible to append items to the end of an array using the
`+=` operator, like this:
```scala
jb.fruit.varieties += "braeburn"
```
Note that it is required to
```scala
import rapture.json.dictionaries.dynamic._
```
or define a dictionary
```scala
implicit val dict = rapture.data.Dictionary.define("name", "color", "varieties", ...)
```
in order to compile your code. It goes part of the way towards ensuring you don't write `colour` when you meant `color`.
Mutable JSON is not yet available for all backends, though this work is in
progress. Note that the underlying JSON backend does not need to be inherently
mutable to support mutable JSON. If a backend which uses an immutable AST is
used, Rapture JSON will efficiently perform the necessary tree manipulations,
updating references as necessary to give the impression of a mutable data
structure. However, using a backend which uses a mutable JSON representation
will likely result in better performance.
## Converting JSON
All JSON values are represented by the same Scala type, `Json`, regardless of
whether they represents a JSON object, array, string, number or boolean, and
regardless of which backend was used to create it.
In order to combine two `Json` values, which may be represented using different
ASTs, it is sometimes necessary to convert the internal representations of the
JSON values from one backend to another. In all cases, this happens seamlessly
when required.
For example, given the two values `j1` and `j2`,
```scala
import jsonBackends.jawn._
val j1: Json = json"""{ "foo": "bar" }"""
import jsonBackends.jfc._
val j2: Json = json"""{ "baz": "quux" }"""
```
the two JSON objects can be merged with `j1 ++ j2`. This will traverse the AST
of the value `j2`, converting it from a JFC to a Jawn representation, and then
merge it with the value `j1` to produce a `Json` value, represented as a Jawn
AST.
Likewise, substitutions into other JSON values will invoke conversions, as
necessary. So, given the previous two values `j1` and `j2`, we could substitute
both into a new JSON object (represented by some third backend AST), and each
will be converted to the new AST representation.
```scala
import jsonBackends.argonaut._
val j3 = json"""{ "j1": $j1, "j2": $j2 }"""
```
Sometimes it is useful to eagerly force conversion of a `Json` value to the
current JSON backend. This can be achieved in one of two ways:
- extract a `Json` type from the existing `Json` value, i.e.
`jsonValue.as[Json]`
- construct a new `Json` value from the existing `Json` value, i.e.
`Json(jsonValue)`
These operations are equivalent, and usage is a matter of personal taste. If
the value `jsonValue` is already represented by the currently-scoped JSON
backend, these operations will be no-ops.
Given that conversion happens seamlessly, on demand, the detail of which AST is
used to represent the JSON is abstracted away from the user. It can, however,
be revealed in a couple of ways:
- extracting an `Any` from the `Json` value using `jsonValue.as[Any]`; this
returns the underlying representation of the JSON value
- getting the `JsonAst` from the `Json` value using `Json.ast(jsonValue)`
## Outputting JSON
Often, the easiest way to output JSON from the `Json` type is to call
`.toString` on the `Json` value. Although simple, this has the disadvantages
that it does not offer any flexibility in how the JSON is formatted, and it
always returns a `String` whereas other types, such as an input stream may be
more appropriate for some applications.
The more general method is to use the `Json.format` method, with an appropriate
implicit `Formatter` in scope. Two formatters are provided as standard:
- `formatters.humanReadable._`, which formats the JSON with newlines and
indentation, attempting to make it as readable as possible,
- `formatters.compact._`, which includes no unnecessary whitespace
Both formatters return `String`s, though it is possible for other backends to
provide their own formatters for outputting to other types.
For example,
```scala
import formatters.compact._
val out = Json.format(json)
```
## Defining custom extractors and serializers
In order to be able to extract or serialize values of a particular Scala type,
`T` to or from JSON, an implicit instance of `Extractor[T]` or `Serializer[T]`
must be available in scope.
### Extractors
The easiest way to define an `Extractor` for a particular type is to start with
an existing extractor, e.g. the `String` extractor, by summoning it with
`Json.extractor[String]`. Extractors are functors, so you can `map` across the
extractor to produce a new extractor for a different type. For example, to
create an extractor for `java.util.Date`s, where these are stored as numbers in
the JSON, we can write:
```scala
implicit val dateExtractor = Json.extractor[Long].map(new java.util.Date(_))
```
and it then becomes possible to extract a date, e.g.
```scala
val j = json"""{ "start": 1438967950000 }"""
val d = j.start.as[java.util.Date]
```
Often, the most useful starting point for defining a new extractor is the no-op
`Json` extractor, `Json.extractor[Json]`. This allows definitions such as:
```scala
implicit val rangeExt = Json.extractor[Json].map { j =>
Range(j.start.as[Int], j.end.as[Int])
}
```
or
```scala
implicit val msgExtractor = Json.extractor[Json].map {
case json"""{ "ignore": true }""" =>
None
case json"""{ "message": $msg, "ignore": false }""" =>
Some(Message(str.as[String]))
}
```
### Serializers
Likewise, `Serializer`s are cofunctors, so new serializers may be created by
`contramap`ping across an existing serializer. We can summon the serializer for
a type `T` with `Json.serializer[T]`. To produce a serializer for a type `S`
from this serializer, we need to provide the `contramap` method with a function
`S => T`, though because Scala's type system can't infer the type `S` from a
function literal, we need to specify this type explicitly to the `contramap`
method.
Here's an example:
```scala
implicit val exceptionSerializer = Json.serializer[String].contramap[Exception] { e =>
s"${e.getClass.getName}: ${e.getMessage}"
}
```
The existence of this implicit serializer will then result in any `Exception`
being serialized to a representative `String`, anywhere it needs to be
converted into a `Json` value.
As with `Extractor`s, the `Json` serializer is often a useful starting point:
```scala
implicit val eitherSerializer = Json.serializer[Json].contramap[Either[String, Int]] {
case Left(s) =>
json"""{ "branch": "left", "value": $s }"""
case Right(i) =>
json"""{ "branch": "right", "value": $i }"""
}
```
### Fallback extractors
Extractors may sometimes encounter JSON data that doesn't fit their expected
pattern, and result in failure. It can be useful to provide alternative
extractors for JSON in the event that the first one fails. Extractors can be
composed in this way using the `orElse` combinator.
For example, the following extractor redefines the `Int` extractor to also
accept integers provided as JSON strings as a fallback option:
```scala
implicit val intExt = Json.extractor[Int] orElse Json.extractor[String].map(_.toInt)
```
Hopefully this demonstrates the concise and readable syntax Rapture JSON uses
for defining extractors and serializers, and the ease with which they can be
composed and transformed.
================================================
FILE: doc/m4-release.md
================================================
# Changes since Rapture 2.0.0-M3
## HTML
### Support for more HTML syntax (help)
### Support for nesting iterables inside elements
## JSON
### Serialization and extraction of maps
### Bugfixes: serialization of string-like things
### Improvements to JSON addition
## I18n
### Google translate support
### Use & operator instead of | for (thanks to @odersky)
## HTTP
### Fix for match errors on content types (help)
###
## CLI
### Issue 61
### Optional extractors always extract
###
## Core
### Removal of some reflection (causing problems with Android and Scala JS)
================================================
FILE: dom/shared/src/main/scala/rapture/dom/dom.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.dom
import rapture.core._
import language.higherKinds
import language.implicitConversions
import language.dynamics
import scala.annotation._
import language.experimental.macros
trait ElementType
trait AttributeType
trait `DomNodes#apply` extends MethodConstraint
trait `Element#selectDynamic` extends MethodConstraint
object Applicable {
implicit def reportElementError[Child <: ElementType, Att <: AttributeType, Child2 <: ElementType,
Elem <: ElementType, Att2 <: AttributeType](value: DomNode[Child2, Elem, Att]): Any = macro DomMacros
.reportElementErrorMacro[Child, Att, Child2, Elem, Att2]
implicit def listToApplicable[Child <: ElementType,
Elem <: ElementType,
Att <: AttributeType,
Ap <: Element[Child, Elem, Att]](apps: List[Ap]): Element[Child, Elem, Att] = apps.head
implicit def wrapIterable[Child <: ElementType, This <: ElementType, Att <: AttributeType](
xs: Iterable[Element[Child, This, Att]]): ElementLike[Child, This, Att] = ElementSeq[Child, This, Att](xs)
}
trait Applicable[+ChildType, +ThisAttType, AppliedType[_ <: ElementType, _ <: ElementType, _ <: AttributeType]] {
def application[Child <: ElementType, This <: ElementType, Att <: AttributeType](
element: Element[Child, This, Att],
applied: Applicable[Child, Att, AppliedType]*): AppliedType[Child, This, Att]
}
sealed abstract class DomNode[+ChildType <: ElementType, +ThisType <: ElementType, ThisAttType <: AttributeType]
extends Applicable[ThisType, Nothing, AppliedElement] {
def block = true
def application[Child <: ElementType, This <: ElementType, Att <: AttributeType](
element: Element[Child, This, Att],
applied: Applicable[Child, Att, AppliedElement]*): AppliedElement[Child, This, Att] =
AppliedElement[Child, This, Att](
element.tagName,
element.attributes,
applied.to[List].asInstanceOf[List[Element[_ <: ElementType, Child, _ <: AttributeType]]],
element.forceClosingTag,
element.block
)
}
case class DomNodes[ChildType <: ElementType, ThisType <: ElementType, AttType <: AttributeType](
elements: Vector[Element[ChildType, ThisType, AttType]])
extends AnyVal {
def apply(i: Int = 0)(implicit mode: Mode[`DomNodes#apply`]) = mode.wrap(elements(i))
override def toString = elements.mkString("\n")
def \[Child <: ElementType, This <: ElementType, Att <: AttributeType](
tag: Tag[Child, This, Att]): DomNodes[Child, This, Att] =
DomNodes(elements.flatMap { xs =>
(xs \ tag).elements
})
def \\[Child <: ElementType, This <: ElementType, Att <: AttributeType](
tag: Tag[Child, This, Att]): DomNodes[Child, This, Att] =
DomNodes(elements.flatMap { xs =>
(xs \\ tag).elements
})
}
case class MissingAttributeException(name: String) extends Exception(s"The attribute $name was not found")
case class TextNode[ThisType <: ElementType, ThisAttType <: AttributeType, Position <: ElementType](text: String)
extends DomNode[Position, ThisType, ThisAttType] {
def format[Output](implicit formatter: DomFormatter[Output]): Output = formatter.format(this)
override def toString = DomFormatter.domFormatterImplicit.format(this)
override def block = false
}
case class Comment(comment: String) extends DomNode {
def format[Output](implicit formatter: DomFormatter[Output]): Output = formatter.format(this)
override def toString = DomFormatter.domFormatterImplicit.format(this)
}
object Element {
implicit def reportElementError2[Child <: ElementType, Att <: AttributeType, Child2 <: ElementType,
Elem <: ElementType](value: DomNode[Child2, Elem, Att]): Any = macro DomMacros
.reportElementError2Macro[Child, Att, Child2, Elem]
}
sealed abstract class ElementLike[ChildType <: ElementType, ThisType <: ElementType, AttType <: AttributeType]
extends DomNode[ChildType, ThisType, AttType]
with Applicable[ThisType, Nothing, AppliedElement]
with Dynamic
with Product
with Serializable {}
sealed abstract class Element[ChildType <: ElementType, ThisType <: ElementType, AttType <: AttributeType]
extends ElementLike[ChildType, ThisType, AttType] {
def tagName: String
def attributes: Map[AttributeKey[String, AttributeType], Any]
def children: List[DomNode[_ <: ElementType, ChildType, _ <: AttributeType]]
def forceClosingTag: Boolean
def block: Boolean
def format[Output](implicit formatter: DomFormatter[Output]): Output = formatter.format(this)
def selectDynamic(s: String)(implicit ar: AttributeKey[s.type, AttType], mode: Mode[`Element#selectDynamic`]) =
mode.wrap {
val ar2 = ar.asInstanceOf[AttributeKey[String, AttributeType]]
if (attributes.contains(ar2)) attributes(ar2).asInstanceOf[ar.Value]
else mode.exception(MissingAttributeException(ar2.attributeName))
}
def \[Child <: ElementType, This <: ElementType, Att <: AttributeType](
tag: Tag[Child, This, Att]): DomNodes[Child, This, Att] =
DomNodes[Child, This, Att](children.filter {
case elem: Element[_, _, _] => elem.tagName == tag.tagName
case _ => false
}.map(_.asInstanceOf[Element[Child, This, Att]]).to[Vector])
def \\[Child <: ElementType, This <: ElementType, Att <: AttributeType](
tag: Tag[Child, This, Att]): DomNodes[Child, This, Att] =
DomNodes(children.to[Vector].flatMap {
case e: Element[_, _, _] =>
val found = e \ tag
found.elements ++ (e \\ tag).elements
case _ => Vector()
})
override def toString = DomFormatter.domFormatterImplicit.format(this)
}
case class Tag[ChildType <: ElementType, ThisType <: ElementType, AttType <: AttributeType](
forceClosingTag: Boolean = false,
override val block: Boolean = true)(implicit assigned: AssignedName)
extends Element[ChildType, ThisType, AttType] {
type Content = AppliedElement[_ <: ElementType, ChildType, _ <: AttType]
def tagName = assigned.name.toLowerCase
def attributes = Map()
def children = List()
def apply[AppliedType[_ <: ElementType, _ <: ElementType, _ <: AttributeType] <: DomNode[_, _, _]](
first: Applicable[ChildType, AttType, AppliedType],
applied: Applicable[ChildType, AttType, AppliedType]*): AppliedType[ChildType, ThisType, AttType] =
first.application(this, first +: applied: _*)
}
case class ElementSeq[ChildType <: ElementType, ThisType <: ElementType, AttType <: AttributeType](
elems: Iterable[Element[ChildType, ThisType, AttType]])
extends ElementLike[ChildType, ThisType, AttType]
case class EmptyElement[ChildType <: ElementType, ThisType <: ElementType, AttType <: AttributeType](
tagName: String,
attributes: Map[AttributeKey[String, AttributeType], Any],
forceClosingTag: Boolean = false,
override val block: Boolean = true
) extends Element[ChildType, ThisType, AttType] {
def children = List()
def apply(elements: DomNode[_ <: ElementType, ChildType, _ <: AttributeType]*)
: AppliedElement[ChildType, ThisType, AttType] =
AppliedElement[ChildType, ThisType, AttType](tagName, attributes, elements.to[List], forceClosingTag, block)
}
case class AppliedElement[ChildType <: ElementType, ThisType <: ElementType, AttType <: AttributeType](
tagName: String,
attributes: Map[AttributeKey[String, AttributeType], Any] = Map(),
children: List[DomNode[_ <: ElementType, ChildType, _ <: AttributeType]] = Nil,
forceClosingTag: Boolean,
override val block: Boolean
) extends Element[ChildType, ThisType, AttType]
@implicitNotFound("Cannot access the attribute ${Name} on ${AttType} DOM nodes")
abstract class AttributeKey[+Name <: String, AttType <: AttributeType](val attributeName: String, actualName: String = null) {
type Value
override def toString = if (actualName == null) attributeName else actualName
def serialize(t: Value): String
def set[Elem <: ElementType](v: Value) =
new Attribute[Elem, AttType, Value](this.asInstanceOf[AttributeKey[String, AttributeType]], v)
override def hashCode = attributeName.hashCode
override def equals(that: Any) = that match {
case ar: AttributeKey[typ, attType] => ar.attributeName == attributeName
case _ => false
}
}
object Attribute {
def apply[Att <: AttributeType, V](name: String, actualName: String = null)(
serializer: V => String): AttributeKey[name.type, Att] { type Value = V } =
new AttributeKey[name.type, Att](if (actualName == null) name else actualName) {
type Value = V
def serialize(v: Value): String = serializer(v)
}
}
class Attribute[Elem <: ElementType, AttType <: AttributeType, Value](val id: AttributeKey[String, AttributeType],
val value: Value)
extends Applicable[Elem, AttType, EmptyElement] {
def name = id.attributeName
def application[Child <: ElementType, This <: ElementType, Att <: AttributeType](
element: Element[Child, This, Att],
applied: Applicable[Child, Att, EmptyElement]*): EmptyElement[Child, This, Att] = {
val as = applied
.to[List]
.map { x =>
val y = x.asInstanceOf[Attribute[ElementType, AttributeType, Any]]
y.id -> y.value.asInstanceOf[Any]
}
.toMap
EmptyElement(element.tagName, as, element.forceClosingTag, element.block)
}
}
================================================
FILE: dom/shared/src/main/scala/rapture/dom/format.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.dom
import rapture.core._
package domFormatters {
object compact {
implicit val domFormatterImplicit = new DomFormatter[String] {
def format(element: DomNode[_, _, _]): String = element match {
case TextNode(t) =>
text(t)
case Comment(c) =>
comment(c)
case elems: ElementSeq[_, _, _] =>
elems.elems.map { elem =>
val xs = elem.children.map(format).mkString
val as = elem.tagName +: elem.attributes.to[List].filter(_._2 != null).map {
case (k, v) =>
k.attributeName + "=\"" + k.serialize(v.asInstanceOf[k.Value]) + "\""
}
if (xs.isEmpty && !elem.forceClosingTag) s"<${as.mkString(" ")}/>"
else s"<${as.mkString(" ")}>$xs${elem.tagName}>"
}.mkString
case elem: Element[_, _, _] =>
val xs = elem.children.map(format).mkString
val as = elem.tagName +: elem.attributes.to[List].filter(_._2 != null).map {
case (k, v) =>
k.attributeName + "=\"" + k.serialize(v.asInstanceOf[k.Value]) + "\""
}
if (xs.isEmpty && !elem.forceClosingTag) s"<${as.mkString(" ")}/>"
else s"<${as.mkString(" ")}>$xs${elem.tagName}>"
}
}
}
}
object DomFormatter {
implicit val domFormatterImplicit: DomFormatter[String] = new DomFormatter[String] {
def format(element: DomNode[_, _, _]): String =
format(0, element).map {
case (i, s) =>
(" " * i) + s
}.mkString("\n")
protected def format(indent: Int, element: DomNode[_, _, _]): Vector[(Int, String)] = element match {
case TextNode(t) =>
Vector(indent -> text(t))
case Comment(c) =>
Vector(indent -> comment(c))
case elem: Element[_, _, _] =>
val children = elem.children.to[Vector]
//.asInstanceOf[Vector[DomNode[ElementType, ElementType, AttributeType]]]
val xs = children
.foldLeft(Vector[(Int, String)]() -> false) {
case ((Vector(), _), child) =>
(format(indent + 1, child), child.block)
case ((acc, blk), child) =>
val cs = format(indent + 1, child)
val join = cs.length == 1 && !blk
if (join) (acc.init :+ ((acc.last._1, acc.last._2 + cs(0)._2)), !join)
else (acc ++ cs, !join)
}
._1
val hasBlock = elem.children.exists(_.block)
val as = elem.tagName +: elem.attributes.to[List].filter(_._2 != null).map {
case (k, v) =>
k.attributeName + "=\"" + k.serialize(v.asInstanceOf[k.Value]) + "\""
}
if (xs.isEmpty && !elem.forceClosingTag) Vector(indent -> s"<${as.mkString(" ")}/>")
else if (hasBlock || elem.block)
(indent -> s"<${as.mkString(" ")}>") +: xs :+ (indent -> s"${elem.tagName}>")
else Vector(indent -> s"<${as.mkString(" ")}>${xs.map(_._2).mkString}${elem.tagName}>")
case elem: ElementSeq[_, _, _] =>
elem.elems.to[Vector].flatMap(format(indent, _))
}
}
}
trait DomFormatter[Output] {
protected def text(string: String): String = string.replace("&", "&").replace("<", "<").replace(">", ">")
protected def comment(string: String) = ""
def format(element: DomNode[_, _, _]): Output
}
================================================
FILE: dom/shared/src/main/scala/rapture/dom/macro.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.dom
import rapture.base._
object DomMacros {
// The macro is invoked primarily to provide meaningful errors
def reportElementErrorMacro[Child <: ElementType: c.WeakTypeTag,
Att <: AttributeType: c.WeakTypeTag,
Child2 <: ElementType: c.WeakTypeTag,
Elem <: ElementType: c.WeakTypeTag,
Att2 <: AttributeType: c.WeakTypeTag](c: WhiteboxContext)(
value: c.Expr[DomNode[Child2, Elem, Att]]): c.Expr[Any] = {
//c.Expr[Applicable[Child, Att2, DomNode]] = {
import c.universe._
if (weakTypeOf[Elem].weak_<:<(weakTypeOf[Child])) {
reify { value.splice.asInstanceOf[Applicable[Child, Att2, DomNode]] }
} else {
val found = weakTypeOf[Elem].toString.split(" with ").map(_.split("\\.").last).to[Vector] match {
case Vector(one) => one
case init :+ last => init.mkString(", ") + " or " + last
}
val expected = weakTypeOf[Child].toString.split(" with ").map(_.split("\\.").last).to[Vector] match {
case Vector(one) => one
case init :+ last => init.mkString(", ") + " or " + last
}
c.abort(c.enclosingPosition,
s"Attempted to nest a $found node in a position where only $expected nodes are " +
"permitted")
}
}
def reportElementError2Macro[Child <: ElementType: c.WeakTypeTag,
Att <: AttributeType: c.WeakTypeTag,
Child2 <: ElementType: c.WeakTypeTag,
Elem <: ElementType: c.WeakTypeTag](c: WhiteboxContext)(
value: c.Expr[DomNode[Child2, Elem, Att]]): c.Expr[Element[_, Child, _]] = {
import c.universe._
if (weakTypeOf[Elem].weak_<:<(weakTypeOf[Child])) {
reify { value.splice.asInstanceOf[Element[_ <: ElementType, Child, _ <: AttributeType]] }
} else {
val found = weakTypeOf[Elem].toString.split(" with ").map(_.split("\\.").last).to[Vector] match {
case Vector(one) => one
case init :+ last => init.mkString(", ") + " or " + last
}
val expected = weakTypeOf[Child].toString.split(" with ").map(_.split("\\.").last).to[Vector] match {
case Vector(one) => one
case init :+ last => init.mkString(", ") + " or " + last
}
c.abort(c.enclosingPosition,
s"Attempted to nest a $found node in a position where only $expected nodes are " +
"permitted")
}
}
}
================================================
FILE: etc/header
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
================================================
FILE: etc/updateheader.sh
================================================
#!/bin/bash
OLDHEADERSIZE=18
for FILE in $(find . -name '*.scala'); do
# Remove old header
sed -i 1,${OLDHEADERSIZE}d ${FILE}
# Create a new file with the new header
cat etc/header $FILE > $FILE.new
# Replace the old file with the new one
mv $FILE.new $FILE
done
================================================
FILE: fs/shared/src/main/scala/rapture/fs/files.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.fs
import rapture.core._
import rapture.io._
import rapture.uri._
import java.io.{Reader => _, Writer => _, _}
trait FsMethods extends MethodConstraint
/** Provides support for accessing the file system through FsUrls. This is a wrapper for Java's
* file handling facilities, and provides roughly the same functionality within the general URL
* framework. */
trait LowerPriorityImplicits {
/** Type class object for writing `FsUrl`s as `Output[Stream]`s */
implicit object FileStreamCharWriter extends Writer[FsUrl, Char] {
def output(url: FsUrl): Output[Char] =
new CharOutput(new BufferedWriter(new FileWriter(url.javaFile)))
}
implicit object FileStreamCharAppender extends Appender[FsUrl, Char] {
def appendOutput(url: FsUrl): Output[Char] =
new CharOutput(new BufferedWriter(new FileWriter(url.javaFile, true)))
}
implicit val fileSizable: Sizable[FsUrl, Byte] = new Sizable[FsUrl, Byte] {
/** Returns the size of the file in bytes. */
def size(file: FsUrl): Long = file.length(modes.throwExceptions())
}
implicit val fileDeletable: Deleter[FsUrl] = new Deleter[FsUrl] {
/** Returns the size of the file in bytes. */
def delete(file: FsUrl): Unit = file.javaFile.delete()
}
}
trait LowPriorityImplicits extends LowerPriorityImplicits {
/** Type class object for writing `Byte`s to `FsUrl`s */
implicit object FileStreamByteWriter extends Writer[FsUrl, Byte] {
def output(url: FsUrl): Output[Byte] =
new ByteOutput(new BufferedOutputStream(new FileOutputStream(url.javaFile)))
}
implicit object FileStreamByteAppender extends Appender[FsUrl, Byte] {
def appendOutput(url: FsUrl): Output[Byte] =
new ByteOutput(new BufferedOutputStream(new FileOutputStream(url.javaFile, true)))
}
implicit val fileMovable: Movable[FsUrl, FsUrl] = new Movable[FsUrl, FsUrl] {
def move(from: FsUrl, to: FsUrl): Movable.Summary = {
from.javaFile.renameTo(to.javaFile)
Movable.Summary(None)
// FIXME: Handle failure
}
}
/*implicit class FileCopyable(f: FsUrl) {
/** Renames this file to a new location. */
def renameTo(dest: FsUrl): Boolean = f.javaFile.renameTo(dest.javaFile)
/** Copies this file to a new location specified by the dest parameter. */
def copyTo(dest: FsUrl, overwrite: Boolean = false, recursive: Boolean = false)
(implicit sr: Reader[FsUrl, Byte], mode: Mode[FsMethods]):
mode.Wrap[Int, Exception] = mode.wrap {
if(dest.exists) {
if(f.isFile && !dest.isFile) throw new Exception("Cannot copy a file onto a directory")
else if(!f.isFile && dest.isFile) throw new Exception("Cannot copy a directory onto a file")
else if(!overwrite) throw new Exception("Destination already exists")
else if(f.isFile) sr.pump(f, dest)
else if(!recursive) throw new Exception("Cannot copy directory")
else NavigableFile.children(f)(raw).foldLeft(0) { (c, f2) =>
implicit val eh = raw
c + f2.copyTo(dest / f2.filename, overwrite, recursive)
}
} else {
if(f.isFile) sr.pump(f, dest) else {
dest.mkdir()
NavigableFile.children(f)(raw).foldLeft(0) { (c, f2) =>
implicit val eh = raw
c + f2.copyTo(dest / f2.filename, overwrite, recursive)
}
}
}
}
/** Moves this file to a new location specified by the dest parameter. This will first attempt
* to move the file by renaming it, but will attempt copying and deletion if renaming fails. */
def moveTo(dest: FsUrl)(implicit sr: Reader[FsUrl, Byte], mode: Mode[FsMethods]):
mode.Wrap[Boolean, Exception] =
mode.wrap(renameTo(dest) || (copyTo(dest)(sr, raw) > 0) && delete()(raw))
/** Deletes the file represented by this FsUrl. If the recursive flag is set and the
* filesystem object is a directory, all subfolders and their contents will also be
* deleted. */
def delete(recursive: Boolean = false)(implicit mode: Mode[FsMethods]):
mode.Wrap[Boolean, Exception] = mode.wrap(if(recursive) deleteRecursively(f)
else f.javaFile.delete())
private def deleteRecursively(file: FsUrl): Boolean = {
if(NavigableFile.isDirectory(file)(raw))
NavigableFile.children(file)(raw).foreach(deleteRecursively)
delete()(raw)
}
}*/
/** Specifies how file: URLs should be navigable. */
implicit object NavigableFile extends Navigable[FsUrl] {
def children(url: FsUrl)(implicit mode: Mode[`Navigable#children`]): mode.Wrap[List[FsUrl], Exception] =
mode.wrap { if (url.isFile) Nil else url.javaFile.list().to[List].map(url / _) }
def isDirectory(url: FsUrl)(implicit mode: Mode[`Navigable#isDirectory`]): mode.Wrap[Boolean, Exception] =
mode.wrap { url.javaFile.isDirectory() }
}
}
object `package` extends LowPriorityImplicits {
/** Type class object for reading `Byte`s from `FsUrl`s */
implicit object FileStreamByteReader extends JavaInputStreamReader[FsUrl](f => new FileInputStream(f.javaFile))
implicit class EnrichedFileUriContext(uc: UriContext.type) {
def file(constants: List[String])(variables: List[String]) = {
val fileUrl =
constants.zip(variables :+ "").map { case (a, b) => a + b }.mkString.split("/").filter(_ != "").to[Vector]
FsUrl(fileUrl)
}
}
}
object FsUrl {
implicit val hasResourceName: HasResourceName[FsUrl] = new HasResourceName[FsUrl] {
def resourceName(fsUrl: FsUrl): String = fsUrl.filename
}
implicit val fileCpUrl: ClasspathUrlable[FsUrl] = new ClasspathUrlable[FsUrl] {
def toClasspathUrlItem(f: FsUrl) = ClasspathUrlItem(List(new java.net.URL(f.toString)))
}
implicit def uriCapable: UriCapable[FsUrl] = new UriCapable[FsUrl] {
def uri(f: FsUrl): Uri =
Uri("file", f.elements.mkString("///", "/", ""))
}
implicit def fileSlashString: Dereferenceable[FsUrl, String, FsUrl] =
new Dereferenceable[FsUrl, String, FsUrl] {
def dereference(p1: FsUrl, p2: String) = {
val start = if (p1.elements.lastOption == Some("")) p1.elements.init else p1.elements
FsUrl(start :+ p2)
}
}
implicit def fileSlashRelativePath[RP <: RelativePath]: Dereferenceable[FsUrl, RP, FsUrl] =
new Dereferenceable[FsUrl, RP, FsUrl] {
def dereference(p1: FsUrl, p2: RP) = FsUrl(p1.elements.dropRight(p2.ascent) ++ p2.elements)
}
implicit def fileSlashRootedPath[RP <: RootedPath]: Dereferenceable[FsUrl, RP, FsUrl] =
new Dereferenceable[FsUrl, RP, FsUrl] {
def dereference(p1: FsUrl, p2: RP) = {
val start = if (p1.elements.lastOption == Some("")) p1.elements.init else p1.elements
FsUrl(start ++ p2.elements)
}
}
implicit def fileParentable: Parentable[FsUrl, FsUrl] = new Parentable[FsUrl, FsUrl] {
def parent(fsUrl: FsUrl): FsUrl = FsUrl(fsUrl.elements.dropRight(1))
}
}
/** Defines a URL for the file: scheme, and provides standard filesystem operations on the file
* represented by the URL. */
case class FsUrl(elements: Seq[String]) {
override def toString = s"file:///${elements.mkString("/")}"
/** The java.io.File corresponding to this FsUrl. */
lazy val javaFile: java.io.File = new java.io.File(this.uri.schemeSpecificPart.drop(2))
/** Returns true if the file or directory represented by this FsUrl can be read from. */
def readable: Boolean = javaFile.canRead()
/** Returns true if the file or directory represented by this FsUrl can be written to. */
def writable: Boolean = javaFile.canWrite()
/** Add a hook to the filesystem to delete this file upon shutdown of the JVM. */
def deleteOnExit(): Unit = javaFile.deleteOnExit()
/** Returns true if this object exists on the filesystem. */
def exists: Boolean = javaFile.exists()
/** Returns the filename of this filesystem object. */
def filename: String = javaFile.getName()
/** Returns true if the filesystem object represented by this FsUrl is a file, and false if
* it is a directory. */
def isFile: Boolean = javaFile.isFile()
/** Returns true if the file or directory is hidden. */
def hidden: Boolean = if (exists) javaFile.isHidden() else throw new Exception()
/** Returns the date of the last modification to the file or directory. */
def lastModified[I: TimeSystem.ByInstant](implicit mode: Mode[FsMethods]): mode.Wrap[I, Exception] =
mode.wrap(javaFile.lastModified() match {
case 0L => throw new Exception()
case d => ?[TimeSystem.ByInstant[I]].instant(d)
})
/** Returns the size of the file in bytes. */
def length(implicit mode: Mode[FsMethods]): mode.Wrap[Long, Exception] =
mode.wrap(javaFile.length() match {
case 0L if !exists => throw new Exception()
case x => x
})
/** If the filesystem object represented by this FsUrl does not exist, it is created as a
* directory, provided that either the immediate parent directory already exists, or the
* makeParents path is set. */
def mkdir(makeParents: Boolean = false)(implicit mode: Mode[FsMethods]): mode.Wrap[Boolean, Exception] =
mode.wrap(
if (makeParents) javaFile.mkdirs()
else
javaFile.mkdir())
/** Extract the file extension from the name of this file. */
def extension(implicit mode: Mode[FsMethods]): mode.Wrap[Option[String], Exception] =
mode.wrap(if (filename contains ".") Some(filename.split("\\.").last) else None)
}
/** The file scheme object used as a factory for FsUrls. */
object File extends FsUrl(Vector()) {
private val UrlRegex = """^file:///(.*)$""".r
/** Pares a path to a file */
def parse(s: String) = s match {
case UrlRegex(path) => FsUrl(path.split("\\/").to[Vector])
case path => FsUrl(path.split("\\/").to[Vector].dropWhile(_ == ""))
}
def homeDir = File.parse(System.getenv("HOME"))
}
================================================
FILE: google-translate/shared/src/main/scala/rapture/google-translate/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.i18n.googleTranslate
import rapture.base._
import rapture.i18n._
import scala.reflect._
import language.implicitConversions
import language.experimental.macros
object NotString {
implicit def ambiguous1: NotString[String] = null
implicit def ambiguous2: NotString[String] = null
implicit def unambiguous[S <: String]: NotString[S] = null
}
class NotString[S <: String]
class GoogleApiKey[S <: String](key: S)(implicit notString: NotString[S])
object GoogleApiKey {
def apply[S <: String](key: S)(implicit notString: NotString[key.type]): GoogleApiKey[key.type] =
new GoogleApiKey[key.type](key)(notString)
}
object `package` {
implicit def upcast[ToLang <: Language, FromLang <: Language, S <: String](from: I18n[String, FromLang])(implicit license: GoogleApiKey[S]): I18n[String, ToLang] =
macro Macros.missingTranslationsMacro[ToLang, FromLang, S]
}
object Macros {
def missingTranslationsMacro[ToLang <: Language: c.WeakTypeTag, FromLang <: Language: c.WeakTypeTag, S <: String: c.WeakTypeTag](c:
BlackboxContext)(from: c.Expr[I18n[String, FromLang]])(license: c.Expr[GoogleApiKey[S]]): c.Expr[I18n[String, ToLang]] = {
import c.universe._
import compatibility._
// FIXME: Extract this correctly!
val key = weakTypeOf[S].toString.split("\"")(1)
val fromLangs = (normalize(c)(weakTypeOf[FromLang]) match {
case rt: RefinedType => rt.parents
case typ: Type => List(typ)
}).map(_.toString.split("\\.").last.toLowerCase).to[Set]
val toLangs = (normalize(c)(weakTypeOf[ToLang]) match {
case rt: RefinedType => rt.parents
case typ: Type => List(typ)
}).map(_.toString.split("\\.").last.toLowerCase).to[Set]
val missing = toLangs -- fromLangs
def langs(tree: Tree): Map[String, String] = tree match {
case Apply(Select(Apply(Select(Select(Select(id1, id2), id3), id4), List(Apply(_, List(Literal(Constant(
str: String)))))), lang), _) if id1.toString == "rapture" && id2.toString == "i18n" &&
id3.toString == "package" && id4.toString == "I18nEnrichedStringContext" =>
Map(lang.toString -> str)
case Apply(app: Apply, _) =>
langs(app)
case Apply(TypeApply(Select(q, id6), _), List(app)) if id6.toString == "$bar" =>
langs(q) ++ langs(app)
}
val ls = langs(from.tree)
val extras = ls.find(_._1 == "en").orElse(ls.find(_._1 == "fr")).getOrElse(ls.head) match {
case (lang, text) =>
missing.map { to =>
val tran = GoogleTranslate.translate(key, text, lang.toUpperCase, to.toUpperCase).replaceAll("\"", "\\\\\"")
s"""${to.toLowerCase}"${tran}""""
}
}
c.abort(c.enclosingPosition, s"""Not all required language translations have been provided. Consider appending the following translations to the expression:\n\n ${extras.mkString("& ", " & ", "")}\n""")
}
}
object GoogleTranslate {
import rapture.uri._
import rapture.net._
import rapture.io._
import rapture.codec._, encodings.`UTF-8`._
import rapture.json._, jsonBackends.jawn._
implicit val dict = Dictionary.define("translations", "data", "translatedText")
def translate(key: String, text: String, from: String, to: String): String = {
val out = uri"https://www.googleapis.com/language/translate/v2?q=$text&target=$to&format=text&source=$from&key=$key".slurp[Char]
Json.parse(out).data.translations(0).translatedText.as[String]
}
}
================================================
FILE: html/shared/src/main/scala/rapture/html/doc.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.html
package doctypes {
object html5 {
implicit val implicitDoctype: Doctype = Doctype("html")
}
}
object Doctype {
implicit val defaultDoctype: Doctype = doctypes.html5.implicitDoctype
}
case class Doctype(parts: String*) {
override def toString = s""
}
case class HtmlDoc(html: htmlSyntax.HtmlRoot)(implicit val doctype: Doctype) {
def format = s"$doctype\n${html.format}"
}
================================================
FILE: html/shared/src/main/scala/rapture/html/phantom.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.html
import rapture.dom._
object Html5 {
trait Html extends AttributeType
trait Base extends AttributeType
trait Link extends AttributeType
trait Meta extends AttributeType
trait Style extends AttributeType
trait Script extends AttributeType
trait Body extends AttributeType
trait Blockquote extends AttributeType
trait Ol extends AttributeType
trait Li extends AttributeType
trait A extends AttributeType
trait Q extends AttributeType
trait Time extends AttributeType
trait Progress extends AttributeType
trait Meter extends AttributeType
trait Bdo extends AttributeType
trait Edit extends AttributeType
trait Img extends AttributeType
trait Iframe extends AttributeType
trait Embed extends AttributeType
trait Object extends AttributeType
trait Param extends AttributeType
trait Video extends AttributeType
trait Audio extends AttributeType
trait Source extends AttributeType
trait Canvas extends AttributeType
trait Map extends AttributeType
trait Area extends AttributeType
trait Col extends AttributeType
trait Td extends AttributeType
trait Th extends AttributeType
trait Form extends AttributeType
trait Fieldset extends AttributeType
trait Label extends AttributeType
trait Input extends AttributeType
trait Button extends AttributeType
trait Select extends AttributeType
trait Optgroup extends AttributeType
trait Option extends AttributeType
trait Textarea extends AttributeType
trait Output extends AttributeType
trait Details extends AttributeType
trait Command extends AttributeType
trait Bb extends AttributeType
trait Menu extends AttributeType
trait Global
extends Html
with Base
with Link
with Meta
with Style
with Script
with Body
with Blockquote
with Ol
with Li
with A
with Q
with Time
with Progress
with Meter
with Bdo
with Edit
with Img
with Iframe
with Embed
with Object
with Param
with Video
with Audio
with Source
with Canvas
with Map
with Area
with Col
with Td
with Th
with Form
with Fieldset
with Label
with Input
with Button
with Select
with Optgroup
with Option
with Textarea
with Output
with Details
with Command
with Bb
with Menu
trait Flow extends ElementType
trait Metadata extends ElementType
trait Top extends ElementType
trait Definitions extends ElementType
trait ListItems extends ElementType
trait TableItems extends ElementType
trait ColItems extends ElementType
trait TrItems extends ElementType
trait TdItems extends ElementType
trait OptionItems extends ElementType
trait Sectioning extends Flow
trait Heading extends Flow
trait Interactive extends Flow
trait Phrasing extends Flow
trait Embedded extends Phrasing
trait Text extends Phrasing
}
================================================
FILE: html/shared/src/main/scala/rapture/html/syntax.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.html
import rapture.dom._
import rapture.core._
import rapture.codec._
import rapture.net._
import rapture.uri._
import rapture.js._
import rapture.css._
import language.{dynamics, implicitConversions}
trait DynamicCssReferences
object dynamicCssReferencing {
def apply(): DynamicCssReferences = dynamicCssReferencingImplicit
implicit val dynamicCssReferencingImplicit: DynamicCssReferences = new DynamicCssReferences {}
}
object htmlSyntax {
import Html5._
class DynamicAttributeKey[Name <: String, Att <: AttributeType, Val](name: String, ser: Val => String) extends AttributeKey[Name, Att](name) with Dynamic {
type Value = Val
def serialize(v: Value): String = ser(v)
def selectDynamic(att: String) = Attribute[Global, String](s"$name-$att")(identity(_))
def updateDynamic[E <: ElementType](att: String)(v: String) = selectDynamic(att).set[E](v)
}
def dynamic[Att <: AttributeType, Val](name: String, actualName: String = null)(serializer: Val => String) = new DynamicAttributeKey[name.type, Att, Val](if(actualName == null) name else actualName, serializer)
implicit def stringToTextNode(str: String): TextNode[Nothing, Nothing, Html5.Text] =
TextNode[Nothing, Nothing, Html5.Text](str)
type HtmlRoot = Element[Top, ElementType, Html]
type HtmlElement[T <: ElementType] = Element[_ <: ElementType, _ <: T, _ <: AttributeType]
// FIXME: These tag types are not currently working
def A[T <: ElementType] = Tag[T, T, A](block = false)(new AssignedName("A"))
def Ins[T <: ElementType] = Tag[T, T, Edit]()(new AssignedName("Ins"))
def Del[T <: ElementType] = Tag[T, T, Edit]()(new AssignedName("Del"))
def Object[T <: Embedded] = Tag[T, T, Object]()(new AssignedName("Object"))
def Video[T <: Embedded with Interactive] = Tag[T, T, Video]()(new AssignedName("Video"))
def Audio[T <: Embedded with Interactive] = Tag[T, T, Audio]()(new AssignedName("Audio"))
def Canvas[T <: Embedded] = Tag[T, T, Canvas]()(new AssignedName("Canvas"))
val Html = Tag[Top, ElementType, Html]()
val Head = Tag[Metadata, Top, Nothing]()
val Title = Tag[Text, Metadata, Global]()
val Base = Tag[Nothing, Metadata, Base]()
val Link = Tag[Nothing, Metadata, Link]()
val Meta = Tag[Metadata, Metadata, Meta]()
val Style = Tag[Text, Metadata with Flow, AttributeType](block = true)
val Script = Tag[Text, Metadata with Phrasing, Script](forceClosingTag = true, block = true)
val Noscript = Tag[Text, Metadata with Phrasing, AttributeType]()
val Body = Tag[Flow, Top, Body]()
val Section = Tag[Flow, Sectioning, AttributeType]()
val Nav = Tag[Flow, Sectioning, AttributeType]()
val Article = Tag[Flow, Sectioning, AttributeType]()
val Aside = Tag[Flow, Sectioning, AttributeType]()
val H1 = Tag[Phrasing, Heading, AttributeType]()
val H2 = Tag[Phrasing, Heading, AttributeType]()
val H3 = Tag[Phrasing, Heading, AttributeType]()
val H4 = Tag[Phrasing, Heading, AttributeType]()
val H5 = Tag[Phrasing, Heading, AttributeType]()
val H6 = Tag[Phrasing, Heading, AttributeType]()
val Header = Tag[Flow, Heading, AttributeType]()
val Footer = Tag[Flow, Flow, AttributeType]()
val Address = Tag[Flow, Flow, AttributeType]()
val P = Tag[Phrasing, Flow, AttributeType]()
val Hr = Tag[Nothing, Flow, AttributeType]()
val Br = Tag[Phrasing, Nothing, AttributeType](block = false)
val Pre = Tag[Phrasing, Flow, AttributeType](block = false)
val Dialog = Tag[Definitions, Flow, AttributeType]()
val Blockquote = Tag[Flow, Sectioning, Blockquote]()
val Ol = Tag[ListItems, Flow, Ol]()
val Ul = Tag[ListItems, Flow, AttributeType]()
val Li = Tag[Flow, ListItems, Li]()
val Dl = Tag[Definitions, Flow, AttributeType]()
val Dt = Tag[Phrasing, Definitions, AttributeType]()
val Dd = Tag[Flow, Definitions, AttributeType]()
val Q = Tag[Phrasing, Phrasing, AttributeType]()
val Cite = Tag[Phrasing, Phrasing, AttributeType]()
val Em = Tag[Phrasing, Phrasing, AttributeType](block = false)
val Strong = Tag[Phrasing, Phrasing, AttributeType](block = false)
val Small = Tag[Phrasing, Phrasing, AttributeType]()
val Mark = Tag[Phrasing, Phrasing, AttributeType]()
val Dfn = Tag[Phrasing, Phrasing, AttributeType]()
val Time = Tag[Phrasing, Phrasing, AttributeType]()
val Progress = Tag[Phrasing, Phrasing, AttributeType]()
val Meter = Tag[Phrasing, Phrasing, Meter]()
val Code = Tag[Phrasing, Phrasing, AttributeType](block = false)
val Var = Tag[Phrasing, Phrasing, AttributeType]()
val Samp = Tag[Phrasing, Phrasing, AttributeType]()
val Kbd = Tag[Phrasing, Phrasing, AttributeType]()
val Sup = Tag[Phrasing, Phrasing, AttributeType](block = false)
val Sub = Tag[Phrasing, Phrasing, AttributeType](block = false)
val Span = Tag[Phrasing, Phrasing, AttributeType](block = false)
val I = Tag[Phrasing, Phrasing, AttributeType](block = false)
val B = Tag[Phrasing, Phrasing, AttributeType](block = false)
val Bdo = Tag[Phrasing, Phrasing, AttributeType]()
val Ruby = Tag[Phrasing, Phrasing, AttributeType]()
val Rt = Tag[Nothing, Phrasing, AttributeType]()
val Rp = Tag[Nothing, Phrasing, AttributeType]()
val Figure = Tag[Flow, Sectioning, AttributeType]()
val Img = Tag[Nothing, Embedded, Img]()
val Iframe = Tag[Text, Embedded, Iframe]()
val Embed = Tag[Text, Embedded, Embed]()
val Param = Tag[Flow, Embedded, Param]()
val Source = Tag[Nothing, Flow, Source]()
val Map = Tag[Flow, Flow, Map]()
val Area = Tag[Nothing, Phrasing, Area]()
val Table = Tag[TableItems, Flow, Area]()
val Caption = Tag[Phrasing, TableItems, AttributeType]()
val Colgroup = Tag[ColItems, TableItems, Col]()
val Col = Tag[Nothing, ColItems, Col]()
val Tbody = Tag[TrItems, TableItems, AttributeType]()
val Thead = Tag[TrItems, TableItems, AttributeType]()
val Tfoot = Tag[TrItems, TableItems, AttributeType]()
val Tr = Tag[TdItems, TrItems, AttributeType]()
val Td = Tag[Flow, TdItems, Td]()
val Th = Tag[Flow, TdItems, Th]()
val Form = Tag[Flow, Flow, Form]()
val Fieldset = Tag[Flow, Flow, Fieldset]()
val Label = Tag[Phrasing, Phrasing with Interactive, Label]()
val Input = Tag[Nothing, Phrasing with Interactive, Input]()
val Button = Tag[Nothing, Phrasing with Interactive, Button]()
val Select = Tag[OptionItems, Phrasing with Interactive, Select]()
val Datalist = Tag[OptionItems, Phrasing with Interactive, AttributeType]()
val Optgroup = Tag[OptionItems, Phrasing, Optgroup]()
val Option = Tag[Text, OptionItems, Option]()
val Textarea = Tag[Text, Phrasing with Interactive, Textarea](forceClosingTag = true)
val Output = Tag[Phrasing, Phrasing, Output]()
val Details = Tag[Flow, Interactive, Details]()
val Command = Tag[Nothing, Metadata with Phrasing, Command]()
val Bb = Tag[Phrasing, Phrasing with Interactive, Bb]()
val Menu = Tag[ListItems, Phrasing with Interactive, Menu]()
val Legend = Tag[Phrasing, Flow, AttributeType]()
val Div = Tag[Flow, Flow, AttributeType](forceClosingTag = true)
implicit def id = Attribute[Global, String]("id")(identity)
def id_=[E <: ElementType, Value: DomIdable](v: Value) = id.set[E](implicitly[DomIdable[Value]].domId(v))
implicit def lang = Attribute[Global, Symbol]("lang")(_.name)
def lang_=[E <: ElementType](v: Symbol) = lang.set[E](v)
implicit def translate = Attribute[Global, Boolean]("translate")(v => if (v) "yes" else "no")
def translate_=[E <: ElementType](v: Boolean) = translate.set[E](v)
object CssClassable {
implicit val cssClassable: CssClassable[CssClass] =
new CssClassable[CssClass] { def cssClass(cssClass: CssClass) = cssClass.classes.to[List] }
implicit def stringCssClassable(implicit dynamicCssReferencing: DynamicCssReferences): CssClassable[String] =
new CssClassable[String] { def cssClass(string: String) = List(string) }
implicit def symbolCssClassable(implicit dynamicCssReferencing: DynamicCssReferences): CssClassable[Symbol] =
new CssClassable[Symbol] { def cssClass(symbol: Symbol) = List(symbol.name) }
implicit def stringListCssClassable(implicit dynamicCssReferencing: DynamicCssReferences): CssClassable[List[String]] =
new CssClassable[List[String]] { def cssClass(list: List[String]) = list }
implicit def symbolListCssClassable(implicit dynamicCssReferencing: DynamicCssReferences): CssClassable[List[Symbol]] =
new CssClassable[List[Symbol]] { def cssClass(list: List[Symbol]) = list.map(_.name) }
}
trait CssClassable[Value] { def cssClass(value: Value): List[String] }
object DomIdable {
implicit val domIdable: DomIdable[DomId] =
new DomIdable[DomId] { def domId(value: DomId): String = value.id }
implicit def stringDomIdable(implicit dynamicCssReferencing: DynamicCssReferences): DomIdable[String] =
new DomIdable[String] { def domId(string: String): String = string }
implicit def symbolDomIdable(implicit dynamicCssReferencing: DynamicCssReferences): DomIdable[Symbol] =
new DomIdable[Symbol] { def domId(symbol: Symbol): String = symbol.name }
}
trait DomIdable[Value] { def domId(value: Value): String }
implicit def cls = Attribute[Global, Seq[String]]("cls", "class")(_.mkString(" "))
def cls_=[E <: ElementType, Value: CssClassable](value: Value) =
cls.set(implicitly[CssClassable[Value]].cssClass(value))
implicit def onload = Attribute[Body, Js]("onload")(_.content)
def onload_=[E <: ElementType](v: Js) = onload.set[E](v)
implicit def onclick = Attribute[Global, Js]("onclick")(_.content)
def onclick_=[E <: ElementType](v: Js) = onclick.set[E](v)
implicit def onkeypress = Attribute[Global, Js]("onkeypress")(_.content)
def onkeypress_=[E <: ElementType](v: Js) = onkeypress.set(v)
implicit def onmouseover = Attribute[Global, Js]("onmouseover")(_.content)
def onmouseover_=[E <: ElementType](v: Js) = onmouseover.set(v)
implicit def onmouseout = Attribute[Global, Js]("onmouseout")(_.content)
def onmouseout_=[E <: ElementType](v: Js) = onmouseout.set(v)
implicit def onchange = Attribute[Input, Js]("onchange")(_.content)
def onchange_=[E <: ElementType](v: Js) = onchange.set(v)
implicit def onblur = Attribute[Input, Js]("onblur")(_.content)
def onblur_=[E <: ElementType](v: Js) = onblur.set(v)
implicit def title = Attribute[Global, String]("title")(identity)
def title_=[E <: ElementType](v: String) = title.set[E](v)
implicit def alt = Attribute[Img with Area with Input, String]("alt")(identity)
def alt_=[E <: ElementType](v: String) = alt.set[E](v)
implicit def href = Attribute[Base with Link with A with Area, PathLink]("href")(_.link)
def href_=[E <: ElementType, L: Linkable](v: L) = href.set[E](implicitly[Linkable[L]].link(v))
implicit def name =
Attribute[
Meta with Iframe with Object with Param with Map with Form with Fieldset with Input with Button with Select with Textarea with Output,
Symbol]("name")(_.name)
def name_=[E <: ElementType](v: Symbol) = name.set[E](v)
implicit def selected = Attribute[Option, Boolean]("selected") { v =>
if (v) "selected" else null
}
def selected_=[E <: ElementType](v: Boolean) = selected.set[E](v)
implicit def cols = Attribute[Textarea, Int]("cols")(_.toString)
def cols_=[E <: ElementType](v: Int) = cols.set[E](v)
implicit def rows = Attribute[Textarea, Int]("rows")(_.toString)
def rows_=[E <: ElementType](v: Int) = rows.set[E](v)
implicit def colspan = Attribute[Td with Th, Int]("colspan")(_.toString)
def colspan_=[E <: ElementType](v: Int) = colspan.set[E](v)
implicit def rowspan = Attribute[Td with Th, Int]("rowspan")(_.toString)
def rowspan_=[E <: ElementType](v: Int) = rowspan.set[E](v)
implicit def wrap = Attribute[Textarea, Boolean]("wrap") { v =>
if (v) "wrap" else null
}
def wrap_=[E <: ElementType](v: Boolean) = wrap.set[E](v)
implicit def open = Attribute[Details, Boolean]("open") { v =>
if (v) "open" else null
}
def open_=[E <: ElementType](v: Boolean) = open.set[E](v)
implicit def max = Attribute[Progress with Meter with Input, Double]("max")(_.toString)
def max_=[E <: ElementType](v: Double) = max.set[E](v)
implicit def min = Attribute[Meter with Input, Double]("min")(_.toString)
def min_=[E <: ElementType](v: Double) = min.set[E](v)
implicit def low = Attribute[Meter, Double]("low")(_.toString)
def low_=[E <: ElementType](v: Double) = low.set[E](v)
implicit def high = Attribute[Meter, Double]("high")(_.toString)
def high_=[E <: ElementType](v: Double) = high.set[E](v)
implicit def optimum = Attribute[Meter, Double]("optimum")(_.toString)
def optimum_=[E <: ElementType](v: Double) = optimum.set[E](v)
implicit def span = Attribute[Col, Int]("span")(_.toString)
def span_=[E <: ElementType](v: Int) = span.set[E](v)
class HttpEquiv(val name: String)
case object contentType extends HttpEquiv("content-type")
case object defaultStyle extends HttpEquiv("default-style")
case object refresh extends HttpEquiv("refresh")
implicit def httpEquiv = Attribute[Meta, HttpEquiv]("httpEquiv", "http-equiv")(_.name)
def httpEquiv_=[E <: ElementType](v: HttpEquiv) = httpEquiv.set[E](v)
implicit def charset = Attribute[Meta with Script, Encoding]("charset")(_.name)
def charset_=[E <: ElementType](v: Encoding) = charset.set[E](v)
implicit def content = Attribute[Meta, String]("content")(identity)
def content_=[E <: ElementType](v: String) = content.set[E](v)
implicit def manifest = Attribute[Html, HttpUrl]("manifest")(_.toString)
def manifest_=[E <: ElementType](v: HttpUrl) = manifest.set[E](v)
implicit def target =
Attribute[Base with Link with A with Area with Form with Input with Button, Symbol]("target")(_.name)
def target_=[E <: ElementType](v: Symbol) = target.set[E](v)
sealed class Rel(val name: String)
case object alternate extends Rel("alternate")
case object author extends Rel("author")
case object bookmark extends Rel("bookmark")
case object help extends Rel("help")
case object license extends Rel("license")
case object next extends Rel("next")
case object nofollow extends Rel("nofollow")
case object noreferrer extends Rel("noreferrer")
case object prefetch extends Rel("prefetch")
case object prev extends Rel("prev")
case object search extends Rel("search")
case object stylesheet extends Rel("stylesheet")
case object tag extends Rel("tag")
implicit def rel = Attribute[Link with A with Area, Rel]("rel")(_.name)
def rel_=[E <: ElementType](v: Rel) = rel.set[E](v)
// FIXME: Provide &, | and ! operators to write media expressions, and implement all values
trait MediaExpr
sealed class Media(val name: String) extends MediaExpr { override def toString = name }
sealed class Device(val name: String) extends MediaExpr { override def toString = name }
case object all extends Device("all")
case object aural extends Device("aural")
case object braille extends Device("braille")
case object handheld extends Device("handheld")
case object projection extends Device("projection")
case object print extends Device("print")
case object screen extends Device("screen")
case object tty extends Device("tty")
case object tv extends Device("tv")
implicit def media = Attribute[Link with Style with A with Source with Area, MediaExpr]("media")(_.toString)
def media_=[E <: ElementType](v: MediaExpr) = media.set[E](v)
implicit def style = Attribute[Global, Css]("style")(_.content)
def style_=[E <: ElementType](v: Css) = style.set[E](v)
implicit def src =
Attribute[Script with Img with Iframe with Embed with Video with Audio with Source with Input, PathLink]("src")(
_.toString)
def src_=[E <: ElementType, L: Linkable](v: L) = src.set[E](implicitly[Linkable[L]].link(v))
implicit def value =
Attribute[Li with Progress with Meter with Param with Input with Button with Option, String]("value")(identity)
def value_=[E <: ElementType](v: String) = value.set[E](v)
implicit def typ =
Attribute[
Link with Style with Script with A with Embed with Object with Source with Area with Input with Button with Command with Bb with Menu,
String]("typ", "type")(identity)
def typ_=[E <: ElementType](v: String) = typ.set[E](v)
implicit def action = Attribute[Form with Input with Button, PathLink]("action")(_.link)
def action_=[E <: ElementType, L: Linkable](v: L) = action.set(implicitly[Linkable[L]].link(v))
implicit def method = Attribute[Form with Input with Button, String]("method")(identity)
def method_=[E <: ElementType](v: String) = method.set(v)
implicit def enctype = Attribute[Form with Input with Button, String]("enctype")(identity)
def enctype_=[E <: ElementType](v: String) = enctype.set(v)
implicit def checked = Attribute[Input, Boolean]("checked")(v => if (v) "checked" else null)
def checked_=[E <: ElementType](v: Boolean) = checked.set(v)
implicit def maxlength = Attribute[Input with Textarea, Int]("maxlength")(_.toString)
def maxlength_=[E <: ElementType](v: Int) = maxlength.set(v)
implicit def hreflang = Attribute[Link, Symbol]("hreflang")(_.name)
def hreflang_=[E <: ElementType](v: Symbol) = hreflang.set(v)
implicit def sizes = Attribute[Link, String]("sizes")(identity)
def sizes_=[E <: ElementType](v: String) = sizes.set(v)
implicit def scoped = Attribute[Style, Boolean]("scoped")(v => if (v) "scoped" else null)
def scoped_=[E <: ElementType](v: Boolean) = scoped.set(v)
implicit def async = Attribute[Script, Boolean]("async")(v => if (v) "async" else null)
def async_=[E <: ElementType](v: Boolean) = async.set(v)
implicit def defer = Attribute[Script, Boolean]("defer")(v => if (v) "defer" else null)
def defer_=[E <: ElementType](v: Boolean) = defer.set(v)
implicit def onbeforeunload = Attribute[Body, Js]("onbeforeunload")(_.content)
def onbeforeunload_=[E <: ElementType](v: Js) = onbeforeunload.set(v)
implicit def onerror = Attribute[Body, Js]("onerror")(_.content)
def onerror_=[E <: ElementType](v: Js) = onerror.set(v)
implicit def onhashchange = Attribute[Body, Js]("onhashchange")(_.content)
def onhashchange_=[E <: ElementType](v: Js) = onhashchange.set(v)
implicit def onmessage = Attribute[Body, Js]("onmessage")(_.content)
def onmessage_=[E <: ElementType](v: Js) = onmessage.set(v)
implicit def onoffline = Attribute[Body, Js]("onoffline")(_.content)
def onoffline_=[E <: ElementType](v: Js) = onoffline.set(v)
implicit def onpopstate = Attribute[Body, Js]("onpopstate")(_.content)
def onpopstate_=[E <: ElementType](v: Js) = onpopstate.set(v)
implicit def onresize = Attribute[Body, Js]("onresize")(_.content)
def onresize_=[E <: ElementType](v: Js) = onresize.set(v)
implicit def onstorage = Attribute[Body, Js]("onstorage")(_.content)
def onstorage_=[E <: ElementType](v: Js) = onstorage.set(v)
implicit def onunload = Attribute[Body, Js]("onunload")(_.content)
def onunload_=[E <: ElementType](v: Js) = onunload.set(v)
implicit def reversed = Attribute[Ol, Boolean]("reversed")(v => if (v) "reversed" else null)
def reversed_=[E <: ElementType](v: Boolean) = reversed.set(v)
implicit def start = Attribute[Ol, Int]("start")(_.toString)
def start_=[E <: ElementType](v: Int) = start.set(v)
implicit def ping = Attribute[Link with Area, PathLink]("ping")(_.link)
def ping_=[E <: ElementType, L: Linkable](v: L) = ping.set(implicitly[Linkable[L]].link(v))
implicit def cite = Attribute[Blockquote with Q with Edit, PathLink]("cite")(_.link)
def cite_=[E <: ElementType, L: Linkable](v: L) = cite.set(implicitly[Linkable[L]].link(v))
implicit def datetime = Attribute[Time with Edit, String]("datetime")(identity)
def datetime_=[E <: ElementType](v: String) = datetime.set(v)
implicit def dir = Attribute[Global, Symbol]("dir")(_.name)
def dir_=[E <: ElementType](v: Symbol) = dir.set(v)
implicit def usemap = Attribute[Img with Object, String]("usemap")(identity)
def usemap_=[E <: ElementType](v: String) = usemap.set(v)
implicit def ismap = Attribute[Img, Boolean]("ismap")(v => if (v) "ismap" else null)
def ismap_=[E <: ElementType](v: Boolean) = ismap.set(v)
implicit def width =
Attribute[Img with Iframe with Embed with Object with Video with Canvas with Input, Int]("width")(_.toString)
def width_=[E <: ElementType](v: Int) = width.set(v)
implicit def height =
Attribute[Img with Iframe with Embed with Object with Video with Canvas with Input, Int]("height")(_.toString)
def height_=[E <: ElementType](v: Int) = height.set(v)
implicit def sandbox = Attribute[Iframe, Boolean]("sandbox")(v => if (v) "sandbox" else null)
def sandbox_=[E <: ElementType](v: Boolean) = sandbox.set(v)
implicit def seamless = Attribute[Iframe, Boolean]("seamless")(v => if (v) "seamless" else null)
def seamless_=[E <: ElementType](v: Boolean) = seamless.set(v)
implicit def poster = Attribute[Video, PathLink]("poster")(_.link)
def poster_=[E <: ElementType, L: Linkable](v: L) = poster.set(implicitly[Linkable[L]].link(v))
implicit def data = dynamic[Object, String]("data")(identity)
def data_=[E <: ElementType](v: String) = data.set(v)
implicit def autobuffer = Attribute[Video with Audio, Boolean]("autobuffer")(v => if (v) "autobuffer" else null)
def autobuffer_=[E <: ElementType](v: Boolean) = autobuffer.set(v)
implicit def autoplay = Attribute[Video with Audio, Boolean]("autoplay")(v => if (v) "autoplay" else null)
def autoplay_=[E <: ElementType](v: Boolean) = autoplay.set(v)
implicit def loop = Attribute[Video with Audio, Boolean]("loop")(v => if (v) "loop" else null)
def loop_=[E <: ElementType](v: Boolean) = loop.set(v)
implicit def controls = Attribute[Video with Audio, Boolean]("controls")(v => if (v) "controls" else null)
def controls_=[E <: ElementType](v: Boolean) = controls.set(v)
implicit def coords = Attribute[Area, String]("coords")(identity)
def coords_=[E <: ElementType](v: String) = coords.set(v)
implicit def shape = Attribute[Area, String]("shape")(identity)
def shape_=[E <: ElementType](v: String) = shape.set(v)
implicit def headers = Attribute[Td with Th, Symbol]("headers")(_.name)
def headers_=[E <: ElementType](v: Symbol) = headers.set(v)
implicit def scope = Attribute[Th, Symbol]("scope")(_.name)
def scope_=[E <: ElementType](v: Symbol) = scope.set(v)
implicit def acceptCharset = Attribute[Form, String]("accept-charset")(identity)
def acceptCharset_=[E <: ElementType](v: String) = acceptCharset.set(v)
implicit def autocomplete = Attribute[Form with Input, Boolean]("autocomplete")(v => if (v) "on" else "off")
def autocomplete_=[E <: ElementType](v: Boolean) = autocomplete.set(v)
implicit def novalidate =
Attribute[Form with Input with Button, Boolean]("novalidate")(v => if (v) "novalidate" else null)
def novalidate_=[E <: ElementType](v: Boolean) = novalidate.set(v)
implicit def label = Attribute[Option with Command with Menu, String]("label")(identity)
def label_=[E <: ElementType](v: String) = label.set(v)
implicit def forName = Attribute[Option with Command with Menu, Symbol]("forName")(_.name)
def forName_=[E <: ElementType](v: Symbol) = forName.set(v)
implicit def `for` = Attribute[Label, Symbol]("for")(_.name)
def for_=[E <: ElementType](v: Symbol) = `for`.set(v)
implicit def accept = Attribute[Input with Menu, String]("accept")(identity)
def accept_=[E <: ElementType](v: String) = accept.set(v)
implicit def autofocus =
Attribute[Input with Button with Select with Textarea, Boolean]("autofocus")(v => if (v) "autofocus" else null)
def autofocus_=[E <: ElementType](v: Boolean) = autofocus.set(v)
implicit def list = Attribute[Input, Symbol]("list")(_.name)
def list_=[E <: ElementType](v: Symbol) = list.set(v)
implicit def multiple = Attribute[Input with Select, Boolean]("multiple")(v => if (v) "multiple" else null)
def multiple_=[E <: ElementType](v: Boolean) = multiple.set(v)
implicit def pattern = Attribute[Input, String]("pattern")(identity)
def pattern_=[E <: ElementType](v: String) = pattern.set(v)
implicit def placeholder = Attribute[Input, String]("placeholder")(identity)
def placeholder_=[E <: ElementType](v: String) = placeholder.set(v)
implicit def readonly = Attribute[Input with Textarea, Boolean]("readonly")(v => if (v) "readonly" else null)
def readonly_=[E <: ElementType](v: Boolean) = readonly.set(v)
implicit def required = Attribute[Input with Textarea, Boolean]("required")(v => if (v) "required" else null)
def required_=[E <: ElementType](v: Boolean) = required.set(v)
implicit def size = Attribute[Input with Select, Int]("size")(_.toString)
def size_=[E <: ElementType](v: Int) = size.set(v)
implicit def step = Attribute[Input, Int]("step")(_.toString)
def step_=[E <: ElementType](v: Int) = step.set(v)
implicit def icon = Attribute[Command, PathLink]("icon")(_.link)
def icon_=[E <: ElementType, L: Linkable](v: L) = icon.set(implicitly[Linkable[L]].link(v))
implicit def radiogroup = Attribute[Command, Symbol]("radiogroup")(_.name)
def radiogroup_=[E <: ElementType](v: Symbol) = radiogroup.set(v)
implicit def default = Attribute[Command, String]("default")(identity)
def default_=[E <: ElementType](v: String) = default.set(v)
case class TypeOption(typeName: String) extends AnyVal {
override implicit def toString = typeName
}
val hidden = TypeOption("hidden")
val text = TypeOption("text")
val button = TypeOption("button")
val tel = TypeOption("tel")
val url = TypeOption("url")
val email = TypeOption("email")
val password = TypeOption("password")
val date = TypeOption("date")
val month = TypeOption("month")
val week = TypeOption("week")
val datetimeLocal = TypeOption("datetime-local")
val time = TypeOption("time")
val number = TypeOption("number")
val range = TypeOption("range")
val color = TypeOption("color")
val checkbox = TypeOption("checkbox")
val radio = TypeOption("radio")
val file = TypeOption("file")
val submit = TypeOption("submit")
val image = TypeOption("image")
val reset = TypeOption("reset")
}
================================================
FILE: html/shared/src/test/scala/rapture/html/tests.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.html
import rapture.uri._
import rapture.net._
import rapture.js._
import dynamicCssReferencing._
object Tests {
import htmlSyntax._
def `Div can contain P` = Div(P)
def `Html can contain Head` = Html(Head)
def `Html can contain Body` = Html(Body)
def `Table can contain Tbody/Thead` = Table(Thead, Tbody)
def `Tbody can contain Tr` = Tbody(Tr, Tr, Tr)
def `Tr can contain Th/Tr` = Tr(Th, Td, Td, Td)
def `Div with id can contain P` = Div(id = 'foo)(P)
def `Html with id can contain Head` = Html(id = 'foo)(Head)
def `Html with id can contain Body` = Html(id = 'foo)(Body)
def `Table with id can contain Tbody/Thead` = Table(id = 'foo)(Thead, Tbody)
def `Tbody with id can contain Tr` = Tbody(id = 'foo)(Tr, Tr, Tr)
def `Tr with id can contain Th/Tr` = Tr(id = 'foo)(Th, Td, Td, Td)
def `Img has src attribute` = Img(src = ^ / "foo.jpg")
def `Link has hreflang attribute` = Link(hreflang = 'en)
def `Link has sizes attribute` = Link(sizes = "16x16")
def `Style has scoped attribute` = Style(scoped = true)
def `Script has async attribute` = Script(async = true)
def `Script has defer attribute` = Script(defer = true)
def `Body has onbeforeunload attribute` = Body(onbeforeunload = js"foo()")
def `Body has onerror attribute` = Body(onerror = js"foo()")
def `Body has onhashchange attribute` = Body(onhashchange = js"foo()")
def `Body has onmessage attribute` = Body(onmessage = js"foo()")
def `Body has onoffline attribute` = Body(onoffline = js"foo()")
def `Body has onpopstate attribute` = Body(onpopstate = js"foo()")
def `Body has onresize attribute` = Body(onresize = js"foo()")
def `Body has onstorage attribute` = Body(onstorage = js"foo()")
def `Body has onunload attribute` = Body(onunload = js"foo()")
def `Ol has reversed attribute` = Ol(reversed = true)
def `Ol has start attribute` = Ol(start = 10)
def `Link has ping attribute` = Link(ping = uri"http://foo/bar")
def `Blockquote has cite attribute` = Blockquote(cite = uri"http://foo/bar")
def `Time has datetime attribute` = Time(datetime = "2008-02-14")
def `P has dir attribute` = P(dir = 'rtl)
def `Img has alt attribute` = Img(alt = "foo")
def `Img has usemap attribute` = Img(usemap = "#foo")
def `Img has ismap attribute` = Img(ismap = true)
def `Iframe has width attribute` = Iframe(width = 200)
def `Iframe has height attribute` = Iframe(height = 300)
def `Iframe has sandbox attribute` = Iframe(sandbox = true)
def `Iframe has seamless attribute` = Iframe(seamless = true)
def `Object has data attribute` = Object(data = "foo.bar")
def `Video has poster attribute` = Video(poster = ^ / "foo.bar")
def `Video has autobuffer attribute` = Video(autobuffer = true)
def `Video has autoplay attribute` = Video(autoplay = true)
def `Video has loop attribute` = Video(loop = true)
def `Video has controls attribute` = Video(controls = true)
def `Area has coords attribute` = Area(coords = "124,58,8")
def `Area has shape attribute` = Area(shape = "124,58,8")
def `Td has headers attribute` = Td(headers = 'foo)
def `Th has scope attribute` = Th(scope = 'foo)
def `Form has accept-charset attribute` = Form(acceptCharset = "ISO-8859-1")
def `Input has autocomplete attribute` = Input(autocomplete = true)
def `Form has novalidate attribute` = Form(novalidate = true)
def `Command has label attribute` = Command(label = "foo")
def `Command has forName attribute` = Command(forName = 'foo)
def `Input has accept attribute` = Input(accept = "image/*")
def `Input has autofocus attribute` = Input(autofocus = true)
def `Input has list attribute` = Input(list = 'foo)
def `Input has multiple attribute` = Input(multiple = true)
def `Input has pattern attribute` = Input(pattern = "[A-Za-z]{3}")
def `Input has placeholder attribute` = Input(placeholder = "foo")
def `Input has readonly attribute` = Input(readonly = true)
def `Input has required attribute` = Input(required = true)
def `Input has size attribute` = Input(size = 20)
def `Input has step attribute` = Input(step = 2)
def `Command has icon attribute` = Command(icon = ^ / "foo.jpg")
def `Command has radiogroup attribute` = Command(radiogroup = 'foo)
def `Command has default attribute` = Command(default = "foo")
def `Label has for attribute` = Label(`for` = 'foo)
def `Fieldset can contain Legend` = Fieldset(Legend("foo"))
//def `Should fail` = Html(src = "foo")
def `Get Tds` = Table(Tbody(Tr(Td, Td, Td), Tr(Td, Td, Td)))
}
================================================
FILE: http/shared/src/main/scala/rapture/http/extractors.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.http
import rapture.mime._
import rapture.codec._
import rapture.uri._
object requestExtractors {
/** A standard implementaiton of a response which confirms cross-domain access corntrol */
def accessControlAllowOrigin(domain: String)(implicit enc: Encoding): Response =
StreamResponse(
200,
("Access-Control-Allow-Origin" -> domain) :: ("Access-Control-Allow-Credentials" -> "true") :: Response.NoCache,
MimeTypes.`application/xml`,
v => ())(enc)
/** Method for creating new HTTP header extractors for requests */
def withHttpHeader(h: String) = new HttpHeader(h)
class HasParam(p: Symbol) {
def unapply(r: HttpRequest): Option[Boolean] = Some(r.exists(p))
}
class GetParam(p: Symbol) { def unapply(r: HttpRequest): Option[String] = r.param(p) }
class GetCookie(p: Symbol) {
def unapply(r: HttpRequest): Option[String] = r.cookie(p)
}
object & {
def unapply(r: HttpRequest): Option[(HttpRequest, HttpRequest)] = Some((r, r))
}
class HasCookie(p: Symbol) {
def unapply(r: HttpRequest): Option[Boolean] =
Some(r.cookie(p).isDefined)
}
/** Method for producing new cookie extractors for requests */
def getCookie(c: Symbol) = new GetCookie(c)
def hasCookie(c: Symbol) = new HasCookie(c)
object AsInt {
def unapply(s: String): Option[Int] =
try Some(s.toInt)
catch { case e: Exception => None }
}
/** Extract the path from the request */
object Path { def unapply(r: HttpRequest): Option[RootedPath] = Some(r.path) }
/** Defines a pattern matching construct to be used to chain together constraints on requests */
object ~ { def unapply(r: HttpRequest) = Some((r, r)) }
/** Method for creating new parameter extractors for requests */
def getParam(p: Symbol) = new GetParam(p)
def hasParam(p: Symbol) = new HasParam(p)
class HttpHeader(p: String) { def unapply(r: HttpRequest): Option[String] = r.headers.get(p).flatMap(_.headOption) }
}
================================================
FILE: http/shared/src/main/scala/rapture/http/forms.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.http
import scala.language.higherKinds
import rapture.core._
import rapture.mime._
import rapture.uri._
import rapture.net._
import rapture.dom._
import rapture.html._
import rapture.css._, dynamicCssReferencing._
import scala.collection.mutable.ListBuffer
object Forms extends Widgets with Parsers {
class BasicForm(val name: Symbol,
val params: Map[String, String] = Map(),
val uploads: Map[String, Array[Byte]] = Map()) { form =>
type Field[T] <: BasicField[T]
val formName = name.name
protected val fields = new ListBuffer[Field[_]]
def submitted = params.contains(formName + "_submit")
def complete = submitted
def save() = fields.foreach(_.save())
trait BasicField[T] {
def name: Symbol
def fieldName: String = name.name
def paramValue: Option[String] = form.params.get(fieldName)
def value: Option[T] =
if (parser.submitted(stringValue)) Some(parser.parse(stringValue, dataValue)) else None
def dataValue: Option[Array[Byte]] = form.uploads.get(fieldName)
def stringValue: Option[String] =
if (form.submitted) paramValue else if (cell == null) None else parser.serialize(cell())
def fieldValue: String = stringValue.getOrElse("")
def apply(): T = value.get
def parser: FieldParser[T]
def cell: Cell[T]
def save(): Unit = value foreach { c =>
if (cell == null) () else cell.update(c)
}
override def toString = s"${fieldName}: value=${value}"
}
}
trait FieldLabels {
type FormField[T] <: LabelledField
trait LabelledField { def label: String }
}
trait FormValidation {
this: (BasicForm with FormValidation) =>
def validated = fields.forall(_.validated)
def showValidation = submitted && !validated
abstract override def complete = submitted && validated
type Field[T] <: ValidatedField[T]
trait ValidatedField[T] {
this: BasicField[T] =>
lazy val validationIssues: List[String] = if (!submitted) Nil else validator(stringValue)
def validated: Boolean = validationIssues.isEmpty
def validator: Option[String] => List[String]
def required: Boolean
override def toString =
s"${fieldName}: value=${value}, validated=${validated}, required=${required}, validator=${validator}, parser=${parser}, cell=${cell}, paramValue=${paramValue}"
}
// String validators
// FIXME: Reformat these lines
val validUrl: Option[String] => List[String] = {
case None => Nil
case Some(s) =>
if (s.matches("\\b(https?|ftp)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#" +
"/%=~_|]")) Nil
else List("Please enter a valid URL")
}
val validInteger: Option[String] => List[String] = {
case None => Nil
case Some(s) => if (s.matches("^-?[1-9][0-9]*$")) Nil else List("Please enter a valid number")
}
val validPhoneNumber: Option[String] => List[String] = {
case Some(s) =>
if (s.matches("""^[+\- ()0-9]*$""")) Nil
else
List(
"Please enter a valid tele" +
"phone number")
case None => Nil
}
val validTwitterHandle: Option[String] => List[String] = {
case Some(s) =>
if (s.matches("|[a-zA-Z0-9_]{1,15}")) Nil
else List("Please enter a valid Twitter handle, or leave this field blank.")
case None => Nil
}
val validEmailAddress: Option[String] => List[String] = {
case Some(s) =>
if (s.matches("""^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2}[a-z]*)$""")) Nil
else List("Please enter a valid email address")
case None => Nil
}
val optValidEmailAddress: Option[String] => List[String] = {
case Some(s) =>
if (s.matches("""^([_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-"+
"9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4}))?$""")) Nil
else
List(
"Please enter a valid email addre" +
"ss")
case None => Nil
}
val validDateTime: Option[String] => List[String] = {
case Some(s) =>
if (s.matches("[0-9][0-9]\\/[0-9][0-9]\\/[0-9][0-9] [0-9][0-" +
"9]:[0-9][0-9]:[0-9][0-9]")) Nil
else
List(
"Please enter a valid date, in the format DD/MM" +
"/YY hh:mm:ss.")
case None => Nil
}
def notEmpty(msg: String = "Value is required and can't be empty."): Option[String] => List[String] = {
case Some(s) => if (s.isEmpty) List(msg) else Nil
case None => Nil
}
def minimumLength(length: Int): Option[String] => List[String] = {
case Some(s) => if (s.length < 8) List(s"The password must be at least $length characters long") else Nil
case None => Nil
}
val isSlug: Option[String] => List[String] = {
case Some(s) =>
if (!s.matches("[a-z0-9]*"))
List(
"Value can only contain lower-case alphanum" +
"eric characters.")
else Nil
case None => Nil
}
val isChecked: Option[String] => List[String] = {
case Some(s) => Nil
case None => List("You must check this field to continue.")
}
def notDuplicate(xs: List[String]): Option[String] => List[String] = {
case Some(s) =>
if (xs contains s)
List(
"This value is not unique. Please choose something di" +
"fferent.")
else Nil
case None => Nil
}
}
trait FormHelp {
this: BasicForm =>
type Field[T] <: HelpField[T]
trait HelpField[T] extends BasicField[T] { def help: String }
}
trait Preprocessing {
this: BasicForm =>
type Field[T] <: PreprocessedField[T]
trait PreprocessedField[T] extends BasicField[T] {
def processString(s: String): String
override def stringValue = super.stringValue.map(processString)
}
}
/** Adds renderability functionality to a form. */
trait RenderableForm {
this: (BasicForm with RenderableForm) =>
type Field[T] <: RenderableField[T]
type RenderType
type FormPart
type RenderedForm
val formParts = new ListBuffer[FormPart]
def wrap[T, F <: Field[T], W <: Widget](field: F, widget: W)(implicit renderer: Renderer[T, F, W]): FormPart
def content(fp: FormPart) = formParts += fp
def render: RenderedForm
// asInstanceOf[F] is here as an indirect consequence of compiler bug SI-6443
trait RenderableField[T] {
this: Field[T] =>
def as[F <: Field[T], W <: Widget](w: W)(implicit renderer: Renderer[T, F, W]): this.type = {
formParts += wrap[T, F, W](this.asInstanceOf[F], w)(renderer)
fields += this
this
}
}
trait Renderer[T, -F <: RenderableField[T], -W <: Widget] {
def render(f: F, w: W): RenderType
def hideLabel: Boolean = false
}
}
object WebForm {
implicit class FormExtras[F <: Forms.WebForm[_]](f: F) {
def show[T: HttpHandler](p1: F => T) = new {
def andThen[S: HttpHandler](p2: F => S): Response =
if (f.complete) {
f.save()
?[HttpHandler[S]].response(p2(f))
} else ?[HttpHandler[T]].response(p1(f))
}
}
}
abstract class WebForm[L](name: Symbol,
params: Map[String, String] = Map(),
uploads: Map[String, Array[Byte]] = Map(),
val postMethod: HttpMethods.FormMethod = HttpMethods.Post,
val formAction: L = ^)(implicit actionLinkableParam: Linkable[L])
extends BasicForm(name, params, uploads)
with RenderableForm
with FieldLabels
with Preprocessing
with FormValidation
with FormHelp {
implicit protected def actionLinkable: Linkable[L] = actionLinkableParam
def encoding: MimeTypes.MimeType =
if (fields.exists(_.needsMultipart)) MimeTypes.`multipart/form-data`
else MimeTypes.`application/x-www-form-urlencoded`
class Field[T](val name: Symbol,
val label: String,
val cell: Cell[T],
val parser: FieldParser[T],
process: String => String,
validate: Option[String] => List[String],
val required: Boolean,
val help: String,
val needsMultipart: Boolean = false)
extends BasicField[T]
with RenderableField[T]
with LabelledField
with PreprocessedField[T]
with ValidatedField[T]
with HelpField[T] {
def processString(s: String) = process(s)
def validator = validate
}
def field[T: FieldParser](name: Symbol,
label: String,
cell: Cell[T] = null,
process: (String => String) = identity[String],
validate: Option[String] => List[String] = { s =>
Nil
},
required: Boolean = false,
help: String = "") =
new Field[T](name,
label,
cell,
?[FieldParser[T]],
process,
validate,
required,
help,
?[FieldParser[T]].needsMultipart)
import htmlSyntax._
type RenderType = DomNode[_ <: ElementType, Html5.Phrasing, _ <: AttributeType]
implicit val stringRenderer = new Renderer[String, Field[String], StringInput] {
def render(f: Field[String], w: StringInput): RenderType =
Input(htmlSyntax.name = f.name, typ = "text", value = f.fieldValue)
}
implicit val passwordRenderer = new Renderer[String, Field[String], PasswordInput] {
def render(f: Field[String], w: PasswordInput): RenderType =
Input(htmlSyntax.name = f.name, typ = "password", value = f.fieldValue)
}
implicit val uploadRenderer = new Renderer[Array[Byte], Field[Array[Byte]], FileUploader] {
def render(f: Field[Array[Byte]], w: FileUploader): RenderType =
Input(htmlSyntax.name = f.name, typ = "file", value = f.fieldValue)
}
implicit val checkboxRenderer = new Renderer[Boolean, Field[Boolean], Checkbox] {
override def hideLabel = true
def render(f: Field[Boolean], w: Checkbox): RenderType =
Label(
Input(typ = "checkbox",
htmlSyntax.value = "1",
htmlSyntax.name = f.name,
checked = f.value.getOrElse(false)),
" " + f.label
)
}
implicit val textareaRenderer = new Renderer[String, Field[String], TextArea] {
def render(f: Field[String], w: TextArea): RenderType =
Textarea(htmlSyntax.name = f.name, maxlength = w.maxLength.getOrElse(-1))(TextNode(f.fieldValue))
}
implicit def dropdownRenderer[T, Q] = new Renderer[T, Field[T], Dropdown[Q]] {
def render(f: Field[T], w: Dropdown[Q]): RenderType =
Select(htmlSyntax.name = f.name)(
w.options.map { opt =>
Option(value = w.id(opt))(TextNode(w.description(opt)))
}: _*
)
}
implicit def radioListRenderer[T, Q] = new Renderer[T, Field[T], RadioList[Q]] {
def render(f: Field[T], w: RadioList[Q]): RenderType =
Span(style = css"display:inline-block")(
w.options.flatMap { opt =>
List(
Span(
Input(typ = "radio",
htmlSyntax.name = f.name,
value = w.id(opt),
checked = w.id(opt) == f.fieldValue),
" " + w.description(opt),
Br
)
)
}: _*
)
}
implicit val hiddenRenderer = new Renderer[String, Field[String], Hidden] {
def render(f: Field[String], w: Hidden): RenderType =
Input(typ = "hidden", htmlSyntax.name = f.name, htmlSyntax.value = f.fieldValue)
}
}
class BootstrapForm[L: Linkable](name: Symbol,
params: Map[String, String],
uploads: Map[String, Array[Byte]] = Map(),
postMethod: HttpMethods.FormMethod = HttpMethods.Post,
formAction: L = ^)
extends WebForm[L](name, params, uploads, postMethod, formAction)
with FormValidation {
import htmlSyntax._
type FormPart = DomNode[_ <: ElementType, Html5.Flow, _ <: AttributeType]
type RenderedForm = HtmlElement[Html5.Flow]
def hideLabels = false
def wrap[T, F <: Field[T], W <: Widget](field: F, widget: W)(implicit renderer: Renderer[T, F, W]): FormPart =
Div(cls = List.strap("control-group", field.validationIssues.headOption.map(x => "error")))(
Label(cls = "control-label" /*, forName = field.name.name*/ )(TextNode(field.label)),
Div(cls = 'controls)(
renderer.render(field, widget),
Div(
Div,
field.validationIssues.map { i =>
Span(cls = "help-inline")(i + " ")
}: _*
)
)
)
def render: RenderedForm =
Form(enctype = encoding.toString, cls = 'form, action = formAction, method = postMethod.toString)(
Fieldset(
formParts.head,
List.strap(
formParts.tail.toList,
submitRow
): _*
)
)
def submitRow =
Div(
Input(htmlSyntax.name = Symbol(formName + "_submit"),
typ = "submit",
cls = List("btn", "btn-primary"),
value = submitButtonText))
def submitButtonText = "Save"
}
trait TabularLayout[L] {
this: (WebForm[L] with TabularLayout[L]) =>
import htmlSyntax._
type FormPart = List[HtmlElement[Html5.TrItems]]
type RenderedForm = HtmlElement[Html5.Flow]
def hideLabels = false
def wrap[T, F <: Field[T], W <: Widget](field: F, widget: W)(implicit renderer: Renderer[T, F, W]): FormPart = {
List.strap(
field.validationIssues.map { err =>
Tr(Td(colspan = 3)(""), Td(cls = 'validation)(err))
},
Tr(Td,
List.strap(
if (hideLabels) Nil
else if (renderer.hideLabel) List(Td(""), Td(""))
else
List(
Td(field.label),
Td(if (field.required) "*" else "")
),
Td(renderer.render(field, widget))
): _*)
)
}
def render: RenderedForm = {
val fps = formParts.flatten
Form(enctype = encoding.toString, action = formAction, method = postMethod.toString)(
Table(
Tbody(
fps.head,
List.strap(
fps.tail.toList,
submitRow
): _*
)
)
)
}
def submitButtonText = "Save"
def submitRow =
if (hideLabels) Tr(Td, Td(submitButton))
else
Tr(
Td,
Td,
Td,
Td(submitButton)
)
def submitButton: HtmlElement[Html5.Flow] =
Input(htmlSyntax.name = Symbol(formName + "_submit"), value = submitButtonText, typ = "submit")
}
}
trait Parsers {
@annotation.implicitNotFound(
"Unable to use values of type ${Value} in form fields without a corresponding FieldParser.")
trait FieldParser[Value] {
def parse(value: Option[String], data: Option[Array[Byte]] = None): Value
def serialize(value: Value): Option[String]
def submitted(value: Option[String]): Boolean = value.isDefined
def needsMultipart: Boolean = false
}
implicit val StringParser = new FieldParser[String] {
def parse(s: Option[String], data: Option[Array[Byte]] = None) = s.getOrElse("")
def serialize(s: String): Option[String] = Some(s)
}
implicit val IntParser = new FieldParser[Int] {
def parse(s: Option[String], data: Option[Array[Byte]] = None): Int = s.get.toInt
def serialize(value: Int) = Some(value.toString)
}
implicit val BooleanParser = new FieldParser[Boolean] {
def parse(s: Option[String], data: Option[Array[Byte]] = None) = s.isDefined
def serialize(value: Boolean) = if (value) Some("") else None
override def submitted(value: Option[String]): Boolean = true
}
implicit val DataParser = new FieldParser[Array[Byte]] {
def parse(s: Option[String], data: Option[Array[Byte]] = None) = data.getOrElse(Array[Byte]())
def serialize(value: Array[Byte]) = Some("")
override def needsMultipart: Boolean = true
}
def enumParser(enum: Enumeration) = new FieldParser[enum.Value] {
def parse(s: Option[String], data: Option[Array[Byte]] = None) = enum(s.get.toInt)
def serialize(value: enum.Value) = Some(value.id.toString)
}
}
================================================
FILE: http/shared/src/main/scala/rapture/http/handlers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.http
import scala.xml._
import scala.concurrent._
import rapture.io._
import rapture.core._
import rapture.time._
import rapture.json._
import rapture.uri._
import rapture.mime._
import rapture.fs._
import rapture.html._
import rapture.dom._
import rapture.codec._
trait HttpHandler_1 {
implicit val linkRedirectHandler = new HttpHandler[PathLink] {
def response(link: PathLink) = RedirectResponse(Nil, link.toString)
}
}
trait HttpHandler[-T] { httpHandler =>
def response(t: T): Response
def contraMap[S](fn: S => T): HttpHandler[S] = new HttpHandler[S] {
def response(t: S) = httpHandler.response(fn(t))
}
}
object extensionBasedMimeTypes {
implicit def handler[T: Linkable](implicit reader: Reader[T, Byte]): HttpHandler[T] = new HttpHandler[T] {
def response(in: T) = {
val input = reader.input(in)
val parts = implicitly[Linkable[T]].link(in).link.split("\\.").to[List]
val extension = if (parts.length < 2) Nil else List(parts.last)
val mime = extension.flatMap(MimeTypes.extension).headOption.getOrElse(MimeTypes.`application/octet-stream`)
ByteStreamResponse(200, Response.NoCache, mime, { os =>
input > os
os.close()
})
}
}
}
object HttpHandler extends HttpHandler_1 {
implicit def charInputHandler(implicit enc: Encoding, mimeType: MimeTypes.MimeType) = new HttpHandler[Input[Char]] {
def response(in: Input[Char]) =
StreamResponse(200, Response.NoCache, mimeType, { os =>
in > os
os.close()
})
}
implicit val StringInputHandler = new HttpHandler[Input[String]] {
import encodings.`UTF-8`._
def response(in: Input[String]) =
StreamResponse(200, Response.NoCache, MimeTypes.`text/plain`, { os =>
var ln = in.read()
while (ln != None) {
(ln + "\n").input > os
ln = in.read()
}
os.close()
})
}
implicit def xmlHandler(implicit enc: Encoding) = new HttpHandler[Seq[Node]] {
def response(t: Seq[Node]) =
StreamResponse(200, Response.NoCache, MimeTypes.`application/xml`, { os =>
("\n").input > os
t.toString.input > os
os.close()
})
}
implicit def htmlDocHandler(implicit f: DomFormatter[String]): HttpHandler[HtmlDoc] = new HttpHandler[HtmlDoc] {
def response(htmlDoc: HtmlDoc) =
StreamResponse(200, Response.NoCache, MimeTypes.`text/html`, { out =>
(htmlDoc.doctype.toString + "\n").input > out
htmlDoc.html.format.input > out
out.close()
})(encodings.`UTF-8`())
}
/*implicit def csvHandler(implicit enc: Encoding) = new HttpHandler[Csv] {
def response(csv: Csv) = StreamResponse(200, List("Pragma" -> "public",
"Content-Disposition" -> "attachment;filename=data.csv",
"Expires" -> "Sat, 6 May 1995 12:00:00 GMT",
"Cache-Control" -> "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"
),
MimeTypes.`text/csv`, { os =>
csv.toString.input > os
os.close()
})
}*/
/*implicit def cssHandler(implicit enc: Encoding) = new HttpHandler[HtmlCss.Stylesheet] {
def response(css: HtmlCss.Stylesheet) = StreamResponse(200, Response.NoCache,
MimeTypes.`text/css`, { os =>
css.toString.input > os
os.close()
})
}*/
implicit def stringHandler(implicit enc: Encoding) = new HttpHandler[String] {
def response(t: String) =
StreamResponse(200, Response.NoCache, MimeTypes.`text/plain`, { os =>
t.input > os
os.close()
})
}
implicit def byteInputHandleri(implicit mimeType: MimeTypes.MimeType) = new HttpHandler[Input[Byte]] {
def response(in: Input[Byte]) =
ByteStreamResponse(200, Response.NoCache, mimeType, { os =>
in > os
os.close()
})
}
implicit def fileHandler = new HttpHandler[FsUrl] {
def response(file: FsUrl) =
FileResponse(200,
Response.NoCache,
file.extension.toList.flatMap(MimeTypes.extension).headOption.getOrElse(MimeTypes.`text/plain`),
file)
}
implicit def cacheHandler[T](implicit h: HttpHandler[T]): HttpHandler[Cached[T]] = new HttpHandler[Cached[T]] {
def response(resp: Cached[T]) = {
val r = h.response(resp.toCache)
val dateFormat = DateFormat("EEE, d MMM yyyy")
val timeFormat = TimeFormat("HH:mm:ss z")
val lastModified = List("Last-modified" -> resp.lastModified.format(dateFormat, timeFormat))
r match {
case BufferResponse(code, headers, contentType, buffers) =>
BufferResponse(code, lastModified, contentType, buffers)
case sr @ StreamResponse(code, headers, contentType, send) =>
StreamResponse(code, lastModified, contentType, send)(sr.encoding)
case ByteStreamResponse(code, headers, contentType, send) =>
ByteStreamResponse(code, lastModified, contentType, send)
case ErrorResponse(code, headers, message, detail) =>
ErrorResponse(code, lastModified, message, detail)
case FileResponse(code, headers, contentType, file) =>
FileResponse(code, lastModified, contentType, file)
case RedirectResponse(headers, location) =>
RedirectResponse(lastModified, location)
}
}
}
implicit def attachmentHandler[T](implicit h: HttpHandler[T]): HttpHandler[Attachment[T]] =
new HttpHandler[Attachment[T]] {
def response(resp: Attachment[T]) = {
val r = h.response(resp.original)
val headers = ("Content-Disposition" -> ("attachment; filename=" + resp.filename)) :: r.headers.toList
r match {
case BufferResponse(code, headers, contentType, buffers) =>
BufferResponse(code, headers, contentType, buffers)
case sr @ StreamResponse(code, headers, contentType, send) =>
StreamResponse(code, headers, contentType, send)(sr.encoding)
case ByteStreamResponse(code, headers, contentType, send) =>
ByteStreamResponse(code, headers, contentType, send)
case ErrorResponse(code, headers, message, detail) =>
ErrorResponse(code, headers, message, detail)
case FileResponse(code, headers, contentType, file) =>
FileResponse(code, headers, contentType, file)
case RedirectResponse(headers, location) =>
RedirectResponse(headers, location)
}
}
}
implicit def futureHandler[T](implicit h: HttpHandler[T], ec: ExecutionContext): HttpHandler[Future[T]] =
new HttpHandler[Future[T]] {
def response(future: Future[T]) = h.response(Await.result(future, duration.Duration.Inf))
}
implicit val nullHandler = new HttpHandler[Response] { def response(r: Response) = r }
implicit def jsonHandler(implicit enc: Encoding) = new HttpHandler[Json] {
def response(t: Json) =
StreamResponse(200, Response.NoCache, MimeTypes.`application/json`, { os =>
t.toString.input > os
os.close()
})
}
/*implicit def pageHandler(implicit enc: Encoding) = new HttpHandler[Layout.Page] {
def response(page: Layout.Page) = StreamResponse(page.httpStatus, Response.NoCache,
MimeTypes.`text/html`, { os =>
page.stream > os
})
}*/
}
================================================
FILE: http/shared/src/main/scala/rapture/http/http.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.http
import rapture.core._
trait `HttpServer.listen` extends MethodConstraint
trait `HttpServer#stop` extends MethodConstraint
trait HttpBackend {
def startListening(port: Int)(handler: HttpRequest => Response): Unit
def stopListening(): Unit
}
case class ListenException(msg: String) extends RuntimeException
case class Listening(port: Int)
case class PortListenException(port: Int)
object HttpServer {
def listen(port: Int = 80)(handler: HttpRequest => Response)(implicit backend: HttpBackend,
mode: Mode[`HttpServer.listen`]): HttpServer = {
val httpServer = new HttpServer(port) {
protected def handle(r: HttpRequest) = handler(r)
}
httpServer.start()
httpServer
}
}
/** This trait provides a nice interface to the HTTP server */
abstract class HttpServer(val serverPort: Int = 80)(implicit httpBackend: HttpBackend) {
private[HttpServer] def start()(implicit mode: Mode[_]): mode.Wrap[Listening, ListenException] = mode.wrap {
httpBackend.startListening(serverPort)(handle)
Listening(serverPort)
}
def stop()(implicit mode: Mode[`HttpServer#stop`]): mode.Wrap[Unit, ListenException] =
mode.wrap(httpBackend.stopListening())
protected def handle(r: HttpRequest): Response
def notFound(r: HttpRequest): Response =
ErrorResponse(404, Nil, "Not found", "The requested resource could not be found")
def error(r: HttpRequest, e: Throwable): Response =
ErrorResponse(500, Nil, "An unexpected error has occurred", "Unknown error")
}
================================================
FILE: http/shared/src/main/scala/rapture/http/page.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.http
/*import rapture.io._
import rapture.core._
import rapture.net._
import rapture.mime._
import rapture.uri._
import rapture.html._
import htmlSyntax._
object Layout {
import MimeTypes._
trait PageMetadata { page: Page =>
override def metas: List[Element[Metadata]] =
(metaData.toList map { case (k, v) => Meta(htmlSyntax.name = k, htmlSyntax.content = v)() }) :::
page.metas
def metaData: collection.Map[Symbol, String] = collection.Map(
'description = metaDescription,
'keywords = metaKeywords.mkString(","),
'author = metaAuthor
)
def metaDescription: String
def metaKeywords: List[String]
def metaAuthor: String
}
trait JQueryUi extends Page { this: JQuery =>
def jQueryUiLocation = Http / "ajax.googleapis.com" / "ajax" / "libs" / "jqueryui" / "1.8.23" /
"jquery-ui.min.js"
override def scripts: List[Element[Metadata]] =
Script(scriptType = `text/javascript`, src = PathLink(jQueryUiLocation.schemeSpecificPart)) :: super.scripts
}
trait JQuery extends Page {
def jQueryLocation: HttpUrl = Http / "ajax.googleapis.com" / "ajax" / "libs" / "jquery" / "1.7.2" / "jquery.min.js"
override def scripts: List[Element[Metadata]] =
Script(scriptType = `text/javascript`, src = PathLink(jQueryLocation.schemeSpecificPart)) :: super.scripts
}
abstract class Page { page =>
def httpStatus = 200
def doctype = ""
def stylesheets: List[Stylesheet] = Nil
case class Stylesheet(link: PathLink)
def lang: String = "en"
def title: String
def links: List[Element[Metadata]] =
stylesheets map { ss => Link(rel = "stylesheet", href = ss.link)() }
def scripts: List[Element[Metadata]] = Nil
def styles: List[Element[Metadata]] = Nil
def metas: List[Element[Metadata]] = Nil
def head =
Title(page.title) :: styles.reverse ::: links.reverse ::: scripts.reverse ::: metas
def body: List[Element[Flow]]
def document =
Html(htmlSyntax.lang = page.lang)(
Head(page.head: _*),
Body(page.body: _*)
)
def stream: Input[Char] = {
val sb = new StringBuilder
sb.append(doctype)
sb.append(document.toString)
sb.toString.input[Char]
}
}
trait Bootstrap extends Page {
def bootstrapLocation = Http / "twitter.github.com" / "bootstrap" / "1.4.0" / "bootstrap.min.css"
override def links: List[Element[Metadata]] =
Link(rel = "stylesheet", href = bootstrapLocation)() :: super.links
}
import Forms._
trait TinyMce extends Page {
def tinyMceLocation: PathLink
override def scripts: List[Element[Metadata]] =
Script(scriptType = `text/javascript`, src = tinyMceLocation)() :: super.links
}
trait TinyMceForm { this: WebForm =>
implicit val tinyMceEditorRenderer =
new Renderer[String, Field[String], HtmlEditor] {
def render(f: Field[String], w: HtmlEditor) =
Textarea(style = width(100.percent), htmlSyntax.name = f.name, cls = "mceEditorCustom")(raw(f.fieldValue))
}
}
}*/
================================================
FILE: http/shared/src/main/scala/rapture/http/request.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.http
import java.io._
import rapture.io._
import rapture.mime._
import rapture.uri._
import rapture.time._
import rapture.net._
import scala.collection.mutable.ListBuffer
object HttpRequest {
sealed trait QueryParam { def name: String }
case class StringQueryParam(name: String, value: String) extends QueryParam
case class FileQueryParam(name: String, localFile: File)(val clientFilename: String,
val contentType: MimeTypes.MimeType)
extends QueryParam
}
/** Represents an HTTP request. */
abstract class HttpRequest {
/** The length of incoming data, e.g. for POST or PUT. */
def contentLength: Int
/** The part of the URI following the ?, or the empty string. */
def queryString: String
/** The HTTP method, e.g. GET or POST, etc. */
def requestMethod: HttpMethods.Method
/** The virtual path, i.e. the part of the URL following the hostname, not
* including any query parameters. Always starts with a slash. */
def scriptName: String
/** If true, indicates that this is a secure connection. */
def https: Boolean
/** The name the web server thinks this (virtual) server is called, e.g.
* www.example.com. */
def serverName: String
/** The port the web server says the request was made to. */
def serverPort: Int
/** The requested URL, without any query parameters, e.g.
* http://www.example.com:8080/basePath/servicePath/remainder. */
def url: String
/** The application base path used in this request, relative to the domain
* root. Conventionally has a leading slash only, unless it's empty. */
def basePathString: String
/** The service path requested, relative to the base path. Conventionally
* has a leading slash only, unless it's empty. */
def servicePathString: String
/** The remainder of the URL following the service path, without any query
* parameters. Conventionally has a leading slash only, unless it's empty. */
def remainderString: String
/** Array of all query and POST parameters in order. */
def parameters: Map[String, String]
def fileUploads: Map[String, Array[Byte]]
/** Request headers. */
def headers: Map[String, Seq[String]]
/** Body PUT or POSTed */
def body: String
/** The time the request arrived */
val time: Long = System.currentTimeMillis
/** The path of the script */
lazy val path: RootedPath = RootedPath.parse(servicePathString + remainderString).get
protected var streamRead = false
lazy val remainder: List[String] = remainderString.split("\\/").toList
def onComplete(block: => Unit) = completionTasks += (() => block)
val completionTasks: ListBuffer[() => Unit] = new ListBuffer
/** Checks for the existence of a named request param. */
def exists(k: Symbol): Boolean = parameters.contains(k.name)
/** Gets a named request param (which must exist). */
def apply(k: String): String = parameters.get(k) match {
case Some(v) => v
case None => throw new Exception("Missing parameter: " + k)
}
/** Gets a named request param or returns the default. */
def param(k: Symbol, default: String): String = parameters.get(k.name) match {
case Some(v) => v
case None => default
}
/** Gets a named request param which may not exist. */
def param(k: Symbol): Option[String] = parameters.get(k.name)
/** Gets the value of a cookie from the request */
def cookie(c: Symbol): Option[String] = cookies.get(c.name)
private lazy val cookies: scala.collection.immutable.Map[String, String] = {
var cs = scala.collection.immutable.Map[String, String]()
headers.get("cookie") match {
case Some(Seq(v)) =>
val vs = v.split("; ?")
for (v <- vs) {
val kv = v.split("=", 2)
if (kv.length == 2) cs = cs + (kv(0).urlDecode -> kv(1).urlDecode)
}
case _ => ()
}
cs
}
val responseCookies: ListBuffer[(String, String, String, String, Option[Long], Boolean)] =
new ListBuffer[(String, String, String, String, Option[Long], Boolean)]
def setCookie(name: Symbol,
value: String,
domain: String = serverName,
path: RootedPath = ^,
expiry: Option[DateTime] = None,
secure: Boolean = false) =
responseCookies += ((name.name, value, domain, path.toString, expiry.map(_.toLong), secure))
}
================================================
FILE: http/shared/src/main/scala/rapture/http/response.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.http
import rapture.core._
import java.nio._
import rapture.io._
import rapture.mime._
import rapture.codec._
import rapture.fs._
import rapture.time._
/** A collection of standard response-related objects. */
object Response {
val NotModified = ErrorResponse(304, Nil, "Not Modified", "Resource is unchanged.")
val Forbidden = ErrorResponse(403, Nil, "Forbidden", "Access to the requested resource is denied.")
val NotFound = ErrorResponse(404, Nil, "Not Found", "The requested resource could not be located.")
val NoCache = List(
"Expires" -> "Sat, 6 May 1995 12:00:00 GMT",
"Cache-Control" -> "no-store, no-cache, must-revalidate, post-check=0, pre-check=0",
"Pragma" -> "no-cache"
)
implicit def handled[T: HttpHandler](t: T): Response = ?[HttpHandler[T]].response(t)
}
/** Basic definition for a response */
sealed trait Response {
def code: Int
def headers: Seq[(String, String)]
}
case class BufferResponse(code: Int,
headers: Seq[(String, String)],
contentType: MimeTypes.MimeType,
buffers: Array[ByteBuffer])
extends Response
case class StreamResponse(code: Int,
headers: Seq[(String, String)],
contentType: MimeTypes.MimeType,
send: Output[Char] => Unit)(implicit enc: Encoding)
extends Response {
def encoding = enc
}
case class ByteStreamResponse(code: Int,
headers: Seq[(String, String)],
contentType: MimeTypes.MimeType,
send: Output[Byte] => Unit)
extends Response
case class ErrorResponse(code: Int, headers: Seq[(String, String)], message: String, detail: String) extends Response
case class FileResponse(code: Int, headers: Seq[(String, String)], contentType: MimeTypes.MimeType, file: FsUrl)
extends Response
case class RedirectResponse(headers: Seq[(String, String)], location: String) extends Response {
final def code = 302
}
case class Cached[T](toCache: T, lastModified: DateTime)
case class Attachment[T](original: T, filename: String)
================================================
FILE: http/shared/src/main/scala/rapture/http/widgets.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.http
trait Widgets {
trait Widget
case class Dropdown[T](options: List[T])(val id: T => String = (t: Any) => t.toString,
val description: T => String = (t: Any) => t.toString)
extends Widget
case class RadioList[T](options: List[T])(val id: T => String = (t: Any) => t.toString,
val description: T => String = (t: Any) => t.toString)
extends Widget
case class TextArea(width: Int = 8, height: Int = 80, maxLength: Option[Int] = None) extends Widget
case class HtmlEditor() extends Widget
case class StringInput() extends Widget
case class PasswordInput() extends Widget
case class FileUploader() extends Widget
case class Checkbox() extends Widget
case class Hidden() extends Widget
}
================================================
FILE: http-jetty/shared/src/main/scala/rapture/http-jetty/http.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.http
package httpBackends {
object jetty {
implicit val implicitHttpServer = new HttpBackend {
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.ServletContextHandler
import org.eclipse.jetty.servlet.ServletHolder
private var server: Option[Server] = None
class HttpServletWrapper(fn: HttpRequest => Response) extends ServletWrapper {
def handle(r: HttpRequest) = fn(r)
}
def startListening(port: Int)(handler: HttpRequest => Response): Unit = {
import org.eclipse.jetty.util.log.Logger
object NoLogging extends Logger {
override def getName = "no"
override def warn(msg: String, args: AnyRef*) = ()
override def warn(thrown: Throwable) = ()
override def warn(msg: String, thrown: Throwable) = ()
override def info(msg: String, args: AnyRef*) = ()
override def info(thrown: Throwable) = ()
override def info(msg: String, thrown: Throwable) = ()
override def isDebugEnabled(): Boolean = false
override def setDebugEnabled(enabled: Boolean) = ()
override def debug(msg: String, args: AnyRef*) = ()
override def debug(thrown: Throwable) = ()
override def debug(msg: String, thrown: Throwable) = ()
override def getLogger(name: String): Logger = this
override def ignore(thrown: Throwable) = ()
}
org.eclipse.jetty.util.log.Log.setLog(NoLogging)
server = Some(new Server(port))
val sch = new ServletContextHandler(server.get, "/", true, false)
val httpServlet = new HttpServletWrapper(handler)
sch.addServlet(new ServletHolder(httpServlet), "/")
server.foreach(_.start())
}
def stopListening(): Unit = server.foreach(_.stop())
}
}
}
================================================
FILE: http-jetty/shared/src/main/scala/rapture/http-jetty/servlet.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.http
import rapture.core._
import rapture.mime._
import rapture.codec._
import rapture.io._
import rapture.net.{Cookie => _, _}
import scala.collection.mutable.{Map => _, _}
import javax.servlet.http._
import java.nio.ByteBuffer
import java.io._
class JettyHttpRequest(req: HttpServletRequest, resp: HttpServletResponse) extends HttpRequest {
def contentType = {
val ct = Option(req.getContentType) getOrElse "application/x-www-form-urlencoded"
val ct2 = ct.split(";").head
MimeTypes.unapply(ct2).getOrElse(MimeTypes.MimeType(ct2))
}
def contentLength = req.getContentLength
def queryString = req.getQueryString
def requestMethod = HttpMethods.method(req.getMethod)
def scriptName = req.getRequestURI
def https = req.isSecure
def serverName = req.getServerName
def serverPort = req.getServerPort
lazy val url = req.getRequestURL.toString
def basePathString = req.getContextPath
def servicePathString = req.getServletPath
def remainderString = Option(req.getPathInfo).getOrElse("")
def uploadSizeLimit = 50 * 1024 * 1024
private var uploadsValue: Map[String, Array[Byte]] = Map[String, Array[Byte]]()
def fileUploads: Map[String, Array[Byte]] = uploadsValue
private def stripQuotes(s: String) = if (s.startsWith("\"")) s.substring(1, s.length - 1) else s
val parameters = contentType match {
case MimeTypes.`multipart/form-data` =>
val params = new HashMap[String, String]
val ct = headers("Content-Type").head.split("; *")
val boundary = ct.find(_.startsWith("boundary=")).get.substring(9)
val mpr = new MultipartReader(boundary, req.getInputStream, uploadSizeLimit)
while (mpr.ready()) {
mpr.read() foreach { m =>
if (m.filename.isDefined) {
uploadsValue += stripQuotes(m.name.get) -> m.data
params(stripQuotes(m.name.get)) = stripQuotes(m.filename.get)
} else
params(stripQuotes(m.name.get)) = new String(m.data, Option(req.getCharacterEncoding).getOrElse("ASCII"))
}
}
params.toMap
case MimeTypes.`application/x-www-form-urlencoded` =>
val params = new HashMap[String, String]
val enum = req.getParameterNames
while (enum.hasMoreElements) {
val name = enum.nextElement.asInstanceOf[String]
for (value <- req.getParameterValues(name))
params(name) = value
}
params.toMap
case _ =>
Map.empty[String, String]
}
private val input = {
val in = req.getInputStream
import encodings.`UTF-8`._
InputBuilder.inputStreamCharBuilder.input(in)
}
lazy val body =
if (streamRead) throw new Exception("Stream has already been read")
else {
streamRead = true
input.slurp()
}
private def enumToList(e: java.util.Enumeration[_], list: List[String] = Nil): List[String] =
if (e.hasMoreElements) enumToList(e, e.nextElement.asInstanceOf[String] :: list) else list
lazy val headers = enumToList(req.getHeaderNames).map { h =>
h -> enumToList(req.getHeaders(h))
}.toMap
}
abstract class ServletWrapper extends HttpServlet { wrapper =>
def handle(req: HttpRequest): Response
override def service(req: HttpServletRequest, resp: HttpServletResponse) = {
val t0 = System.currentTimeMillis
val vReq = try {
new JettyHttpRequest(req, resp)
} catch {
case e: Exception =>
throw e
}
val vResp = handle(vReq)
vReq.completionTasks.foreach(_ ())
resp.setStatus(vResp.code)
for ((n, v) <- vResp.headers) resp.addHeader(n, v)
for (rc <- vReq.responseCookies) {
val c = new Cookie(rc._1, rc._2)
c.setDomain(rc._3)
c.setMaxAge(rc._5 match {
case Some(t) => (t / 1000).toInt
case None => -1
})
c.setPath(rc._4)
c.setSecure(rc._6)
resp.addCookie(c)
}
val r = try {
vResp match {
case BufferResponse(_, _, ct, buffers) =>
resp.setContentType(ct.name)
val out = resp.getOutputStream
var spare: ByteBuffer = null
for (b <- buffers) {
if (b.hasArray) out.write(b.array, b.arrayOffset, b.limit)
else {
if (spare == null) spare = ByteBuffer.allocate(65536)
while (b.hasRemaining) {
spare.clear()
spare.put(b)
out.write(spare.array, 0, spare.position)
}
}
}
out.flush()
case sr @ StreamResponse(_, _, ct, send) =>
val enc = encodings.`UTF-8`
resp.setContentType(ct.name + "; charset=" + enc.name)
val w = new BufferedWriter(new OutputStreamWriter(resp.getOutputStream(), enc.name))
ensuring(new CharOutput(w))(send)
case sr @ ByteStreamResponse(_, _, ct, send) =>
resp.setContentType(ct.name)
val w = resp.getOutputStream()
ensuring(new ByteOutput(w))(send)
case ErrorResponse(code, _, message, _) =>
resp.sendError(code, message)
case FileResponse(_, _, ct, file) =>
resp.setContentType(ct.name)
resp.setContentLength(file.length.toInt)
val out = new ByteOutput(resp.getOutputStream)
file > out
out.flush()
case RedirectResponse(_, location) =>
resp.sendRedirect(location)
}
} catch {
case e: Exception =>
throw e
} finally {}
r
}
}
================================================
FILE: http-json/shared/src/main/scala/rapture/http-json/handler.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.http
import rapture.json._
import rapture.data._
import rapture.mime._
import rapture.io._
import rapture.net._
import rapture.codec._, encodings.`UTF-8`._
package object jsonInterop {
implicit def jsonHttpHandler(implicit formatter: Formatter[JsonAst] { type Out = String }): HttpHandler[Json] =
new HttpHandler[Json] {
def response(j: Json): Response =
StreamResponse(200, Response.NoCache, MimeTypes.`application/json`, { os =>
Json.format(j).input[Char] > os
os.close()
})
}
implicit def jsonPostType(implicit formatter: Formatter[JsonAst] { type Out = String }): PostType[Json] =
new PostType[Json] {
def contentType = Some(MimeTypes.`application/json`)
def sender(content: Json): Input[Byte] =
Json.format(content).input[Byte]
}
}
================================================
FILE: i18n/shared/src/main/scala/rapture/i18n/i18n.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.i18n
import scala.reflect.runtime.universe._
import language.implicitConversions
import scala.annotation._
import rapture.core._
import language.experimental.macros
import language.implicitConversions
object Locale {
implicit def upcastLocale[From <: Language, ToLang <: From](loc: Locale[From]): Locale[ToLang] =
loc.asInstanceOf[Locale[ToLang]]
}
case class Locale[L <: Language: TypeTag]() {
val typeTag: TypeTag[L] = implicitly[TypeTag[L]]
val name = typeTag.tpe.toString.split("\\.").last.toLowerCase
def from[T, L2 <: L](i18n: I18n[T, L2]) = i18n(typeTag)
def |[L2 <: Language](locale: Locale[L2]): LocaleParser[L with L2] =
new LocaleParser[L with L2](Map(name -> this, locale.name -> locale))
override def toString = name
implicit val defaultLanguage: DefaultLanguage[L] = DefaultLanguage[L](typeTag)
}
case class LocaleException(locale: String) extends Exception(s"Locale '$locale' not recognised.")
class LocaleParser[L <: Language](val locales: Map[String, Locale[_ >: L <: Language]]) {
def |[L2 <: Language](locale: Locale[L2]) = new LocaleParser[L with L2](locales + (locale.name -> locale))
def parse(s: String)(implicit mode: Mode[_]): mode.Wrap[Locale[L], LocaleException] = mode.wrap {
locales.get(s.toLowerCase) match {
case Some(loc) => loc.asInstanceOf[Locale[L]]
case None => mode.exception(LocaleException(s))
}
}
override def toString = locales.keys.mkString("|")
}
object I18n {
implicit def upcast[ToLang <: Language, FromLang <: Language](from: I18n[String, FromLang]): I18n[String, ToLang] = macro Macros
.missingTranslationsMacro[ToLang, FromLang]
implicit def convertToType[T, L <: Language, L2 >: L <: Language: DefaultLanguage](i18n: I18n[T, L]): T =
i18n.map(implicitly[DefaultLanguage[L2]].tag.tpe)
class `I18n.apply`[L <: Language]() {
def apply[T](value: T)(implicit tt: TypeTag[L]) = {
new I18n[T, L](parentsOrSelf(tt.tpe).map(_ -> value).toMap)
}
}
def apply[L <: Language] = new `I18n.apply`[L]()
}
@implicitNotFound("This I18nString already includes the language ${Lang}.")
private[i18n] trait RequireLanguage[Lang]
private[i18n] object RequireLanguage { implicit def requireLanguage: RequireLanguage[Language] = null }
class I18n[T, Languages <: Language](private val map: Map[Type, T]) {
def apply[Lang >: Languages](implicit tt: TypeTag[Lang]): T = map(tt.tpe)
final def &[L >: Languages <: Language, Lang2 <: L](s2: I18n[T, Lang2])(
implicit ev: RequireLanguage[L]): I18n[T, Languages with Lang2] =
new I18n[T, Languages with Lang2](map ++ s2.map)
override def toString = {
val langs = map.keys.map(_.toString.takeRight(2).toLowerCase).mkString("&")
val content: Option[T] = map.get(implicitly[TypeTag[En]].tpe)
lazy val first: Option[T] = map.headOption.flatMap { case (k, v) => map.get(k) }
val value = content.orElse(first).map(_.toString).getOrElse("") match {
case string: String => string
case other => s""""$other""""
}
s"$langs:$value"
}
override def hashCode = map.hashCode ^ 248327829
override def equals(that: Any) = that match {
case that: I18n[_, _] => map == that.map
case _ => false
}
}
object I18nStringParam {
implicit def stringToStringParam[L <: Language](s: String): I18nStringParam[L] =
new I18nStringParam[L](new I18n[String, L](Map()) {
override def apply[Lang >: L](implicit tt: TypeTag[Lang]) = s
})
implicit def toI18nStringParam[L <: Language](s: I18n[String, L]): I18nStringParam[L] =
I18nStringParam(s)
}
case class I18nStringParam[+L <: Language](i18n: I18n[String, L @annotation.unchecked.uncheckedVariance])
extends AnyVal
trait LanguageBundle[Langs <: Language] {
type IString = I18n[String, Langs]
}
================================================
FILE: i18n/shared/src/main/scala/rapture/i18n/languages.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.i18n
import annotation.unchecked._
import scala.reflect.runtime.universe._
object languages {
object aa extends Locale[Aa]()
object ab extends Locale[Ab]()
object ae extends Locale[Ae]()
object af extends Locale[Af]()
object ak extends Locale[Ak]()
object am extends Locale[Am]()
object an extends Locale[An]()
object ar extends Locale[Ar]()
object as extends Locale[As]()
object av extends Locale[Av]()
object ay extends Locale[Ay]()
object az extends Locale[Az]()
object ba extends Locale[Ba]()
object be extends Locale[Be]()
object bg extends Locale[Bg]()
object bh extends Locale[Bh]()
object bi extends Locale[Bi]()
object bm extends Locale[Bm]()
object bn extends Locale[Bn]()
object bo extends Locale[Bo]()
object br extends Locale[Br]()
object bs extends Locale[Bs]()
object ca extends Locale[Ca]()
object ce extends Locale[Ce]()
object ch extends Locale[Ch]()
object co extends Locale[Co]()
object cr extends Locale[Cr]()
object cs extends Locale[Cs]()
object cu extends Locale[Cu]()
object cv extends Locale[Cv]()
object cy extends Locale[Cy]()
object da extends Locale[Da]()
object de extends Locale[De]()
object dv extends Locale[Dv]()
object dz extends Locale[Dz]()
object ee extends Locale[Ee]()
object el extends Locale[El]()
object en extends Locale[En]()
object eo extends Locale[Eo]()
object es extends Locale[Es]()
object et extends Locale[Et]()
object eu extends Locale[Eu]()
object fa extends Locale[Fa]()
object ff extends Locale[Ff]()
object fi extends Locale[Fi]()
object fj extends Locale[Fj]()
object fo extends Locale[Fo]()
object fr extends Locale[Fr]()
object fy extends Locale[Fy]()
object ga extends Locale[Ga]()
object gd extends Locale[Gd]()
object gl extends Locale[Gl]()
object gn extends Locale[Gn]()
object gu extends Locale[Gu]()
object gv extends Locale[Gv]()
object ha extends Locale[Ha]()
object he extends Locale[He]()
object hi extends Locale[Hi]()
object ho extends Locale[Ho]()
object hr extends Locale[Hr]()
object ht extends Locale[Ht]()
object hu extends Locale[Hu]()
object hy extends Locale[Hy]()
object hz extends Locale[Hz]()
object ia extends Locale[Ia]()
object id extends Locale[Id]()
object ie extends Locale[Ie]()
object ig extends Locale[Ig]()
object ii extends Locale[Ii]()
object ik extends Locale[Ik]()
object io extends Locale[Io]()
object is extends Locale[Is]()
object it extends Locale[It]()
object iu extends Locale[Iu]()
object ja extends Locale[Ja]()
object jv extends Locale[Jv]()
object ka extends Locale[Ka]()
object kg extends Locale[Kg]()
object ki extends Locale[Ki]()
object kj extends Locale[Kj]()
object kk extends Locale[Kk]()
object kl extends Locale[Kl]()
object km extends Locale[Km]()
object kn extends Locale[Kn]()
object ko extends Locale[Ko]()
object kr extends Locale[Kr]()
object ks extends Locale[Ks]()
object ku extends Locale[Ku]()
object kv extends Locale[Kv]()
object kw extends Locale[Kw]()
object ky extends Locale[Ky]()
object la extends Locale[La]()
object lb extends Locale[Lb]()
object lg extends Locale[Lg]()
object li extends Locale[Li]()
object ln extends Locale[Ln]()
object lo extends Locale[Lo]()
object lt extends Locale[Lt]()
object lu extends Locale[Lu]()
object lv extends Locale[Lv]()
object mg extends Locale[Mg]()
object mh extends Locale[Mh]()
object mi extends Locale[Mi]()
object mk extends Locale[Mk]()
object ml extends Locale[Ml]()
object mn extends Locale[Mn]()
object mr extends Locale[Mr]()
object ms extends Locale[Ms]()
object mt extends Locale[Mt]()
object my extends Locale[My]()
object na extends Locale[Na]()
object nb extends Locale[Nb]()
object nd extends Locale[Nd]()
object ne extends Locale[Ne]()
object ng extends Locale[Ng]()
object nl extends Locale[Nl]()
object nn extends Locale[Nn]()
object no extends Locale[No]()
object nr extends Locale[Nr]()
object nv extends Locale[Nv]()
object ny extends Locale[Ny]()
object oc extends Locale[Oc]()
object oj extends Locale[Oj]()
object om extends Locale[Om]()
object or extends Locale[Or]()
object os extends Locale[Os]()
object pa extends Locale[Pa]()
object pi extends Locale[Pi]()
object pl extends Locale[Pl]()
object ps extends Locale[Ps]()
object pt extends Locale[Pt]()
object qu extends Locale[Qu]()
object rm extends Locale[Rm]()
object rn extends Locale[Rn]()
object ro extends Locale[Ro]()
object ru extends Locale[Ru]()
object rw extends Locale[Rw]()
object sa extends Locale[Sa]()
object sc extends Locale[Sc]()
object sd extends Locale[Sd]()
object se extends Locale[Se]()
object sg extends Locale[Sg]()
object si extends Locale[Si]()
object sk extends Locale[Sk]()
object sl extends Locale[Sl]()
object sm extends Locale[Sm]()
object sn extends Locale[Sn]()
object so extends Locale[So]()
object sq extends Locale[Sq]()
object sr extends Locale[Sr]()
object ss extends Locale[Ss]()
object st extends Locale[St]()
object su extends Locale[Su]()
object sv extends Locale[Sv]()
object sw extends Locale[Sw]()
object ta extends Locale[Ta]()
object te extends Locale[Te]()
object tg extends Locale[Tg]()
object th extends Locale[Th]()
object ti extends Locale[Ti]()
object tk extends Locale[Tk]()
object tl extends Locale[Tl]()
object tn extends Locale[Tn]()
object to extends Locale[To]()
object tr extends Locale[Tr]()
object ts extends Locale[Ts]()
object tt extends Locale[Tt]()
object tw extends Locale[Tw]()
object ty extends Locale[Ty]()
object ug extends Locale[Ug]()
object uk extends Locale[Uk]()
object ur extends Locale[Ur]()
object uz extends Locale[Uz]()
object ve extends Locale[Ve]()
object vi extends Locale[Vi]()
object vo extends Locale[Vo]()
object wa extends Locale[Wa]()
object wo extends Locale[Wo]()
object xh extends Locale[Xh]()
object yi extends Locale[Yi]()
object yo extends Locale[Yo]()
object za extends Locale[Za]()
object zh extends Locale[Zh]()
object zu extends Locale[Zu]()
}
case class DefaultLanguage[-L <: Language](tag: TypeTag[L @uncheckedVariance])
trait Language
final class Aa extends Language
final class Ab extends Language
final class Ae extends Language
final class Af extends Language
final class Ak extends Language
final class Am extends Language
final class An extends Language
final class Ar extends Language
final class As extends Language
final class Av extends Language
final class Ay extends Language
final class Az extends Language
final class Ba extends Language
final class Be extends Language
final class Bg extends Language
final class Bh extends Language
final class Bi extends Language
final class Bm extends Language
final class Bn extends Language
final class Bo extends Language
final class Br extends Language
final class Bs extends Language
final class Ca extends Language
final class Ce extends Language
final class Ch extends Language
final class Co extends Language
final class Cr extends Language
final class Cs extends Language
final class Cu extends Language
final class Cv extends Language
final class Cy extends Language
final class Da extends Language
final class De extends Language
final class Dv extends Language
final class Dz extends Language
final class Ee extends Language
final class El extends Language
final class En extends Language
final class Eo extends Language
final class Es extends Language
final class Et extends Language
final class Eu extends Language
final class Fa extends Language
final class Ff extends Language
final class Fi extends Language
final class Fj extends Language
final class Fo extends Language
final class Fr extends Language
final class Fy extends Language
final class Ga extends Language
final class Gd extends Language
final class Gl extends Language
final class Gn extends Language
final class Gu extends Language
final class Gv extends Language
final class Ha extends Language
final class He extends Language
final class Hi extends Language
final class Ho extends Language
final class Hr extends Language
final class Ht extends Language
final class Hu extends Language
final class Hy extends Language
final class Hz extends Language
final class Ia extends Language
final class Id extends Language
final class Ie extends Language
final class Ig extends Language
final class Ii extends Language
final class Ik extends Language
final class Io extends Language
final class Is extends Language
final class It extends Language
final class Iu extends Language
final class Ja extends Language
final class Jv extends Language
final class Ka extends Language
final class Kg extends Language
final class Ki extends Language
final class Kj extends Language
final class Kk extends Language
final class Kl extends Language
final class Km extends Language
final class Kn extends Language
final class Ko extends Language
final class Kr extends Language
final class Ks extends Language
final class Ku extends Language
final class Kv extends Language
final class Kw extends Language
final class Ky extends Language
final class La extends Language
final class Lb extends Language
final class Lg extends Language
final class Li extends Language
final class Ln extends Language
final class Lo extends Language
final class Lt extends Language
final class Lu extends Language
final class Lv extends Language
final class Mg extends Language
final class Mh extends Language
final class Mi extends Language
final class Mk extends Language
final class Ml extends Language
final class Mn extends Language
final class Mr extends Language
final class Ms extends Language
final class Mt extends Language
final class My extends Language
final class Na extends Language
final class Nb extends Language
final class Nd extends Language
final class Ne extends Language
final class Ng extends Language
final class Nl extends Language
final class Nn extends Language
final class No extends Language
final class Nr extends Language
final class Nv extends Language
final class Ny extends Language
final class Oc extends Language
final class Oj extends Language
final class Om extends Language
final class Or extends Language
final class Os extends Language
final class Pa extends Language
final class Pi extends Language
final class Pl extends Language
final class Ps extends Language
final class Pt extends Language
final class Qu extends Language
final class Rm extends Language
final class Rn extends Language
final class Ro extends Language
final class Ru extends Language
final class Rw extends Language
final class Sa extends Language
final class Sc extends Language
final class Sd extends Language
final class Se extends Language
final class Sg extends Language
final class Si extends Language
final class Sk extends Language
final class Sl extends Language
final class Sm extends Language
final class Sn extends Language
final class So extends Language
final class Sq extends Language
final class Sr extends Language
final class Ss extends Language
final class St extends Language
final class Su extends Language
final class Sv extends Language
final class Sw extends Language
final class Ta extends Language
final class Te extends Language
final class Tg extends Language
final class Th extends Language
final class Ti extends Language
final class Tk extends Language
final class Tl extends Language
final class Tn extends Language
final class To extends Language
final class Tr extends Language
final class Ts extends Language
final class Tt extends Language
final class Tw extends Language
final class Ty extends Language
final class Ug extends Language
final class Uk extends Language
final class Ur extends Language
final class Uz extends Language
final class Ve extends Language
final class Vi extends Language
final class Vo extends Language
final class Wa extends Language
final class Wo extends Language
final class Xh extends Language
final class Yi extends Language
final class Yo extends Language
final class Za extends Language
final class Zh extends Language
final class Zu extends Language
================================================
FILE: i18n/shared/src/main/scala/rapture/i18n/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.i18n
import rapture.base._
import language.implicitConversions
import scala.reflect.runtime.universe._
object `package` {
def parentsOrSelf(t: Type): List[Type] = t match {
case RefinedType(parents, _) => parents
case other => other :: Nil
}
implicit def i18nStringToString[L <: Language](msg: I18n[String, L])
(implicit locale: Locale[_ >: L]): String = locale.from(msg)
implicit class I18nEnrichedStringContext(sc: StringContext) {
private def context[L <: Language: TypeTag](sc: StringContext, params: List[I18nStringParam[L]]):
I18n[String, L] =
new I18n[String, L](parentsOrSelf(implicitly[TypeTag[L]].tpe).map(_ -> sc.parts.zip(params.map(_.i18n.apply[L]) :+ "").map {
case (a, b) => a+b
}.mkString).toMap)
def aa(params: I18nStringParam[Aa]*): I18n[String, Aa] = context[Aa](sc, params.toList)
def ab(params: I18nStringParam[Ab]*): I18n[String, Ab] = context[Ab](sc, params.toList)
def ae(params: I18nStringParam[Ae]*): I18n[String, Ae] = context[Ae](sc, params.toList)
def af(params: I18nStringParam[Af]*): I18n[String, Af] = context[Af](sc, params.toList)
def ak(params: I18nStringParam[Ak]*): I18n[String, Ak] = context[Ak](sc, params.toList)
def am(params: I18nStringParam[Am]*): I18n[String, Am] = context[Am](sc, params.toList)
def an(params: I18nStringParam[An]*): I18n[String, An] = context[An](sc, params.toList)
def ar(params: I18nStringParam[Ar]*): I18n[String, Ar] = context[Ar](sc, params.toList)
def as(params: I18nStringParam[As]*): I18n[String, As] = context[As](sc, params.toList)
def av(params: I18nStringParam[Av]*): I18n[String, Av] = context[Av](sc, params.toList)
def ay(params: I18nStringParam[Ay]*): I18n[String, Ay] = context[Ay](sc, params.toList)
def az(params: I18nStringParam[Az]*): I18n[String, Az] = context[Az](sc, params.toList)
def ba(params: I18nStringParam[Ba]*): I18n[String, Ba] = context[Ba](sc, params.toList)
def be(params: I18nStringParam[Be]*): I18n[String, Be] = context[Be](sc, params.toList)
def bg(params: I18nStringParam[Bg]*): I18n[String, Bg] = context[Bg](sc, params.toList)
def bh(params: I18nStringParam[Bh]*): I18n[String, Bh] = context[Bh](sc, params.toList)
def bi(params: I18nStringParam[Bi]*): I18n[String, Bi] = context[Bi](sc, params.toList)
def bm(params: I18nStringParam[Bm]*): I18n[String, Bm] = context[Bm](sc, params.toList)
def bn(params: I18nStringParam[Bn]*): I18n[String, Bn] = context[Bn](sc, params.toList)
def bo(params: I18nStringParam[Bo]*): I18n[String, Bo] = context[Bo](sc, params.toList)
def br(params: I18nStringParam[Br]*): I18n[String, Br] = context[Br](sc, params.toList)
def bs(params: I18nStringParam[Bs]*): I18n[String, Bs] = context[Bs](sc, params.toList)
def ca(params: I18nStringParam[Ca]*): I18n[String, Ca] = context[Ca](sc, params.toList)
def ce(params: I18nStringParam[Ce]*): I18n[String, Ce] = context[Ce](sc, params.toList)
def ch(params: I18nStringParam[Ch]*): I18n[String, Ch] = context[Ch](sc, params.toList)
def co(params: I18nStringParam[Co]*): I18n[String, Co] = context[Co](sc, params.toList)
def cr(params: I18nStringParam[Cr]*): I18n[String, Cr] = context[Cr](sc, params.toList)
def cs(params: I18nStringParam[Cs]*): I18n[String, Cs] = context[Cs](sc, params.toList)
def cu(params: I18nStringParam[Cu]*): I18n[String, Cu] = context[Cu](sc, params.toList)
def cv(params: I18nStringParam[Cv]*): I18n[String, Cv] = context[Cv](sc, params.toList)
def cy(params: I18nStringParam[Cy]*): I18n[String, Cy] = context[Cy](sc, params.toList)
def da(params: I18nStringParam[Da]*): I18n[String, Da] = context[Da](sc, params.toList)
def de(params: I18nStringParam[De]*): I18n[String, De] = context[De](sc, params.toList)
def dv(params: I18nStringParam[Dv]*): I18n[String, Dv] = context[Dv](sc, params.toList)
def dz(params: I18nStringParam[Dz]*): I18n[String, Dz] = context[Dz](sc, params.toList)
def ee(params: I18nStringParam[Ee]*): I18n[String, Ee] = context[Ee](sc, params.toList)
def el(params: I18nStringParam[El]*): I18n[String, El] = context[El](sc, params.toList)
def en(params: I18nStringParam[En]*): I18n[String, En] = context[En](sc, params.toList)
def eo(params: I18nStringParam[Eo]*): I18n[String, Eo] = context[Eo](sc, params.toList)
def es(params: I18nStringParam[Es]*): I18n[String, Es] = context[Es](sc, params.toList)
def et(params: I18nStringParam[Et]*): I18n[String, Et] = context[Et](sc, params.toList)
def eu(params: I18nStringParam[Eu]*): I18n[String, Eu] = context[Eu](sc, params.toList)
def fa(params: I18nStringParam[Fa]*): I18n[String, Fa] = context[Fa](sc, params.toList)
def ff(params: I18nStringParam[Ff]*): I18n[String, Ff] = context[Ff](sc, params.toList)
def fi(params: I18nStringParam[Fi]*): I18n[String, Fi] = context[Fi](sc, params.toList)
def fj(params: I18nStringParam[Fj]*): I18n[String, Fj] = context[Fj](sc, params.toList)
def fo(params: I18nStringParam[Fo]*): I18n[String, Fo] = context[Fo](sc, params.toList)
def fr(params: I18nStringParam[Fr]*): I18n[String, Fr] = context[Fr](sc, params.toList)
def fy(params: I18nStringParam[Fy]*): I18n[String, Fy] = context[Fy](sc, params.toList)
def ga(params: I18nStringParam[Ga]*): I18n[String, Ga] = context[Ga](sc, params.toList)
def gd(params: I18nStringParam[Gd]*): I18n[String, Gd] = context[Gd](sc, params.toList)
def gl(params: I18nStringParam[Gl]*): I18n[String, Gl] = context[Gl](sc, params.toList)
def gn(params: I18nStringParam[Gn]*): I18n[String, Gn] = context[Gn](sc, params.toList)
def gu(params: I18nStringParam[Gu]*): I18n[String, Gu] = context[Gu](sc, params.toList)
def gv(params: I18nStringParam[Gv]*): I18n[String, Gv] = context[Gv](sc, params.toList)
def ha(params: I18nStringParam[Ha]*): I18n[String, Ha] = context[Ha](sc, params.toList)
def he(params: I18nStringParam[He]*): I18n[String, He] = context[He](sc, params.toList)
def hi(params: I18nStringParam[Hi]*): I18n[String, Hi] = context[Hi](sc, params.toList)
def ho(params: I18nStringParam[Ho]*): I18n[String, Ho] = context[Ho](sc, params.toList)
def hr(params: I18nStringParam[Hr]*): I18n[String, Hr] = context[Hr](sc, params.toList)
def ht(params: I18nStringParam[Ht]*): I18n[String, Ht] = context[Ht](sc, params.toList)
def hu(params: I18nStringParam[Hu]*): I18n[String, Hu] = context[Hu](sc, params.toList)
def hy(params: I18nStringParam[Hy]*): I18n[String, Hy] = context[Hy](sc, params.toList)
def hz(params: I18nStringParam[Hz]*): I18n[String, Hz] = context[Hz](sc, params.toList)
def ia(params: I18nStringParam[Ia]*): I18n[String, Ia] = context[Ia](sc, params.toList)
def id(params: I18nStringParam[Id]*): I18n[String, Id] = context[Id](sc, params.toList)
def ie(params: I18nStringParam[Ie]*): I18n[String, Ie] = context[Ie](sc, params.toList)
def ig(params: I18nStringParam[Ig]*): I18n[String, Ig] = context[Ig](sc, params.toList)
def ii(params: I18nStringParam[Ii]*): I18n[String, Ii] = context[Ii](sc, params.toList)
def ik(params: I18nStringParam[Ik]*): I18n[String, Ik] = context[Ik](sc, params.toList)
def io(params: I18nStringParam[Io]*): I18n[String, Io] = context[Io](sc, params.toList)
def is(params: I18nStringParam[Is]*): I18n[String, Is] = context[Is](sc, params.toList)
def it(params: I18nStringParam[It]*): I18n[String, It] = context[It](sc, params.toList)
def iu(params: I18nStringParam[Iu]*): I18n[String, Iu] = context[Iu](sc, params.toList)
def ja(params: I18nStringParam[Ja]*): I18n[String, Ja] = context[Ja](sc, params.toList)
def jv(params: I18nStringParam[Jv]*): I18n[String, Jv] = context[Jv](sc, params.toList)
def ka(params: I18nStringParam[Ka]*): I18n[String, Ka] = context[Ka](sc, params.toList)
def kg(params: I18nStringParam[Kg]*): I18n[String, Kg] = context[Kg](sc, params.toList)
def ki(params: I18nStringParam[Ki]*): I18n[String, Ki] = context[Ki](sc, params.toList)
def kj(params: I18nStringParam[Kj]*): I18n[String, Kj] = context[Kj](sc, params.toList)
def kk(params: I18nStringParam[Kk]*): I18n[String, Kk] = context[Kk](sc, params.toList)
def kl(params: I18nStringParam[Kl]*): I18n[String, Kl] = context[Kl](sc, params.toList)
def km(params: I18nStringParam[Km]*): I18n[String, Km] = context[Km](sc, params.toList)
def kn(params: I18nStringParam[Kn]*): I18n[String, Kn] = context[Kn](sc, params.toList)
def ko(params: I18nStringParam[Ko]*): I18n[String, Ko] = context[Ko](sc, params.toList)
def kr(params: I18nStringParam[Kr]*): I18n[String, Kr] = context[Kr](sc, params.toList)
def ks(params: I18nStringParam[Ks]*): I18n[String, Ks] = context[Ks](sc, params.toList)
def ku(params: I18nStringParam[Ku]*): I18n[String, Ku] = context[Ku](sc, params.toList)
def kv(params: I18nStringParam[Kv]*): I18n[String, Kv] = context[Kv](sc, params.toList)
def kw(params: I18nStringParam[Kw]*): I18n[String, Kw] = context[Kw](sc, params.toList)
def ky(params: I18nStringParam[Ky]*): I18n[String, Ky] = context[Ky](sc, params.toList)
def la(params: I18nStringParam[La]*): I18n[String, La] = context[La](sc, params.toList)
def lb(params: I18nStringParam[Lb]*): I18n[String, Lb] = context[Lb](sc, params.toList)
def lg(params: I18nStringParam[Lg]*): I18n[String, Lg] = context[Lg](sc, params.toList)
def li(params: I18nStringParam[Li]*): I18n[String, Li] = context[Li](sc, params.toList)
def ln(params: I18nStringParam[Ln]*): I18n[String, Ln] = context[Ln](sc, params.toList)
def lo(params: I18nStringParam[Lo]*): I18n[String, Lo] = context[Lo](sc, params.toList)
def lt(params: I18nStringParam[Lt]*): I18n[String, Lt] = context[Lt](sc, params.toList)
def lu(params: I18nStringParam[Lu]*): I18n[String, Lu] = context[Lu](sc, params.toList)
def lv(params: I18nStringParam[Lv]*): I18n[String, Lv] = context[Lv](sc, params.toList)
def mg(params: I18nStringParam[Mg]*): I18n[String, Mg] = context[Mg](sc, params.toList)
def mh(params: I18nStringParam[Mh]*): I18n[String, Mh] = context[Mh](sc, params.toList)
def mi(params: I18nStringParam[Mi]*): I18n[String, Mi] = context[Mi](sc, params.toList)
def mk(params: I18nStringParam[Mk]*): I18n[String, Mk] = context[Mk](sc, params.toList)
def ml(params: I18nStringParam[Ml]*): I18n[String, Ml] = context[Ml](sc, params.toList)
def mn(params: I18nStringParam[Mn]*): I18n[String, Mn] = context[Mn](sc, params.toList)
def mr(params: I18nStringParam[Mr]*): I18n[String, Mr] = context[Mr](sc, params.toList)
def ms(params: I18nStringParam[Ms]*): I18n[String, Ms] = context[Ms](sc, params.toList)
def mt(params: I18nStringParam[Mt]*): I18n[String, Mt] = context[Mt](sc, params.toList)
def my(params: I18nStringParam[My]*): I18n[String, My] = context[My](sc, params.toList)
def na(params: I18nStringParam[Na]*): I18n[String, Na] = context[Na](sc, params.toList)
def nb(params: I18nStringParam[Nb]*): I18n[String, Nb] = context[Nb](sc, params.toList)
def nd(params: I18nStringParam[Nd]*): I18n[String, Nd] = context[Nd](sc, params.toList)
def ne(params: I18nStringParam[Ne]*): I18n[String, Ne] = context[Ne](sc, params.toList)
def ng(params: I18nStringParam[Ng]*): I18n[String, Ng] = context[Ng](sc, params.toList)
def nl(params: I18nStringParam[Nl]*): I18n[String, Nl] = context[Nl](sc, params.toList)
def nn(params: I18nStringParam[Nn]*): I18n[String, Nn] = context[Nn](sc, params.toList)
def no(params: I18nStringParam[No]*): I18n[String, No] = context[No](sc, params.toList)
def nr(params: I18nStringParam[Nr]*): I18n[String, Nr] = context[Nr](sc, params.toList)
def nv(params: I18nStringParam[Nv]*): I18n[String, Nv] = context[Nv](sc, params.toList)
def ny(params: I18nStringParam[Ny]*): I18n[String, Ny] = context[Ny](sc, params.toList)
def oc(params: I18nStringParam[Oc]*): I18n[String, Oc] = context[Oc](sc, params.toList)
def oj(params: I18nStringParam[Oj]*): I18n[String, Oj] = context[Oj](sc, params.toList)
def om(params: I18nStringParam[Om]*): I18n[String, Om] = context[Om](sc, params.toList)
def or(params: I18nStringParam[Or]*): I18n[String, Or] = context[Or](sc, params.toList)
def os(params: I18nStringParam[Os]*): I18n[String, Os] = context[Os](sc, params.toList)
def pa(params: I18nStringParam[Pa]*): I18n[String, Pa] = context[Pa](sc, params.toList)
def pi(params: I18nStringParam[Pi]*): I18n[String, Pi] = context[Pi](sc, params.toList)
def pl(params: I18nStringParam[Pl]*): I18n[String, Pl] = context[Pl](sc, params.toList)
def ps(params: I18nStringParam[Ps]*): I18n[String, Ps] = context[Ps](sc, params.toList)
def pt(params: I18nStringParam[Pt]*): I18n[String, Pt] = context[Pt](sc, params.toList)
def qu(params: I18nStringParam[Qu]*): I18n[String, Qu] = context[Qu](sc, params.toList)
def rm(params: I18nStringParam[Rm]*): I18n[String, Rm] = context[Rm](sc, params.toList)
def rn(params: I18nStringParam[Rn]*): I18n[String, Rn] = context[Rn](sc, params.toList)
def ro(params: I18nStringParam[Ro]*): I18n[String, Ro] = context[Ro](sc, params.toList)
def ru(params: I18nStringParam[Ru]*): I18n[String, Ru] = context[Ru](sc, params.toList)
def rw(params: I18nStringParam[Rw]*): I18n[String, Rw] = context[Rw](sc, params.toList)
def sa(params: I18nStringParam[Sa]*): I18n[String, Sa] = context[Sa](sc, params.toList)
def sc(params: I18nStringParam[Sc]*): I18n[String, Sc] = context[Sc](sc, params.toList)
def sd(params: I18nStringParam[Sd]*): I18n[String, Sd] = context[Sd](sc, params.toList)
def se(params: I18nStringParam[Se]*): I18n[String, Se] = context[Se](sc, params.toList)
def sg(params: I18nStringParam[Sg]*): I18n[String, Sg] = context[Sg](sc, params.toList)
def si(params: I18nStringParam[Si]*): I18n[String, Si] = context[Si](sc, params.toList)
def sk(params: I18nStringParam[Sk]*): I18n[String, Sk] = context[Sk](sc, params.toList)
def sl(params: I18nStringParam[Sl]*): I18n[String, Sl] = context[Sl](sc, params.toList)
def sm(params: I18nStringParam[Sm]*): I18n[String, Sm] = context[Sm](sc, params.toList)
def sn(params: I18nStringParam[Sn]*): I18n[String, Sn] = context[Sn](sc, params.toList)
def so(params: I18nStringParam[So]*): I18n[String, So] = context[So](sc, params.toList)
def sq(params: I18nStringParam[Sq]*): I18n[String, Sq] = context[Sq](sc, params.toList)
def sr(params: I18nStringParam[Sr]*): I18n[String, Sr] = context[Sr](sc, params.toList)
def ss(params: I18nStringParam[Ss]*): I18n[String, Ss] = context[Ss](sc, params.toList)
def st(params: I18nStringParam[St]*): I18n[String, St] = context[St](sc, params.toList)
def su(params: I18nStringParam[Su]*): I18n[String, Su] = context[Su](sc, params.toList)
def sv(params: I18nStringParam[Sv]*): I18n[String, Sv] = context[Sv](sc, params.toList)
def sw(params: I18nStringParam[Sw]*): I18n[String, Sw] = context[Sw](sc, params.toList)
def ta(params: I18nStringParam[Ta]*): I18n[String, Ta] = context[Ta](sc, params.toList)
def te(params: I18nStringParam[Te]*): I18n[String, Te] = context[Te](sc, params.toList)
def tg(params: I18nStringParam[Tg]*): I18n[String, Tg] = context[Tg](sc, params.toList)
def th(params: I18nStringParam[Th]*): I18n[String, Th] = context[Th](sc, params.toList)
def ti(params: I18nStringParam[Ti]*): I18n[String, Ti] = context[Ti](sc, params.toList)
def tk(params: I18nStringParam[Tk]*): I18n[String, Tk] = context[Tk](sc, params.toList)
def tl(params: I18nStringParam[Tl]*): I18n[String, Tl] = context[Tl](sc, params.toList)
def tn(params: I18nStringParam[Tn]*): I18n[String, Tn] = context[Tn](sc, params.toList)
def to(params: I18nStringParam[To]*): I18n[String, To] = context[To](sc, params.toList)
def tr(params: I18nStringParam[Tr]*): I18n[String, Tr] = context[Tr](sc, params.toList)
def ts(params: I18nStringParam[Ts]*): I18n[String, Ts] = context[Ts](sc, params.toList)
def tt(params: I18nStringParam[Tt]*): I18n[String, Tt] = context[Tt](sc, params.toList)
def tw(params: I18nStringParam[Tw]*): I18n[String, Tw] = context[Tw](sc, params.toList)
def ty(params: I18nStringParam[Ty]*): I18n[String, Ty] = context[Ty](sc, params.toList)
def ug(params: I18nStringParam[Ug]*): I18n[String, Ug] = context[Ug](sc, params.toList)
def uk(params: I18nStringParam[Uk]*): I18n[String, Uk] = context[Uk](sc, params.toList)
def ur(params: I18nStringParam[Ur]*): I18n[String, Ur] = context[Ur](sc, params.toList)
def uz(params: I18nStringParam[Uz]*): I18n[String, Uz] = context[Uz](sc, params.toList)
def ve(params: I18nStringParam[Ve]*): I18n[String, Ve] = context[Ve](sc, params.toList)
def vi(params: I18nStringParam[Vi]*): I18n[String, Vi] = context[Vi](sc, params.toList)
def vo(params: I18nStringParam[Vo]*): I18n[String, Vo] = context[Vo](sc, params.toList)
def wa(params: I18nStringParam[Wa]*): I18n[String, Wa] = context[Wa](sc, params.toList)
def wo(params: I18nStringParam[Wo]*): I18n[String, Wo] = context[Wo](sc, params.toList)
def xh(params: I18nStringParam[Xh]*): I18n[String, Xh] = context[Xh](sc, params.toList)
def yi(params: I18nStringParam[Yi]*): I18n[String, Yi] = context[Yi](sc, params.toList)
def yo(params: I18nStringParam[Yo]*): I18n[String, Yo] = context[Yo](sc, params.toList)
def za(params: I18nStringParam[Za]*): I18n[String, Za] = context[Za](sc, params.toList)
def zh(params: I18nStringParam[Zh]*): I18n[String, Zh] = context[Zh](sc, params.toList)
def zu(params: I18nStringParam[Zu]*): I18n[String, Zu] = context[Zu](sc, params.toList)
}
}
object Macros {
def missingTranslationsMacro[ToLang <: Language: c.WeakTypeTag, FromLang <: Language: c.WeakTypeTag](c:
BlackboxContext)(from: c.Expr[I18n[String, FromLang]]): c.Expr[I18n[String, ToLang]] = {
import c.universe._
import compatibility._
val fromLangs = (normalize(c)(weakTypeOf[FromLang]) match {
case rt: RefinedType => rt.parents
case typ: Type => List(typ)
}).map(_.toString.split("\\.").last.toLowerCase).to[Set]
val toLangs = (normalize(c)(weakTypeOf[ToLang]) match {
case rt: RefinedType => rt.parents
case typ: Type => List(typ)
}).map(_.toString.split("\\.").last.toLowerCase).to[Set]
val missing = toLangs -- fromLangs
def langs(tree: Tree): Map[String, String] = tree match {
case Apply(Select(Apply(Select(Select(Select(id1, id2), id3), id4), List(Apply(_, List(Literal(Constant(
str: String)))))), lang), _) if id1.toString == "rapture" && id2.toString == "i18n" &&
id3.toString == "package" && id4.toString == "I18nEnrichedStringContext" =>
Map(lang.toString -> str)
case Apply(app: Apply, _) =>
langs(app)
case Apply(TypeApply(Select(q, id6), _), List(app)) if id6.toString == "$bar" =>
langs(q) ++ langs(app)
}
if(!missing.isEmpty)
c.abort(c.enclosingPosition, s"""Some language translations were not provided: ${missing.mkString(", ")}""")
else
reify(from.splice.asInstanceOf[I18n[String, ToLang]])
}
}
================================================
FILE: i18n/shared/src/test/scala/rapture/i18n/tests.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.i18n.test
import rapture.i18n._
import rapture.test._
import rapture.core._
class TestRun extends Programme {
include(I18nTests)
}
object I18nTests extends TestSuite {
import languages._
val `Create basic English string` = test {
val greetingEn: I18n[String, En] = en"Hello world"
greetingEn[En]
} returns "Hello world"
val `Create basic French string` = test {
val greetingFr: I18n[String, Fr] = fr"Bonjour le monde"
greetingFr[Fr]
} returns "Bonjour le monde"
val `Create combined internationalized strings, getting English` = test {
val greeting = en"Hello world" & fr"Bonjour le monde"
greeting[En]
} returns "Hello world"
val `Create combined internationalized strings, getting French` = test {
val greeting = en"Hello world" & fr"Bonjour le monde"
greeting[Fr]
} returns "Bonjour le monde"
val `Check providing surplus language definitions allowed` = test {
val greeting = en"Hello world" & fr"Bonjour le monde"
val en: I18n[String, En] = greeting
val fr: I18n[String, Fr] = greeting
val both: I18n[String, En with Fr] = greeting
}.returns(())
val `Check internationalized substitution` = test {
val greeting = en"Hello world" & fr"Bonjour le monde"
val msg = en"In English, we say '$greeting'"
msg[En]
} returns "In English, we say 'Hello world'"
val `Check internationalized substitution (French)` = test {
val greeting = en"Hello world" & fr"Bonjour le monde"
val msg = fr"En français, on dit '$greeting'"
msg[Fr]
} returns "En français, on dit 'Bonjour le monde'"
val `Substitute ordinary string` = test {
val lang = "Scala"
val msg = en"I speak $lang." & fr"Je parle $lang." & de"Ich spreche $lang."
msg[De]
} returns "Ich spreche Scala."
object MyMessages extends LanguageBundle[En with Fr] {
val greeting: IString = en"Hello world" & fr"Bonjour le monde"
}
val `Test message bundle` = test {
MyMessages.greeting[En]
} returns "Hello world"
val `Test message bundle (French)` = test {
MyMessages.greeting[Fr]
} returns "Bonjour le monde"
val `Use default language` = test {
import languages.fr._
val str: String = MyMessages.greeting
str
} returns "Bonjour le monde"
val `Adding existing language does not compile` = test {
typeMismatch {
import deferTypeErrors._
en"a" & fr"b" & en"c"
}
} returns true
val `Adding existing language does not compile (2)` = test {
typeMismatch {
import deferTypeErrors._
(en"a" & fr"b") & (de"c" & en"d")
}
} returns true
val `Get language string using runtime value` = test {
val msg = en"Hello" & fr"Bonjour"
val langs = en | fr
implicit val loc = langs.parse("FR")
msg: String
} returns "Bonjour"
val `Get language string from subset using runtime value` = test {
typeMismatch {
import deferTypeErrors._
val msg = en"Hello" & fr"Bonjour"
val langs = en | fr | de
implicit val loc = langs.parse("FR")
msg: String
}
} returns true
val `Get language string from superset using runtime value` = test {
val msg = en"Hello" & fr"Bonjour" & de"Hallo"
val langs = en | fr
implicit val loc = langs.parse("FR")
msg: String
} returns "Bonjour"
val `Get both parent languages from a refined-type i18n` = test {
val msg = I18n[En with Fr]("biscuit")
(msg[En], msg[Fr])
} returns (("biscuit", "biscuit"))
val `Refined-type i18n can be combined like others` = test {
val msg = I18n[En with Fr]("biscuit") & de"german biscuit"
(msg[En], msg[Fr], msg[De])
} returns (("biscuit", "biscuit", "german biscuit"))
}
================================================
FILE: io/shared/src/main/scala/rapture/io/contenttype.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.io
import rapture.mime._
object extensionBasedMimeTypes {
def apply[Res: HasResourceName](): HasContentType[Res] = hasContentTypeImplicit[Res]
implicit def hasContentTypeImplicit[Res: HasResourceName]: HasContentType[Res] =
new HasContentType[Res] {
def contentType(res: Res): MimeTypes.MimeType = res.resourceExtension.flatMap { ext =>
MimeTypes.extension(ext).headOption
}.getOrElse(MimeTypes.`application/octet-stream`)
}
}
trait HasContentType[Res] {
def contentType(res: Res): MimeTypes.MimeType
}
object HasContentType {
class Capability[Res](res: Res) {
def contentType(implicit hasContentType: HasContentType[Res]): MimeTypes.MimeType =
hasContentType.contentType(res)
}
}
================================================
FILE: io/shared/src/main/scala/rapture/io/copy.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.io
import rapture.core._
trait Copyable_1 {
implicit def streamableCopyable[SrcType, DestType](implicit reader: Reader[SrcType, Byte],
writer: Writer[DestType, Byte]): Copyable[SrcType, DestType] =
new Copyable[SrcType, DestType] {
def copy(src: SrcType, dest: DestType): Copyable.Summary = {
val bytes = reader.input(src) > writer.output(dest)
Copyable.StreamSummary(bytes)
}
}
}
object Copyable extends Copyable_1 {
trait Summary
case class StreamSummary(bytes: Long) extends Summary {
override def toString = s"streamed $bytes bytes"
}
class Capability[SrcType](from: SrcType) {
def copyTo[DestType](to: DestType)(implicit mode: Mode[`Copyable#copyTo`],
copyable: Copyable[SrcType, DestType]): mode.Wrap[Summary, Exception] =
mode.wrap(?[Copyable[SrcType, DestType]].copy(from, to))
}
}
trait Copyable[-SrcType, -DestType] {
def copy(from: SrcType, to: DestType): Copyable.Summary
}
================================================
FILE: io/shared/src/main/scala/rapture/io/delete.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.io
import rapture.core._
trait Deleter[Res] {
def delete(res: Res): Unit
}
object Deletable {
case class Summary(deleted: Int) {
override def toString = s"$deleted file(s) deleted"
}
class Capability[Res](res: Res) {
def delete()(implicit mode: Mode[`Deletable#delete`], deleter: Deleter[Res]): mode.Wrap[Summary, Exception] =
mode wrap {
deleter.delete(res)
Summary(1)
}
}
}
================================================
FILE: io/shared/src/main/scala/rapture/io/guid.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.io
import rapture.core._
object Guid {
private val GuidPattern = """^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$""".r
def generate() = Guid(java.util.UUID.randomUUID().toString)
}
case class Guid(id: String) {
override def toString = id
def apply() = id
}
================================================
FILE: io/shared/src/main/scala/rapture/io/io.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.io
import rapture.core._
import java.io._
import language.reflectiveCalls
object javaResources {
type StructuralReadable = { def getInputStream(): InputStream }
type StructuralWritable = { def getOutputStream(): OutputStream }
implicit val structuralReader = new JavaInputStreamReader[StructuralReadable](_.getInputStream())
implicit val structuralWriter = new JavaOutputStreamWriter[StructuralWritable](_.getOutputStream())
implicit val javaFileReader = new JavaInputStreamReader[java.io.File](new java.io.FileInputStream(_))
implicit val javaNioPathReader = new JavaInputStreamReader[java.nio.file.Path](java.nio.file.Files.newInputStream(_))
implicit val javaFileWriter = new JavaOutputStreamWriter[java.io.File](new java.io.FileOutputStream(_))
implicit val javaFileAppender = new JavaOutputAppender[java.io.File](f => alloc[java.io.FileOutputStream](f, true))
}
================================================
FILE: io/shared/src/main/scala/rapture/io/move.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.io
import rapture.core._
object Movable {
case class Summary(streamed: Option[Long]) {
override def toString = streamed match {
case None => "moved file"
case Some(b) => s"streamed, deleted $b bytes"
}
}
class Capability[FromType](from: FromType) {
def moveTo[ToType](to: ToType)(implicit mode: Mode[`Movable#moveTo`],
movable: Movable[FromType, ToType]): mode.Wrap[Summary, Exception] =
mode.wrap(?[Movable[FromType, ToType]].move(from, to))
}
}
trait Movable[FromType, ToType] {
def move(from: FromType, to: ToType): Movable.Summary
}
================================================
FILE: io/shared/src/main/scala/rapture/io/multipart.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.io
import rapture.core._
import rapture.mime._
import scala.collection.mutable.ListBuffer
case class Multipart(data: Array[Byte], headers: Map[String, String]) {
def contentType: Option[MimeTypes.MimeType] =
headers.get("Content-Type") map {
case MimeTypes(t) => t
case t => MimeTypes.MimeType(t)
}
lazy val contentDisposition: Option[(String, Map[String, String])] =
headers.get("Content-Disposition") flatMap { v =>
v.split("; *").to[List] match {
case h :: t =>
val m = t
.map({ a =>
val b = a.split("=")
b(0) -> b(1)
})
.toMap
Some(h -> m)
case _ => None
}
}
def filename: Option[String] = contentDisposition flatMap { case (_, m) => m.get("filename") }
def name: Option[String] = contentDisposition flatMap { case (_, m) => m.get("name") }
def disposition: Option[String] = contentDisposition.map(_._1)
}
class MultipartReader(boundary: String, in: java.io.InputStream, val sizeLimit: Int = 160) extends Input[Multipart] {
private val bnd = ("--" + boundary).getBytes("ASCII")
private var finished = false
private var cued = next()
def close(): Unit = in.close()
def ready(): Boolean = cued.isDefined
def read(): Option[Multipart] = {
val r = cued
cued = next()
r
}
private def next(): Option[Multipart] = {
var buf: Array[Byte] = null
var count = -1
val bufs = alloc[ListBuffer[Array[Byte]]]()
var headers: Map[String, String] = Map()
var dataStart = 0
var boundmatch: Int = 0
while (!finished) {
var cur = in.read()
if (buf != null && dataStart == 0 && (buf(count % 65536) == 10 && cur == 13 ||
buf(count % 65536) == 13 && cur == 10)) {
// do nothing
} else if (buf != null && dataStart == 0 && (cur == 10 || cur == 13 &&
buf(count % 65536) == cur)) {
dataStart = count + 1
val next = in.read().toByte
if (next != 10 && next != 13) {
count += 1
buf(count % 65536) = next
}
headers = alloc[String](buf.slice(1, dataStart), "ISO-8859-1")
.split("\r")
.map({ h =>
val i = h.indexOf(':')
h.substring(0, i) -> h.substring(i + 2, h.length)
})
.toMap
} else {
count += 1
if (cur == -1) {
finished = true
return None
}
if (count % 65536 == 0) {
if (count > sizeLimit) throw alloc[RuntimeException]("Upload size limit exceeded.")
buf = alloc(65536)
bufs += buf
}
buf(count % 65536) = cur.toByte
boundmatch = if (buf(count % 65536) == bnd(boundmatch)) boundmatch + 1 else 0
if (boundmatch == bnd.length) {
val dataEnd = count - boundmatch - 1
val size = dataEnd - dataStart
if (size >= 0) {
val res: Array[Byte] = alloc(size)
var done = 0
var i = 0
var offset = dataStart
while (done < size) {
val chunk = List(65536 - offset, size - done).min
System.arraycopy(bufs(i), offset, res, done, chunk)
done += chunk
offset = 0
i += 1
}
return Some(Multipart(res, headers))
} else {
count = -1
bufs.clear()
buf = null
boundmatch = 0
dataStart = 0
}
}
}
}
None
}
}
================================================
FILE: io/shared/src/main/scala/rapture/io/name.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.io
import rapture.uri._
trait HasResourceName[Res] {
def resourceName(res: Res): String
def resourceExtension(res: Res): Option[String] = {
val parts = resourceName(res).split("\\.")
if(parts.length > 1) Some(parts.last) else None
}
}
object HasResourceName {
implicit val classpathHasResourceName: HasResourceName[ClasspathUrl] = new HasResourceName[ClasspathUrl] {
def resourceName(classpathUrl: ClasspathUrl): String = classpathUrl.elements.last
}
class Capability[Res](res: Res) {
def resourceName(implicit hasResourceName: HasResourceName[Res]): String =
hasResourceName.resourceName(res)
def resourceExtension(implicit hasResourceName: HasResourceName[Res]): Option[String] =
hasResourceName.resourceExtension(res)
}
}
================================================
FILE: io/shared/src/main/scala/rapture/io/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.io
import rapture.core._
import rapture.uri._
import java.io._
import scala.language.implicitConversions
trait `Appendable#appendOutput` extends MethodConstraint
trait `Readable#input` extends MethodConstraint
trait `Readable#redirectTo` extends MethodConstraint
trait `Readable#appendTo` extends MethodConstraint
trait `Writable#output` extends MethodConstraint
trait `Sizable#size` extends MethodConstraint
trait `Slurpable#slurp` extends MethodConstraint
trait `Copyable#copyTo` extends MethodConstraint
trait `Movable#moveTo` extends MethodConstraint
trait `Deletable#delete` extends MethodConstraint
object `package` {
/** Views an `Input[Byte]` as a `java.io.InputStream` */
implicit def inputStreamUnwrapper(is: Input[Byte]): InputStream =
new InputStream { def read() = is.read().map(_.toInt).getOrElse(-1) }
implicit def classpathStreamByteReader(implicit cl: ClassLoader): JavaInputStreamReader[ClasspathUrl] =
ClasspathStream.classpathStreamByteReader
def ensuring[Res, Strm: Closable](create: Strm)(body: Strm => Res): Res = Utils.ensuring[Res, Strm](create)(body)
implicit def stringMethods(s: String): StringMethods = alloc(s)
implicit def copyable[Res](res: Res): Copyable.Capability[Res] = alloc(res)
implicit def appendable[Res](res: Res): Appendable.Capability[Res] = alloc(res)
implicit def readable[Res](res: Res): Readable.Capability[Res] = alloc(res)
implicit def deletable[Res](res: Res): Deletable.Capability[Res] = alloc(res)
implicit def slurpable[Res](res: Res): Slurpable.Capability[Res] = alloc(res)
implicit def writable[Res](res: Res): Writable.Capability[Res] = alloc(res)
implicit def movable[Res](res: Res): Movable.Capability[Res] = alloc(res)
implicit def sizable[Res](res: Res): Sizable.Capability[Res] = alloc(res)
implicit def hasResourceName[Res](res: Res): HasResourceName.Capability[Res] = alloc(res)
implicit def hasContentType[Res](res: Res): HasContentType.Capability[Res] = alloc(res)
}
================================================
FILE: io/shared/src/main/scala/rapture/io/size.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.io
import rapture.core._
import scala.reflect._
object Sizable {
class Capability[Res](res: Res) {
/** Returns the size in bytes of this resource */
def size[Data](implicit mode: Mode[`Sizable#size`], sizable: Sizable[Res, Data]): mode.Wrap[Long, Exception] =
mode wrap sizable.size(res)
}
implicit def charSizable[Res, Data: ClassTag](implicit reader: Reader[Res, Data]): Sizable[Res, Data] =
new Sizable[Res, Data] {
private def accumulator() = new Accumulator[Data, Long] with Output[Data] {
private var count = 0
def buffer: Long = count
def write(b: Data) = count += 1
def flush(): Unit = ()
def close(): Unit = ()
}
def size(res: Res): Long = {
val acc = accumulator()
res.handleInput[Data, Int](_ pumpTo acc)
acc.buffer
}
}
}
trait Sizable[Res, Data] {
type ExceptionType <: Exception
/** Returns the number of units of the specified resource */
def size(res: Res): Long
}
================================================
FILE: io/shared/src/main/scala/rapture/io/slurp.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.io
import rapture.core._
import rapture.codec._
import scala.reflect._
import java.io._
trait AccumulatorBuilder_1 {
implicit val byteAccumulator: AccumulatorBuilder[Byte] { type Out = Bytes } = ByteAccumulator
implicit val stringAccumulator: AccumulatorBuilder[String] { type Out = String } = StringAccumulator
}
object AccumulatorBuilder extends AccumulatorBuilder_1 {
implicit val charAccumulator: AccumulatorBuilder[Char] { type Out = String } = CharAccumulator
}
/** Interface for an accumulator which is a special kind of output which collects and stores all
* input in a buffer which can be retrieved afterwards. No guarantees are made about input
* supplied after the buffer has been retrieved.
*
* @tparam Data The type of data to be accumulated
* @tparam Acc The type into which the data will be accumulated */
trait Accumulator[Data, +Acc] extends Output[Data] { def buffer: Acc }
/** Defines a trait for creating new `Accumulator`s */
trait AccumulatorBuilder[T] {
type Out
def make(): Accumulator[T, Out]
}
/** Collects `Byte`s into an `Array[Byte]` */
class ByteArrayOutput extends {
private val baos: ByteArrayOutputStream = alloc()
} with ByteOutput(baos) with Accumulator[Byte, Bytes] {
def buffer: Bytes = Bytes(baos.toByteArray)
}
/** Collects `String`s into another `String` */
class LinesOutput extends {
private val sw: StringWriter = alloc()
} with LineOutput(sw) with Accumulator[String, String] {
def buffer: String = sw.toString
}
/** Type class object for creating an accumulator Bytes into an `Array` of `Byte`s */
object ByteAccumulator extends AccumulatorBuilder[Byte] {
type Out = Bytes
def make(): ByteArrayOutput = alloc()
}
/** Type class object for creating an accumulator of `String`s */
object StringAccumulator extends AccumulatorBuilder[String] {
type Out = String
def make(): LinesOutput = alloc()
}
/** Type class object for creating an accumulator of `Char`s into a `String` */
object CharAccumulator extends AccumulatorBuilder[Char] {
type Out = String
def make(): StringOutput = alloc()
}
/** Collects `Char`s into a `String` */
class StringOutput extends {
private val sw: StringWriter = alloc()
} with CharOutput(sw) with Accumulator[Char, String] {
def buffer: String = sw.toString
}
object Slurpable {
class Capability[Res](res: Res) {
def slurp[Data]()(implicit accumulatorBuilder: AccumulatorBuilder[Data],
mode: Mode[`Slurpable#slurp`],
sr: Reader[Res, Data],
mf: ClassTag[Data]): mode.Wrap[accumulatorBuilder.Out, Exception] =
mode.wrap {
val c = accumulatorBuilder.make()
res.handleInput[Data, Int](_ pumpTo c)
c.close()
c.buffer
}
}
}
================================================
FILE: io/shared/src/main/scala/rapture/io/streams.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.io
import rapture.core._
import rapture.codec._
import rapture.mime._
import java.io._
import scala.reflect._
import language.higherKinds
trait Closable[-R] { def close(resource: R): Unit }
object Utils {
/** Safely closes a stream after processing */
def ensuring[Res, Strm: Closable](create: Strm)(blk: Strm => Res) = {
val stream = create
val result = try { blk(stream) } catch {
case e: Throwable =>
try { implicitly[Closable[Strm]].close(stream) } catch { case e2: Exception => () }
throw e
}
implicitly[Closable[Strm]].close(stream)
result
}
}
case class StringIsInput(string: String) extends CharInput(alloc[StringReader](string))
case class ByteArrayInput(array: Array[Byte]) extends ByteInput(alloc[ByteArrayInputStream](array))
object InputBuilder {
implicit def stringInputBuilder(implicit encoding: Encoding): InputBuilder[InputStream, String] =
new InputBuilder[InputStream, String] {
def input(s: InputStream): Input[String] =
alloc[LineInput](alloc[InputStreamReader](s, encoding.name))
}
implicit def inputStreamCharBuilder(implicit encoding: Encoding): InputBuilder[InputStream, Char] =
new InputBuilder[InputStream, Char] {
def input(s: InputStream): Input[Char] =
alloc[CharInput](alloc[InputStreamReader](s, encoding.name))
}
implicit val buildInputStream: InputBuilder[InputStream, Byte] = InputStreamBuilder
implicit val buildReader: InputBuilder[java.io.Reader, Char] = ReaderBuilder
implicit val buildLineReader: InputBuilder[java.io.Reader, String] = LineReaderBuilder
}
object Input {
implicit def inputClosable[T]: Closable[Input[T]] = new Closable[Input[T]] {
def close(in: Input[T]): Unit = in.close()
}
}
trait InputBuilder[InputType, Data] {
def input(s: InputType): Input[Data]
}
object OutputBuilder {
implicit val buildOutputStream: OutputBuilder[OutputStream, Byte] = OutputStreamBuilder
implicit val buildWriter: OutputBuilder[java.io.Writer, Char] = WriterBuilder
implicit def stringOutputBuilder(implicit encoding: Encoding): OutputBuilder[OutputStream, String] =
new OutputBuilder[OutputStream, String] {
def output(s: OutputStream): Output[String] =
new LineOutput(new OutputStreamWriter(s, encoding.name))
}
implicit def outputStreamCharBuilder(implicit encoding: Encoding): OutputBuilder[OutputStream, Char] =
new OutputBuilder[OutputStream, Char] {
def output(s: OutputStream): Output[Char] =
alloc[CharOutput](alloc[OutputStreamWriter](s, encoding.name))
}
}
trait OutputBuilder[OutputType, Data] {
def output(s: OutputType): Output[Data]
}
object AppenderBuilder {
implicit def buildAppender: AppenderBuilder[java.io.Writer, Char] =
new AppenderBuilder[java.io.Writer, Char] {
def appendOutput(s: java.io.Writer) = alloc[CharOutput](s)
}
}
trait AppenderBuilder[OutputType, Data] { def appendOutput(s: OutputType): Output[Data] }
object Appendable {
class Capability[Res](res: Res) {
def appendOutput[Data](implicit sa: Appender[Res, Data], mode: Mode[`Appendable#appendOutput`]) =
sa.appendOutput(res)
def handleAppend[Data, Res2](body: Output[Data] => Res2)(implicit sw: Appender[Res, Data]): Res2 = {
ensuring(appendOutput[Data])(body)
}
}
}
object Readable {
class Capability[Res](res: Res) {
def input[Data](implicit sr: Reader[Res, Data], mode: Mode[`Readable#input`]): mode.Wrap[Input[Data], Exception] =
mode.wrap(sr.input(res))
def redirectTo[Data, DestRes](dest: DestRes)(implicit sr: Reader[Res, Data],
sw: Writer[DestRes, Data],
mode: Mode[`Readable#redirectTo`],
mf: ClassTag[Data]): mode.Wrap[Int, Exception] =
mode.wrap(handleInput[Data, Int] { in =>
writable(dest).handleOutput[Data, Int](in.pumpTo)
})
def >[Data, DestRes](dest: DestRes)(implicit sr: Reader[Res, Data],
sw: Writer[DestRes, Data],
mode: Mode[`Readable#redirectTo`],
mf: ClassTag[Data]): mode.Wrap[Int, Exception] =
redirectTo[Data, DestRes](dest)(sr, sw, mode, mf)
def pipeTo[Data, DestRes](
dest: DestRes)(implicit sr: Reader[Res, Data], sw: Writer[DestRes, Data], mf: ClassTag[Data]): DestRes = {
redirectTo(dest)
dest
}
def |[Data, DestRes](
dest: DestRes)(implicit sr: Reader[Res, Data], sw: Writer[DestRes, Data], mf: ClassTag[Data]): DestRes =
pipeTo(dest)(sr, sw, mf)
def >>[Data, DestRes](dest: DestRes)(implicit sr: Reader[Res, Data],
sw: Appender[DestRes, Data],
mode: Mode[`Readable#appendTo`],
mf: ClassTag[Data]): mode.Wrap[Int, Exception] =
mode.wrap(handleInput[Data, Int] { in =>
dest.handleAppend[Data, Int](in.pumpTo)
})
def >[Data](out: Output[Data])(implicit sr: Reader[Res, Data],
mode: Mode[`Readable#redirectTo`],
mf: ClassTag[Data]): mode.Wrap[Int, Exception] =
mode.wrap(handleInput[Data, Int](_ pumpTo out))
def handleInput[Data, Res2](body: Input[Data] => Res2)(implicit sr: Reader[Res, Data]): Res2 =
ensuring(input[Data])(body)
}
}
object Writable {
class Capability[Res](res: Res) {
def output[Data](implicit sw: Writer[Res, Data],
mode: Mode[`Writable#output`]): mode.Wrap[Output[Data], Exception] = mode.wrap(sw.output(res))
def handleOutput[Data, Res2](body: Output[Data] => Res2)(implicit sw: Writer[Res, Data]): Res2 =
ensuring(output[Data])(body)
}
}
object Writer {
implicit def byteToLineWriters[T](implicit jisw: JavaOutputStreamWriter[T], encoding: Encoding): Writer[T, String] =
new Writer[T, String] {
def output(t: T): Output[String] = alloc[LineOutput](alloc[OutputStreamWriter](jisw.getOutputStream(t)))
}
implicit def byteToCharWriters[T](implicit jisw: JavaOutputStreamWriter[T], encoding: Encoding): Writer[T, Char] =
new Writer[T, Char] {
def output(t: T): Output[Char] = alloc[CharOutput](alloc[OutputStreamWriter](jisw.getOutputStream(t)))
}
implicit val stdoutWriter: JavaOutputStreamWriter[Stdout.type] =
new JavaOutputStreamWriter[Stdout.type](x => System.out, _ => ())
implicit val stderrWriter: Writer[Stderr.type, Byte] = new Writer[Stderr.type, Byte] {
def output(stderr: Stderr.type): Output[Byte] =
?[OutputBuilder[OutputStream, Byte]].output(System.out)
}
}
@implicitNotFound(
msg = "Cannot write $"+"{Data} data to $"+"{Resource} resources. Note that if you " +
"are working with Char data, you will require an implicit character encoding, e.g. " +
"import encodings.system._ or import encodings.`UTF-8`._.")
trait Writer[-Resource, @specialized(Byte, Char) Data] {
def output(res: Resource): Output[Data]
}
object Appender extends Appender_1 {
implicit def byteToCharAppenders[T](implicit jisw: JavaOutputAppender[T], encoding: Encoding): Appender[T, Char] =
new Appender[T, Char] {
def appendOutput(t: T): Output[Char] =
alloc[CharOutput](alloc[OutputStreamWriter](jisw.getOutputStream(t)))
}
implicit def byteToLineAppender[Res](implicit appender: Appender[Res, Byte], enc: Encoding) = {
new Appender[Res, String] {
def appendOutput(res: Res): Output[String] = new Output[String] {
private lazy val output = appender.appendOutput(res)
def close() = output.close()
def flush() = output.flush()
def write(s: String) = {
output.writeBlock((s + "\n").getBytes(enc.name))
output.flush()
}
}
}
}
implicit val stdoutAppender: JavaOutputAppender[Stdout.type] =
new JavaOutputAppender[Stdout.type](x => System.out, _ => ())
implicit val stderrAppender: JavaOutputAppender[Stderr.type] =
new JavaOutputAppender[Stderr.type](x => System.err, _ => ())
implicit val stdoutCharAppender: Appender[Stdout.type, Char] =
byteToCharAppenders(stdoutAppender, encodings.system())
implicit val stderrCharAppender: Appender[Stderr.type, Char] =
byteToCharAppenders(stderrAppender, encodings.system())
}
trait Appender_1 {
implicit def charToLineAppender[Res](implicit appender: Appender[Res, Char]) = {
new Appender[Res, String] {
def appendOutput(res: Res): Output[String] = new Output[String] {
private lazy val output = appender.appendOutput(res)
def close() = output.close()
def flush() = output.flush()
def write(s: String) = {
output.writeBlock((s + "\n").to[Array])
output.flush()
}
}
}
}
}
trait Appender[-Resource, Data] {
def appendOutput(res: Resource): Output[Data]
}
trait TypedInput { thisInput: Input[_] =>
def mimeType: MimeTypes.MimeType
}
trait Input[@specialized(Byte, Char) Data] extends Seq[Data] { thisInput =>
private var beingHandled = false
override def toString() = ""
// FIXME: This just shouldn't be a Seq
def length: Int = throw alloc[Exception]("Cannot calculate length of a stream")
def apply(n: Int) = {
for (i <- 0 until n) read()
read().get
}
def typed(mime: MimeTypes.MimeType) = new Input[Data] with TypedInput {
def mimeType = mime
def ready() = thisInput.ready()
def close() = thisInput.close()
def read() = thisInput.read()
}
def iterator: Iterator[Data] = new Iterator[Data] {
private var nextVal: Option[Data] = read()
def hasNext = nextVal.isDefined
def next() = {
val x = nextVal.get
nextVal = read()
x
}
}
def ready(): Boolean
def read(): Option[Data]
def readBlock(array: Array[Data], offset: Int = 0, length: Int = -1): Int = {
val end = if (length < 0) array.length - offset else offset + length
read() match {
case None => -1
case Some(c) =>
array(offset) = c
var i = offset + 1
var continue = true
while (i < end && continue) {
read() match {
case None =>
continue = false
case Some(c) =>
array(i) = c
i += 1
}
}
i - offset
}
}
def close(): Unit
def pumpTo(out: Output[Data])(implicit mf: ClassTag[Data]): Int = {
val buf: Array[Data] = alloc(65536)
var len = readBlock(buf)
var count = 0
while (len >= 0) {
out.writeBlock(buf, length = len)
count += len
len = readBlock(buf)
}
count
}
def map[T](fn: Data => T): Input[T] = new Input[T] {
def read(): Option[T] = thisInput.read().map(fn)
def ready(): Boolean = thisInput.ready()
def close(): Unit = thisInput.close()
}
def flatMap[T](fn: Data => Seq[T]): Input[T] = new Input[T] {
private var buf: Seq[T] = Nil
private var cur = 0
private var avail = 0
def read(): Option[T] =
if (cur == avail) {
cur = 0
avail = 0
thisInput.read().map(fn) match {
case None => None
case Some(xs) =>
if (xs.isEmpty) read()
else if (xs.length == 1) xs.headOption
else {
avail = xs.length
cur += 1
buf = xs
xs.headOption
}
}
} else {
cur += 1
Some(buf(cur - 1))
}
def ready(): Boolean = cur < avail || thisInput.ready()
def close(): Unit = {
cur = 0
avail = 0
thisInput.close()
}
}
override def foreach[U](fn: Data => U): Unit = {
var next: Option[Data] = read()
while (next.isDefined) {
fn(next.get)
next = read()
}
}
}
object Output {
implicit def outputClosable[T]: Closable[Output[T]] = new Closable[Output[T]] {
def close(out: Output[T]): Unit = out.close()
}
}
trait Output[@specialized(Byte, Char) Data] {
private var beingHandled = false
def write(data: Data): Unit
def writeBlock(array: Array[Data], offset: Int = 0, length: Int = -1): Int = {
val end = if (length < 0) array.length - offset else offset + length
array.slice(offset, end).foreach(write)
end - offset
}
def flush(): Unit
def close(): Unit
}
trait Reader_1 {
implicit def stringByteReader(implicit encoding: Encoding): Reader[String, Byte] =
new Reader[String, Byte] {
def input(s: String): Input[Byte] = ByteArrayInput(s.getBytes(encoding.name))
}
implicit val stringLineReader: Reader[String, String] = StringLineReader
}
object Reader extends Reader_1 {
type ForBytes[-Resource] = Reader[Resource, Byte]
type ForChars[-Resource] = Reader[Resource, Char]
implicit def inputStreamReader[T, I[T] <: Input[T]]: Reader[I[T], T] =
new Reader[I[T], T] {
def input(in: I[T]): Input[T] = in
}
implicit def byteInputToCharReader(implicit encoding: Encoding): Reader[Input[Char], Byte] =
new Reader[Input[Char], Byte] {
def input(in: Input[Char]): Input[Byte] = new Input[Byte] {
private var cued: Array[Byte] = Array()
private var index = 0
def read(): Option[Byte] = {
if (index >= cued.length) {
// FIXME: Find a less stupid way of doing this
val next = in.read()
if (next.isEmpty) return None
cued = next.get.toString.getBytes(encoding.name)
index = 0
}
val next = cued(index)
index += 1
Some(next)
}
def ready(): Boolean = in.ready() || index < cued.length
def close(): Unit = in.close()
}
}
implicit def charInputToByteReader(implicit encoding: Encoding): Reader[Input[Byte], Char] =
new Reader[Input[Byte], Char] {
def input(in: Input[Byte]): Input[Char] = {
val javaInputStream = new InputStream {
def read(): Int = {
val r = in.read()
if (r.isDefined) r.get.toInt else -1
}
}
alloc[CharInput](alloc[InputStreamReader](javaInputStream, encoding.name))
}
}
implicit def byteToLineReaders[T](implicit jisr: JavaInputStreamReader[T], encoding: Encoding): Reader[T, String] =
new Reader[T, String] {
def input(t: T): Input[String] =
alloc[LineInput](alloc[InputStreamReader](jisr.getInputStream(t)))
}
implicit def byteToCharReaders[T](implicit jisr: JavaInputStreamReader[T], encoding: Encoding): Reader[T, Char] =
new Reader[T, Char] {
def input(t: T): Input[Char] =
alloc[CharInput](alloc[InputStreamReader](jisr.getInputStream(t)))
}
implicit def resourceBytes[Res](res: Res)(implicit sr: Reader[Res, Byte]): Bytes =
slurpable(res).slurp[Byte]
implicit val stringCharReader: Reader[String, Char] = StringCharReader
implicit val byteArrayReader: Reader[Array[Byte], Byte] = ByteArrayReader
implicit val bytesReader: Reader[Bytes, Byte] = BytesReader
implicit val stdinReader: Reader[Stdin.type, Byte] = new Reader[Stdin.type, Byte] {
def input(stdin: Stdin.type): Input[Byte] =
?[InputBuilder[InputStream, Byte]].input(System.in)
}
}
@implicitNotFound(
msg = "Cannot find implicit Reader for $"+"{Resource} resources. " +
"$"+"{Resource} resources can only be read if a Reader implicit exists within scope. " +
"Note that if you are working with Char data, you will require an implicit character " +
"encoding, e.g. import encodings.system._ or import encodings.`UTF-8`._.")
trait Reader[-Resource, @specialized(Byte, Char) Data] {
def input(res: Resource): Input[Data]
def pump[DestResource](res: Resource, dest: DestResource)(implicit sw: Writer[DestResource, Data],
mf: ClassTag[Data]): Int =
input(res) pumpTo sw.output(dest)
}
object StringCharReader extends Reader[String, Char] {
def input(s: String): Input[Char] = StringIsInput(s)
}
object StringLineReader extends Reader[String, String] {
def input(s: String): Input[String] = new Input[String] {
private val lines = s.split("\n")
private var cur = -1
def ready() = cur < lines.length
def close() = ()
def read() = {
cur += 1
if (ready()) Some(lines(cur)) else None
}
}
}
object BytesReader extends Reader[Bytes, Byte] {
def input(s: Bytes): Input[Byte] = ByteArrayInput(s.bytes)
}
object ByteArrayReader extends Reader[Array[Byte], Byte] {
def input(s: Array[Byte]): Input[Byte] = ByteArrayInput(s)
}
object Stdin
object Stdout
object Stderr
================================================
FILE: io/shared/src/main/scala/rapture/io/strings.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.io
import rapture.core._
import rapture.codec._
import java.net._
class StringMethods(s: String) {
@inline def urlEncode(implicit encoding: Encoding = encodings.`UTF-8`()) =
URLEncoder.encode(s, encoding.name)
@inline def urlDecode(implicit encoding: Encoding = encodings.`UTF-8`()) =
URLDecoder.decode(s, encoding.name)
}
================================================
FILE: io/shared/src/main/scala/rapture/io/wrappers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.io
import rapture.core._
import rapture.codec._
import rapture.uri._
import java.io._
/** Type class object for creating an Input[Byte] from a Java InputStream */
object InputStreamBuilder extends InputBuilder[InputStream, Byte] {
def input(s: InputStream): Input[Byte] = alloc[ByteInput](s)
}
/** Type class object for creating an Output[Byte] from a Java Reader */
object OutputStreamBuilder extends OutputBuilder[OutputStream, Byte] {
def output(s: OutputStream): Output[Byte] = alloc[ByteOutput](s)
}
object ClasspathStream {
def classpathStreamByteReader(implicit cl: ClassLoader) =
new JavaInputStreamReader[ClasspathUrl](url => cl.javaClassLoader.getResourceAsStream(url.uri.schemeSpecificPart))
}
/** Wraps a `java.io.Reader` as an `Input[Char]` */
class CharInput(in: java.io.Reader) extends Input[Char] {
private val bin = alloc[BufferedReader](in)
def ready() = bin.ready()
def read() = bin.read() match {
case -1 => None
case x => Some(x.toChar)
}
def close() = bin.close()
override def readBlock(array: Array[Char], offset: Int = 0, length: Int = -1): Int =
bin.read(array, offset, if (length == -1) array.length - offset else length)
override def toString() = ""
}
/** Wraps a `java.io.InputStream` as an `Input[Byte]` */
class ByteInput(in: InputStream) extends Input[Byte] {
private val bin = alloc[BufferedInputStream](in)
// FIXME: This might be really slow
def ready() = bin.available() > 0
def read() = bin.read() match {
case -1 => None
case x => Some(x.toByte)
}
override def readBlock(array: Array[Byte], offset: Int = 0, length: Int = -1): Int =
bin.read(array, offset, if (length == -1) array.length - offset else length)
def close() = in.close()
override def toString() = ""
}
/** Wraps a `java.io.OutputStream` into an `Output[Byte]`
*
* @param out The `java.io.OutputStream` to be wrapped */
class ByteOutput(out: OutputStream, closer: OutputStream => Unit = _.close()) extends Output[Byte] {
private val bout = alloc[BufferedOutputStream](out)
def write(b: Byte) = bout.write(b)
def flush(): Unit = bout.flush()
def close(): Unit = bout.close()
override def toString() = ""
override def writeBlock(array: Array[Byte], offset: Int = 0, length: Int = -1): Int = {
val len = if (length == -1) array.length - offset else length
bout.write(array, offset, len)
bout.flush()
len
}
}
/** Wraps a `java.io.Writer`
*
* @param out The `java.io.Writer` to be wrapped */
class CharOutput(out: java.io.Writer) extends Output[Char] {
private val bout = alloc[BufferedWriter](out)
def write(b: Char) = bout.write(b)
def flush(): Unit = bout.flush()
def close(): Unit = bout.close()
override def toString() = ""
override def writeBlock(array: Array[Char], offset: Int = 0, length: Int = -1): Int = {
val len = if (length == -1) array.length - offset else length
bout.write(array, offset, len)
bout.flush()
len
}
}
/** Wraps a `java.io.BufferedWriter` for providing line-by-line output of `String`s
*
* @param writer The `java.io.Writer` to be wrapped */
class LineOutput(writer: java.io.Writer) extends Output[String] {
def this(os: OutputStream, encoding: Encoding) =
this(new OutputStreamWriter(os, encoding.name))
private val out = alloc[BufferedWriter](writer)
def write(s: String) = {
out.write(s)
out.write("\n")
}
def flush(): Unit = out.flush()
def close(): Unit = out.close()
override def toString() = ""
}
/** Wraps a `java.io.Reader` as an `Input[String]`, where each String item read from the stream
* is a line of characters delimited by a newline. This is roughly equivalent to a
* `java.io.BufferedReader`.
*
* @constructor takes the Java Reader to be wrapped
* @param reader The Java Reader instance being wrapped. */
class LineInput(reader: java.io.Reader) extends Input[String] {
def this(is: InputStream, encoding: Encoding) =
this(new InputStreamReader(is, encoding.name))
private val in = alloc[BufferedReader](reader)
def ready(): Boolean = in.ready()
/** Reads one line from the stream as a `String` */
def read() = Option(in.readLine)
/** Closes the input stream and underlying `BufferedReader` */
def close() = in.close()
}
/** Type class object for creating an Input[Char] from a Java Reader */
object ReaderBuilder extends InputBuilder[java.io.Reader, Char] {
def input(s: java.io.Reader): Input[Char] = alloc[CharInput](s)
}
/** Type class object for creating an Input[String] from a Java Reader */
object LineReaderBuilder extends InputBuilder[java.io.Reader, String] {
def input(s: java.io.Reader): Input[String] = alloc[LineInput](s)
}
/** Type class object for creating an Output[Char] from a Java Writer */
object WriterBuilder extends OutputBuilder[java.io.Writer, Char] {
def output(s: java.io.Writer): Output[Char] = alloc[CharOutput](s)
}
class JavaOutputStreamWriter[T](val getOutputStream: T => OutputStream, val closer: OutputStream => Unit = _.close())
extends Writer[T, Byte] {
def output(t: T): Output[Byte] = alloc[ByteOutput](alloc[BufferedOutputStream](getOutputStream(t)), closer)
}
class JavaOutputAppender[T](val getOutputStream: T => OutputStream, val closer: OutputStream => Unit = _.close())
extends Appender[T, Byte] {
def appendOutput(t: T): Output[Byte] = alloc[ByteOutput](alloc[BufferedOutputStream](getOutputStream(t)), closer)
}
class JavaInputStreamReader[T](val getInputStream: T => InputStream) extends Reader[T, Byte] {
def input(t: T): Input[Byte] = alloc[ByteInput](alloc[BufferedInputStream](getInputStream(t)))
}
================================================
FILE: java8-support/shared/src/main/scala/rapture/core/java8/time.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.core.java8
import java.time._
import java.time.format.DateTimeFormatter
import java.time.format.DateTimeFormatter._
import rapture.core.{StringParser, StringSerializer}
private[java8] trait TimeSerializers {
implicit final def localDateSerializer: StringSerializer[LocalDate] = serializeLocalDate(ISO_LOCAL_DATE)
implicit final def localDateTimeSerializer: StringSerializer[LocalDateTime] = serializeLocalDateTime(ISO_LOCAL_DATE_TIME)
implicit final def localTimeSerializer: StringSerializer[LocalTime] = serializeLocalTime(ISO_LOCAL_TIME)
implicit final def zonedDateTimeSerializer: StringSerializer[ZonedDateTime] = serializeZonedDateTime(ISO_ZONED_DATE_TIME)
implicit final def offsetDateTimeSerializer: StringSerializer[OffsetDateTime] = serializeOffsetDateTime(ISO_OFFSET_DATE_TIME)
implicit final def offsetTimeSerializer: StringSerializer[OffsetTime] = serializeOffsetTime(ISO_OFFSET_TIME)
final def serializeLocalDate(formatter: DateTimeFormatter): StringSerializer[LocalDate] = {
StringSerializer(_.format(formatter))
}
final def serializeLocalDateTime(formatter: DateTimeFormatter): StringSerializer[LocalDateTime] = {
StringSerializer(_.format(formatter))
}
final def serializeLocalTime(formatter: DateTimeFormatter): StringSerializer[LocalTime] = {
StringSerializer(_.format(formatter))
}
final def serializeZonedDateTime(formatter: DateTimeFormatter): StringSerializer[ZonedDateTime] = {
StringSerializer(_.format(formatter))
}
final def serializeOffsetDateTime(formatter: DateTimeFormatter): StringSerializer[OffsetDateTime] = {
StringSerializer(_.format(formatter))
}
final def serializeOffsetTime(formatter: DateTimeFormatter): StringSerializer[OffsetTime] = {
StringSerializer(_.format(formatter))
}
}
private[java8] trait TimeStringParsers {
implicit final def localDateStringParser: StringParser[LocalDate] = parseLocalDate(ISO_LOCAL_DATE)
implicit final def localDateTimeStringParser: StringParser[LocalDateTime] = parseLocalDateTime(ISO_LOCAL_DATE_TIME)
implicit final def localTimeStringParser: StringParser[LocalTime] = parseLocalTime(ISO_LOCAL_TIME)
implicit final def zonedDateTimeStringParser: StringParser[ZonedDateTime] = parseZonedDateTime(ISO_ZONED_DATE_TIME)
implicit final def offsetDateTimeStringParser: StringParser[OffsetDateTime] = parseOffsetDateTime(ISO_OFFSET_DATE_TIME)
implicit final def offsetTimeStringParser: StringParser[OffsetTime] = parseOffsetTime(ISO_OFFSET_TIME)
final def parseLocalDate(formatter: DateTimeFormatter): StringParser[LocalDate] = {
StringParser(LocalDate.parse(_, formatter))
}
final def parseLocalDateTime(formatter: DateTimeFormatter): StringParser[LocalDateTime] = {
StringParser(LocalDateTime.parse(_, formatter))
}
final def parseLocalTime(formatter: DateTimeFormatter): StringParser[LocalTime] = {
StringParser(LocalTime.parse(_, formatter))
}
final def parseZonedDateTime(formatter: DateTimeFormatter): StringParser[ZonedDateTime] = {
StringParser(ZonedDateTime.parse(_, formatter))
}
final def parseOffsetDateTime(formatter: DateTimeFormatter): StringParser[OffsetDateTime] = {
StringParser(OffsetDateTime.parse(_, formatter))
}
final def parseOffsetTime(formatter: DateTimeFormatter): StringParser[OffsetTime] = {
StringParser(OffsetTime.parse(_, formatter))
}
}
object time extends TimeSerializers with TimeStringParsers
================================================
FILE: js/shared/src/main/scala/rapture/js/context.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.js
import rapture.base._
import rapture.data._
import scala.language.experimental.macros
private[js] object JsMacros {
def parseSource(s: List[String], stringsUsed: List[Boolean]): Option[(Int, Int, String)] =
try {
JsValidator.validate(s)
None
} catch {
case JsValidator.ValidationException(strNo, pos, msg) =>
Some((strNo, pos, s"failed to parse Js literal: $msg"))
}
def contextMacro(c: BlackboxContext)(exprs: c.Expr[ForcedConversion[Js]]*): c.Expr[Js] = {
import c.universe._
c.prefix.tree match {
case Select(Apply(_, List(Apply(_, rawParts))), _) =>
val ys = rawParts
val text = rawParts map { case lit @ Literal(Constant(part: String)) => part }
val listExprs = c.Expr[List[ForcedConversion[Js]]](q"_root_.scala.List(..${exprs.map(_.tree).to[List]})")
val stringsUsed: List[Boolean] = listExprs.tree match {
case Apply(_, bs) =>
bs.map {
case Apply(Apply(TypeApply(Select(_, nme), _), _), _) => nme.toString == "forceStringConversion"
}
}
parseSource(text, stringsUsed) foreach {
case (n, offset, msg) =>
val oldPos = ys(n).asInstanceOf[Literal].pos
val newPos = oldPos.withPoint(oldPos.start + offset)
c.error(newPos, msg)
}
val listParts = c.Expr[List[ForcedConversion[Js]]](q"_root_.scala.List(..$rawParts)")
reify {
val sb = new StringBuilder
val textParts = listParts.splice.iterator
val expressions: Iterator[ForcedConversion[_]] = listExprs.splice.iterator
sb.append(textParts.next())
while (textParts.hasNext) {
sb.append(expressions.next.value)
sb.append(textParts.next)
}
Js(sb.toString)
}
}
}
}
private[js] class JsStrings(sc: StringContext) {
class JsContext() {
def apply(exprs: ForcedConversion[Js]*): Js = macro JsMacros.contextMacro
}
val js = new JsContext()
}
================================================
FILE: js/shared/src/main/scala/rapture/js/js.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.js
case class Js(content: String) {
override def toString = s"""js${"\"" * 3}$content${"\"" * 3}"""
}
================================================
FILE: js/shared/src/main/scala/rapture/js/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.js
import language.implicitConversions
object `package` {
implicit def jsStringContext(sc: StringContext): JsStrings = new JsStrings(sc)
}
================================================
FILE: js/shared/src/main/scala/rapture/js/validator.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.js
import rapture.core._
import javax.script._
private[js] object JsValidator {
case class ValidationException(strNo: Int, pos: Int, msg: String) extends Exception
def validate(parts: List[String]): Unit = {
val script = parts.mkString("null")
val engine: Compilable = alloc[ScriptEngineManager]().getEngineByName("JavaScript") match {
case e: Compilable => e
}
try engine.compile(script)
catch {
case e: ScriptException =>
val pos = script.split("\n").take(e.getLineNumber - 1).map(_.length + 1).sum + e.getColumnNumber
val Regex = ":[0-9]+:[0-9]+ (.*)$".r
println("pos = " + pos)
val msg = e.getMessage.split("\n").head match { case Regex(m) => m }
throw ValidationException(0, pos, msg)
}
}
}
================================================
FILE: json/shared/src/main/scala/rapture/json/ast.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json
import rapture.core._
import rapture.data._
/** Represents a JSON ast implementation which is used throughout this library */
trait JsonAst extends DataAst {
def isScalar(any: Any) = isBoolean(any) || isNumber(any) || isString(any)
/** Extracts a `Boolean` from the parsed JSON. */
def getBoolean(boolean: Any): Boolean
def fromBoolean(boolean: Boolean): Any
/** Extracts a `String` from the parsed JSON. */
def getString(string: Any): String
def fromString(string: String): Any
/** Extracts a `Double` from the parsed JSON. */
def getDouble(number: Any): Double
def fromDouble(number: Double): Any
/** Extracts a `BigDecimal` from the parsed JSON. */
def getBigDecimal(number: Any): BigDecimal
def fromBigDecimal(number: BigDecimal): Any
/** Tests if the element represents a `Boolean` */
def isBoolean(any: Any): Boolean
/** Tests if the element represents a `String` */
def isString(any: Any): Boolean
/** Tests if the element represents a number */
def isNumber(any: Any): Boolean
/** Tests if the element represents a `null` */
def isNull(any: Any): Boolean
/** The value used to represent a `null` */
def nullValue: Any
/** Returns the DataType instance for the particular type. */
def getType(any: Any): DataTypes.DataType =
if (isBoolean(any)) DataTypes.Boolean
else if (isString(any)) DataTypes.String
else if (isNumber(any)) DataTypes.Number
else if (isObject(any)) DataTypes.Object
else if (isArray(any)) DataTypes.Array
else if (isNull(any)) DataTypes.Null
else throw MissingValueException()
def convert(v: Any, ast: DataAst): Any = {
val oldAst = ast.asInstanceOf[JsonAst]
if (oldAst.isString(v)) fromString(oldAst.getString(v))
else if (oldAst.isBoolean(v)) fromBoolean(oldAst.getBoolean(v))
else if (oldAst.isNumber(v)) fromDouble(oldAst.getDouble(v))
else if (oldAst.isArray(v)) fromArray(oldAst.getArray(v).map(convert(_, oldAst)))
else if (oldAst.isObject(v)) fromObject(oldAst.getObject(v).mapValues(convert(_, oldAst)))
else nullValue
}
protected def typeTest(pf: PartialFunction[Any, Unit])(v: Any) = pf.isDefinedAt(v)
}
trait JsonBufferAst extends JsonAst with MutableDataAst
================================================
FILE: json/shared/src/main/scala/rapture/json/context.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json
import rapture.base._
import rapture.core._
import rapture.data._
import language.experimental.macros
private[json] object JsonDataMacros extends DataContextMacros[Json, JsonAst] {
def dataCompanion(c: BlackboxContext): c.Expr[DataCompanion[Json, JsonAst]] = c.universe.reify(Json)
def parseSource(s: List[String], stringsUsed: List[Boolean]) =
try {
JsonValidator.validate(s, stringsUsed)
None
} catch {
case JsonValidator.ValidationException(strNo, pos, expected, found) =>
val f = if (found == '\u0000') "end of input" else s"'$found'"
Some((strNo, pos, s"failed to parse Json literal: expected $expected, but found $f"))
case JsonValidator.DuplicateKeyException(strNo, pos, key) =>
Some((strNo, pos, s"""duplicate key found in Json literal: "$key""""))
case JsonValidator.NonStringKeyException(strNo, pos) =>
Some((strNo, pos, s"""only Strings may be used as JSON object keys"""))
}
override def contextMacro(c: BlackboxContext)(exprs: c.Expr[ForcedConversion[Json]]*)(
parser: c.Expr[Parser[String, JsonAst]]): c.Expr[Json] =
super.contextMacro(c)(exprs: _*)(parser)
}
private[json] object JsonBufferDataMacros extends DataContextMacros[JsonBuffer, JsonBufferAst] {
def dataCompanion(c: BlackboxContext): c.Expr[DataCompanion[JsonBuffer, JsonBufferAst]] =
c.universe.reify(JsonBuffer)
def parseSource(s: List[String], stringsUsed: List[Boolean]) =
try {
JsonValidator.validate(s, stringsUsed)
None
} catch {
case JsonValidator.ValidationException(strNo, pos, expected, found) =>
val f = if (found == '\u0000') "end of input" else s"'$found'"
Some((strNo, pos, s"Failed to parse JsonBuffer literal: Expected $expected, but found $f."))
}
override def contextMacro(c: BlackboxContext)(exprs: c.Expr[ForcedConversion[JsonBuffer]]*)(
parser: c.Expr[Parser[String, JsonBufferAst]]): c.Expr[JsonBuffer] =
super.contextMacro(c)(exprs: _*)(parser)
}
/** Provides support for JSON literals, in the form json" { } " or json""" { } """.
* Interpolation is used to substitute variable names into the JSON, and to extract values
* from a JSON string. */
private[json] class JsonStrings(sc: StringContext) {
class JsonContext() extends DataContext(Json, sc) {
def apply(exprs: ForcedConversion[Json]*)(implicit parser: Parser[String, JsonAst]): Json = macro JsonDataMacros.contextMacro
}
val json = new JsonContext()
}
private[json] class JsonBufferStrings(sc: StringContext) {
class JsonBufferContext() extends DataContext(JsonBuffer, sc) {
def apply(exprs: ForcedConversion[JsonBuffer]*)(implicit parser: Parser[String, JsonBufferAst]): JsonBuffer = macro JsonBufferDataMacros.contextMacro
}
val jsonBuffer = new JsonBufferContext()
}
================================================
FILE: json/shared/src/main/scala/rapture/json/extractors.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json
import rapture.core._
import rapture.data._
import scala.util._
import language.higherKinds
private[json] case class JsonCastExtractor[T](ast: JsonAst, dataType: DataTypes.DataType)
private[json] trait Extractors extends Extractors_1 {
implicit def optionExtractor[T](
implicit ext: Extractor[T, Json]): Extractor[Option[T], Json] { type Throws = Nothing } =
GeneralExtractors.optionExtractor[Json, T]
implicit def tryExtractor[T](implicit ext: Extractor[T, Json]): Extractor[Try[T], Json] { type Throws = Nothing } =
GeneralExtractors.tryExtractor[Json, T]
implicit def genSeqExtractor[T, Coll[_]](
implicit cbf: scala.collection.generic.CanBuildFrom[Nothing, T, Coll[T]],
ext: Extractor[T, Json]): Extractor[Coll[T], Json] { type Throws = ext.Throws } = {
GeneralExtractors.genSeqExtractor[T, Coll, Json]
}
implicit def mapExtractor[K, V](implicit ext: Extractor[V, Json],
ext2: StringParser[K]): Extractor[Map[K, V], Json] =
GeneralExtractors.mapExtractor[K, V, Json]
}
private[json] trait Extractors_1 extends Extractors_2 {
implicit def jsonExtractor(implicit ast: JsonAst): Extractor[Json, Json] { type Throws = DataGetException } =
new Extractor[Json, Json] {
type Throws = DataGetException
def extract(any: Json, dataAst: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Json, DataGetException] =
mode.wrap(mode.catching[DataGetException, Json](any.$wrap(any.$normalize)))
}
implicit val stringExtractor: Extractor[String, Json] { type Throws = DataGetException } =
new Extractor[String, Json] {
type Throws = DataGetException
def extract(any: Json, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[String, DataGetException] =
mode.wrap(mode.catching[DataGetException, String](any.$ast.getString(any.$normalize)))
}
implicit val nullExtractor: Extractor[Null, Json] { type Throws = DataGetException } = new Extractor[Null, Json] {
type Throws = DataGetException
override def extract(any: Json, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Null, this.Throws] = {
mode.wrap(
mode.catching[DataGetException, Null](
if (any.$ast.isNull(any.$normalize)) null
else throw TypeMismatchException(any.$ast.getType(any.$normalize), DataTypes.Null)
))
}
}
implicit val doubleExtractor: Extractor[Double, Json] { type Throws = DataGetException } =
new Extractor[Double, Json] {
type Throws = DataGetException
def extract(any: Json, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Double, Throws] =
mode.wrap(mode.catching[DataGetException, Double](any.$ast.getDouble(any.$normalize)))
}
implicit val intExtractor: Extractor[Int, Json] { type Throws = DataGetException } = doubleExtractor.smap(_.toInt)
implicit val booleanExtractor: Extractor[Boolean, Json] { type Throws = DataGetException } =
new Extractor[Boolean, Json] {
type Throws = DataGetException
def extract(any: Json, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Boolean, DataGetException] =
mode.wrap(any.$ast.getBoolean(any.$normalize))
}
implicit val bigDecimalExtractor: Extractor[BigDecimal, Json] { type Throws = DataGetException } =
new Extractor[BigDecimal, Json] {
type Throws = DataGetException
def extract(any: Json,
ast: DataAst,
mode: Mode[_ <: MethodConstraint]): mode.Wrap[BigDecimal, DataGetException] =
mode.wrap(any.$ast.getBigDecimal(any.$normalize))
}
implicit val bigIntExtractor: Extractor[BigInt, Json] { type Throws = DataGetException } =
bigDecimalExtractor.smap(_.toBigInt)
implicit val longExtractor: Extractor[Long, Json] { type Throws = DataGetException } = bigIntExtractor.smap(_.toLong)
implicit val byteExtractor: Extractor[Byte, Json] { type Throws = DataGetException } = intExtractor.smap(_.toByte)
implicit val floatExtractor: Extractor[Float, Json] { type Throws = DataGetException } =
doubleExtractor.smap(_.toFloat)
implicit val shortExtractor: Extractor[Short, Json] { type Throws = DataGetException } = intExtractor.smap(_.toShort)
}
private[json] trait Extractors_2 {
implicit def jsonBufferExtractor[T](implicit jsonAst: JsonAst,
ext: Extractor[T, Json]): Extractor[T, JsonBuffer] { type Throws = ext.Throws } =
new Extractor[T, JsonBuffer] {
type Throws = ext.Throws
def extract(any: JsonBuffer, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[T, ext.Throws] =
ext.extract(Json.construct(MutableCell(any.$root.value), Vector()), ast, mode)
}
implicit def jsonBufferToJsonExtractor(implicit ast: JsonBufferAst): Extractor[JsonBuffer, Json] =
new Extractor[JsonBuffer, Json] {
type Throws = DataGetException
def extract(any: Json, dataAst: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[JsonBuffer, Throws] =
mode.wrap(JsonBuffer.construct(MutableCell(JsonDataType.jsonSerializer.serialize(any)), Vector()))
}
implicit def generalStringExtractor[S](implicit parser: StringParser[S]): Extractor[S, Json] {
type Throws = DataGetException with parser.Throws
} = new Extractor[S, Json] {
type Throws = DataGetException with parser.Throws
def extract(any: Json,
ast: DataAst,
mode: Mode[_ <: MethodConstraint]): mode.Wrap[S, DataGetException with parser.Throws] =
mode.wrap(mode.unwrap(parser.parse(any.$ast.getString(any.$normalize), mode)))
}
}
================================================
FILE: json/shared/src/main/scala/rapture/json/formatters.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json
import rapture.core._
import rapture.data._
object formatters extends formatters_1 {
object compact {
def apply[Ast <: JsonAst]()(implicit ast: Ast, df: DecimalFormat): Formatter[Ast] { type Out = String } =
jsonFormatterImplicit[Ast]
implicit def jsonFormatterImplicit[Ast <: JsonAst](implicit ast: Ast,
df: DecimalFormat): Formatter[Ast] { type Out = String } =
new Formatter[Ast] {
type Out = String
def format(json: Any): String = general(json, 0, ast, "", "")
}
}
}
private[json] class formatters_1 {
/** Formats the JSON object for multi-line readability. */
protected def general[Ast <: JsonAst](json: Any, ln: Int, ast: Ast, pad: String = " ", brk: String = "\n")(
implicit df: DecimalFormat): String = {
val indent = pad * ln
json match {
case j =>
if (ast.isString(j)) {
"\"" + ast
.getString(j)
.replaceAll("\\\\", "\\\\\\\\")
.replaceAll("\r", "\\\\r")
.replaceAll("\t", "\\\\t")
.replaceAll("\n", "\\\\n")
.replaceAll("\"", "\\\\\"") + "\""
} else if (ast.isBoolean(j)) {
if (ast.getBoolean(j)) "true" else "false"
} else if (ast.isNumber(j)) {
val bd = ast.getBigDecimal(j)
if (bd.isWhole) String(bd.toBigInt) else String(df.format(bd))
} else if (ast.isArray(j)) {
val arr = ast.getArray(j)
if (arr.isEmpty) "[]"
else
List("[", arr map { v =>
s"${indent}${pad}${general(v, ln + 1, ast, pad, brk)}"
} mkString s",${brk}", s"${indent}]") mkString brk
} else if (ast.isObject(j)) {
val keys = ast.getKeys(j)
if (keys.isEmpty) "{}"
else
List("{", keys map { k =>
val inner = ast.dereferenceObject(j, k)
s"""${indent}${pad}"${k}":${pad}${general(inner, ln + 1, ast, pad, brk)}"""
} mkString s",${brk}", s"${indent}}") mkString brk
} else if (ast.isNull(j)) "null"
else if (j == DataCompanion.Empty) "empty"
else "undefined"
}
}
object humanReadable {
def apply[Ast <: JsonAst]()(implicit ast: Ast): Formatter[Ast] { type Out = String } =
jsonFormatterImplicit[Ast]
implicit def jsonFormatterImplicit[Ast <: JsonAst](implicit ast: Ast,
df: DecimalFormat): Formatter[Ast] { type Out = String } =
new Formatter[Ast] {
type Out = String
def format(json: Any): String = general(json, 0, ast, " ", "\n")
}
}
}
================================================
FILE: json/shared/src/main/scala/rapture/json/json.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json
import rapture.core._
import rapture.data._
import language.experimental.macros
private[json] trait Json_2 {
implicit def jsonExtractorMacro[T <: Product, Th]: Extractor[T, Json] = macro JsonMacros
.jsonExtractorMacro[T, Th]
implicit def jsonSerializerMacro[T <: Product](implicit ast: JsonAst): Serializer[T, Json] = macro JsonMacros
.jsonSerializerMacro[T]
}
private[json] trait Json_1 extends Json_2 {
implicit def dynamicWorkaround(j: Json) = new DynamicWorkaround(j)
}
private[json] class DynamicWorkaround(json: Json) {
def self: Json = json.selectDynamic("self")(null)
}
trait `Json.parse` extends MethodConstraint
private[json] trait JsonDataCompanion[+Type <: JsonDataType[Type, AstType], AstType <: JsonAst]
extends DataCompanion[Type, AstType] {
type ParseMethodConstraint = `Json.parse`
/** Formats the JSON object for multi-line readability. */
private[json] def doFormat(json: Any, ln: Int, ast: AstType, pad: String = " ", brk: String = "\n"): String = {
val indent = pad * ln
json match {
case j =>
if (ast.isString(j)) {
"\"" + ast
.getString(j)
.replaceAll("\\\\", "\\\\\\\\")
.replaceAll("\r", "\\\\r")
.replaceAll("\n", "\\\\n")
.replaceAll("\"", "\\\\\"") + "\""
} else if (ast.isBoolean(j)) {
if (ast.getBoolean(j)) "true" else "false"
} else if (ast.isNumber(j)) {
val n = ast.getDouble(j)
if (n == n.floor) n.toInt.toString else String(n)
} else if (ast.isArray(j)) {
val arr = ast.getArray(j)
if (arr.isEmpty) "[]"
else
List("[", arr map { v =>
s"${indent}${pad}${doFormat(v, ln + 1, ast, pad, brk)}"
} mkString s",${brk}", s"${indent}]") mkString brk
} else if (ast.isObject(j)) {
val keys = ast.getKeys(j)
if (keys.isEmpty) "{}"
else
List("{", keys map { k =>
val inner = ast.dereferenceObject(j, k)
s"""${indent}${pad}"${k}":${pad}${doFormat(inner, ln + 1, ast, pad, brk)}"""
} mkString s",${brk}", s"${indent}}") mkString brk
} else if (ast.isNull(j)) "null"
else if (j == DataCompanion.Empty) "empty"
else "undefined"
}
}
}
private[json] object JsonDataType extends Extractors with Serializers
private[json] trait JsonDataType[+T <: JsonDataType[T, AstType], AstType <: JsonAst] extends DataType[T, AstType]
object JsonBuffer extends JsonDataCompanion[JsonBuffer, JsonBufferAst] {
def construct(any: MutableCell, path: Vector[Either[Int, String]])(implicit ast: JsonBufferAst): JsonBuffer =
new JsonBuffer(any, path)
}
/** Companion object to the `Json` type, providing factory and extractor methods, and a JSON
* pretty printer. */
object Json extends JsonDataCompanion[Json, JsonAst] with Json_1 {
def apply[T](t: T)(implicit ast: JsonAst, ser: Serializer[T, Json]): Json =
construct(MutableCell(if(t == null) ast.nullValue else ser.serialize(t)), Vector())
implicit def stringParser(implicit parser: Parser[String, JsonAst],
mode: Mode[_ <: ParseMethodConstraint]): StringParser[Json] =
new StringParser[Json] {
type Throws = rapture.data.ParseException
def parse(str: String, mode2: Mode[_ <: MethodConstraint]): mode2.Wrap[Json, rapture.data.ParseException] =
mode2.wrap {
mode.unwrap(Json.parse(str)(implicitly[StringSerializer[String]], mode, parser))
}
}
def construct(any: MutableCell, path: Vector[Either[Int, String]])(implicit ast: JsonAst): Json = new Json(any, path)
def ast(json: Json): JsonAst = json.$ast
def extractor[T](implicit ext: Extractor[T, Json]): Extractor[T, Json] { type Throws = ext.Throws } = ext
def serializer[T](implicit ser: Serializer[T, Json]) = ser
implicit def jsonCastExtractor[T: JsonCastExtractor](
implicit ast: JsonAst): Extractor[T, JsonDataType[_, _ <: JsonAst]] =
new Extractor[T, JsonDataType[_, _ <: JsonAst]] {
type Throws = DataGetException
def extract(value: JsonDataType[_, _ <: JsonAst],
ast2: DataAst,
mode: Mode[_ <: MethodConstraint]): mode.Wrap[T, DataGetException] =
mode.wrap(ast2 match {
case ast2: JsonAst =>
val norm = mode.catching[DataGetException, Any](value.$normalize)
try {
if (ast == ast2) norm.asInstanceOf[T]
else
JsonDataType.jsonSerializer
.serialize(Json.construct(MutableCell(norm), Vector())(ast2))
.asInstanceOf[T]
} catch {
case e: ClassCastException =>
mode.exception[T, DataGetException](
TypeMismatchException(ast.getType(norm), implicitly[JsonCastExtractor[T]].dataType))
}
case _ => ???
})
}
}
/** Represents some parsed JSON. */
class Json(val $root: MutableCell, val $path: Vector[Either[Int, String]] = Vector())(implicit val $ast: JsonAst)
extends JsonDataType[Json, JsonAst]
with DynamicData[Json, JsonAst] {
def $wrap(any: Any, path: Vector[Either[Int, String]]): Json =
new Json(MutableCell(any), path)
def $deref(path: Vector[Either[Int, String]]): Json = new Json($root, path)
def applyDynamic(key: String)(i: Int = 0): Json = $deref(Left(i) +: Right(key) +: $path)
def $extract(sp: Vector[Either[Int, String]]): Json =
if (sp.isEmpty) this
else
sp match {
case Left(i) +: tail => apply(i).$extract(tail)
case Right(e) +: tail => selectDynamic(e)(null).$extract(tail)
}
def toBareString: String =
try Json.format(this)(formatters.compact.jsonFormatterImplicit($ast, decimalFormats.exact()))
catch {
case e: Exception => "undefined"
}
override def toString: String = s"""json""${'"'}${toBareString}""${'"'}"""
}
class JsonBuffer(val $root: MutableCell, val $path: Vector[Either[Int, String]] = Vector())(
implicit val $ast: JsonBufferAst)
extends JsonDataType[JsonBuffer, JsonBufferAst]
with MutableDataType[JsonBuffer, JsonBufferAst]
with DynamicData[JsonBuffer, JsonBufferAst] {
def applyDynamic(key: String)(i: Int = 0): JsonBuffer = $deref(Left(i) +: Right(key) +: $path)
def $wrap(any: Any, path: Vector[Either[Int, String]]): JsonBuffer =
new JsonBuffer(MutableCell(any), path)
def $deref(path: Vector[Either[Int, String]]): JsonBuffer = new JsonBuffer($root, path)
def $extract(sp: Vector[Either[Int, String]]): JsonBuffer =
if (sp.isEmpty) this
else
sp match {
case Left(i) +: tail => apply(i).$extract(tail)
case Right(e) +: tail => selectDynamic(e)(null).$extract(tail)
}
def toBareString: String =
try Json.format(this)(formatters.compact.jsonFormatterImplicit($ast, decimalFormats.exact()))
catch {
case e: Exception => "undefined"
}
override def toString: String = s"""json""${'"'}${toBareString}""${'"'}"""
}
================================================
FILE: json/shared/src/main/scala/rapture/json/macros.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json
import rapture.base._
import rapture.data._
private[json] object JsonMacros {
def jsonExtractorMacro[T: c.WeakTypeTag, Th](c: WhiteboxContext): c.Expr[Extractor[T, Json]] =
Macros.extractorMacro[T, Json, Th](c)
//def jsonBufferExtractorMacro[T: c.WeakTypeTag](c: Context) =
// Macros.extractorMacro2[T, JsonBuffer](c)
def jsonSerializerMacro[T: c.WeakTypeTag](c: WhiteboxContext)(ast: c.Expr[JsonAst]): c.Expr[Serializer[T, Json]] =
Macros.serializerMacro[T, Json](c)(ast)
def jsonBufferSerializerMacro[T: c.WeakTypeTag](c: WhiteboxContext)(
ast: c.Expr[JsonBufferAst]): c.Expr[Serializer[T, JsonBuffer]] =
Macros.serializerMacro[T, JsonBuffer](c)(ast)
}
================================================
FILE: json/shared/src/main/scala/rapture/json/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json
import rapture.core._
import rapture.data._
object `package` {
val patternMatching = rapture.data.patternMatching
type Extractor[T, -D] = rapture.data.Extractor[T, D]
type Serializer[T, -D] = rapture.data.Serializer[T, D]
type DataGetException = rapture.data.DataGetException
type TypeMismatchException = rapture.data.TypeMismatchException
type MissingValueException = rapture.data.MissingValueException
type Dictionary[S <: String] = rapture.data.Dictionary[S]
val Dictionary = rapture.data.Dictionary
val TypeMismatchException = rapture.data.TypeMismatchException
val MissingValueException = rapture.data.MissingValueException
implicit def jsonStringContext(sc: StringContext)(implicit parser: Parser[String, JsonAst]) =
new JsonStrings(sc)
implicit def jsonBufferStringContext(sc: StringContext)(implicit parser: Parser[String, JsonBufferAst]) =
new JsonBufferStrings(sc)
implicit class JsonOperations(json: Json) extends DataType.DataClassOperations[Json, JsonAst](json)
val dictionaries = rapture.data.dictionaries
}
================================================
FILE: json/shared/src/main/scala/rapture/json/serializers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json
import rapture.core._
import rapture.data._
import language.higherKinds
private[json] case class DirectJsonSerializer[T](ast: JsonAst)
private[json] case class BasicJsonSerializer[T](serialization: T => Any) extends Serializer[T, Json] {
def serialize(t: T): Any = serialization(t)
}
private[json] trait Serializers extends Serializers_1 {
implicit def jsonBufferSerializer[T](implicit ser: Serializer[T, Json]): Serializer[T, JsonBuffer] =
new Serializer[T, JsonBuffer] { def serialize(t: T): Any = ser.serialize(t) }
implicit def intSerializer(implicit ast: JsonAst): Serializer[Int, Json] =
BasicJsonSerializer(ast fromDouble _.toDouble)
implicit def booleanSerializer(implicit ast: JsonAst): Serializer[Boolean, Json] =
BasicJsonSerializer(ast fromBoolean _)
implicit def stringSerializer(implicit ast: JsonAst): Serializer[String, Json] =
BasicJsonSerializer(ast fromString _)
implicit def floatSerializer(implicit ast: JsonAst): Serializer[Float, Json] =
BasicJsonSerializer(ast fromDouble _.toDouble)
implicit def doubleSerializer(implicit ast: JsonAst): Serializer[Double, Json] =
BasicJsonSerializer(ast fromDouble _)
implicit def bigDecimalSerializer(implicit ast: JsonAst): Serializer[BigDecimal, Json] =
BasicJsonSerializer(ast fromBigDecimal _)
implicit def bigIntSerializer(implicit ast: JsonAst): Serializer[BigInt, Json] =
BasicJsonSerializer(ast fromBigDecimal BigDecimal(_))
implicit def longSerializer(implicit ast: JsonAst): Serializer[Long, Json] =
BasicJsonSerializer(ast fromDouble _.toDouble)
implicit def shortSerializer(implicit ast: JsonAst): Serializer[Short, Json] =
BasicJsonSerializer(ast fromDouble _.toDouble)
implicit def byteSerializer(implicit ast: JsonAst): Serializer[Byte, Json] =
BasicJsonSerializer(ast fromDouble _.toDouble)
implicit def nilSerializer(implicit ast: JsonAst): Serializer[Nil.type, Json] =
BasicJsonSerializer(v => ast fromArray Nil)
implicit def traversableSerializer[Type, Coll[T] <: Traversable[T]](
implicit ast: JsonAst,
ser: Serializer[Type, Json]): Serializer[Coll[Type], Json] =
BasicJsonSerializer(ast fromArray _.map(ser.serialize).to[List])
implicit def optionSerializer[Type](implicit ast: JsonAst,
ser: Serializer[Type, Json]): Serializer[Option[Type], Json] =
BasicJsonSerializer(_ map ser.serialize getOrElse ast.nullValue)
implicit def mapSerializer[K, Type, Ast <: JsonAst](implicit ast: Ast,
ser: Serializer[Type, Json],
ser2: StringSerializer[K]): Serializer[Map[K, Type], Json] =
new Serializer[Map[K, Type], Json] {
def serialize(m: Map[K, Type]) =
ast.fromObject(m.map {
case (k, v) =>
ser2.serialize(k) -> ser.serialize(v)
})
}
implicit def directJsonSerializer[T: DirectJsonSerializer](implicit ast: JsonAst): Serializer[T, Json] =
BasicJsonSerializer(
obj => jsonSerializer.serialize(Json.construct(MutableCell(obj), Vector())(?[DirectJsonSerializer[T]].ast)))
implicit def jsonSerializer[JsonType <: JsonDataType[JsonType, _ <: JsonAst]](
implicit ast: JsonAst): Serializer[JsonType, Json] =
BasicJsonSerializer[JsonType]({ j =>
if (j.$ast == ast) j.$normalize else ast.convert(j.$normalize, j.$ast)
})
}
trait Serializers_1 {
implicit def generalStringSerializer[S](implicit ast: JsonAst, ss: StringSerializer[S]): Serializer[S, Json] =
BasicJsonSerializer(s => ast fromString ss.serialize(s))
}
================================================
FILE: json/shared/src/main/scala/rapture/json/validator.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json
private[json] object JsonValidator {
case class ValidationException(strNo: Int, pos: Int, expected: String, found: Char) extends Exception
case class DuplicateKeyException(strNo: Int, pos: Int, key: String) extends Exception
case class NonStringKeyException(strNo: Int, pos: Int) extends Exception
def validate(parts: List[String], stringsUsed: List[Boolean]) = {
var i = 0
var n = 0
def s = parts(n)
def cur = if (i >= s.length) '\u0000' else s(i)
def fail(expected: String) = throw ValidationException(n, i, expected, cur)
def failPosition(expected: String) = throw ValidationException(n, i, expected, cur)
def duplicateKey(start: Int, key: String) = throw DuplicateKeyException(n, start, key)
def takeWhitespace(): Unit = while (cur.isWhitespace) next()
def consume(cs: Char*): Unit = cs foreach { c =>
if (cur == c) next() else fail(s"'$c'")
}
def next() = i += 1
def takeValue(): Unit = cur match {
case '{' => takeObject()
case '[' => takeArray()
case '"' => takeString()
case c if c.isDigit || c == '-' => takeNumber()
case 't' => takeTrue()
case 'f' => takeFalse()
case 'n' => takeNull()
case '\u0000' =>
if (n + 1 < parts.length) {
n += 1
i = 0
} else fail("new token or interpolated value")
case _ => fail("new token")
}
def takeTrue() = consume('t', 'r', 'u', 'e')
def takeFalse() = consume('f', 'a', 'l', 's', 'e')
def takeNull() = consume('n', 'u', 'l', 'l')
def takeNumber() = {
if (cur == '-') next()
if (cur == '0') next()
else if (cur.isDigit) while (cur.isDigit) next()
else fail("digit")
if (cur == '.') {
next()
if (cur.isDigit) next() else fail("digit")
while (cur.isDigit) next()
}
if (cur == 'e' || cur == 'E') {
next()
if (cur == '+' || cur == '-') next()
if (cur.isDigit) next() else fail("digit")
while (cur.isDigit) next()
}
}
def takeObject(): Unit = {
var seen: Set[String] = Set()
def takeKeyValue(): Unit = {
val start = i
cur match {
case '\u0000' =>
if (n + 1 < parts.length) {
if (!stringsUsed(n)) throw new NonStringKeyException(n, i)
n += 1
i = 0
} else fail("new token or interpolated value")
case '"' =>
takeString()
val key = s.substring(start + 1, i - 1)
if (seen contains key) duplicateKey(start, key) else seen += key
}
takeWhitespace()
cur match {
case ':' =>
consume(':')
takeWhitespace()
takeValue()
takeWhitespace()
cur match {
case ',' =>
consume(',')
takeWhitespace()
takeKeyValue()
case '}' => consume('}')
case _ => fail("',' or '}'")
}
case _ => fail("':'")
}
}
consume('{')
takeWhitespace()
cur match {
case '"' | '\u0000' => takeKeyValue()
case '}' => consume('}')
case _ => fail("'\"' or '}'")
}
}
def takeArray(): Unit = {
def takeElement(): Unit = {
takeValue()
takeWhitespace()
cur match {
case ',' =>
consume(',')
takeWhitespace()
takeElement()
case ']' => consume(']')
case _ => fail("',' or ']'")
}
}
consume('[')
takeWhitespace()
cur match {
case ']' => consume(']')
case _ => takeElement()
}
}
def takeString(): Unit = {
consume('"')
while (cur != '"') cur match {
case '\\' =>
consume('\\')
cur match {
case '"' | '\\' | '/' | 'b' | 'f' | 'n' | 'r' | 't' => next()
case 'u' =>
consume('u')
1 to 4 foreach { j =>
if (cur.isDigit || cur >= 'a' && cur <= 'f' || cur >= 'A' && cur <= 'F') next()
else fail("hexadecimal digit")
}
}
case '\u0000' => failPosition("'\"' or more string content")
case _ => next()
}
consume('"')
}
takeWhitespace()
takeValue()
takeWhitespace()
if (i != s.length) fail("end of data")
}
}
================================================
FILE: json/shared/src/main/scala/rapture/json/verifier.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json
object JsonVerifier {
case class VerifierException(strNo: Int, pos: Int, expected: String, found: Char) extends Exception
case class DuplicateKeyException(strNo: Int, pos: Int, key: String) extends Exception
def verify(parts: List[String]) = {
var i = 0
var n = 0
def s = parts(n)
def cur = if (i >= s.length) '\u0000' else s(i)
def fail(expected: String) = throw VerifierException(n, i, expected, cur)
def failPosition(expected: String) = throw VerifierException(n, i, expected, cur)
def duplicateKey(start: Int, key: String) = throw DuplicateKeyException(n, start, key)
def takeWhitespace(): Unit = while (cur.isWhitespace) next()
def consume(cs: Char*): Unit = cs foreach { c =>
if (cur == c) next() else fail(s"'$c'")
}
def next() = i += 1
def takeValue(): Unit = cur match {
case '{' => takeObject()
case '[' => takeArray()
case '"' => takeString()
case c if c.isDigit || c == '-' => takeNumber()
case 't' => takeTrue()
case 'f' => takeFalse()
case 'n' => takeNull()
case '\u0000' =>
if (n + 1 < parts.length) {
n += 1
i = 0
} else fail("new token or interpolated value")
case _ => fail("new token")
}
def takeTrue() = consume('t', 'r', 'u', 'e')
def takeFalse() = consume('f', 'a', 'l', 's', 'e')
def takeNull() = consume('n', 'u', 'l', 'l')
def takeNumber() = {
if (cur == '-') next()
if (cur == '0') next()
else if (cur.isDigit) while (cur.isDigit) next()
else fail("digit")
if (cur == '.') {
next()
if (cur.isDigit) next() else fail("digit")
while (cur.isDigit) next()
}
if (cur == 'e' || cur == 'E') {
next()
if (cur == '+' || cur == '-') next()
if (cur.isDigit) next() else fail("digit")
while (cur.isDigit) next()
}
}
def takeObject(): Unit = {
var seen: Set[String] = Set()
def takeKeyValue(): Unit = {
val start = i
takeString()
val key = s.substring(start + 1, i - 1)
if (seen contains key) duplicateKey(start, key) else seen += key
takeWhitespace()
cur match {
case ':' =>
consume(':')
takeWhitespace()
takeValue()
takeWhitespace()
cur match {
case ',' =>
consume(',')
takeWhitespace()
takeKeyValue()
case '}' => consume('}')
case _ => fail("',' or '}'")
}
case _ => fail("':'")
}
}
consume('{')
takeWhitespace()
cur match {
case '"' => takeKeyValue()
case '}' => consume('}')
case _ => fail("'\"' or '}'")
}
}
def takeArray(): Unit = {
def takeElement(): Unit = {
takeValue()
takeWhitespace()
cur match {
case ',' =>
consume(',')
takeWhitespace()
takeElement()
case ']' => consume(']')
case _ => fail("',' or ']'")
}
}
consume('[')
takeWhitespace()
cur match {
case ']' => consume(']')
case _ => takeElement()
}
}
def takeString(): Unit = {
consume('"')
while (cur != '"') cur match {
case '\\' =>
consume('\\')
cur match {
case '"' | '\\' | '/' | 'b' | 'f' | 'n' | 'r' | 't' => next()
case 'u' =>
consume('u')
1 to 4 foreach { j =>
if (cur.isDigit || cur >= 'a' && cur <= 'f' || cur >= 'A' && cur <= 'F') next()
else fail("hexadecimal digit")
}
}
case '\u0000' => failPosition("'\"' or more string content")
case _ => next()
}
consume('"')
}
takeWhitespace()
takeValue()
takeWhitespace()
if (i != s.length) fail("end of data")
}
}
================================================
FILE: json-argonaut/shared/src/main/scala/rapture/json-argonaut/ast.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.argonaut
import rapture.core._
import rapture.data.DataTypes
import rapture.json._
import argonaut.{Json => AJson, _}
import Argonaut._
private[argonaut] object ArgonautAst extends JsonBufferAst {
override def toString = ""
override def dereferenceObject(obj: Any, element: String): Any =
obj match {
case j: AJson if j.isObject => j.field(element).getOrElse(throw MissingValueException())
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def getKeys(obj: Any): Iterator[String] =
obj match {
case j: AJson if j.isObject => j.objectFields.get.iterator
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def dereferenceArray(array: Any, element: Int): Any =
array match {
case j: AJson if j.isArray => j.array.get(element)
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def getArray(array: Any): List[Any] = array match {
case j: AJson if j.isArray => j.array.get
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def getBoolean(boolean: Any): Boolean = boolean match {
case j: AJson if j.isBool => j.bool.get
case _ => throw TypeMismatchException(getType(boolean), DataTypes.Boolean)
}
def getDouble(double: Any): Double = double match {
case j: AJson if j.isNumber => j.number.get.toDouble.get
case _ => throw TypeMismatchException(getType(double), DataTypes.Number)
}
def getBigDecimal(bigDecimal: Any): BigDecimal = bigDecimal match {
case j: AJson if j.isNumber => BigDecimal(j.number.get.toBigInt.get)
case _ => throw TypeMismatchException(getType(bigDecimal), DataTypes.Number)
}
def getString(string: Any): String = string match {
case j: AJson if j.isString => j.string.get
case _ => throw TypeMismatchException(getType(string), DataTypes.String)
}
def getObject(obj: Any): Map[String, Any] = obj match {
case j: AJson if j.isObject => j.obj.get.toMap.map { case (k, v) => k.toString -> v }
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
def setObjectValue(obj: Any, name: String, value: Any): Any = {
val contents = (name, value) :: obj.asInstanceOf[AJson].obj.get.toList.collect {
case (k, v) if k.toString != name => k.toString -> v
}
fromObject(contents.toMap)
}
def removeObjectValue(obj: Any, name: String): Any = {
val contents = obj.asInstanceOf[AJson].obj.get.toList.collect {
case (k, v) if k.toString != name => k.toString -> v
}
fromObject(contents.toMap)
}
def addArrayValue(array: Any, value: Any): Any =
fromArray(array.asInstanceOf[AJson].array.get :+ value)
def setArrayValue(array: Any, index: Int, value: Any): Any =
fromArray(array.asInstanceOf[AJson].array.get.padTo(index, nullValue).patch(index, Seq(value), 1))
def isArray(array: Any): Boolean = array match {
case j: AJson if j.isArray => true
case _ => false
}
def isBoolean(boolean: Any): Boolean = boolean match {
case j: AJson if j.isBool => true
case _ => false
}
def isNumber(num: Any): Boolean = num match {
case j: AJson if j.isNumber => true
case _ => false
}
def isString(string: Any): Boolean = string match {
case j: AJson if j.isString => true
case _ => false
}
def isObject(obj: Any): Boolean = obj match {
case j: AJson if j.isObject => true
case _ => false
}
def isNull(obj: Any): Boolean = obj match {
case j: AJson if j.isNull => true
case _ => false
}
def fromArray(array: Seq[Any]): Any = jArray(array.to[List] map { case v: AJson => v })
def fromBoolean(boolean: Boolean): Any = jBool(boolean)
def fromDouble(number: Double): Any = jNumber(number).get
def fromBigDecimal(number: BigDecimal): Any = jNumber(number.toDouble).get
def fromObject(obj: Map[String, Any]): Any =
AJson(obj.mapValues { case v: AJson => v }.to[List]: _*)
def fromString(string: String): Any = jString(string)
// FIXME: Is there a better way of getting a JNull?
lazy val nullValue: Any = argonaut.Parse.parseOption("null").get
}
================================================
FILE: json-argonaut/shared/src/main/scala/rapture/json-argonaut/extractors.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.argonaut
import rapture.json._
import rapture.data._
import argonaut.{Json => AJson, _}
private[argonaut] trait Extractors {
implicit val argonautJObjectExtractor: JsonCastExtractor[JsonObject] =
JsonCastExtractor(ArgonautAst, DataTypes.Object)
implicit val argonautJValueExtractor: JsonCastExtractor[AJson] = JsonCastExtractor(ArgonautAst, DataTypes.Object)
}
================================================
FILE: json-argonaut/shared/src/main/scala/rapture/json-argonaut/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.argonaut
object `package` extends Extractors with Serializers {
implicit val implicitJsonAst = ArgonautAst
implicit val implicitJsonStringParser = ArgonautParser
}
================================================
FILE: json-argonaut/shared/src/main/scala/rapture/json-argonaut/parse.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.argonaut
import rapture.core._
import rapture.data._
import rapture.json._
import argonaut._
private[argonaut] object ArgonautParser extends Parser[String, JsonBufferAst] {
val ast = ArgonautAst
def parse(s: String): Option[Any] = Parse.parseOption(s)
override def toString = ""
}
================================================
FILE: json-argonaut/shared/src/main/scala/rapture/json-argonaut/serializers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.argonaut
import rapture.json._
import argonaut.{Json => AJson}
private[argonaut] trait Serializers {
implicit val argonautJValueSerializer: DirectJsonSerializer[AJson] = DirectJsonSerializer(ArgonautAst)
}
================================================
FILE: json-circe/shared/src/main/scala/rapture/json-circe/ast.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.circe
import rapture.core._
import rapture.data.DataTypes
import rapture.json._
import io.circe.{Json => CirceJson}
private[circe] object CirceAst extends JsonBufferAst {
override def toString = ""
override def dereferenceObject(obj: Any, element: String): Any = {
def fail(): Nothing = throw TypeMismatchException(getType(obj), DataTypes.Object)
obj match {
case j: CirceJson => j.asObject.getOrElse(fail())(element).get
case _ => fail()
}
}
override def getKeys(obj: Any): Iterator[String] = {
def fail(): Nothing = throw TypeMismatchException(getType(obj), DataTypes.Object)
obj match {
case j: CirceJson => j.asObject.getOrElse(fail()).fields.to[Iterator]
case _ => fail()
}
}
override def dereferenceArray(j: Any, elem: Int): Any = j match {
case j: CirceJson if j.isArray => j.asArray.get(elem)
case _ => throw TypeMismatchException(getType(j), DataTypes.Array)
}
def getArray(j: Any): List[Any] = j match {
case j: CirceJson if j.isArray => j.asArray.get.to[List]
case _ => throw TypeMismatchException(getType(j), DataTypes.Array)
}
def getBoolean(j: Any): Boolean = j match {
case j: CirceJson if j.isBoolean => j.asBoolean.get
case _ => throw TypeMismatchException(getType(j), DataTypes.Boolean)
}
def getDouble(double: Any): Double = double match {
case j: CirceJson if j.isNumber => j.asNumber.get.toDouble
case _ => throw TypeMismatchException(getType(double), DataTypes.Number)
}
def getBigDecimal(bigDecimal: Any): BigDecimal = bigDecimal match {
case j: CirceJson if j.isNumber =>
j.asNumber.get.toBigDecimal.getOrElse(throw TypeMismatchException(getType(bigDecimal), DataTypes.Number))
case _ =>
throw TypeMismatchException(getType(bigDecimal), DataTypes.Number)
}
def getString(string: Any): String = string match {
case j: CirceJson if j.isString => j.asString.get
case _ => throw TypeMismatchException(getType(string), DataTypes.String)
}
def getObject(obj: Any): Map[String, Any] = obj match {
case j: CirceJson if j.isObject => j.asObject.get.toMap.map { case (k, v) => k.toString -> v }
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
def setObjectValue(obj: Any, name: String, value: Any): Any = {
val contents = (name, value) :: obj.asInstanceOf[CirceJson].asObject.get.toList.collect {
case (k, v) if k.toString != name => k.toString -> v
}
fromObject(contents.toMap)
}
def removeObjectValue(obj: Any, name: String): Any = {
val contents = obj.asInstanceOf[CirceJson].asObject.get.toList.collect {
case (k, v) if k.toString != name => k.toString -> v
}
fromObject(contents.toMap)
}
def addArrayValue(array: Any, value: Any): Any =
fromArray(array.asInstanceOf[CirceJson].asArray.get :+ value)
def setArrayValue(array: Any, index: Int, value: Any): Any =
fromArray(array.asInstanceOf[CirceJson].asArray.get.padTo(index, nullValue).patch(index, Seq(value), 1))
def isArray(array: Any): Boolean = array match {
case j: CirceJson if j.isArray => true
case _ => false
}
def isBoolean(boolean: Any): Boolean = boolean match {
case j: CirceJson if j.isBoolean => true
case _ => false
}
def isNumber(num: Any): Boolean = num match {
case j: CirceJson if j.isNumber => true
case _ => false
}
def isString(string: Any): Boolean = string match {
case j: CirceJson if j.isString => true
case _ => false
}
def isObject(obj: Any): Boolean = obj match {
case j: CirceJson if j.isObject => true
case _ => false
}
def isNull(obj: Any): Boolean = obj match {
case j: CirceJson if j.isNull => true
case _ => false
}
def fromArray(array: Seq[Any]): Any = CirceJson.arr(array.to[List].map { case v: CirceJson => v }: _*)
def fromBoolean(boolean: Boolean): Any = CirceJson.fromBoolean(boolean)
def fromDouble(number: Double): Any = CirceJson.fromDouble(number).get
def fromBigDecimal(number: BigDecimal): Any = CirceJson.fromBigDecimal(number)
def fromObject(obj: Map[String, Any]): Any =
CirceJson.obj(obj.mapValues { case v: CirceJson => v }.to[List]: _*)
def fromString(string: String): Any = CirceJson.fromString(string)
// FIXME: Is there a better way of getting a JNull?
lazy val nullValue: Any = CirceJson.Null
}
================================================
FILE: json-circe/shared/src/main/scala/rapture/json-circe/extractors.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.circe
import rapture.json._
import rapture.data._
import io.circe.{Json => CirceJson, _}
private[circe] trait Extractors {
implicit val circeJObjectExtractor: JsonCastExtractor[JsonObject] = JsonCastExtractor(CirceAst, DataTypes.Object)
implicit val circeJValueExtractor: JsonCastExtractor[CirceJson] = JsonCastExtractor(CirceAst, DataTypes.Object)
}
================================================
FILE: json-circe/shared/src/main/scala/rapture/json-circe/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.circe
object `package` extends Extractors with Serializers {
implicit val implicitJsonAst = CirceAst
implicit val implicitJsonStringParser = CirceParser
}
================================================
FILE: json-circe/shared/src/main/scala/rapture/json-circe/parse.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.circe
import rapture.core._
import rapture.data._
import rapture.json._
import io.circe.jawn._
private[circe] object CirceParser extends Parser[String, JsonBufferAst] {
val ast = CirceAst
def parse(s: String): Option[Any] = CirceSupportParser.parseFromString(s).toOption
override def toString = ""
}
================================================
FILE: json-circe/shared/src/main/scala/rapture/json-circe/serializers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.circe
import rapture.json._
import io.circe.{Json => CirceJson}
private[circe] trait Serializers {
implicit val circeJValueSerializer: DirectJsonSerializer[CirceJson] = DirectJsonSerializer(CirceAst)
}
================================================
FILE: json-jackson/shared/src/main/scala/rapture/json-jackson/ast.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.jackson
import rapture.core._
import rapture.json._
import rapture.data.DataTypes
import com.fasterxml.jackson.databind._
import com.fasterxml.jackson.databind.node.NullNode
import scala.collection.JavaConverters._
/** A type class for Jackson parsing */
private[jackson] object JacksonAst extends JsonAst {
override def toString = ""
private val mapper = new ObjectMapper()
.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
.enable(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS)
def getArray(array: Any): List[Any] = array match {
case list: JsonNode if list.isArray => asScalaIteratorConverter(list.elements).asScala.to[List]
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def getBoolean(boolean: Any): Boolean = boolean match {
case boolean: JsonNode if boolean.isBoolean => boolean.asBoolean
case _ => throw TypeMismatchException(getType(boolean), DataTypes.Boolean)
}
def getDouble(number: Any): Double = number match {
case number: JsonNode if number.isBigDecimal => number.decimalValue.doubleValue
case number: JsonNode if number.isBigInteger => number.bigIntegerValue.doubleValue
case number: JsonNode if number.isNumber => number.asDouble
case number: Double => number
case _ => throw TypeMismatchException(getType(number), DataTypes.Number)
}
def getBigDecimal(number: Any): BigDecimal = number match {
case number: JsonNode if number.isBigDecimal => BigDecimal(number.decimalValue)
case number: JsonNode if number.isBigInteger => BigDecimal(number.bigIntegerValue)
case number: JsonNode if number.isNumber => number.asDouble
case number: Double => BigDecimal(number)
case _ => throw TypeMismatchException(getType(number), DataTypes.Number)
}
def getString(string: Any): String = string match {
case string: JsonNode if string.isTextual => string.asText
case string: String => string
case _ => throw TypeMismatchException(getType(string), DataTypes.String)
}
def getObject(obj: Any): Map[String, Any] = obj match {
case obj: JsonNode if obj.isObject =>
(asScalaIteratorConverter(obj.fieldNames).asScala map { case k => k -> Option(obj.get(k)).get }).toMap
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def dereferenceObject(obj: Any, element: String): Any = obj match {
case obj: JsonNode if obj.isObject => Option(obj.get(element)).get
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def getKeys(obj: Any): Iterator[String] = obj match {
case obj: JsonNode if obj.isObject => asScalaIteratorConverter(obj.fieldNames).asScala
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def dereferenceArray(array: Any, element: Int): Any = array match {
case array: JsonNode if array.isArray => array.get(element)
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def setObjectValue(obj: JsonNode, name: String, value: JsonNode): Unit = obj match {
case obj: node.ObjectNode => obj.set(name, value)
}
def removeObjectValue(obj: JsonNode, name: String): Unit = obj match {
case obj: node.ObjectNode => obj.remove(name)
}
def addArrayValue(array: JsonNode, value: JsonNode): Unit = array match {
case array: node.ArrayNode => array.add(value)
}
def setArrayValue(array: JsonNode, index: Int, value: JsonNode): Unit = ???
def nullValue = NullNode.instance
def fromArray(array: Seq[Any]): Any = {
val newArray = mapper.createArrayNode
for (v <- array) v match {
case v: Boolean => newArray.add(v)
case v: String => newArray.add(v)
case v: Double => newArray.add(v)
case v: JsonNode => newArray.add(v)
}
newArray
}
def fromBoolean(boolean: Boolean): Any = boolean
def fromDouble(number: Double): Any = number
def fromBigDecimal(number: BigDecimal): Any = number.toDouble
def fromObject(obj: Map[String, Any]): Any = {
val newObject = mapper.createObjectNode
for ((k, v) <- obj) v match {
case v: Boolean => newObject.put(k, v)
case v: String => newObject.put(k, v)
case v: Double => newObject.put(k, v)
case v: JsonNode => newObject.set(k, v)
case null => newObject.putNull(k)
}
newObject
}
def fromString(string: String): Any = string
def isBoolean(any: Any): Boolean = any match {
case x: JsonNode if x.isBoolean => true
case _ => false
}
def isString(any: Any): Boolean = any match {
case x: JsonNode if x.isTextual => true
case x: String => true
case _ => false
}
def isNumber(any: Any): Boolean = any match {
case x: JsonNode if x.isNumber => true
case x: Double => true
case _ => false
}
def isObject(any: Any): Boolean = any match {
case x: JsonNode if x.isObject => true
case _ => false
}
def isArray(any: Any): Boolean = any match {
case x: JsonNode if x.isArray => true
case _ => false
}
def isNull(any: Any): Boolean = any match {
case x: JsonNode if x.isNull => true
case _ => false
}
}
================================================
FILE: json-jackson/shared/src/main/scala/rapture/json-jackson/extractors.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.jackson
import rapture.json._
import rapture.data._
import com.fasterxml.jackson.databind._
private[jackson] trait Extractors {
implicit val jacksonJsonNodeExtractor: JsonCastExtractor[JsonNode] = JsonCastExtractor(JacksonAst, DataTypes.Any)
}
================================================
FILE: json-jackson/shared/src/main/scala/rapture/json-jackson/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.jackson
import rapture.json._
import rapture.data._
object `package` extends Extractors with Serializers {
implicit val implicitJsonAst: JsonAst = JacksonAst
implicit val implicitJsonStringParser: Parser[String, JsonAst] = JacksonParser
}
================================================
FILE: json-jackson/shared/src/main/scala/rapture/json-jackson/parse.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.jackson
import rapture.core._
import rapture.json._
import rapture.data._
import com.fasterxml.jackson.databind._
private[jackson] object JacksonParser extends Parser[String, JsonAst] {
val ast = JacksonAst
override def toString = ""
private val mapper = new ObjectMapper()
.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
.enable(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS)
def parse(s: String): Option[Any] =
Some(mapper.readTree(s))
}
================================================
FILE: json-jackson/shared/src/main/scala/rapture/json-jackson/serializers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.jackson
import rapture.json._
private[jackson] trait Serializers {
import com.fasterxml.jackson.databind._
implicit val jacksonJsonNodeSerializer: DirectJsonSerializer[JsonNode] = DirectJsonSerializer(JacksonAst)
}
================================================
FILE: json-jawn/shared/src/main/scala/rapture/json-jawn/ast.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.jawn
import rapture.core._
import rapture.json._
import rapture.data.DataTypes
import rapture.data.TypeMismatchException
import rapture.data.MissingValueException
import jawn.ast._
private[jawn] object JawnAst extends JsonBufferAst {
override def dereferenceObject(obj: Any, element: String): Any =
obj match {
case JObject(obj) =>
try obj(element)
catch {
case e: Exception => throw MissingValueException()
}
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def getKeys(obj: Any): Iterator[String] =
obj match {
case JObject(obj) => obj.keys.iterator
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def dereferenceArray(array: Any, element: Int): Any =
array match {
case JArray(arr) => arr(element)
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def getArray(array: Any): List[Any] = array match {
case JArray(xs) => xs.toList
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def getBoolean(boolean: Any): Boolean = boolean match {
case boolean: Boolean => boolean
case JTrue => true
case JFalse => false
case _ => throw TypeMismatchException(getType(boolean), DataTypes.Boolean)
}
def getBigDecimal(bigDecimal: Any): BigDecimal = bigDecimal match {
case DoubleNum(d) => BigDecimal(d)
case DeferLong(v) => BigDecimal(v)
case DeferNum(v) => BigDecimal(v)
case _ => throw TypeMismatchException(getType(bigDecimal), DataTypes.Number)
}
def getDouble(double: Any): Double = double match {
case DoubleNum(d) => d
case DeferLong(v) => v.toDouble
case DeferNum(v) => java.lang.Double.valueOf(v)
case _ => throw TypeMismatchException(getType(double), DataTypes.Number)
}
def getString(string: Any): String = string match {
case JString(s) => s
case _ => throw TypeMismatchException(getType(string), DataTypes.String)
}
def getObject(obj: Any): Map[String, Any] = obj match {
case JObject(o) => o.toMap
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
def setObjectValue(obj: Any, name: String, value: Any): Any = {
obj.asInstanceOf[JObject].vs(name) = value.asInstanceOf[JValue]
obj
}
def removeObjectValue(obj: Any, name: String): Any = {
obj.asInstanceOf[JObject].vs -= name
obj
}
def addArrayValue(array: Any, value: Any): Any =
JArray(array.asInstanceOf[JArray].vs :+ value.asInstanceOf[JValue])
def setArrayValue(array: Any, index: Int, value: Any): Any =
JArray(array.asInstanceOf[JArray].vs.padTo(index, null).patch(index, Seq(value.asInstanceOf[JValue]), 1))
def isArray(array: Any): Boolean = array match {
case JArray(xs) => true
case _ => false
}
def isBoolean(boolean: Any): Boolean = boolean match {
case JTrue | JFalse => true
case _ => false
}
def isNumber(num: Any): Boolean = num match {
case DoubleNum(_) | DeferLong(_) | DeferNum(_) => true
case _ => false
}
def isString(string: Any): Boolean = string match {
case JString(_) => true
case _ => false
}
def isObject(obj: Any): Boolean = obj match {
case JObject(_) => true
case _ => false
}
def isNull(obj: Any): Boolean = obj match {
case JNull => true
case _ => false
}
def fromArray(array: Seq[Any]): Any = JArray(array.to[Array] map { case v: JValue => v })
def fromBoolean(boolean: Boolean): Any = if (boolean) JTrue else JFalse
def fromDouble(number: Double): Any = DoubleNum(number)
def fromBigDecimal(number: BigDecimal): Any = DeferNum(number.toString)
def fromObject(obj: Map[String, Any]): Any =
JObject(collection.mutable.Map(obj.mapValues { case v: JValue => v }.to[Seq]: _*))
def fromString(string: String): Any = JString(string)
val nullValue = JNull
override def toString = ""
}
================================================
FILE: json-jawn/shared/src/main/scala/rapture/json-jawn/extractors.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.jawn
import rapture.data._
import rapture.json._
import _root_.jawn.ast._
private[jawn] trait Extractors {
implicit val jawnJObjectExtractor: JsonCastExtractor[JObject] = JsonCastExtractor(JawnAst, DataTypes.Object)
implicit val jawnJArrayExtractor: JsonCastExtractor[JArray] = JsonCastExtractor(JawnAst, DataTypes.Array)
implicit val jawnDeferNumExtractor: JsonCastExtractor[DeferNum] = JsonCastExtractor(JawnAst, DataTypes.Number)
implicit val jawnDoubleNumExtractor: JsonCastExtractor[DoubleNum] = JsonCastExtractor(JawnAst, DataTypes.Number)
implicit val jawnLongNumExtractor: JsonCastExtractor[LongNum] = JsonCastExtractor(JawnAst, DataTypes.Number)
implicit val jawnJNumExtractor: JsonCastExtractor[JNum] = JsonCastExtractor(JawnAst, DataTypes.Number)
implicit val jawnStringExtractor: JsonCastExtractor[JString] = JsonCastExtractor(JawnAst, DataTypes.String)
implicit val jawnAtomExtractor: JsonCastExtractor[JAtom] = JsonCastExtractor(JawnAst, DataTypes.Scalar)
implicit val jawnValueExtractor: JsonCastExtractor[JValue] = JsonCastExtractor(JawnAst, DataTypes.Any)
}
================================================
FILE: json-jawn/shared/src/main/scala/rapture/json-jawn/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.jawn
import rapture.core._
import rapture.data._
import rapture.json._
import _root_.jawn.{Parser => _, _}
import _root_.jawn.ast._
private[jawn] trait package_1 {
implicit val jawnFacade: Facade[JValue] = JawnFacade
}
object `package` extends package_1 with Extractors with Serializers {
implicit val implicitJsonAst: JsonBufferAst = JawnAst
implicit def implicitJsonStringParser(implicit f: Facade[_]): Parser[String, JsonBufferAst] =
new JawnStringParser
implicit def implicitJsonByteBufferParser(implicit f: Facade[_]): Parser[java.nio.ByteBuffer, JsonBufferAst] =
new JawnByteBufferParser
implicit def implicitJsonFileParser(implicit f: Facade[_]): Parser[java.io.File, JsonBufferAst] = new JawnFileParser
implicit def jsonFormatterImplicit[Ast <: JsonAst](implicit ast: Ast): Formatter[Ast] {
type Out = String
} = new Formatter[Ast] {
type Out = String
def format(json: Any): String = json match {
case jv: JValue => jv.render(FastRenderer)
case _ => ???
}
}
}
================================================
FILE: json-jawn/shared/src/main/scala/rapture/json-jawn/parse.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.jawn
import rapture.core._
import rapture.data._
import rapture.json._
import jawn.{Parser => JawnParser, _}
private[jawn] class JawnStringParser(implicit f: Facade[_]) extends Parser[String, JsonBufferAst] {
override def toString = ""
val ast = JawnAst
def parse(s: String): Option[Any] = JawnParser.parseFromString(s).toOption
}
private[jawn] class JawnByteBufferParser(implicit f: Facade[_]) extends Parser[java.nio.ByteBuffer, JsonBufferAst] {
override def toString = ""
val ast = JawnAst
def parse(buf: java.nio.ByteBuffer): Option[Any] =
JawnParser.parseFromByteBuffer(buf).toOption
}
private[jawn] class JawnFileParser(implicit f: Facade[_]) extends Parser[java.io.File, JsonBufferAst] {
override def toString = ""
val ast = JawnAst
def parse(file: java.io.File): Option[Any] = JawnParser.parseFromFile(file).toOption
}
================================================
FILE: json-jawn/shared/src/main/scala/rapture/json-jawn/serializers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.jawn
import rapture.json._
import _root_.jawn.ast._
private[jawn] trait Serializers {
implicit val jawnJValueSerializer: DirectJsonSerializer[JValue] = DirectJsonSerializer(JawnAst)
}
================================================
FILE: json-json4s/shared/src/main/scala/rapture/json-json4s/ast.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.json4s
import org.json4s._
import rapture.data.DataTypes
import rapture.json._
private[json4s] object Json4sAst extends JsonBufferAst {
import JsonAST._
override def toString = ""
def getArray(array: Any): List[Any] = array match {
case JArray(xs) => xs.toList
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def fromArray(array: Seq[Any]): Any = JArray(array.to[List] map { case v: JValue => v })
def getBoolean(boolean: Any): Boolean = boolean match {
case boolean: Boolean => boolean
case JBool(v) => v
case _ => throw TypeMismatchException(getType(boolean), DataTypes.Boolean)
}
def fromBoolean(boolean: Boolean): Any = JBool(boolean)
def getDouble(double: Any): Double = double match {
case JDouble(d) => d
case JInt(v) => v.toDouble
case JDecimal(v) => v.toDouble
case _ => throw TypeMismatchException(getType(double), DataTypes.Number)
}
def getBigDecimal(bigDecimal: Any): BigDecimal = bigDecimal match {
case JDecimal(v) => v
case JDouble(d) => BigDecimal(d)
case JInt(v) => BigDecimal(v)
case _ => throw TypeMismatchException(getType(bigDecimal), DataTypes.Number)
}
def fromDouble(number: Double): Any = JDouble(number)
def fromBigDecimal(number: BigDecimal): Any = JDecimal(number)
def getString(string: Any): String = string match {
case JString(s) => s
case _ => throw TypeMismatchException(getType(string), DataTypes.String)
}
def fromString(string: String): Any = JString(string)
def getObject(obj: Any): Map[String, Any] = obj match {
case JObject(o) => o.toMap
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
def fromObject(obj: Map[String, Any]): Any =
JObject(obj.mapValues { case v: JValue => v }.to[List])
def setObjectValue(obj: Any, name: String, value: Any): Any = {
val contents = (name, value) :: obj.asInstanceOf[JObject].obj.filter(_._1 != name)
JObject(contents map {
case (k: String, v: JValue) => k -> v
case _ => ???
})
}
def removeObjectValue(obj: Any, name: String): Any =
JObject(obj.asInstanceOf[JObject].obj.filter(_._1 == name))
def addArrayValue(array: Any, value: Any): Any =
JArray(array.asInstanceOf[JArray].arr :+ value.asInstanceOf[JValue])
def setArrayValue(array: Any, index: Int, value: Any): Any = array match {
case array: JArray =>
JArray(array.arr.padTo(index, JNull).patch(index, Seq(value.asInstanceOf[JValue]), 1))
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def isBoolean(boolean: Any): Boolean = boolean match {
case JBool(_) => true
case _ => false
}
def isString(string: Any): Boolean = string match {
case JString(_) => true
case _ => false
}
def isNumber(num: Any): Boolean = num match {
case JDecimal(_) | JInt(_) | JDouble(_) => true
case _ => false
}
def isObject(obj: Any): Boolean = obj match {
case JObject(_) => true
case _ => false
}
def isArray(array: Any): Boolean = array match {
case JArray(xs) => true
case _ => false
}
def isNull(obj: Any): Boolean = obj match {
case JNull => true
case _ => false
}
def nullValue: Any = JNull
override def dereferenceObject(obj: Any, element: String): Any =
obj match {
case obj: JObject =>
val result = obj \ element
if(result == JNothing) throw MissingValueException()
else result
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def getKeys(obj: Any): Iterator[String] =
obj match {
case JObject(obj) => obj.map(_._1).iterator
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def dereferenceArray(array: Any, element: Int): Any =
array match {
case JArray(arr) =>
val result = arr(element)
if(result == JNothing) throw MissingValueException()
else result
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
}
================================================
FILE: json-json4s/shared/src/main/scala/rapture/json-json4s/extractors.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.json4s
import rapture.json._
import rapture.data._
import org.json4s._
private[json4s] trait Extractors {
implicit val json4sJValueExtractor: JsonCastExtractor[JValue] = JsonCastExtractor(Json4sAst, DataTypes.Any)
implicit val json4sJDecimalExtractor: JsonCastExtractor[JDecimal] = JsonCastExtractor(Json4sAst, DataTypes.Number)
implicit val json4sJDoubleExtractor: JsonCastExtractor[JDouble] = JsonCastExtractor(Json4sAst, DataTypes.Number)
implicit val json4sJStringExtractor: JsonCastExtractor[JString] = JsonCastExtractor(Json4sAst, DataTypes.String)
implicit val json4sJIntExtractor: JsonCastExtractor[JInt] = JsonCastExtractor(Json4sAst, DataTypes.Number)
implicit val json4sJArrayExtractor: JsonCastExtractor[JArray] = JsonCastExtractor(Json4sAst, DataTypes.Array)
implicit val json4sJObjectExtractor: JsonCastExtractor[JObject] = JsonCastExtractor(Json4sAst, DataTypes.Object)
}
================================================
FILE: json-json4s/shared/src/main/scala/rapture/json-json4s/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.json4s
object `package` extends Extractors with Serializers {
implicit val implicitJsonAst = Json4sAst
implicit val implicitJsonStringParser = Json4sParser
}
================================================
FILE: json-json4s/shared/src/main/scala/rapture/json-json4s/parse.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.json4s
import rapture.data._
import rapture.json._
import org.json4s._
private[json4s] object Json4sParser extends Parser[String, JsonBufferAst] {
val ast = Json4sAst
def parse(s: String): Option[Any] =
try Some(native.JsonParser.parse(s"""{"x":$s}""", useBigDecimalForDouble = true) \ "x")
catch {
case e: Exception => None
}
override def toString = ""
}
================================================
FILE: json-json4s/shared/src/main/scala/rapture/json-json4s/serializers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.json4s
import rapture.json._
import org.json4s._
private[json4s] trait Serializers {
implicit val json4sJValueSerializer: DirectJsonSerializer[JValue] = DirectJsonSerializer(Json4sAst)
}
================================================
FILE: json-lift/shared/src/main/scala/rapture/json-lift/ast.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.lift
import rapture.core._
import rapture.json._
import rapture.data.DataTypes
import net.liftweb.json._
private[lift] object LiftAst extends JsonBufferAst {
import JsonAST._
override def toString = ""
override def dereferenceObject(obj: Any, element: String): Any =
obj match {
case JObject(obj) => obj.find(_.name == element).get.value
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def getKeys(obj: Any): Iterator[String] =
obj match {
case JObject(obj) => obj.map(_.name).iterator
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def dereferenceArray(array: Any, element: Int): Any =
array match {
case JArray(arr) => arr(element)
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def getArray(array: Any): List[Any] = array match {
case JArray(xs) => xs.toList
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def getBoolean(boolean: Any): Boolean = boolean match {
case boolean: Boolean => boolean
case JBool(v) => v
case _ => throw TypeMismatchException(getType(boolean), DataTypes.Boolean)
}
def getBigDecimal(bigDecimal: Any): BigDecimal = bigDecimal match {
case JDouble(d) => BigDecimal(d)
case JInt(v) => BigDecimal(v)
case _ => throw TypeMismatchException(getType(bigDecimal), DataTypes.Number)
}
def getDouble(double: Any): Double = double match {
case JDouble(d) => d
case JInt(v) => v.toDouble
case _ => throw TypeMismatchException(getType(double), DataTypes.Number)
}
def getString(string: Any): String = string match {
case JString(s) => s
case _ => throw TypeMismatchException(getType(string), DataTypes.String)
}
def getObject(obj: Any): Map[String, Any] = obj match {
case JObject(o) =>
o.map { f =>
f.name -> f.value
}.toMap
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
def setObjectValue(obj: Any, name: String, value: Any): Any = {
val contents = (name, value) :: obj.asInstanceOf[JObject].obj.filter(_.name != name)
JObject(contents map {
case JField(k: String, v: JValue) => JField(k, v)
case (k: String, v: JValue) => JField(k, v)
})
}
def removeObjectValue(obj: Any, name: String): Any =
JObject(obj.asInstanceOf[JObject].obj.filter(_.name == name))
def addArrayValue(array: Any, value: Any): Any =
JArray(array.asInstanceOf[JArray].arr :+ value.asInstanceOf[JValue])
def setArrayValue(array: Any, index: Int, value: Any): Any = array match {
case array: JArray =>
JArray(array.arr.padTo(index, JNull).patch(index, Seq(value.asInstanceOf[JValue]), 1))
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def isArray(array: Any): Boolean = array match {
case JArray(xs) => true
case _ => false
}
def isBoolean(boolean: Any): Boolean = boolean match {
case JBool(_) => true
case _ => false
}
def isNumber(num: Any): Boolean = num match {
case JInt(_) | JDouble(_) => true
case _ => false
}
def isString(string: Any): Boolean = string match {
case JString(_) => true
case _ => false
}
def isObject(obj: Any): Boolean = obj match {
case JObject(_) => true
case _ => false
}
def isNull(obj: Any): Boolean = obj match {
case JNull => true
case _ => false
}
def nullValue: Any = JNull
def fromArray(array: Seq[Any]): Any = JArray(array.to[List] map { case v: JValue => v })
def fromBoolean(boolean: Boolean): Any = JBool(boolean)
def fromDouble(number: Double): Any = JDouble(number)
def fromBigDecimal(number: BigDecimal): Any = JDouble(number.toDouble)
def fromObject(obj: Map[String, Any]): Any =
JObject(obj.map {
case (k, v: JValue) => JField(k, v)
case _ => ???
}.to[List])
def fromString(string: String): Any = JString(string)
}
================================================
FILE: json-lift/shared/src/main/scala/rapture/json-lift/extractors.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.lift
import rapture.json._
import rapture.data._
import net.liftweb.json._
import JsonAST._
private[lift] trait Extractors {
implicit val liftJValueExtractor: JsonCastExtractor[JValue] = JsonCastExtractor(LiftAst, DataTypes.Any)
implicit val liftJStringExtractor: JsonCastExtractor[JString] = JsonCastExtractor(LiftAst, DataTypes.String)
implicit val liftJIntExtractor: JsonCastExtractor[JInt] = JsonCastExtractor(LiftAst, DataTypes.Number)
implicit val liftJDoubleExtractor: JsonCastExtractor[JDouble] = JsonCastExtractor(LiftAst, DataTypes.Number)
implicit val liftJArrayExtractor: JsonCastExtractor[JArray] = JsonCastExtractor(LiftAst, DataTypes.Array)
implicit val liftJObjectExtractor: JsonCastExtractor[JObject] = JsonCastExtractor(LiftAst, DataTypes.Object)
}
================================================
FILE: json-lift/shared/src/main/scala/rapture/json-lift/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.lift
object `package` extends Serializers with Extractors {
implicit val implicitJsonAst = LiftAst
implicit val implicitJsonStringParser = LiftParser
}
================================================
FILE: json-lift/shared/src/main/scala/rapture/json-lift/parse.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.lift
import rapture.core._
import rapture.json._
import rapture.data._
import net.liftweb.json._
private[lift] object LiftParser extends Parser[String, JsonBufferAst] {
val ast = LiftAst
def parse(s: String): Option[Any] =
try Some(JsonParser.parse(s))
catch { case e: Exception => None }
override def toString = ""
}
================================================
FILE: json-lift/shared/src/main/scala/rapture/json-lift/serializers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.lift
import rapture.json._
import net.liftweb.json._
import JsonAST._
private[lift] trait Serializers {
implicit val liftJValueSerializer: DirectJsonSerializer[JValue] = DirectJsonSerializer(LiftAst)
}
================================================
FILE: json-play/shared/src/main/scala/rapture/json-play/ast.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.play
import rapture.core._
import rapture.json._
import rapture.data.DataTypes
import play.api.libs.json.{Json => PJson, _}
private[play] object PlayAst extends JsonBufferAst {
override def toString = ""
override def dereferenceObject(obj: Any, element: String): Any = obj match {
case obj @ JsObject(_) =>
obj \ element match {
case JsDefined(v) => v
case _ => throw MissingValueException()
}
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def getKeys(obj: Any): Iterator[String] =
obj match {
case obj: JsObject => obj.keys.iterator
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def dereferenceArray(array: Any, element: Int): Any =
array match {
case arr @ JsArray(_) =>
arr(element) match {
case JsDefined(v) => v
case _ => throw MissingValueException()
}
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def getArray(array: Any): List[Any] = array match {
case JsArray(arr) => arr.to[List]
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def getBoolean(boolean: Any): Boolean = boolean match {
case JsBoolean(v) => v
case _ => throw TypeMismatchException(getType(boolean), DataTypes.Boolean)
}
def getBigDecimal(bigDecimal: Any): BigDecimal = bigDecimal match {
case JsNumber(n) => n
case _ => throw TypeMismatchException(getType(bigDecimal), DataTypes.Number)
}
def getDouble(double: Any): Double = double match {
case JsNumber(n) => n.toDouble
case _ => throw TypeMismatchException(getType(double), DataTypes.Number)
}
def getString(string: Any): String = string match {
case JsString(s) => s
case _ => throw TypeMismatchException(getType(string), DataTypes.String)
}
def getObject(obj: Any): Map[String, Any] = obj match {
case JsObject(obj) => obj.toMap
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
def setObjectValue(obj: Any, name: String, value: Any): Any =
(value, obj) match {
case (value: JsValue, obj: JsValue) => PJson.toJson(obj.as[Map[String, JsValue]].updated(name, value))
case (_, _) => ??? // should never get there?
}
def removeObjectValue(obj: Any, name: String): Any = obj match {
case obj: JsObject => PJson.toJson(obj.as[Map[String, JsValue]] - name)
}
def addArrayValue(array: Any, value: Any): Any = array match {
case v: JsValue => PJson.toJson(v.as[Array[JsValue]] :+ value.asInstanceOf[JsValue])
}
def setArrayValue(array: Any, index: Int, value: Any): Any = array match {
case v: JsValue =>
val array = v.as[Array[JsValue]]
PJson.toJson(array.padTo(index, JsNull: JsValue).patch(index, Seq(value.asInstanceOf[JsValue]), 1))
}
def isArray(array: Any): Boolean =
try {
array match {
case JsArray(_) => true
case _ => false
}
} catch { case e: Exception => false }
def isBoolean(boolean: Any): Boolean =
try {
boolean match {
case JsBoolean(boolean) => true
case _ => false
}
} catch { case e: Exception => false }
def isNumber(num: Any): Boolean =
try {
num match {
case JsNumber(_) => true
case _ => false
}
} catch { case e: Exception => false }
def isString(string: Any): Boolean =
try {
string match {
case JsString(s) => true
case _ => false
//case JsDefined(string) => string.asOpt[String].isDefined
}
} catch { case e: Exception => false }
def isObject(obj: Any): Boolean =
try {
obj match {
case JsObject(obj) => true
case _ => false
}
} catch { case e: Exception => false }
def isNull(obj: Any): Boolean = obj match {
case JsNull => true
case _ => false
}
val nullValue: Any = JsNull
def fromArray(array: Seq[Any]): Any = PJson.toJson(array.map(_.asInstanceOf[JsValue]))
def fromBoolean(boolean: Boolean): Any = PJson.toJson(boolean)
def fromDouble(number: Double): Any = PJson.toJson(number)
def fromBigDecimal(number: BigDecimal): Any = PJson.toJson(number)
def fromObject(obj: Map[String, Any]): Any =
PJson.toJson(obj.map {
case (k, v: JsValue) => (k, v)
case _ => ???
})
def fromString(string: String): Any = PJson.toJson(string)
}
================================================
FILE: json-play/shared/src/main/scala/rapture/json-play/extraction.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.play
import rapture.json._
import rapture.data._
import play.api.libs.json._
private[play] trait Extractors {
implicit val playJsValueExtractor: JsonCastExtractor[JsValue] = JsonCastExtractor(PlayAst, DataTypes.Any)
implicit val playJsObjectExtractor: JsonCastExtractor[JsObject] = JsonCastExtractor(PlayAst, DataTypes.Object)
implicit val playJsArrayExtractor: JsonCastExtractor[JsArray] = JsonCastExtractor(PlayAst, DataTypes.Array)
}
================================================
FILE: json-play/shared/src/main/scala/rapture/json-play/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.play
object `package` extends Extractors with Serializers {
implicit val implicitJsonAst = PlayAst
implicit val implicitJsonStringParser = PlayParser
}
================================================
FILE: json-play/shared/src/main/scala/rapture/json-play/parse.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.play
import rapture.core._
import rapture.json._
import rapture.data._
import play.api.libs.json.{Json => PJson}
private[play] object PlayParser extends Parser[String, JsonBufferAst] {
val ast = PlayAst
def parse(s: String): Option[Any] =
try Some(PJson.parse(s))
catch { case e: Exception => None }
override def toString = ""
}
================================================
FILE: json-play/shared/src/main/scala/rapture/json-play/serializers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.play
import rapture.json._
import play.api.libs.json._
private[play] trait Serializers {
implicit val playJsValueSerializer: DirectJsonSerializer[JsValue] = DirectJsonSerializer(PlayAst)
implicit val playJsObjectSerializer: DirectJsonSerializer[JsObject] = DirectJsonSerializer(PlayAst)
}
================================================
FILE: json-spray/shared/src/main/scala/rapture/json-spray/ast.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.spray
import rapture.core._
import rapture.json._
import rapture.data.DataTypes
import spray.json._
import DefaultJsonProtocol._
private[spray] object SprayAst extends JsonBufferAst {
override def toString = ""
override def dereferenceObject(obj: Any, element: String): Any =
obj match {
case obj: JsObject =>
try obj.getFields(element).head
catch {
case e: IndexOutOfBoundsException => throw MissingValueException()
}
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def getKeys(obj: Any): Iterator[String] =
obj match {
case obj: JsObject => obj.fields.keysIterator
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
override def dereferenceArray(array: Any, element: Int): Any =
array match {
case v: JsValue =>
val arr = v.convertTo[Array[JsValue]]
arr(element)
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def getArray(array: Any): List[Any] = array match {
case v: JsValue =>
try v.convertTo[List[JsValue]]
catch {
case e: Exception => throw TypeMismatchException(getType(array), DataTypes.Array)
}
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def getBoolean(boolean: Any): Boolean = boolean match {
case v: JsValue =>
try v.convertTo[Boolean]
catch {
case e: Exception => throw TypeMismatchException(getType(boolean), DataTypes.Boolean)
}
case _ => throw TypeMismatchException(getType(boolean), DataTypes.Boolean)
}
def getBigDecimal(bigDecimal: Any): BigDecimal = bigDecimal match {
case v: JsValue =>
try v.convertTo[BigDecimal]
catch {
case e: Exception => throw TypeMismatchException(getType(bigDecimal), DataTypes.Number)
}
case _ => throw TypeMismatchException(getType(bigDecimal), DataTypes.Number)
}
def getDouble(double: Any): Double = double match {
case v: JsValue =>
try v.convertTo[Double]
catch {
case e: Exception => throw TypeMismatchException(getType(double), DataTypes.Number)
}
case _ => throw TypeMismatchException(getType(double), DataTypes.Number)
}
def getString(string: Any): String = string match {
case v: JsValue =>
try v.convertTo[String]
catch {
case e: Exception => throw TypeMismatchException(getType(string), DataTypes.String)
}
case _ => throw TypeMismatchException(getType(string), DataTypes.String)
}
def getObject(obj: Any): Map[String, Any] = obj match {
case v: JsObject => v.fields
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
def setObjectValue(obj: Any, name: String, value: Any): Any =
(value, obj) match {
case (value: JsValue, obj: JsValue) => obj.asJsObject.fields.updated(name, value).toJson
case _ => ???
}
def removeObjectValue(obj: Any, name: String): Any = obj match {
case obj: JsObject => (obj.fields - name).toJson
}
def addArrayValue(array: Any, value: Any): Any = array match {
case v: JsValue => (v.convertTo[Array[JsValue]] :+ value.asInstanceOf[JsValue]).toJson
}
def setArrayValue(array: Any, index: Int, value: Any): Any = array match {
case v: JsValue =>
val array = v.convertTo[Array[JsValue]]
array.padTo(index, JsNull: JsValue).patch(index, Seq(value.asInstanceOf[JsValue]), 1).toJson
}
def isArray(array: Any): Boolean =
try {
array match {
case array: JsValue =>
array.convertTo[Array[JsValue]]
true
case _ => false
}
} catch {
case e: DeserializationException => false
}
def isBoolean(boolean: Any): Boolean =
try {
boolean match {
case boolean: JsValue =>
boolean.convertTo[Boolean]
true
case _ => false
}
} catch {
case e: ClassCastException => false
case e: DeserializationException => false
}
def isNumber(num: Any): Boolean =
try {
num match {
case JsNull => false
case num: JsValue =>
num.convertTo[Double]
true
case _ => false
}
} catch {
case e: ClassCastException => false
case e: DeserializationException => false
}
def isString(string: Any): Boolean =
try {
string match {
case string: JsValue =>
string.convertTo[String]
true
case _ => false
}
} catch {
case e: ClassCastException => false
case e: DeserializationException => false
}
def isObject(obj: Any): Boolean = obj match {
case obj: JsObject => true
case _ => false
}
def isNull(obj: Any): Boolean = obj match {
case JsNull => true
case _ => false
}
def nullValue: Any = JsNull
def fromArray(array: Seq[Any]): Any = array.map(_.asInstanceOf[JsValue]).toJson
def fromBoolean(boolean: Boolean): Any = boolean.toJson
def fromDouble(number: Double): Any = number.toJson
def fromBigDecimal(number: BigDecimal): Any = number.toJson
def fromObject(obj: Map[String, Any]): Any =
obj.map {
case (k, v: JsValue) => (k, v)
case _ => ???
}.toJson
def fromString(string: String): Any = string.toJson
}
================================================
FILE: json-spray/shared/src/main/scala/rapture/json-spray/extraction.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.spray
import rapture.json._
import rapture.data._
import spray.json._
private[spray] trait Extractors {
implicit val sprayJsValueExtractor: JsonCastExtractor[JsValue] = JsonCastExtractor(SprayAst, DataTypes.Any)
implicit val sprayJsObjectExtractor: JsonCastExtractor[JsObject] = JsonCastExtractor(SprayAst, DataTypes.Object)
}
================================================
FILE: json-spray/shared/src/main/scala/rapture/json-spray/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.spray
object `package` extends Extractors with Serializers {
implicit val implicitJsonAst = SprayAst
implicit val implicitJsonStringParser = SprayParser
}
================================================
FILE: json-spray/shared/src/main/scala/rapture/json-spray/parse.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.spray
import rapture.core._
import rapture.json._
import rapture.data._
import spray.json._
private[spray] object SprayParser extends Parser[String, JsonBufferAst] {
val ast = SprayAst
def parse(s: String): Option[Any] =
try Some(s.parseJson)
catch { case e: Exception => None }
override def toString = ""
}
================================================
FILE: json-spray/shared/src/main/scala/rapture/json-spray/serializers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.jsonBackends.spray
import rapture.json._
import spray.json._
private[spray] trait Serializers {
implicit val sprayJsValueSerializer: DirectJsonSerializer[JsValue] = DirectJsonSerializer(SprayAst)
implicit val sprayJsObjectSerializer: DirectJsonSerializer[JsObject] = DirectJsonSerializer(SprayAst)
}
================================================
FILE: json-test/shared/src/test/scala/rapture/json-test/java8TimeTests.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.test
import java.time._
import rapture.core.ParseException
import rapture.data.Parser
import rapture.json.jsonBackends._
import rapture.json.{JsonAst, _}
import rapture.test.{Programme, TestSuite}
import rapture.core.java8.time._
import dictionaries.dynamic._
class JsonJava8TimeApiTestRun extends Programme {
include(PlayTests)
include(JawnTests)
include(Json4sTests)
include(SprayTests)
include(JacksonTests)
include(ArgonautTests)
include(CirceTests)
include(LiftTests)
object PlayTests extends JsonJava8TimeApiTests(play.implicitJsonAst, play.implicitJsonStringParser)
object JawnTests extends JsonJava8TimeApiTests(jawn.implicitJsonAst, jawn.implicitJsonStringParser(jawn.jawnFacade))
object Json4sTests extends JsonJava8TimeApiTests(json4s.implicitJsonAst, json4s.implicitJsonStringParser)
object SprayTests extends JsonJava8TimeApiTests(spray.implicitJsonAst, spray.implicitJsonStringParser)
object JacksonTests extends JsonJava8TimeApiTests(jackson.implicitJsonAst, jackson.implicitJsonStringParser)
object ArgonautTests extends JsonJava8TimeApiTests(argonaut.implicitJsonAst, argonaut.implicitJsonStringParser)
object CirceTests extends JsonJava8TimeApiTests(circe.implicitJsonAst, circe.implicitJsonStringParser)
object LiftTests extends JsonJava8TimeApiTests(lift.implicitJsonAst, lift.implicitJsonStringParser)
}
abstract class JsonJava8TimeApiTests(ast: JsonAst, parser: Parser[String, JsonAst]) extends TestSuite {
implicit def implicitAst: JsonAst = ast
implicit def implicitParser: Parser[String, JsonAst] = parser
case class TestLocalDate(time: LocalDate)
case class TestLocalDateTime(time: LocalDateTime)
case class TestLocalTime(time: LocalTime)
case class TestZonedDateTime(time: ZonedDateTime)
case class TestOffsetDateTime(time: OffsetDateTime)
case class TestOffsetTime(time: OffsetTime)
val `[Java 8 Time Extractor] Extract LocalDate` = test {
json"""{"time": "2017-01-23"}""".time.as[LocalDate]
} returns LocalDate.of(2017, 1, 23)
val `[Java 8 Time Extractor] Extract LocalDateTime` = test {
json"""{"time": "2017-01-23T18:28:51.045"}""".time.as[LocalDateTime]
} returns LocalDateTime.of(2017, 1, 23, 18, 28, 51, 45000000)
val `[Java 8 Time Extractor] Extract LocalTime` = test {
json"""{"time": "18:38:14.997"}""".time.as[LocalTime]
} returns LocalTime.of(18, 38, 14, 997000000)
val `[Java 8 Time Extractor] Extract ZonedDateTime` = test {
json"""{"time": "2017-01-23T18:41:02.086+02:00[Europe/Kiev]"}""".time.as[ZonedDateTime]
} returns ZonedDateTime.of(2017, 1, 23, 18, 41, 2, 86000000, ZoneId.of("Europe/Kiev"))
val `[Java 8 Time Extractor] Extract OffsetDateTime` = test {
json"""{"time": "2017-01-23T18:44:18.221+02:00"}""".time.as[OffsetDateTime]
} returns OffsetDateTime.of(2017, 1, 23, 18, 44, 18, 221000000, ZoneOffset.ofHours(2))
val `[Java 8 Time Extractor] Extract OffsetTime` = test {
json"""{"time": "19:03:25.325+02:00"}""".time.as[OffsetTime]
} returns OffsetTime.of(19, 3, 25, 325000000, ZoneOffset.ofHours(2))
val `[Java 8 Time Extractor] Extract Failure` = test {
json"""{"time": "19:03:25.325+02:0"}""".time.as[OffsetTime]
} throws classOf[ParseException]
val `[Java 8 Time Serializator] Serialize LocalDate` = test {
Json(TestLocalDate(LocalDate.of(2017, 1, 23)))
} returns json"""{"time": "2017-01-23"}"""
val `[Java 8 Time Serializator] Serialize LocalDateTime` = test {
Json(TestLocalDateTime( LocalDateTime.of(2017, 1, 23, 18, 28, 51, 45000000)))
} returns json"""{"time": "2017-01-23T18:28:51.045"}"""
val `[Java 8 Time Serializator] Serialize LocalTime` = test {
Json(TestLocalTime(LocalTime.of(18, 38, 14, 997000000)))
} returns json"""{"time": "18:38:14.997"}"""
val `[Java 8 Time Serializator] Serialize ZonedDateTime` = test {
Json(TestZonedDateTime(ZonedDateTime.of(2017, 1, 23, 18, 41, 2, 86000000, ZoneId.of("Europe/Kiev"))))
} returns json"""{"time": "2017-01-23T18:41:02.086+02:00[Europe/Kiev]"}"""
val `[Java 8 Time Serializator] Serialize OffsetDateTime` = test {
Json(TestOffsetDateTime(OffsetDateTime.of(2017, 1, 23, 18, 44, 18, 221000000, ZoneOffset.ofHours(2))))
} returns json"""{"time": "2017-01-23T18:44:18.221+02:00"}"""
val `[Java 8 Time Serializator] Serialize OffsetTime` = test {
Json(TestOffsetTime(OffsetTime.of(19, 3, 25, 325000000, ZoneOffset.ofHours(2))))
} returns json"""{"time": "19:03:25.325+02:00"}"""
}
================================================
FILE: json-test/shared/src/test/scala/rapture/json-test/tests.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.json.test
//import rapture.core._
import rapture.json._
import rapture.data.{DataTypes, Parser}
import rapture.test._
import jsonBackends._
import dictionaries.dynamic._
class TestRun extends Programme {
include(PlayTests)
include(JawnTests)
include(Json4sTests)
include(SprayTests)
include(JacksonTests)
include(ArgonautTests)
include(CirceTests)
include(LiftTests)
//include(MutablePlayTests)
//include(MutableJawnTests)
//include(MutableJson4sTests)
//include(MutableSprayTests)
//include(MutableArgonautTests)
//include(MutableCirceTests)
//include(MutableLiftTests)
object PlayTests extends JsonTests(play.implicitJsonAst, play.implicitJsonStringParser)
object JawnTests extends JsonTests(jawn.implicitJsonAst, jawn.implicitJsonStringParser(jawn.jawnFacade))
object Json4sTests extends JsonTests(json4s.implicitJsonAst, json4s.implicitJsonStringParser)
object SprayTests extends JsonTests(spray.implicitJsonAst, spray.implicitJsonStringParser)
object JacksonTests extends JsonTests(jackson.implicitJsonAst, jackson.implicitJsonStringParser)
object ArgonautTests extends JsonTests(argonaut.implicitJsonAst, argonaut.implicitJsonStringParser)
object CirceTests extends JsonTests(circe.implicitJsonAst, circe.implicitJsonStringParser)
object LiftTests extends JsonTests(lift.implicitJsonAst, lift.implicitJsonStringParser)
object MutablePlayTests extends MutableJsonTests(play.implicitJsonAst, play.implicitJsonStringParser)
object MutableJawnTests extends MutableJsonTests(jawn.implicitJsonAst, jawn.implicitJsonStringParser(jawn.jawnFacade))
object MutableJson4sTests extends MutableJsonTests(json4s.implicitJsonAst, json4s.implicitJsonStringParser)
object MutableSprayTests extends MutableJsonTests(spray.implicitJsonAst, spray.implicitJsonStringParser)
object MutableArgonautTests extends MutableJsonTests(argonaut.implicitJsonAst, argonaut.implicitJsonStringParser)
object MutableCirceTests extends MutableJsonTests(circe.implicitJsonAst, circe.implicitJsonStringParser)
object MutableLiftTests extends MutableJsonTests(lift.implicitJsonAst, lift.implicitJsonStringParser)
}
case class Foo(alpha: String, beta: Int)
case class Bar(foo: Foo, gamma: Double)
case class Baz(alpha: String, beta: Option[Int])
case class Baz2(alpha: String, beta: util.Try[Int])
case class HasDefault(alpha: String = "yes", beta: Int)
case class HasDefault2(alpha: String, beta: Int = 1)
case class A(a: B)
case class B(b: C)
case class C(c: D)
case class D(d: E)
case class E(e: F)
case class F(f: Int)
case class FooDefaultOption(param1: Option[String] = None, param2: Option[Int] = None)
abstract class JsonTests(ast: JsonAst, parser: Parser[String, JsonAst]) extends TestSuite {
implicit def implicitAst: JsonAst = ast
implicit def implicitParser: Parser[String, JsonAst] = parser
val source1 = json"""{
"string": "Hello",
"int": 42,
"double": 3.14159,
"boolean": true,
"list": [1, 2, 3],
"foo": { "alpha": "test", "beta": 1 },
"bar": { "foo": { "alpha": "test2", "beta": 2 }, "gamma": 2.7 },
"baz": { "alpha": "test" },
"baz2": { "alpha": "test", "beta": 7 },
"self": 0,
"boo": null,
"booInner": {"foo": null, "bar": "value"}
}"""
val `Extract Int` = test {
source1.int.as[Int]
} returns 42
val `Extract value called "self"` = test {
source1.self.as[Int]
} returns 0
val `Extract Option[Int]` = test {
source1.int.as[Option[Int]]
} returns Some(42)
val `Extract Option[Int], wrong type` = test {
source1.string.as[Option[Int]]
} returns None
val `Extract String` = test {
source1.string.as[String]
} returns "Hello"
val `Extract Double` = test {
source1.double.as[Double]
} returns 3.14159
val `Extract Boolean` = test {
source1.boolean.as[Boolean]
} returns true
val `Extract List[Int]` = test {
source1.list.as[List[Int]]
} returns List(1, 2, 3)
val `Extract Vector[Int]` = test {
source1.list.as[Vector[Int]]
} returns Vector(1, 2, 3)
val `Extract case class` = test {
source1.foo.as[Foo]
} returns Foo("test", 1)
val `Extract case class with missing optional value` = test {
source1.baz.as[Baz]
} returns Baz("test", None)
val `Extract case class with missing tried value` = test {
source1.baz.as[Baz2]
} returns Baz2("test", util.Failure(MissingValueException("beta")))
val `Extract case class with present optional value` = test {
source1.baz2.as[Baz]
} returns Baz("test", Some(7))
val `Extract case class with present tried value` = test {
source1.baz2.as[Baz2]
} returns Baz2("test", util.Success(7))
val `Extract nested case class` = test {
source1.bar.as[Bar]
} returns Bar(Foo("test2", 2), 2.7)
val `Extract deeply-nested case class` = test {
json"""{ "a": { "b": { "c": { "d": { "e": { "f": 1 } } } } } }""".as[A]
} returns A(B(C(D(E(F(1))))))
val `Extract List element` = test {
source1.list(1).as[Int]
} returns 2
val `Extract object element` = test {
source1.bar.foo.alpha.as[String]
} returns "test2"
val `Extract null element` = test[Null] {
source1.boo.as[Null]
} returns null
val `Extract null element from inner value` = test[Null] {
source1.booInner.foo.as[Null]
} returns null
val `Try to extract null element from not null inner value` = test {
source1.booInner.bar.as[Null]
} throws TypeMismatchException(DataTypes.String, DataTypes.Null)
val `Try to extract null element from not null value` = test {
source1.double.as[Null]
} throws TypeMismatchException(DataTypes.Number, DataTypes.Null)
val `Match null element` = test[Null] {
source1 match {
case json""" { "boo": $h } """ => h.as[Null]
}
} returns null
val `Match inner null element` = test[Null] {
source1 match {
case json""" { "booInner": {"foo": $h } } """ => h.as[Null]
}
} returns null
val `Extract long element` = test {
source1.int.as[Long]
} returns 42L
val `Extract missing value with case class default` = test {
json"""{"beta": 0}""".as[HasDefault]
} returns HasDefault("yes", 0)
val `Extract missing value with case class default 2` = test {
json"""{"alpha": "no"}""".as[HasDefault2]
} returns HasDefault2("no", 1)
val `Extract case class ignoring default value` = test {
json"""{"alpha": "no", "beta": 0}""".as[HasDefault2]
} returns HasDefault2("no", 0)
val `Check type failure` = test {
source1.string.as[Int]
} throws TypeMismatchException(DataTypes.String, DataTypes.Number)
val `Check missing value failure` = test {
source1.nothing.as[Int]
} throws MissingValueException("nothing")
val `Match string` = test {
source1 match {
case json""" { "string": $h } """ => h.as[String]
}
} returns "Hello"
val `Match inner JSON` = test {
source1 match {
case json""" { "foo": $foo } """ => foo
}
} returns json"""{ "alpha": "test", "beta": 1 }"""
val `Match inner string` = test {
source1 match {
case json""" { "foo": { "alpha": $t } } """ => t.as[String]
}
} returns "test"
val `Filtered match` = test {
source1 match {
case json""" { "int": 42, "foo": { "alpha": $t } } """ => t.as[String]
}
} returns "test"
val `Inner filtered match` = test {
source1 match {
case json""" { "foo": { "alpha": "test" }, "bar": { "gamma": $g } } """ => g.as[Double]
}
} returns 2.7
val `Filtered failed match` = test {
source1 match {
case json""" { "int": 0, "foo": { "alpha": $t } } """ => t.as[String]
}
} throws classOf[MatchError]
val `Multiple pattern match` = test {
json"""{ "foo": "bar" }""" match {
case json"""{ "bar": "foo" }""" => 0
case json"""{ "foo": "baz" }""" => 1
case json"""{ "foo": "bar" }""" => 2
}
} returns 2
val `Empty object doesn't match` = test {
json"""{ "foo": "bar" }""" match {
case json"""{ "foo": {} }""" => 0
}
} throws classOf[MatchError]
val `Serialize string` = test {
Json("Hello World!").toString
} returns "json\"\"\"\"Hello World!\"\"\"\""
val `Serialize int` = test {
Json(1648).toString
} returns "json\"\"\"1648\"\"\""
val `Serialize array` = test {
Json(List(1, 2, 3)).toString
} returns "json\"\"\"[1,2,3]\"\"\""
val `Serialize object` = test {
import formatters.humanReadable._
Json.format(json"""{"baz":"quux","foo":"bar"}""")
} returns """{
| "baz": "quux",
| "foo": "bar"
|}""".stripMargin
val `Empty object serialization` = test {
import formatters.humanReadable._
Json.format(json"{}")
} returns "{}"
val `Empty array serialization` = test {
import formatters.humanReadable._
Json.format(json"[]")
} returns "[]"
// As reported by Jim Newsham
val `Extracting Option should not throw exception` = test {
val j = json"""{"foo":"bar"}"""
j.as[Option[String]]
} returns None
val `Tabs should be escaped when serializing strings` = test {
Json("\t").toString
} returns "json\"\"\"\"\\t\"\"\"\""
val `Extract Byte` = test {
val j = json"""{ "foo": 127 }"""
j.foo.as[Byte]
} returns (127.toByte)
val `Extract Short` = test {
val j = json"""{ "foo": 12345 }"""
j.foo.as[Short]
} returns (12345.toShort)
val `Extract Long` = test {
val j = json"""{ "foo": 1234567890123456789 }"""
j.foo.as[Long]
} returns 1234567890123456789L
val `Extract case class with empty/default option` = test {
import rapture.json.formatters.compact._
Json.format(Json(FooDefaultOption()))
} returns "{}"
val `Extract case class with default None param and one Some(..) param` = test {
import rapture.json.formatters.compact._
Json.format(Json(FooDefaultOption(param2 = Some(10))))
} returns """{"param2":10}"""
val `Serialize null` = test { Json(null) } returns json"""{"nullValue":null}""".nullValue
val `Parse basic JSON null value` = test { json"null" } returns json"null"
/*val `Serialize sealed trait` = test {
Json(Left(50): Either[Int, String])
}.returns(json"""{"left":50}""")
val `Extract sealed trait` = test {
json"""{ "left": 50 }""".as[Either[Int, String]]
}.returns(Left(50))*/
}
abstract class MutableJsonTests(ast: JsonBufferAst, parser: Parser[String, JsonBufferAst]) extends TestSuite {
implicit def implicitAst: JsonBufferAst = ast
implicit def implicitParser: Parser[String, JsonBufferAst] = parser
case class Foo(alpha: String, beta: Int)
case class Bar(foo: Foo, gamma: Double)
val mutableSource = jsonBuffer"""{
"string": "Hello",
"int": 42,
"double": 3.14159,
"boolean": true,
"list": [1, 2, 3],
"foo": { "alpha": "test", "beta": 1 },
"bar": { "foo": { "alpha": "test2", "beta": 2 }, "gamma": 2.7 },
"baz": { "alpha": "test" },
"baz2": { "alpha": "test", "beta": 7 },
"self": 0
}"""
val `Mutable extract Int` = test {
mutableSource.int.as[Int]
} returns 42
val source2 = JsonBuffer.parse("""{
"string": "Hello",
"int": 42
}""")
val `Mutable get String` = test {
source2.string.as[String]
} returns "Hello"
//val `Mutable get optional String` = test {
// source2.string.as[Option[String]]
//} returns Some("Hello")
val `Mutable get Int` = test {
source2.int.as[Int]
} returns 42
val `Mutable change String` = test {
source2.string = "World"
source2.string.as[String]
} returns "World"
val `Mutable add String` = test {
source2.inner.newString = "Hello"
source2.inner.newString.as[String]
} returns "Hello"
val `Mutable add Json` = test {
val jb = JsonBuffer.empty
jb.foo = json"""{ "foo": "bar" }"""
} returns jsonBuffer"""{ "foo": { "foo": "bar" } }"""
val `Mutable add case class` = test {
source2.foo = Foo("string", -1)
source2.foo.as[Foo]
} returns Foo("string", -1)
val `Deep insertion of integer` = test {
source2.alpha.beta.gamma.delta = 1
source2.alpha.beta.gamma.delta.as[Int]
} returns 1
val `Array autopadding` = test {
source2.autopad(4) = 1
source2.autopad(4).as[Int]
} returns 1
val `Deep array insertion of integer` = test {
source2.array(1)(2)(3)(4) = 1
source2.array(1)(2)(3)(4).as[Int]
} returns 1
val `Deep mixed insertion of string` = test {
source2.mixed(4).foo.bar(2).baz = "Mixed"
source2.mixed(4).foo.bar(2).baz.as[String]
} returns "Mixed"
val `Mutable add array String` = test {
source2.inner.newArray += "Hello"
source2.inner.newArray(0).as[String]
} returns "Hello"
}
================================================
FILE: latex/shared/src/main/scala/latex/latex.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.latex
import rapture.io._
import rapture.fs._
import rapture.text._
import rapture.uri._
import rapture.core._
import rapture.cli._
import rapture.codec._, encodings.`UTF-8`._
import language.implicitConversions
object TemporaryStorage {
implicit def defaultTemporary: TemporaryStorage = TemporaryStorage(uri"file:///tmp")
}
case class TemporaryStorage(file: FsUrl) {
def tmpFile(prefix: String = "rapture", suffix: String = ".tmp") =
File.parse(java.io.File.createTempFile(prefix, suffix, file.javaFile).getAbsolutePath)
}
trait LatexBackend {
def process(latex: Latex, data: Seq[(String, Bytes)], mode: Mode[_], tmp: TemporaryStorage): PdfFile
}
package latexBackends {
object xelatex {
implicit val implicitLatexBackend: LatexBackend = new LatexBackend {
def process(latex: Latex, data: Seq[(String, Bytes)], mode: Mode[_], tmp: TemporaryStorage): PdfFile = {
val dir = tmp.file / Guid.generate()()
dir.mkdir()
data.foreach {
case (name, bytes) =>
val f = dir / name
bytes.copyTo(f)
}
val file = dir / "document.tex"
implicit val env: Environment = new Environment {
def workDir = Some(dir.javaFile.getAbsolutePath)
def apply() = environments.enclosing()()
}
latex.content.copyTo(file)
val cmd = sh"/usr/bin/xelatex -interaction nonstopmode ${file}"
val output = cmd.exec[Iterator[String]]
while (output.hasNext) {
var next = output.next()
if (next startsWith "! ") {
val msg = next.drop(if (next.startsWith("! LaTeX Error: ")) 15 else 2)
val content = new StringBuilder()
while (output.hasNext && !next.startsWith("l.")) {
next = output.next()
if (!next.startsWith("l.")) content.append(s"$next\n")
else {
val line = next.drop(2).takeWhile(_ != ' ').toInt
mode.exception(LatexException(msg, line, content.toString.trim))
}
}
}
}
PdfFile((file.parent / file.filename.replaceAll("tex$", "pdf")).slurp[Byte])
}
}
}
}
object Latex {
def escape(string: String): String = string.flatMap {
case c @ ('#' | '$' | '%' | '&' | '_' | '{' | '}') => s"\\$c"
case '\\' => "\\textbackslash{}"
case '\n' => " \\\\\n"
case '^' => "\\textasciicircum{}"
case '~' => "\\textasciitilde{}"
case c => c.toString
}
}
trait `Latex#generate` extends MethodConstraint
case class LatexException(msg: String, line: Int, content: String) extends Exception {
override def getMessage = s"latex error at line $line: $msg"
}
case class Latex(content: String) {
def generate(data: (String, Bytes)*)(implicit backend: LatexBackend,
mode: Mode[`Latex#generate`],
tmp: TemporaryStorage): mode.Wrap[PdfFile, LatexException] =
mode.wrap { backend.process(this, data, mode, tmp) }
}
case class PdfFile(data: Bytes)
object Latexable {
implicit val stringLatexable: Latexable[String] = new Latexable[String] {
def toLatex(s: String) = Latex.escape(s)
}
implicit val latexLatexable: Latexable[Latex] = new Latexable[Latex] {
def toLatex(latex: Latex) = latex.content
}
implicit def seqLatexable[T: Latexable]: Latexable[Seq[T]] = new Latexable[Seq[T]] {
def toLatex(seq: Seq[T]) = seq.map(?[Latexable[T]].toLatex(_)).mkString
}
}
trait Latexable[-T] { def toLatex(t: T): String }
case class LatexStringContext(sc: StringContext) {
def latex(variables: Annex[Latexable]*)(implicit process: TextProcess) =
Latex(process(sc.parts.zip(variables.map(_ (_.toLatex))).map { case (a, b) => a + b }.mkString + sc.parts.last))
}
object `package` {
implicit def latexStringContext(sc: StringContext): LatexStringContext = LatexStringContext(sc)
}
================================================
FILE: log/shared/src/main/scala/rapture/log/levels.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.log
trait LogLevel
trait Trace extends LogLevel
trait Debug extends Trace
trait Info extends Debug
trait Warn extends Info
trait Error extends Warn
trait Fatal extends Error
object logLevels {
object trace {
implicit val logLevelImplicit: NamedLogAction = new NamedLogAction(0, "trace")
}
object debug {
implicit val logLevelImplicit: NamedLogAction = new NamedLogAction(1, "debug")
}
object info {
implicit val logLevelImplicit: NamedLogAction = new NamedLogAction(2, "info")
}
object warn {
implicit val logLevelImplicit: NamedLogAction = new NamedLogAction(3, "warn")
}
object error {
implicit val logLevelImplicit: NamedLogAction = new NamedLogAction(4, "error")
}
object fatal {
implicit val logLevelImplicit: NamedLogAction = new NamedLogAction(5, "fatal")
}
}
================================================
FILE: log/shared/src/main/scala/rapture/log/log.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.log
import rapture.base._
import rapture.core._
import rapture.io._
import scala.annotation._
import language.experimental.macros
object `package` {
val log = Log
implicit class LogStringContext(sc: StringContext) {
def log(xs: rapture.log.parts.Part*): Spec = {
new Spec {
def render(level: Int, lineNo: Int, source: String) = {
val sb = new StringBuilder
for (i <- 0 until (sc.parts.length - 1)) {
sb.append(sc.parts(i))
sb.append(xs(i).fit(level, lineNo, source))
}
sb.append(sc.parts.last)
sb.toString
}
}
}
}
}
trait Outputter {
def log[L <: LogLevel](prefix: String, msg: Array[String])
}
object LogAction {
implicit def defaultLogAction(implicit act: NamedLogAction): LogAction =
new LogAction { def level = -1 }
}
@implicitNotFound(
"You have not specified a valid logging level. Please import one of logLevels" +
".{trace._, debug._, info._, warn._, error._, fatal._}.")
trait LogAction {
def level: Int
}
class NamedLogAction(val level: Int, val name: String) extends LogAction
object Loggable {
implicit val stringLoggable: Loggable[String] = new Loggable[String] {
def toArray(msg: String) = Array(msg)
}
implicit val exceptionLoggable: Loggable[Throwable] = new Loggable[Throwable] {
def toArray(msg: Throwable) = Array(msg.toString) ++ msg.getStackTrace.map(" at " + _)
}
}
trait Loggable[-Msg] { def toArray(msg: Msg): Array[String] }
object SourceContext {
implicit def sourceContext: SourceContext = macro LogMacros.sourceContextMacro
}
case class SourceContext(lineNo: Int, sourceFile: String)
object LogMacros {
def logMacro[Msg: c.WeakTypeTag](level: Int)(c: BlackboxContext)(msg: c.Expr[Msg])(
log: c.Expr[Log],
loggable: c.Expr[Loggable[Msg]],
srcCtx: c.Expr[SourceContext]): c.Expr[Unit] = {
import c.universe._
val lev = c.Expr[Int](q"$level")
reify {
if (log.splice.action.level <= lev.splice) {
log.splice.out.log(log.splice.spec.render(lev.splice, srcCtx.splice.lineNo, srcCtx.splice.sourceFile),
loggable.splice.toArray(msg.splice))
}
}
}
def sourceContextMacro(c: BlackboxContext): c.Expr[SourceContext] = {
import c.universe._
val lineNo = c.Expr[Int](q"${c.enclosingPosition.line}")
val sourceFile = c.Expr[String](q"${c.enclosingPosition.source.toString}")
reify { SourceContext(lineNo.splice, sourceFile.splice) }
}
def traceMacro[Msg: c.WeakTypeTag](c: BlackboxContext)(msg: c.Expr[Msg])(
log: c.Expr[Log],
loggable: c.Expr[Loggable[Msg]],
sourceContext: c.Expr[SourceContext]): c.Expr[Unit] =
logMacro(0)(c)(msg)(log, loggable, sourceContext)
def debugMacro[Msg: c.WeakTypeTag](c: BlackboxContext)(msg: c.Expr[Msg])(
log: c.Expr[Log],
loggable: c.Expr[Loggable[Msg]],
sourceContext: c.Expr[SourceContext]): c.Expr[Unit] =
logMacro(1)(c)(msg)(log, loggable, sourceContext)
def infoMacro[Msg: c.WeakTypeTag](c: BlackboxContext)(msg: c.Expr[Msg])(
log: c.Expr[Log],
loggable: c.Expr[Loggable[Msg]],
sourceContext: c.Expr[SourceContext]): c.Expr[Unit] =
logMacro(2)(c)(msg)(log, loggable, sourceContext)
def warnMacro[Msg: c.WeakTypeTag](c: BlackboxContext)(msg: c.Expr[Msg])(
log: c.Expr[Log],
loggable: c.Expr[Loggable[Msg]],
sourceContext: c.Expr[SourceContext]): c.Expr[Unit] =
logMacro(3)(c)(msg)(log, loggable, sourceContext)
def errorMacro[Msg: c.WeakTypeTag](c: BlackboxContext)(msg: c.Expr[Msg])(
log: c.Expr[Log],
loggable: c.Expr[Loggable[Msg]],
sourceContext: c.Expr[SourceContext]): c.Expr[Unit] =
logMacro(4)(c)(msg)(log, loggable, sourceContext)
def fatalMacro[Msg: c.WeakTypeTag](c: BlackboxContext)(msg: c.Expr[Msg])(
log: c.Expr[Log],
loggable: c.Expr[Loggable[Msg]],
sourceContext: c.Expr[SourceContext]): c.Expr[Unit] =
logMacro(5)(c)(msg)(log, loggable, sourceContext)
}
abstract class Spec {
def render(level: Int, lineNo: Int, source: String): String
}
/*object Main extends App {
import logLevels.debug._
import encodings.system
implicit val output = Logger(Stdout)
implicit val spec = log" "
Log.logImplicit
log.info("Here is an information message.")
sys.exit(1)
}*/
object Log {
implicit def logImplicit(implicit spec: Spec, out: Outputter, action: LogAction) =
Log(spec, out, action)
def trace[Msg](msg: Msg)(implicit log: Log, loggable: Loggable[Msg], sourceContext: SourceContext): Unit = macro LogMacros
.traceMacro[Msg]
def debug[Msg](msg: Msg)(implicit log: Log, loggable: Loggable[Msg], sourceContext: SourceContext): Unit = macro LogMacros
.debugMacro[Msg]
def info[Msg](msg: Msg)(implicit log: Log, loggable: Loggable[Msg], sourceContext: SourceContext): Unit = macro LogMacros
.infoMacro[Msg]
def warn[Msg](msg: Msg)(implicit log: Log, loggable: Loggable[Msg], sourceContext: SourceContext): Unit = macro LogMacros
.warnMacro[Msg]
def error[Msg](msg: Msg)(implicit log: Log, loggable: Loggable[Msg], sourceContext: SourceContext): Unit = macro LogMacros
.errorMacro[Msg]
def fatal[Msg](msg: Msg)(implicit log: Log, loggable: Loggable[Msg], sourceContext: SourceContext): Unit = macro LogMacros
.fatalMacro[Msg]
}
case class Log(spec: Spec, out: Outputter, action: LogAction)
case class Logger[Res](res: Res)(implicit appender: Appender[Res, String]) extends Outputter {
final val maxDelay = 25
final val queueThreshold = 10
private val queue = new scala.collection.mutable.Queue[String]
private var blankPrefix: String = null
private val thread: Thread = Thread.fork("rapture-log") {
var continue = true
sys.addShutdownHook { continue = false }
while (continue) {
try {
queue synchronized {
queue.wait(maxDelay)
if (queue.nonEmpty) res handleAppend { out: Output[String] =>
while (queue.nonEmpty) out.write(queue.dequeue)
}
}
} catch {
case e: InterruptedException =>
continue = false
}
}
}
def log[L <: LogLevel](prefix: String, msg: Array[String]) = queue synchronized {
if (blankPrefix == null) blankPrefix = " " * (prefix.length + 1)
queue.enqueue(prefix + " " + msg(0))
msg.tail foreach { m =>
queue.enqueue(blankPrefix + m)
}
if (queue.size >= queueThreshold) queue.notify()
}
}
object stdoutLogging {
import parts._
implicit def implicitSpec(implicit severity: Severity, date: Date, time: Time, thread: Thread): Spec =
log"""$date $time [$severity] ${sourceFile(width = 12, Right)}:${lineNo(4)} ${thread(10)}"""
implicit val output = Logger(Stdout)
def apply()(implicit severity: Severity, date: Date, time: Time, thread: Thread): Spec with Outputter =
new Spec with Outputter {
def render(level: Int, lineNo: Int, source: String): String =
implicitSpec.render(level, lineNo, source)
def log[L <: LogLevel](prefix: String, msg: Array[String]) = output.log(prefix, msg)
}
}
================================================
FILE: log/shared/src/main/scala/rapture/log/parts.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.log
import rapture.core._
object parts {
abstract class Part(width: Int, align: Alignment) { part =>
def text(level: Int, lineNo: Int, source: String): String
def fit(level: Int, lineNo: Int, source: String) = {
val t = text(level, lineNo, source)
if (t.length > width) t.substring(0, width)
else if (align == Left) t.padTo(width, ' ')
else " " * (width - t.length) + t
}
def apply(width: Int = width, align: Alignment = align): Part = new Part(width, align) {
def text(level: Int, lineNo: Int, source: String) =
part.text(level, lineNo, source)
}
}
sealed trait Alignment
case object Left extends Alignment
case object Right extends Alignment
object Severity {
implicit def severity: Severity = new Severity()
}
class Severity() extends Part(5, Left) {
def text(level: Int, lineNo: Int, source: String) = level match {
case 0 => "TRACE"
case 1 => "DEBUG"
case 2 => "INFO"
case 3 => "WARN"
case 4 => "ERROR"
case 5 => "FATAL"
}
}
object Time {
implicit def logTime = new Time(System.currentTimeMillis)
val timeFormat = new java.text.SimpleDateFormat("HH:mm:ss.SSS")
}
class Time(time: Long) extends Part(12, Left) {
def text(level: Int, lineNo: Int, source: String) = Time.timeFormat.format(time)
}
object Date {
implicit def logDate = new Date(System.currentTimeMillis)
val dateFormat = new java.text.SimpleDateFormat("dd-MMM-yyyy")
}
class Date(date: Long) extends Part(9, Left) {
def text(level: Int, lineNo: Int, source: String) = Date.dateFormat.format(date)
}
object sourceFile extends Part(4, Left) {
def text(level: Int, lineNo: Int, source: String) = source.toString
}
object lineNo extends Part(4, Left) {
def text(level: Int, lineNo: Int, source: String) = lineNo.toString
}
object Thread {
implicit def currentThread: Thread = new Thread(java.lang.Thread.currentThread.getName)
}
class Thread(name: String) extends Part(10, Left) {
def text(level: Int, lineNo: Int, source: String) = name
}
}
================================================
FILE: mail/shared/src/main/scala/rapture/mail/javamail.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.mail
import rapture.core._
package sendmailBackends {
object javamail {
def apply()(implicit smtpServer: Smtp): SendmailBackend = implicitSendmailBackend
implicit def implicitSendmailBackend(implicit smtpServer: Smtp): SendmailBackend =
new SendmailBackend {
def sendmail(to: Seq[String],
from: String,
subject: String,
cc: Seq[String],
bcc: Seq[String],
bodyText: String,
bodyHtml: Option[(String, Seq[Annex[Attachable]])],
attachments: Seq[Annex[Attachable]])(implicit mode: Mode[_]): mode.Wrap[SendReport, SendAddressException with SendException] = mode wrap {
import javax.mail._
import javax.mail.util._
import javax.mail.internet._
import javax.activation._
val props = System.getProperties()
props.put("mail.smtp.host", smtpServer.hostname)
props.put("mail.smtp.port", smtpServer.port.toString)
val session = Session.getDefaultInstance(props, null)
val msg = new MimeMessage(session)
msg.setFrom(new InternetAddress(from))
for (r <- to) msg.addRecipient(Message.RecipientType.TO, new InternetAddress(r))
for (r <- cc) msg.addRecipient(Message.RecipientType.CC, new InternetAddress(r))
for (r <- bcc) msg.addRecipient(Message.RecipientType.BCC, new InternetAddress(r))
msg.setSubject(subject)
def source(attachment: Annex[Attachable], inline: Boolean) = {
val part = new MimeBodyPart()
part.setDisposition(if(inline) Part.INLINE else Part.ATTACHMENT)
if(inline) part.setHeader("Content-ID", s"<${attachment(_.resourceName)}>")
else part.setFileName(attachment(_.resourceName))
part.setDataHandler(new DataHandler(new ByteArrayDataSource(attachment(_.bytes).bytes, attachment(_.contentType).name)))
part
}
bodyHtml match {
case Some((html, inlines)) =>
var top = new MimeMultipart("alternative")
val textPart = new MimeBodyPart()
textPart.setText(bodyText, "UTF-8")
top.addBodyPart(textPart)
val htmlPart = new MimeBodyPart()
htmlPart.setContent(html, "text/html;charset=UTF-8")
top.addBodyPart(htmlPart)
if (inlines.length > 0) {
val body = new MimeBodyPart()
body.setContent(top)
top = new MimeMultipart("related")
top.addBodyPart(body)
inlines.foreach { inline => top.addBodyPart(source(inline, true)) }
}
if (attachments.length > 0) {
val body = new MimeBodyPart()
body.setContent(top)
top = new MimeMultipart("mixed")
top.addBodyPart(body)
attachments.foreach { attachment => top.addBodyPart(source(attachment, false)) }
}
msg.setContent(top)
case None => {
if (attachments.length > 0) {
val body = new MimeBodyPart()
body.setText(bodyText, "UTF-8")
val top = new MimeMultipart("mixed")
top.addBodyPart(body)
attachments.foreach { attachment => top.addBodyPart(source(attachment, false)) }
msg.setContent(top)
} else {
msg.setText(bodyText, "UTF-8")
}
}
}
Transport.send(msg)
SendReport(msg.getMessageID)
}
}
}
}
================================================
FILE: mail/shared/src/main/scala/rapture/mail/mail.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.mail
import rapture.base._
import rapture.core._
import rapture.io._
import rapture.uri._
import rapture.html._
import rapture.mime._
import rapture.codec._
import scala.reflect._
import scala.language.experimental.macros
object Macros {
def mailtoMacro(c: BlackboxContext)(constants: c.Expr[List[String]])(
variables: c.Expr[List[String]]): c.Expr[MailtoUri] = {
import c.universe._
c.Expr(q"""
new _root_.rapture.mail.MailtoUri(_root_.scala.List($constants,
$variables :+ "").transpose.flatten.mkString)
""")
}
def contactMacro(c: BlackboxContext)(variables: c.Expr[String]*): c.Expr[Contact] = {
import c.universe._
val literals = c.prefix.tree match {
case Apply(_, List(Apply(_, rawParts))) => rawParts.map {
case Literal(Constant(s: String)) => s
}
}
val mock = literals.mkString("x")
val result = if(Contact.parse(mock).isDefined) c.Expr(q"""
_root_.rapture.mail.Contact.parse(_root_.scala.List($literals,
_root_.scala.List(..$variables, "")).transpose.flatten.mkString).get
""") else c.abort(c.enclosingPosition, "this is not a valid email address")
result
}
def smtpMacro(c: BlackboxContext)(constants: c.Expr[List[String]])(
variables: c.Expr[List[String]]): c.Expr[Smtp] = {
import c.universe._
import compatibility._
val start = constants.tree match {
case Apply(_, constants) =>
val Literal(Constant(start: String)) = constants.head
start
}
if(!start.startsWith("//")) c.abort(c.enclosingPosition, "this is not a valid SMTP URI")
val rest = start.substring(2)
val newName = termName(c, freshName(c)("ctx"))
c.Expr[Smtp](q"""{
val $newName = List($constants, $variables :+ "").transpose.flatten.mkString.substring(2).split(":")
_root_.rapture.mail.Smtp($newName(0), new _root_.rapture.core.EnrichedString(
if($newName.length > 1) $newName(1) else "25").as[_root_.scala.Int](
_root_.rapture.core.StringParser.intParser, _root_.rapture.core.modes.returnOption()).getOrElse(25))
}""")
}
}
trait `Smtp#send` extends MethodConstraint
trait `Smtp#sendmail` extends MethodConstraint
trait `send` extends MethodConstraint
trait `sendTo` extends MethodConstraint
object Mailto {
private val Regex =
"""^mailto:([_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,}))$""".r
def parse(s: String): MailtoUri = s match {
case Regex(address, _, _, _) => new MailtoUri(address)
}
}
object MailtoUri {
implicit val mailtoUriLinkable: UriCapable[MailtoUri] = new UriCapable[MailtoUri] {
def uri(mu: MailtoUri): Uri =
Uri("mailto", mu.email)
}
}
case class MailtoUri(email: String) {
override def toString = s"mailto:$email"
}
case class HtmlEmail(html: HtmlDoc, inlines: List[Annex[Attachable]], attachments: List[Annex[Attachable]])
object Attachable {
implicit def attachable[Res: HasResourceName: HasContentType: Reader.ForBytes] = new Attachable[Res] {
def resourceName(res: Res): String = res.resourceName
def contentType(res: Res): MimeTypes.MimeType = res.contentType
def bytes(res: Res): Bytes = res.slurp[Byte]
}
}
trait Attachable[Res] {
def resourceName(res: Res): String
def contentType(res: Res): MimeTypes.MimeType
def bytes(res: Res): Bytes
}
case class Envelope(
subject: String,
from: Contact,
to: SeqParameter[Contact],
cc: SeqParameter[Contact] = Nil,
bcc: SeqParameter[Contact] = Nil) {
def insert(mailable: Annex[Mailable], attachments: Annex[Attachable]*) =
EmailMessage(from, to.elements, cc.elements, bcc.elements, subject, mailable, attachments)
}
object EmailMessage {
implicit val emailMessageSendable: Sendable[EmailMessage] = new Sendable[EmailMessage] {
def to(env: EmailMessage): Seq[Contact] = env.to
def cc(env: EmailMessage): Seq[Contact] = env.cc
def bcc(env: EmailMessage): Seq[Contact] = env.bcc
def from(env: EmailMessage): Contact = env.from
def subject(env: EmailMessage): String = env.subject
def bodyText(env: EmailMessage): String = env.mailable(_.bodyText)
def bodyHtml(env: EmailMessage): Option[(String, Seq[Annex[Attachable]])] = env.mailable(_.bodyHtml)
def attachments(env: EmailMessage): Seq[Annex[Attachable]] = env.mailable(_.attachments)
}
}
case class EmailMessage(from: Contact, to: Seq[Contact], cc: Seq[Contact], bcc: Seq[Contact], subject: String, mailable: Annex[Mailable], attachments: Seq[Annex[Attachable]]*)
class ContactStringContext(sc: StringContext) {
def contact(variables: String*): Contact = macro Macros.contactMacro
}
object Contact {
private val EmailWithName =
"""^([^<]*) <([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,})>$""".r
private val JustEmail =
"""^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,})$""".r
def parse(email: String): Option[Contact] = email match {
case JustEmail(e, _, _) => Some(Contact(e))
case EmailWithName(n, e, _, _0) => Some(Contact(e, Some(n)))
case _ => None
}
}
case class Contact(email: String, name: Option[String] = None) {
override def toString = if (name == None) email else s""""${name.get}" <${email}>"""
}
object Smtp {
private val Regex = """^smtp:\/\/([^:]*)(:([1-9][0-9]*))?\/?$""".r
def parse(s: String) = s match {
case Regex(host, _, port) => new Smtp(host, Option(port).map(_.toInt).getOrElse(25))
}
}
case class MailEnrichedUriContext(uri: UriContext.type) {
def mailto(constants: List[String])(variables: List[String]): MailtoUri = macro Macros.mailtoMacro
def smtp(constants: List[String])(variables: List[String]): Smtp = macro Macros.smtpMacro
def cid(constants: List[String])(variables: List[String]): PathLink = PathLink(s"cid:${List(constants, variables :+ "").transpose.flatten.mkString}")
}
object Mailable {
implicit val stringMailable: Mailable[String] = new Mailable[String] {
def bodyText(t: String) = t
def bodyHtml(t: String) = None
def attachments(t: String): Seq[Annex[Attachable]] = Nil
}
implicit def htmlMailable(implicit conv: HtmlToPlainTextConverter): Mailable[HtmlEmail] =
new Mailable[HtmlEmail] {
def bodyText(t: HtmlEmail) = conv.convert(t.html)
def bodyHtml(t: HtmlEmail) = Some((t.html.format, t.inlines))
def attachments(t: HtmlEmail) = t.attachments
}
}
object Attachment {
implicit def attachmentIsAttachable: Attachable[Attachment] = new Attachable[Attachment] {
def resourceName(attachment: Attachment): String = attachment.name
def contentType(attachment: Attachment): MimeTypes.MimeType =
attachment.contentType().orElse(MimeTypes.extension(attachment.name).headOption).getOrElse(
MimeTypes.`application/octet-stream`)
def bytes(attachment: Attachment): Bytes =
attachment.content { implicit reader => _.slurp[Byte] }
}
}
case class Attachment(name: String, content: Annex[Reader.ForBytes],
contentType: OptionalParameter[MimeTypes.MimeType] = UnspecifiedParameter)
trait Mailable[T] {
def bodyText(t: T): String
def bodyHtml(t: T): Option[(String, Seq[Annex[Attachable]])]
def attachments(t: T): Seq[Annex[Attachable]]
}
object `package` {
implicit def mailEnrichedUriContext(uri: UriContext.type): MailEnrichedUriContext =
MailEnrichedUriContext(uri)
implicit def mailEnrichedStringContext(sc: StringContext): ContactStringContext =
new ContactStringContext(sc)
implicit def sendExtensionMethod[T: Sendable](sendable: T): Sendable.Capability[T] =
Sendable.Capability[T](sendable)
}
case class Smtp(hostname: String, port: Int = 25)
/*{
def sendmail(to: Seq[Contact],
from: Contact,
subject: String,
cc: Seq[Contact],
bcc: Seq[Contact],
content: String,
bodyHtml: Option[(String, Seq[Annex[Attachable]])],
attachments: Seq[Annex[Attachable]])(implicit mode: Mode[`Smtp#sendmail`],
backend: SendmailBackend): mode.Wrap[SendReport, SendAddressException with SendException] =
backend.sendmail(hostname,
port,
to.map(_.toString),
from.toString,
subject,
cc.map(_.toString),
bcc.map(_.toString),
content,
bodyHtml,
attachments)
}*/
case class SendReport(messageId: String)
object Sendable {
case class Capability[T: Sendable](msg: T) {
def send()(implicit mode: Mode[`send`], sendmailBackend: SendmailBackend): mode.Wrap[SendReport,
SendAddressException with SendException] =
sendmailBackend.sendmail(
to = ?[Sendable[T]].to(msg).map(_.toString),
from = ?[Sendable[T]].from(msg).toString,
subject = ?[Sendable[T]].subject(msg),
cc = ?[Sendable[T]].cc(msg).map(_.toString),
bcc = ?[Sendable[T]].bcc(msg).map(_.toString),
bodyText = ?[Sendable[T]].bodyText(msg),
bodyHtml = ?[Sendable[T]].bodyHtml(msg),
attachments = ?[Sendable[T]].attachments(msg)
)
}
}
trait Sendable[T] {
def to(t: T): Seq[Contact]
def cc(t: T): Seq[Contact]
def bcc(t: T): Seq[Contact]
def from(t: T): Contact
def subject(t: T): String
def bodyText(t: T): String
def bodyHtml(t: T): Option[(String, Seq[Annex[Attachable]])]
def attachments(t: T): Seq[Annex[Attachable]]
}
case class SendAddressException(invalid: Set[Contact], validSent: Set[Contact],
validUnsent: Set[Contact]) extends RuntimeException("the email could not be sent to all addresses")
case class SendException() extends RuntimeException("the email could not be sent")
trait SendmailBackend {
def sendmail(to: Seq[String],
from: String,
subject: String,
cc: Seq[String],
bcc: Seq[String],
bodyText: String,
bodyHtml: Option[(String, Seq[Annex[Attachable]])],
attachments: Seq[Annex[Attachable]])(implicit mode: Mode[_]): mode.Wrap[SendReport, SendAddressException with SendException]
}
================================================
FILE: mail/shared/src/main/scala/rapture/mail/plaintext.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.mail
import rapture.core._
import rapture.io._
import rapture.fs._
import rapture.uri._
import rapture.html._
import rapture.cli._, environments.enclosing._
import rapture.codec._, encodings.`UTF-8`._
package htmlToPlainTextConverters {
object elinks {
implicit val htmlToPlainTextConverter: HtmlToPlainTextConverter = new HtmlToPlainTextConverter {
def convert(html: HtmlDoc): String = {
val file = uri"file:///tmp/${Guid.generate()()}.html"
html.format.copyTo(file)
val output = sh"elinks -dump -dump-width 76 '$file'".exec[String]
file.delete()
output
}
}
}
object links {
implicit val htmlToPlainTextConverter: HtmlToPlainTextConverter = new HtmlToPlainTextConverter {
def convert(html: HtmlDoc): String = {
val file = uri"file:///tmp/${Guid.generate()()}.html"
html.format.copyTo(file)
val output = sh"links -dump 'file://$file'".exec[String]
file.delete()
output
}
}
}
object lynx {
implicit val htmlToPlainTextConverter: HtmlToPlainTextConverter = new HtmlToPlainTextConverter {
def convert(html: HtmlDoc): String = {
val file = uri"file:///tmp/${Guid.generate()()}.html"
html.format.copyTo(file)
val output = sh"lynx -dump -width=76 'file://$file'".exec[String]
file.delete()
output
}
}
}
}
trait HtmlToPlainTextConverter {
def convert(html: HtmlDoc): String
}
================================================
FILE: mime/shared/src/main/scala/rapture/mime/mime.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.mime
/** Provides a typesafe list of MIME types, including mappings from common file extensions. This
* list was produced from the public domain list of MIME types at
* http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types w*/
object MimeTypes {
private var exts = Map[String, List[MimeType]]()
private var types = Map[String, MimeType]()
def unapply(mt: String) = types.get(mt)
/** Looks up the MIME type based on a file extension. */
def extension(ext: String) = exts.get(ext).getOrElse(Nil)
/** Provides a simple wrapper around a String to represent a MIME type, and the filename
* extensions which correspond to that type. */
case class MimeType(name: String, extensions: String*) {
override def toString = name
for (ext <- extensions) exts = exts.updated(ext, this :: exts.get(ext).getOrElse(Nil))
types = types.updated(name, this)
}
val `text/plain` = MimeType("text/plain", "asc", "conf", "def", "diff", "in", "list", "log", "pot", "text", "txt")
val `application/x-www-form-urlencoded` = MimeType("application/x-www-form-urlencoded")
val `application/activemessage` = MimeType("application/activemessage")
val `application/andrew-inset` = MimeType("application/andrew-inset", "ez")
val `application/applefile` = MimeType("application/applefile")
val `application/applixware` = MimeType("application/applixware", "aw")
val `application/atom+xml` = MimeType("application/atom+xml", "atom")
val `application/atomcat+xml` = MimeType("application/atomcat+xml", "atomcat")
val `application/atomicmail` = MimeType("application/atomicmail")
val `application/atomsvc+xml` = MimeType("application/atomsvc+xml", "atomsvc")
val `application/auth-policy+xml` = MimeType("application/auth-policy+xml")
val `application/batch-smtp` = MimeType("application/batch-smtp")
val `application/beep+xml` = MimeType("application/beep+xml")
val `application/cals-1840` = MimeType("application/cals-1840")
val `application/ccxml+xml` = MimeType("application/ccxml+xml", "ccxml")
val `application/cea-2018+xml` = MimeType("application/cea-2018+xml")
val `application/cellml+xml` = MimeType("application/cellml+xml")
val `application/cnrp+xml` = MimeType("application/cnrp+xml")
val `application/commonground` = MimeType("application/commonground")
val `application/conference-info+xml` = MimeType("application/conference-info+xml")
val `application/cpl+xml` = MimeType("application/cpl+xml")
val `application/csta+xml` = MimeType("application/csta+xml")
val `application/cstadata+xml` = MimeType("application/cstadata+xml")
val `application/cu-seeme` = MimeType("application/cu-seeme", "cu")
val `application/cybercash` = MimeType("application/cybercash")
val `application/davmount+xml` = MimeType("application/davmount+xml", "davmount")
val `application/dca-rft` = MimeType("application/dca-rft")
val `application/dec-dx` = MimeType("application/dec-dx")
val `application/dialog-info+xml` = MimeType("application/dialog-info+xml")
val `application/dicom` = MimeType("application/dicom")
val `application/dns` = MimeType("application/dns")
val `application/dsptype` = MimeType("application/dsptype", "tsp")
val `application/dvcs` = MimeType("application/dvcs")
val `application/ecmascript` = MimeType("application/ecmascript", "ecma")
val `application/edi-consent` = MimeType("application/edi-consent")
val `application/edi-x12` = MimeType("application/edi-x12")
val `application/edifact` = MimeType("application/edifact")
val `application/emma+xml` = MimeType("application/emma+xml", "emma")
val `application/epp+xml` = MimeType("application/epp+xml")
val `application/epub+zip` = MimeType("application/epub+zip", "epub")
val `application/eshop` = MimeType("application/eshop")
val `application/example` = MimeType("application/example")
val `application/fastinfoset` = MimeType("application/fastinfoset")
val `application/fastsoap` = MimeType("application/fastsoap")
val `application/fits` = MimeType("application/fits")
val `application/font-tdpfr` = MimeType("application/font-tdpfr", "pfr")
val `application/futuresplash` = MimeType("application/futuresplash", "spl")
val `application/h224` = MimeType("application/h224")
val `application/hta` = MimeType("application/hta", "hta")
val `application/http` = MimeType("application/http")
val `application/hyperstudio` = MimeType("application/hyperstudio", "stk")
val `application/ibe-key-request+xml` = MimeType("application/ibe-key-request+xml")
val `application/ibe-pkg-reply+xml` = MimeType("application/ibe-pkg-reply+xml")
val `application/ibe-pp-data` = MimeType("application/ibe-pp-data")
val `application/iges` = MimeType("application/iges")
val `application/im-iscomposing+xml` = MimeType("application/im-iscomposing+xml")
val `application/index` = MimeType("application/index")
val `application/index.cmd` = MimeType("application/index.cmd")
val `application/index.obj` = MimeType("application/index.obj")
val `application/index.response` = MimeType("application/index.response")
val `application/index.vnd` = MimeType("application/index.vnd")
val `application/iotp` = MimeType("application/iotp")
val `application/ipp` = MimeType("application/ipp")
val `application/isup` = MimeType("application/isup")
val `application/java-archive` = MimeType("application/java-archive", "jar")
val `application/java-serialized-object` = MimeType("application/java-serialized-object", "ser")
val `application/java-vm` = MimeType("application/java-vm", "class")
val `application/javascript` = MimeType("application/javascript", "js")
val `application/json` = MimeType("application/json", "json")
val `application/kpml-request+xml` = MimeType("application/kpml-request+xml")
val `application/kpml-response+xml` = MimeType("application/kpml-response+xml")
val `application/lost+xml` = MimeType("application/lost+xml", "lostxml")
val `application/mac-binhex40` = MimeType("application/mac-binhex40", "hqx")
val `application/mac-compactpro` = MimeType("application/mac-compactpro", "cpt")
val `application/macwriteii` = MimeType("application/macwriteii")
val `application/marc` = MimeType("application/marc", "mrc")
val `application/mathematica` = MimeType("application/mathematica", "ma", "mb", "nb")
val `application/mathml+xml` = MimeType("application/mathml+xml", "mathml")
val `application/mbms-associated-procedure-description+xml` = MimeType(
"application/mbms-associated-procedure-description+xml")
val `application/mbms-deregister+xml` = MimeType("application/mbms-deregister+xml")
val `application/mbms-envelope+xml` = MimeType("application/mbms-envelope+xml")
val `application/mbms-msk+xml` = MimeType("application/mbms-msk+xml")
val `application/mbms-msk-response+xml` = MimeType("application/mbms-msk-response+xml")
val `application/mbms-protection-description+xml` = MimeType("application/mbms-protection-description+xml")
val `application/mbms-reception-report+xml` = MimeType("application/mbms-reception-report+xml")
val `application/mbms-register+xml` = MimeType("application/mbms-register+xml")
val `application/mbms-register-response+xml` = MimeType("application/mbms-register-response+xml")
val `application/mbms-user-service-description+xml` = MimeType("application/mbms-user-service-description+xml")
val `application/mbox` = MimeType("application/mbox", "mbox")
val `application/media_control+xml` = MimeType("application/media_control+xml")
val `application/mediaservercontrol+xml` = MimeType("application/mediaservercontrol+xml", "mscml")
val `application/mikey` = MimeType("application/mikey")
val `application/moss-keys` = MimeType("application/moss-keys")
val `application/moss-signature` = MimeType("application/moss-signature")
val `application/mosskey-data` = MimeType("application/mosskey-data")
val `application/mosskey-request` = MimeType("application/mosskey-request")
val `application/mp4` = MimeType("application/mp4", "mp4s")
val `application/mpeg4-generic` = MimeType("application/mpeg4-generic")
val `application/mpeg4-iod` = MimeType("application/mpeg4-iod")
val `application/mpeg4-iod-xmt` = MimeType("application/mpeg4-iod-xmt")
val `application/msaccess` = MimeType("application/msaccess", "mdb")
val `application/msword` = MimeType("application/msword", "doc", "dot")
val `application/mxf` = MimeType("application/mxf", "mxf")
val `application/nasdata` = MimeType("application/nasdata")
val `application/news-checkgroups` = MimeType("application/news-checkgroups")
val `application/news-groupinfo` = MimeType("application/news-groupinfo")
val `application/news-transmission` = MimeType("application/news-transmission")
val `application/nss` = MimeType("application/nss")
val `application/ocsp-request` = MimeType("application/ocsp-request")
val `application/ocsp-response` = MimeType("application/ocsp-response")
val `application/octet-stream` = MimeType("application/octet-stream",
"bin",
"bpk",
"deploy",
"dist",
"distz",
"dmg",
"dms",
"dump",
"elc",
"iso",
"lha",
"lrf",
"lzh",
"pkg",
"so")
val `application/oda` = MimeType("application/oda", "oda")
val `application/oebps-package+xml` = MimeType("application/oebps-package+xml", "opf")
val `application/ogg` = MimeType("application/ogg", "ogg", "ogx")
val `application/onenote` = MimeType("application/onenote", "onepkg", "onetmp", "onetoc", "onetoc2")
val `application/parityfec` = MimeType("application/parityfec")
val `application/patch-ops-error+xml` = MimeType("application/patch-ops-error+xml", "xer")
val `application/pdf` = MimeType("application/pdf", "pdf")
val `application/pgp-encrypted` = MimeType("application/pgp-encrypted", "pgp")
val `application/pgp-keys` = MimeType("application/pgp-keys", "key")
val `application/pgp-signature` = MimeType("application/pgp-signature", "asc", "pgp", "sig")
val `application/pics-rules` = MimeType("application/pics-rules", "prf")
val `application/pidf+xml` = MimeType("application/pidf+xml")
val `application/pidf-diff+xml` = MimeType("application/pidf-diff+xml")
val `application/pkcs10` = MimeType("application/pkcs10", "p10")
val `application/pkcs7-mime` = MimeType("application/pkcs7-mime", "p7c", "p7m")
val `application/pkcs7-signature` = MimeType("application/pkcs7-signature", "p7s")
val `application/pkix-cert` = MimeType("application/pkix-cert", "cer")
val `application/pkix-crl` = MimeType("application/pkix-crl", "crl")
val `application/pkix-pkipath` = MimeType("application/pkix-pkipath", "pkipath")
val `application/pkixcmp` = MimeType("application/pkixcmp", "pki")
val `application/pls+xml` = MimeType("application/pls+xml", "pls")
val `application/poc-settings+xml` = MimeType("application/poc-settings+xml")
val `application/postscript` = MimeType("application/postscript", "ai", "eps", "ps")
val `application/prs.alvestrand.titrax-sheet` = MimeType("application/prs.alvestrand.titrax-sheet")
val `application/prs.cww` = MimeType("application/prs.cww", "cww")
val `application/prs.nprend` = MimeType("application/prs.nprend")
val `application/prs.plucker` = MimeType("application/prs.plucker")
val `application/qsig` = MimeType("application/qsig")
val `application/rar` = MimeType("application/rar", "rar")
val `application/rdf+xml` = MimeType("application/rdf+xml", "rdf")
val `application/reginfo+xml` = MimeType("application/reginfo+xml", "rif")
val `application/relax-ng-compact-syntax` = MimeType("application/relax-ng-compact-syntax", "rnc")
val `application/remote-printing` = MimeType("application/remote-printing")
val `application/resource-lists+xml` = MimeType("application/resource-lists+xml", "rl")
val `application/resource-lists-diff+xml` = MimeType("application/resource-lists-diff+xml", "rld")
val `application/riscos` = MimeType("application/riscos")
val `application/rlmi+xml` = MimeType("application/rlmi+xml")
val `application/rls-services+xml` = MimeType("application/rls-services+xml", "rs")
val `application/rsd+xml` = MimeType("application/rsd+xml", "rsd")
val `application/rss+xml` = MimeType("application/rss+xml", "rss")
val `application/rtf` = MimeType("application/rtf", "rtf")
val `application/rtx` = MimeType("application/rtx")
val `application/samlassertion+xml` = MimeType("application/samlassertion+xml")
val `application/samlmetadata+xml` = MimeType("application/samlmetadata+xml")
val `application/sbml+xml` = MimeType("application/sbml+xml", "sbml")
val `application/scvp-cv-request` = MimeType("application/scvp-cv-request", "scq")
val `application/scvp-cv-response` = MimeType("application/scvp-cv-response", "scs")
val `application/scvp-vp-request` = MimeType("application/scvp-vp-request", "spq")
val `application/scvp-vp-response` = MimeType("application/scvp-vp-response", "spp")
val `application/sdp` = MimeType("application/sdp", "sdp")
val `application/set-payment` = MimeType("application/set-payment")
val `application/set-payment-initiation` = MimeType("application/set-payment-initiation", "setpay")
val `application/set-registration` = MimeType("application/set-registration")
val `application/set-registration-initiation` = MimeType("application/set-registration-initiation", "setreg")
val `application/sgml` = MimeType("application/sgml")
val `application/sgml-open-catalog` = MimeType("application/sgml-open-catalog")
val `application/shf+xml` = MimeType("application/shf+xml", "shf")
val `application/sieve` = MimeType("application/sieve")
val `application/simple-filter+xml` = MimeType("application/simple-filter+xml")
val `application/simple-message-summary` = MimeType("application/simple-message-summary")
val `application/simplesymbolcontainer` = MimeType("application/simplesymbolcontainer")
val `application/slate` = MimeType("application/slate")
val `application/smil` = MimeType("application/smil", "smi", "smil")
val `application/smil+xml` = MimeType("application/smil+xml", "smi", "smil")
val `application/soap+fastinfoset` = MimeType("application/soap+fastinfoset")
val `application/soap+xml` = MimeType("application/soap+xml")
val `application/sparql-query` = MimeType("application/sparql-query", "rq")
val `application/sparql-results+xml` = MimeType("application/sparql-results+xml", "srx")
val `application/spirits-event+xml` = MimeType("application/spirits-event+xml")
val `application/srgs` = MimeType("application/srgs", "gram")
val `application/srgs+xml` = MimeType("application/srgs+xml", "grxml")
val `application/ssml+xml` = MimeType("application/ssml+xml", "ssml")
val `application/timestamp-query` = MimeType("application/timestamp-query")
val `application/timestamp-reply` = MimeType("application/timestamp-reply")
val `application/tve-trigger` = MimeType("application/tve-trigger")
val `application/ulpfec` = MimeType("application/ulpfec")
val `application/vemmi` = MimeType("application/vemmi")
val `application/vividence.scriptfile` = MimeType("application/vividence.scriptfile")
val `application/vnd.3gpp.bsf+xml` = MimeType("application/vnd.3gpp.bsf+xml")
val `application/vnd.3gpp.pic-bw-large` = MimeType("application/vnd.3gpp.pic-bw-large", "plb")
val `application/vnd.3gpp.pic-bw-small` = MimeType("application/vnd.3gpp.pic-bw-small", "psb")
val `application/vnd.3gpp.pic-bw-var` = MimeType("application/vnd.3gpp.pic-bw-var", "pvb")
val `application/vnd.3gpp.sms` = MimeType("application/vnd.3gpp.sms")
val `application/vnd.3gpp2.bcmcsinfo+xml` = MimeType("application/vnd.3gpp2.bcmcsinfo+xml")
val `application/vnd.3gpp2.sms` = MimeType("application/vnd.3gpp2.sms")
val `application/vnd.3gpp2.tcap` = MimeType("application/vnd.3gpp2.tcap", "tcap")
val `application/vnd.3m.post-it-notes` = MimeType("application/vnd.3m.post-it-notes", "pwn")
val `application/vnd.accpac.simply.aso` = MimeType("application/vnd.accpac.simply.aso", "aso")
val `application/vnd.accpac.simply.imp` = MimeType("application/vnd.accpac.simply.imp", "imp")
val `application/vnd.acucobol` = MimeType("application/vnd.acucobol", "acu")
val `application/vnd.acucorp` = MimeType("application/vnd.acucorp", "acutc", "atc")
val `application/vnd.adobe.air-application-installer-package+zip` =
MimeType("application/vnd.adobe.air-application-installer-package+zip", "air")
val `application/vnd.adobe.xdp+xml` = MimeType("application/vnd.adobe.xdp+xml", "xdp")
val `application/vnd.adobe.xfdf` = MimeType("application/vnd.adobe.xfdf", "xfdf")
val `application/vnd.aether.imp` = MimeType("application/vnd.aether.imp")
val `application/vnd.airzip.filesecure.azf` = MimeType("application/vnd.airzip.filesecure.azf", "azf")
val `application/vnd.airzip.filesecure.azs` = MimeType("application/vnd.airzip.filesecure.azs", "azs")
val `application/vnd.amazon.ebook` = MimeType("application/vnd.amazon.ebook", "azw")
val `application/vnd.americandynamics.acc` = MimeType("application/vnd.americandynamics.acc", "acc")
val `application/vnd.amiga.ami` = MimeType("application/vnd.amiga.ami", "ami")
val `application/vnd.android.package-archive` = MimeType("application/vnd.android.package-archive", "apk")
val `application/vnd.anser-web-certificate-issue-initiation` =
MimeType("application/vnd.anser-web-certificate-issue-initiation", "cii")
val `application/vnd.anser-web-funds-transfer-initiation` =
MimeType("application/vnd.anser-web-funds-transfer-initiation", "fti")
val `application/vnd.antix.game-component` = MimeType("application/vnd.antix.game-component", "atx")
val `application/vnd.apple.installer+xml` = MimeType("application/vnd.apple.installer+xml", "mpkg")
val `application/vnd.arastra.swi` = MimeType("application/vnd.arastra.swi", "swi")
val `application/vnd.audiograph` = MimeType("application/vnd.audiograph", "aep")
val `application/vnd.autopackage` = MimeType("application/vnd.autopackage")
val `application/vnd.avistar+xml` = MimeType("application/vnd.avistar+xml")
val `application/vnd.blueice.multipass` = MimeType("application/vnd.blueice.multipass", "mpm")
val `application/vnd.bluetooth.ep.oob` = MimeType("application/vnd.bluetooth.ep.oob")
val `application/vnd.bmi` = MimeType("application/vnd.bmi", "bmi")
val `application/vnd.businessobjects` = MimeType("application/vnd.businessobjects", "rep")
val `application/vnd.cab-jscript` = MimeType("application/vnd.cab-jscript")
val `application/vnd.canon-cpdl` = MimeType("application/vnd.canon-cpdl")
val `application/vnd.canon-lips` = MimeType("application/vnd.canon-lips")
val `application/vnd.cendio.thinlinc.clientconf` = MimeType("application/vnd.cendio.thinlinc.clientconf")
val `application/vnd.chemdraw+xml` = MimeType("application/vnd.chemdraw+xml", "cdxml")
val `application/vnd.chipnuts.karaoke-mmd` = MimeType("application/vnd.chipnuts.karaoke-mmd", "mmd")
val `application/vnd.cinderella` = MimeType("application/vnd.cinderella", "cdy")
val `application/vnd.cirpack.isdn-ext` = MimeType("application/vnd.cirpack.isdn-ext")
val `application/vnd.claymore` = MimeType("application/vnd.claymore", "cla")
val `application/vnd.clonk.c4group` = MimeType("application/vnd.clonk.c4group", "c4d", "c4f", "c4g", "c4p", "c4u")
val `application/vnd.commerce-battelle` = MimeType("application/vnd.commerce-battelle")
val `application/vnd.commonspace` = MimeType("application/vnd.commonspace", "csp")
val `application/vnd.contact.cmsg` = MimeType("application/vnd.contact.cmsg", "cdbcmsg")
val `application/vnd.cosmocaller` = MimeType("application/vnd.cosmocaller", "cmc")
val `application/vnd.crick.clicker` = MimeType("application/vnd.crick.clicker", "clkx")
val `application/vnd.crick.clicker.keyboard` = MimeType("application/vnd.crick.clicker.keyboard", "clkk")
val `application/vnd.crick.clicker.palette` = MimeType("application/vnd.crick.clicker.palette", "clkp")
val `application/vnd.crick.clicker.template` = MimeType("application/vnd.crick.clicker.template", "clkt")
val `application/vnd.crick.clicker.wordbank` = MimeType("application/vnd.crick.clicker.wordbank", "clkw")
val `application/vnd.criticaltools.wbs+xml` = MimeType("application/vnd.criticaltools.wbs+xml", "wbs")
val `application/vnd.ctc-posml` = MimeType("application/vnd.ctc-posml", "pml")
val `application/vnd.ctct.ws+xml` = MimeType("application/vnd.ctct.ws+xml")
val `application/vnd.cups-pdf` = MimeType("application/vnd.cups-pdf")
val `application/vnd.cups-postscript` = MimeType("application/vnd.cups-postscript")
val `application/vnd.cups-ppd` = MimeType("application/vnd.cups-ppd", "ppd")
val `application/vnd.cups-raster` = MimeType("application/vnd.cups-raster")
val `application/vnd.cups-raw` = MimeType("application/vnd.cups-raw")
val `application/vnd.curl.car` = MimeType("application/vnd.curl.car", "car")
val `application/vnd.curl.pcurl` = MimeType("application/vnd.curl.pcurl", "pcurl")
val `application/vnd.cybank` = MimeType("application/vnd.cybank")
val `application/vnd.data-vision.rdz` = MimeType("application/vnd.data-vision.rdz", "rdz")
val `application/vnd.denovo.fcselayout-link` = MimeType("application/vnd.denovo.fcselayout-link", "fe", "_launch")
val `application/vnd.dir-bi.plate-dl-nosuffix` = MimeType("application/vnd.dir-bi.plate-dl-nosuffix")
val `application/vnd.dna` = MimeType("application/vnd.dna", "dna")
val `application/vnd.dolby.mlp` = MimeType("application/vnd.dolby.mlp", "mlp")
val `application/vnd.dolby.mobile.1` = MimeType("application/vnd.dolby.mobile.1")
val `application/vnd.dolby.mobile.2` = MimeType("application/vnd.dolby.mobile.2")
val `application/vnd.dpgraph` = MimeType("application/vnd.dpgraph", "dpg")
val `application/vnd.dreamfactory` = MimeType("application/vnd.dreamfactory", "dfac")
val `application/vnd.dvb.esgcontainer` = MimeType("application/vnd.dvb.esgcontainer")
val `application/vnd.dvb.ipdcdftnotifaccess` = MimeType("application/vnd.dvb.ipdcdftnotifaccess")
val `application/vnd.dvb.ipdcesgaccess` = MimeType("application/vnd.dvb.ipdcesgaccess")
val `application/vnd.dvb.ipdcroaming` = MimeType("application/vnd.dvb.ipdcroaming")
val `application/vnd.dvb.iptv.alfec-base` = MimeType("application/vnd.dvb.iptv.alfec-base")
val `application/vnd.dvb.iptv.alfec-enhancement` = MimeType("application/vnd.dvb.iptv.alfec-enhancement")
val `application/vnd.dvb.notif-aggregate-root+xml` = MimeType("application/vnd.dvb.notif-aggregate-root+xml")
val `application/vnd.dvb.notif-container+xml` = MimeType("application/vnd.dvb.notif-container+xml")
val `application/vnd.dvb.notif-generic+xml` = MimeType("application/vnd.dvb.notif-generic+xml")
val `application/vnd.dvb.notif-ia-msglist+xml` = MimeType("application/vnd.dvb.notif-ia-msglist+xml")
val `application/vnd.dvb.notif-ia-registration-request+xml` = MimeType(
"application/vnd.dvb.notif-ia-registration-request+xml")
val `application/vnd.dvb.notif-ia-registration-response+xml` = MimeType(
"application/vnd.dvb.notif-ia-registration-response+xml")
val `application/vnd.dvb.notif-init+xml` = MimeType("application/vnd.dvb.notif-init+xml")
val `application/vnd.dxr` = MimeType("application/vnd.dxr")
val `application/vnd.dynageo` = MimeType("application/vnd.dynageo", "geo")
val `application/vnd.ecdis-update` = MimeType("application/vnd.ecdis-update")
val `application/vnd.ecowin.chart` = MimeType("application/vnd.ecowin.chart", "mag")
val `application/vnd.ecowin.filerequest` = MimeType("application/vnd.ecowin.filerequest")
val `application/vnd.ecowin.fileupdate` = MimeType("application/vnd.ecowin.fileupdate")
val `application/vnd.ecowin.series` = MimeType("application/vnd.ecowin.series")
val `application/vnd.ecowin.seriesrequest` = MimeType("application/vnd.ecowin.seriesrequest")
val `application/vnd.ecowin.seriesupdate` = MimeType("application/vnd.ecowin.seriesupdate")
val `application/vnd.emclient.accessrequest+xml` = MimeType("application/vnd.emclient.accessrequest+xml")
val `application/vnd.enliven` = MimeType("application/vnd.enliven", "nml")
val `application/vnd.epson.esf` = MimeType("application/vnd.epson.esf", "esf")
val `application/vnd.epson.msf` = MimeType("application/vnd.epson.msf", "msf")
val `application/vnd.epson.quickanime` = MimeType("application/vnd.epson.quickanime", "qam")
val `application/vnd.epson.salt` = MimeType("application/vnd.epson.salt", "slt")
val `application/vnd.epson.ssf` = MimeType("application/vnd.epson.ssf", "ssf")
val `application/vnd.ericsson.quickcall` = MimeType("application/vnd.ericsson.quickcall")
val `application/vnd.eszigno3+xml` = MimeType("application/vnd.eszigno3+xml", "es3", "et3")
val `application/vnd.etsi.aoc+xml` = MimeType("application/vnd.etsi.aoc+xml")
val `application/vnd.etsi.cug+xml` = MimeType("application/vnd.etsi.cug+xml")
val `application/vnd.etsi.iptvcommand+xml` = MimeType("application/vnd.etsi.iptvcommand+xml")
val `application/vnd.etsi.iptvdiscovery+xml` = MimeType("application/vnd.etsi.iptvdiscovery+xml")
val `application/vnd.etsi.iptvprofile+xml` = MimeType("application/vnd.etsi.iptvprofile+xml")
val `application/vnd.etsi.iptvsad-bc+xml` = MimeType("application/vnd.etsi.iptvsad-bc+xml")
val `application/vnd.etsi.iptvsad-cod+xml` = MimeType("application/vnd.etsi.iptvsad-cod+xml")
val `application/vnd.etsi.iptvsad-npvr+xml` = MimeType("application/vnd.etsi.iptvsad-npvr+xml")
val `application/vnd.etsi.iptvueprofile+xml` = MimeType("application/vnd.etsi.iptvueprofile+xml")
val `application/vnd.etsi.mcid+xml` = MimeType("application/vnd.etsi.mcid+xml")
val `application/vnd.etsi.sci+xml` = MimeType("application/vnd.etsi.sci+xml")
val `application/vnd.etsi.simservs+xml` = MimeType("application/vnd.etsi.simservs+xml")
val `application/vnd.eudora.data` = MimeType("application/vnd.eudora.data")
val `application/vnd.ezpix-album` = MimeType("application/vnd.ezpix-album", "ez2")
val `application/vnd.ezpix-package` = MimeType("application/vnd.ezpix-package", "ez3")
val `application/vnd.f-secure.mobile` = MimeType("application/vnd.f-secure.mobile")
val `application/vnd.fdf` = MimeType("application/vnd.fdf", "fdf")
val `application/vnd.fdsn.mseed` = MimeType("application/vnd.fdsn.mseed", "mseed")
val `application/vnd.fdsn.seed` = MimeType("application/vnd.fdsn.seed", "dataless", "seed")
val `application/vnd.ffsns` = MimeType("application/vnd.ffsns")
val `application/vnd.fints` = MimeType("application/vnd.fints")
val `application/vnd.flographit` = MimeType("application/vnd.flographit", "gph")
val `application/vnd.fluxtime.clip` = MimeType("application/vnd.fluxtime.clip", "ftc")
val `application/vnd.font-fontforge-sfd` = MimeType("application/vnd.font-fontforge-sfd")
val `application/vnd.framemaker` = MimeType("application/vnd.framemaker", "book", "fm", "frame", "maker")
val `application/vnd.frogans.fnc` = MimeType("application/vnd.frogans.fnc", "fnc")
val `application/vnd.frogans.ltf` = MimeType("application/vnd.frogans.ltf", "ltf")
val `application/vnd.fsc.weblaunch` = MimeType("application/vnd.fsc.weblaunch", "fsc")
val `application/vnd.fujitsu.oasys` = MimeType("application/vnd.fujitsu.oasys", "oas")
val `application/vnd.fujitsu.oasys2` = MimeType("application/vnd.fujitsu.oasys2", "oa2")
val `application/vnd.fujitsu.oasys3` = MimeType("application/vnd.fujitsu.oasys3", "oa3")
val `application/vnd.fujitsu.oasysgp` = MimeType("application/vnd.fujitsu.oasysgp", "fg5")
val `application/vnd.fujitsu.oasysprs` = MimeType("application/vnd.fujitsu.oasysprs", "bh2")
val `application/vnd.fujixerox.art-ex` = MimeType("application/vnd.fujixerox.art-ex")
val `application/vnd.fujixerox.art4` = MimeType("application/vnd.fujixerox.art4")
val `application/vnd.fujixerox.ddd` = MimeType("application/vnd.fujixerox.ddd", "ddd")
val `application/vnd.fujixerox.docuworks` = MimeType("application/vnd.fujixerox.docuworks", "xdw")
val `application/vnd.fujixerox.docuworks.binder` = MimeType("application/vnd.fujixerox.docuworks.binder", "xbd")
val `application/vnd.fujixerox.hbpl` = MimeType("application/vnd.fujixerox.hbpl")
val `application/vnd.fut-misnet` = MimeType("application/vnd.fut-misnet")
val `application/vnd.fuzzysheet` = MimeType("application/vnd.fuzzysheet", "fzs")
val `application/vnd.genomatix.tuxedo` = MimeType("application/vnd.genomatix.tuxedo", "txd")
val `application/vnd.geogebra.file` = MimeType("application/vnd.geogebra.file", "ggb")
val `application/vnd.geogebra.tool` = MimeType("application/vnd.geogebra.tool", "ggt")
val `application/vnd.geometry-explorer` = MimeType("application/vnd.geometry-explorer", "gex", "gre")
val `application/vnd.gmx` = MimeType("application/vnd.gmx", "gmx")
val `application/vnd.google-earth.kml+xml` = MimeType("application/vnd.google-earth.kml+xml", "kml")
val `application/vnd.google-earth.kmz` = MimeType("application/vnd.google-earth.kmz", "kmz")
val `application/vnd.grafeq` = MimeType("application/vnd.grafeq", "gqf", "gqs")
val `application/vnd.gridmp` = MimeType("application/vnd.gridmp")
val `application/vnd.groove-account` = MimeType("application/vnd.groove-account", "gac")
val `application/vnd.groove-help` = MimeType("application/vnd.groove-help", "ghf")
val `application/vnd.groove-identity-message` = MimeType("application/vnd.groove-identity-message", "gim")
val `application/vnd.groove-injector` = MimeType("application/vnd.groove-injector", "grv")
val `application/vnd.groove-tool-message` = MimeType("application/vnd.groove-tool-message", "gtm")
val `application/vnd.groove-tool-template` = MimeType("application/vnd.groove-tool-template", "tpl")
val `application/vnd.groove-vcard` = MimeType("application/vnd.groove-vcard", "vcg")
val `application/vnd.handheld-entertainment+xml` = MimeType("application/vnd.handheld-entertainment+xml", "zmm")
val `application/vnd.hbci` = MimeType("application/vnd.hbci", "hbci")
val `application/vnd.hcl-bireports` = MimeType("application/vnd.hcl-bireports")
val `application/vnd.hhe.lesson-player` = MimeType("application/vnd.hhe.lesson-player", "les")
val `application/vnd.hp-hpgl` = MimeType("application/vnd.hp-hpgl", "hpgl")
val `application/vnd.hp-hpid` = MimeType("application/vnd.hp-hpid", "hpid")
val `application/vnd.hp-hps` = MimeType("application/vnd.hp-hps", "hps")
val `application/vnd.hp-jlyt` = MimeType("application/vnd.hp-jlyt", "jlt")
val `application/vnd.hp-pcl` = MimeType("application/vnd.hp-pcl", "pcl")
val `application/vnd.hp-pclxl` = MimeType("application/vnd.hp-pclxl", "pclxl")
val `application/vnd.httphone` = MimeType("application/vnd.httphone")
val `application/vnd.hydrostatix.sof-data` = MimeType("application/vnd.hydrostatix.sof-data", "sfd", "-hdstx")
val `application/vnd.hzn-3d-crossword` = MimeType("application/vnd.hzn-3d-crossword", "x3d")
val `application/vnd.ibm.afplinedata` = MimeType("application/vnd.ibm.afplinedata")
val `application/vnd.ibm.electronic-media` = MimeType("application/vnd.ibm.electronic-media")
val `application/vnd.ibm.minipay` = MimeType("application/vnd.ibm.minipay", "mpy")
val `application/vnd.ibm.modcap` = MimeType("application/vnd.ibm.modcap", "afp", "list3820", "listafp")
val `application/vnd.ibm.rights-management` = MimeType("application/vnd.ibm.rights-management", "irm")
val `application/vnd.ibm.secure-container` = MimeType("application/vnd.ibm.secure-container", "sc")
val `application/vnd.iccprofile` = MimeType("application/vnd.iccprofile", "icc", "icm")
val `application/vnd.igloader` = MimeType("application/vnd.igloader", "igl")
val `application/vnd.immervision-ivp` = MimeType("application/vnd.immervision-ivp", "ivp")
val `application/vnd.immervision-ivu` = MimeType("application/vnd.immervision-ivu", "ivu")
val `application/vnd.informedcontrol.rms+xml` = MimeType("application/vnd.informedcontrol.rms+xml")
val `application/vnd.informix-visionary` = MimeType("application/vnd.informix-visionary")
val `application/vnd.intercon.formnet` = MimeType("application/vnd.intercon.formnet", "xpw", "xpx")
val `application/vnd.intertrust.digibox` = MimeType("application/vnd.intertrust.digibox")
val `application/vnd.intertrust.nncp` = MimeType("application/vnd.intertrust.nncp")
val `application/vnd.intu.qbo` = MimeType("application/vnd.intu.qbo", "qbo")
val `application/vnd.intu.qfx` = MimeType("application/vnd.intu.qfx", "qfx")
val `application/vnd.iptc.g2.conceptitem+xml` = MimeType("application/vnd.iptc.g2.conceptitem+xml")
val `application/vnd.iptc.g2.knowledgeitem+xml` = MimeType("application/vnd.iptc.g2.knowledgeitem+xml")
val `application/vnd.iptc.g2.newsitem+xml` = MimeType("application/vnd.iptc.g2.newsitem+xml")
val `application/vnd.iptc.g2.packageitem+xml` = MimeType("application/vnd.iptc.g2.packageitem+xml")
val `application/vnd.ipunplugged.rcprofile` = MimeType("application/vnd.ipunplugged.rcprofile", "rcprofile")
val `application/vnd.irepository.package+xml` = MimeType("application/vnd.irepository.package+xml", "irp")
val `application/vnd.is-xpr` = MimeType("application/vnd.is-xpr", "xpr")
val `application/vnd.jam` = MimeType("application/vnd.jam", "jam")
val `application/vnd.japannet-directory-service` = MimeType("application/vnd.japannet-directory-service")
val `application/vnd.japannet-jpnstore-wakeup` = MimeType("application/vnd.japannet-jpnstore-wakeup")
val `application/vnd.japannet-payment-wakeup` = MimeType("application/vnd.japannet-payment-wakeup")
val `application/vnd.japannet-registration` = MimeType("application/vnd.japannet-registration")
val `application/vnd.japannet-registration-wakeup` = MimeType("application/vnd.japannet-registration-wakeup")
val `application/vnd.japannet-setstore-wakeup` = MimeType("application/vnd.japannet-setstore-wakeup")
val `application/vnd.japannet-verification` = MimeType("application/vnd.japannet-verification")
val `application/vnd.japannet-verification-wakeup` = MimeType("application/vnd.japannet-verification-wakeup")
val `application/vnd.jcp.javame.midlet-rms` = MimeType("application/vnd.jcp.javame.midlet-rms", "rms")
val `application/vnd.jisp` = MimeType("application/vnd.jisp", "jisp")
val `application/vnd.joost.joda-archive` = MimeType("application/vnd.joost.joda-archive", "joda")
val `application/vnd.kahootz` = MimeType("application/vnd.kahootz", "ktr", "ktz")
val `application/vnd.kde.karbon` = MimeType("application/vnd.kde.karbon", "karbon")
val `application/vnd.kde.kchart` = MimeType("application/vnd.kde.kchart", "chrt")
val `application/vnd.kde.kformula` = MimeType("application/vnd.kde.kformula", "kfo")
val `application/vnd.kde.kivio` = MimeType("application/vnd.kde.kivio", "flw")
val `application/vnd.kde.kontour` = MimeType("application/vnd.kde.kontour", "kon")
val `application/vnd.kde.kpresenter` = MimeType("application/vnd.kde.kpresenter", "kpr", "kpt")
val `application/vnd.kde.kspread` = MimeType("application/vnd.kde.kspread", "ksp")
val `application/vnd.kde.kword` = MimeType("application/vnd.kde.kword", "kwd", "kwt")
val `application/vnd.kenameaapp` = MimeType("application/vnd.kenameaapp", "htke")
val `application/vnd.kidspiration` = MimeType("application/vnd.kidspiration", "kia")
val `application/vnd.kinar` = MimeType("application/vnd.kinar", "kne", "knp")
val `application/vnd.koan` = MimeType("application/vnd.koan", "skd", "skm", "skp", "skt")
val `application/vnd.kodak-descriptor` = MimeType("application/vnd.kodak-descriptor", "sse")
val `application/vnd.liberty-request+xml` = MimeType("application/vnd.liberty-request+xml")
val `application/vnd.llamagraphics.life-balance.desktop` =
MimeType("application/vnd.llamagraphics.life-balance.desktop", "lbd")
val `application/vnd.llamagraphics.life-balance.exchange+xml` =
MimeType("application/vnd.llamagraphics.life-balance.exchange+xml", "lbe")
val `application/vnd.lotus-1-2-3` = MimeType("application/vnd.lotus-1-2-3", "123")
val `application/vnd.lotus-approach` = MimeType("application/vnd.lotus-approach", "apr")
val `application/vnd.lotus-freelance` = MimeType("application/vnd.lotus-freelance", "pre")
val `application/vnd.lotus-notes` = MimeType("application/vnd.lotus-notes", "nsf")
val `application/vnd.lotus-organizer` = MimeType("application/vnd.lotus-organizer", "org")
val `application/vnd.lotus-screencam` = MimeType("application/vnd.lotus-screencam", "scm")
val `application/vnd.lotus-wordpro` = MimeType("application/vnd.lotus-wordpro", "lwp")
val `application/vnd.macports.portpkg` = MimeType("application/vnd.macports.portpkg", "portpkg")
val `application/vnd.marlin.drm.actiontoken+xml` = MimeType("application/vnd.marlin.drm.actiontoken+xml")
val `application/vnd.marlin.drm.conftoken+xml` = MimeType("application/vnd.marlin.drm.conftoken+xml")
val `application/vnd.marlin.drm.license+xml` = MimeType("application/vnd.marlin.drm.license+xml")
val `application/vnd.marlin.drm.mdcf` = MimeType("application/vnd.marlin.drm.mdcf")
val `application/vnd.mcd` = MimeType("application/vnd.mcd", "mcd")
val `application/vnd.medcalcdata` = MimeType("application/vnd.medcalcdata", "mc1")
val `application/vnd.mediastation.cdkey` = MimeType("application/vnd.mediastation.cdkey", "cdkey")
val `application/vnd.meridian-slingshot` = MimeType("application/vnd.meridian-slingshot")
val `application/vnd.mfer` = MimeType("application/vnd.mfer", "mwf")
val `application/vnd.mfmp` = MimeType("application/vnd.mfmp", "mfm")
val `application/vnd.micrografx.flo` = MimeType("application/vnd.micrografx.flo", "flo")
val `application/vnd.micrografx.igx` = MimeType("application/vnd.micrografx.igx", "igx")
val `application/vnd.mif` = MimeType("application/vnd.mif", "mif")
val `application/vnd.minisoft-hp3000-save` = MimeType("application/vnd.minisoft-hp3000-save")
val `application/vnd.mitsubishi.misty-guard.trustweb` = MimeType("application/vnd.mitsubishi.misty-guard.trustweb")
val `application/vnd.mobius.daf` = MimeType("application/vnd.mobius.daf", "daf")
val `application/vnd.mobius.dis` = MimeType("application/vnd.mobius.dis", "dis")
val `application/vnd.mobius.mbk` = MimeType("application/vnd.mobius.mbk", "mbk")
val `application/vnd.mobius.mqy` = MimeType("application/vnd.mobius.mqy", "mqy")
val `application/vnd.mobius.msl` = MimeType("application/vnd.mobius.msl", "msl")
val `application/vnd.mobius.plc` = MimeType("application/vnd.mobius.plc", "plc")
val `application/vnd.mobius.txf` = MimeType("application/vnd.mobius.txf", "txf")
val `application/vnd.mophun.application` = MimeType("application/vnd.mophun.application", "mpn")
val `application/vnd.mophun.certificate` = MimeType("application/vnd.mophun.certificate", "mpc")
val `application/vnd.motorola.flexsuite` = MimeType("application/vnd.motorola.flexsuite")
val `application/vnd.motorola.flexsuite.adsi` = MimeType("application/vnd.motorola.flexsuite.adsi")
val `application/vnd.motorola.flexsuite.fis` = MimeType("application/vnd.motorola.flexsuite.fis")
val `application/vnd.motorola.flexsuite.gotap` = MimeType("application/vnd.motorola.flexsuite.gotap")
val `application/vnd.motorola.flexsuite.kmr` = MimeType("application/vnd.motorola.flexsuite.kmr")
val `application/vnd.motorola.flexsuite.ttc` = MimeType("application/vnd.motorola.flexsuite.ttc")
val `application/vnd.motorola.flexsuite.wem` = MimeType("application/vnd.motorola.flexsuite.wem")
val `application/vnd.motorola.iprm` = MimeType("application/vnd.motorola.iprm")
val `application/vnd.mozilla.xul+xml` = MimeType("application/vnd.mozilla.xul+xml", "xul")
val `application/vnd.ms-artgalry` = MimeType("application/vnd.ms-artgalry", "cil")
val `application/vnd.ms-asf` = MimeType("application/vnd.ms-asf")
val `application/vnd.ms-cab-compressed` = MimeType("application/vnd.ms-cab-compressed", "cab")
val `application/vnd.ms-excel` =
MimeType("application/vnd.ms-excel", "xla", "xlb", "xlc", "xlm", "xls", "xlt", "xlw")
val `application/vnd.ms-excel.addin.macroenabled.12` =
MimeType("application/vnd.ms-excel.addin.macroenabled.12", "xlam")
val `application/vnd.ms-excel.sheet.binary.macroenabled.12` =
MimeType("application/vnd.ms-excel.sheet.binary.macroenabled.12", "xlsb")
val `application/vnd.ms-excel.sheet.macroenabled.12` =
MimeType("application/vnd.ms-excel.sheet.macroenabled.12", "xlsm")
val `application/vnd.ms-excel.template.macroenabled.12` =
MimeType("application/vnd.ms-excel.template.macroenabled.12", "xltm")
val `application/vnd.ms-fontobject` = MimeType("application/vnd.ms-fontobject", "eot")
val `application/vnd.ms-htmlhelp` = MimeType("application/vnd.ms-htmlhelp", "chm")
val `application/vnd.ms-ims` = MimeType("application/vnd.ms-ims", "ims")
val `application/vnd.ms-lrm` = MimeType("application/vnd.ms-lrm", "lrm")
val `application/vnd.ms-pki.seccat` = MimeType("application/vnd.ms-pki.seccat", "cat")
val `application/vnd.ms-pki.stl` = MimeType("application/vnd.ms-pki.stl", "stl")
val `application/vnd.ms-playready.initiator+xml` = MimeType("application/vnd.ms-playready.initiator+xml")
val `application/vnd.ms-powerpoint` = MimeType("application/vnd.ms-powerpoint", "pot", "pps", "ppt")
val `application/vnd.ms-powerpoint.addin.macroenabled.12` =
MimeType("application/vnd.ms-powerpoint.addin.macroenabled.12", "ppam")
val `application/vnd.ms-powerpoint.presentation.macroenabled.12` =
MimeType("application/vnd.ms-powerpoint.presentation.macroenabled.12", "pptm")
val `application/vnd.ms-powerpoint.slide.macroenabled.12` =
MimeType("application/vnd.ms-powerpoint.slide.macroenabled.12", "sldm")
val `application/vnd.ms-powerpoint.slideshow.macroenabled.12` =
MimeType("application/vnd.ms-powerpoint.slideshow.macroenabled.12", "ppsm")
val `application/vnd.ms-powerpoint.template.macroenabled.12` =
MimeType("application/vnd.ms-powerpoint.template.macroenabled.12", "potm")
val `application/vnd.ms-project` = MimeType("application/vnd.ms-project", "mpp", "mpt")
val `application/vnd.ms-tnef` = MimeType("application/vnd.ms-tnef")
val `application/vnd.ms-wmdrm.lic-chlg-req` = MimeType("application/vnd.ms-wmdrm.lic-chlg-req")
val `application/vnd.ms-wmdrm.lic-resp` = MimeType("application/vnd.ms-wmdrm.lic-resp")
val `application/vnd.ms-wmdrm.meter-chlg-req` = MimeType("application/vnd.ms-wmdrm.meter-chlg-req")
val `application/vnd.ms-wmdrm.meter-resp` = MimeType("application/vnd.ms-wmdrm.meter-resp")
val `application/vnd.ms-word.document.macroenabled.12` =
MimeType("application/vnd.ms-word.document.macroenabled.12", "docm")
val `application/vnd.ms-word.template.macroenabled.12` =
MimeType("application/vnd.ms-word.template.macroenabled.12", "dotm")
val `application/vnd.ms-works` = MimeType("application/vnd.ms-works", "wcm", "wdb", "wks", "wps")
val `application/vnd.ms-wpl` = MimeType("application/vnd.ms-wpl", "wpl")
val `application/vnd.ms-xpsdocument` = MimeType("application/vnd.ms-xpsdocument", "xps")
val `application/vnd.mseq` = MimeType("application/vnd.mseq", "mseq")
val `application/vnd.msign` = MimeType("application/vnd.msign")
val `application/vnd.multiad.creator` = MimeType("application/vnd.multiad.creator")
val `application/vnd.multiad.creator.cif` = MimeType("application/vnd.multiad.creator.cif")
val `application/vnd.music-niff` = MimeType("application/vnd.music-niff")
val `application/vnd.musician` = MimeType("application/vnd.musician", "mus")
val `application/vnd.muvee.style` = MimeType("application/vnd.muvee.style", "msty")
val `application/vnd.ncd.control` = MimeType("application/vnd.ncd.control")
val `application/vnd.ncd.reference` = MimeType("application/vnd.ncd.reference")
val `application/vnd.nervana` = MimeType("application/vnd.nervana")
val `application/vnd.netfpx` = MimeType("application/vnd.netfpx")
val `application/vnd.neurolanguage.nlu` = MimeType("application/vnd.neurolanguage.nlu", "nlu")
val `application/vnd.noblenet-directory` = MimeType("application/vnd.noblenet-directory", "nnd")
val `application/vnd.noblenet-sealer` = MimeType("application/vnd.noblenet-sealer", "nns")
val `application/vnd.noblenet-web` = MimeType("application/vnd.noblenet-web", "nnw")
val `application/vnd.nokia.catalogs` = MimeType("application/vnd.nokia.catalogs")
val `application/vnd.nokia.conml+wbxml` = MimeType("application/vnd.nokia.conml+wbxml")
val `application/vnd.nokia.conml+xml` = MimeType("application/vnd.nokia.conml+xml")
val `application/vnd.nokia.iptv.config+xml` = MimeType("application/vnd.nokia.iptv.config+xml")
val `application/vnd.nokia.isds-radio-presets` = MimeType("application/vnd.nokia.isds-radio-presets")
val `application/vnd.nokia.landmark+wbxml` = MimeType("application/vnd.nokia.landmark+wbxml")
val `application/vnd.nokia.landmark+xml` = MimeType("application/vnd.nokia.landmark+xml")
val `application/vnd.nokia.landmarkcollection+xml` = MimeType("application/vnd.nokia.landmarkcollection+xml")
val `application/vnd.nokia.n-gage.ac+xml` = MimeType("application/vnd.nokia.n-gage.ac+xml")
val `application/vnd.nokia.n-gage.data` = MimeType("application/vnd.nokia.n-gage.data", "ngdat")
val `application/vnd.nokia.n-gage.symbian.install` =
MimeType("application/vnd.nokia.n-gage.symbian.install", "n", "-gage")
val `application/vnd.nokia.ncd` = MimeType("application/vnd.nokia.ncd")
val `application/vnd.nokia.pcd+wbxml` = MimeType("application/vnd.nokia.pcd+wbxml")
val `application/vnd.nokia.pcd+xml` = MimeType("application/vnd.nokia.pcd+xml")
val `application/vnd.nokia.radio-preset` = MimeType("application/vnd.nokia.radio-preset", "rpst")
val `application/vnd.nokia.radio-presets` = MimeType("application/vnd.nokia.radio-presets", "rpss")
val `application/vnd.novadigm.edm` = MimeType("application/vnd.novadigm.edm", "edm")
val `application/vnd.novadigm.edx` = MimeType("application/vnd.novadigm.edx", "edx")
val `application/vnd.novadigm.ext` = MimeType("application/vnd.novadigm.ext", "ext")
val `application/vnd.oasis.opendocument.chart` = MimeType("application/vnd.oasis.opendocument.chart", "odc")
val `application/vnd.oasis.opendocument.chart-template` =
MimeType("application/vnd.oasis.opendocument.chart-template", "otc")
val `application/vnd.oasis.opendocument.database` = MimeType("application/vnd.oasis.opendocument.database", "odb")
val `application/vnd.oasis.opendocument.formula` = MimeType("application/vnd.oasis.opendocument.formula", "odf")
val `application/vnd.oasis.opendocument.formula-template` =
MimeType("application/vnd.oasis.opendocument.formula-template", "odft")
val `application/vnd.oasis.opendocument.graphics` = MimeType("application/vnd.oasis.opendocument.graphics", "odg")
val `application/vnd.oasis.opendocument.graphics-template` =
MimeType("application/vnd.oasis.opendocument.graphics-template", "otg")
val `application/vnd.oasis.opendocument.image` = MimeType("application/vnd.oasis.opendocument.image", "odi")
val `application/vnd.oasis.opendocument.image-template` =
MimeType("application/vnd.oasis.opendocument.image-template", "oti")
val `application/vnd.oasis.opendocument.presentation` =
MimeType("application/vnd.oasis.opendocument.presentation", "odp")
val `application/vnd.oasis.opendocument.presentation-template` =
MimeType("application/vnd.oasis.opendocument.presentation-template", "otp")
val `application/vnd.oasis.opendocument.spreadsheet` =
MimeType("application/vnd.oasis.opendocument.spreadsheet", "ods")
val `application/vnd.oasis.opendocument.spreadsheet-template` =
MimeType("application/vnd.oasis.opendocument.spreadsheet-template", "ots")
val `application/vnd.oasis.opendocument.text` = MimeType("application/vnd.oasis.opendocument.text", "odt")
val `application/vnd.oasis.opendocument.text-master` =
MimeType("application/vnd.oasis.opendocument.text-master", "odm", "otm")
val `application/vnd.oasis.opendocument.text-template` =
MimeType("application/vnd.oasis.opendocument.text-template", "ott")
val `application/vnd.oasis.opendocument.text-web` = MimeType("application/vnd.oasis.opendocument.text-web", "oth")
val `application/vnd.obn` = MimeType("application/vnd.obn")
val `application/vnd.olpc-sugar` = MimeType("application/vnd.olpc-sugar", "xo")
val `application/vnd.oma-scws-config` = MimeType("application/vnd.oma-scws-config")
val `application/vnd.oma-scws-http-request` = MimeType("application/vnd.oma-scws-http-request")
val `application/vnd.oma-scws-http-response` = MimeType("application/vnd.oma-scws-http-response")
val `application/vnd.oma.bcast.associated-procedure-parameter+xml` = MimeType(
"application/vnd.oma.bcast.associated-procedure-parameter+xml")
val `application/vnd.oma.bcast.drm-trigger+xml` = MimeType("application/vnd.oma.bcast.drm-trigger+xml")
val `application/vnd.oma.bcast.imd+xml` = MimeType("application/vnd.oma.bcast.imd+xml")
val `application/vnd.oma.bcast.ltkm` = MimeType("application/vnd.oma.bcast.ltkm")
val `application/vnd.oma.bcast.notification+xml` = MimeType("application/vnd.oma.bcast.notification+xml")
val `application/vnd.oma.bcast.provisioningtrigger` = MimeType("application/vnd.oma.bcast.provisioningtrigger")
val `application/vnd.oma.bcast.sgboot` = MimeType("application/vnd.oma.bcast.sgboot")
val `application/vnd.oma.bcast.sgdd+xml` = MimeType("application/vnd.oma.bcast.sgdd+xml")
val `application/vnd.oma.bcast.sgdu` = MimeType("application/vnd.oma.bcast.sgdu")
val `application/vnd.oma.bcast.simple-symbol-container` = MimeType(
"application/vnd.oma.bcast.simple-symbol-container")
val `application/vnd.oma.bcast.smartcard-trigger+xml` = MimeType("application/vnd.oma.bcast.smartcard-trigger+xml")
val `application/vnd.oma.bcast.sprov+xml` = MimeType("application/vnd.oma.bcast.sprov+xml")
val `application/vnd.oma.bcast.stkm` = MimeType("application/vnd.oma.bcast.stkm")
val `application/vnd.oma.dcd` = MimeType("application/vnd.oma.dcd")
val `application/vnd.oma.dcdc` = MimeType("application/vnd.oma.dcdc")
val `application/vnd.oma.dd2+xml` = MimeType("application/vnd.oma.dd2+xml", "dd2")
val `application/vnd.oma.drm.risd+xml` = MimeType("application/vnd.oma.drm.risd+xml")
val `application/vnd.oma.group-usage-list+xml` = MimeType("application/vnd.oma.group-usage-list+xml")
val `application/vnd.oma.poc.detailed-progress-report+xml` = MimeType(
"application/vnd.oma.poc.detailed-progress-report+xml")
val `application/vnd.oma.poc.final-report+xml` = MimeType("application/vnd.oma.poc.final-report+xml")
val `application/vnd.oma.poc.groups+xml` = MimeType("application/vnd.oma.poc.groups+xml")
val `application/vnd.oma.poc.invocation-descriptor+xml` = MimeType(
"application/vnd.oma.poc.invocation-descriptor+xml")
val `application/vnd.oma.poc.optimized-progress-report+xml` = MimeType(
"application/vnd.oma.poc.optimized-progress-report+xml")
val `application/vnd.oma.xcap-directory+xml` = MimeType("application/vnd.oma.xcap-directory+xml")
val `application/vnd.omads-email+xml` = MimeType("application/vnd.omads-email+xml")
val `application/vnd.omads-file+xml` = MimeType("application/vnd.omads-file+xml")
val `application/vnd.omads-folder+xml` = MimeType("application/vnd.omads-folder+xml")
val `application/vnd.omaloc-supl-init` = MimeType("application/vnd.omaloc-supl-init")
val `application/vnd.openofficeorg.extension` = MimeType("application/vnd.openofficeorg.extension", "oxt")
val `application/vnd.openxmlformats-officedocument.presentationml.presentation` =
MimeType("application/vnd.openxmlformats-officedocument.presentationml.presentation", "pptx")
val `application/vnd.openxmlformats-officedocument.presentationml.slide` =
MimeType("application/vnd.openxmlformats-officedocument.presentationml.slide", "sldx")
val `application/vnd.openxmlformats-officedocument.presentationml.slideshow` =
MimeType("application/vnd.openxmlformats-officedocument.presentationml.slideshow", "ppsx")
val `application/vnd.openxmlformats-officedocument.presentationml.template` =
MimeType("application/vnd.openxmlformats-officedocument.presentationml.template", "potx")
val `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` =
MimeType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xlsx")
val `application/vnd.openxmlformats-officedocument.spreadsheetml.template` =
MimeType("application/vnd.openxmlformats-officedocument.spreadsheetml.template", "xltx")
val `application/vnd.openxmlformats-officedocument.wordprocessingml.document` =
MimeType("application/vnd.openxmlformats-officedocument.wordprocessingml.document", "docx")
val `application/vnd.openxmlformats-officedocument.wordprocessingml.template` =
MimeType("application/vnd.openxmlformats-officedocument.wordprocessingml.template", "dotx")
val `application/vnd.osa.netdeploy` = MimeType("application/vnd.osa.netdeploy")
val `application/vnd.osgi.bundle` = MimeType("application/vnd.osgi.bundle")
val `application/vnd.osgi.dp` = MimeType("application/vnd.osgi.dp", "dp")
val `application/vnd.otps.ct-kip+xml` = MimeType("application/vnd.otps.ct-kip+xml")
val `application/vnd.palm` = MimeType("application/vnd.palm", "oprc", "pdb", "pqa")
val `application/vnd.paos.xml` = MimeType("application/vnd.paos.xml")
val `application/vnd.pg.format` = MimeType("application/vnd.pg.format", "str")
val `application/vnd.pg.osasli` = MimeType("application/vnd.pg.osasli", "ei6")
val `application/vnd.piaccess.application-licence` = MimeType("application/vnd.piaccess.application-licence")
val `application/vnd.picsel` = MimeType("application/vnd.picsel", "efif")
val `application/vnd.poc.group-advertisement+xml` = MimeType("application/vnd.poc.group-advertisement+xml")
val `application/vnd.pocketlearn` = MimeType("application/vnd.pocketlearn", "plf")
val `application/vnd.powerbuilder6` = MimeType("application/vnd.powerbuilder6", "pbd")
val `application/vnd.powerbuilder6-s` = MimeType("application/vnd.powerbuilder6-s")
val `application/vnd.powerbuilder7` = MimeType("application/vnd.powerbuilder7")
val `application/vnd.powerbuilder7-s` = MimeType("application/vnd.powerbuilder7-s")
val `application/vnd.powerbuilder75` = MimeType("application/vnd.powerbuilder75")
val `application/vnd.powerbuilder75-s` = MimeType("application/vnd.powerbuilder75-s")
val `application/vnd.preminet` = MimeType("application/vnd.preminet")
val `application/vnd.previewsystems.box` = MimeType("application/vnd.previewsystems.box", "box")
val `application/vnd.proteus.magazine` = MimeType("application/vnd.proteus.magazine", "mgz")
val `application/vnd.publishare-delta-tree` = MimeType("application/vnd.publishare-delta-tree", "qps")
val `application/vnd.pvi.ptid1` = MimeType("application/vnd.pvi.ptid1", "ptid")
val `application/vnd.pwg-multiplexed` = MimeType("application/vnd.pwg-multiplexed")
val `application/vnd.pwg-xhtml-print+xml` = MimeType("application/vnd.pwg-xhtml-print+xml")
val `application/vnd.qualcomm.brew-app-res` = MimeType("application/vnd.qualcomm.brew-app-res")
val `application/vnd.quark.quarkxpress` =
MimeType("application/vnd.quark.quarkxpress", "qwd", "qwt", "qxb", "qxd", "qxl", "qxt")
val `application/vnd.rapid` = MimeType("application/vnd.rapid")
val `application/vnd.recordare.musicxml` = MimeType("application/vnd.recordare.musicxml", "mxl")
val `application/vnd.recordare.musicxml+xml` = MimeType("application/vnd.recordare.musicxml+xml", "musicxml")
val `application/vnd.renlearn.rlprint` = MimeType("application/vnd.renlearn.rlprint")
val `application/vnd.rim.cod` = MimeType("application/vnd.rim.cod", "cod")
val `application/vnd.rn-realmedia` = MimeType("application/vnd.rn-realmedia", "rm")
val `application/vnd.route66.link66+xml` = MimeType("application/vnd.route66.link66+xml", "link66")
val `application/vnd.ruckus.download` = MimeType("application/vnd.ruckus.download")
val `application/vnd.s3sms` = MimeType("application/vnd.s3sms")
val `application/vnd.sbm.cid` = MimeType("application/vnd.sbm.cid")
val `application/vnd.sbm.mid2` = MimeType("application/vnd.sbm.mid2")
val `application/vnd.scribus` = MimeType("application/vnd.scribus")
val `application/vnd.sealed.3df` = MimeType("application/vnd.sealed.3df")
val `application/vnd.sealed.csf` = MimeType("application/vnd.sealed.csf")
val `application/vnd.sealed.doc` = MimeType("application/vnd.sealed.doc")
val `application/vnd.sealed.eml` = MimeType("application/vnd.sealed.eml")
val `application/vnd.sealed.mht` = MimeType("application/vnd.sealed.mht")
val `application/vnd.sealed.net` = MimeType("application/vnd.sealed.net")
val `application/vnd.sealed.ppt` = MimeType("application/vnd.sealed.ppt")
val `application/vnd.sealed.tiff` = MimeType("application/vnd.sealed.tiff")
val `application/vnd.sealed.xls` = MimeType("application/vnd.sealed.xls")
val `application/vnd.sealedmedia.softseal.html` = MimeType("application/vnd.sealedmedia.softseal.html")
val `application/vnd.sealedmedia.softseal.pdf` = MimeType("application/vnd.sealedmedia.softseal.pdf")
val `application/vnd.seemail` = MimeType("application/vnd.seemail", "see")
val `application/vnd.sema` = MimeType("application/vnd.sema", "sema")
val `application/vnd.semd` = MimeType("application/vnd.semd", "semd")
val `application/vnd.semf` = MimeType("application/vnd.semf", "semf")
val `application/vnd.shana.informed.formdata` = MimeType("application/vnd.shana.informed.formdata", "ifm")
val `application/vnd.shana.informed.formtemplate` = MimeType("application/vnd.shana.informed.formtemplate", "itp")
val `application/vnd.shana.informed.interchange` = MimeType("application/vnd.shana.informed.interchange", "iif")
val `application/vnd.shana.informed.package` = MimeType("application/vnd.shana.informed.package", "ipk")
val `application/vnd.simtech-mindmapper` = MimeType("application/vnd.simtech-mindmapper", "twd", "twds")
val `application/vnd.smaf` = MimeType("application/vnd.smaf", "mmf")
val `application/vnd.smart.teacher` = MimeType("application/vnd.smart.teacher", "teacher")
val `application/vnd.software602.filler.form+xml` = MimeType("application/vnd.software602.filler.form+xml")
val `application/vnd.software602.filler.form-xml-zip` = MimeType("application/vnd.software602.filler.form-xml-zip")
val `application/vnd.solent.sdkm+xml` = MimeType("application/vnd.solent.sdkm+xml", "sdkd", "sdkm")
val `application/vnd.spotfire.dxp` = MimeType("application/vnd.spotfire.dxp", "dxp")
val `application/vnd.spotfire.sfs` = MimeType("application/vnd.spotfire.sfs", "sfs")
val `application/vnd.sss-cod` = MimeType("application/vnd.sss-cod")
val `application/vnd.sss-dtf` = MimeType("application/vnd.sss-dtf")
val `application/vnd.sss-ntf` = MimeType("application/vnd.sss-ntf")
val `application/vnd.stardivision.calc` = MimeType("application/vnd.stardivision.calc", "sdc")
val `application/vnd.stardivision.draw` = MimeType("application/vnd.stardivision.draw", "sda")
val `application/vnd.stardivision.impress` = MimeType("application/vnd.stardivision.impress", "sdd", "sdp")
val `application/vnd.stardivision.math` = MimeType("application/vnd.stardivision.math", "sdf", "smf")
val `application/vnd.stardivision.writer` = MimeType("application/vnd.stardivision.writer", "sdw", "vor")
val `application/vnd.stardivision.writer-global` = MimeType("application/vnd.stardivision.writer-global", "sgl")
val `application/vnd.street-stream` = MimeType("application/vnd.street-stream")
val `application/vnd.sun.wadl+xml` = MimeType("application/vnd.sun.wadl+xml")
val `application/vnd.sun.xml.calc` = MimeType("application/vnd.sun.xml.calc", "sxc")
val `application/vnd.sun.xml.calc.template` = MimeType("application/vnd.sun.xml.calc.template", "stc")
val `application/vnd.sun.xml.draw` = MimeType("application/vnd.sun.xml.draw", "sxd")
val `application/vnd.sun.xml.draw.template` = MimeType("application/vnd.sun.xml.draw.template", "std")
val `application/vnd.sun.xml.impress` = MimeType("application/vnd.sun.xml.impress", "sxi")
val `application/vnd.sun.xml.impress.template` = MimeType("application/vnd.sun.xml.impress.template", "sti")
val `application/vnd.sun.xml.math` = MimeType("application/vnd.sun.xml.math", "sxm")
val `application/vnd.sun.xml.writer` = MimeType("application/vnd.sun.xml.writer", "sxw")
val `application/vnd.sun.xml.writer.global` = MimeType("application/vnd.sun.xml.writer.global", "sxg")
val `application/vnd.sun.xml.writer.template` = MimeType("application/vnd.sun.xml.writer.template", "stw")
val `application/vnd.sus-calendar` = MimeType("application/vnd.sus-calendar", "sus", "susp")
val `application/vnd.svd` = MimeType("application/vnd.svd", "svd")
val `application/vnd.swiftview-ics` = MimeType("application/vnd.swiftview-ics")
val `application/vnd.symbian.install` = MimeType("application/vnd.symbian.install", "sis", "sisx")
val `application/vnd.syncml+xml` = MimeType("application/vnd.syncml+xml", "xsm")
val `application/vnd.syncml.dm+wbxml` = MimeType("application/vnd.syncml.dm+wbxml", "bdm")
val `application/vnd.syncml.dm+xml` = MimeType("application/vnd.syncml.dm+xml", "xdm")
val `application/vnd.syncml.dm.notification` = MimeType("application/vnd.syncml.dm.notification")
val `application/vnd.syncml.ds.notification` = MimeType("application/vnd.syncml.ds.notification")
val `application/vnd.tao.intent-module-archive` = MimeType("application/vnd.tao.intent-module-archive", "tao")
val `application/vnd.tmobile-livetv` = MimeType("application/vnd.tmobile-livetv", "tmo")
val `application/vnd.trid.tpt` = MimeType("application/vnd.trid.tpt", "tpt")
val `application/vnd.triscape.mxs` = MimeType("application/vnd.triscape.mxs", "mxs")
val `application/vnd.trueapp` = MimeType("application/vnd.trueapp", "tra")
val `application/vnd.truedoc` = MimeType("application/vnd.truedoc")
val `application/vnd.ufdl` = MimeType("application/vnd.ufdl", "ufd", "ufdl")
val `application/vnd.uiq.theme` = MimeType("application/vnd.uiq.theme", "utz")
val `application/vnd.umajin` = MimeType("application/vnd.umajin", "umj")
val `application/vnd.unity` = MimeType("application/vnd.unity", "unityweb")
val `application/vnd.uoml+xml` = MimeType("application/vnd.uoml+xml", "uoml")
val `application/vnd.uplanet.alert` = MimeType("application/vnd.uplanet.alert")
val `application/vnd.uplanet.alert-wbxml` = MimeType("application/vnd.uplanet.alert-wbxml")
val `application/vnd.uplanet.bearer-choice` = MimeType("application/vnd.uplanet.bearer-choice")
val `application/vnd.uplanet.bearer-choice-wbxml` = MimeType("application/vnd.uplanet.bearer-choice-wbxml")
val `application/vnd.uplanet.cacheop` = MimeType("application/vnd.uplanet.cacheop")
val `application/vnd.uplanet.cacheop-wbxml` = MimeType("application/vnd.uplanet.cacheop-wbxml")
val `application/vnd.uplanet.channel` = MimeType("application/vnd.uplanet.channel")
val `application/vnd.uplanet.channel-wbxml` = MimeType("application/vnd.uplanet.channel-wbxml")
val `application/vnd.uplanet.list` = MimeType("application/vnd.uplanet.list")
val `application/vnd.uplanet.list-wbxml` = MimeType("application/vnd.uplanet.list-wbxml")
val `application/vnd.uplanet.listcmd` = MimeType("application/vnd.uplanet.listcmd")
val `application/vnd.uplanet.listcmd-wbxml` = MimeType("application/vnd.uplanet.listcmd-wbxml")
val `application/vnd.uplanet.signal` = MimeType("application/vnd.uplanet.signal")
val `application/vnd.vcx` = MimeType("application/vnd.vcx", "vcx")
val `application/vnd.vd-study` = MimeType("application/vnd.vd-study")
val `application/vnd.vectorworks` = MimeType("application/vnd.vectorworks")
val `application/vnd.vidsoft.vidconference` = MimeType("application/vnd.vidsoft.vidconference")
val `application/vnd.visio` = MimeType("application/vnd.visio", "vsd", "vss", "vst", "vsw")
val `application/vnd.visionary` = MimeType("application/vnd.visionary", "vis")
val `application/vnd.vividence.scriptfile` = MimeType("application/vnd.vividence.scriptfile")
val `application/vnd.vsf` = MimeType("application/vnd.vsf", "vsf")
val `application/vnd.wap.sic` = MimeType("application/vnd.wap.sic")
val `application/vnd.wap.slc` = MimeType("application/vnd.wap.slc")
val `application/vnd.wap.wbxml` = MimeType("application/vnd.wap.wbxml", "wbxml")
val `application/vnd.wap.wmlc` = MimeType("application/vnd.wap.wmlc", "wmlc")
val `application/vnd.wap.wmlscriptc` = MimeType("application/vnd.wap.wmlscriptc", "wmlsc")
val `application/vnd.webturbo` = MimeType("application/vnd.webturbo", "wtb")
val `application/vnd.wfa.wsc` = MimeType("application/vnd.wfa.wsc")
val `application/vnd.wmc` = MimeType("application/vnd.wmc")
val `application/vnd.wmf.bootstrap` = MimeType("application/vnd.wmf.bootstrap")
val `application/vnd.wordperfect` = MimeType("application/vnd.wordperfect", "wpd")
val `application/vnd.wqd` = MimeType("application/vnd.wqd", "wqd")
val `application/vnd.wrq-hp3000-labelled` = MimeType("application/vnd.wrq-hp3000-labelled")
val `application/vnd.wt.stf` = MimeType("application/vnd.wt.stf", "stf")
val `application/vnd.wv.csp+wbxml` = MimeType("application/vnd.wv.csp+wbxml")
val `application/vnd.wv.csp+xml` = MimeType("application/vnd.wv.csp+xml")
val `application/vnd.wv.ssp+xml` = MimeType("application/vnd.wv.ssp+xml")
val `application/vnd.xara` = MimeType("application/vnd.xara", "xar")
val `application/vnd.xfdl` = MimeType("application/vnd.xfdl", "xfdl")
val `application/vnd.xfdl.webform` = MimeType("application/vnd.xfdl.webform")
val `application/vnd.xmi+xml` = MimeType("application/vnd.xmi+xml")
val `application/vnd.xmpie.cpkg` = MimeType("application/vnd.xmpie.cpkg")
val `application/vnd.xmpie.dpkg` = MimeType("application/vnd.xmpie.dpkg")
val `application/vnd.xmpie.plan` = MimeType("application/vnd.xmpie.plan")
val `application/vnd.xmpie.ppkg` = MimeType("application/vnd.xmpie.ppkg")
val `application/vnd.xmpie.xlim` = MimeType("application/vnd.xmpie.xlim")
val `application/vnd.yamaha.hv-dic` = MimeType("application/vnd.yamaha.hv-dic", "hvd")
val `application/vnd.yamaha.hv-script` = MimeType("application/vnd.yamaha.hv-script", "hvs")
val `application/vnd.yamaha.hv-voice` = MimeType("application/vnd.yamaha.hv-voice", "hvp")
val `application/vnd.yamaha.openscoreformat` = MimeType("application/vnd.yamaha.openscoreformat", "osf")
val `application/vnd.yamaha.openscoreformat.osfpvg+xml` =
MimeType("application/vnd.yamaha.openscoreformat.osfpvg+xml", "osfpvg")
val `application/vnd.yamaha.smaf-audio` = MimeType("application/vnd.yamaha.smaf-audio", "saf")
val `application/vnd.yamaha.smaf-phrase` = MimeType("application/vnd.yamaha.smaf-phrase", "spf")
val `application/vnd.yellowriver-custom-menu` = MimeType("application/vnd.yellowriver-custom-menu", "cmp")
val `application/vnd.zul` = MimeType("application/vnd.zul", "zir", "zirz")
val `application/vnd.zzazz.deck+xml` = MimeType("application/vnd.zzazz.deck+xml", "zaz")
val `application/voicexml+xml` = MimeType("application/voicexml+xml", "vxml")
val `application/watcherinfo+xml` = MimeType("application/watcherinfo+xml")
val `application/whoispp-query` = MimeType("application/whoispp-query")
val `application/whoispp-response` = MimeType("application/whoispp-response")
val `application/winhlp` = MimeType("application/winhlp", "hlp")
val `application/wita` = MimeType("application/wita")
val `application/wordperfect` = MimeType("application/wordperfect", "wpd")
val `application/wordperfect5.1` = MimeType("application/wordperfect5.1", "wp5")
val `application/wsdl+xml` = MimeType("application/wsdl+xml", "wsdl")
val `application/wspolicy+xml` = MimeType("application/wspolicy+xml", "wspolicy")
val `application/x-123` = MimeType("application/x-123", "wk")
val `application/x-abiword` = MimeType("application/x-abiword", "abw")
val `application/x-ace-compressed` = MimeType("application/x-ace-compressed", "ace")
val `application/x-apple-diskimage` = MimeType("application/x-apple-diskimage", "dmg")
val `application/x-authorware-bin` = MimeType("application/x-authorware-bin", "aab", "u32", "vox", "x32")
val `application/x-authorware-map` = MimeType("application/x-authorware-map", "aam")
val `application/x-authorware-seg` = MimeType("application/x-authorware-seg", "aas")
val `application/x-bcpio` = MimeType("application/x-bcpio", "bcpio")
val `application/x-bittorrent` = MimeType("application/x-bittorrent", "torrent")
val `application/x-bzip` = MimeType("application/x-bzip", "bz")
val `application/x-bzip2` = MimeType("application/x-bzip2", "boz", "bz2")
val `application/x-cdf` = MimeType("application/x-cdf", "cdf")
val `application/x-cdlink` = MimeType("application/x-cdlink", "vcd")
val `application/x-chat` = MimeType("application/x-chat", "chat")
val `application/x-chess-pgn` = MimeType("application/x-chess-pgn", "pgn")
val `application/x-compress` = MimeType("application/x-compress")
val `application/x-cpio` = MimeType("application/x-cpio", "cpio")
val `application/x-csh` = MimeType("application/x-csh", "csh")
val `application/x-debian-package` = MimeType("application/x-debian-package", "deb", "udeb")
val `application/x-director` =
MimeType("application/x-director", "cct", "cst", "cxt", "dcr", "dir", "dxr", "fgd", "swa", "w3d")
val `application/x-dms` = MimeType("application/x-dms", "dms")
val `application/x-doom` = MimeType("application/x-doom", "wad")
val `application/x-dtbncx+xml` = MimeType("application/x-dtbncx+xml", "ncx")
val `application/x-dtbook+xml` = MimeType("application/x-dtbook+xml", "dtb")
val `application/x-dtbresource+xml` = MimeType("application/x-dtbresource+xml", "res")
val `application/x-dvi` = MimeType("application/x-dvi", "dvi")
val `application/x-flac` = MimeType("application/x-flac", "flac")
val `application/x-font` = MimeType("application/x-font", "gsf", "pcf", "pcf", ".Z", "pfa", "pfb")
val `application/x-font-bdf` = MimeType("application/x-font-bdf", "bdf")
val `application/x-font-dos` = MimeType("application/x-font-dos")
val `application/x-font-framemaker` = MimeType("application/x-font-framemaker")
val `application/x-font-ghostscript` = MimeType("application/x-font-ghostscript", "gsf")
val `application/x-font-libgrx` = MimeType("application/x-font-libgrx")
val `application/x-font-linux-psf` = MimeType("application/x-font-linux-psf", "psf")
val `application/x-font-otf` = MimeType("application/x-font-otf", "otf")
val `application/x-font-pcf` = MimeType("application/x-font-pcf", "pcf")
val `application/x-font-snf` = MimeType("application/x-font-snf", "snf")
val `application/x-font-speedo` = MimeType("application/x-font-speedo")
val `application/x-font-sunos-news` = MimeType("application/x-font-sunos-news")
val `application/x-font-ttf` = MimeType("application/x-font-ttf", "ttc", "ttf")
val `application/x-font-type1` = MimeType("application/x-font-type1", "afm", "pfa", "pfb", "pfm")
val `application/x-font-vfont` = MimeType("application/x-font-vfont")
val `application/x-freemind` = MimeType("application/x-freemind", "mm")
val `application/x-futuresplash` = MimeType("application/x-futuresplash", "spl")
val `application/x-gnumeric` = MimeType("application/x-gnumeric", "gnumeric")
val `application/x-go-sgf` = MimeType("application/x-go-sgf", "sgf")
val `application/x-graphing-calculator` = MimeType("application/x-graphing-calculator", "gcf")
val `application/x-gtar` = MimeType("application/x-gtar", "gtar", "taz", "tgz")
val `application/x-gzip` = MimeType("application/x-gzip")
val `application/x-hdf` = MimeType("application/x-hdf", "hdf")
val `application/x-ica` = MimeType("application/x-ica", "ica")
val `application/x-internet-signup` = MimeType("application/x-internet-signup", "ins", "isp")
val `application/x-iphone` = MimeType("application/x-iphone", "iii")
val `application/x-iso9660-image` = MimeType("application/x-iso9660-image", "iso")
val `application/x-java-jnlp-file` = MimeType("application/x-java-jnlp-file", "jnlp")
val `application/x-javascript` = MimeType("application/x-javascript", "js")
val `application/x-jmol` = MimeType("application/x-jmol", "jmz")
val `application/x-kchart` = MimeType("application/x-kchart", "chrt")
val `application/x-killustrator` = MimeType("application/x-killustrator", "kil")
val `application/x-koan` = MimeType("application/x-koan", "skd", "skm", "skp", "skt")
val `application/x-kpresenter` = MimeType("application/x-kpresenter", "kpr", "kpt")
val `application/x-kspread` = MimeType("application/x-kspread", "ksp")
val `application/x-kword` = MimeType("application/x-kword", "kwd", "kwt")
val `application/x-latex` = MimeType("application/x-latex", "latex")
val `application/x-lha` = MimeType("application/x-lha", "lha")
val `application/x-lzh` = MimeType("application/x-lzh", "lzh")
val `application/x-lzx` = MimeType("application/x-lzx", "lzx")
val `application/x-maker` = MimeType("application/x-maker", "book", "fb", "fbdoc", "fm", "frame", "frm", "maker")
val `application/x-mif` = MimeType("application/x-mif", "mif")
val `application/x-mobipocket-ebook` = MimeType("application/x-mobipocket-ebook", "mobi", "prc")
val `application/x-ms-application` = MimeType("application/x-ms-application", "application")
val `application/x-ms-wmd` = MimeType("application/x-ms-wmd", "wmd")
val `application/x-ms-wmz` = MimeType("application/x-ms-wmz", "wmz")
val `application/x-ms-xbap` = MimeType("application/x-ms-xbap", "xbap")
val `application/x-msaccess` = MimeType("application/x-msaccess", "mdb")
val `application/x-msbinder` = MimeType("application/x-msbinder", "obd")
val `application/x-mscardfile` = MimeType("application/x-mscardfile", "crd")
val `application/x-msclip` = MimeType("application/x-msclip", "clp")
val `application/x-msdos-program` = MimeType("application/x-msdos-program", "bat", "com", "dll", "exe")
val `application/x-msdownload` = MimeType("application/x-msdownload", "bat", "com", "dll", "exe", "msi")
val `application/x-msi` = MimeType("application/x-msi", "msi")
val `application/x-msmediaview` = MimeType("application/x-msmediaview", "m13", "m14", "mvb")
val `application/x-msmetafile` = MimeType("application/x-msmetafile", "wmf")
val `application/x-msmoney` = MimeType("application/x-msmoney", "mny")
val `application/x-mspublisher` = MimeType("application/x-mspublisher", "pub")
val `application/x-msschedule` = MimeType("application/x-msschedule", "scd")
val `application/x-msterminal` = MimeType("application/x-msterminal", "trm")
val `application/x-mswrite` = MimeType("application/x-mswrite", "wri")
val `application/x-netcdf` = MimeType("application/x-netcdf", "cdf", "nc")
val `application/x-ns-proxy-autoconfig` = MimeType("application/x-ns-proxy-autoconfig", "pac")
val `application/x-nwc` = MimeType("application/x-nwc", "nwc")
val `application/x-object` = MimeType("application/x-object", "o")
val `application/x-oz-application` = MimeType("application/x-oz-application", "oza")
val `application/x-pkcs12` = MimeType("application/x-pkcs12", "p12", "pfx")
val `application/x-pkcs7-certificates` = MimeType("application/x-pkcs7-certificates", "p7b", "spc")
val `application/x-pkcs7-certreqresp` = MimeType("application/x-pkcs7-certreqresp", "p7r")
val `application/x-pkcs7-crl` = MimeType("application/x-pkcs7-crl", "crl")
val `application/x-python-code` = MimeType("application/x-python-code", "pyc", "pyo")
val `application/x-quicktimeplayer` = MimeType("application/x-quicktimeplayer", "qtl")
val `application/x-rar-compressed` = MimeType("application/x-rar-compressed", "rar")
val `application/x-redhat-package-manager` = MimeType("application/x-redhat-package-manager", "rpm")
val `application/x-sh` = MimeType("application/x-sh", "sh")
val `application/x-shar` = MimeType("application/x-shar", "shar")
val `application/x-shockwave-flash` = MimeType("application/x-shockwave-flash", "swf", "swfl")
val `application/x-silverlight-app` = MimeType("application/x-silverlight-app", "xap")
val `application/x-stuffit` = MimeType("application/x-stuffit", "sit", "sitx")
val `application/x-stuffitx` = MimeType("application/x-stuffitx", "sitx")
val `application/x-sv4cpio` = MimeType("application/x-sv4cpio", "sv4cpio")
val `application/x-sv4crc` = MimeType("application/x-sv4crc", "sv4crc")
val `application/x-tar` = MimeType("application/x-tar", "tar")
val `application/x-tcl` = MimeType("application/x-tcl", "tcl")
val `application/x-tex` = MimeType("application/x-tex", "tex")
val `application/x-tex-gf` = MimeType("application/x-tex-gf", "gf")
val `application/x-tex-pk` = MimeType("application/x-tex-pk", "pk")
val `application/x-tex-tfm` = MimeType("application/x-tex-tfm", "tfm")
val `application/x-texinfo` = MimeType("application/x-texinfo", "texi", "texinfo")
val `application/x-trash` = MimeType("application/x-trash", "%", "bak", "old", "sik", "~")
val `application/x-troff` = MimeType("application/x-troff", "roff", "t", "tr")
val `application/x-troff-man` = MimeType("application/x-troff-man", "man")
val `application/x-troff-me` = MimeType("application/x-troff-me", "me")
val `application/x-troff-ms` = MimeType("application/x-troff-ms", "ms")
val `application/x-ustar` = MimeType("application/x-ustar", "ustar")
val `application/x-wais-source` = MimeType("application/x-wais-source", "src")
val `application/x-wingz` = MimeType("application/x-wingz", "wz")
val `application/x-x509-ca-cert` = MimeType("application/x-x509-ca-cert", "crt", "der")
val `application/x-xcf` = MimeType("application/x-xcf", "xcf")
val `application/x-xfig` = MimeType("application/x-xfig", "fig")
val `application/x-xpinstall` = MimeType("application/x-xpinstall", "xpi")
val `application/x400-bp` = MimeType("application/x400-bp")
val `application/xcap-att+xml` = MimeType("application/xcap-att+xml")
val `application/xcap-caps+xml` = MimeType("application/xcap-caps+xml")
val `application/xcap-el+xml` = MimeType("application/xcap-el+xml")
val `application/xcap-error+xml` = MimeType("application/xcap-error+xml")
val `application/xcap-ns+xml` = MimeType("application/xcap-ns+xml")
val `application/xcon-conference-info+xml` = MimeType("application/xcon-conference-info+xml")
val `application/xcon-conference-info-diff+xml` = MimeType("application/xcon-conference-info-diff+xml")
val `application/xenc+xml` = MimeType("application/xenc+xml", "xenc")
val `application/xhtml+xml` = MimeType("application/xhtml+xml", "xht", "xhtml")
val `application/xhtml-voice+xml` = MimeType("application/xhtml-voice+xml")
val `application/xml` = MimeType("application/xml", "xml", "xsl")
val `application/xml-dtd` = MimeType("application/xml-dtd", "dtd")
val `application/xml-external-parsed-entity` = MimeType("application/xml-external-parsed-entity")
val `application/xmpp+xml` = MimeType("application/xmpp+xml")
val `application/xop+xml` = MimeType("application/xop+xml", "xop")
val `application/xslt+xml` = MimeType("application/xslt+xml", "xslt")
val `application/xspf+xml` = MimeType("application/xspf+xml", "xspf")
val `application/xv+xml` = MimeType("application/xv+xml", "mxml", "xhvml", "xvm", "xvml")
val `application/zip` = MimeType("application/zip", "zip")
val `audio/32kadpcm` = MimeType("audio/32kadpcm")
val `audio/3gpp` = MimeType("audio/3gpp")
val `audio/3gpp2` = MimeType("audio/3gpp2")
val `audio/ac3` = MimeType("audio/ac3")
val `audio/adpcm` = MimeType("audio/adpcm", "adp")
val `audio/amr` = MimeType("audio/amr")
val `audio/amr-wb` = MimeType("audio/amr-wb")
val `audio/amr-wb+` = MimeType("audio/amr-wb+")
val `audio/asc` = MimeType("audio/asc")
val `audio/basic` = MimeType("audio/basic", "au", "snd")
val `audio/bv16` = MimeType("audio/bv16")
val `audio/bv32` = MimeType("audio/bv32")
val `audio/clearmode` = MimeType("audio/clearmode")
val `audio/cn` = MimeType("audio/cn")
val `audio/dat12` = MimeType("audio/dat12")
val `audio/dls` = MimeType("audio/dls")
val `audio/dsr-es201108` = MimeType("audio/dsr-es201108")
val `audio/dsr-es202050` = MimeType("audio/dsr-es202050")
val `audio/dsr-es202211` = MimeType("audio/dsr-es202211")
val `audio/dsr-es202212` = MimeType("audio/dsr-es202212")
val `audio/dvi4` = MimeType("audio/dvi4")
val `audio/eac3` = MimeType("audio/eac3")
val `audio/evrc` = MimeType("audio/evrc")
val `audio/evrc-qcp` = MimeType("audio/evrc-qcp")
val `audio/evrc0` = MimeType("audio/evrc0")
val `audio/evrc1` = MimeType("audio/evrc1")
val `audio/evrcb` = MimeType("audio/evrcb")
val `audio/evrcb0` = MimeType("audio/evrcb0")
val `audio/evrcb1` = MimeType("audio/evrcb1")
val `audio/evrcwb` = MimeType("audio/evrcwb")
val `audio/evrcwb0` = MimeType("audio/evrcwb0")
val `audio/evrcwb1` = MimeType("audio/evrcwb1")
val `audio/example` = MimeType("audio/example")
val `audio/g719` = MimeType("audio/g719")
val `audio/g722` = MimeType("audio/g722")
val `audio/g7221` = MimeType("audio/g7221")
val `audio/g723` = MimeType("audio/g723")
val `audio/g726-16` = MimeType("audio/g726-16")
val `audio/g726-24` = MimeType("audio/g726-24")
val `audio/g726-32` = MimeType("audio/g726-32")
val `audio/g726-40` = MimeType("audio/g726-40")
val `audio/g728` = MimeType("audio/g728")
val `audio/g729` = MimeType("audio/g729")
val `audio/g7291` = MimeType("audio/g7291")
val `audio/g729d` = MimeType("audio/g729d")
val `audio/g729e` = MimeType("audio/g729e")
val `audio/gsm` = MimeType("audio/gsm")
val `audio/gsm-efr` = MimeType("audio/gsm-efr")
val `audio/ilbc` = MimeType("audio/ilbc")
val `audio/l16` = MimeType("audio/l16")
val `audio/l20` = MimeType("audio/l20")
val `audio/l24` = MimeType("audio/l24")
val `audio/l8` = MimeType("audio/l8")
val `audio/lpc` = MimeType("audio/lpc")
val `audio/midi` = MimeType("audio/midi", "kar", "mid", "midi", "rmi")
val `audio/mobile-xmf` = MimeType("audio/mobile-xmf")
val `audio/mp4` = MimeType("audio/mp4", "mp4a")
val `audio/mp4a-latm` = MimeType("audio/mp4a-latm")
val `audio/mpa` = MimeType("audio/mpa")
val `audio/mpa-robust` = MimeType("audio/mpa-robust")
val `audio/mpeg` = MimeType("audio/mpeg", "m2a", "m3a", "m4a", "mp2", "mp2a", "mp3", "mpega", "mpga")
val `audio/mpeg4-generic` = MimeType("audio/mpeg4-generic")
val `audio/mpegurl` = MimeType("audio/mpegurl", "m3u")
val `audio/ogg` = MimeType("audio/ogg", "oga", "ogg", "spx")
val `audio/parityfec` = MimeType("audio/parityfec")
val `audio/pcma` = MimeType("audio/pcma")
val `audio/pcma-wb` = MimeType("audio/pcma-wb")
val `audio/pcmu` = MimeType("audio/pcmu")
val `audio/pcmu-wb` = MimeType("audio/pcmu-wb")
val `audio/prs.sid` = MimeType("audio/prs.sid", "sid")
val `audio/qcelp` = MimeType("audio/qcelp")
val `audio/red` = MimeType("audio/red")
val `audio/rtp-enc-aescm128` = MimeType("audio/rtp-enc-aescm128")
val `audio/rtp-midi` = MimeType("audio/rtp-midi")
val `audio/rtx` = MimeType("audio/rtx")
val `audio/smv` = MimeType("audio/smv")
val `audio/smv-qcp` = MimeType("audio/smv-qcp")
val `audio/smv0` = MimeType("audio/smv0")
val `audio/sp-midi` = MimeType("audio/sp-midi")
val `audio/t140c` = MimeType("audio/t140c")
val `audio/t38` = MimeType("audio/t38")
val `audio/telephone-event` = MimeType("audio/telephone-event")
val `audio/tone` = MimeType("audio/tone")
val `audio/ulpfec` = MimeType("audio/ulpfec")
val `audio/vdvi` = MimeType("audio/vdvi")
val `audio/vmr-wb` = MimeType("audio/vmr-wb")
val `audio/vnd.3gpp.iufp` = MimeType("audio/vnd.3gpp.iufp")
val `audio/vnd.4sb` = MimeType("audio/vnd.4sb")
val `audio/vnd.audiokoz` = MimeType("audio/vnd.audiokoz")
val `audio/vnd.celp` = MimeType("audio/vnd.celp")
val `audio/vnd.cisco.nse` = MimeType("audio/vnd.cisco.nse")
val `audio/vnd.cmles.radio-events` = MimeType("audio/vnd.cmles.radio-events")
val `audio/vnd.cns.anp1` = MimeType("audio/vnd.cns.anp1")
val `audio/vnd.cns.inf1` = MimeType("audio/vnd.cns.inf1")
val `audio/vnd.digital-winds` = MimeType("audio/vnd.digital-winds", "eol")
val `audio/vnd.dlna.adts` = MimeType("audio/vnd.dlna.adts")
val `audio/vnd.dolby.heaac.1` = MimeType("audio/vnd.dolby.heaac.1")
val `audio/vnd.dolby.heaac.2` = MimeType("audio/vnd.dolby.heaac.2")
val `audio/vnd.dolby.mlp` = MimeType("audio/vnd.dolby.mlp")
val `audio/vnd.dolby.mps` = MimeType("audio/vnd.dolby.mps")
val `audio/vnd.dolby.pl2` = MimeType("audio/vnd.dolby.pl2")
val `audio/vnd.dolby.pl2x` = MimeType("audio/vnd.dolby.pl2x")
val `audio/vnd.dolby.pl2z` = MimeType("audio/vnd.dolby.pl2z")
val `audio/vnd.dts` = MimeType("audio/vnd.dts", "dts")
val `audio/vnd.dts.hd` = MimeType("audio/vnd.dts.hd", "dtshd")
val `audio/vnd.everad.plj` = MimeType("audio/vnd.everad.plj")
val `audio/vnd.hns.audio` = MimeType("audio/vnd.hns.audio")
val `audio/vnd.lucent.voice` = MimeType("audio/vnd.lucent.voice", "lvp")
val `audio/vnd.ms-playready.media.pya` = MimeType("audio/vnd.ms-playready.media.pya", "pya")
val `audio/vnd.nokia.mobile-xmf` = MimeType("audio/vnd.nokia.mobile-xmf")
val `audio/vnd.nortel.vbk` = MimeType("audio/vnd.nortel.vbk")
val `audio/vnd.nuera.ecelp4800` = MimeType("audio/vnd.nuera.ecelp4800", "ecelp4800")
val `audio/vnd.nuera.ecelp7470` = MimeType("audio/vnd.nuera.ecelp7470", "ecelp7470")
val `audio/vnd.nuera.ecelp9600` = MimeType("audio/vnd.nuera.ecelp9600", "ecelp9600")
val `audio/vnd.octel.sbc` = MimeType("audio/vnd.octel.sbc")
val `audio/vnd.qcelp` = MimeType("audio/vnd.qcelp")
val `audio/vnd.rhetorex.32kadpcm` = MimeType("audio/vnd.rhetorex.32kadpcm")
val `audio/vnd.sealedmedia.softseal.mpeg` = MimeType("audio/vnd.sealedmedia.softseal.mpeg")
val `audio/vnd.vmx.cvsd` = MimeType("audio/vnd.vmx.cvsd")
val `audio/vorbis` = MimeType("audio/vorbis")
val `audio/vorbis-config` = MimeType("audio/vorbis-config")
val `audio/x-aac` = MimeType("audio/x-aac", "aac")
val `audio/x-aiff` = MimeType("audio/x-aiff", "aif", "aifc", "aiff")
val `audio/x-gsm` = MimeType("audio/x-gsm", "gsm")
val `audio/x-mpegurl` = MimeType("audio/x-mpegurl", "m3u")
val `audio/x-ms-wax` = MimeType("audio/x-ms-wax", "wax")
val `audio/x-ms-wma` = MimeType("audio/x-ms-wma", "wma")
val `audio/x-pn-realaudio` = MimeType("audio/x-pn-realaudio", "ra", "ram", "rm")
val `audio/x-pn-realaudio-plugin` = MimeType("audio/x-pn-realaudio-plugin", "rmp")
val `audio/x-realaudio` = MimeType("audio/x-realaudio", "ra")
val `audio/x-scpls` = MimeType("audio/x-scpls", "pls")
val `audio/x-sd2` = MimeType("audio/x-sd2", "sd2")
val `audio/x-wav` = MimeType("audio/x-wav", "wav")
val `chemical/x-alchemy` = MimeType("chemical/x-alchemy", "alc")
val `chemical/x-cache` = MimeType("chemical/x-cache", "cac", "cache")
val `chemical/x-cache-csf` = MimeType("chemical/x-cache-csf", "csf")
val `chemical/x-cactvs-binary` = MimeType("chemical/x-cactvs-binary", "cascii", "cbin", "ctab")
val `chemical/x-cdx` = MimeType("chemical/x-cdx", "cdx")
val `chemical/x-cerius` = MimeType("chemical/x-cerius", "cer")
val `chemical/x-chem3d` = MimeType("chemical/x-chem3d", "c3d")
val `chemical/x-chemdraw` = MimeType("chemical/x-chemdraw", "chm")
val `chemical/x-cif` = MimeType("chemical/x-cif", "cif")
val `chemical/x-cmdf` = MimeType("chemical/x-cmdf", "cmdf")
val `chemical/x-cml` = MimeType("chemical/x-cml", "cml")
val `chemical/x-compass` = MimeType("chemical/x-compass", "cpa")
val `chemical/x-crossfire` = MimeType("chemical/x-crossfire", "bsd")
val `chemical/x-csml` = MimeType("chemical/x-csml", "csm", "csml")
val `chemical/x-ctx` = MimeType("chemical/x-ctx", "ctx")
val `chemical/x-cxf` = MimeType("chemical/x-cxf", "cef", "cxf")
val `chemical/x-embl-dl-nucleotide` = MimeType("chemical/x-embl-dl-nucleotide", "emb", "embl")
val `chemical/x-galactic-spc` = MimeType("chemical/x-galactic-spc", "spc")
val `chemical/x-gamess-input` = MimeType("chemical/x-gamess-input", "gam", "gamin", "inp")
val `chemical/x-gaussian-checkpoint` = MimeType("chemical/x-gaussian-checkpoint", "fch", "fchk")
val `chemical/x-gaussian-cube` = MimeType("chemical/x-gaussian-cube", "cub")
val `chemical/x-gaussian-input` = MimeType("chemical/x-gaussian-input", "gau", "gjc", "gjf")
val `chemical/x-gaussian-log` = MimeType("chemical/x-gaussian-log", "gal")
val `chemical/x-gcg8-sequence` = MimeType("chemical/x-gcg8-sequence", "gcg")
val `chemical/x-genbank` = MimeType("chemical/x-genbank", "gen")
val `chemical/x-hin` = MimeType("chemical/x-hin", "hin")
val `chemical/x-isostar` = MimeType("chemical/x-isostar", "ist", "istr")
val `chemical/x-jcamp-dx` = MimeType("chemical/x-jcamp-dx", "dx", "jdx")
val `chemical/x-kinemage` = MimeType("chemical/x-kinemage", "kin")
val `chemical/x-macmolecule` = MimeType("chemical/x-macmolecule", "mcm")
val `chemical/x-macromodel-input` = MimeType("chemical/x-macromodel-input", "mmd", "mmod")
val `chemical/x-mdl-molfile` = MimeType("chemical/x-mdl-molfile", "mol")
val `chemical/x-mdl-rdfile` = MimeType("chemical/x-mdl-rdfile", "rd")
val `chemical/x-mdl-rxnfile` = MimeType("chemical/x-mdl-rxnfile", "rxn")
val `chemical/x-mdl-sdfile` = MimeType("chemical/x-mdl-sdfile", "sd", "sdf")
val `chemical/x-mdl-tgf` = MimeType("chemical/x-mdl-tgf", "tgf")
val `chemical/x-mmcif` = MimeType("chemical/x-mmcif", "mcif")
val `chemical/x-mol2` = MimeType("chemical/x-mol2", "mol2")
val `chemical/x-molconn-Z` = MimeType("chemical/x-molconn-Z", "b")
val `chemical/x-mopac-graph` = MimeType("chemical/x-mopac-graph", "gpt")
val `chemical/x-mopac-input` = MimeType("chemical/x-mopac-input", "dat", "mop", "mopcrt", "mpc", "zmt")
val `chemical/x-mopac-out` = MimeType("chemical/x-mopac-out", "moo")
val `chemical/x-mopac-vib` = MimeType("chemical/x-mopac-vib", "mvb")
val `chemical/x-ncbi-asn1` = MimeType("chemical/x-ncbi-asn1", "asn")
val `chemical/x-ncbi-asn1-ascii` = MimeType("chemical/x-ncbi-asn1-ascii", "ent", "prt")
val `chemical/x-ncbi-asn1-binary` = MimeType("chemical/x-ncbi-asn1-binary", "aso", "val")
val `chemical/x-ncbi-asn1-spec` = MimeType("chemical/x-ncbi-asn1-spec", "asn")
val `chemical/x-pdb` = MimeType("chemical/x-pdb", "ent", "pdb")
val `chemical/x-rosdal` = MimeType("chemical/x-rosdal", "ros")
val `chemical/x-swissprot` = MimeType("chemical/x-swissprot", "sw")
val `chemical/x-vamas-iso14976` = MimeType("chemical/x-vamas-iso14976", "vms")
val `chemical/x-vmd` = MimeType("chemical/x-vmd", "vmd")
val `chemical/x-xtel` = MimeType("chemical/x-xtel", "xtel")
val `chemical/x-xyz` = MimeType("chemical/x-xyz", "xyz")
val `image/bmp` = MimeType("image/bmp", "bmp")
val `image/cgm` = MimeType("image/cgm", "cgm")
val `image/example` = MimeType("image/example")
val `image/fits` = MimeType("image/fits")
val `image/g3fax` = MimeType("image/g3fax", "g3")
val `image/gif` = MimeType("image/gif", "gif")
val `image/ief` = MimeType("image/ief", "ief")
val `image/jp2` = MimeType("image/jp2")
val `image/jpeg` = MimeType("image/jpeg", "jpe", "jpeg", "jpg")
val `image/jpm` = MimeType("image/jpm")
val `image/jpx` = MimeType("image/jpx")
val `image/naplps` = MimeType("image/naplps")
val `image/pcx` = MimeType("image/pcx", "pcx")
val `image/png` = MimeType("image/png", "png")
val `image/prs.btif` = MimeType("image/prs.btif", "btif")
val `image/prs.pti` = MimeType("image/prs.pti")
val `image/svg+xml` = MimeType("image/svg+xml", "svg", "svgz")
val `image/t38` = MimeType("image/t38")
val `image/tiff` = MimeType("image/tiff", "tif", "tiff")
val `image/tiff-fx` = MimeType("image/tiff-fx")
val `image/vnd.adobe.photoshop` = MimeType("image/vnd.adobe.photoshop", "psd")
val `image/vnd.cns.inf2` = MimeType("image/vnd.cns.inf2")
val `image/vnd.djvu` = MimeType("image/vnd.djvu", "djv", "djvu")
val `image/vnd.dwg` = MimeType("image/vnd.dwg", "dwg")
val `image/vnd.dxf` = MimeType("image/vnd.dxf", "dxf")
val `image/vnd.fastbidsheet` = MimeType("image/vnd.fastbidsheet", "fbs")
val `image/vnd.fpx` = MimeType("image/vnd.fpx", "fpx")
val `image/vnd.fst` = MimeType("image/vnd.fst", "fst")
val `image/vnd.fujixerox.edmics-mmr` = MimeType("image/vnd.fujixerox.edmics-mmr", "mmr")
val `image/vnd.fujixerox.edmics-rlc` = MimeType("image/vnd.fujixerox.edmics-rlc", "rlc")
val `image/vnd.globalgraphics.pgb` = MimeType("image/vnd.globalgraphics.pgb")
val `image/vnd.microsoft.icon` = MimeType("image/vnd.microsoft.icon")
val `image/vnd.mix` = MimeType("image/vnd.mix")
val `image/vnd.ms-modi` = MimeType("image/vnd.ms-modi", "mdi")
val `image/vnd.net-fpx` = MimeType("image/vnd.net-fpx", "npx")
val `image/vnd.radiance` = MimeType("image/vnd.radiance")
val `image/vnd.sealed.png` = MimeType("image/vnd.sealed.png")
val `image/vnd.sealedmedia.softseal.gif` = MimeType("image/vnd.sealedmedia.softseal.gif")
val `image/vnd.sealedmedia.softseal.jpg` = MimeType("image/vnd.sealedmedia.softseal.jpg")
val `image/vnd.svf` = MimeType("image/vnd.svf")
val `image/vnd.wap.wbmp` = MimeType("image/vnd.wap.wbmp", "wbmp")
val `image/vnd.xiff` = MimeType("image/vnd.xiff", "xif")
val `image/x-cmu-raster` = MimeType("image/x-cmu-raster", "ras")
val `image/x-cmx` = MimeType("image/x-cmx", "cmx")
val `image/x-coreldraw` = MimeType("image/x-coreldraw", "cdr")
val `image/x-coreldrawpattern` = MimeType("image/x-coreldrawpattern", "pat")
val `image/x-coreldrawtemplate` = MimeType("image/x-coreldrawtemplate", "cdt")
val `image/x-corelphotopaint` = MimeType("image/x-corelphotopaint", "cpt")
val `image/x-freehand` = MimeType("image/x-freehand", "fh", "fh4", "fh5", "fh7", "fhc")
val `image/x-icon` = MimeType("image/x-icon", "ico")
val `image/x-jg` = MimeType("image/x-jg", "art")
val `image/x-jng` = MimeType("image/x-jng", "jng")
val `image/x-ms-bmp` = MimeType("image/x-ms-bmp", "bmp")
val `image/x-pcx` = MimeType("image/x-pcx", "pcx")
val `image/x-photoshop` = MimeType("image/x-photoshop", "psd")
val `image/x-pict` = MimeType("image/x-pict", "pct", "pic")
val `image/x-portable-anymap` = MimeType("image/x-portable-anymap", "pnm")
val `image/x-portable-bitmap` = MimeType("image/x-portable-bitmap", "pbm")
val `image/x-portable-graymap` = MimeType("image/x-portable-graymap", "pgm")
val `image/x-portable-pixmap` = MimeType("image/x-portable-pixmap", "ppm")
val `image/x-rgb` = MimeType("image/x-rgb", "rgb")
val `image/x-xbitmap` = MimeType("image/x-xbitmap", "xbm")
val `image/x-xpixmap` = MimeType("image/x-xpixmap", "xpm")
val `image/x-xwindowdump` = MimeType("image/x-xwindowdump", "xwd")
val `message/cpim` = MimeType("message/cpim")
val `message/delivery-status` = MimeType("message/delivery-status")
val `message/disposition-notification` = MimeType("message/disposition-notification")
val `message/example` = MimeType("message/example")
val `message/external-body` = MimeType("message/external-body")
val `message/global` = MimeType("message/global")
val `message/global-delivery-status` = MimeType("message/global-delivery-status")
val `message/global-disposition-notification` = MimeType("message/global-disposition-notification")
val `message/global-headers` = MimeType("message/global-headers")
val `message/http` = MimeType("message/http")
val `message/imdn+xml` = MimeType("message/imdn+xml")
val `message/news` = MimeType("message/news")
val `message/partial` = MimeType("message/partial")
val `message/rfc822` = MimeType("message/rfc822", "eml", "mime")
val `message/s-http` = MimeType("message/s-http")
val `message/sip` = MimeType("message/sip")
val `message/sipfrag` = MimeType("message/sipfrag")
val `message/tracking-status` = MimeType("message/tracking-status")
val `message/vnd.si.simp` = MimeType("message/vnd.si.simp")
val `model/example` = MimeType("model/example")
val `model/iges` = MimeType("model/iges", "iges", "igs")
val `model/mesh` = MimeType("model/mesh", "mesh", "msh", "silo")
val `model/vnd.dwf` = MimeType("model/vnd.dwf", "dwf")
val `model/vnd.flatland.3dml` = MimeType("model/vnd.flatland.3dml")
val `model/vnd.gdl` = MimeType("model/vnd.gdl", "gdl")
val `model/vnd.gs-gdl` = MimeType("model/vnd.gs-gdl")
val `model/vnd.gs.gdl` = MimeType("model/vnd.gs.gdl")
val `model/vnd.gtw` = MimeType("model/vnd.gtw", "gtw")
val `model/vnd.moml+xml` = MimeType("model/vnd.moml+xml")
val `model/vnd.mts` = MimeType("model/vnd.mts", "mts")
val `model/vnd.parasolid.transmit.binary` = MimeType("model/vnd.parasolid.transmit.binary")
val `model/vnd.parasolid.transmit.text` = MimeType("model/vnd.parasolid.transmit.text")
val `model/vnd.vtu` = MimeType("model/vnd.vtu", "vtu")
val `model/vrml` = MimeType("model/vrml", "vrml", "wrl")
val `multipart/alternative` = MimeType("multipart/alternative")
val `multipart/appledouble` = MimeType("multipart/appledouble")
val `multipart/byteranges` = MimeType("multipart/byteranges")
val `multipart/digest` = MimeType("multipart/digest")
val `multipart/encrypted` = MimeType("multipart/encrypted")
val `multipart/example` = MimeType("multipart/example")
val `multipart/form-data` = MimeType("multipart/form-data")
val `multipart/header-set` = MimeType("multipart/header-set")
val `multipart/mixed` = MimeType("multipart/mixed")
val `multipart/parallel` = MimeType("multipart/parallel")
val `multipart/related` = MimeType("multipart/related")
val `multipart/report` = MimeType("multipart/report")
val `multipart/signed` = MimeType("multipart/signed")
val `multipart/voice-message` = MimeType("multipart/voice-message")
val `text/calendar` = MimeType("text/calendar", "ics", "icz", "ifb")
val `text/comma-separated-values` = MimeType("text/comma-separated-values", "csv")
val `text/css` = MimeType("text/css", "css")
val `text/csv` = MimeType("text/csv", "csv")
val `text/directory` = MimeType("text/directory")
val `text/dns` = MimeType("text/dns")
val `text/ecmascript` = MimeType("text/ecmascript")
val `text/enriched` = MimeType("text/enriched")
val `text/example` = MimeType("text/example")
val `text/h323` = MimeType("text/h323", "323")
val `text/html` = MimeType("text/html", "htm", "html", "shtml")
val `text/iuls` = MimeType("text/iuls", "uls")
val `text/javascript` = MimeType("text/javascript")
val `text/mathml` = MimeType("text/mathml", "mml")
val `text/parityfec` = MimeType("text/parityfec")
val `text/prs.fallenstein.rst` = MimeType("text/prs.fallenstein.rst")
val `text/prs.lines.tag` = MimeType("text/prs.lines.tag", "dsc")
val `text/red` = MimeType("text/red")
val `text/rfc822-headers` = MimeType("text/rfc822-headers")
val `text/richtext` = MimeType("text/richtext", "rtx")
val `text/rtf` = MimeType("text/rtf", "rtf")
val `text/rtp-enc-aescm128` = MimeType("text/rtp-enc-aescm128")
val `text/rtx` = MimeType("text/rtx")
val `text/scriptlet` = MimeType("text/scriptlet", "sct", "wsc")
val `text/sgml` = MimeType("text/sgml", "sgm", "sgml")
val `text/t140` = MimeType("text/t140")
val `text/tab-separated-values` = MimeType("text/tab-separated-values", "tsv")
val `text/texmacs` = MimeType("text/texmacs", "tm", "ts")
val `text/troff` = MimeType("text/troff", "man", "me", "ms", "roff", "t", "tr")
val `text/ulpfec` = MimeType("text/ulpfec")
val `text/uri-list` = MimeType("text/uri-list", "uri", "uris", "urls")
val `text/vnd.abc` = MimeType("text/vnd.abc")
val `text/vnd.curl` = MimeType("text/vnd.curl", "curl")
val `text/vnd.curl.dcurl` = MimeType("text/vnd.curl.dcurl", "dcurl")
val `text/vnd.curl.mcurl` = MimeType("text/vnd.curl.mcurl", "mcurl")
val `text/vnd.curl.scurl` = MimeType("text/vnd.curl.scurl", "scurl")
val `text/vnd.dmclientscript` = MimeType("text/vnd.dmclientscript")
val `text/vnd.esmertec.theme-descriptor` = MimeType("text/vnd.esmertec.theme-descriptor")
val `text/vnd.fly` = MimeType("text/vnd.fly", "fly")
val `text/vnd.fmi.flexstor` = MimeType("text/vnd.fmi.flexstor", "flx")
val `text/vnd.graphviz` = MimeType("text/vnd.graphviz", "gv")
val `text/vnd.in3d.3dml` = MimeType("text/vnd.in3d.3dml", "3dml")
val `text/vnd.in3d.spot` = MimeType("text/vnd.in3d.spot", "spot")
val `text/vnd.iptc.newsml` = MimeType("text/vnd.iptc.newsml")
val `text/vnd.iptc.nitf` = MimeType("text/vnd.iptc.nitf")
val `text/vnd.latex-z` = MimeType("text/vnd.latex-z")
val `text/vnd.motorola.reflex` = MimeType("text/vnd.motorola.reflex")
val `text/vnd.ms-mediapackage` = MimeType("text/vnd.ms-mediapackage")
val `text/vnd.net2phone.commcenter.command` = MimeType("text/vnd.net2phone.commcenter.command")
val `text/vnd.si.uricatalogue` = MimeType("text/vnd.si.uricatalogue")
val `text/vnd.sun.j2me.app-descriptor` = MimeType("text/vnd.sun.j2me.app-descriptor", "jad")
val `text/vnd.trolltech.linguist` = MimeType("text/vnd.trolltech.linguist")
val `text/vnd.wap.si` = MimeType("text/vnd.wap.si")
val `text/vnd.wap.sl` = MimeType("text/vnd.wap.sl")
val `text/vnd.wap.wml` = MimeType("text/vnd.wap.wml", "wml")
val `text/vnd.wap.wmlscript` = MimeType("text/vnd.wap.wmlscript", "wmls")
val `text/x-asm` = MimeType("text/x-asm", "asm", "s")
val `text/x-bibtex` = MimeType("text/x-bibtex", "bib")
val `text/x-c` = MimeType("text/x-c", "c", "cc", "cpp", "cxx", "dic", "h", "hh")
val `text/x-c++hdr` = MimeType("text/x-c++hdr", "h", "++", "hh", "hpp", "hxx")
val `text/x-c++src` = MimeType("text/x-c++src", "c", "++", "cc", "cpp", "cxx")
val `text/x-chdr` = MimeType("text/x-chdr", "h")
val `text/x-csh` = MimeType("text/x-csh", "csh")
val `text/x-csrc` = MimeType("text/x-csrc", "c")
val `text/x-fortran` = MimeType("text/x-fortran", "f", "f77", "f90", "for")
val `text/x-haskell` = MimeType("text/x-haskell", "hs")
val `text/x-java` = MimeType("text/x-java", "java")
val `text/x-java-source` = MimeType("text/x-java-source", "java")
val `text/x-literate-haskell` = MimeType("text/x-literate-haskell", "lhs")
val `text/x-moc` = MimeType("text/x-moc", "moc")
val `text/x-pascal` = MimeType("text/x-pascal", "p", "pas")
val `text/x-pcs-gcd` = MimeType("text/x-pcs-gcd", "gcd")
val `text/x-perl` = MimeType("text/x-perl", "pl", "pm")
val `text/x-psp` = MimeType("text/x-psp", "psp")
val `text/x-python` = MimeType("text/x-python", "py")
val `text/x-setext` = MimeType("text/x-setext", "etx")
val `text/x-sh` = MimeType("text/x-sh", "sh")
val `text/x-tcl` = MimeType("text/x-tcl", "tcl", "tk")
val `text/x-tex` = MimeType("text/x-tex", "cls", "ltx", "sty", "tex")
val `text/x-uuencode` = MimeType("text/x-uuencode", "uu")
val `text/x-vcalendar` = MimeType("text/x-vcalendar", "vcs")
val `text/x-vcard` = MimeType("text/x-vcard", "vcf")
val `text/xml` = MimeType("text/xml")
val `text/xml-external-parsed-entity` = MimeType("text/xml-external-parsed-entity")
val `video/3gpp` = MimeType("video/3gpp", "3gp")
val `video/3gpp-tt` = MimeType("video/3gpp-tt")
val `video/3gpp2` = MimeType("video/3gpp2", "3g2")
val `video/bmpeg` = MimeType("video/bmpeg")
val `video/bt656` = MimeType("video/bt656")
val `video/celb` = MimeType("video/celb")
val `video/dl` = MimeType("video/dl", "dl")
val `video/dv` = MimeType("video/dv", "dif", "dv")
val `video/example` = MimeType("video/example")
val `video/fli` = MimeType("video/fli", "fli")
val `video/gl` = MimeType("video/gl", "gl")
val `video/h261` = MimeType("video/h261", "h261")
val `video/h263` = MimeType("video/h263", "h263")
val `video/h263-1998` = MimeType("video/h263-1998")
val `video/h263-2000` = MimeType("video/h263-2000")
val `video/h264` = MimeType("video/h264", "h264")
val `video/jpeg` = MimeType("video/jpeg", "jpgv")
val `video/jpeg2000` = MimeType("video/jpeg2000")
val `video/jpm` = MimeType("video/jpm", "jpgm", "jpm")
val `video/mj2` = MimeType("video/mj2", "mj2", "mjp2")
val `video/mp1s` = MimeType("video/mp1s")
val `video/mp2p` = MimeType("video/mp2p")
val `video/mp2t` = MimeType("video/mp2t")
val `video/mp4` = MimeType("video/mp4", "mp4", "mp4v", "mpg4")
val `video/mp4v-es` = MimeType("video/mp4v-es")
val `video/mpeg` = MimeType("video/mpeg", "m1v", "m2v", "mpe", "mpeg", "mpg")
val `video/mpeg4-generic` = MimeType("video/mpeg4-generic")
val `video/mpv` = MimeType("video/mpv")
val `video/nv` = MimeType("video/nv")
val `video/ogg` = MimeType("video/ogg", "ogv")
val `video/parityfec` = MimeType("video/parityfec")
val `video/pointer` = MimeType("video/pointer")
val `video/quicktime` = MimeType("video/quicktime", "mov", "qt")
val `video/raw` = MimeType("video/raw")
val `video/rtp-enc-aescm128` = MimeType("video/rtp-enc-aescm128")
val `video/rtx` = MimeType("video/rtx")
val `video/smpte292m` = MimeType("video/smpte292m")
val `video/ulpfec` = MimeType("video/ulpfec")
val `video/vc1` = MimeType("video/vc1")
val `video/vnd.cctv` = MimeType("video/vnd.cctv")
val `video/vnd.dlna.mpeg-tts` = MimeType("video/vnd.dlna.mpeg-tts")
val `video/vnd.fvt` = MimeType("video/vnd.fvt", "fvt")
val `video/vnd.hns.video` = MimeType("video/vnd.hns.video")
val `video/vnd.iptvforum.1dparityfec-1010` = MimeType("video/vnd.iptvforum.1dparityfec-1010")
val `video/vnd.iptvforum.1dparityfec-2005` = MimeType("video/vnd.iptvforum.1dparityfec-2005")
val `video/vnd.iptvforum.2dparityfec-1010` = MimeType("video/vnd.iptvforum.2dparityfec-1010")
val `video/vnd.iptvforum.2dparityfec-2005` = MimeType("video/vnd.iptvforum.2dparityfec-2005")
val `video/vnd.iptvforum.ttsavc` = MimeType("video/vnd.iptvforum.ttsavc")
val `video/vnd.iptvforum.ttsmpeg2` = MimeType("video/vnd.iptvforum.ttsmpeg2")
val `video/vnd.motorola.video` = MimeType("video/vnd.motorola.video")
val `video/vnd.motorola.videop` = MimeType("video/vnd.motorola.videop")
val `video/vnd.mpegurl` = MimeType("video/vnd.mpegurl", "m4u", "mxu")
val `video/vnd.ms-playready.media.pyv` = MimeType("video/vnd.ms-playready.media.pyv", "pyv")
val `video/vnd.nokia.interleaved-multimedia` = MimeType("video/vnd.nokia.interleaved-multimedia")
val `video/vnd.nokia.videovoip` = MimeType("video/vnd.nokia.videovoip")
val `video/vnd.objectvideo` = MimeType("video/vnd.objectvideo")
val `video/vnd.sealed.mpeg1` = MimeType("video/vnd.sealed.mpeg1")
val `video/vnd.sealed.mpeg4` = MimeType("video/vnd.sealed.mpeg4")
val `video/vnd.sealed.swf` = MimeType("video/vnd.sealed.swf")
val `video/vnd.sealedmedia.softseal.mov` = MimeType("video/vnd.sealedmedia.softseal.mov")
val `video/vnd.vivo` = MimeType("video/vnd.vivo", "viv")
val `video/x-f4v` = MimeType("video/x-f4v", "f4v")
val `video/x-fli` = MimeType("video/x-fli", "fli")
val `video/x-flv` = MimeType("video/x-flv", "flv")
val `video/x-la-asf` = MimeType("video/x-la-asf", "lsf", "lsx")
val `video/x-m4v` = MimeType("video/x-m4v", "m4v")
val `video/x-mng` = MimeType("video/x-mng", "mng")
val `video/x-ms-asf` = MimeType("video/x-ms-asf", "asf", "asx")
val `video/x-ms-wm` = MimeType("video/x-ms-wm", "wm")
val `video/x-ms-wmv` = MimeType("video/x-ms-wmv", "wmv")
val `video/x-ms-wmx` = MimeType("video/x-ms-wmx", "wmx")
val `video/x-ms-wvx` = MimeType("video/x-ms-wvx", "wvx")
val `video/x-msvideo` = MimeType("video/x-msvideo", "avi")
val `video/x-sgi-movie` = MimeType("video/x-sgi-movie", "movie")
val `x-conference/x-cooltalk` = MimeType("x-conference/x-cooltalk", "ice")
val `x-world/x-vrml` = MimeType("x-world/x-vrml", "vrm", "vrml", "wrl")
val mimeTypesMap = new javax.activation.MimetypesFileTypeMap()
types.values foreach { t =>
mimeTypesMap.addMimeTypes(t.name + " " + t.extensions.mkString(" "))
}
}
================================================
FILE: net/shared/src/main/scala/rapture/net/browser.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.net
import rapture.core._
import rapture.io._
import rapture.uri._
import java.text.SimpleDateFormat
import java.util.Locale
import scala.collection.mutable
case class Cookie[I, D](domain: String,
name: String,
value: String,
path: RootedPath,
expiry: Option[I],
secure: Boolean)(implicit ts: TimeSystem[I, D]) {
lazy val pathString = path.toString
}
class Browser[I: TimeSystem.ByInstant]() {
val browserString = "Rapture Browser 2.0.0"
private val Rfc1036Pattern = "EEE, dd-MMM-yyyy HH:mm:ss zzz"
val ts = ?[TimeSystem.ByInstant[I]]
val cookies: mutable.HashMap[(String, String, RootedPath), Cookie[I, _]] =
new mutable.HashMap[(String, String, RootedPath), Cookie[I, _]]
def parseCookie(s: String, domain: String): Cookie[I, _] = {
val ps = s.split(";").map(_.trim.split("=")) map { a =>
a(0) -> (if (a.length > 1) a(1).urlDecode else "")
}
val details = ps.tail.toMap
Cookie(details.getOrElse("domain", domain),
ps.head._1,
ps.head._2,
RootedPath.parse(details.getOrElse("path", "")).getOrElse(RootedPath(Vector())),
details.get("expires") map { exp =>
ts.instant(new SimpleDateFormat(Rfc1036Pattern, Locale.US).parse(exp).getTime)
},
details.contains("secure"))
}
def domainCookies(domain: String, secure: Boolean, path: String): String = {
val now = System.currentTimeMillis
cookies foreach { c =>
if (c._2.expiry.exists(e => ts.fromInstant(e) < now))
cookies.remove((c._2.domain, c._2.name, c._2.path))
}
cookies.toList
.filter(secure || !_._2.secure)
.filter(domain endsWith
_._2.domain)
.filter(path startsWith _._2.pathString)
.map(_._2)
.groupBy(_.name) map { c =>
c._1 + "=" + c._2.maxBy(_.pathString.length).value.urlEncode
} mkString "; "
}
def accept[I2, D](c: Cookie[I2, D]): Boolean = c.domain.split("\\.").length > 1
/*class BrowserUrl(url: HttpUrl) {
def httpGet[D]()(implicit httpTimeout: HttpTimeout, httpCertificateConfig: HttpCertificateConfig,
httpRedirectConfig: HttpRedirectConfig) = url.httpGet()
def httpPost[C: PostType, D](
content: C,
headers: Map[String, String] = Map())
(implicit mode: Mode[`BrowserUrl#httpPost`], httpTimeout: HttpTimeout, httpCertificateConfig: HttpCertificateConfig, httpRedirectConfig: HttpRedirectConfig, httpBasicAuthentication: HttpBasicAuthentication): mode.Wrap[HttpResponse, HttpExceptions with httpTimeout.Throws] =
mode.wrap {
implicit val m = mode.generic
// FIXME: Reimplement this with recursion
var u = url
var retries = 0
var response: HttpResponse = null
do {
response = mode.unwrap(u.httpPost[C, D](content, headers + ("Cookie" -> domainCookies(u.hostname, u.ssl, u.pathString))))
val newCookies = response.headers.get("Set-Cookie").getOrElse(Nil) map { c =>
parseCookie(c, u.hostname)
} filter { c: Cookie[I, _] => accept(c) }
for(c <- newCookies) cookies((c.domain, c.name, c.path)) = c
if(response.status/100 == 3) {
retries += 1
if(retries > 5) throw TooManyRedirects()
val dest = response.headers("Location").headOption.getOrElse(throw BadHttpResponse())
u = if(dest.startsWith("http")) Http.parse(dest)
else if(dest.startsWith("/")) Http / u.hostname / RootedPath.parse(dest)
// FIXME: This doesn't handle ascent in relative paths
else u / RootedPath.parse(dest)
}
} while(response.status/100 == 3)
response
}
}
def apply(url: HttpUrl): BrowserUrl = new BrowserUrl(url)*/
}
================================================
FILE: net/shared/src/main/scala/rapture/net/exceptions.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.net
sealed trait HttpExceptions extends Exception
case class TooManyRedirects() extends HttpExceptions
case class BadHttpResponse() extends HttpExceptions
================================================
FILE: net/shared/src/main/scala/rapture/net/http.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.net
import rapture.io._
import rapture.uri._
import rapture.core._
import java.io._
import java.net._
import javax.net.ssl._
object HttpSupport {
class Capability[Res](res: Res) {
def httpPut[C: PostType](
content: C,
headers: Map[String, String] = Map()
)(
implicit httpSupport: HttpSupport[Res],
mode: Mode[`NetUrl#httpPut`],
httpTimeout: HttpTimeout,
httpRedirectConfig: HttpRedirectConfig,
httpCertificateConfig: HttpCertificateConfig,
httpBasicAuthentication: HttpBasicAuthentication
): mode.Wrap[HttpResponse, HttpExceptions with httpTimeout.Throws] =
mode.wrap(httpSupport.doHttp(res, content, headers, "PUT"))
def httpHead(
headers: Map[String, String] = Map()
)(
implicit httpSupport: HttpSupport[Res],
mode: Mode[`NetUrl#httpHead`],
httpTimeout: HttpTimeout,
httpRedirectConfig: HttpRedirectConfig,
httpCertificateConfig: HttpCertificateConfig,
httpBasicAuthentication: HttpBasicAuthentication
): mode.Wrap[HttpResponse, HttpExceptions with httpTimeout.Throws] =
mode.wrap(httpSupport.doHttp(res, None, headers, "HEAD"))
def httpGet(
headers: Map[String, String] = Map()
)(
implicit httpSupport: HttpSupport[Res],
mode: Mode[`NetUrl#httpHead`],
httpTimeout: HttpTimeout,
httpRedirectConfig: HttpRedirectConfig,
httpCertificateConfig: HttpCertificateConfig,
httpBasicAuthentication: HttpBasicAuthentication
): mode.Wrap[HttpResponse, HttpExceptions with httpTimeout.Throws] =
mode.wrap(httpSupport.doHttp(res, None, headers, "GET"))
def httpPost[C: PostType](
content: C,
headers: Map[String, String] = Map()
)(
implicit httpSupport: HttpSupport[Res],
mode: Mode[`NetUrl#httpPut`],
httpTimeout: HttpTimeout,
httpRedirectConfig: HttpRedirectConfig,
httpCertificateConfig: HttpCertificateConfig,
httpBasicAuthentication: HttpBasicAuthentication
): mode.Wrap[HttpResponse, HttpExceptions with httpTimeout.Throws] =
mode.wrap(httpSupport.doHttp(res, content, headers, "POST"))
def httpDelete(
headers: Map[String, String] = Map()
)(
implicit httpSupport: HttpSupport[Res],
mode: Mode[`NetUrl#httpPut`],
httpTimeout: HttpTimeout,
httpRedirectConfig: HttpRedirectConfig,
httpCertificateConfig: HttpCertificateConfig,
httpBasicAuthentication: HttpBasicAuthentication
): mode.Wrap[HttpResponse, HttpExceptions with httpTimeout.Throws] =
mode.wrap(httpSupport.doHttp(res, None, headers, "DELETE"))
def httpOptions(
headers: Map[String, String] = Map()
)(
implicit httpSupport: HttpSupport[Res],
mode: Mode[`NetUrl#httpPut`],
httpTimeout: HttpTimeout,
httpRedirectConfig: HttpRedirectConfig,
httpCertificateConfig: HttpCertificateConfig,
httpBasicAuthentication: HttpBasicAuthentication
): mode.Wrap[HttpResponse, HttpExceptions with httpTimeout.Throws] =
mode.wrap(httpSupport.doHttp(res, None, headers, "OPTIONS"))
def httpTrace(
headers: Map[String, String] = Map()
)(
implicit httpSupport: HttpSupport[Res],
mode: Mode[`NetUrl#httpPut`],
httpTimeout: HttpTimeout,
httpRedirectConfig: HttpRedirectConfig,
httpCertificateConfig: HttpCertificateConfig,
httpBasicAuthentication: HttpBasicAuthentication
): mode.Wrap[HttpResponse, HttpExceptions with httpTimeout.Throws] =
mode.wrap(httpSupport.doHttp(res, None, headers, "TRACE"))
}
implicit def basicHttpSupport[H: UriCapable]: HttpSupport[H] = new HttpSupport[H] {
def doHttp[C: PostType, T](
res: H,
content: C,
headers: Map[String, String],
method: String
)(
implicit mode: Mode[`NetUrl#httpPost`],
httpTimeout: HttpTimeout,
httpRedirectConfig: HttpRedirectConfig,
httpCertificateConfig: HttpCertificateConfig,
httpBasicAuthentication: HttpBasicAuthentication
): mode.Wrap[HttpResponse, HttpExceptions with httpTimeout.Throws] =
mode wrap {
// FIXME: This will produce a race condition if creating multiple URL connections with
// different values for followRedirects in parallel
HttpURLConnection.setFollowRedirects(httpRedirectConfig.follow)
val conn: URLConnection = new URL(implicitly[UriCapable[H]].uri(res).toString).openConnection()
conn.setConnectTimeout(httpTimeout.duration)
conn match {
case c: HttpsURLConnection =>
if (httpCertificateConfig.ignoreIfInvalid) {
c.setSSLSocketFactory(NetUrl.sslContext.getSocketFactory)
c.setHostnameVerifier(NetUrl.allHostsValid)
}
c.setRequestMethod(method)
if (content != None) c.setDoOutput(true)
c.setUseCaches(false)
case c: HttpURLConnection =>
c.setRequestMethod(method)
if (content != None) c.setDoOutput(true)
c.setUseCaches(false)
}
// FIXME: What an ugly way of writing this.
httpBasicAuthentication.credentials foreach {
case (username, password) =>
conn.setRequestProperty("Authorization",
"Basic " + NetUrl.base64.encode(s"$username:$password".getBytes("UTF-8")).mkString)
}
?[PostType[C]].contentType foreach { ct =>
conn.setRequestProperty("Content-Type", ct.name)
}
for ((k, v) <- headers) conn.setRequestProperty(k, v)
if (content != None)
ensuring(OutputStreamBuilder.output(conn.getOutputStream)) { out =>
?[PostType[C]].sender(content) > out
}
import scala.collection.JavaConverters._
val statusCode = conn match {
case c: HttpsURLConnection => c.getResponseCode()
case c: HttpURLConnection => c.getResponseCode()
}
val is = try conn.getInputStream()
catch {
case e: IOException =>
conn match {
case c: HttpsURLConnection => c.getErrorStream()
case c: HttpURLConnection => c.getErrorStream()
}
}
new HttpResponse(mapAsScalaMapConverter(conn.getHeaderFields()).asScala.toMap
.mapValues(collectionAsScalaIterableConverter(_).asScala.to[List]), statusCode, is)
}
}
}
trait HttpSupport[Res] {
def doHttp[C: PostType, T](
res: Res,
content: C,
headers: Map[String, String],
method: String
)(
implicit mode: Mode[`NetUrl#httpPost`],
httpTimeout: HttpTimeout,
httpRedirectConfig: HttpRedirectConfig,
httpCertificateConfig: HttpCertificateConfig,
httpBasicAuthentication: HttpBasicAuthentication
): mode.Wrap[HttpResponse, HttpExceptions with httpTimeout.Throws]
}
================================================
FILE: net/shared/src/main/scala/rapture/net/ip.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.net
import rapture.core._
import rapture.codec._
object Ipv6 {
def parse(s: String)(implicit mode: Mode[`Ipv6.parse`]): mode.Wrap[Ipv6, Exception] =
mode.wrap {
val groups: Array[String] = s.split("::").map(_.split(":")) match {
case Array() => Array.fill(8)("")
case Array(xs) => xs.padTo(8, "")
case Array(Array(""), xs) => Array.fill(8 - xs.length)("") ++ xs
case Array(xs, ys) => xs ++ Array.fill(8 - xs.length - ys.length)("") ++ ys
}
val gs = groups map (decode[Hex](_).bytes) map {
case Array() => 0
case Array(le) => le
case Array(be, le) => (be << 8) + le
}
Ipv6(gs(0), gs(1), gs(2), gs(3), gs(4), gs(5), gs(6), gs(7))
}
}
object Ipv4 {
def parse(s: String) = {
val vs = s.split("\\.").map(_.toInt)
Ipv4(vs(0), vs(1), vs(2), vs(3))
}
def fromLong(lng: Long) =
Ipv4((lng >> 24 & 255L).toInt, (lng >> 16 & 255L).toInt, (lng >> 8 & 255L).toInt, (lng & 255L).toInt)
lazy val privateSubnets =
List(Ipv4(10, 0, 0, 0) / 8, Ipv4(192, 168, 0, 0) / 16, Ipv4(172, 16, 0, 0) / 12, Ipv4(127, 0, 0, 0) / 8)
}
case class Ipv6(s1: Int, s2: Int, s3: Int, s4: Int, s5: Int, s6: Int, s7: Int, s8: Int) {
def groups = Vector(s1, s2, s3, s4, s5, s6, s7, s8)
def expanded =
groups map { s =>
Bytes(Array(((s >> 8) & 0xff).toByte, (s & 0xff).toByte)).encode[Hex]
} mkString ":"
override def toString = expanded.replaceAll("^0+", "").replaceAll(":0+", ":").replaceAll("::+", "::")
}
case class Ipv4(b1: Int, b2: Int, b3: Int, b4: Int) {
if (b1 > 255 || b2 > 255 || b3 > 255 || b4 > 255 || b1 < 0 || b2 < 0 || b3 < 0 || b4 < 0)
throw new InstantiationException("The components of the IP address must be in the range 0-255")
def asLong = (b1.toLong << 24) + (b2 << 16) + (b3 << 8) + b4
def /(i: Int): Subnet = new Subnet(this, i)
def in(subnet: Subnet) = subnet contains this
override def toString() = b1 + "." + b2 + "." + b3 + "." + b4
def isPrivate = Ipv4.privateSubnets.exists(in)
override def equals(that: Any): Boolean = that match {
case that: Ipv4 => b1 == that.b1 && b2 == that.b2 && b3 == that.b3 && b4 == that.b4
case _ => false
}
override def hashCode = b1 << 24 | b2 << 16 | b3 << 8 | b4
}
object Subnet {
def parse(s: String) = {
val x = s.split("\\/")
new Subnet(Ipv4.parse(x(0)), x(1).toInt)
}
}
class Subnet(baseIp: Ipv4, val bits: Int) extends Iterable[Ipv4] {
if (bits < 0 || bits > 32)
throw new InstantiationException("The subnet size must be in the range 0-32")
def iterator: Iterator[Ipv4] = new Iterator[Ipv4] {
private var current = baseIp.asLong - 1
def hasNext = current < maximum.asLong
def next = {
current += 1
Ipv4.fromLong(current)
}
}
def maximum = Ipv4.fromLong((((baseIp.asLong >> (32 - bits)) + 1) << (32 - bits)) - 1)
val ip = Ipv4.fromLong((baseIp.asLong >> (32 - bits)) << (32 - bits))
override def size = 1 << (32 - bits)
override def toString() = ip.toString + "/" + bits
def contains(ip2: Ipv4) = Ipv4.fromLong((ip2.asLong >> (32 - bits)) << (32 - bits)) == ip
override def equals(that: Any) = that match {
case that: Subnet => ip == that.ip && bits == that.bits
case _ => false
}
override def hashCode = ip.hashCode | bits
}
object Localhost extends Ipv4(127, 0, 0, 1)
================================================
FILE: net/shared/src/main/scala/rapture/net/net.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.net
import rapture.io._
import rapture.uri._
import rapture.mime._
import rapture.core._
import rapture.codec._
import java.io._
import javax.net.ssl._
case class TimeoutException() extends Exception("Timeout")
case class InvalidCertificateException() extends Exception("Timeout")
object HttpTimeout {
implicit val defaultHttpTimeout: HttpTimeout { type Throws = TimeoutException } = new HttpTimeout(10000) {
type Throws = TimeoutException
}
def apply[T: TimeSystem.ByDuration](timeout: T) =
new HttpTimeout(Math.min(Int.MaxValue, ?[TimeSystem.ByDuration[T]].fromDuration(timeout)).toInt) {
type Throws = TimeoutException
}
}
class HttpTimeout(val duration: Int) {
type Throws <: Exception
}
class HttpCertificateConfig(val ignoreIfInvalid: Boolean) {
type Throws <: Exception
}
object HttpCertificateConfig {
implicit val defaultHttpCertificateConfig: HttpCertificateConfig { type Throws = InvalidCertificateException } =
new HttpCertificateConfig(true) { type Throws = InvalidCertificateException }
}
object HttpRedirectConfig {
implicit val defaultHttpRedirectConfig: HttpRedirectConfig = new HttpRedirectConfig(true)
}
class HttpRedirectConfig(val follow: Boolean)
object HttpBasicAuthentication {
implicit val defaultHttpBasicAuthentication: HttpBasicAuthentication = new HttpBasicAuthentication(None)
}
class HttpBasicAuthentication(val credentials: Option[(String, String)]) {
type Throws
}
object httpOptions {
object noTimeout {
implicit val implicitHttpTimeout: HttpTimeout { type Throws = Nothing } = new HttpTimeout(-1) {
type Throws = Nothing
}
}
object ignoreInvalidCertificates {
implicit val implicitCertificateConfig: HttpCertificateConfig = new HttpCertificateConfig(true)
}
object doNotFollowRedirects {
implicit val implicitFollowRedirects: HttpRedirectConfig = new HttpRedirectConfig(false)
}
}
object HttpMethods {
private val methods = new scala.collection.mutable.HashMap[String, Method]
sealed class Method(val string: String) {
def unapply(r: String) = r == string
override def toString = string
methods += string -> this
}
trait FormMethod { this: Method => }
def method(s: String) = methods(s)
val Get = new Method("GET") with FormMethod
val Put = new Method("PUT")
val Post = new Method("POST") with FormMethod
val Delete = new Method("DELETE")
val Trace = new Method("TRACE")
val Options = new Method("OPTIONS")
val Head = new Method("HEAD")
val Connect = new Method("CONNECT")
val Patch = new Method("PATCH")
}
class HttpResponse(val headers: Map[String, List[String]], val status: Int, is: InputStream) {
def input[Data](implicit ib: InputBuilder[InputStream, Data],
mode: Mode[`HttpResponse#input`]): mode.Wrap[Input[Data], Exception] =
mode.wrap(ib.input(is))
}
object PostType {
implicit val nonePostType: PostType[None.type] = new PostType[None.type] {
def contentType = Some(MimeTypes.`application/x-www-form-urlencoded`)
def sender(content: None.type) = ByteArrayInput(Array[Byte](0))
}
implicit def formPostType: PostType[Map[Symbol, String]] = new PostType[Map[Symbol, String]] {
def contentType = Some(MimeTypes.`application/x-www-form-urlencoded`)
def sender(content: Map[Symbol, String]) =
ByteArrayInput((content map {
case (k, v) =>
java.net.URLEncoder.encode(k.name, "UTF-8") + "=" + java.net.URLEncoder.encode(v, "UTF-8")
} mkString "&").getBytes("UTF-8"))
}
implicit def stringPostType[S: StringSerializer](implicit enc: Encoding): PostType[S] = new PostType[S] {
def contentType = Some(MimeTypes.`text/plain`)
def sender(content: S) = implicitly[StringSerializer[S]].serialize(content).input[Byte]
}
}
trait PostType[-C] {
def contentType: Option[MimeTypes.MimeType]
def sender(content: C): Input[Byte]
}
object NetUrl {
val sslContext = SSLContext.getInstance("SSL")
val allHostsValid = new HostnameVerifier {
def verify(hostname: String, session: SSLSession) = true
}
trait Base64Padded extends CodecType
implicit val base64: ByteCodec[Base64Padded] = new Base64Codec[Base64Padded](endPadding = true)
}
trait NetUrl {
private val trustAllCertificates = {
Array[TrustManager](new X509TrustManager {
override def getAcceptedIssuers(): Array[java.security.cert.X509Certificate] = null
def checkClientTrusted(certs: Array[java.security.cert.X509Certificate], authType: String): Unit = ()
def checkServerTrusted(certs: Array[java.security.cert.X509Certificate], authType: String): Unit = ()
})
}
NetUrl.sslContext.init(null, trustAllCertificates, new java.security.SecureRandom())
def hostname: String
def port: Int
def ssl: Boolean
def canonicalPort: Int
}
object HttpUrl {
implicit val hasResourceName: HasResourceName[HttpUrl] = new HasResourceName[HttpUrl] {
def resourceName(httpUrl: HttpUrl): String = httpUrl.elements.lastOption.getOrElse(httpUrl.root.hostname)
}
implicit val parser: StringParser[HttpUrl] = new StringParser[HttpUrl] {
type Throws = ParseException
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[HttpUrl, Throws] = mode.wrap(Http.parse(s))
}
implicit val serializer: StringSerializer[HttpUrl] = new StringSerializer[HttpUrl] {
def serialize(h: HttpUrl): String = h.toString
}
implicit def uriCapable: UriCapable[HttpUrl] = new UriCapable[HttpUrl] {
def uri(cp: HttpUrl) = {
val portString = if (cp.ssl && cp.port == 443 || !cp.ssl && cp.port == 80) "" else s":${cp.port}"
Uri(if (cp.ssl) "https" else "http", s"//${cp.hostname}${portString}/${cp.elements.mkString("/")}")
}
}
implicit def urlSlashRootedPath[RP <: RootedPath]: Dereferenceable[HttpUrl, RP, HttpUrl] =
new Dereferenceable[HttpUrl, RP, HttpUrl] {
def dereference(p1: HttpUrl, p2: RP) = {
val start = if (p1.elements.lastOption == Some("")) p1.elements.init else p1.elements
HttpUrl(p1.root, start ++ p2.elements)
}
}
implicit def urlSlashRelativePath[RP <: RelativePath]: Dereferenceable[HttpUrl, RP, HttpUrl] =
new Dereferenceable[HttpUrl, RP, HttpUrl] {
def dereference(p1: HttpUrl, p2: RP) =
HttpUrl(p1.root, p1.elements.dropRight(p2.ascent) ++ p2.elements)
}
implicit def urlSlashString: Dereferenceable[HttpUrl, String, HttpUrl] =
new Dereferenceable[HttpUrl, String, HttpUrl] {
def dereference(p1: HttpUrl, p2: String) = {
val start = if (p1.elements.lastOption == Some("")) p1.elements.init else p1.elements
HttpUrl(p1.root, start :+ p2)
}
}
implicit def urlParentable: Parentable[HttpUrl, HttpUrl] = new Parentable[HttpUrl, HttpUrl] {
def parent(httpUrl: HttpUrl): HttpUrl = HttpUrl(httpUrl.root, httpUrl.elements.dropRight(1))
}
}
/** Represets a URL with the http scheme */
case class HttpUrl(root: HttpDomain, elements: Vector[String]) extends NetUrl {
override def toString = HttpUrl.uriCapable.uri(this).toString
def hostname = root.hostname
def port = root.port
def canonicalPort = if (root.ssl) 443 else 80
def ssl = root.ssl
def query[Q: Query](q: Q): HttpQuery = HttpQuery(this, ?[Query[Q]].queryString(q))
}
trait Query[-T] {
def queryString(t: T): String
}
object Query {
implicit def mapQuery[K: StringSerializer, V: StringSerializer]: Query[Map[K, V]] = new Query[Map[K, V]] {
def queryString(m: Map[K, V]): String =
m.map {
case (k, v) =>
val key = java.net.URLEncoder.encode(?[StringSerializer[K]].serialize(k), "UTF-8")
val value = java.net.URLEncoder.encode(?[StringSerializer[V]].serialize(v), "UTF-8")
s"$key=$value"
}.mkString("&")
}
}
object HttpQuery {
implicit val serializer: StringSerializer[HttpQuery] = new StringSerializer[HttpQuery] {
def serialize(h: HttpQuery): String = h.toString
}
implicit val httpUrlParser: StringParser[HttpUrl] = new StringParser[HttpUrl] {
type Throws = ParseException
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[HttpUrl, Throws] =
mode.wrap(Http.parse(s))
}
implicit val httpQueryParser: StringParser[HttpQuery] = new StringParser[HttpQuery] {
type Throws = ParseException
def parse(s: String, mode: Mode[_ <: MethodConstraint]): mode.Wrap[HttpQuery, Throws] =
mode.wrap(HttpQuery.parse(s))
}
implicit def uriCapable: UriCapable[HttpQuery] = new UriCapable[HttpQuery] {
def uri(hq: HttpQuery) = {
val httpUrlUri = HttpUrl.uriCapable.uri(hq.httpUrl)
Uri(httpUrlUri.scheme, s"${httpUrlUri.schemeSpecificPart}?${hq.queryString}")
}
}
private val UrlRegex = """(https?):\/\/([\.\-a-z0-9]+)(:[1-9][0-9]*)?(\/?([^\?]*)(\?([^\?]*))?)""".r
def parse(s: String): HttpQuery = s match {
case UrlRegex(scheme, server, port, _, path, _, after) =>
val rp = RootedPath(path.split("/").to[Vector])
val httpUrl = scheme match {
case "http" =>
Http(server, if (port == null) 80 else port.substring(1).toInt) / rp
case "https" =>
Https(server, if (port == null) 443 else port.substring(1).toInt) / rp
case _ => throw new Exception(s)
}
HttpQuery(httpUrl, Option(after).getOrElse(""))
case _ => throw new Exception(s)
}
}
case class HttpQuery(httpUrl: HttpUrl, queryString: String) {
override def toString = {
val httpUrlUri = HttpUrl.uriCapable.uri(httpUrl)
if (queryString == "") httpUrlUri.toString else s"$httpUrlUri?$queryString"
}
}
object HttpDomain {
implicit def cpSlashString: Dereferenceable[HttpDomain, String, HttpUrl] =
new Dereferenceable[HttpDomain, String, HttpUrl] {
def dereference(p1: HttpDomain, p2: String) = HttpUrl(p1, Vector(p2))
}
implicit def cpSlashRelativePath[RP <: RelativePath]: Dereferenceable[HttpDomain, RP, HttpUrl] =
new Dereferenceable[HttpDomain, RP, HttpUrl] {
def dereference(p1: HttpDomain, p2: RP) = HttpUrl(p1, p2.elements)
}
implicit def cpSlashRootedPath[RRP <: RootedPath]: Dereferenceable[HttpDomain, RRP, HttpUrl] =
new Dereferenceable[HttpDomain, RRP, HttpUrl] {
def dereference(p1: HttpDomain, p2: RRP) = HttpUrl(p1, p2.elements)
}
implicit def uriCapable: UriCapable[HttpDomain] = new UriCapable[HttpDomain] {
def uri(cp: HttpDomain) = {
val portString = if (cp.ssl && cp.port == 443 || !cp.ssl && cp.port == 80) "" else s":${cp.port}"
Uri(if (cp.ssl) "https" else "http", s"//${cp.hostname}$portString")
}
}
}
case class HttpDomain(hostname: String, port: Int, ssl: Boolean) {
override def toString = HttpDomain.uriCapable.uri(this).toString
}
object Http {
def apply(hostname: String, port: Int = services.tcp.http.portNo) =
HttpDomain(hostname, port, false)
def parse(s: String): HttpUrl = HttpQuery.parse(s).httpUrl
}
object Https {
def apply(hostname: String, port: Int = services.tcp.https.portNo) =
HttpDomain(hostname, port, true)
def parse(s: String): HttpUrl = HttpQuery.parse(s).httpUrl
}
================================================
FILE: net/shared/src/main/scala/rapture/net/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.net
import rapture.io._
import rapture.uri._
import rapture.core._
import rapture.base._
import rapture.codec._
import java.io.{Reader => _, Writer => _, _}
import scala.language.implicitConversions
import scala.language.experimental.macros
trait `NetUrl#httpGet` extends MethodConstraint
trait `NetUrl#httpPost` extends MethodConstraint
trait `NetUrl#httpHead` extends MethodConstraint
trait `NetUrl#httpPut` extends MethodConstraint
trait `Tcp.listen` extends MethodConstraint
trait `BrowserUrl#httpPost` extends MethodConstraint
trait `Ftp.parse` extends MethodConstraint
trait `HttpResponse#input` extends MethodConstraint
trait `Ipv6.parse` extends MethodConstraint
object `package` {
implicit class EnrichedHttpUriContext(uc: UriContext.type) {
def http(constants: List[String])(variables: List[String]): Any = macro NetMacros.httpUrlMacro
def https(constants: List[String])(variables: List[String]): Any = macro NetMacros.httpsUrlMacro
}
implicit def httpUrlSizable(implicit httpTimeout: HttpTimeout, toUri: UriCapable[HttpUrl]): Sizable[HttpUrl, Byte] =
new Sizable[HttpUrl, Byte] {
type ExceptionType = HttpExceptions
HttpSupport.basicHttpSupport
def size(url: HttpUrl): Long = url.httpHead().headers.get("Content-Length").get.head.toLong
}
implicit def httpCapable[Res: HttpSupport](res: Res): HttpSupport.Capability[Res] =
new HttpSupport.Capability[Res](res)
implicit val httpStreamByteReader: JavaInputStreamReader[HttpUrl] = new JavaInputStreamReader[HttpUrl]({ u =>
new java.net.URL(u.uri.toString).openConnection.asInstanceOf[java.net.HttpURLConnection].getInputStream
})
implicit val httpQueryStreamByteReader: JavaInputStreamReader[HttpQuery] = new JavaInputStreamReader[HttpQuery]({
u =>
new java.net.URL(u.uri.toString).openConnection.asInstanceOf[java.net.HttpURLConnection].getInputStream
})
implicit val httpResponseCharReader: Reader[HttpResponse, Char] = new Reader[HttpResponse, Char] {
def input(response: HttpResponse): Input[Char] = {
import encodings.`UTF-8`._
response.input[Char]
}
}
implicit val httpResponseByteReader: Reader[HttpResponse, Byte] = new Reader[HttpResponse, Byte] {
def input(response: HttpResponse): Input[Byte] =
response.input[Byte](?[InputBuilder[InputStream, Byte]], modes.throwExceptions())
}
implicit val socketStreamByteReader: JavaInputStreamReader[SocketUri] =
new JavaInputStreamReader[SocketUri](_.javaSocket.getInputStream)
implicit val socketStreamByteWriter: JavaOutputStreamWriter[SocketUri] =
new JavaOutputStreamWriter[SocketUri](_.javaSocket.getOutputStream)
implicit val socketStreamByteAppender: JavaOutputAppender[SocketUri] =
new JavaOutputAppender[SocketUri](_.javaSocket.getOutputStream)
}
object NetMacros {
def httpUrlMacro(c: WhiteboxContext)(constants: c.Expr[List[String]])(variables: c.Expr[List[String]]): c.Expr[Any] = {
import c.universe._
constants.tree match {
case Apply(_, List(rawParts@_*)) =>
val httpQuery = q"""_root_.rapture.net.HttpQuery.parse("http:" + $constants.zip($variables :+ "").map { case (a, b) => a + b }.mkString)"""
if(rawParts.mkString contains "?") c.Expr(httpQuery)
else c.Expr(q"$httpQuery.httpUrl")
}
}
def httpsUrlMacro(c: WhiteboxContext)(constants: c.Expr[List[String]])(variables: c.Expr[List[String]]): c.Expr[Any] = {
import c.universe._
constants.tree match {
case Apply(_, List(rawParts@_*)) =>
val httpQuery = q"""_root_.rapture.net.HttpQuery.parse("https:" + $constants.zip($variables :+ "").map { case (a, b) => a + b }.mkString)"""
if(rawParts.mkString contains "?") c.Expr(httpQuery)
else c.Expr(q"$httpQuery.httpUrl")
}
}
}
================================================
FILE: net/shared/src/main/scala/rapture/net/services.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.net
import rapture.core._
/** Provides a typesafe list of network services mapping from port number to service name. This
* is based on [http://www.iana.org/assignments/port-numbers] and
* [http://www.freebsd.org/cgi/cvsweb.cgi/src/etc/services] */
object services {
object tcp {
private lazy val serviceNames: Map[String, Port] = enumerateMembers[Port](this).map { p =>
p.name -> p
}.toMap
def apply(name: String) = serviceNames(name)
case class Port(portNo: Int)(implicit assigned: AssignedName) { def name = assigned.name }
val tcpmux = Port(1)
val compressnet = Port(2)
val compressnet2 = Port(3)
val rje = Port(5)
val echo = Port(7)
val discard = Port(9)
val systat = Port(11)
val daytime = Port(13)
val qotd = Port(17)
val msp = Port(18)
val chargen = Port(19)
val `ftp-data` = Port(20)
val ftp = Port(21)
val ssh = Port(22)
val telnet = Port(23)
val smtp = Port(25)
val `nsw-fe` = Port(27)
val `msg-icp` = Port(29)
val `msg-auth` = Port(31)
val dsp = Port(33)
val time = Port(37)
val rap = Port(38)
val rlp = Port(39)
val graphics = Port(41)
val nameserver = Port(42)
val nicname = Port(43)
val `mpm-flags` = Port(44)
val mpm = Port(45)
val `mpm-snd` = Port(46)
val `ni-ftp` = Port(47)
val auditd = Port(48)
val tacacs = Port(49)
val `re-mail-ck` = Port(50)
val domain = Port(53)
val `xns-ch` = Port(54)
val `isi-gl` = Port(55)
val `xns-auth` = Port(56)
val `xns-mail` = Port(58)
val `ni-mail` = Port(61)
val acas = Port(62)
val `whois++` = Port(63)
val covia = Port(64)
val `tacacs-ds` = Port(65)
val `sql*net` = Port(66)
val bootps = Port(67)
val bootpc = Port(68)
val tftp = Port(69)
val gopher = Port(70)
val `netrjs-1` = Port(71)
val `netrjs-2` = Port(72)
val `netrjs-3` = Port(73)
val `netrjs-4` = Port(74)
val deos = Port(76)
val vettcp = Port(78)
val finger = Port(79)
val http = Port(80)
val `hosts2-ns` = Port(81)
val xfer = Port(82)
val `mit-ml-dev` = Port(83)
val ctf = Port(84)
val `mit-ml-dev2` = Port(85)
val mfcobol = Port(86)
val kerberos = Port(88)
val `su-mit-tg` = Port(89)
val dnsix = Port(90)
val `mit-dov` = Port(91)
val npp = Port(92)
val dcp = Port(93)
val objcall = Port(94)
val supdup = Port(95)
val dixie = Port(96)
val `swift-rvf` = Port(97)
val tacnews = Port(98)
val metagram = Port(99)
val hostname = Port(101)
val `iso-tsap` = Port(102)
val gppitnp = Port(103)
val `acr-nema` = Port(104)
val cso = Port(105)
val `3com-tsmux` = Port(106)
val rtelnet = Port(107)
val snagas = Port(108)
val pop2 = Port(109)
val pop3 = Port(110)
val sunrpc = Port(111)
val mcidas = Port(112)
val auth = Port(113)
val sftp = Port(115)
val ansanotify = Port(116)
val `uucp-path` = Port(117)
val sqlserv = Port(118)
val nntp = Port(119)
val cfdptkt = Port(120)
val erpc = Port(121)
val smakynet = Port(122)
val ntp = Port(123)
val ansatrader = Port(124)
val `locus-map` = Port(125)
val nxedit = Port(126)
val `locus-con` = Port(127)
val `gss-xlicen` = Port(128)
val pwdgen = Port(129)
val `cisco-fna` = Port(130)
val `cisco-tna` = Port(131)
val `cisco-sys` = Port(132)
val statsrv = Port(133)
val `ingres-net` = Port(134)
val epmap = Port(135)
val profile = Port(136)
val `netbios-ns` = Port(137)
val `netbios-dgm` = Port(138)
val `netbios-ssn` = Port(139)
val `emfis-data` = Port(140)
val `emfis-cntl` = Port(141)
val imap = Port(143)
val uma = Port(144)
val uaac = Port(145)
val `iso-tp0` = Port(146)
val `iso-ip` = Port(147)
val jargon = Port(148)
val `aed-512` = Port(149)
val `sql-net` = Port(150)
val hems = Port(151)
val bftp = Port(152)
val sgmp = Port(153)
val `netsc-prod` = Port(154)
val `netsc-dev` = Port(155)
val sqlsrv = Port(156)
val `knet-cmp` = Port(157)
val `pcmail-srv` = Port(158)
val `nss-routing` = Port(159)
val `sgmp-traps` = Port(160)
val snmp = Port(161)
val snmptrap = Port(162)
val `cmip-man` = Port(163)
val `cmip-agent` = Port(164)
val `xns-courier` = Port(165)
val `s-net` = Port(166)
val namp = Port(167)
val rsvd = Port(168)
val send = Port(169)
val `print-srv` = Port(170)
val multiplex = Port(171)
val `xyplex-mux` = Port(173)
val mailq = Port(174)
val vmnet = Port(175)
val `genrad-mux` = Port(176)
val xdmcp = Port(177)
val nextstep = Port(178)
val bgp = Port(179)
val ris = Port(180)
val unify = Port(181)
val audit = Port(182)
val ocbinder = Port(183)
val ocserver = Port(184)
val `remote-kis` = Port(185)
val kis = Port(186)
val aci = Port(187)
val mumps = Port(188)
val qft = Port(189)
val gacp = Port(190)
val prospero = Port(191)
val `osu-nms` = Port(192)
val srmp = Port(193)
val irc = Port(194)
val `dn6-nlm-aud` = Port(195)
val `dn6-smm-red` = Port(196)
val dls = Port(197)
val `dls-mon` = Port(198)
val smux = Port(199)
val src = Port(200)
val `at-rtmp` = Port(201)
val `at-nbp` = Port(202)
val `at-echo` = Port(204)
val `at-zis` = Port(206)
val qmtp = Port(209)
val `z39.50` = Port(210)
val anet = Port(212)
val ipx = Port(213)
val imap3 = Port(220)
val link = Port(245)
val pawserv = Port(345)
val zserv = Port(346)
val fatserv = Port(347)
val scoi2odialog = Port(360)
val semantix = Port(361)
val srssend = Port(362)
val rsvp_tunnel = Port(363)
val `aurora-cmgr` = Port(364)
val dtk = Port(365)
val odmr = Port(366)
val rpc2portmap = Port(369)
val codaauth2 = Port(370)
val clearcase = Port(371)
val ulistproc = Port(372)
val ldap = Port(389)
val imsp = Port(406)
val svrloc = Port(427)
val `mobileip-agent` = Port(434)
val `mobilip-mn` = Port(435)
val https = Port(443)
val snpp = Port(444)
val `microsoft-ds` = Port(445)
val kpasswd = Port(464)
val urd = Port(465)
val photuris = Port(468)
val rcp = Port(469)
val saft = Port(487)
val `gss-http` = Port(488)
val `pim-rp-disc` = Port(496)
val isakmp = Port(500)
val exec = Port(512)
val login = Port(513)
val shell = Port(514)
val printer = Port(515)
val videotex = Port(516)
val talk = Port(517)
val ntalk = Port(518)
val utime = Port(519)
val efs = Port(520)
val ripng = Port(521)
val ulp = Port(522)
val `ibm-db2` = Port(523)
val ncp = Port(524)
val timed = Port(525)
val tempo = Port(526)
val courier = Port(530)
val conference = Port(531)
val netnews = Port(532)
val netwall = Port(533)
val `mm-admin` = Port(534)
val iiop = Port(535)
val `opalis-rdv` = Port(536)
val nmsp = Port(537)
val gdomap = Port(538)
val uucp = Port(540)
val klogin = Port(543)
val kshell = Port(544)
val appleqtcsrvr = Port(545)
val `dhcpv6-client` = Port(546)
val `dhcpv6-server` = Port(547)
val afpovertcp = Port(548)
val rtsp = Port(554)
val dsf = Port(555)
val remotefs = Port(556)
val nntps = Port(563)
val `9pfs` = Port(564)
val whoami = Port(565)
val submission = Port(587)
val `http-alt` = Port(591)
val nqs = Port(607)
val `npmp-local` = Port(610)
val `npmp-gui` = Port(611)
val `hmmp-ind` = Port(612)
val cryptoadmin = Port(624)
val dec_dlm = Port(625)
val asia = Port(626)
val `passgo-tivoli` = Port(627)
val qmqp = Port(628)
val `3com-amp3` = Port(629)
val rda = Port(630)
val ipp = Port(631)
val ldaps = Port(636)
val tinc = Port(655)
val acap = Port(674)
val asipregistry = Port(687)
val `realm-rusd` = Port(688)
val nmap = Port(689)
val `ha-cluster` = Port(694)
val epp = Port(700)
val `iris-beep` = Port(702)
val silc = Port(706)
val `kerberos-adm` = Port(749)
val `kerberos-iv` = Port(750)
val pump = Port(751)
val qrh = Port(752)
val rrh = Port(753)
val tell = Port(754)
val nlogin = Port(758)
val con = Port(759)
val ns = Port(760)
val webster = Port(765)
val phonebook = Port(767)
val rsync = Port(873)
val `ftps-data` = Port(989)
val ftps = Port(990)
val nas = Port(991)
val telnets = Port(992)
val imaps = Port(993)
val ircs = Port(994)
val pop3s = Port(995)
val imgames = Port(1077)
val socks = Port(1080)
val rmiregistry = Port(1099)
val bnetgame = Port(1119)
val bnetfile = Port(1120)
val hpvmmcontrol = Port(1124)
val hpvmmagent = Port(1125)
val hpvmmdata = Port(1126)
val resacommunity = Port(1154)
val `3comnetman` = Port(1181)
val `mysql-cluster` = Port(1186)
val alias = Port(1187)
val openvpn = Port(1194)
val kazaa = Port(1214)
val bvcontrol = Port(1236)
val nessus = Port(1241)
val h323hostcallsc = Port(1300)
val lotusnote = Port(1352)
val `ms-sql-s` = Port(1433)
val `ms-sql-m` = Port(1434)
val ica = Port(1494)
val wins = Port(1512)
val ingreslock = Port(1524)
val `prospero-np` = Port(1525)
val datametrics = Port(1645)
val `sa-msg-port` = Port(1646)
val rsap = Port(1647)
val `concurrent-lm` = Port(1648)
val kermit = Port(1649)
val l2tp = Port(1701)
val h323gatedisc = Port(1718)
val h323gatestat = Port(1719)
val h323hostcall = Port(1720)
val iberiagames = Port(1726)
val gamegen1 = Port(1738)
val `tftp-mcast` = Port(1758)
val hello = Port(1789)
val radius = Port(1812)
val `radius-acct` = Port(1813)
val mtp = Port(1911)
val egs = Port(1926)
val `unix-status` = Port(1957)
val hsrp = Port(1985)
val licensedaemon = Port(1986)
val `tr-rsrb-p1` = Port(1987)
val `tr-rsrb-p2` = Port(1988)
val `tr-rsrb-p3` = Port(1989)
val `stun-p1` = Port(1990)
val `stun-p2` = Port(1991)
val `stun-p3` = Port(1992)
val `snmp-tcp-port` = Port(1994)
val `stun-port` = Port(1995)
val `perf-port` = Port(1996)
val `gdp-port` = Port(1997)
val `x25-svc-port` = Port(1998)
val `tcp-id-port` = Port(1999)
val `cisco-sccp` = Port(2000)
val nfs = Port(2049)
val radsec = Port(2083)
val gnunet = Port(2086)
val `rtcm-sc104` = Port(2101)
val `zephyr-srv` = Port(2102)
val `zephyr-clt` = Port(2103)
val `zephyr-hm` = Port(2104)
val eyetv = Port(2170)
val `msfw-storage` = Port(2171)
val `msfw-s-storage` = Port(2172)
val `msfw-replica` = Port(2173)
val `msfw-array` = Port(2174)
val airsync = Port(2175)
val rapi = Port(2176)
val qwave = Port(2177)
val tivoconnect = Port(2190)
val tvbus = Port(2191)
val `mysql-im` = Port(2273)
val `dict-lookup` = Port(2289)
val redstorm_join = Port(2346)
val redstorm_find = Port(2347)
val redstorm_info = Port(2348)
val cvspserver = Port(2401)
val venus = Port(2430)
val `venus-se` = Port(2431)
val codasrv = Port(2432)
val `codasrv-se` = Port(2433)
val netadmin = Port(2450)
val netchat = Port(2451)
val snifferclient = Port(2452)
val ppcontrol = Port(2505)
val lstp = Port(2559)
val mon = Port(2583)
val hpstgmgr = Port(2600)
val `discp-client` = Port(2601)
val `discp-server` = Port(2602)
val servicemeter = Port(2603)
val `nsc-ccs` = Port(2604)
val `nsc-posa` = Port(2605)
val netmon = Port(2606)
val connection = Port(2607)
val `wag-service` = Port(2608)
val dict = Port(2628)
val exce = Port(2769)
val `dvr-esm` = Port(2804)
val corbaloc = Port(2809)
val ndtp = Port(2882)
val gamelobby = Port(2914)
val gds_db = Port(3050)
val xbox = Port(3074)
val icpv2 = Port(3130)
val `nm-game-admin` = Port(3148)
val `nm-game-server` = Port(3149)
val mysql = Port(3306)
val sftu = Port(3326)
val trnsprntproxy = Port(3346)
val `ms-wbt-server` = Port(3389)
val prsvp = Port(3455)
val nut = Port(3493)
val ironstorm = Port(3504)
val `cctv-port` = Port(3559)
val `iw-mmogame` = Port(3596)
val distcc = Port(3632)
val daap = Port(3689)
val svn = Port(3690)
val blizwow = Port(3724)
val `netboot-pxe` = Port(3928)
val `smauth-port` = Port(3929)
val treehopper = Port(3959)
val cobraclient = Port(3970)
val cobraserver = Port(3971)
val `pxc-spvr-ft` = Port(4002)
val `pxc-splr-ft` = Port(4003)
val `pxc-roid` = Port(4004)
val `pxc-pin` = Port(4005)
val `pxc-spvr` = Port(4006)
val `pxc-splr` = Port(4007)
val xgrid = Port(4111)
val bzr = Port(4155)
val rwhois = Port(4321)
val epmd = Port(4369)
val krb524 = Port(4444)
val `ipsec-nat-t` = Port(4500)
val hylafax = Port(4559)
val piranha1 = Port(4600)
val `playsta2-app` = Port(4658)
val `playsta2-lob` = Port(4659)
val snap = Port(4752)
val `radmin-port` = Port(4899)
val rfe = Port(5002)
val `ita-agent` = Port(5051)
val `sdl-ets` = Port(5081)
val bzflag = Port(5154)
val aol = Port(5190)
val `xmpp-client` = Port(5222)
val caevms = Port(5251)
val `xmpp-server` = Port(5269)
val cfengine = Port(5308)
val `nat-pmp` = Port(5351)
val `dns-llq` = Port(5352)
val mdns = Port(5353)
val mdnsresponder = Port(5354)
val llmnr = Port(5355)
val `dj-ice` = Port(5419)
val `beyond-remote` = Port(5424)
val `br-channel` = Port(5425)
val postgresql = Port(5432)
val `sgi-eventmond` = Port(5553)
val `sgi-esphttp` = Port(5554)
val cvsup = Port(5999)
val x11 = Port(6000)
val `kftp-data` = Port(6620)
val kftp = Port(6621)
val ktelnet = Port(6623)
val `gnutella-svc` = Port(6346)
val `gnutella-rtr` = Port(6347)
val `sane-port` = Port(6566)
val `parsec-game` = Port(6582)
val `afs3-fileserver` = Port(7000)
val `afs3-callback` = Port(7001)
val `afs3-prserver` = Port(7002)
val `afs3-vlserver` = Port(7003)
val `afs3-kaserver` = Port(7004)
val `afs3-volser` = Port(7005)
val `afs3-errors` = Port(7006)
val `afs3-bos` = Port(7007)
val `afs3-update` = Port(7008)
val `afs3-rmtsys` = Port(7009)
val `font-service` = Port(7100)
val sncp = Port(7560)
val `soap-http` = Port(7627)
val `http-alt2` = Port(8008)
val `http-alt3` = Port(8080)
val sunproxyadmin = Port(8081)
val pichat = Port(9009)
val `bacula-dir` = Port(9101)
val `bacula-fd` = Port(9102)
val `bacula-sd` = Port(9103)
val dddp = Port(9131)
val `wap-wsp` = Port(9200)
val `wap-wsp-wtp` = Port(9201)
val `wap-wsp-s` = Port(9202)
val `wap-wsp-wtp-s` = Port(9203)
val `wap-vcard` = Port(9204)
val `wap-vcal` = Port(9205)
val `wap-vcard-s` = Port(9206)
val `wap-vcal-s` = Port(9207)
val git = Port(9418)
val cba8 = Port(9593)
val davsrc = Port(9800)
val sqlexec = Port(9088)
val `sqlexec-ssl` = Port(9089)
val sd = Port(9876)
val `cyborg-systems` = Port(9888)
val monkeycom = Port(9898)
val `sctp-tunneling` = Port(9899)
val domaintime = Port(9909)
val amanda = Port(10080)
val vce = Port(11111)
val smsqp = Port(11201)
val hkp = Port(11371)
val h323callsigalt = Port(11720)
val `rets-ssl` = Port(12109)
val cawas = Port(12168)
val bprd = Port(13720)
val bpdbm = Port(13721)
val `bpjava-msvc` = Port(13722)
val vnetd = Port(13724)
val bpcd = Port(13782)
val vopied = Port(13783)
val xpilot = Port(15345)
val wnn6 = Port(22273)
val binkp = Port(24554)
val quake = Port(26000)
val `wnn6-ds` = Port(26208)
val tetrinet = Port(31457)
val `gamesmith-port` = Port(31765)
val traceroute = Port(33434)
val candp = Port(42508)
val candrp = Port(42509)
val caerpc = Port(42510)
val kpop = Port(1109)
val knetd = Port(2053)
val eklogin = Port(2105)
val supfilesrv = Port(871)
val supfiledbg = Port(1127)
val swat = Port(901)
val rndc = Port(953)
val skkserv = Port(1178)
val xtel = Port(1313)
val support = Port(1529)
val cfinger = Port(2003)
val ninstall = Port(2150)
val afbackup = Port(2988)
val fax = Port(4557)
val rplay = Port(5555)
val canna = Port(5680)
val `x11-ssh` = Port(6010)
val ircd = Port(6667)
val jetdirect = Port(9100)
val kamanda = Port(10081)
val amandaidx = Port(10082)
val amidxtape = Port(10083)
val isdnlog = Port(20011)
val vboxd = Port(20012)
val wnn4_Cn = Port(22289)
val wnn4_Kr = Port(22305)
val wnn4_Tw = Port(22321)
val asp = Port(27374)
val tfido = Port(60177)
val fido = Port(60179)
}
}
================================================
FILE: net/shared/src/main/scala/rapture/net/sockets.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.net
import rapture.core._
import rapture.io._
import rapture.uri._
import java.io._
object Tcp {
def listen[K](port: Int)(implicit ib: InputBuilder[InputStream, K],
ob: OutputBuilder[OutputStream, K],
mode: Mode[`Tcp.listen`]): mode.Wrap[(Input[K], Output[K]), Exception] = mode.wrap {
val sock = new java.net.ServerSocket(port)
val sock2 = sock.accept()
(ib.input(sock2.getInputStream), ob.output(sock2.getOutputStream))
}
def handle[K](port: Int)(action: (Input[K], Output[K]) => Unit)(implicit ib: InputBuilder[InputStream, K],
ob: OutputBuilder[OutputStream, K]): Unit = {
val sock = new java.net.ServerSocket(port)
while (true) {
val sock2 = sock.accept()
Thread.fork(s"rapture-port$port") {
action(ib.input(sock2.getInputStream), ob.output(sock2.getOutputStream))
}
}
}
}
object SocketUri {
implicit val socketUri = new UriCapable[SocketUri] {
def uri(su: SocketUri): Uri = Uri("socket", s"//${su.hostname}:${su.port}")
}
}
case class SocketUri(hostname: String, port: Int) {
lazy val javaSocket: java.net.Socket = new java.net.Socket(hostname, port)
def schemeSpecificPart = "//" + hostname + ":" + port
def absolute = true
}
object Socket {
def apply(hostname: String, port: Int): SocketUri = new SocketUri(hostname, port)
def apply(hostname: String, svc: services.tcp.Port): SocketUri = new SocketUri(hostname, svc.portNo)
private val UriMatcher = """socket://([a-z0-9\.]+):([1-9][0-9]*)""".r
def parse(uri: String) = uri match {
case UriMatcher(host, port) => new SocketUri(host, port.toInt)
}
}
================================================
FILE: net-test/shared/src/test/scala/rapture/net/test/DockerHttpBinServerSpec.scala
================================================
package rapture.net.test
import org.scalatest.concurrent.Eventually._
import org.scalatest.concurrent.PatienceConfiguration._
import org.scalatest.time.{Seconds, Span}
import org.scalatest.{BeforeAndAfter, Suite}
import rapture.net._
import rapture.net.test.helper.{DockerContainer, ExposePort}
trait DockerHttpBinServerSpec extends BeforeAndAfter {
this: Suite =>
val SERVER_PORT = 33881
val SERVER_URL = s"http://127.0.0.1:$SERVER_PORT"
private var startedDockerContainer: DockerContainer#StartedDockerContainer = _
before {
startedDockerContainer =
new DockerContainer("paddycarey/httpbin", Set(ExposePort(SERVER_PORT.toString, "8000"))).startContainer()
eventually(Timeout(Span(30, Seconds))) {
println("Trying to connect....")
assert(Http("127.0.0.1", SERVER_PORT).httpGet().status == 200)
}
}
after {
startedDockerContainer.killAndRemoveContainer()
}
}
================================================
FILE: net-test/shared/src/test/scala/rapture/net/test/HttpClientSpec.scala
================================================
package rapture.net.test
import org.scalatest.{Matchers, WordSpec}
import rapture.io._
import rapture.json.Json
import rapture.json.jsonBackends.circe._
import rapture.net.{Http, HttpQuery}
class HttpClientSpec extends WordSpec with Matchers with DockerHttpBinServerSpec {
"Http client" should {
"make GET request and get 200 OK status" in {
val result = Http.parse(s"$SERVER_URL/get").httpGet()
result.status shouldEqual 200
}
"make GET request with query params and get 200 OK status" in {
val result =
HttpQuery.parse(s"$SERVER_URL/get?foo=333&bar=abc").httpGet(Map("Content-Type" -> "application/json"))
result.status shouldEqual 200
val json = Json.parse(result.slurp[Char])
json.args.foo.as[String] shouldEqual "333"
json.args.bar.as[String] shouldEqual "abc"
}
"make GET request with custom headers and get 200 OK" in {
val result = HttpQuery
.parse(s"$SERVER_URL/get")
.httpGet(Map("Content-Type" -> "application/json", "Mytest-Header" -> "111-222-333-abc"))
result.status shouldEqual 200
val json = Json.parse(result.slurp[Char])
json.headers.`Mytest-Header`.as[String] shouldEqual "111-222-333-abc"
}
}
}
================================================
FILE: net-test/shared/src/test/scala/rapture/net/test/helper/DockerContainer.scala
================================================
package rapture.net.test.helper
import com.spotify.docker.client.DefaultDockerClient
import com.spotify.docker.client.messages.{ContainerConfig, ContainerCreation, HostConfig, PortBinding}
import rapture.core.Mode
import scala.collection.JavaConverters._
case class ExposePort(externalPort: String, internalPort: String)
class DockerContainer(image: String, exposedPorts: Set[ExposePort]) {
import java.util
lazy val docker = DefaultDockerClient.fromEnv().build()
def startContainer()(implicit mode: Mode[_]): mode.Wrap[StartedDockerContainer, Nothing] = mode.wrap {
docker.pull(image)
val portBindings = new util.HashMap[String, util.List[PortBinding]]
exposedPorts.foreach { port =>
portBindings.put(port.internalPort, List(PortBinding.of("0.0.0.0", port.externalPort)).asJava)
}
val containerConfig = ContainerConfig
.builder()
.hostConfig(HostConfig.builder().portBindings(portBindings).build())
.image(image)
.exposedPorts(exposedPorts.map(_.internalPort).asJava)
.build()
val creation = docker.createContainer(containerConfig)
docker.startContainer(creation.id())
new StartedDockerContainer(image, exposedPorts, creation)
}
class StartedDockerContainer(image: String, exposedPorts: Set[ExposePort], creation: ContainerCreation) {
def killAndRemoveContainer(): Unit = {
docker.killContainer(creation.id)
docker.removeContainer(creation.id)
}
}
}
================================================
FILE: project/build.properties
================================================
sbt.version=0.13.13
================================================
FILE: project/plugins.sbt
================================================
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.1")
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.4")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.5.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "0.8.5")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.14")
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "0.5.1")
//addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "0.2.10")
================================================
FILE: test/shared/src/main/scala/rapture/test/macros.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.test
import scala.language.experimental.macros
import rapture.base._
object deferTypeErrors {
implicit def deferTypeErrorsConvertAnyToAny[T, S](t: T): S = ???
implicit def deferTypeErrorsResolveAnyImplicit[T]: T = ???
}
object typeMismatch {
def apply[T](fn: => T): Boolean = macro applyMacro[T]
def applyMacro[T](c: BlackboxContext)(fn: c.Expr[T]): c.Expr[Boolean] = {
import c.universe._
val found = fn.tree.exists {
case Select(_, name) =>
name.decodedName.toString match {
case "deferTypeErrorsConvertAnyToAny" => true
case "deferTypeErrorsResolveAnyImplicit" => true
case _ => false
}
case _ => false
}
c.Expr[Boolean](q"$found")
}
}
================================================
FILE: test/shared/src/main/scala/rapture/test/report.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.test
import rapture.text._
import java.io.PrintStream
trait Reporter {
type Tag
def title(text: String)(implicit tty: ansi.Tty)
def startTask(text: String)(implicit tty: ansi.Tty): Tag
def completeTask(tag: Tag, result: TestResult)(implicit tty: ansi.Tty): Unit
def report(text: String, inset: Boolean = false)(implicit tty: ansi.Tty): Unit
def summary(status: Int, text: String)(implicit tty: ansi.Tty): Unit
}
class BasicReporter(width: Int, out: PrintStream) extends Reporter {
private var spaceAbove = false
def mkSpace() = {
if (!spaceAbove) out.println()
spaceAbove = true
}
def output(text: String) {
out.println(text)
spaceAbove = false
}
class Tag(val text: String) {
val t0 = System.currentTimeMillis
}
private var activeTags: Set[Tag] = Set()
def startTask(text: String)(implicit tty: ansi.Tty): Tag = synchronized {
val cutText = text.take(width - 20)
val tag = new Tag(cutText)
out.print(s"${ansi.normal}${cutText}")
activeTags += tag
tag
}
def completeTask(tag: Tag, result: TestResult)(implicit tty: ansi.Tty): Unit = synchronized {
val t = System.currentTimeMillis - tag.t0
out.print(" " * (width - tag.text.length - 20))
val pad = " " * (5 - t.toString.length)
val colorText = result match {
case Success => s"${ansi.green}SUCCESS"
case Failure(msg) => s"${ansi.yellow}FAILURE"
case Error(e) => s"${ansi.red} ERROR "
}
output(s"${ansi.boldBlue}[ ${colorText}${ansi.boldBlue} ]${pad}${t} ms${ansi.normal}")
activeTags -= tag
}
def report(text: String, inset: Boolean = false)(implicit tty: ansi.Tty) = {
val indent = if (inset) s" ${ansi.boldBlue}" else ansi.normal
text split "\n" flatMap (_.grouped(width - 25)) map (indent + _) foreach output
}
def summary(status: Int, text: String)(implicit tty: ansi.Tty) = {
val color = status match {
case 1 => ansi.green
case 0 => ansi.yellow
case _ => ansi.red
}
text grouped (width - 4) foreach { ln =>
output(s" ${color}* ${ansi.normal}${ln}")
}
}
def title(text: String)(implicit tty: ansi.Tty) =
text grouped (width - 4) foreach { ln =>
output(s" ${ansi.green}* ${ansi.normal}${ln}")
}
}
================================================
FILE: test/shared/src/main/scala/rapture/test/scalatest.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.test
import language.experimental.macros
class Programme extends org.scalatest.FunSuite {
def include[TS <: TestSuite](suite: TS): Unit = macro rapture.test.run.includeMacro[TS]
def includeAll(tests: List[(String, TestSuite#Test)]): Unit = {
tests.foreach {
case (n, t) =>
test(n) {
val result = t.runCheck()
assert(result == Success)
}
}
}
}
================================================
FILE: test/shared/src/main/scala/rapture/test/test.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.test
import rapture.core._
import rapture.text._
import rapture.base._
import rapture.fs._
import scala.reflect._
import java.net.URLClassLoader
import scala.language.experimental.macros
object Util {
private val entries: collection.mutable.HashMap[FsUrl, Seq[String]] = new collection.mutable.HashMap()
def entriesFromZip(f: FsUrl): Seq[String] = {
import java.util.zip._
import scala.collection.JavaConverters._
val zf = new ZipFile(f.javaFile)
entries.getOrElseUpdate(f,
enumerationAsScalaIteratorConverter(zf.entries).asScala
.to[List]
.filter(_.getName
endsWith ".class")
.filter(!_.getName.contains("$"))
.map(_.getName.dropRight(6)))
}
def getAllZipfiles(): List[FsUrl] = {
val urls: Array[java.net.URL] =
java.lang.Thread.currentThread.getContextClassLoader.asInstanceOf[URLClassLoader].getURLs
urls
.to[List]
.map { u =>
File.parse("file://" + u.getFile)
}
.filter(_.writable)
}
}
/*object Main extends BackgroundCliApp {
object Params extends Params(ClasspathParam, SuiteParam, TestParam, ShutdownParam)
lazy val ShutdownParam = Param("shutdown", "K", "Shutdown the server")
lazy val ClasspathParam = Param("classpath", "c", "Specify the classpath for the test")
lazy val TestParam = Param("test", "t", "Specify a single test to run")
lazy val SuiteParam = Param("suite", "s", "Specify the suite of tests to run")
def handle(line: CmdLine) = line match {
case Params(ps) =>
val directory = line.pwd.children.filter(_.filename endsWith ".jar")
val cp: List[FsUrl] = ps.get(ClasspathParam, Suggestions.from(directory)(_.filename, f =>
(f.size/1024)+"KB")).map { f => List(line.pwd / f) }.getOrElse(Util.getAllZipfiles())
val classes: Seq[String] = cp.flatMap(Util.entriesFromZip).map(_.replaceAll("\\/", "."))
val allSuites = ClassLoader(cp).applyTo {
classes.filter { n => try { classOf[TestSuite] isAssignableFrom Class.forName(n) } catch {
case e: Throwable => false
} }
}
val oneSuite = ps.get(SuiteParam, Suggestions.from(allSuites)(identity)).map(List(_))
val suites = oneSuite.getOrElse(allSuites).flatMap { s =>
Try(s -> Class.forName(s).newInstance().asInstanceOf[TestSuite]).toOption
}
exec { out =>
val cols = 100
implicit val reporter = new BasicReporter(cols, out)
for((n, s) <- suites) {
out.println(s"Running test suite ${Ansi.Blue}${n}${Ansi.Normal}")
out.println(s"${Ansi.BoldBlack}${"-"*cols}")
s.runAll()
out.println()
}
if(suites.isEmpty) out.println("Usage: rtest [--classpath ] --suite ")
}
}
}*/
sealed trait TestResult { def message: Option[String] }
case object Success extends TestResult { def message = None }
case class Failure(msg: String) extends TestResult { def message = Some(msg) }
case class Error(error: Throwable) extends TestResult {
private val stack = error.getStackTrace.map(_.toString).takeWhile(!_.startsWith("rapture.test"))
private val stackString = stack.mkString(" ", "\n ", "")
def message = Some(s"Exception thrown during test: ${error.toString}\n${stackString}")
}
trait TestCase
trait TestSuite {
abstract class Test extends TestCase { thisTest =>
type Return
def dependencies = Set[Test]()
def action: () => Return
def check(run: () => Return): TestResult
def name: String
def runCheck(): TestResult =
try check(action)
catch { case e: Throwable => Error(e) }
protected def compare[T](x: T, y: T): TestResult =
if (x == y) Success
else {
Failure(s"Found $x, but expected $y")
}
def returns(chk: => Return)(implicit assigned: AssignedName) = new Test {
type Return = thisTest.Return
def name = assigned.name
def action: () => Return = thisTest.action
def check(run: () => Return): TestResult = {
val result = run()
val y = chk
if (result == y) Success else Failure(s"Found $result but expected $y")
}
}
def satisfies(chk: Return => Boolean)(implicit assigned: AssignedName) = new Test {
type Return = thisTest.Return
def name = assigned.name
def action: () => Return = thisTest.action
def check(run: () => Return): TestResult = {
val result = run()
if (chk(result)) Success else Failure(s"Result $result did not satisfy predicate.")
}
}
def throws[E <: Throwable: ClassTag](cls: Class[E])(implicit assigned: AssignedName): Test = new Test {
type Return = thisTest.Return
def name = assigned.name
def action: () => Return = thisTest.action
def check(run: () => Return): TestResult =
try {
run()
Failure("Expected exception not thrown.")
} catch {
case e: E => Success
case e: Throwable => Failure(s"Expected exception of type `${classTag[E]}', but found exception `${e}'.")
}
}
def throws[E <: Throwable](exp: E)(implicit assigned: AssignedName): Test = new Test {
type Return = thisTest.Return
def name = assigned.name
def action: () => Return = thisTest.action
def check(run: () => Return): TestResult =
try {
run()
Failure("Expected exception not thrown.")
} catch {
case e if e == exp => Success
case e: Throwable => Failure(s"Expected exception `$exp`, but found exception `$e`.")
}
}
/*def apply(done: Set[Test] = Set())(implicit reporter: Reporter): TestSummary = {
val (_, (success, count)) = dependencies.foldLeft((done, (0, 0))) {
case ((d, (s0, n0)), t) =>
val (s, n) = if(!d.contains(t)) t(d) else (0, 0)
(d + t, (s0 + s, n0 + n))
}
val tag = reporter.startTask(s"${name}")
val result = try check(action) catch { case e: Throwable => Error(e) }
reporter.completeTask(tag, result)
result.message foreach { s => reporter.report(s, inset = true) }
TestSummary(success + (if(result == Success) 1 else 0), count + 1)
}*/
}
def test[T](act: => T): Test { type Return = T } = new Test {
type Return = T
def name = "Unnamed test"
def action: () => Return = () => act
def check(run: () => Return): TestResult = Success
}
}
trait `run` extends MethodConstraint
case class TestSummary(successes: Int, failures: Int, errors: Int)
class BadTestResult(msg: String) extends Exception(msg)
case class TestFailure(name: String, error: String) extends BadTestResult(s"Test `$name` failed with error `$error`")
case class TestError(name: String, exception: Throwable)
extends BadTestResult(s"Test `$name` failed with exception `$exception`")
object run {
def apply[TS <: TestSuite](ts: TS)(implicit mode: Mode[`run`]): Any = macro run.runMacro[TS]
def doTests(ts: List[TestSuite#Test], mode: Mode[`run`]): mode.Wrap[TestSummary, BadTestResult] = mode.wrap {
implicit val reporter: Reporter = new BasicReporter(116, System.out)
ansi { implicit tty =>
val (successes, failures, errors) = ts.foldLeft((0, 0, 0)) {
case ((s, f, e), t) =>
val task = reporter.startTask(t.name)
val result = t.runCheck()
reporter.completeTask(task, result)
result.message foreach { msg =>
reporter.report(msg, inset = true)
}
result match {
case Success =>
(s + 1, f, e)
case Failure(msg) =>
mode.exception(TestFailure(t.name, msg))
(s, f + 1, e)
case Error(msg) =>
mode.exception(TestError(t.name, msg))
(s, f, e + 1)
}
}
if (successes + failures + errors == 0) reporter.summary(0, "No tests found.")
else if (failures + errors == 0) reporter.summary(1, "All tests passed.")
else if (successes == 0) reporter.summary(-1, "All tests failed.")
else reporter.summary(0, s"${successes} out of ${successes + failures + errors} tests passed.")
TestSummary(successes, failures, errors)
}
}
def runMacro[TS <: TestSuite: c.WeakTypeTag](c: WhiteboxContext)(ts: c.Expr[TS])(
mode: c.Expr[Mode[`run`]]): c.Expr[Any] = {
import c.universe._
import compatibility._
val cls = weakTypeOf[TS]
val allMethods = weakTypeOf[TS].members.to[List].filter(_.isMethod).map(_.asMethod)
val matchingMethods = allMethods filter { m =>
paramLists(c)(m).isEmpty && m.returnType.weak_<:<(weakTypeOf[TestSuite#Test])
}
val methodNames = matchingMethods map { m => q"$ts.${m.name.toTermName}" }
c.Expr(q"""_root_.rapture.test.run.doTests(_root_.scala.List(..$methodNames), $mode)""")
}
def includeMacro[TS <: TestSuite: c.WeakTypeTag](c: WhiteboxContext)(suite: c.Expr[TS]): c.Expr[Unit] = {
import c.universe._
import compatibility._
val cls = weakTypeOf[TS]
val allMethods = weakTypeOf[TS].members.to[List].filter(_.isMethod).map(_.asMethod)
val matchingMethods = allMethods filter { m =>
paramLists(c)(m).isEmpty && m.returnType.weak_<:<(weakTypeOf[TestSuite#Test])
}
val methodNames = matchingMethods map { m =>
val sel = q"${suite.tree}.${m.name.toTermName}"
val suiteName = cls.toString.replaceAll(".type$", "").split("\\.").last
q"""($suiteName+" / "+$sel.name, $sel)"""
}
c.Expr[Unit](q"""includeAll(_root_.scala.List(..$methodNames))""")
}
}
================================================
FILE: text/shared/src/main/scala/rapture/text/ansi.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.text
import rapture.base._
object ansi {
def apply[T](fn: Tty => T) = {
val tty = new Tty()
try fn(tty)
catch {
case e: Throwable =>
print(normal(tty))
throw e
} finally print(normal(tty))
}
def esc(implicit tty: Tty) = 27.toChar
def normal(implicit tty: Tty) = s"$esc[0m"
def bold(implicit tty: Tty) = s"$esc[1m"
def underline(implicit tty: Tty) = s"$esc[4m"
def blink(implicit tty: Tty) = s"$esc[5m"
def reverse(implicit tty: Tty) = s"$esc[7m"
def nondisplayed(implicit tty: Tty) = s"$esc[8m"
def black(implicit tty: Tty) = s"$esc[0;30m"
def red(implicit tty: Tty) = s"$esc[0;31m"
def green(implicit tty: Tty) = s"$esc[0;32m"
def yellow(implicit tty: Tty) = s"$esc[0;33m"
def blue(implicit tty: Tty) = s"$esc[0;34m"
def magenta(implicit tty: Tty) = s"$esc[0;35m"
def cyan(implicit tty: Tty) = s"$esc[0;36m"
def white(implicit tty: Tty) = s"$esc[0;37m"
def boldBlack(implicit tty: Tty) = s"$esc[1;30m"
def boldRed(implicit tty: Tty) = s"$esc[1;31m"
def boldGreen(implicit tty: Tty) = s"$esc[1;32m"
def boldYellow(implicit tty: Tty) = s"$esc[1;33m"
def boldBlue(implicit tty: Tty) = s"$esc[1;34m"
def boldMagenta(implicit tty: Tty) = s"$esc[1;35m"
def boldCyan(implicit tty: Tty) = s"$esc[1;36m"
def boldWhite(implicit tty: Tty) = s"$esc[1;37m"
def cursor(row: Int, col: Int)(implicit tty: Tty) = s"$esc[${row};${col}H"
def up(n: Int = 1)(implicit tty: Tty) = s"$esc[${n}A"
def down(n: Int = 1)(implicit tty: Tty) = s"$esc[${n}B"
def right(n: Int = 1)(implicit tty: Tty) = s"$esc[${n}C"
def left(n: Int = 1)(implicit tty: Tty) = s"$esc[${n}D"
def readPassword(prompt: String)(implicit tty: Tty): String = {
print(s"${prompt}$nondisplayed")
val res = compatibility.readLine
println(normal)
res
}
class Tty private[text] ()
}
================================================
FILE: text/shared/src/main/scala/rapture/text/text.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.text
object TextProcess {
implicit val defaultTextProcess: TextProcess = unindent()
}
trait TextProcess {
def apply(s: String): String
}
object unindent {
def apply(): TextProcess = implicitTextProcess
implicit val implicitTextProcess: TextProcess = new TextProcess {
def apply(s: String): String = {
val lines = s.split("\n").dropWhile(_.isEmpty)
val indent = lines.headOption.getOrElse("").indexWhere(_ != ' ')
lines.map { ln =>
if (ln.take(indent).forall(_ == ' ')) ln.drop(indent) else ln.dropWhile(_ == ' ')
}.mkString("\n")
}
}
}
================================================
FILE: time/shared/src/main/scala/rapture/time/time.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.time
import rapture.core._
import java.util.Calendar
import java.text.SimpleDateFormat
object dateFormats {
object shortUs { implicit val implicitDateFormat = DateFormat("MM/dd/yy") }
object shortEuropean { implicit val implicitDateFormat = DateFormat("dd/MM/yy") }
object longUs { implicit val implicitDateFormat = DateFormat("MMMM d, yyyy") }
object longEuropean { implicit val implicitDateFormat = DateFormat("d MMMM yyyy") }
}
object timeFormats {
object hms { implicit val implicitTimeFormat = TimeFormat("HH:mm:ss") }
object hm { implicit val implicitTimeFormat = TimeFormat("HH:mm") }
object alternative { implicit val implicitTimeFormat = TimeFormat("h.mma") }
}
case class DateFormat(pattern: String) {
def format(d: Date): String = {
val c = Calendar.getInstance
c.setTimeInMillis(d.toLong)
new SimpleDateFormat(pattern).format(c.getTime)
}
def format(dt: DateTime): String = {
val c = Calendar.getInstance
c.setTimeInMillis(dt.toLong)
new SimpleDateFormat(pattern).format(c.getTime)
}
}
case class TimeFormat(pattern: String) {
def format(dt: DateTime): String = {
val c = Calendar.getInstance
c.setTimeInMillis(dt.toLong)
new SimpleDateFormat(pattern).format(c.getTime)
}
}
object Date {
def unapply(n: Long) = {
val c = Calendar.getInstance
c.setTimeInMillis(n)
Some(Date(c.get(Calendar.YEAR), c.get(Calendar.MONTH) + 1, c.get(Calendar.DATE)))
}
}
object DateTime {
def unapply(n: Long) = {
val Date(date) = n
val c = Calendar.getInstance
c.setTimeInMillis(n)
Some(DateTime(date, c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE), c.get(Calendar.SECOND)))
}
}
object Time {
def apply(hours: Int): Time = Time(hours, 0, 0)
def apply(hours: Int, minutes: Int): Time = Time(hours, minutes, 0)
}
object `package` {
def monthString(n: Int) =
List("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")(n - 1)
val Jan = Month(1)
val Feb = Month(2)
val Mar = Month(3)
val Apr = Month(4)
val May = Month(5)
val Jun = Month(6)
val Jul = Month(7)
val Aug = Month(8)
val Sep = Month(9)
val Oct = Month(10)
val Nov = Month(11)
val Dec = Month(12)
implicit class TimeEnrichedString(s: StringContext) {
private val Matcher1 = "([0-9][0-9]):([0-9][0-9])".r
private val Matcher2 = "([0-9][0-9]):([0-9][0-9]):([0-9][0-9])".r
def t(args: Int*): Time = s.parts.head match {
case Matcher1(h, m) => Time(h.toInt, m.toInt)
case Matcher2(h, m, s) => Time(h.toInt, m.toInt, s.toInt)
}
}
implicit val dateOrder = new Ordering[Date] {
def compare(d1: Date, d2: Date) = if (d1 < d2) -1 else if (d2 == d1) 0 else 1
}
implicit val dateTimeOrder = new Ordering[DateTime] {
def compare(d1: DateTime, d2: DateTime) = if (d1 < d2) -1 else if (d2 == d1) 0 else 1
}
def now() = DateTime.unapply(System.currentTimeMillis).get
implicit class IntoMonth(d: Int) {
def -(m: Month) = new IntoDay(m)
class IntoDay(m: Month) {
def -(y: Int) = Date(y, m.no, d)
}
}
}
case class Time(hours: Int, minutes: Int, seconds: Int)
case class Date(year: Int, month: Int, day: Int) { date =>
override def toString() =
day + "-" + monthString(month) + "-" + year
def +(n: Int) = Date.unapply(n + toLong).get
def -(n: Int) = Date.unapply(toLong - n).get
override def equals(that: Any): Boolean = that match {
case that: Date => toLong == that.toLong
case that: DateTime => toLong == that.toLong
case _ => false
}
def toLong = {
val c = Calendar.getInstance
c.set(Calendar.YEAR, year)
c.set(Calendar.MONTH, month - 1)
c.set(Calendar.DATE, day)
c.getTimeInMillis
}
def at(time: Time) = DateTime(date, time.hours, time.minutes, time.seconds)
def at(hours: Int) = new {
def h(minutes: Int) = new DateTime(date, hours, minutes, 0) {
def m(seconds: Int) = DateTime(date, hours, minutes, seconds)
}
}
def >(that: Date): Boolean = toLong > that.toLong
def <(that: Date): Boolean = toLong < that.toLong
def >=(that: Date): Boolean = toLong >= that.toLong
def <=(that: Date): Boolean = toLong <= that.toLong
def format(implicit dateFormat: DateFormat) = dateFormat.format(this)
}
case class DateTime(date: Date, hour: Int, minute: Int, second: Int) {
def pad(n: Int) = if (n < 10) "0" + n else n
def +(n: Int) = DateTime.unapply(n + toLong).get
def -(n: Int) = DateTime.unapply(toLong - n).get
def -(d: DateTime): Long = toLong - d.toLong
override def toString() =
date.toString + " " + pad(hour) + ":" + pad(minute) + ":" + pad(second)
override def equals(that: Any): Boolean = that match {
case that: Date => toLong == that.toLong
case that: DateTime => toLong == that.toLong
case _ => false
}
def >(that: DateTime): Boolean = toLong > that.toLong
def <(that: DateTime): Boolean = toLong < that.toLong
def >=(that: DateTime): Boolean = toLong >= that.toLong
def <=(that: DateTime): Boolean = toLong <= that.toLong
def toLong = {
val c = Calendar.getInstance
c.setTimeInMillis(0L)
c.set(Calendar.YEAR, date.year)
c.set(Calendar.MONTH, date.month - 1)
c.set(Calendar.DATE, date.day)
c.set(Calendar.HOUR, hour)
c.set(Calendar.MINUTE, minute)
c.set(Calendar.SECOND, second)
c.getTimeInMillis
}
def format(implicit dateFormat: DateFormat, timeFormat: TimeFormat) =
dateFormat.format(this) + " " + timeFormat.format(this)
}
case class Month(no: Int)
================================================
FILE: unixsocket/jvm/src/main/scala/rapture/unixsocket/UnixSocketHttpClient.scala
================================================
package rapture.unixsocket
import java.io.File
import java.net.{Socket, InetSocketAddress}
import java.util.concurrent.TimeUnit
import org.apache.http.{HttpRequest, HttpHost}
import org.apache.http.config.SocketConfig
import org.apache.http.conn.{ManagedHttpClientConnection, HttpClientConnectionOperator, SchemePortResolver}
import org.apache.http.impl.conn.{PoolingHttpClientConnectionManager, ManagedHttpClientConnectionFactory, DefaultHttpResponseParserFactory, DefaultRoutePlanner}
import org.apache.http.impl.client.HttpClients
import org.apache.http.impl.io.DefaultHttpRequestWriterFactory
import org.apache.http.protocol.HttpContext
import org.newsclub.net.unix.{AFUNIXSocketAddress, AFUNIXSocket}
object UnixSocketHttpClient {
/**
* Executes an HttpRequest
* @param host The custom HttpHost (the hostname is actually the socket file)
* @param request The HttpRequest (eg. GET /)
* @return The CloseableHttpResponse
*/
def execute(host: HttpHost, request: HttpRequest) =
client.execute(host, request)
/**
* Create the customized http client
*/
private val client = HttpClients
.custom
.setConnectionManager(connectionManager)
.setConnectionManagerShared(true)
.setRoutePlanner(routePlanner)
.build
/**
* The customized connection manager
*/
private def connectionManager = new PoolingHttpClientConnectionManager(connectionOperator, connectionFactory, -1, TimeUnit.MILLISECONDS)
/**
* A route planner with our custom scheme port resolver
*/
private def routePlanner = new DefaultRoutePlanner(schemePortResolver)
/**
* Our connection operator
* It will create unix socket connections for us
*/
private def connectionOperator = new HttpClientConnectionOperator {
/**
* Creates the socket for our request, which is a unix socket.
*/
def connect(conn: ManagedHttpClientConnection, host: HttpHost, localAddress: InetSocketAddress,
connectTimeout: Int, socketConfig: SocketConfig, context: HttpContext): Unit = {
val sock: Socket = AFUNIXSocket.newInstance
sock.setTcpNoDelay(socketConfig.isTcpNoDelay)
if (socketConfig.getRcvBufSize > 0) {
sock.setReceiveBufferSize(socketConfig.getRcvBufSize)
}
if (socketConfig.getSndBufSize > 0) {
sock.setSendBufferSize(socketConfig.getSndBufSize)
}
val linger: Int = socketConfig.getSoLinger
if (linger >= 0) {
sock.setSoLinger(true, linger)
}
sock.connect(new AFUNIXSocketAddress(new File(host.getHostName)), connectTimeout)
conn.bind(sock)
}
/**
* Can upgrade an http connection. This is only used for proxies - so we don't need it
*/
def upgrade(conn: ManagedHttpClientConnection, host: HttpHost, context: HttpContext) =
throw new NotImplementedError("upgrade is not supported - a unix-socket cannot be accessed through a proxy")
}
/**
* A default managed connection factory
*/
private def connectionFactory = new ManagedHttpClientConnectionFactory(
new DefaultHttpRequestWriterFactory(),
new DefaultHttpResponseParserFactory()
)
/**
* Resolves the port for the "unix" scheme
* We don't actually need a port, but an NPE will be thrown if we don't replace it.
*/
private def schemePortResolver = new SchemePortResolver { def resolve(host: HttpHost) = 0 }
}
================================================
FILE: unixsocket/jvm/src/main/scala/rapture/unixsocket/UnixSocketHttpUrl.scala
================================================
package rapture.unixsocket
import rapture.core.ParseException
case class UnixSocketHttpUrl(socketFileName: String, queryString: String, queryParams: Option[String])
object UnixSocketHttpUrl {
private val UnixSocketRegex = """unix:\/\/(\/[^:]+):(\/?[^\?]*)(\?[^\?]*)?""".r
@throws[ParseException]
def parse(unixSocketUrl: String): UnixSocketHttpUrl = {
unixSocketUrl match {
case UnixSocketRegex(unixSocket, queryUrl, queryParams) => UnixSocketHttpUrl(unixSocket, queryUrl, Option(queryParams))
case _ => throw new ParseException(unixSocketUrl, "unix socket url")
}
}
}
================================================
FILE: unixsocket/jvm/src/main/scala/rapture/unixsocket/package.scala
================================================
package rapture
import rapture.core.`package`._
import rapture.core.Mode
import rapture.io.OutputStreamBuilder
import rapture.io.`package`._
import rapture.net._
import rapture.uri.UriContext
import java.io._
import org.apache.http.HttpHost
import org.apache.http.client.config.RequestConfig
import org.apache.http.client.methods._
import org.apache.http.entity.AbstractHttpEntity
package object unixsocket {
implicit class EnrichedUnixUriContext(uc: UriContext.type) {
// `unix+http` as method name did not play well with the implicit conversion it seems :(
def unix(constants: List[String])(variables: List[String]) = {
var unixSocketUrl = "unix:" + constants.zip(variables :+ "").map { case (a, b) => a+b }.mkString
UnixSocketHttpUrl.parse(unixSocketUrl)
}
}
implicit def basicHttpSupport: HttpSupport[UnixSocketHttpUrl] = new HttpSupport[UnixSocketHttpUrl] {
def doHttp[C: PostType, T](unixSocketHttpUrl: UnixSocketHttpUrl, content: C,
headers: Map[String, String] = Map(),method: String = "POST")
(implicit mode: Mode[`NetUrl#httpPost`], httpTimeout: HttpTimeout,
httpRedirectConfig: HttpRedirectConfig, httpCertificateConfig: HttpCertificateConfig,
httpBasicAuthentication: HttpBasicAuthentication):
mode.Wrap[HttpResponse, HttpExceptions with httpTimeout.Throws] =
mode wrap {
val host = HttpHost.create(s"unix://${unixSocketHttpUrl.socketFileName}")
val url = unixSocketHttpUrl.queryString + unixSocketHttpUrl.queryParams.getOrElse("")
class InvertedHttpEntity extends AbstractHttpEntity {
override def isRepeatable: Boolean = false
override def getContentLength: Long = -1
override def isStreaming: Boolean = false
override def getContent: InputStream = throw new UnsupportedOperationException
override def writeTo(outputStream: OutputStream): Unit = {
ensuring(OutputStreamBuilder.output(outputStream)) { out =>
?[PostType[C]].sender(content) > out
}
}
}
val request = method.toUpperCase match {
case "GET" => new HttpGet(url)
case "POST" => {
val post = new HttpPost(url)
if(content != None)
post.setEntity(new InvertedHttpEntity)
post
}
case "PUT" => {
val put = new HttpPut(url)
if(content != None)
put.setEntity(new InvertedHttpEntity)
put
}
case "DELETE" => new HttpDelete(url)
}
val config = RequestConfig
.custom()
.setConnectTimeout(httpTimeout.duration)
.build
request.setConfig(config)
def base64encode(content: String) =
NetUrl.base64.encode(content.getBytes("UTF-8")).mkString
httpBasicAuthentication.credentials foreach {
case (username, password) =>
request.setHeader("Authorization", "Basic " + base64encode(s"$username:$password"))
}
?[PostType[C]]
.contentType
.foreach { ct => request.setHeader("Content-Type", ct.name) }
for((k, v) <- headers) request.setHeader(k, v)
val response = UnixSocketHttpClient.execute(host, request)
val statusLine = response.getStatusLine
val statusCode = statusLine.getStatusCode
val responseHeaders = response.getAllHeaders.map(header => (header.getName, List(header.getValue))).toMap
new HttpResponse(responseHeaders, statusCode, response.getEntity.getContent)
}
}
}
================================================
FILE: uri/shared/src/main/scala/rapture/uri/classpath.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.uri
import rapture.core._
object ClasspathUrl {
implicit def cpSlashString: Dereferenceable[ClasspathUrl, String, ClasspathUrl] =
new Dereferenceable[ClasspathUrl, String, ClasspathUrl] {
def dereference(p1: ClasspathUrl, p2: String) = ClasspathUrl(p1.elements :+ p2)
}
implicit def cpSlashRelativePath[RP <: RelativePath]: Dereferenceable[ClasspathUrl, RP, ClasspathUrl] =
new Dereferenceable[ClasspathUrl, RP, ClasspathUrl] {
def dereference(p1: ClasspathUrl, p2: RP) = ClasspathUrl(p1.elements.dropRight(p2.ascent) ++ p2.elements)
}
implicit def uriCapable: UriCapable[ClasspathUrl] = new UriCapable[ClasspathUrl] {
def uri(cp: ClasspathUrl) = Uri("classpath", cp.elements.mkString("/"))
}
}
case class ClasspathUrl(elements: Vector[String]) {
override def toString: String = s"classpath:${elements.mkString("/")}"
}
================================================
FILE: uri/shared/src/main/scala/rapture/uri/macros.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.uri
import rapture.base._
import rapture.core._
object Paramable {
implicit val stringParamable = new Paramable[String] { def paramize(s: String): String = s }
implicit val intParamable = new Paramable[Int] { def paramize(s: Int): String = s.toString }
implicit val doubleParamable = new Paramable[Double] { def paramize(s: Double): String = s.toString }
}
trait Paramable[T] {
def paramize(t: T): String
}
object UriMacros {
def uriMacro(c: WhiteboxContext)(content: c.Expr[String]*): c.Expr[Any] = {
import c.universe._
import compatibility._
c.prefix.tree match {
case Apply(_, List(Apply(_, rawParts))) =>
rawParts.head match {
case Literal(Constant(part: String)) =>
val scheme = part.split(":", 2) match {
case Array(s, _) => s
case _ => c.abort(c.enclosingPosition, "could not find a valid scheme for this URI.")
}
val constants: List[String] = rawParts.map {
case Literal(Constant(s: String)) => s
}
val constantsAfterScheme = constants match {
case h :: t => h.substring(scheme.length + 1) :: t
case Nil => Nil
}
val variables = content.map(_.tree).to[List]
c.Expr(q"""_root_.rapture.uri.UriContext.${termName(c, scheme)}(_root_.scala.List(
..$constantsAfterScheme))(_root_.scala.List(..$variables))""")
}
}
}
}
================================================
FILE: uri/shared/src/main/scala/rapture/uri/nav.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.uri
import rapture.core._
trait `Navigable#children` extends MethodConstraint
trait `Navigable#descendants` extends MethodConstraint
trait `Navigable#isDirectory` extends MethodConstraint
trait `Navigable#walkFilter` extends MethodConstraint
trait Navigable[UrlType] {
def children(url: UrlType)(implicit mode: Mode[`Navigable#children`]): mode.Wrap[Seq[UrlType], Exception]
/** Returns false if the filesystem object represented by this FsUrl is a file, and true if
* it is a directory. */
def isDirectory(url: UrlType)(implicit mode: Mode[`Navigable#isDirectory`]): mode.Wrap[Boolean, Exception]
/** If this represents a directory, returns an iterator over all its descendants,
* otherwise returns the empty iterator. */
def descendants(url: UrlType)(
implicit mode: Mode[`Navigable#descendants`]): mode.Wrap[Iterator[UrlType], Exception] =
mode wrap {
children(url)(modes.throwExceptions()).iterator.flatMap { c =>
if (isDirectory(c)(modes.throwExceptions()))
Iterator(c) ++ descendants(c)(modes.throwExceptions())
else Iterator(c)
}
}
}
class NavigableExtras[UrlType: Navigable](url: UrlType) {
/** Return a sequence of children of this URL */
def children(implicit mode: Mode[`Navigable#children`]) =
mode flatWrap ?[Navigable[UrlType]].children(url)
/** Return true if this URL node is a directory (i.e. it can contain other URLs). */
def isDirectory(implicit mode: Mode[`Navigable#isDirectory`]): mode.Wrap[Boolean, Exception] =
mode flatWrap ?[Navigable[UrlType]].isDirectory(url)
/** Return an iterator of all descendants of this URL. */
def descendants(implicit mode: Mode[`Navigable#descendants`]): mode.Wrap[Iterator[UrlType], Exception] =
mode flatWrap ?[Navigable[UrlType]].descendants(url)
def walkFilter(cond: UrlType => Boolean)(
implicit mode: Mode[`Navigable#walkFilter`]): mode.Wrap[Seq[UrlType], Exception] = mode wrap {
children(modes.throwExceptions()) filter cond flatMap { f =>
new NavigableExtras(f).walkFilter(cond)(modes.throwExceptions())
}
}
}
================================================
FILE: uri/shared/src/main/scala/rapture/uri/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.uri
import rapture.core._
import language.experimental.macros
import scala.language.implicitConversions
object UriContext
object `package` {
implicit class EnrichedStringContext(sc: StringContext) {
def uri(content: String*): Any = macro UriMacros.uriMacro
}
implicit class EnrichedUriContext(uc: UriContext.type) {
def classpath(constants: List[String])(variables: List[String]) =
new ClasspathUrl(constants.zip(variables :+ "").map { case (a, b) => a + b }.mkString.split("/").to[Vector])
}
val $ : String = ""
val !! : String = ".."
object ^ extends RootedPath(Vector())
implicit def dereferenceable[Res](res: Res): Dereferenceable.Capability[Res] = alloc(res)
implicit def uriCapable[Res: UriCapable](res: Res): UriCapable.Capability[Res] = alloc(res)
implicit def linkCapable[Res: Linkable](res: Res): Linkable.Capability[Res] = alloc(res)
implicit def parentable[Res](res: Res): Parentable.Capability[Res] = alloc(res)
implicit def navigableExtras[Res: Navigable](url: Res): NavigableExtras[Res] =
new NavigableExtras(url)
}
================================================
FILE: uri/shared/src/main/scala/rapture/uri/paths.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.uri
import scala.annotation.implicitNotFound
object RelativePath {
implicit val relativePathLinkable: Linkable[RelativePath] = new Linkable[RelativePath] {
def link(res: RelativePath): PathLink = PathLink(res.toString)
}
val Self: RelativePath = RelativePath(0, Vector())
}
case class RelativePath(ascent: Int, elements: Vector[String]) {
override def toString = if (ascent == 0 && elements.isEmpty) "." else "../" * ascent + elements.mkString("/")
override def equals(that: Any) = that match {
case RelativePath(a, es) => a == ascent && es == elements
case _ => false
}
override def hashCode = ascent ^ elements.hashCode
}
object RootedPath {
def parse(s: String): Option[RootedPath] = {
if (s.head == '/') Some(RootedPath(s.tail.split("/").to[Vector]))
else None
}
implicit val linkable: Linkable[RootedPath] = new Linkable[RootedPath] {
def link(res: RootedPath): PathLink = PathLink(res.toString)
}
}
object / {
def unapply(p: RootedPath): Option[(RootedPath, String)] =
if (p.elements.isEmpty) None
else Some((RootedPath(p.elements.init), p.elements.last))
}
case class RootedPath(elements: Vector[String]) {
override def toString = elements.mkString("/", "/", "")
override def equals(that: Any) = that match {
case RootedPath(es) => es == elements
case _ => false
}
override def hashCode = elements.hashCode
}
object Dereferenceable {
implicit val stringSlashString: Dereferenceable[String, String, RelativePath] =
new Dereferenceable[String, String, RelativePath] {
def dereference(p1: String, p2: String): RelativePath = RelativePath(0, Vector(p1, p2))
}
implicit def relativePathSlashString[RP <: RelativePath]: Dereferenceable[RP, String, RelativePath] =
new Dereferenceable[RP, String, RelativePath] {
def dereference(p1: RP, p2: String): RelativePath = RelativePath(p1.ascent, p1.elements :+ p2)
}
implicit def rootSlashString[RRP <: RootedPath]: Dereferenceable[RRP, String, RootedPath] =
new Dereferenceable[RRP, String, RootedPath] {
def dereference(p1: RRP, p2: String): RootedPath = RootedPath(p1.elements :+ p2)
}
implicit def rootSlashRelative[RRP <: RootedPath, RP <: RelativePath]: Dereferenceable[RRP, RP, RootedPath] =
new Dereferenceable[RRP, RP, RootedPath] {
def dereference(p1: RRP, p2: RP): RootedPath = RootedPath(p2.elements ++ p1.elements.drop(p2.ascent))
}
class Capability[Path](val path: Path) {
def /[Elem, Return](elem: Elem)(implicit deref: Dereferenceable[Path, Elem, Return]): Return =
deref.dereference(path, elem)
}
}
@implicitNotFound("it is not possible to dereference a value of type ${P1} by a value of type ${P2}.")
trait Dereferenceable[-P1, -P2, +Return] {
def dereference(p1: P1, p2: P2): Return
}
object Parentable {
implicit def relativePathParent[RP <: RelativePath]: Parentable[RP, RelativePath] =
new Parentable[RP, RelativePath] {
def parent(p: RP): RelativePath =
RelativePath(if (p.elements.isEmpty) p.ascent + 1 else p.ascent, p.elements.dropRight(1))
}
implicit def rootRelativePathParent[RRP <: RootedPath]: Parentable[RRP, RootedPath] =
new Parentable[RRP, RootedPath] {
def parent(p1: RRP): RootedPath = RootedPath(p1.elements.dropRight(1))
}
class Capability[Path](val path: Path) {
def parent[Return](implicit parentable: Parentable[Path, Return]): Return =
parentable.parent(path)
}
}
@implicitNotFound("type ${P} does not have a parent")
trait Parentable[-P, +Return] {
def parent(p1: P): Return
}
================================================
FILE: uri/shared/src/main/scala/rapture/uri/uri.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.uri
object UriCapable {
class Capability[Res: UriCapable](res: Res) {
def uri: Uri = implicitly[UriCapable[Res]].uri(res)
}
}
case class Uri(scheme: String, schemeSpecificPart: String) {
override def toString: String = s"$scheme:$schemeSpecificPart"
}
trait UriCapable[-Res] {
def uri(res: Res): Uri
}
object Linkable {
class Capability[Res: Linkable](res: Res) {
def link: PathLink = implicitly[Linkable[Res]].link(res)
}
implicit def linkableUri[Res: UriCapable]: Linkable[Res] = new Linkable[Res] {
def link(res: Res): PathLink = PathLink(implicitly[UriCapable[Res]].uri(res).toString)
}
}
object PathLink {
implicit def linkLinkable: Linkable[PathLink] = new Linkable[PathLink] {
def link(lnk: PathLink): PathLink = lnk
}
}
case class PathLink(link: String) {
override def toString: String = link
}
trait Linkable[-Res] {
def link(res: Res): PathLink
}
================================================
FILE: version.sbt
================================================
version in ThisBuild := "2.0.0-M9"
================================================
FILE: xml/shared/src/main/scala/rapture/xml/ast.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml
import rapture.core._
import rapture.data._
import scala.util._
import scala.collection.immutable._
trait XmlAst extends DataAst {
def isScalar(any: Any) = isString(any)
def getScala(any: Any) = Try(getString(any)) getOrElse { throw new Exception }
def getString(string: Any): String
def fromString(string: String): Any
def isComment(any: Any): Boolean
def isPi(any: Any): Boolean
def getPiText(any: Any): String
def getComment(any: Any): String
def getAttributes(obj: Any): Map[String, String]
/** Tests if the element represents a `String` */
def isString(any: Any): Boolean
/** Returns the DataType instance for the particular type. */
def getType(any: Any): DataTypes.DataType =
if (isString(any)) DataTypes.String
else if (isObject(any)) DataTypes.Object
else if (isArray(any)) DataTypes.Array
else throw MissingValueException()
def convert(v: Any, ast: DataAst): Any = {
val oldAst = ast.asInstanceOf[XmlAst]
if (oldAst.isString(v)) fromString(oldAst.getString(v))
else if (oldAst.isArray(v)) fromArray(oldAst.getArray(v).map(convert(_, oldAst)))
else if (oldAst.isObject(v)) fromObject(oldAst.getObject(v).mapValues(convert(_, oldAst)))
else nullValue
}
val nullValue = ""
protected def typeTest(pf: PartialFunction[Any, Unit])(v: Any) = pf.isDefinedAt(v)
}
trait XmlBufferAst extends XmlAst with MutableDataAst
================================================
FILE: xml/shared/src/main/scala/rapture/xml/context.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml
import rapture.base._
import rapture.core._
import rapture.data._
import language.experimental.macros
private[xml] object XmlDataMacros extends DataContextMacros[Xml, XmlAst] {
def dataCompanion(c: BlackboxContext): c.Expr[DataCompanion[Xml, XmlAst]] = c.universe.reify(Xml)
def parseSource(s: List[String], stringsUsed: List[Boolean]) =
try {
XmlValidator.validate(s)
None
} catch {
case XmlValidator.ValidationException(strNo, pos, expected, found) =>
val f = if (found == '\u0000') "end of input" else s"'$found'"
Some((strNo, pos, s"failed to parse Xml literal: expected $expected, but found $f"))
case XmlValidator.DuplicateKeyException(strNo, pos, key) =>
Some((strNo, pos, s"""duplicate key found in Xml literal: "$key""""))
}
override def contextMacro(c: BlackboxContext)(exprs: c.Expr[ForcedConversion[Xml]]*)(
parser: c.Expr[Parser[String, XmlAst]]): c.Expr[Xml] =
super.contextMacro(c)(exprs: _*)(parser)
}
private[xml] object XmlBufferDataMacros extends DataContextMacros[XmlBuffer, XmlBufferAst] {
def dataCompanion(c: BlackboxContext): c.Expr[DataCompanion[XmlBuffer, XmlBufferAst]] =
c.universe.reify(XmlBuffer)
def parseSource(s: List[String], stringsUsed: List[Boolean]) =
try {
XmlValidator.validate(s)
None
} catch {
case XmlValidator.ValidationException(strNo, pos, expected, found) =>
val f = if (found == '\u0000') "end of input" else s"'$found'"
Some((strNo, pos, s"Failed to parse XmlBuffer literal: Expected $expected, but found $f."))
}
override def contextMacro(c: BlackboxContext)(exprs: c.Expr[ForcedConversion[XmlBuffer]]*)(
parser: c.Expr[Parser[String, XmlBufferAst]]): c.Expr[XmlBuffer] =
super.contextMacro(c)(exprs: _*)(parser)
}
/** Provides support for XML literals, in the form xml" { } " or xml""" { } """.
* Interpolation is used to substitute variable names into the XML, and to extract values
* from a XML string. */
private[xml] class XmlStrings(sc: StringContext) {
class XmlContext() extends DataContext(Xml, sc) {
def apply(exprs: ForcedConversion[Xml]*)(implicit parser: Parser[String, XmlAst]): Xml = macro XmlDataMacros.contextMacro
}
val xml = new XmlContext()
}
private[xml] class XmlBufferStrings(sc: StringContext) {
class XmlBufferContext() extends DataContext(XmlBuffer, sc) {
def apply(exprs: ForcedConversion[XmlBuffer]*)(implicit parser: Parser[String, XmlBufferAst]): XmlBuffer = macro XmlBufferDataMacros.contextMacro
}
val xmlBuffer = new XmlBufferContext()
}
================================================
FILE: xml/shared/src/main/scala/rapture/xml/extractors.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml
import rapture.core._
import rapture.data._
import scala.util._
import language.higherKinds
private[xml] case class XmlCastExtractor[T](ast: XmlAst, dataType: DataTypes.DataType)
private[xml] trait Extractors extends Extractors_1 {
implicit def optionExtractor[T](
implicit ext: Extractor[T, Xml]): Extractor[Option[T], Xml] { type Throws = Nothing } =
GeneralExtractors.optionExtractor[Xml, T]
implicit def tryExtractor[T](implicit ext: Extractor[T, Xml]): Extractor[Try[T], Xml] { type Throws = Nothing } =
GeneralExtractors.tryExtractor[Xml, T]
implicit def genSeqExtractor[T, Coll[_]](
implicit cbf: scala.collection.generic.CanBuildFrom[Nothing, T, Coll[T]],
ext: Extractor[T, Xml]): Extractor[Coll[T], Xml] { type Throws = ext.Throws } = {
GeneralExtractors.genSeqExtractor[T, Coll, Xml]
}
implicit def xmlExtractor(implicit ast: XmlAst): Extractor[Xml, Xml] { type Throws = DataGetException } =
new Extractor[Xml, Xml] {
type Throws = DataGetException
def extract(any: Xml, dataAst: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[Xml, DataGetException] =
mode.wrap(mode.catching[DataGetException, Xml](any.$wrap(any.$normalize)))
}
}
private[xml] trait Extractors_1 {
implicit def stringableExtractors[T](implicit ext: StringParser[T]): Extractor[T, Xml] {
type Throws = DataGetException with ext.Throws
} = new Extractor[T, Xml] {
type Throws = DataGetException with ext.Throws
def extract(any: Xml,
ast: DataAst,
mode: Mode[_ <: MethodConstraint]): mode.Wrap[T, DataGetException with ext.Throws] = mode.wrap {
val value: String = mode.catching[DataGetException, String](any.$ast.getString(any.$normalize))
mode.unwrap(ext.parse(value, mode))
}
}
implicit def xmlBufferExtractor[T](implicit xmlAst: XmlAst,
ext: Extractor[T, Xml]): Extractor[T, XmlBuffer] { type Throws = ext.Throws } =
new Extractor[T, XmlBuffer] {
type Throws = ext.Throws
def extract(any: XmlBuffer, ast: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[T, ext.Throws] =
ext.extract(Xml.construct(MutableCell(any.$root.value), Vector()), ast, mode)
}
implicit def xmlBufferToXmlExtractor(implicit ast: XmlBufferAst): Extractor[XmlBuffer, Xml] =
new Extractor[XmlBuffer, Xml] {
type Throws = DataGetException
def extract(any: Xml, dataAst: DataAst, mode: Mode[_ <: MethodConstraint]): mode.Wrap[XmlBuffer, Throws] =
mode.wrap(XmlBuffer.construct(MutableCell(XmlDataType.xmlSerializer.serialize(any)), Vector()))
}
}
================================================
FILE: xml/shared/src/main/scala/rapture/xml/formatters.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml
import rapture.core._
import rapture.data._
object formatters {
object compact {
def apply[Ast <: XmlAst]()(implicit ast: Ast): Formatter[Ast] { type Out = String } = xmlFormatterImplicit[Ast]
implicit def xmlFormatterImplicit[Ast <: XmlAst](implicit ast: Ast): Formatter[Ast] { type Out = String } =
new Formatter[Ast] {
type Out = String
// FIXME: This is a lazy implementation
def format(xml: Any): String = xml.toString
}
}
}
================================================
FILE: xml/shared/src/main/scala/rapture/xml/macros.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml
import rapture.base._
import rapture.data._
private[xml] object XmlMacros {
def xmlExtractorMacro[T: c.WeakTypeTag, Th](c: WhiteboxContext): c.Expr[Extractor[T, Xml]] =
Macros.extractorMacro[T, Xml, Th](c)
//def xmlBufferExtractorMacro[T: c.WeakTypeTag](c: Context) =
// Macros.extractorMacro2[T, XmlBuffer](c)
def xmlSerializerMacro[T: c.WeakTypeTag](c: WhiteboxContext)(ast: c.Expr[XmlAst]): c.Expr[Serializer[T, Xml]] =
Macros.serializerMacro[T, Xml](c)(ast)
def xmlBufferSerializerMacro[T: c.WeakTypeTag](c: WhiteboxContext)(
ast: c.Expr[XmlBufferAst]): c.Expr[Serializer[T, XmlBuffer]] =
Macros.serializerMacro[T, XmlBuffer](c)(ast)
}
================================================
FILE: xml/shared/src/main/scala/rapture/xml/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml
import rapture.core._
import rapture.data._
object `package` {
val patternMatching = rapture.data.patternMatching
type Extractor[T, -D] = rapture.data.Extractor[T, D]
type Serializer[T, -D] = rapture.data.Serializer[T, D]
type DataGetException = rapture.data.DataGetException
type TypeMismatchException = rapture.data.TypeMismatchException
type MissingValueException = rapture.data.MissingValueException
val TypeMismatchException = rapture.data.TypeMismatchException
val MissingValueException = rapture.data.MissingValueException
implicit def xmlStringContext(sc: StringContext)(implicit parser: Parser[String, XmlAst]) =
new XmlStrings(sc)
implicit def xmlBufferStringContext(sc: StringContext)(implicit parser: Parser[String, XmlBufferAst]) =
new XmlBufferStrings(sc)
}
================================================
FILE: xml/shared/src/main/scala/rapture/xml/serializers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml
import rapture.core._
import rapture.data._
import language.higherKinds
private[xml] case class DirectXmlSerializer[T](ast: XmlAst)
private[xml] case class BasicXmlSerializer[T](serialization: T => Any) extends Serializer[T, Xml] {
def serialize(t: T): Any = serialization(t)
}
private[xml] trait Serializers extends Serializers_1{
implicit def xmlBufferSerializer[T](implicit ser: Serializer[T, Xml]): Serializer[T, XmlBuffer] =
new Serializer[T, XmlBuffer] { def serialize(t: T): Any = ser.serialize(t) }
implicit def intSerializer(implicit ast: XmlAst): Serializer[Int, Xml] =
BasicXmlSerializer(ast fromString _.toString)
implicit def booleanSerializer(implicit ast: XmlAst): Serializer[Boolean, Xml] =
BasicXmlSerializer(ast fromString _.toString)
implicit def stringSerializer(implicit ast: XmlAst): Serializer[String, Xml] =
BasicXmlSerializer(ast.fromString)
implicit def floatSerializer(implicit ast: XmlAst): Serializer[Float, Xml] =
BasicXmlSerializer(ast fromString _.toString)
implicit def doubleSerializer(implicit ast: XmlAst): Serializer[Double, Xml] =
BasicXmlSerializer(ast fromString _.toString)
implicit def bigDecimalSerializer(implicit ast: XmlAst): Serializer[BigDecimal, Xml] =
BasicXmlSerializer(ast fromString _.toString)
implicit def bigIntSerializer(implicit ast: XmlAst): Serializer[BigInt, Xml] =
BasicXmlSerializer(ast fromString _.toString)
implicit def longSerializer(implicit ast: XmlAst): Serializer[Long, Xml] =
BasicXmlSerializer(ast fromString _.toString)
implicit def shortSerializer(implicit ast: XmlAst): Serializer[Short, Xml] =
BasicXmlSerializer(ast fromString _.toString)
implicit def byteSerializer(implicit ast: XmlAst): Serializer[Byte, Xml] =
BasicXmlSerializer(ast fromString _.toString)
implicit def nilSerializer(implicit ast: XmlAst): Serializer[Nil.type, Xml] =
BasicXmlSerializer(v => ast fromArray Nil)
implicit def traversableSerializer[Type, Coll[T] <: Traversable[T]](
implicit ast: XmlAst,
ser: Serializer[Type, Xml]): Serializer[Coll[Type], Xml] =
BasicXmlSerializer(ast fromArray _.map(ser.serialize).to[List])
implicit def optionSerializer[Type](implicit ast: XmlAst,
ser: Serializer[Type, Xml]): Serializer[Option[Type], Xml] =
BasicXmlSerializer(_ map ser.serialize getOrElse ast.nullValue)
implicit def mapSerializer[Type, Ast <: XmlAst](implicit ast: Ast,
ser: Serializer[Type, Xml]): Serializer[Map[String, Type], Xml] =
new Serializer[Map[String, Type], Xml] {
def serialize(m: Map[String, Type]) = ast.fromObject(m.mapValues(ser.serialize))
}
implicit def directXmlSerializer[T: DirectXmlSerializer](implicit ast: XmlAst): Serializer[T, Xml] =
BasicXmlSerializer(
obj => xmlSerializer.serialize(Xml.construct(MutableCell(obj), Vector())(?[DirectXmlSerializer[T]].ast)))
implicit def xmlSerializer[XmlType <: XmlDataType[XmlType, _ <: XmlAst]](
implicit ast: XmlAst): Serializer[XmlType, Xml] =
BasicXmlSerializer[XmlType]({ j =>
if (j.$ast == ast) j.$normalize else ast.convert(j.$normalize, j.$ast)
})
}
trait Serializers_1 {
implicit def generalStringSerializer[S](implicit ast: XmlAst, ss: StringSerializer[S]): Serializer[S, Xml] =
BasicXmlSerializer(s => ast fromString ss.serialize(s))
}
================================================
FILE: xml/shared/src/main/scala/rapture/xml/validator.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml
private[xml] object XmlValidator {
case class ValidationException(strNo: Int, pos: Int, expected: String, found: Char) extends Exception
case class DuplicateKeyException(strNo: Int, pos: Int, key: String) extends Exception
def validate(parts: List[String]) = {
var i = 0
var n = 0
var stack: List[String] = Nil
def s = parts(n)
def cur = if (i >= s.length) '\u0000' else s(i)
def ahead(j: Int) = if (i + j >= s.length) '\u0000' else s(i + j)
def fail(expected: String) = throw ValidationException(n, i, expected, cur)
def failPosition(expected: String) = throw ValidationException(n, i, expected, cur)
def duplicateKey(start: Int, key: String) = throw DuplicateKeyException(n, start, key)
def takeWhitespace(): Unit = while (cur.isWhitespace) next()
def consume(cs: Char*): Unit = cs foreach { c =>
if (cur == c) next() else fail(s"'$c'")
}
def next() = i += 1
def takeTag(): Unit = {
consume('<')
cur match {
case '/' => takeEndTag()
case '?' => takePi()
case '!' => takeSpecial()
case _ => takeStartTag(i)
}
if (stack.nonEmpty) takeText()
}
def takePi(): Unit = {
consume('?')
takeName()
takeWhitespace()
while (i < s.length && cur != '?') next()
consume('?', '>')
}
def takeComment(): Unit = {
consume("--": _*)
while (i < s.length && !(cur == '-' && ahead(1) == '-')) next()
consume("-->": _*)
}
def takeSpecial(): Unit = {
consume('!')
cur match {
case '-' => takeComment()
case '[' =>
consume('[')
cur match {
case 'C' =>
consume("CDATA[": _*)
case 'P' =>
consume("PCDATA[": _*)
case _ =>
fail("CDATA or PCDATA section")
}
while (i < s.length && !(cur == ']' && ahead(1) == ']')) next()
consume("]]>": _*)
case _ => fail("'-' or '['")
}
}
def takeEndTag(): Unit = {
consume('/')
consume(stack.head: _*)
stack = stack.tail
consume('>')
}
def takeName(): String = {
val start = i
if (!cur.isLetter) fail("letter") else next()
while (cur.isLetterOrDigit && i < s.length) next()
s.substring(start, i)
}
def takeAttribute(): Unit = {
takeName()
takeWhitespace()
consume('=')
takeWhitespace()
takeAttributeValue()
}
def takeStartTag(start: Int): Unit = {
val tagName = takeName()
stack ::= tagName
takeWhitespace()
takeTagContents(tagName)
}
def takeTagContents(tagName: String): Unit = cur match {
case '>' =>
consume('>')
case '/' =>
stack = stack.tail
consume('/', '>')
case _ =>
takeAttribute()
takeWhitespace()
takeTagContents(tagName)
}
def takeText(): Unit = cur match {
case '<' =>
takeTag()
case '&' =>
takeEntity()
takeText()
case '\u0000' =>
fail(s"""closing tag "${stack.head}"""")
case _ =>
next()
takeText()
}
def takeEntity(): Unit = {
consume('&')
takeName()
consume(';')
}
def takeAttributeValue(): Unit = cur match {
case quot @ ('\'' | '"') =>
consume(quot)
var finished = false
while (!finished) cur match {
case `quot` =>
consume(quot)
finished = true
case '&' =>
takeEntity()
case _ =>
next()
}
case _ => fail("single or double quote")
}
takeTag()
takeWhitespace()
if (i != s.length) fail("end of data")
}
}
================================================
FILE: xml/shared/src/main/scala/rapture/xml/xml.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml
import rapture.core._
import rapture.data._
import language.experimental.macros
import scala.language.implicitConversions
private[xml] trait Xml_2 {
implicit def xmlExtractorMacro[T <: Product, Th]: Extractor[T, Xml] = macro XmlMacros
.xmlExtractorMacro[T, Th]
implicit def xmlSerializerMacro[T <: Product](implicit ast: XmlAst): Serializer[T, Xml] = macro XmlMacros
.xmlSerializerMacro[T]
}
private[xml] trait Xml_1 extends Xml_2 {
implicit def dynamicWorkaround(j: Xml): DynamicWorkaround = new DynamicWorkaround(j)
}
private[xml] class DynamicWorkaround(xml: Xml) {
def self: Xml = xml.selectDynamic("self")(null)
}
trait `Xml.parse` extends MethodConstraint
private[xml] trait XmlDataCompanion[Type <: XmlDataType[Type, AstType], AstType <: XmlAst]
extends DataCompanion[Type, AstType] {
type ParseMethodConstraint = `Xml.parse`
}
private[xml] object XmlDataType extends Extractors with Serializers
private[xml] trait XmlDataType[+T <: XmlDataType[T, AstType], AstType <: XmlAst] extends DataType[T, AstType]
object XmlBuffer extends XmlDataCompanion[XmlBuffer, XmlBufferAst] {
def construct(any: MutableCell, path: Vector[Either[Int, String]])(implicit ast: XmlBufferAst): XmlBuffer =
new XmlBuffer(any, path)
}
/** Companion object to the `Xml` type, providing factory and extractor methods, and a XML
* pretty printer. */
object Xml extends XmlDataCompanion[Xml, XmlAst] with Xml_1 {
def apply[T](t: T)(implicit ast: XmlAst, ser: Serializer[T, Xml]): Xml =
construct(MutableCell(if(t == null) ast.nullValue else ser.serialize(t)), Vector())
object DynamicApplied {
implicit def auto[L](k: L)(implicit dynApp: DynamicApply[L]): DynamicApplied[L, dynApp.Result] =
new DynamicApplied[L, dynApp.Result](dynApp, k) {
def apply(v: Xml): dynApp.Result = dynApp(v, k)
}
}
abstract class DynamicApplied[L, R](val dynApp: DynamicApply[L] { type Result = R }, key: L) {
def apply(v: Xml): R
}
abstract class DynamicApply[L] {
type Result
def apply(v: Xml, k: L): Result
}
implicit val applyInt: DynamicApply[Int] { type Result = Xml } = new DynamicApply[Int] {
type Result = Xml
def apply(v: Xml, k: Int): Xml = v.$deref(Left(k) +: v.$path)
}
implicit val applySymbol: DynamicApply[Symbol] { type Result = XmlAttribute } = new DynamicApply[Symbol] {
type Result = XmlAttribute
def apply(v: Xml, k: Symbol): XmlAttribute = v.$attribute(k)
}
def construct(any: MutableCell, path: Vector[Either[Int, String]])(implicit ast: XmlAst): Xml = new Xml(any, path)
def ast(xml: Xml): XmlAst = xml.$ast
def extractor[T](implicit ext: Extractor[T, Xml]): Extractor[T, Xml] { type Throws = ext.Throws } = ext
def serializer[T](implicit ser: Serializer[T, Xml]) = ser
implicit def xmlCastExtractor[T: XmlCastExtractor](implicit ast: XmlAst): Extractor[T, XmlDataType[_, _ <: XmlAst]] =
new Extractor[T, XmlDataType[_, _ <: XmlAst]] {
type Throws = DataGetException
def extract(value: XmlDataType[_, _ <: XmlAst],
ast2: DataAst,
mode: Mode[_ <: MethodConstraint]): mode.Wrap[T, DataGetException] =
mode.wrap(ast2 match {
case ast2: XmlAst =>
val norm = mode.catching[DataGetException, Any](value.$normalize)
try {
if (ast == ast2) norm.asInstanceOf[T]
else
XmlDataType.xmlSerializer.serialize(Xml.construct(MutableCell(norm), Vector())(ast2)).asInstanceOf[T]
} catch {
case e: ClassCastException =>
mode.exception[T, DataGetException](
TypeMismatchException(ast.getType(norm), implicitly[XmlCastExtractor[T]].dataType))
}
case _ => ???
})
}
}
case class XmlAttribute(key: String, value: String) {
def as[T: StringParser]: T = implicitly[StringParser[T]].parse(value, modes.throwExceptions())
def is[T: StringParser]: Boolean =
try {
as[T]
true
} catch { case e: Exception => false }
override def toString = s"""$key="$value""""
}
/** Represents some parsed XML. */
class Xml(val $root: MutableCell, val $path: Vector[Either[Int, String]] = Vector())(implicit val $ast: XmlAst)
extends XmlDataType[Xml, XmlAst]
with DynamicData[Xml, XmlAst] {
def apply(attribute: Symbol): XmlAttribute = $attribute(attribute)
def $attribute(attribute: Symbol): XmlAttribute =
XmlAttribute(attribute.name, $ast.getAttributes($normalize)(attribute.name))
def applyDynamic[L, R](field: String)(dynApp: Xml.DynamicApplied[L, R] = 0): R =
dynApp($deref(Right(field) +: $path))
def $wrap(any: Any, path: Vector[Either[Int, String]]): Xml =
new Xml(MutableCell(any), path)
def $deref(path: Vector[Either[Int, String]]): Xml = new Xml($root, path)
def $extract(sp: Vector[Either[Int, String]]): Xml =
if (sp.isEmpty) this
else
sp match {
case Left(i) +: tail => apply(i).$extract(tail)
case Right(e) +: tail => selectDynamic(e)(null).$extract(tail)
}
override def toBareString =
try Xml.format(this)(formatters.compact()($ast))
catch {
case e: Exception => "undefined"
}
override def toString: String = s"""xml""${'"'}$toBareString""${'"'}"""
}
class XmlBuffer(val $root: MutableCell, val $path: Vector[Either[Int, String]] = Vector())(
implicit val $ast: XmlBufferAst)
extends XmlDataType[XmlBuffer, XmlBufferAst]
with MutableDataType[XmlBuffer, XmlBufferAst]
with DynamicData[XmlBuffer, XmlBufferAst] {
def $wrap(any: Any, path: Vector[Either[Int, String]]): XmlBuffer =
new XmlBuffer(MutableCell(any), path)
def $deref(path: Vector[Either[Int, String]]): XmlBuffer = new XmlBuffer($root, path)
def $extract(sp: Vector[Either[Int, String]]): XmlBuffer =
if (sp.isEmpty) this
else
sp match {
case Left(i) +: tail => apply(i).$extract(tail)
case Right(e) +: tail => selectDynamic(e)(null).$extract(tail)
}
override def toBareString =
try Xml.format(this)(formatters.compact()($ast))
catch {
case e: Exception => "undefined"
}
override def toString: String = s"""xml""${'"'}$toBareString""${'"'}"""
}
================================================
FILE: xml-stdlib/shared/src/main/scala/rapture/xml-stdlib/ast.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml.xmlBackends.stdlib
import rapture.core._
import rapture.xml._
import rapture.data.DataTypes
import rapture.data.TypeMismatchException
import rapture.data.MissingValueException
import scala.collection.immutable.ListMap
import scala.xml._
private[stdlib] object StdlibAst extends XmlBufferAst {
override def dereferenceObject(obj: Any, element: String): Any = obj match {
case n: Node if n.child.exists(_.label == element) => n \ element
case ns: NodeSeq if ns.exists(_.child.exists(_.label == element)) => ns \ element
case _ => throw MissingValueException()
}
override def getChildren(obj: Any): Seq[Any] = obj match {
case n: Node => n.child.to[List]
case n: NodeSeq => n.flatMap(_.child).to[List]
case _ => throw new Exception
}
def getArray(array: Any): List[Any] = array match {
case ns: NodeSeq => ns.to[List]
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def getString(string: Any): String = string match {
case ns: NodeSeq => ns.text
case _ => throw TypeMismatchException(getType(string), DataTypes.String)
}
def getObject(obj: Any): ListMap[String, Any] = obj match {
case n: Node =>
ListMap(n.child.map { e =>
e.label -> e.child
}: _*)
case n: NodeSeq =>
ListMap(n.flatMap(_.child.map { e =>
e.label -> e.child
}): _*)
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
def getLabel(obj: Any): String = obj match {
case n: Node => n.label
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
def getAttributes(obj: Any): Map[String, String] = obj match {
case n: Node => n.attributes.asAttrMap
case v =>
println(s"Found $v of type ${v.getClass}")
throw TypeMismatchException(getType(obj), DataTypes.Object)
}
def setObjectValue(obj: Any, name: String, value: Any): Any =
fromObject(getObject(obj).updated(name, value))
def removeObjectValue(obj: Any, name: String): Any = obj match {
case obj: ListMap[_, _] => obj.asInstanceOf[ListMap[String, Any]] - name
case _ => throw TypeMismatchException(getType(obj), DataTypes.Object)
}
def addArrayValue(array: Any, value: Any): Any = array match {
case array: NodeSeq => array :+ value
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def setArrayValue(array: Any, index: Int, value: Any): Any = array match {
case array: NodeSeq =>
new NodeSeq {
def theSeq = array.patch(index, List(value.asInstanceOf[Node]), 1).to[List]
}
case _ => throw TypeMismatchException(getType(array), DataTypes.Array)
}
def isPi(any: Any): Boolean = any match {
case ProcInstr(_, _) => true
case _ => false
}
def getPiText(any: Any): String = any match {
case ProcInstr(_, text) => text
case _ => throw TypeMismatchException(getType(any), DataTypes.Object)
}
def isComment(any: Any): Boolean = any match {
case Comment(_) => true
case _ => false
}
def getComment(any: Any): String = any match {
case Comment(text) => text
case _ => throw TypeMismatchException(getType(any), DataTypes.Object)
}
def getPiTarget(any: Any): String = any match {
case ProcInstr(target, _) => target
case _ => throw TypeMismatchException(getType(any), DataTypes.Object)
}
def isArray(array: Any): Boolean = array match {
case n: Node => false
case ns: NodeSeq => true
case _ => false
}
def isString(string: Any): Boolean = string match {
case Text(_) => true
case _ => false
}
def isObject(obj: Any): Boolean = obj match {
case _: Node => true
case _: NodeSeq => true
case _ => false
}
def isNull(obj: Any): Boolean = false
def fromArray(array: Seq[Any]): Any = array.collect { case e: NodeSeq => e }.foldLeft(NodeSeq.Empty)(_ ++ _)
def fromObject(obj: Map[String, Any]): Any =
obj
.to[List]
.collect {
case (k, v: NodeSeq) =>
Elem(null, k, Null, TopScope, true, v: _*): NodeSeq
}
.foldLeft(NodeSeq.Empty)(_ ++ _)
def fromString(string: String): Any = Text(string)
override val nullValue = ""
override def toString = ""
}
================================================
FILE: xml-stdlib/shared/src/main/scala/rapture/xml-stdlib/extractors.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml.xmlBackends.stdlib
private[stdlib] trait Extractors {}
================================================
FILE: xml-stdlib/shared/src/main/scala/rapture/xml-stdlib/package.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml.xmlBackends.stdlib
import rapture.xml._
object `package` extends Extractors with Serializers {
implicit val implicitXmlAst: XmlBufferAst = StdlibAst
implicit val implicitXmlStringParser: StdlibStringParser.type = StdlibStringParser
}
================================================
FILE: xml-stdlib/shared/src/main/scala/rapture/xml-stdlib/parse.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml.xmlBackends.stdlib
import rapture.core._
import rapture.data._
import rapture.xml._
import scala.xml._
private[stdlib] object StdlibStringParser extends Parser[String, XmlBufferAst] {
override def toString = ""
val ast = StdlibAst
def parse(s: String): Option[Any] =
try Some(XML.loadString(s))
catch { case e: Exception => None }
}
================================================
FILE: xml-stdlib/shared/src/main/scala/rapture/xml-stdlib/serializers.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml.xmlBackends.stdlib
private[stdlib] trait Serializers {}
================================================
FILE: xml-test/shared/src/test/scala/rapture/xml-test/java8TimeTests.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml.test
import java.time._
import rapture.core.ParseException
import rapture.xml._
import rapture.data.Parser
import rapture.test._
import rapture.xml.xmlBackends.stdlib
import rapture.core.java8.time._
class XmlJava8TimeApiTestRun extends Programme {
include(StdlibTests)
object StdlibTests extends XmlJava8TimeApiTests(stdlib.implicitXmlAst, stdlib.implicitXmlStringParser)
}
abstract class XmlJava8TimeApiTests(ast: XmlAst, parser: Parser[String, XmlAst]) extends TestSuite {
implicit def implicitAst: XmlAst = ast
implicit def implicitParser: Parser[String, XmlAst] = parser
case class TestLocalDate(time: LocalDate)
case class TestLocalDateTime(time: LocalDateTime)
case class TestLocalTime(time: LocalTime)
case class TestZonedDateTime(time: ZonedDateTime)
case class TestOffsetDateTime(time: OffsetDateTime)
case class TestOffsetTime(time: OffsetTime)
val `[Java 8 Time Extractor] Extract LocalDate` = test {
xml"""""".as[LocalDate]
} returns LocalDate.of(2017, 1, 23)
val `[Java 8 Time Extractor] Extract LocalDateTime` = test {
xml"""""".as[LocalDateTime]
} returns LocalDateTime.of(2017, 1, 23, 18, 28, 51, 45000000)
val `[Java 8 Time Extractor] Extract LocalTime` = test {
xml"""""".as[LocalTime]
} returns LocalTime.of(18, 38, 14, 997000000)
val `[Java 8 Time Extractor] Extract ZonedDateTime` = test {
xml"""""".as[ZonedDateTime]
} returns ZonedDateTime.of(2017, 1, 23, 18, 41, 2, 86000000, ZoneId.of("Europe/Kiev"))
val `[Java 8 Time Extractor] Extract OffsetDateTime` = test {
xml"""""".as[OffsetDateTime]
} returns OffsetDateTime.of(2017, 1, 23, 18, 44, 18, 221000000, ZoneOffset.ofHours(2))
val `[Java 8 Time Extractor] Extract OffsetTime` = test {
xml"""""".as[OffsetTime]
} returns OffsetTime.of(19, 3, 25, 325000000, ZoneOffset.ofHours(2))
val `[Java 8 Time Extractor] Extract Failure` = test {
xml"""""".as[OffsetTime]
} throws classOf[ParseException]
val `[Java 8 Time Serializator] Serialize LocalDate` = test {
Xml(TestLocalDate(LocalDate.of(2017, 1, 23))).toBareString
} returns xml"""""".toBareString
val `[Java 8 Time Serializator] Serialize LocalDateTime` = test {
Xml(TestLocalDateTime( LocalDateTime.of(2017, 1, 23, 18, 28, 51, 45000000))).toBareString
} returns xml"""""".toBareString
val `[Java 8 Time Serializator] Serialize LocalTime` = test {
Xml(TestLocalTime(LocalTime.of(18, 38, 14, 997000000))).toBareString
} returns xml"""""".toBareString
val `[Java 8 Time Serializator] Serialize ZonedDateTime` = test {
Xml(TestZonedDateTime(ZonedDateTime.of(2017, 1, 23, 18, 41, 2, 86000000, ZoneId.of("Europe/Kiev")))).toBareString
} returns xml"""""".toBareString
val `[Java 8 Time Serializator] Serialize OffsetDateTime` = test {
Xml(TestOffsetDateTime(OffsetDateTime.of(2017, 1, 23, 18, 44, 18, 221000000, ZoneOffset.ofHours(2)))).toBareString
} returns xml"""""".toBareString
val `[Java 8 Time Serializator] Serialize OffsetTime` = test {
Xml(TestOffsetTime(OffsetTime.of(19, 3, 25, 325000000, ZoneOffset.ofHours(2)))).toBareString
} returns xml"""""".toBareString
}
================================================
FILE: xml-test/shared/src/test/scala/rapture/xml-test/tests.scala
================================================
/*
Rapture, version 2.0.0. Copyright 2010-2016 Jon Pretty, Propensive Ltd.
The primary distribution site is
http://rapture.io/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package rapture.xml.test
import rapture.core._
import rapture.xml._
import rapture.data.Parser
import rapture.test._
import rapture.data.dictionaries.dynamic._
class TestRun extends Programme {
include(StdlibTests)
}
private[test] case class Foo(alpha: String, beta: Int)
private[test] case class Bar(foo: Foo, gamma: Double)
private[test] case class Baz(alpha: String, beta: Option[Int])
private[test] case class Baz2(alpha: String, beta: util.Try[Int])
private[test] case class HasDefault(alpha: String = "yes", beta: Int)
private[test] case class HasDefault2(alpha: String, beta: Int = 1)
private[test] case class A(a: B)
private[test] case class B(b: C)
private[test] case class C(c: D)
private[test] case class D(d: E)
private[test] case class E(e: F)
private[test] case class F(f: Int)
import xmlBackends._
object StdlibTests extends XmlTests(stdlib.implicitXmlAst, stdlib.implicitXmlStringParser)
object StdlibPatternMatchTests extends XmlPatternMatchingTests(stdlib.implicitXmlAst, stdlib.implicitXmlStringParser)
object Data {
def source1(implicit ast: XmlAst, parser: Parser[String, XmlAst]) = xml"""Hello423.14159true123test1test222.7testtest70"""
}
abstract class XmlTests(ast: XmlAst, parser: Parser[String, XmlAst]) extends TestSuite {
implicit def implicitAst: XmlAst = ast
implicit def implicitParser: Parser[String, XmlAst] = parser
val source1 = Data.source1
val `Extract Int` = test {
source1.int.as[Int]
} returns 42
val `Extract Option[Int]` = test {
source1.int.as[Option[Int]]
} returns Some(42)
val `Extract Option[Int], wrong type` = test {
source1.string.as[Option[Int]]
} returns None
val `Extract Double` = test {
source1.double.as[Double]
} returns 3.14159
val `Extract Boolean` = test {
source1.boolean.as[Boolean]
} returns true
val `Extract String` = test {
source1.string.as[String]
} returns "Hello"
val `Extract List[Int]` = test {
source1.list.item.as[List[Int]]
} returns List(1, 2, 3)
val `Extract Vector[Int]` = test {
source1.list.item.as[Vector[Int]]
} returns Vector(1, 2, 3)
val `Extract case class` = test {
source1.foo.as[Foo]
} returns Foo("test", 1)
val `Extract case class with missing optional value` = test {
source1.baz.as[Baz]
} returns Baz("test", None)
val `Extract case class with missing tried value` = test {
source1.baz.as[Baz2]
} returns Baz2("test", util.Failure(MissingValueException("beta")))
val `Extract case class with present optional value` = test {
source1.baz2.as[Baz]
} returns Baz("test", Some(7))
val `Extract case class with present tried value` = test {
source1.baz2.as[Baz2]
} returns Baz2("test", util.Success(7))
val `Extract nested case class` = test {
source1.bar.as[Bar]
} returns Bar(Foo("test2", 2), 2.7)
val `Extract deeply-nested case class` = test {
xml"""1""".as[A]
} returns A(B(C(D(E(F(1))))))
val `Extract List element` = test {
source1.list.item(1).as[Int]
} returns 2
val `Extract object element` = test {
source1.bar.foo.alpha.as[String]
} returns "test2"
val `Extract missing value with case class default` = test {
xml"""0""".as[HasDefault]
} returns HasDefault("yes", 0)
val `Extract missing value with case class default 2` = test {
xml"""no""".as[HasDefault2]
} returns HasDefault2("no", 1)
val `Extract case class ignoring default value` = test {
xml"""0no""".as[HasDefault2]
} returns HasDefault2("no", 0)
val `Check type failure` = test {
source1.string.as[Int]
} throws InvalidNumber("Hello", "integer")
val `Check missing value failure` = test {
source1.nothing.as[Int]
} throws MissingValueException("nothing")
val `Serialize string` = test {
Xml("Hello World!").toString
} returns "xml\"\"\"Hello World!\"\"\""
val `Serialize int` = test {
Xml(1648).toString
} returns "xml\"\"\"1648\"\"\""
/*val `Serialize array` = test {
Json(List(1, 2, 3)).toString
} returns "123"
val `Serialize object` = test {
import formatters.humanReadable._
Xml.format(xml"quuxbar")
} returns "quuxbar"
val `Empty object serialization` = test {
import formatters.humanReadable._
Json.format(json"{}")
} returns "{}"
val `Empty node serialization` = test {
import formatters.humanReadable._
Xml.format(xml"")
} returns ""
val `Extracting Option should not throw exception` = test {
val x = xml"""{"foo":"bar"}"""
j.as[Option[String]]
} returns None*/
}
abstract class XmlPatternMatchingTests(ast: XmlAst, parser: Parser[String, XmlAst]) extends TestSuite {
implicit def implicitAst: XmlAst = ast
implicit def implicitParser: Parser[String, XmlAst] = parser
val source1 = Data.source1
val `Pattern matching` = test {
Xml("") match {
case xml"""""" => "Match"
case _ => "Does not match"
}
} returns "Match"
val `Match string` = test {
source1 match {
case xml"""$h""" => h.as[String]
}
} returns "Hello"
val `Match int` = test {
source1 match {
case xml"""$h""" => h.as[Int]
}
} returns 42
val `Match double` = test {
source1 match {
case xml"""$h""" => h.as[Double]
}
} returns 3.14159
val `Match boolean` = test {
source1 match {
case xml"""$h""" => h.as[Boolean]
}
} returns true
}