mustermann 3.1.1 → 4.0.0.alpha2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +1 -2
- data/README.md +95 -370
- data/lib/mustermann/ast/compiler.rb +124 -29
- data/lib/mustermann/ast/pattern.rb +10 -0
- data/lib/mustermann/ast/translator.rb +7 -2
- data/lib/mustermann/concat.rb +9 -3
- data/lib/mustermann/error.rb +1 -0
- data/lib/mustermann/expander.rb +8 -3
- data/lib/mustermann/hybrid.rb +50 -0
- data/lib/mustermann/match.rb +39 -0
- data/lib/mustermann/pattern.rb +8 -31
- data/lib/mustermann/rails.rb +1 -1
- data/lib/mustermann/regexp_based.rb +22 -7
- data/lib/mustermann/router.rb +99 -0
- data/lib/mustermann/set/cache.rb +30 -0
- data/lib/mustermann/set/linear.rb +30 -0
- data/lib/mustermann/set/match.rb +16 -0
- data/lib/mustermann/set/trie.rb +173 -0
- data/lib/mustermann/set.rb +327 -0
- data/lib/mustermann/version.rb +1 -1
- data/lib/mustermann.rb +0 -6
- metadata +24 -9
- data/lib/mustermann/extension.rb +0 -3
- data/lib/mustermann/mapper.rb +0 -91
- data/lib/mustermann/pattern_cache.rb +0 -50
- data/lib/mustermann/simple_match.rb +0 -49
- data/lib/mustermann/to_pattern.rb +0 -51
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2aedc31385aca5281460e4f6febcbb1324893268be9b618145de232753872094
|
|
4
|
+
data.tar.gz: 3e33a069dcae0e6585070403c57b294f5c8f00ccc59e44fb8267e2c2ab3b886a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6d59d5e758aacedb994f6c9dce3c0215a626d8b0603535a01ab88b998f2f1666522d2eb94f4471fd785d56a3501b0c54c190f2ba594bbd759df5544bd72a9dfb
|
|
7
|
+
data.tar.gz: fc17a19691e4cdf94466402258f9467a48def4722dddaf3a01eca8170f70ad3d5ddfe51bf5a03ce7a973756ef43be4b787ae63aa18066762f864bd88d473541c
|
data/LICENSE
CHANGED
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The Amazing Mustermann
|
|
2
2
|
|
|
3
|
-
*Make sure you view the correct docs: [latest release](
|
|
3
|
+
*Make sure you view the correct docs: [latest release](https://rubydoc.info/gems/mustermann/), [master](http://rubydoc.info/github/sinatra/mustermann).*
|
|
4
4
|
|
|
5
5
|
Welcome to [Mustermann](http://en.wikipedia.org/wiki/List_of_placeholder_names_by_language#German). Mustermann is your personal string matching expert. As an expert in the field of strings and patterns, Mustermann keeps its runtime dependencies to a minimum and is fully covered with specs and documentation.
|
|
6
6
|
|
|
@@ -41,8 +41,8 @@ pattern.params('/a/b.c') # => { "prefix" => "a", splat => ["b", "c"] }
|
|
|
41
41
|
|
|
42
42
|
These features are included in the library, but not loaded by default
|
|
43
43
|
|
|
44
|
-
* **[
|
|
45
|
-
* **
|
|
44
|
+
* **[Pattern Set](#-pattern-set):** A collection of patterns with associated values, designed for building routing tables that dispatch efficiently as the number of routes grows.
|
|
45
|
+
* **Mustermann::Router:** A very basic rack router built on top of `Mustermann::Set` for demonstration purposes. Simple and fast.
|
|
46
46
|
|
|
47
47
|
<a name="-pattern-types"></a>
|
|
48
48
|
## Pattern Types
|
|
@@ -56,7 +56,7 @@ require 'mustermann'
|
|
|
56
56
|
pattern = Mustermann.new('/*/**', type: :shell)
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
Note that this will use the type as suggestion: When passing in a string argument, it will create a pattern of the given type, but it might choose a different type for other objects (a regular expression argument will always result in a [regexp](
|
|
59
|
+
Note that this will use the type as suggestion: When passing in a string argument, it will create a pattern of the given type, but it might choose a different type for other objects (a regular expression argument will always result in a [regexp](../docs/patterns/regexp.md) pattern, a symbol always in a [sinatra](../docs/patterns/sinatra.md) pattern, etc).
|
|
60
60
|
|
|
61
61
|
Alternatively, you can also load and instantiate the pattern type directly:
|
|
62
62
|
|
|
@@ -65,7 +65,7 @@ require 'mustermann/shell'
|
|
|
65
65
|
pattern = Mustermann::Shell.new('/*/**')
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
Mustermann itself includes the [sinatra](
|
|
68
|
+
Mustermann itself includes the [sinatra](../docs/patterns/sinatra.md), [identity](../docs/patterns/identity.md) and [regexp](../docs/patterns/regexp.md) pattern types. Other pattern types are available as separate gems.
|
|
69
69
|
|
|
70
70
|
<a name="-binary-operators"></a>
|
|
71
71
|
## Binary Operators
|
|
@@ -123,16 +123,12 @@ pattern.match('/') # => nil
|
|
|
123
123
|
pattern.match('/home') # => #<MatchData "/home" page:"home">
|
|
124
124
|
pattern =~ '/home' # => 0
|
|
125
125
|
pattern === '/home' # => true (this allows using it in case statements)
|
|
126
|
-
pattern.names # => ['page']
|
|
127
|
-
pattern.names # => {"page"=>[1]}
|
|
128
126
|
|
|
129
127
|
pattern = Mustermann.new('/home', type: :identity)
|
|
130
128
|
pattern.match('/') # => nil
|
|
131
|
-
pattern.match('/home') # => #<Mustermann::
|
|
129
|
+
pattern.match('/home') # => #<Mustermann::Match ...>
|
|
132
130
|
pattern =~ '/home' # => 0
|
|
133
131
|
pattern === '/home' # => true (this allows using it in case statements)
|
|
134
|
-
pattern.names # => []
|
|
135
|
-
pattern.names # => {}
|
|
136
132
|
```
|
|
137
133
|
|
|
138
134
|
Moreover, patterns based on regular expressions (all but `identity` and `shell`) automatically convert to regular expressions when needed:
|
|
@@ -179,7 +175,7 @@ Peeking gives the option to match a pattern against the beginning of a string ra
|
|
|
179
175
|
|
|
180
176
|
* `peek` returns the matching substring.
|
|
181
177
|
* `peek_size` returns the number of characters matching.
|
|
182
|
-
* `peek_match` will return a `
|
|
178
|
+
* `peek_match` will return a `Mustermann::Match` (just like `match` does for the full string)
|
|
183
179
|
* `peek_params` will return the `params` hash parsed from the substring and the number of characters.
|
|
184
180
|
|
|
185
181
|
All of the above will turn `nil` if there was no match.
|
|
@@ -359,119 +355,118 @@ pattern = Mustermann.new(":name@:domain.:tld")
|
|
|
359
355
|
email = list.detect(&pattern) # => "example@email.com"
|
|
360
356
|
```
|
|
361
357
|
|
|
362
|
-
<a name="-
|
|
363
|
-
##
|
|
358
|
+
<a name="-pattern-set"></a>
|
|
359
|
+
## Pattern Set
|
|
364
360
|
|
|
365
|
-
|
|
366
|
-
You can use a mapper to transform strings according to two or more mappings:
|
|
361
|
+
`Mustermann::Set` is a collection of patterns where each pattern is associated with an arbitrary value — typically a handler or action. A single call to `match` returns both the captured parameters and the value for the first matching pattern, making it straightforward to build a routing table.
|
|
367
362
|
|
|
368
363
|
``` ruby
|
|
369
|
-
require 'mustermann/
|
|
370
|
-
|
|
371
|
-
mapper = Mustermann::Mapper.new("/:page(.:format)?" => ["/:page/view.:format", "/:page/view.html"])
|
|
372
|
-
mapper['/foo'] # => "/foo/view.html"
|
|
373
|
-
mapper['/foo.xml'] # => "/foo/view.xml"
|
|
374
|
-
mapper['/foo/bar'] # => "/foo/bar"
|
|
375
|
-
```
|
|
364
|
+
require 'mustermann/set'
|
|
376
365
|
|
|
377
|
-
|
|
378
|
-
|
|
366
|
+
set = Mustermann::Set.new
|
|
367
|
+
set.add('/users/:id', :users_show)
|
|
368
|
+
set.add('/posts/:id', :posts_show)
|
|
369
|
+
set.add('/posts', :posts_index)
|
|
379
370
|
|
|
380
|
-
|
|
371
|
+
m = set.match('/users/42')
|
|
372
|
+
m.value # => :users_show
|
|
373
|
+
m.params['id'] # => '42'
|
|
381
374
|
|
|
382
|
-
|
|
375
|
+
set.match('/unknown') # => nil
|
|
376
|
+
```
|
|
383
377
|
|
|
384
|
-
You can
|
|
378
|
+
You can supply the initial mapping directly to the constructor:
|
|
385
379
|
|
|
386
380
|
``` ruby
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
set :pattern, type: :shell
|
|
381
|
+
set = Mustermann::Set.new(
|
|
382
|
+
'/users/:id' => :users_show,
|
|
383
|
+
'/posts/:id' => :posts_show
|
|
384
|
+
)
|
|
385
|
+
```
|
|
393
386
|
|
|
394
|
-
|
|
395
|
-
send_file request.path_info
|
|
396
|
-
end
|
|
387
|
+
Or use a block for imperative setup:
|
|
397
388
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
389
|
+
``` ruby
|
|
390
|
+
set = Mustermann::Set.new do |s|
|
|
391
|
+
s.add('/users/:id', :users_show)
|
|
392
|
+
s.add('/posts/:id', :posts_show)
|
|
401
393
|
end
|
|
402
394
|
```
|
|
403
395
|
|
|
404
|
-
|
|
396
|
+
Pattern options such as `type:` are passed as keyword arguments and apply to all patterns in the set:
|
|
405
397
|
|
|
406
398
|
``` ruby
|
|
407
|
-
|
|
408
|
-
|
|
399
|
+
set = Mustermann::Set.new(type: :rails)
|
|
400
|
+
set.add('/:controller(/:action(/:id))', :route)
|
|
401
|
+
```
|
|
409
402
|
|
|
410
|
-
|
|
411
|
-
set :pattern, capture: { ext: %w[png jpg html txt] }
|
|
403
|
+
### Values
|
|
412
404
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
405
|
+
Each pattern can be associated with multiple values. `match` returns the first, while `match_all` returns one match per value:
|
|
406
|
+
|
|
407
|
+
``` ruby
|
|
408
|
+
set = Mustermann::Set.new
|
|
409
|
+
set.add('/users/:id', :admin_handler, :user_handler)
|
|
410
|
+
|
|
411
|
+
set.match('/users/1').value # => :admin_handler
|
|
412
|
+
set.match_all('/users/1').map(&:value) # => [:admin_handler, :user_handler]
|
|
419
413
|
```
|
|
420
414
|
|
|
421
|
-
|
|
415
|
+
When no value is given, a match still succeeds but `value` is `nil`:
|
|
422
416
|
|
|
423
417
|
``` ruby
|
|
424
|
-
|
|
425
|
-
|
|
418
|
+
set = Mustermann::Set.new
|
|
419
|
+
set.add('/ping')
|
|
420
|
+
set.match('/ping').value # => nil
|
|
421
|
+
```
|
|
426
422
|
|
|
427
|
-
|
|
423
|
+
### Conflict Resolution
|
|
428
424
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
425
|
+
The set follows insertion order: when two patterns both match a string, the one added first wins. Use `match_all` to retrieve every match:
|
|
426
|
+
|
|
427
|
+
``` ruby
|
|
428
|
+
set = Mustermann::Set.new
|
|
429
|
+
set.add('/foo', :static)
|
|
430
|
+
set.add('/:var', :dynamic)
|
|
431
|
+
|
|
432
|
+
set.match('/foo').value # => :static
|
|
433
|
+
set.match_all('/foo').map(&:value) # => [:static, :dynamic]
|
|
435
434
|
```
|
|
436
435
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
436
|
+
### Peeking
|
|
437
|
+
|
|
438
|
+
`peek_match` matches a prefix of the input rather than the full string. The unmatched remainder is available via `post_match`:
|
|
440
439
|
|
|
441
440
|
``` ruby
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
require 'mustermann'
|
|
441
|
+
set = Mustermann::Set.new
|
|
442
|
+
set.add('/users/:id', :users)
|
|
445
443
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
444
|
+
m = set.peek_match('/users/42/posts')
|
|
445
|
+
m.to_s # => '/users/42'
|
|
446
|
+
m.post_match # => '/posts'
|
|
447
|
+
m.value # => :users
|
|
448
|
+
```
|
|
449
449
|
|
|
450
|
-
|
|
451
|
-
before '*:ext', capture: Rack::Mime::MIME_TYPES.keys do
|
|
452
|
-
content_type params[:ext] # set Content-Type
|
|
453
|
-
request.path_info = params[:splat].first # drop the extension
|
|
454
|
-
end
|
|
450
|
+
`peek_match_all` returns every pattern that matches a prefix:
|
|
455
451
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
end
|
|
452
|
+
``` ruby
|
|
453
|
+
results = set.peek_match_all('/users/42/posts')
|
|
454
|
+
results.map(&:value) # => [:users]
|
|
455
|
+
results.map(&:post_match) # => ['/posts']
|
|
461
456
|
```
|
|
462
457
|
|
|
463
|
-
###
|
|
458
|
+
### Expanding
|
|
464
459
|
|
|
465
|
-
|
|
466
|
-
* Allows you to use different pattern styles in your app
|
|
467
|
-
* The default is more robust and powerful than the built-in patterns
|
|
468
|
-
* Sinatra 2.0 will use Mustermann internally
|
|
469
|
-
* Better exceptions for broken route syntax
|
|
460
|
+
A set can generate strings from parameter hashes using the same interface as individual pattern expansion:
|
|
470
461
|
|
|
471
|
-
|
|
462
|
+
``` ruby
|
|
463
|
+
set = Mustermann::Set.new
|
|
464
|
+
set.add('/users/:id', :users)
|
|
465
|
+
set.add('/posts/:id', :posts)
|
|
472
466
|
|
|
473
|
-
|
|
474
|
-
|
|
467
|
+
set.expand(id: '5') # => '/users/5' (first applicable pattern)
|
|
468
|
+
set.expand(:posts, id: '5') # => '/posts/5' (patterns for a specific value)
|
|
469
|
+
```
|
|
475
470
|
|
|
476
471
|
<a name="-duck-typing"></a>
|
|
477
472
|
## Duck Typing
|
|
@@ -494,33 +489,6 @@ object = MyObject.new
|
|
|
494
489
|
Mustermann.new(object, type: :rails) # => #<Mustermann::Rails:"/foo">
|
|
495
490
|
```
|
|
496
491
|
|
|
497
|
-
It might also be that you want to call `to_pattern` yourself instead of `Mustermann.new`. You can load `mustermann/to_pattern` to implement this method for strings, regular expressions and pattern objects:
|
|
498
|
-
|
|
499
|
-
``` ruby
|
|
500
|
-
require 'mustermann/to_pattern'
|
|
501
|
-
|
|
502
|
-
"/foo".to_pattern # => #<Mustermann::Sinatra:"/foo">
|
|
503
|
-
"/foo".to_pattern(type: :rails) # => #<Mustermann::Rails:"/foo">
|
|
504
|
-
%r{/foo}.to_pattern # => #<Mustermann::Regular:"\\/foo">
|
|
505
|
-
"/foo".to_pattern.to_pattern # => #<Mustermann::Sinatra:"/foo">
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
You can also use the `Mustermann::ToPattern` mixin to easily add `to_pattern` to your own objects:
|
|
509
|
-
|
|
510
|
-
``` ruby
|
|
511
|
-
require 'mustermann/to_pattern'
|
|
512
|
-
|
|
513
|
-
class MyObject
|
|
514
|
-
include Mustermann::ToPattern
|
|
515
|
-
|
|
516
|
-
def to_s
|
|
517
|
-
"/foo"
|
|
518
|
-
end
|
|
519
|
-
end
|
|
520
|
-
|
|
521
|
-
MyObject.new.to_pattern # => #<Mustermann::Sinatra:"/foo">
|
|
522
|
-
```
|
|
523
|
-
|
|
524
492
|
<a name="-duck-typing-respond-to"></a>
|
|
525
493
|
### `respond_to?`
|
|
526
494
|
|
|
@@ -679,264 +647,21 @@ By setting `ignore_unknown_options` to `true`, it will happily ignore the option
|
|
|
679
647
|
<a name="-performance"></a>
|
|
680
648
|
## Performance
|
|
681
649
|
|
|
682
|
-
|
|
650
|
+
Mustermann is designed so that as much work as possible happens at object-creation time, keeping matching and expansion fast at request time. Pattern objects should be treated as immutable; their internals are optimized for both speed and low memory usage.
|
|
683
651
|
|
|
684
|
-
|
|
652
|
+
Key points:
|
|
685
653
|
|
|
686
|
-
|
|
654
|
+
* **Pattern caching:** `Mustermann.new` may return the same instance for identical arguments while that instance is still alive. Do not rely on object identity.
|
|
655
|
+
* **Single-pattern matching:** AST-based patterns (sinatra, rails, hybrid, template, flask) use bounded character classes, negative look-ahead, and non-greedy splats to avoid unnecessary backtracking in Ruby's Oniguruma engine. Using a pattern as a `Regexp` replacement adds at most one method-dispatch of overhead.
|
|
656
|
+
* **Routing with `Mustermann::Set`:** Uses a trie (prefix tree) for large tables. Rather than checking every route in sequence, the trie walks the input one character at a time, sharing prefix traversal across all patterns that start with the same characters. Dispatch time grows far more slowly than a linear scan. A `use_trie:` threshold (default 50) controls when the switch happens, and an optional `ObjectSpace::WeakKeyMap` cache avoids re-matching the same string.
|
|
657
|
+
* **Expansion:** Most computation is shifted to compile time. Memory grows linearly with the number of optional-key combinations in a pattern.
|
|
687
658
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
In certain cases, Mustermann might outperform naive, equivalent regular expressions. It achieves this by using look-ahead and atomic groups in ways that work well with a backtracking, NFA-based regular expression engine (such as the Oniguruma/Onigmo engine used by Ruby). It can be difficult and error prone to construct complex regular expressions using these techniques by hand. This only applies to patterns generating an AST internally (all but [identity](#-pattern-details-identity), [shell](#-pattern-details-shell), [simple](#-pattern-details-simple) and [regexp](#-pattern-details-regexp) patterns).
|
|
691
|
-
|
|
692
|
-
When using a Mustermann pattern as a direct Regexp replacement (ie, via methods like `=~`, `match` or `===`), the overhead will be a single method dispatch, which some Ruby implementations might even eliminate with method inlining. This only applies to patterns using a regular expression internally (all but [identity](#-pattern-details-identity) and [shell](#-pattern-details-shell) patterns).
|
|
693
|
-
|
|
694
|
-
### Expanding
|
|
695
|
-
|
|
696
|
-
Pattern expansion significantly outperforms other, widely used Ruby tools for generating URLs from URL patterns in most use cases.
|
|
697
|
-
|
|
698
|
-
This comes with a few trade-offs:
|
|
699
|
-
|
|
700
|
-
* As with pattern compilation, as much computation as possible has been shifted to compiling expansion rules. This will add compilation overhead, which is why patterns only generate these rules on the first invocation to `Mustermann::Pattern#expand`. Create a `Mustermann::Expander` instance yourself to get better control over the point in time this computation should happen.
|
|
701
|
-
* Memory is sacrificed in favor of performance: The size of the expander object will grow linear with the number of possible combination for expansion keys ("/:foo/:bar" has one such combination, but "/(:foo/)?:bar?" has four)
|
|
702
|
-
* Parsing a params hash from a string generated from another params hash might not result in two identical hashes, and vice versa. Specifically, expanding ignores capture constraints, type casting and greediness.
|
|
703
|
-
* Partial expansion is (currently) not supported.
|
|
659
|
+
See **[docs/performance.md](../docs/performance.md)** for a detailed explanation of each optimization, the linear vs. trie trade-off, caching, thread-safety, and benchmark guidance.
|
|
704
660
|
|
|
705
661
|
## Details on Pattern Types
|
|
706
662
|
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
[`
|
|
712
|
-
[`ignore_unknown_options`](#-available-options--ignore_unknown_options).
|
|
713
|
-
|
|
714
|
-
<table>
|
|
715
|
-
<thead>
|
|
716
|
-
<tr>
|
|
717
|
-
<th>Syntax Element</th>
|
|
718
|
-
<th>Description</th>
|
|
719
|
-
</tr>
|
|
720
|
-
</thead>
|
|
721
|
-
<tbody>
|
|
722
|
-
<tr>
|
|
723
|
-
<td><i>any character</i></td>
|
|
724
|
-
<td>Matches exactly that character or a URI escaped version of it.</td>
|
|
725
|
-
</tr>
|
|
726
|
-
</tbody>
|
|
727
|
-
</table>
|
|
728
|
-
|
|
729
|
-
<a name="-regexp-pattern"></a>
|
|
730
|
-
### `regexp`
|
|
731
|
-
|
|
732
|
-
**Supported options:**
|
|
733
|
-
[`uri_decode`](#-available-options--uri_decode),
|
|
734
|
-
[`ignore_unknown_options`](#-available-options--ignore_unknown_options), `check_anchors`.
|
|
735
|
-
|
|
736
|
-
The pattern string (or actual Regexp instance) should not contain anchors (`^` outside of square brackets, `$`, `\A`, `\z`, or `\Z`).
|
|
737
|
-
Anchors will be injected where necessary by Mustermann.
|
|
738
|
-
|
|
739
|
-
By default, Mustermann will raise a `Mustermann::CompileError` if an anchor is encountered.
|
|
740
|
-
If you still want it to contain anchors at your own risk, set the `check_anchors` option to `false`.
|
|
741
|
-
|
|
742
|
-
Using anchors will break [peeking](#-peeking) and [concatenation](#-concatenation).
|
|
743
|
-
|
|
744
|
-
<table>
|
|
745
|
-
<thead>
|
|
746
|
-
<tr>
|
|
747
|
-
<th>Syntax Element</th>
|
|
748
|
-
<th>Description</th>
|
|
749
|
-
</tr>
|
|
750
|
-
</thead>
|
|
751
|
-
<tbody>
|
|
752
|
-
<tr>
|
|
753
|
-
<td><i>any string</i></td>
|
|
754
|
-
<td>Interpreted as regular expression.</td>
|
|
755
|
-
</tr>
|
|
756
|
-
</tbody>
|
|
757
|
-
</table>
|
|
758
|
-
|
|
759
|
-
<a name="-sinatra-pattern"></a>
|
|
760
|
-
### `sinatra`
|
|
761
|
-
|
|
762
|
-
**Supported options:**
|
|
763
|
-
[`capture`](#-available-options--capture),
|
|
764
|
-
[`except`](#-available-options--except),
|
|
765
|
-
[`greedy`](#-available-options--greedy),
|
|
766
|
-
[`space_matches_plus`](#-available-options--space_matches_plus),
|
|
767
|
-
[`uri_decode`](#-available-options--uri_decode),
|
|
768
|
-
[`ignore_unknown_options`](#-available-options--ignore_unknown_options).
|
|
769
|
-
|
|
770
|
-
<table>
|
|
771
|
-
<thead>
|
|
772
|
-
<tr>
|
|
773
|
-
<th>Syntax Element</th>
|
|
774
|
-
<th>Description</th>
|
|
775
|
-
</tr>
|
|
776
|
-
</thead>
|
|
777
|
-
<tbody>
|
|
778
|
-
<tr>
|
|
779
|
-
<td><b>:</b><i>name</i> <i><b>or</b></i> <b>{</b><i>name</i><b>}</b></td>
|
|
780
|
-
<td>
|
|
781
|
-
Captures anything but a forward slash in a semi-greedy fashion. Capture is named <i>name</i>.
|
|
782
|
-
Capture behavior can be modified with <tt>capture</tt> and <tt>greedy</tt> option.
|
|
783
|
-
</td>
|
|
784
|
-
</tr>
|
|
785
|
-
<tr>
|
|
786
|
-
<td><b>*</b><i>name</i> <i><b>or</b></i> <b>{+</b><i>name</i><b>}</b></td>
|
|
787
|
-
<td>
|
|
788
|
-
Captures anything in a non-greedy fashion. Capture is named <i>name</i>.
|
|
789
|
-
</td>
|
|
790
|
-
</tr>
|
|
791
|
-
<tr>
|
|
792
|
-
<td><b>*</b> <i><b>or</b></i> <b>{+splat}</b></td>
|
|
793
|
-
<td>
|
|
794
|
-
Captures anything in a non-greedy fashion. Capture is named splat.
|
|
795
|
-
It is always an array of captures, as you can use it more than once in a pattern.
|
|
796
|
-
</td>
|
|
797
|
-
</tr>
|
|
798
|
-
<tr>
|
|
799
|
-
<td><b>(</b><i>expression</i><b>)</b></td>
|
|
800
|
-
<td>
|
|
801
|
-
Enclosed <i>expression</i> is a group. Useful when combined with <tt>?</tt> to make it optional,
|
|
802
|
-
or to separate two elements that would otherwise be parsed as one.
|
|
803
|
-
</td>
|
|
804
|
-
</tr>
|
|
805
|
-
<tr>
|
|
806
|
-
<td><i>expression</i><b>|</b><i>expression</i><b>|</b><i>...</i></td>
|
|
807
|
-
<td>
|
|
808
|
-
Will match anything matching the nested expressions. May contain any other syntax element, including captures.
|
|
809
|
-
</td>
|
|
810
|
-
</tr>
|
|
811
|
-
<tr>
|
|
812
|
-
<td><i>x</i><b>?</b></td>
|
|
813
|
-
<td>Makes <i>x</i> optional. For instance, <tt>(foo)?</tt> matches <tt>foo</tt> or an empty string.</td>
|
|
814
|
-
</tr>
|
|
815
|
-
<tr>
|
|
816
|
-
<td><b>/</b></td>
|
|
817
|
-
<td>
|
|
818
|
-
Matches forward slash. Does not match URI encoded version of forward slash.
|
|
819
|
-
</td>
|
|
820
|
-
</tr>
|
|
821
|
-
<tr>
|
|
822
|
-
<td><b>\</b><i>x</i></td>
|
|
823
|
-
<td>Matches <i>x</i> or URI encoded version of <i>x</i>. For instance <tt>\*</tt> matches <tt>*</tt>.</td>
|
|
824
|
-
</tr>
|
|
825
|
-
<tr>
|
|
826
|
-
<td><i>any other character</i></td>
|
|
827
|
-
<td>Matches exactly that character or a URI encoded version of it.</td>
|
|
828
|
-
</tr>
|
|
829
|
-
</tbody>
|
|
830
|
-
</table>
|
|
831
|
-
|
|
832
|
-
<a name="-rails-pattern"></a>
|
|
833
|
-
### `rails`
|
|
834
|
-
|
|
835
|
-
Mustermann also implements the `rails` pattern. It is compatible with [Ruby on Rails](http://rubyonrails.org/), [Journey](https://github.com/rails/journey), the [http_router gem](https://github.com/joshbuddy/http_router), [Lotus](http://lotusrb.org/) and [Scalatra](http://scalatra.org/) (if [configured](http://scalatra.org/2.3/guides/http/routes.html#toc_248))</td>
|
|
836
|
-
|
|
837
|
-
**Supported options:**
|
|
838
|
-
[`capture`](#-available-options--capture),
|
|
839
|
-
[`except`](#-available-options--except),
|
|
840
|
-
[`greedy`](#-available-options--greedy),
|
|
841
|
-
[`space_matches_plus`](#-available-options--space_matches_plus),
|
|
842
|
-
[`uri_decode`](#-available-options--uri_decode),
|
|
843
|
-
[`version`](#-rails-pattern--version),
|
|
844
|
-
[`ignore_unknown_options`](#-available-options--ignore_unknown_options).
|
|
845
|
-
|
|
846
|
-
**External documentation:**
|
|
847
|
-
[Ruby on Rails Guides: Routing](http://guides.rubyonrails.org/routing.html).
|
|
848
|
-
|
|
849
|
-
``` ruby
|
|
850
|
-
require 'mustermann'
|
|
851
|
-
|
|
852
|
-
pattern = Mustermann.new('/:example', type: :rails)
|
|
853
|
-
pattern === "/foo.bar" # => true
|
|
854
|
-
pattern === "/foo/bar" # => false
|
|
855
|
-
pattern.params("/foo.bar") # => { "example" => "foo.bar" }
|
|
856
|
-
pattern.params("/foo/bar") # => nil
|
|
857
|
-
|
|
858
|
-
pattern = Mustermann.new('/:example(/:optional)', type: :rails)
|
|
859
|
-
pattern === "/foo.bar" # => true
|
|
860
|
-
pattern === "/foo/bar" # => true
|
|
861
|
-
pattern.params("/foo.bar") # => { "example" => "foo.bar", "optional" => nil }
|
|
862
|
-
pattern.params("/foo/bar") # => { "example" => "foo", "optional" => "bar" }
|
|
863
|
-
|
|
864
|
-
pattern = Mustermann.new('/*example', type: :rails)
|
|
865
|
-
pattern === "/foo.bar" # => true
|
|
866
|
-
pattern === "/foo/bar" # => true
|
|
867
|
-
pattern.params("/foo.bar") # => { "example" => "foo.bar" }
|
|
868
|
-
pattern.params("/foo/bar") # => { "example" => "foo/bar" }
|
|
869
|
-
```
|
|
870
|
-
|
|
871
|
-
<a name="-rails-pattern--version"></a>
|
|
872
|
-
#### `version`
|
|
873
|
-
|
|
874
|
-
Rails syntax changed over time. You can target different Ruby on Rails versions by setting the `version` option to the desired Rails version.
|
|
875
|
-
|
|
876
|
-
The default is `5.0`. Versions prior to `2.3` are not supported.
|
|
877
|
-
|
|
878
|
-
``` ruby
|
|
879
|
-
require 'mustermann'
|
|
880
|
-
Mustermann.new('/', type: :rails, version: "2.3")
|
|
881
|
-
Mustermann.new('/', type: :rails, version: "3.0.0")
|
|
882
|
-
|
|
883
|
-
require 'rails'
|
|
884
|
-
Mustermann.new('/', type: :rails, version: Rails::VERSION::STRING)
|
|
885
|
-
```
|
|
886
|
-
|
|
887
|
-
#### Syntax
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
<table>
|
|
891
|
-
<thead>
|
|
892
|
-
<tr>
|
|
893
|
-
<th>Syntax Element</th>
|
|
894
|
-
<th>Description</th>
|
|
895
|
-
</tr>
|
|
896
|
-
</thead>
|
|
897
|
-
<tbody>
|
|
898
|
-
<tr>
|
|
899
|
-
<td><b>:</b><i>name</i></td>
|
|
900
|
-
<td>
|
|
901
|
-
Captures anything but a forward slash in a semi-greedy fashion. Capture is named <i>name</i>.
|
|
902
|
-
Capture behavior can be modified with <tt>capture</tt> and <tt>greedy</tt> option.
|
|
903
|
-
</td>
|
|
904
|
-
</tr>
|
|
905
|
-
<tr>
|
|
906
|
-
<td><b>*</b><i>name</i></td>
|
|
907
|
-
<td>
|
|
908
|
-
Captures anything in a non-greedy fashion. Capture is named <i>name</i>.
|
|
909
|
-
</td>
|
|
910
|
-
</tr>
|
|
911
|
-
<tr>
|
|
912
|
-
<td><b>(</b><i>expression</i><b>)</b></td>
|
|
913
|
-
<td>Enclosed <i>expression</i> is optional. Not available in 2.3 compatibility mode.</td>
|
|
914
|
-
</tr>
|
|
915
|
-
<tr>
|
|
916
|
-
<td><b>/</b></td>
|
|
917
|
-
<td>
|
|
918
|
-
Matches forward slash. Does not match URI encoded version of forward slash.
|
|
919
|
-
</td>
|
|
920
|
-
</tr>
|
|
921
|
-
<tr>
|
|
922
|
-
<td><b>\</b><i>x</i></td>
|
|
923
|
-
<td>
|
|
924
|
-
In 3.x compatibility mode and starting with 4.2:
|
|
925
|
-
Matches <i>x</i> or URI encoded version of <i>x</i>. For instance <tt>\*</tt> matches <tt>*</tt>.<br>
|
|
926
|
-
In 4.0 or 4.1 compatibility mode:
|
|
927
|
-
<b>\</b> is ignored, <i>x</i> is parsed normally.<br>
|
|
928
|
-
</td>
|
|
929
|
-
</tr>
|
|
930
|
-
<tr>
|
|
931
|
-
<td><i>expression</i> <b>|</b> <i>expression</i></td>
|
|
932
|
-
<td>
|
|
933
|
-
3.2+ mode: This will raise a `Mustermann::ParseError`. While Ruby on Rails happily parses this character, it will result in broken routes due to a buggy implementation.<br>
|
|
934
|
-
5.0 mode: It will match if any of the nested expressions matches.
|
|
935
|
-
</td>
|
|
936
|
-
</tr>
|
|
937
|
-
<tr>
|
|
938
|
-
<td><i>any other character</i></td>
|
|
939
|
-
<td>Matches exactly that character or a URI encoded version of it.</td>
|
|
940
|
-
</tr>
|
|
941
|
-
</tbody>
|
|
942
|
-
</table>
|
|
663
|
+
- [`identity`](../docs/patterns/identity.md)
|
|
664
|
+
- [`regexp`](../docs/patterns/regexp.md)
|
|
665
|
+
- [`sinatra`](../docs/patterns/sinatra.md)
|
|
666
|
+
- [`rails`](../docs/patterns/rails.md)
|
|
667
|
+
- [`hybrid`](../docs/patterns/hybrid.md)
|