From df2ad7c83b8cc1ef00e1e0fc446121879057d77d Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 8 Jul 2014 15:19:20 +0200 Subject: add support for custom ranges --- src/main/scala/spray/boilerplate/Generator.scala | 8 ++++---- .../scala/spray/boilerplate/TemplateParser.scala | 21 +++++++++++++++++---- .../scala/spray/boilerplate/GeneratorSpecs.scala | 12 ++++++++++++ .../spray/boilerplate/TemplateParserSpecs.scala | 3 +++ 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/main/scala/spray/boilerplate/Generator.scala b/src/main/scala/spray/boilerplate/Generator.scala index b115002..5576f56 100644 --- a/src/main/scala/spray/boilerplate/Generator.scala +++ b/src/main/scala/spray/boilerplate/Generator.scala @@ -13,9 +13,9 @@ object Generator { generate(TemplateParser.parse(template))(expandTo) def generate(format: TemplateElement)(idx: Int): String = format match { - case Sequence(els @ _*) ⇒ els.map(e ⇒ generate(e)(idx)).mkString - case Expand(inner, sep) ⇒ (1 to idx).map(generate(inner)).mkString(sep) - case Offset(i) ⇒ (idx + i - 1).toString - case LiteralString(lit) ⇒ lit + case Sequence(els @ _*) ⇒ els.map(e ⇒ generate(e)(idx)).mkString + case Expand(inner, sep, range) ⇒ (range.start.getOrElse(1) to range.end.getOrElse(idx)).map(generate(inner)).mkString(sep) + case Offset(i) ⇒ (idx + i - 1).toString + case LiteralString(lit) ⇒ lit } } diff --git a/src/main/scala/spray/boilerplate/TemplateParser.scala b/src/main/scala/spray/boilerplate/TemplateParser.scala index 6d8e22d..8808bc8 100644 --- a/src/main/scala/spray/boilerplate/TemplateParser.scala +++ b/src/main/scala/spray/boilerplate/TemplateParser.scala @@ -19,8 +19,14 @@ case class Sequence(elements: TemplateElement*) extends TemplateElement { case class LiteralString(literal: String) extends TemplateElement /* An offset to be replaced by the current index */ case class Offset(i: Int) extends TemplateElement + +case class Range(start: Option[Int] = None, end: Option[Int] = None) + /** A region in which to apply expansions */ -case class Expand(inner: TemplateElement, separator: String = Expand.defaultSeparator) extends TemplateElement +case class Expand( + inner: TemplateElement, + separator: String = Expand.defaultSeparator, + range: Range = Range(None, None)) extends TemplateElement object Expand { val defaultSeparator = ", " } @@ -36,7 +42,7 @@ object TemplateParser extends RegexParsers { def offset: Parser[Offset] = offsetChars ^^ (s ⇒ Offset(s.toInt)) def literalString: Parser[LiteralString] = rep1(escapedLiteralNumber | literalChar) ^^ (chs ⇒ LiteralString(chs.mkString)) def literalChar: Parser[Char] = - not("[#" | """#[^\]]*\]""".r | offsetChars) ~> elem("Any character", _ ⇒ true) + not(expandStart | """#[^\]]*\]""".r | offsetChars) ~> elem("Any character", _ ⇒ true) def offsetChars = "[012]".r @@ -44,9 +50,16 @@ object TemplateParser extends RegexParsers { def outsideTemplate: Parser[LiteralString] = """(?s).+?(?=(\[#)|(\z))""".r ^^ (LiteralString(_)) - def expand: Parser[Expand] = "[#" ~> elements ~ "#" ~ separatorChars <~ "]" ^^ { - case els ~ x ~ sep ⇒ Expand(els, sep.getOrElse(Expand.defaultSeparator)) + def expand: Parser[Expand] = expandStart ~ elements ~ "#" ~ separatorChars <~ "]" ^^ { + case range ~ els ~ x ~ sep ⇒ Expand(els, sep.getOrElse(Expand.defaultSeparator), range) } + def expandStart: Parser[Range] = "[" ~> range <~ "#" + + def range: Parser[Range] = + (opt("""\d{1,2}""".r) ~ """\s*\.\.\s*""".r ~ opt("""\d{1,2}""".r) ^^ { + case start ~ sep ~ end ⇒ Range(start.map(_.toInt), end.map(_.toInt)) + }) | success(Range()) + def outsideElements: Parser[TemplateElement] = rep1(expand | outsideTemplate) ^^ maybeSequence diff --git a/src/test/scala/spray/boilerplate/GeneratorSpecs.scala b/src/test/scala/spray/boilerplate/GeneratorSpecs.scala index d88010b..d1f6af8 100644 --- a/src/test/scala/spray/boilerplate/GeneratorSpecs.scala +++ b/src/test/scala/spray/boilerplate/GeneratorSpecs.scala @@ -28,6 +28,18 @@ class GeneratorSpecs extends Specification { "support custom separator" in { gen4("[#a1#.]") === "a1.a2.a3.a4" } + "support custom range start" in { + gen4("[2..#a1#.]") === "a2.a3.a4" + } + "support custom range end" in { + gen4("[..6#a1#.]") === "a1.a2.a3.a4.a5.a6" + } + "support custom range" in { + gen4("[5..10#a1#.]") === "a5.a6.a7.a8.a9.a10" + } + "support inner custom range" in { + gen4("[#a1([2..#T1#])#]") === "a1(), a2(T2), a3(T2, T3), a4(T2, T3, T4)" + } } def gen4(template: String): String = Generator.generateFromTemplate(template, 4) diff --git a/src/test/scala/spray/boilerplate/TemplateParserSpecs.scala b/src/test/scala/spray/boilerplate/TemplateParserSpecs.scala index 85b99af..fbf6ee2 100644 --- a/src/test/scala/spray/boilerplate/TemplateParserSpecs.scala +++ b/src/test/scala/spray/boilerplate/TemplateParserSpecs.scala @@ -25,5 +25,8 @@ class TemplateParserSpecs extends Specification { "a quoted number" in { parse("[#T##1#]") === Expand(LiteralString("T1")) } + "custom range" in { + parse("[0..11#T1#]") === Expand(LiteralString("T") ~ Offset(1), range = Range(start = Some(0), end = Some(11))) + } } } -- cgit v1.2.3