class Utopia::Path::Matcher

Performs structured, efficient, matches against {Path} instances. Supports regular expressions, type-casts and constants. @example

path = Utopia::Path['users/20/edit']
matcher = Utopia::Path::Matcher[users: /users/, id: Integer, action: String]
match_data = matcher.match(path)

Public Class Methods

[](patterns) click to toggle source
# File lib/utopia/path/matcher.rb, line 60
def self.[](patterns)
        self.new(patterns)
end
new(patterns = []) click to toggle source

@param patterns [Hash<Symbol,Pattern>] An ordered list of things to match.

# File lib/utopia/path/matcher.rb, line 56
def initialize(patterns = [])
        @patterns = patterns
end

Public Instance Methods

coerce(klass, value) click to toggle source
# File lib/utopia/path/matcher.rb, line 64
def coerce(klass, value)
        if klass == Integer
                Integer(value)
        elsif klass == Float
                Float(value)
        elsif klass == String
                value.to_s
        else
                klass.new(value)
        end
rescue
        return nil
end
match(path) click to toggle source

This is a path prefix matching algorithm. The pattern is an array of String, Symbol, Regexp, or nil. The path is an array of String.

# File lib/utopia/path/matcher.rb, line 79
def match(path)
        components = path.to_a
        
        # Can't possibly match if not enough components:
        return nil if components.size < @patterns.size
        
        named_parts = {}
        
        # Try to match each component against the pattern:
        @patterns.each_with_index do |(key, pattern), index|
                component = components[index]
                
                if pattern.is_a? Class
                        return nil unless value = coerce(pattern, component)
                        
                        named_parts[key] = value
                elsif pattern
                        if result = pattern.match(component)
                                named_parts[key] = result
                        else
                                # Couldn't match:
                                return nil
                        end
                else
                        # Ignore this part:
                        named_parts[key] = component
                end
        end
        
        return MatchData.new(named_parts, components[@patterns.size..-1])
end