Class: Utopia::Path::Matcher

Inherits:
Object
  • Object
show all
Defined in:
lib/utopia/path/matcher.rb

Overview

Performs structured, efficient, matches against Utopia::Path instances. Supports regular expressions, type-casts and constants.

Examples:

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

Defined Under Namespace

Classes: MatchData

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(patterns = []) ⇒ Matcher

Returns a new instance of Matcher.

Parameters:

  • patterns (Hash<Symbol,Pattern>) (defaults to: [])

    An ordered list of things to match.



54
55
56
# File 'lib/utopia/path/matcher.rb', line 54

def initialize(patterns = [])
  @patterns = patterns
end

Class Method Details

.[](patterns) ⇒ Object



58
59
60
# File 'lib/utopia/path/matcher.rb', line 58

def self.[](patterns)
  self.new(patterns)
end

Instance Method Details

#coerce(klass, value) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/utopia/path/matcher.rb', line 62

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) ⇒ Object

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.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/utopia/path/matcher.rb', line 77

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