Class: Mustermann::Set
- Inherits:
-
Object
- Object
- Mustermann::Set
- Defined in:
- lib/mustermann/set.rb,
lib/mustermann/set/trie.rb,
lib/mustermann/set/cache.rb,
lib/mustermann/set/match.rb,
lib/mustermann/set/linear.rb
Overview
A collection of patterns that can be matched against strings efficiently.
Each pattern in the set may be associated with one or more arbitrary values, such as handler objects or route actions. A single #match call returns a Match that provides both the captured parameters and the associated value for the matched pattern. When the set contains many patterns, an internal trie (prefix tree) is used to dispatch requests in sub-linear time.
Defined Under Namespace
Classes: Match
Instance Attribute Summary collapse
-
#options ⇒ Hash
readonly
Pattern options forwarded to new when patterns are created from strings.
Instance Method Summary collapse
-
#[](pattern_or_string) ⇒ Object?
Looks up a value by string or retrieves the first value for a known pattern object.
-
#add(pattern, *values) ⇒ self
(also: #[]=)
Adds a pattern to the set, optionally associated with one or more values.
-
#expand(value = self, behavior = nil, values = nil) ⇒ String
Generates a string from a parameter hash using the patterns in the set.
-
#expander(value = self) ⇒ Mustermann::Expander
Returns an Expander that can generate strings from parameter hashes.
-
#has_value?(value) ⇒ Boolean
Whether the set contains any pattern associated with the given value.
-
#initialize(*mapping, additional_values: :raise, use_trie: 50, use_cache: true, **options, &block) ⇒ Set
constructor
Creates a new set, optionally pre-populated with patterns.
-
#match(string) ⇒ Set::Match?
Matches the string against all patterns in the set and returns the first match.
-
#match_all(string) ⇒ Array<Set::Match>
Matches the string against all patterns and returns every match, one per (pattern, value) pair, in insertion order.
-
#merge(mapping) ⇒ Set
Returns a new set that includes all patterns from the receiver plus those from
mapping. -
#patterns ⇒ Array<Pattern>
Returns all patterns that have been added to the set, in insertion order.
-
#peek_match(string) ⇒ Set::Match?
Matches the beginning of the string against all patterns and returns the first prefix match.
-
#peek_match_all(string) ⇒ Array<Set::Match>
Matches the beginning of the string against all patterns and returns every prefix match, one per (pattern, value) pair.
-
#update(mapping) ⇒ self
(also: #merge!)
Adds all patterns from
mappingto the set in place and returnsself.
Constructor Details
#initialize(*mapping, additional_values: :raise, use_trie: 50, use_cache: true, **options, &block) ⇒ Set
Creates a new set, optionally pre-populated with patterns.
Patterns can be supplied as a Hash (pattern → value), a plain String or Pattern, an Array of any of these, or an existing Mustermann::Set. The same forms are accepted by #update and #add.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/mustermann/set.rb', line 68 def initialize(*mapping, additional_values: :raise, use_trie: 50, use_cache: true, **, &block) raise ArgumentError, "Illegal value %p for additional_values" % additional_values unless Expander::ADDITIONAL_VALUES.include? additional_values raise ArgumentError, "Illegal value %p for use_trie" % use_trie unless [true, false].include?(use_trie) or use_trie.is_a? Integer @use_trie = use_trie @use_cache = use_cache @matcher = nil @mapping = {} @reverse_mapping = {} @options = {} @expanders = {} @additional_values = additional_values .each do |key, value| if key.is_a? Symbol @options[key] = value else mapping << { key => value } end end update(mapping) block.arity == 0 ? update(yield) : yield(self) if block end |
Instance Attribute Details
#options ⇒ Hash (readonly)
Pattern options forwarded to Mustermann.new when patterns are created from strings.
41 42 43 |
# File 'lib/mustermann/set.rb', line 41 def @options end |
Instance Method Details
#[](pattern_or_string) ⇒ Object?
Looks up a value by string or retrieves the first value for a known pattern object.
When given a String, it is matched against the set and the associated value of the first matching pattern is returned. When given a Pattern, the first value registered for that exact pattern is returned without matching.
157 158 159 160 161 162 163 |
# File 'lib/mustermann/set.rb', line 157 def [](pattern_or_string) case pattern_or_string when String then match(pattern_or_string)&.value when Pattern then values_for_pattern(pattern_or_string)&.first else raise ArgumentError, "unsupported pattern type #{pattern_or_string.class}" end end |
#add(pattern, *values) ⇒ self Also known as: []=
Adds a pattern to the set, optionally associated with one or more values.
If the pattern is given as a String it will be compiled via Mustermann.new using the set’s own options. The pattern must be AST-based (Sinatra, Rails, and similar types). Plain regexp patterns are not supported.
Calling add more than once for the same pattern appends additional values without creating duplicates.
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/mustermann/set.rb', line 111 def add(pattern, *values) pattern = Mustermann.new(pattern, **) raise ArgumentError, "Non-AST patterns are not supported" unless pattern.respond_to? :to_ast if @mapping.key? pattern current = @mapping[pattern] else add_pattern(pattern) current = @mapping[pattern] = [] end values = [nil] if values.empty? values.each do |value| raise ArgumentError, "%p may not be used as a value" % value if Expander::ADDITIONAL_VALUES.include? value raise ArgumentError, "the set itself may not be used as value" if value == self next if current.include? value current << value @reverse_mapping[value] ||= [] @reverse_mapping[value] << pattern unless @reverse_mapping[value].include? pattern @expanders[value]&.add(pattern) end self end |
#expand(value = self, behavior = nil, values = nil) ⇒ String
Generates a string from a parameter hash using the patterns in the set.
When called with just a parameter hash, the first pattern that can be fully expanded with those keys is used. Pass a value as the first argument to restrict expansion to the patterns associated with that value. You may also pass an additional_values behavior symbol (:raise, :ignore, or :append) as the first argument to override the set’s default behavior for that call.
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
# File 'lib/mustermann/set.rb', line 280 def (value = self, behavior = nil, values = nil) if Expander::ADDITIONAL_VALUES.include? value if behavior.is_a? Hash values = values ? values.merge(behavior) : behavior behavior = nil elsif behavior and behavior != value raise ArgumentError, "behavior specified multiple times" if behavior end behavior = value value = self elsif value.is_a? Hash and behavior.nil? and values.nil? values = value value = self unless @reverse_mapping.key? values end (value).(behavior || @additional_values, values || {}) end |
#expander(value = self) ⇒ Mustermann::Expander
Returns an Expander that can generate strings from parameter hashes.
When called without arguments (or with the set itself as the value) the expander covers all patterns in the set. Pass a specific value to get an expander limited to the patterns associated with that value.
247 248 249 250 251 252 |
# File 'lib/mustermann/set.rb', line 247 def (value = self) @expanders[value] ||= begin patterns = value == self ? @mapping.keys : @reverse_mapping[value] || [] Mustermann::Expander.new(patterns, additional_values: @additional_values, **) end end |
#has_value?(value) ⇒ Boolean
Returns whether the set contains any pattern associated with the given value.
298 |
# File 'lib/mustermann/set.rb', line 298 def has_value?(value) = @reverse_mapping[value]&.any? |
#match(string) ⇒ Set::Match?
Matches the string against all patterns in the set and returns the first match.
169 |
# File 'lib/mustermann/set.rb', line 169 def match(string) = @matcher&.match(string) |
#match_all(string) ⇒ Array<Set::Match>
Matches the string against all patterns and returns every match, one per (pattern, value) pair, in insertion order.
184 |
# File 'lib/mustermann/set.rb', line 184 def match_all(string) = @matcher&.match(string, all: true) |
#merge(mapping) ⇒ Set
Returns a new set that includes all patterns from the receiver plus those from mapping. The receiver is not modified.
199 |
# File 'lib/mustermann/set.rb', line 199 def merge(mapping) = dup.update(mapping) |
#patterns ⇒ Array<Pattern>
Returns all patterns that have been added to the set, in insertion order.
236 |
# File 'lib/mustermann/set.rb', line 236 def patterns = @mapping.keys |
#peek_match(string) ⇒ Set::Match?
Matches the beginning of the string against all patterns and returns the first prefix match. The unmatched remainder of the string is available via Match#post_match.
177 |
# File 'lib/mustermann/set.rb', line 177 def peek_match(string) = @matcher&.match(string, peek: true) |
#peek_match_all(string) ⇒ Array<Set::Match>
Matches the beginning of the string against all patterns and returns every prefix match, one per (pattern, value) pair. The unmatched remainder is available as Match#post_match on each result.
192 |
# File 'lib/mustermann/set.rb', line 192 def peek_match_all(string) = @matcher&.match(string, all: true, peek: true) |
#update(mapping) ⇒ self Also known as: merge!
Adds all patterns from mapping to the set in place and returns self. Aliased as merge!.
Accepts the same argument forms as #initialize: a Hash, a String, a Pattern, an Array, or another Mustermann::Set.
221 222 223 224 225 226 227 228 229 230 |
# File 'lib/mustermann/set.rb', line 221 def update(mapping) case mapping when Set then mapping.mapping.each { |pattern, values| add(pattern, *values) } when Hash then mapping.each { |k, v| add(k, v) } when String, Pattern then add(mapping) when Array then mapping.each { |item| update(item) } else raise ArgumentError, "unsupported mapping type #{mapping.class}" end self end |