Skip to content

Instantly share code, notes, and snippets.

@exts
Created January 7, 2017 04:06
Show Gist options
  • Save exts/a6a7f7a8b006a3a0d6ebac3fb8acdbe5 to your computer and use it in GitHub Desktop.
Save exts/a6a7f7a8b006a3a0d6ebac3fb8acdbe5 to your computer and use it in GitHub Desktop.
Crystal Lang: Screwing around, trying to figure out a simple way to parse a route w/ named parameters (and optional ones)
#idiotcoder.com
#eatcodegame.com
class RouteParser
@default_regex_replacement = "w+"
getter regex_variables = {} of String => String
getter default_variables = {} of String => String
getter matched_variables = [] of String
def initialize(@route = "")
extract_variables()
end
def regex(key : String, val : String)
if @matched_variables.includes?(key)
@regex_variables[key] = val
end
self
end
def default(key : String, val : String)
if @matched_variables.includes?(key)
@default_variables[key] = val
end
self
end
private def extract_variables
# reset array so we can't call this multiple times
@matched_variables = [] of String
# start the process
extract_variables(@route)
end
private def extract_variables(find : String)
if found = find.match /(?:\:([A-Za-z]+))/
if !found[1]?.nil?
@matched_variables << found[1] if !@matched_variables.includes?(found[1])
if !found.not_nil!.post_match.empty?
extract_variables(found.post_match)
end
end
end
end
def parse
# replace [] with (?:)? optional groups
route = @route.gsub("[", "(?:")
route = route.gsub("]", ")?")
route = route.gsub("/", "\\/")
@matched_variables.each do |mv|
rex = @regex_variables.fetch(mv, "\\" + @default_regex_replacement)
route = route.sub(":" + mv, "(?<" + mv + ">" + rex + ")")
end
route
end
end
str = "/post/:id[/:slug[/:other]]"
parser = RouteParser.new str
parser
.default("id", "1")
.default("slug", "")
.default("other", "")
.regex("id", %(\\d+))
.regex("other", %([A-Za-z]+\\-\\d+))
route = "/post/10/custm_slug/page-10"
if found = route.match /^#{parser.parse}$/
puts found.not_nil!["id"]? # => 10
puts found.not_nil!["slug"]? # => custom_slug
puts found.not_nil!["other"]? # => page-10
end
puts parser.matched_variables # => ["id", "slug", "other"]
puts parser.default_variables # => {"id" => "1", "slug" => "", "other" => ""}
puts parser.regex_variables # => {"id" => "\\d+", "other" => "[A-Za-z]+\\-\\d+"}
puts parser.parse # => \/post\/(?<id>\d+)(?:\/(?<slug>\w+)(?:\/(?<other>[A-Za-z]+\-\d+))?)?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment