ruby-on-railsrubyjourney

Rails style routing string parsing using Journey only


Given this mapping definition: /order/:meal/:cheese

Parse this string /order/hamburger/american into {meal:'hamburger', cheese:'american'}.

I was playing around with Journey's internals trying to figure out if this is possible outside of rails. There are other SO questions that show how it's possible within Rails using recognize_path. And I know you could easily accomplish this with a regex or split but I'd like the extra parsing features for free (like :format etc).

Here's something that works. Just wondering if anyone has improvments. I'm basically zipping/combining up two parts of the Journey matches (names and captures) to make a match hash (like what recognize_path). Just wondering if anyone has reached into Journey and tried to do the same thing.

require 'journey'

def hashify_match matches
  h = {}
  matches.names.each_with_index do |key, i|
    h[key.to_sym] = matches.captures[i]
  end
  h
end

pattern = Journey::Path::Pattern.new '/order/(:meal(/:cheese))'
matches = pattern.match '/order/hamburger/american'

puts hashify_match matches

matches = pattern.match '/order/hotdog/cheddar'
puts hashify_match matches

Here's what prints out.

{:meal=>"hamburger", :cheese=>"american"}
{:meal=>"hotdog", :cheese=>"cheddar"}

Is there another part of Journey that I might use to build the match hash? See, matches.names and matches.captures really are Array objects and this feels like a hack. Certainly some part of Rails puts these together at some point.

Notice that only the Journey gem (included in Rails 3.2.0+) is used.


Solution

  • Journey::Router does it here:

        match_data  = r.path.match(req.path_info)
        match_names = match_data.names.map { |n| n.to_sym }
        match_values = match_data.captures.map { |v| v && Utils.unescape_uri(v) }
        info = Hash[match_names.zip(match_values).find_all { |_,y| y }]
    

    So it doesn't look as though there is a convenient way to do what you're trying to do.