Skip to content

Instantly share code, notes, and snippets.

@Centaur
Last active August 29, 2015 14:25
Show Gist options
  • Save Centaur/a2f9eea34deace925c1d to your computer and use it in GitHub Desktop.
Save Centaur/a2f9eea34deace925c1d to your computer and use it in GitHub Desktop.
parboiled2
package com.gtan.parsers
import org.parboiled2._
import shapeless._
/**
* val MavenFormat = """(/.+)+/((.+?)(_(.+?)(_(.+))?)?)/(.+?)/(\3-\8(-(.+?))?\.(.+))""".r
* "/org/scala-lang/modules/scalajs/scalajs-sbt-plugin_2.10_0.13/0.5.6/scalajs-sbt-plugin-0.5.6.pom"
* "/io/spray/sbt-revolver_2.10_0.13/0.7.2/sbt-revolver-0.7.2.pom"
* "/org/scala-lang/modules/scalajs/scalajs-tools_2.10/0.5.6/scalajs-tools_2.10-0.5.6.pom"
@param input url string
*/
class MavenUrlParser(val input: ParserInput) extends Parser {
val validIdChars = CharPredicate.Visible -- '_' -- '/' -- '.'
def id: Rule0 = rule {
!CharPredicate.Digit ~ (validIdChars +)
}
def number: Rule0 = rule {
CharPredicate.Digit +
}
def version: Rule0 = rule {
number + '.'
}
def crossBuildVersions: Rule1[Seq[String]] = rule {
('_' ~ capture(version)) *
}
def ext: Rule0 = rule {
CharPredicate.Alpha +
}
/**
* a general strategy to implement 'non-greedy' logic in PEG
* see http://stackoverflow.com/a/2225208/448141
*/
def groupIdsAndArtifactName: Rule2[Seq[String], String] = rule {
('/' ~ capture(id) ~ groupIdsAndArtifactName ~> { (oldStr: String, seq: Seq[String], newStr: String) =>
(oldStr +: seq) :: newStr :: HNil
}) | ('/' ~ capture(id) ~> { str: String => Seq() :: str :: HNil })
}
/**
* or in this case
* @return
*/
def groupIdsAndArtifactName2: Rule2[Seq[String], String] = rule {
oneOrMore('/' ~ capture(id)) ~> {seq: Seq[String] => seq.init :: seq.last :: HNil }
}
def root: RuleN[Seq[String] :: String :: Seq[String] :: String :: HNil] = rule {
groupIdsAndArtifactName ~ crossBuildVersions ~ '/' ~ capture(version) ~> {
(groupIds:Seq[String], artifactName: String, crossBuildVersion: Seq[String], ver: String) =>
val reoccurArtifactName = if (crossBuildVersion.size == 1) artifactName + "_" + crossBuildVersion.head else artifactName
run('/' ~ str(reoccurArtifactName) ~ '-' ~ str(ver) ~ '.' ~ ext ~ EOI) ~ push(groupIds :: reoccurArtifactName :: crossBuildVersion :: ver :: HNil)
}
}
}
package com.gtan.parsers
import org.parboiled2._
import org.scalatest.{Matchers, FunSuite}
import shapeless.{HNil, ::, HList}
import scala.util.{Try, Success, Failure}
import shapeless._
class MavenUrlParserSuite extends FunSuite with Matchers {
def testParser(parser: Parser, result: Try[HList], expect: HList): Unit = {
println(result)
result match {
case Failure(error: ParseError) => println(parser.formatError(error))
case _ =>
}
result should matchPattern {
case Success(`expect`) =>
}
}
test("root") {
val candidates = Map[String, HList](
"/org/scala-lang/modules/scalajs/scalajs-sbt-plugin_2.10_0.13/0.5.6/scalajs-sbt-plugin-0.5.6.pom" ->
(Seq("org", "scala-lang", "modules", "scalajs") :: "scalajs-sbt-plugin" :: Seq("2.10", "0.13") :: "0.5.6" :: HNil),
"/io/spray/sbt-revolver_2.10_0.13/0.7.2/sbt-revolver-0.7.2.pom" ->
(Seq("io", "spray") :: "sbt-revolver" :: Seq("2.10", "0.13") :: "0.7.2" :: HNil),
"/com/eed3si9n/sbt-assembly_2.10_0.13/0.12.0/sbt-assembly-0.12.0.pom" ->
(Seq("com", "eed3si9n") :: "sbt-assembly" :: Seq("2.10", "0.13") :: "0.12.0" :: HNil),
"/org/scala-sbt/sbt/0.13.7/sbt-0.13.7.pom" ->
(Seq("org", "scala-sbt") :: "sbt" :: Seq() :: "0.13.7" :: HNil),
"/org/scala-sbt/main/0.13.7/main-0.13.7.pom" ->
(Seq("org", "scala-sbt") :: "main" :: Seq() :: "0.13.7" :: HNil),
"/org/scala-sbt/actions/0.13.7/actions-0.13.7.pom" ->
(Seq("org", "scala-sbt") :: "actions" :: Seq() :: "0.13.7" :: HNil),
"/net/virtual-void/sbt-dependency-graph/0.7.4/sbt-dependency-graph-0.7.4.jar" ->
(Seq("net", "virtual-void") :: "sbt-dependency-graph" :: Seq() :: "0.7.4" :: HNil),
"/com/github/mpeltonen/sbt-idea/1.6.0/sbt-idea-1.6.0.jar" ->
(Seq("com", "github", "mpeltonen") :: "sbt-idea" :: Seq() :: "1.6.0" :: HNil),
"/org/scala-lang/modules/scalajs/scalajs-tools_2.10/0.5.6/scalajs-tools_2.10-0.5.6.pom" ->
(Seq("org", "scala-lang", "modules", "scalajs") :: "scalajs-tools_2.10" :: Seq("2.10") :: "0.5.6" :: HNil)
)
for ((src, expect) <- candidates) {
val parser: MavenUrlParser = new MavenUrlParser(src)
val result = parser.root.run()
testParser(parser, result, expect = expect)
}
}
test("groupIdsAndArtifactName") {
val src = "/org/scala-lang/modules/scalajs/scalajs-tools_2.10"
val parser: MavenUrlParser = new MavenUrlParser(src)
val result = parser.groupIdsAndArtifactName.run()
testParser(parser, result, Seq("org", "scala-lang", "modules", "scalajs") :: "scalajs-tools" :: HNil)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment