mustermann 3.1.0 → 4.0.0.alpha

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0b15c2c5c75d712dde03df8b83d4f0b646455aa892eb59365f1b09ce01bfa7c
4
- data.tar.gz: 358ce50be0eb8638e47ea8bb3cd65512f57e10eb65b93600098145214a2f6d39
3
+ metadata.gz: 295f1b612e2e5a51c3edb1d1fa1c1ed66f56792d3782dda3adb1f48082d702ac
4
+ data.tar.gz: db02262f6b9853a63b8718e87e984526655b90e0e0648c1250ea4af23cb497da
5
5
  SHA512:
6
- metadata.gz: 3360ad1465989d2179b97d67c64261d7a68cf22ca1cea2a02f2450bd5b0894948efd4d99581b7d7609dc7698d4ed0595d85613b67d79dce3ce79b84d08e614ff
7
- data.tar.gz: 8c32fae7ff72697598dacf54c1ddae95ea80a48814fa887c61d91e18bca6a0a1c79768a981fba0cd4d60d986db76c0961a3f6dae5c5a7a8b8276978428fb105e
6
+ metadata.gz: ae9f2778ec8d47418feec32de4ee1ca837b2ad22076ccd59c438872f075bbcd7deef2be648a7710570e45cb49e5c82085b5da1435641c5143131fee69734b8ec
7
+ data.tar.gz: d43838b66491e62f6fc7cf066fcce44ae2a7ec9a28e47abbad100519d3db13d1b0c8eed789bdff64b5f3f18e6548cfbe2e6312288ebe96c6bf236aac80eb0807
data/LICENSE CHANGED
@@ -1,5 +1,4 @@
1
- Copyright (c) 2013-2017 Konstantin Haase
2
- Copyright (c) 2016-2017 Zachary Scott
1
+ Copyright (c) Konstantin Haase
3
2
 
4
3
  Permission is hereby granted, free of charge, to any person
5
4
  obtaining a copy of this software and associated documentation
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](http://rubydoc.info/gems/mustermann/frames), [master](http://rubydoc.info/github/rkh/mustermann/master/frames).*
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
- * **[Mapper](#-mapper):** A simple tool for mapping one string to another based on patterns.
45
- * **[Sinatra Integration](#-sinatra-integration):** Mustermann can be used as a [Sinatra](http://www.sinatrarb.com/) extension. Sinatra 2.0 and beyond will use Mustermann by default.
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](#-pattern-details-regexp) pattern, a symbol always in a [sinatra](#-pattern-details-sinatra) pattern, etc).
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](#-sinatra-pattern), [identity](#-identity-pattern) and [regexp](#-regexp-pattern) pattern types. Other pattern types are available as separate gems.
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::SimpleMatch "/home">
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 `MatchData` or `Mustermann::SimpleMatch` (just like `match` does for the full string)
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.
@@ -311,7 +307,7 @@ require 'mustermann'
311
307
 
312
308
  Mustermann.new("/:name").to_templates # => ["/{name}"]
313
309
  Mustermann.new("/:foo(@:bar)?/*baz").to_templates # => ["/{foo}@{bar}/{+baz}", "/{foo}/{+baz}"]
314
- Mustermann.new("/{name}", type: :template).to_templates # => ["/{name}"
310
+ Mustermann.new("/{name}", type: :template).to_templates # => ["/{name}"]
315
311
  ```
316
312
 
317
313
  Union Composite patterns (with the | operator) support template generation if all patterns they are composed of also support it.
@@ -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="-mapper"></a>
363
- ## Mapper
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/mapper'
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
- <a name="-sinatra-integration"></a>
378
- ## Sinatra Integration
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
- Mustermann is used in Sinatra by default since version 2.0, for previous versions an [extension](https://github.com/sinatra/mustermann-sinatra-extension) is available.
371
+ m = set.match('/users/42')
372
+ m.value # => :users_show
373
+ m.params['id'] # => '42'
381
374
 
382
- ### Configuration
375
+ set.match('/unknown') # => nil
376
+ ```
383
377
 
384
- You can change what pattern type you want to use for your app via the `pattern` option:
378
+ You can supply the initial mapping directly to the constructor:
385
379
 
386
380
  ``` ruby
387
- require 'sinatra/base'
388
- require 'mustermann'
389
-
390
- class MyApp < Sinatra::Base
391
- register Mustermann
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
- get '/images/*.png' do
395
- send_file request.path_info
396
- end
387
+ Or use a block for imperative setup:
397
388
 
398
- get '/index{.htm,.html,}' do
399
- erb :index
400
- end
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
- You can use the same setting for options:
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
- require 'sinatra'
408
- require 'mustermann'
399
+ set = Mustermann::Set.new(type: :rails)
400
+ set.add('/:controller(/:action(/:id))', :route)
401
+ ```
409
402
 
410
- register Mustermann
411
- set :pattern, capture: { ext: %w[png jpg html txt] }
403
+ ### Values
412
404
 
413
- get '/:slug(.:ext)?' do
414
- # slug will be 'foo' for '/foo.png'
415
- # slug will be 'foo.bar' for '/foo.bar'
416
- # slug will be 'foo.bar' for '/foo.bar.html'
417
- params[:slug]
418
- end
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
- It is also possible to pass in options to a specific route:
415
+ When no value is given, a match still succeeds but `value` is `nil`:
422
416
 
423
417
  ``` ruby
424
- require 'sinatra'
425
- require 'mustermann'
418
+ set = Mustermann::Set.new
419
+ set.add('/ping')
420
+ set.match('/ping').value # => nil
421
+ ```
426
422
 
427
- register Mustermann
423
+ ### Conflict Resolution
428
424
 
429
- get '/:slug(.:ext)?', pattern: { greedy: false } do
430
- # slug will be 'foo' for '/foo.png'
431
- # slug will be 'foo' for '/foo.bar'
432
- # slug will be 'foo' for '/foo.bar.html'
433
- params[:slug]
434
- end
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
- Of course, all of the above can be combined.
438
- Moreover, the `capture` and the `except` option can be passed to route directly.
439
- And yes, this also works with `before` and `after` filters.
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
- require 'sinatra/base'
443
- require 'sinatra/respond_with'
444
- require 'mustermann'
441
+ set = Mustermann::Set.new
442
+ set.add('/users/:id', :users)
445
443
 
446
- class MyApp < Sinatra::Base
447
- register Mustermann, Sinatra::RespondWith
448
- set :pattern, capture: { id: /\d+/ } # id will only match digits
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
- # only capture extensions known to Rack
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
- get '/:id' do
457
- not_found unless page = Page.find params[:id]
458
- respond_with(page)
459
- end
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
- ### Why would I want this?
458
+ ### Expanding
464
459
 
465
- * It gives you fine grained control over the pattern matching
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
- ### Why not include this in Sinatra 1.x?
462
+ ``` ruby
463
+ set = Mustermann::Set.new
464
+ set.add('/users/:id', :users)
465
+ set.add('/posts/:id', :posts)
472
466
 
473
- * It would introduce breaking changes, even though these would be minor
474
- * Like Sinatra 2.0, Mustermann requires Ruby 2.0 or newer
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,152 +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
- It's generally a good idea to reuse pattern objects, since as much computation as possible is happening during object creation, so that the actual matching or expanding is quite fast.
683
-
684
- Pattern objects should be treated as immutable. Their internals have been designed for both performance and low memory usage. To reduce pattern compilation, `Mustermann.new` and `Mustermann::Pattern.new` might return the same instance when given the same arguments, if that instance has not yet been garbage collected. However, this is not guaranteed, so do not rely on object identity.
685
-
686
- ### String Matching
687
-
688
- When using a pattern instead of a regular expression for string matching, performance will usually be comparable.
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
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.
695
651
 
696
- Pattern expansion significantly outperforms other, widely used Ruby tools for generating URLs from URL patterns in most use cases.
652
+ Key points:
697
653
 
698
- This comes with a few trade-offs:
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.
699
658
 
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
- <a name="-identity-pattern"></a>
708
- ### `identity`
709
-
710
- **Supported options:**
711
- [`uri_decode`](#-available-options--uri_decode),
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>&#123;</b><i>name</i><b>&#125;</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>&#123;+</b><i>name</i><b>&#125;</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>&#123;+splat&#125;</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>
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)