<commit_before>package org.scalatra

import scala.util.matching.Regex
import util.MultiMap

trait RouteMatcher {

  def apply(): Option[ScalatraKernel.MultiParams]
}

trait ReversibleRouteMatcher {

  def reverse(params: Map[String, String], splats: List[String]): String
}

final class SinatraRouteMatcher(path: String, requestPath: => String)
  extends RouteMatcher with ReversibleRouteMatcher {

  def apply() = SinatraPathPatternParser(path)(requestPath)

  def reverse(params: Map[String, String], splats: List[String]): String =
    replaceSplats(
      replaceNamedParams(
        replaceOptionalParams(path, params),
        params
      ), splats)

  private def replaceOptionalParams(slug: String, params: Map[String, String]): String =
    """[\./]\?:[^/?#\.]+\?""".r replaceAllIn (path, s =>
      params.get(s.matched slice (3, s.matched.size - 1)) match {
        case Some(value) => s.matched.head + value
        case None => ""
      })

  private def replaceNamedParams(slug: String, params: Map[String, String]): String =
    """:[^/?#\.]+""".r replaceAllIn (slug, s => {
      val param = s.matched.tail
      params.get(param) match {
        case Some(value) => value
        case None => throw new Exception(
          "The url \"%s\" requires param \"%s\"" format (path, param))
    }})

  private def replaceSplats(slug: String, splats: List[String]): String =
    splats match {
      case Nil => slug
      case s :: rest => replaceSplats("""\*""".r replaceFirstIn (slug, s), rest)
    }

  override def toString = path
}

final class RailsRouteMatcher(path: String, requestPath: => String)
  extends RouteMatcher with ReversibleRouteMatcher {<commit_msg>Improve sinatra-like reverse routing implementation<commit_after>package org.scalatra

import scala.util.matching.Regex
import util.MultiMap

trait RouteMatcher {

  def apply(): Option[ScalatraKernel.MultiParams]
}

trait ReversibleRouteMatcher {

  def reverse(params: Map[String, String], splats: List[String]): String
}

final class SinatraRouteMatcher(path: String, requestPath: => String)
  extends RouteMatcher with ReversibleRouteMatcher {

  def apply() = SinatraPathPatternParser(path)(requestPath)

  def reverse(params: Map[String, String], splats: List[String]): String =
    replaceSplats(
      replaceNamedParams(
        replaceOptionalParams(path, params),
        params
      ), splats)

  private def replaceOptionalParams(slug: String, params: Map[String, String]): String =
    """([\./])\?:([^/?#\.]+)\?""".r replaceAllIn (slug, m => params.get(m.group(2)) match {
      case Some(value) => m.group(1) + value
      case None => ""
    })

  private def replaceNamedParams(slug: String, params: Map[String, String]): String =
    """:([^/?#\.]+)""".r replaceAllIn (slug, m => params.get(m.group(1)) match {
      case Some(value) => value
      case None => throw new Exception(
        "The url \"%s\" requires param \"%s\"" format (path, m.group(1)))
    })

  private def replaceSplats(slug: String, splats: List[String]): String =
    splats match {
      case Nil => slug
      case s :: rest => replaceSplats("""\*""".r replaceFirstIn (slug, s), rest)
    }

  override def toString = path
}

final class RailsRouteMatcher(path: String, requestPath: => String)
  extends RouteMatcher with ReversibleRouteMatcher {
{'fraction_non_alphanumeric': 0.14345864661654134, 'fraction_numerical': 0.0018045112781954887, 'mean_word_length': 3.7244318181818183, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6434024', 'n_tokens_mistral': 1026, 'n_tokens_neox': 988, 'n_words': 273}