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.



56
57
58
# File 'lib/utopia/path/matcher.rb', line 56

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

Class Method Details

.[](patterns) ⇒ Object



60
61
62
# File 'lib/utopia/path/matcher.rb', line 60

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

Instance Method Details

#coerce(klass, value) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
# 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) ⇒ 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.



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
108
109
# 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