class PathParserService def initialize(template, path) @template = template @path = path end def call components = @path.match(path_parse_pattern)&.named_captures&.symbolize_keys return {} if components.nil? components.merge({ tags: components[:tags]&.split("/")&.compact_blank, model_id: nil # discard ID, never gonna use it in parsing }).compact end private def path_parse_pattern Regexp.new("^/?.*?" + @template.gsub(/{.+?}/) { |token| case token when "{tags}" "(?[[:print:]]*)" when "{creator}" "(?[[:print:]&&[^/]]*?)" when "{collection}" "(?[[:print:]&&[^/]]*?)" when "{modelName}" "(?[[:print:]&&[^/]]*?)" when "{modelId}" "(?#[[:digit:]]+)?" else "[[:print:]&&[^/]]*" end } + "$") end end