mustermann 1.0.2.rc1 → 1.0.2.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +799 -230
  3. data/{mustermann/bench → bench}/capturing.rb +0 -0
  4. data/{mustermann/bench → bench}/regexp.rb +0 -0
  5. data/{mustermann/bench → bench}/simple_vs_sinatra.rb +0 -0
  6. data/{mustermann/bench → bench}/template_vs_addressable.rb +0 -0
  7. data/{mustermann/lib → lib}/mustermann.rb +0 -0
  8. data/{mustermann/lib → lib}/mustermann/ast/boundaries.rb +0 -0
  9. data/{mustermann/lib → lib}/mustermann/ast/compiler.rb +0 -0
  10. data/{mustermann/lib → lib}/mustermann/ast/expander.rb +0 -0
  11. data/{mustermann/lib → lib}/mustermann/ast/node.rb +0 -0
  12. data/{mustermann/lib → lib}/mustermann/ast/param_scanner.rb +0 -0
  13. data/{mustermann/lib → lib}/mustermann/ast/parser.rb +0 -0
  14. data/{mustermann/lib → lib}/mustermann/ast/pattern.rb +0 -0
  15. data/{mustermann/lib → lib}/mustermann/ast/template_generator.rb +0 -0
  16. data/{mustermann/lib → lib}/mustermann/ast/transformer.rb +0 -0
  17. data/{mustermann/lib → lib}/mustermann/ast/translator.rb +0 -0
  18. data/{mustermann/lib → lib}/mustermann/ast/validation.rb +0 -0
  19. data/{mustermann/lib → lib}/mustermann/caster.rb +0 -0
  20. data/{mustermann/lib → lib}/mustermann/composite.rb +0 -0
  21. data/{mustermann/lib → lib}/mustermann/concat.rb +0 -0
  22. data/{mustermann/lib → lib}/mustermann/equality_map.rb +0 -0
  23. data/{mustermann/lib → lib}/mustermann/error.rb +0 -0
  24. data/{mustermann/lib → lib}/mustermann/expander.rb +0 -0
  25. data/{mustermann/lib → lib}/mustermann/extension.rb +0 -0
  26. data/{mustermann/lib → lib}/mustermann/identity.rb +0 -0
  27. data/{mustermann/lib → lib}/mustermann/mapper.rb +0 -0
  28. data/{mustermann/lib → lib}/mustermann/pattern.rb +0 -0
  29. data/{mustermann/lib → lib}/mustermann/pattern_cache.rb +0 -0
  30. data/{mustermann/lib → lib}/mustermann/regexp.rb +0 -0
  31. data/{mustermann/lib → lib}/mustermann/regexp_based.rb +0 -0
  32. data/{mustermann/lib → lib}/mustermann/regular.rb +0 -0
  33. data/{mustermann/lib → lib}/mustermann/simple_match.rb +0 -0
  34. data/{mustermann/lib → lib}/mustermann/sinatra.rb +0 -0
  35. data/{mustermann/lib → lib}/mustermann/sinatra/parser.rb +0 -0
  36. data/{mustermann/lib → lib}/mustermann/sinatra/safe_renderer.rb +0 -0
  37. data/{mustermann/lib → lib}/mustermann/sinatra/try_convert.rb +0 -0
  38. data/{mustermann/lib → lib}/mustermann/to_pattern.rb +0 -0
  39. data/{mustermann/lib → lib}/mustermann/version.rb +1 -1
  40. data/{mustermann/mustermann.gemspec → mustermann.gemspec} +0 -0
  41. data/{mustermann/spec → spec}/ast_spec.rb +0 -0
  42. data/{mustermann/spec → spec}/composite_spec.rb +0 -0
  43. data/{mustermann/spec → spec}/concat_spec.rb +0 -0
  44. data/{mustermann/spec → spec}/equality_map_spec.rb +0 -0
  45. data/{mustermann/spec → spec}/expander_spec.rb +0 -0
  46. data/{mustermann/spec → spec}/extension_spec.rb +0 -0
  47. data/{mustermann/spec → spec}/identity_spec.rb +0 -0
  48. data/{mustermann/spec → spec}/mapper_spec.rb +0 -0
  49. data/{mustermann/spec → spec}/mustermann_spec.rb +0 -0
  50. data/{mustermann/spec → spec}/pattern_spec.rb +0 -0
  51. data/{mustermann/spec → spec}/regexp_based_spec.rb +0 -0
  52. data/{mustermann/spec → spec}/regular_spec.rb +0 -0
  53. data/{mustermann/spec → spec}/simple_match_spec.rb +0 -0
  54. data/{mustermann/spec → spec}/sinatra_spec.rb +0 -0
  55. data/{mustermann/spec → spec}/to_pattern_spec.rb +0 -0
  56. metadata +71 -126
  57. data/.gitignore +0 -18
  58. data/.rspec +0 -5
  59. data/.travis.yml +0 -25
  60. data/.yardopts +0 -3
  61. data/Gemfile +0 -7
  62. data/Rakefile +0 -27
  63. data/mustermann-contrib/LICENSE +0 -23
  64. data/mustermann-contrib/README.md +0 -1155
  65. data/mustermann-contrib/examples/highlighting.rb +0 -35
  66. data/mustermann-contrib/highlighting.png +0 -0
  67. data/mustermann-contrib/irb.png +0 -0
  68. data/mustermann-contrib/lib/mustermann/cake.rb +0 -19
  69. data/mustermann-contrib/lib/mustermann/express.rb +0 -38
  70. data/mustermann-contrib/lib/mustermann/file_utils.rb +0 -218
  71. data/mustermann-contrib/lib/mustermann/file_utils/glob_pattern.rb +0 -40
  72. data/mustermann-contrib/lib/mustermann/fileutils.rb +0 -1
  73. data/mustermann-contrib/lib/mustermann/flask.rb +0 -199
  74. data/mustermann-contrib/lib/mustermann/pyramid.rb +0 -29
  75. data/mustermann-contrib/lib/mustermann/rails.rb +0 -47
  76. data/mustermann-contrib/lib/mustermann/shell.rb +0 -57
  77. data/mustermann-contrib/lib/mustermann/simple.rb +0 -51
  78. data/mustermann-contrib/lib/mustermann/string_scanner.rb +0 -314
  79. data/mustermann-contrib/lib/mustermann/strscan.rb +0 -1
  80. data/mustermann-contrib/lib/mustermann/template.rb +0 -63
  81. data/mustermann-contrib/lib/mustermann/uri_template.rb +0 -1
  82. data/mustermann-contrib/lib/mustermann/versions.rb +0 -47
  83. data/mustermann-contrib/lib/mustermann/visualizer.rb +0 -39
  84. data/mustermann-contrib/lib/mustermann/visualizer/highlight.rb +0 -138
  85. data/mustermann-contrib/lib/mustermann/visualizer/highlighter.rb +0 -38
  86. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/ad_hoc.rb +0 -95
  87. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/ast.rb +0 -103
  88. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/composite.rb +0 -46
  89. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/dummy.rb +0 -19
  90. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/regular.rb +0 -105
  91. data/mustermann-contrib/lib/mustermann/visualizer/pattern_extension.rb +0 -69
  92. data/mustermann-contrib/lib/mustermann/visualizer/renderer/ansi.rb +0 -24
  93. data/mustermann-contrib/lib/mustermann/visualizer/renderer/generic.rb +0 -47
  94. data/mustermann-contrib/lib/mustermann/visualizer/renderer/hansi_template.rb +0 -35
  95. data/mustermann-contrib/lib/mustermann/visualizer/renderer/html.rb +0 -51
  96. data/mustermann-contrib/lib/mustermann/visualizer/renderer/sexp.rb +0 -38
  97. data/mustermann-contrib/lib/mustermann/visualizer/tree.rb +0 -64
  98. data/mustermann-contrib/lib/mustermann/visualizer/tree_renderer.rb +0 -79
  99. data/mustermann-contrib/mustermann-contrib.gemspec +0 -19
  100. data/mustermann-contrib/spec/cake_spec.rb +0 -91
  101. data/mustermann-contrib/spec/express_spec.rb +0 -210
  102. data/mustermann-contrib/spec/file_utils_spec.rb +0 -120
  103. data/mustermann-contrib/spec/flask_spec.rb +0 -362
  104. data/mustermann-contrib/spec/flask_subclass_spec.rb +0 -369
  105. data/mustermann-contrib/spec/pattern_extension_spec.rb +0 -50
  106. data/mustermann-contrib/spec/pyramid_spec.rb +0 -102
  107. data/mustermann-contrib/spec/rails_spec.rb +0 -648
  108. data/mustermann-contrib/spec/shell_spec.rb +0 -148
  109. data/mustermann-contrib/spec/simple_spec.rb +0 -269
  110. data/mustermann-contrib/spec/string_scanner_spec.rb +0 -272
  111. data/mustermann-contrib/spec/template_spec.rb +0 -842
  112. data/mustermann-contrib/spec/visualizer_spec.rb +0 -199
  113. data/mustermann-contrib/theme.png +0 -0
  114. data/mustermann-contrib/tree.png +0 -0
  115. data/mustermann/LICENSE +0 -23
  116. data/mustermann/README.md +0 -853
  117. data/support/lib/support.rb +0 -7
  118. data/support/lib/support/coverage.rb +0 -23
  119. data/support/lib/support/env.rb +0 -19
  120. data/support/lib/support/expand_matcher.rb +0 -28
  121. data/support/lib/support/generate_template_matcher.rb +0 -27
  122. data/support/lib/support/match_matcher.rb +0 -39
  123. data/support/lib/support/pattern.rb +0 -42
  124. data/support/lib/support/projects.rb +0 -20
  125. data/support/lib/support/scan_matcher.rb +0 -63
  126. data/support/support.gemspec +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9008c3296d38ca390e81901f27e8f25194b42218
4
- data.tar.gz: 884e345d599d8eb5f9df1ad640b8b977576c4a6d
3
+ metadata.gz: f9cf78ccbf62f227f7b427b63233e0c4250c908d
4
+ data.tar.gz: e9b45cb9086ac3df7dec099f296d61a2b2e89347
5
5
  SHA512:
6
- metadata.gz: 7621bf788beae885250e78a38408a0d277682a8b212f452075d83bec4c168b3789473374b116d9edc0b73fe14b5ae59a495eecaa1b24dcf45ca2f8f9530bfe20
7
- data.tar.gz: 458c22b4a904a951974445260ee2f967538a7ae1e0b006012a1922708924e32fbbafa8f3bed93587eca379c54b5a4980a5c496d7b3bcbef1bdd1056890b39763
6
+ metadata.gz: 14bd2c392caab21495d160bddb47b192fa15d4f416f9242146c9c49c2a3e63879ea49478c76cc1904776510ed91e10b2f15120abedbb8622b388c0b6a8d20ab7
7
+ data.tar.gz: 9f29abc6079e5092078acd4824d418d78ccf2d24bc74b4bfe641fc7bbce02ef33c13342388e57a8fb564860e20306ff2b69db3ada6aadf33f2c93dd478ecb406
data/README.md CHANGED
@@ -1,284 +1,853 @@
1
1
  # The Amazing Mustermann
2
2
 
3
- [![Build Status](https://travis-ci.org/sinatra/mustermann.svg?branch=master)](https://travis-ci.org/sinatra/mustermann) [![Coverage Status](https://coveralls.io/repos/github/rkh/mustermann/badge.svg?branch=master)](https://coveralls.io/github/rkh/mustermann?branch=master) [![Code Climate](https://img.shields.io/codeclimate/github/rkh/mustermann.svg)](https://codeclimate.com/github/rkh/mustermann) [![Dependency Status](https://gemnasium.com/rkh/mustermann.svg)](https://gemnasium.com/rkh/mustermann) [![Gem Version](https://img.shields.io/gem/v/mustermann.svg)](https://rubygems.org/gems/mustermann)
4
- [![Inline docs](http://inch-ci.org/github/rkh/mustermann.svg)](http://inch-ci.org/github/rkh/mustermann)
5
- [![Documentation](http://img.shields.io/:yard-docs-38c800.svg)](http://www.rubydoc.info/gems/mustermann/frames)
6
- [![License](http://img.shields.io/:license-MIT-38c800.svg)](http://rkh.mit-license.org)
7
- [![Badges](http://img.shields.io/:badges-9/9-38c800.svg)](http://img.shields.io)
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).*
8
4
 
9
- This repository contains multiple projects (each installable as separate gems).
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.
10
6
 
11
- * **[mustermann](https://github.com/sinatra/mustermann/blob/master/mustermann/README.md): Your personal string matching expert. This is probably what you're looking for.**
12
- * [mustermann-contrib](https://github.com/sinatra/mustermann/blob/master/mustermann-contrib/README.md): A meta gem depending on all other official mustermann gems.
13
- * [mustermann-fileutils](https://github.com/sinatra/mustermann/blob/master/mustermann-contrib/README.md#-mustermann-fileutils): Efficient file system operations using Mustermann patterns.
14
- * [mustermann-strscan](https://github.com/sinatra/mustermann/blob/master/mustermann-contrib/README.md#-mustermann-strscan): A version of Ruby's [StringScanner](http://ruby-doc.org/stdlib-2.0/libdoc/strscan/rdoc/StringScanner.html) made for pattern objects.
15
- * [mustermann-visualizer](https://github.com/sinatra/mustermann/blob/master/mustermann-contrib/README.md#-mustermann-visualizer): Syntax highlighting and tree visualization for patterns.'
16
- * A selection of pattern types for mustermann, each as their own little library, see [below](#-pattern-types).
17
-
18
- ## Git versions with Bundler
19
-
20
- You can easily use the latest edge version from GitHub of any of these gems via [Bundler](http://bundler.io/):
7
+ Given a string pattern, Mustermann will turn it into an object that behaves like a regular expression and has comparable performance characteristics.
21
8
 
22
9
  ``` ruby
23
- git 'https://github.com/rkh/mustermann.git' do
24
- gem 'mustermann'
25
- gem 'mustermann-rails'
10
+ if '/foo/bar' =~ Mustermann.new('/foo/*')
11
+ puts 'it works!'
12
+ end
13
+
14
+ case 'something.png'
15
+ when Mustermann.new('foo/*') then puts "prefixed with foo"
16
+ when Mustermann.new('*.pdf') then puts "it's a PDF"
17
+ when Mustermann.new('*.png') then puts "it's an image"
26
18
  end
19
+
20
+ pattern = Mustermann.new('/:prefix/*.*')
21
+ pattern.params('/a/b.c') # => { "prefix" => "a", splat => ["b", "c"] }
27
22
  ```
28
23
 
24
+ ## Overview
25
+
26
+ ### Features
27
+
28
+ * **[Pattern Types](#-pattern-types):** Mustermann supports a wide variety of different pattern types, making it compatible with a large variety of existing software.
29
+ * **[Fine Grained Control](#-available-options):** You can easily adjust matching behavior and add constraints to the placeholders and capture groups.
30
+ * **[Binary Operators](#-binary-operators) and [Concatenation](#-concatenation):** Patterns can be combined into composite patterns using binary operators.
31
+ * **[Regexp Look Alike](#-regexp-look-alike):** Mustermann patterns can be used as a replacement for regular expressions.
32
+ * **[Parameter Parsing](#-parameter-parsing):** Mustermann can parse matched parameters into a Sinatra-style "params" hash, including type casting.
33
+ * **[Peeking](#-peeking):** Lets you check if the beginning of a string matches a pattern.
34
+ * **[Expanding](#-expanding):** Besides parsing a parameters from an input string, a pattern object can also be used to generate a string from a set of parameters.
35
+ * **[Generating Templates](#-generating-templates):** This comes in handy when wanting to hand on patterns rather than fully expanded strings as part of an external API.
36
+ * **[Proc Look Alike](#-proc-look-alike):** Pass on a pattern instead of a block.
37
+ * **[Duck Typing](#-duck-typing):** You can create your own pattern-like objects by implementing `to_pattern`.
38
+ * **[Performance](#-performance):** Patterns are implemented with both performance and a low memory footprint in mind.
39
+
40
+ ### Additional Tooling
41
+
42
+ These features are included in the library, but not loaded by default
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.
46
+
29
47
  <a name="-pattern-types"></a>
30
48
  ## Pattern Types
31
49
 
32
- The `identity`, `regexp` and `sinatra` types are included in the `mustermann` gem, all the other types have their own gems.
50
+ Mustermann support multiple pattern types. A pattern type defines the syntax, matching semantics and whether certain features, like [expanding](#-expanding) and [generating templates](#-generating-templates), are available.
51
+
52
+ You can create a pattern of a certain type by passing `type` option to `Mustermann.new`:
53
+
54
+ ``` ruby
55
+ require 'mustermann'
56
+ pattern = Mustermann.new('/*/**', type: :shell)
57
+ ```
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).
60
+
61
+ Alternatively, you can also load and instantiate the pattern type directly:
62
+
63
+ ``` ruby
64
+ require 'mustermann/shell'
65
+ pattern = Mustermann::Shell.new('/*/**')
66
+ ```
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.
69
+
70
+ <a name="-binary-operators"></a>
71
+ ## Binary Operators
72
+
73
+ Patterns can be combined via binary operators. These are:
74
+
75
+ * `|` (or): Resulting pattern matches if at least one of the input pattern matches.
76
+ * `&` (and): Resulting pattern matches if all input patterns match.
77
+ * `^` (xor): Resulting pattern matches if exactly one of the input pattern matches.
78
+
79
+ ``` ruby
80
+ require 'mustermann'
81
+
82
+ first = Mustermann.new('/foo/:input')
83
+ second = Mustermann.new('/:input/bar')
84
+
85
+ first | second === "/foo/foo" # => true
86
+ first | second === "/foo/bar" # => true
87
+
88
+ first & second === "/foo/foo" # => false
89
+ first & second === "/foo/bar" # => true
90
+
91
+ first ^ second === "/foo/foo" # => true
92
+ first ^ second === "/foo/bar" # => false
93
+ ```
94
+
95
+ These resulting objects are fully functional pattern objects, allowing you to call methods like `params` or `to_proc` on them. Moreover, *or* patterns created solely from expandable patterns will also be expandable. The same logic also applies to generating templates from *or* patterns.
96
+
97
+ <a name="-concatenation"></a>
98
+ ## Concatenation
99
+
100
+ Similar to [Binary Operators](#-binary-operators), two patterns can be concatenated using `+`.
101
+
102
+ ``` ruby
103
+ require 'mustermann'
104
+
105
+ prefix = Mustermann.new("/:prefix")
106
+ about = prefix + "/about"
107
+
108
+ about.params("/main/about") # => {"prefix" => "main"}
109
+ ```
110
+
111
+ Patterns of different types can be mixed. The availability of `to_templates` and `expand` depends on the patterns being concatenated.
112
+
113
+ <a name="-regexp-look-alike"></a>
114
+ ## Regexp Look Alike
115
+
116
+ Pattern objects mimic Ruby's `Regexp` class by implementing `match`, `=~`, `===`, `names` and `named_captures`.
117
+
118
+ ``` ruby
119
+ require 'mustermann'
120
+
121
+ pattern = Mustermann.new('/:page')
122
+ pattern.match('/') # => nil
123
+ pattern.match('/home') # => #<MatchData "/home" page:"home">
124
+ pattern =~ '/home' # => 0
125
+ pattern === '/home' # => true (this allows using it in case statements)
126
+ pattern.names # => ['page']
127
+ pattern.names # => {"page"=>[1]}
128
+
129
+ pattern = Mustermann.new('/home', type: :identity)
130
+ pattern.match('/') # => nil
131
+ pattern.match('/home') # => #<Mustermann::SimpleMatch "/home">
132
+ pattern =~ '/home' # => 0
133
+ pattern === '/home' # => true (this allows using it in case statements)
134
+ pattern.names # => []
135
+ pattern.names # => {}
136
+ ```
137
+
138
+ Moreover, patterns based on regular expressions (all but `identity` and `shell`) automatically convert to regular expressions when needed:
139
+
140
+ ``` ruby
141
+ require 'mustermann'
142
+
143
+ pattern = Mustermann.new('/:page')
144
+ union = Regexp.union(pattern, /^$/)
145
+
146
+ union =~ "/foo" # => 0
147
+ union =~ "" # => 0
148
+
149
+ Regexp.try_convert(pattern) # => /.../
150
+ ```
151
+
152
+ This way, unless some code explicitly checks the class for a regular expression, you should be able to pass in a pattern object instead even if the code in question was not written with Mustermann in mind.
153
+
154
+ <a name="-parameter-parsing"></a>
155
+ ## Parameter Parsing
156
+
157
+ Besides being a `Regexp` look-alike, Mustermann also adds a `params` method, that will give you a Sinatra-style hash:
158
+
159
+ ``` ruby
160
+ require 'mustermann'
161
+
162
+ pattern = Mustermann.new('/:prefix/*.*')
163
+ pattern.params('/a/b.c') # => { "prefix" => "a", splat => ["b", "c"] }
164
+ ```
165
+
166
+ For patterns with typed captures, it will also automatically convert them:
167
+
168
+ ``` ruby
169
+ require 'mustermann'
170
+
171
+ pattern = Mustermann.new('/<prefix>/<int:id>', type: :flask)
172
+ pattern.params('/page/10') # => { "prefix" => "page", "id" => 10 }
173
+ ```
174
+
175
+ <a name="-peeking"></a>
176
+ ## Peeking
177
+
178
+ Peeking gives the option to match a pattern against the beginning of a string rather the full string. Patterns come with four methods for peeking:
179
+
180
+ * `peek` returns the matching substring.
181
+ * `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)
183
+ * `peek_params` will return the `params` hash parsed from the substring and the number of characters.
184
+
185
+ All of the above will turn `nil` if there was no match.
186
+
187
+ ``` ruby
188
+ require 'mustermann'
189
+
190
+ pattern = Mustermann.new('/:prefix')
191
+ pattern.peek('/foo/bar') # => '/foo'
192
+ pattern.peek_size('/foo/bar') # => 4
193
+
194
+ path_info = '/foo/bar'
195
+ params, size = patter.peek_params(path_info) # params == { "prefix" => "foo" }
196
+ rest = path_info[size..-1] # => "/bar"
197
+ ```
198
+
199
+ <a name="-expanding"></a>
200
+ ## Expanding
201
+
202
+ Similarly to parsing, it is also possible to generate a string from a pattern by expanding it with a hash.
203
+ For simple expansions, you can use `Pattern#expand`.
204
+
205
+ ``` ruby
206
+ pattern = Mustermann.new('/:file(.:ext)?')
207
+ pattern.expand(file: 'pony') # => "/pony"
208
+ pattern.expand(file: 'pony', ext: 'jpg') # => "/pony.jpg"
209
+ pattern.expand(ext: 'jpg') # raises Mustermann::ExpandError
210
+ ```
211
+
212
+ Expanding can be useful for instance when implementing link helpers.
213
+
214
+ ### Expander Objects
215
+
216
+ To get fine-grained control over expansion, you can use `Mustermann::Expander` directly.
217
+
218
+ You can create an expander object directly from a string:
219
+
220
+ ``` ruby
221
+ require 'mustermann/expander'
222
+ expander = Mustermann::Expander("/:file.jpg")
223
+ expander.expand(file: 'pony') # => "/pony.jpg"
224
+
225
+ expander = Mustermann::Expander(":file(.:ext)", type: :rails)
226
+ expander.expand(file: 'pony', ext: 'jpg') # => "/pony.jpg"
227
+ ```
228
+
229
+ Or you can pass it a pattern instance:
230
+
231
+ ``` ruby
232
+ require 'mustermann'
233
+ pattern = Mustermann.new("/:file")
234
+
235
+ require 'mustermann/expander'
236
+ expander = Mustermann::Expander.new(pattern)
237
+ ```
238
+
239
+ ### Expanding Multiple Patterns
240
+
241
+ You can add patterns to an expander object via `<<`:
242
+
243
+ ``` ruby
244
+ require 'mustermann'
245
+
246
+ expander = Mustermann::Expander.new
247
+ expander << "/users/:user_id"
248
+ expander << "/pages/:page_id"
249
+
250
+ expander.expand(user_id: 15) # => "/users/15"
251
+ expander.expand(page_id: 58) # => "/pages/58"
252
+ ```
253
+
254
+ You can set pattern options when creating the expander:
255
+
256
+ ``` ruby
257
+ require 'mustermann'
258
+
259
+ expander = Mustermann::Expander.new(type: :template)
260
+ expander << "/users/{user_id}"
261
+ expander << "/pages/{page_id}"
262
+ ```
263
+
264
+ Additionally, it is possible to combine patterns of different types:
265
+
266
+ ``` ruby
267
+ require 'mustermann'
268
+
269
+ expander = Mustermann::Expander.new
270
+ expander << Mustermann.new("/users/{user_id}", type: :template)
271
+ expander << Mustermann.new("/pages/:page_id", type: :rails)
272
+ ```
273
+
274
+ ### Handling Additional Values
275
+
276
+ The handling of additional values passed in to `expand` can be changed by setting the `additional_values` option:
277
+
278
+ ``` ruby
279
+ require 'mustermann'
280
+
281
+ expander = Mustermann::Expander.new("/:slug", additional_values: :raise)
282
+ expander.expand(slug: "foo", value: "bar") # raises Mustermann::ExpandError
283
+
284
+ expander = Mustermann::Expander.new("/:slug", additional_values: :ignore)
285
+ expander.expand(slug: "foo", value: "bar") # => "/foo"
286
+
287
+ expander = Mustermann::Expander.new("/:slug", additional_values: :append)
288
+ expander.expand(slug: "foo", value: "bar") # => "/foo?value=bar"
289
+ ```
290
+
291
+ It is also possible to pass this directly to the `expand` call:
292
+
293
+ ``` ruby
294
+ require 'mustermann'
295
+
296
+ pattern = Mustermann.new('/:slug')
297
+ pattern.expand(:append, slug: "foo", value: "bar") # => "/foo?value=bar"
298
+ ```
299
+
300
+ <a name="-generating-templates"></a>
301
+ ## Generating Templates
302
+
303
+ You can generate a list of URI templates that correspond to a Mustermann pattern (it is a list rather than a single template, as most pattern types are significantly more expressive than URI templates).
304
+
305
+ This comes in quite handy since URI templates are not made for pattern matching. That way you can easily use a more precise template syntax and have it automatically generate hypermedia links for you.
306
+
307
+ Template generation is supported by almost all patterns (notable exceptions are `shell`, `regexp` and `simple` patterns).
308
+
309
+ ``` ruby
310
+ require 'mustermann'
311
+
312
+ Mustermann.new("/:name").to_templates # => ["/{name}"]
313
+ Mustermann.new("/:foo(@:bar)?/*baz").to_templates # => ["/{foo}@{bar}/{+baz}", "/{foo}/{+baz}"]
314
+ Mustermann.new("/{name}", type: :template).to_templates # => ["/{name}"
315
+ ```
316
+
317
+ Union Composite patterns (with the | operator) support template generation if all patterns they are composed of also support it.
318
+
319
+ ``` ruby
320
+ require 'mustermann'
321
+
322
+ pattern = Mustermann.new('/:name')
323
+ pattern |= Mustermann.new('/{name}', type: :template)
324
+ pattern |= Mustermann.new('/example/*nested')
325
+ pattern.to_templates # => ["/{name}", "/example/{+nested}"]
326
+ ```
327
+
328
+ If accepting arbitrary patterns, you can and should use `respond_to?` to check feature availability.
329
+
330
+ ``` ruby
331
+ if pattern.respond_to? :to_templates
332
+ pattern.to_templates
333
+ else
334
+ warn "does not support template generation"
335
+ end
336
+ ```
337
+
338
+ <a name="-proc-look-alike"></a>
339
+ ## Proc Look Alike
340
+
341
+ Patterns implement `to_proc`:
342
+
343
+ ``` ruby
344
+ require 'mustermann'
345
+ pattern = Mustermann.new('/foo')
346
+ callback = pattern.to_proc # => #<Proc>
347
+
348
+ callback.call('/foo') # => true
349
+ callback.call('/bar') # => false
350
+ ```
351
+
352
+ They can therefore be easily passed to methods expecting a block:
353
+
354
+ ``` ruby
355
+ require 'mustermann'
356
+
357
+ list = ["foo", "example@email.com", "bar"]
358
+ pattern = Mustermann.new(":name@:domain.:tld")
359
+ email = list.detect(&pattern) # => "example@email.com"
360
+ ```
361
+
362
+ <a name="-mapper"></a>
363
+ ## Mapper
364
+
365
+
366
+ You can use a mapper to transform strings according to two or more mappings:
367
+
368
+ ``` 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
+ ```
376
+
377
+ <a name="-sinatra-integration"></a>
378
+ ## Sinatra Integration
379
+
380
+ All patterns implement `match`, which means they can be dropped into Sinatra and other Rack routers:
381
+
382
+ ``` ruby
383
+ require 'sinatra'
384
+ require 'mustermann'
385
+
386
+ get Mustermann.new('/:foo') do
387
+ params[:foo]
388
+ end
389
+ ```
390
+
391
+ In fact, since using this with Sinatra is the main use case, it comes with a build-in extension for **Sinatra 1.x**.
392
+
393
+ ``` ruby
394
+ require 'sinatra'
395
+ require 'mustermann'
396
+
397
+ register Mustermann
398
+
399
+ # this will use Mustermann rather than the built-in pattern matching
400
+ get '/:slug(.ext)?' do
401
+ params[:slug]
402
+ end
403
+ ```
404
+
405
+ ### Configuration
406
+
407
+ You can change what pattern type you want to use for your app via the `pattern` option:
408
+
409
+ ``` ruby
410
+ require 'sinatra/base'
411
+ require 'mustermann'
412
+
413
+ class MyApp < Sinatra::Base
414
+ register Mustermann
415
+ set :pattern, type: :shell
416
+
417
+ get '/images/*.png' do
418
+ send_file request.path_info
419
+ end
420
+
421
+ get '/index{.htm,.html,}' do
422
+ erb :index
423
+ end
424
+ end
425
+ ```
426
+
427
+ You can use the same setting for options:
428
+
429
+ ``` ruby
430
+ require 'sinatra'
431
+ require 'mustermann'
432
+
433
+ register Mustermann
434
+ set :pattern, capture: { ext: %w[png jpg html txt] }
435
+
436
+ get '/:slug(.:ext)?' do
437
+ # slug will be 'foo' for '/foo.png'
438
+ # slug will be 'foo.bar' for '/foo.bar'
439
+ # slug will be 'foo.bar' for '/foo.bar.html'
440
+ params[:slug]
441
+ end
442
+ ```
443
+
444
+ It is also possible to pass in options to a specific route:
445
+
446
+ ``` ruby
447
+ require 'sinatra'
448
+ require 'mustermann'
449
+
450
+ register Mustermann
451
+
452
+ get '/:slug(.:ext)?', pattern: { greedy: false } do
453
+ # slug will be 'foo' for '/foo.png'
454
+ # slug will be 'foo' for '/foo.bar'
455
+ # slug will be 'foo' for '/foo.bar.html'
456
+ params[:slug]
457
+ end
458
+ ```
459
+
460
+ Of course, all of the above can be combined.
461
+ Moreover, the `capture` and the `except` option can be passed to route directly.
462
+ And yes, this also works with `before` and `after` filters.
463
+
464
+ ``` ruby
465
+ require 'sinatra/base'
466
+ require 'sinatra/respond_with'
467
+ require 'mustermann'
468
+
469
+ class MyApp < Sinatra::Base
470
+ register Mustermann, Sinatra::RespondWith
471
+ set :pattern, capture: { id: /\d+/ } # id will only match digits
472
+
473
+ # only capture extensions known to Rack
474
+ before '*:ext', capture: Rack::Mime::MIME_TYPES.keys do
475
+ content_type params[:ext] # set Content-Type
476
+ request.path_info = params[:splat].first # drop the extension
477
+ end
478
+
479
+ get '/:id' do
480
+ not_found unless page = Page.find params[:id]
481
+ respond_with(page)
482
+ end
483
+ end
484
+ ```
485
+
486
+ ### Why would I want this?
487
+
488
+ * It gives you fine grained control over the pattern matching
489
+ * Allows you to use different pattern styles in your app
490
+ * The default is more robust and powerful than the built-in patterns
491
+ * Sinatra 2.0 will use Mustermann internally
492
+ * Better exceptions for broken route syntax
493
+
494
+ ### Why not include this in Sinatra 1.x?
495
+
496
+ * It would introduce breaking changes, even though these would be minor
497
+ * Like Sinatra 2.0, Mustermann requires Ruby 2.0 or newer
498
+
499
+ <a name="-duck-typing"></a>
500
+ ## Duck Typing
501
+
502
+ <a name="-duck-typing-to-pattern"></a>
503
+ ### `to_pattern`
504
+
505
+ All methods converting string input to pattern objects will also accept any arbitrary object that implements `to_pattern`:
506
+
507
+ ``` ruby
508
+ require 'mustermann'
509
+
510
+ class MyObject
511
+ def to_pattern(**options)
512
+ Mustermann.new("/foo", **options)
513
+ end
514
+ end
515
+
516
+ object = MyObject.new
517
+ Mustermann.new(object, type: :rails) # => #<Mustermann::Rails:"/foo">
518
+ ```
519
+
520
+ 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:
521
+
522
+ ``` ruby
523
+ require 'mustermann/to_pattern'
524
+
525
+ "/foo".to_pattern # => #<Mustermann::Sinatra:"/foo">
526
+ "/foo".to_pattern(type: :rails) # => #<Mustermann::Rails:"/foo">
527
+ %r{/foo}.to_pattern # => #<Mustermann::Regular:"\\/foo">
528
+ "/foo".to_pattern.to_pattern # => #<Mustermann::Sinatra:"/foo">
529
+ ```
530
+
531
+ You can also use the `Mustermann::ToPattern` mixin to easily add `to_pattern` to your own objects:
532
+
533
+ ``` ruby
534
+ require 'mustermann/to_pattern'
535
+
536
+ class MyObject
537
+ include Mustermann::ToPattern
538
+
539
+ def to_s
540
+ "/foo"
541
+ end
542
+ end
543
+
544
+ MyObject.new.to_pattern # => #<Mustermann::Sinatra:"/foo">
545
+ ```
546
+
547
+ <a name="-duck-typing-respond-to"></a>
548
+ ### `respond_to?`
549
+
550
+ You can and should use `respond_to?` to check if a pattern supports certain features.
551
+
552
+ ``` ruby
553
+ require 'mustermann'
554
+ pattern = Mustermann.new("/")
555
+
556
+ puts "supports expanding" if pattern.respond_to? :expand
557
+ puts "supports generating templates" if pattern.respond_to? :to_templates
558
+ ```
559
+
560
+ Alternatively, you can handle a `NotImplementedError` raised from such a method.
561
+
562
+ ``` ruby
563
+ require 'mustermann'
564
+ pattern = Mustermann.new("/")
565
+
566
+ begin
567
+ p pattern.to_templates
568
+ rescue NotImplementedError
569
+ puts "does not support generating templates"
570
+ end
571
+ ```
572
+
573
+ This behavior corresponds to what Ruby does, for instance for [`fork`](http://ruby-doc.org/core-2.1.1/NotImplementedError.html).
574
+
575
+ <a name="-available-options"></a>
576
+ ## Available Options
577
+
578
+ <a name="-available-options--capture"></a>
579
+ ### `capture`
580
+
581
+ Supported by: All types except `identity`, `shell` and `simple` patterns.
582
+
583
+ Most pattern types support changing the strings named captures will match via the `capture` options.
584
+
585
+ Possible values for a capture:
586
+
587
+ ``` ruby
588
+ # String: Matches the given string (or any URI encoded version of it)
589
+ Mustermann.new('/index.:ext', capture: 'png')
590
+
591
+ # Regexp: Matches the Regular expression
592
+ Mustermann.new('/:id', capture: /\d+/)
593
+
594
+ # Symbol: Matches POSIX character class
595
+ Mustermann.new('/:id', capture: :digit)
596
+
597
+ # Array of the above: Matches anything in the array
598
+ Mustermann.new('/:id_or_slug', capture: [/\d+/, :word])
599
+
600
+ # Hash of the above: Looks up the hash entry by capture name and uses value for matching
601
+ Mustermann.new('/:id.:ext', capture: { id: /\d+/, ext: ['png', 'jpg'] })
602
+ ```
603
+
604
+ Available POSIX character classes are: `:alnum`, `:alpha`, `:blank`, `:cntrl`, `:digit`, `:graph`, `:lower`, `:print`, `:punct`, `:space`, `:upper`, `:xdigit`, `:word` and `:ascii`.
605
+
606
+ <a name="-available-options--except"></a>
607
+ ### `except`
608
+
609
+ Supported by: All types except `identity`, `shell` and `simple` patterns.
610
+
611
+ Given you supply a second pattern via the except option. Any string that would match the primary pattern but also matches the except pattern will not result in a successful match. Feel free to read that again. Or just take a look at this example:
612
+
613
+ ``` ruby
614
+ pattern = Mustermann.new('/auth/*', except: '/auth/login')
615
+ pattern === '/auth/dunno' # => true
616
+ pattern === '/auth/login' # => false
617
+ ```
618
+
619
+ Now, as said above, `except` treats the value as a pattern:
620
+
621
+ ``` ruby
622
+ pattern = Mustermann.new('/*anything', type: :rails, except: '/*anything.png')
623
+ pattern === '/foo.jpg' # => true
624
+ pattern === '/foo.png' # => false
625
+ ```
626
+
627
+ <a name="-available-options--greedy"></a>
628
+ ### `greedy`
629
+
630
+ Supported by: All types except `identity` and `shell` patterns.
631
+ Default value: `true`
632
+
633
+ **Simple** patterns are greedy, meaning that for the pattern `:foo:bar?`, everything will be captured as `foo`, `bar` will always be `nil`. By setting `greedy` to `false`, `foo` will capture as little as possible (which in this case would only be the first letter), leaving the rest to `bar`.
634
+
635
+ **All other** supported patterns are semi-greedy. This means `:foo(.:bar)?` (`:foo(.:bar)` for Rails patterns) will capture everything before the *last* dot as `foo`. For these two pattern types, you can switch into non-greedy mode by setting the `greedy` option to false. In that case `foo` will only capture the part before the *first* dot.
636
+
637
+ Semi-greedy behavior is not specific to dots, it works with all characters or strings. For instance, `:a(foo:b)` will capture everything before the *last* `foo` as `a`, and `:foo(bar)?` will not capture a `bar` at the end.
638
+
639
+ ``` ruby
640
+ pattern = Mustermann.new(':a.:b', greedy: true)
641
+ pattern.match('a.b.c.d') # => #<MatchData a:"a.b.c" b:"d">
642
+
643
+ pattern = Mustermann.new(':a.:b', greedy: false)
644
+ pattern.match('a.b.c.d') # => #<MatchData a:"a" b:"b.c.d">
645
+ ```
646
+
647
+ <a name="-available-options--space_matches_plus"></a>
648
+ ### `space_matches_plus`
649
+
650
+ Supported by: All types except `identity`, `regexp` and `shell` patterns.
651
+ Default value: `true`
652
+
653
+ Most pattern types will by default also match a plus sign for a space in the pattern:
654
+
655
+ ``` ruby
656
+ Mustermann.new('a b') === 'a+b' # => true
657
+ ```
658
+
659
+ You can disable this behavior via `space_matches_plus`:
660
+
661
+ ``` ruby
662
+ Mustermann.new('a b', space_matches_plus: false) === 'a+b' # => false
663
+ ```
664
+
665
+ **Important:** This setting has no effect on captures, captures will always keep plus signs as plus sings and spaces as spaces:
666
+
667
+ ``` ruby
668
+ pattern = Mustermann.new(':x')
669
+ pattern.match('a b')[:x] # => 'a b'
670
+ pattern.match('a+b')[:x] # => 'a+b'
671
+ ````
672
+
673
+ <a name="-available-options--uri_decode"></a>
674
+ ### `uri_decode`
675
+
676
+ Supported by all pattern types.
677
+ Default value: `true`
678
+
679
+ Usually, characters in the pattern will also match the URI encoded version of these characters:
680
+
681
+ ``` ruby
682
+ Mustermann.new('a b') === 'a b' # => true
683
+ Mustermann.new('a b') === 'a%20b' # => true
684
+ ```
685
+
686
+ You can avoid this by setting `uri_decode` to `false`:
687
+
688
+ ``` ruby
689
+ Mustermann.new('a b', uri_decode: false) === 'a b' # => true
690
+ Mustermann.new('a b', uri_decode: false) === 'a%20b' # => false
691
+ ```
692
+
693
+ <a name="-available-options--ignore_unknown_options"></a>
694
+ ### `ignore_unknown_options`
695
+
696
+ Supported by all patterns.
697
+ Default value: `false`
698
+
699
+ If you pass an option in that is not supported by the specific pattern type, Mustermann will raise an `ArgumentError`.
700
+ By setting `ignore_unknown_options` to `true`, it will happily ignore the option.
701
+
702
+ <a name="-performance"></a>
703
+ ## Performance
704
+
705
+ 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.
706
+
707
+ 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.
708
+
709
+ ### String Matching
710
+
711
+ When using a pattern instead of a regular expression for string matching, performance will usually be comparable.
712
+
713
+ 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).
714
+
715
+ 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).
716
+
717
+ ### Expanding
718
+
719
+ Pattern expansion significantly outperforms other, widely used Ruby tools for generating URLs from URL patterns in most use cases.
720
+
721
+ This comes with a few trade-offs:
722
+
723
+ * 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.
724
+ * 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)
725
+ * 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.
726
+ * Partial expansion is (currently) not supported.
727
+
728
+ ## Details on Pattern Types
729
+
730
+ <a name="-identity-pattern"></a>
731
+ ### `identity`
732
+
733
+ **Supported options:**
734
+ [`uri_decode`](#-available-options--uri_decode),
735
+ [`ignore_unknown_options`](#-available-options--ignore_unknown_options).
33
736
 
34
737
  <table>
35
738
  <thead>
36
739
  <tr>
37
- <th>Type</th>
38
- <th>Example</th>
39
- <th>Compatible with</th>
40
- <th>Notes</th>
740
+ <th>Syntax Element</th>
741
+ <th>Description</th>
41
742
  </tr>
42
743
  </thead>
43
744
  <tbody>
44
745
  <tr>
45
- <th><a href="mustermann-contrib/README.md#-mustermann-cake"><tt>cake</tt></a></th>
46
- <td><tt>/:prefix/**</tt></td>
47
- <td><a href="http://cakephp.org/">CakePHP</a></td>
48
- <td></td>
746
+ <td><i>any character</i></td>
747
+ <td>Matches exactly that character or a URI escaped version of it.</td>
49
748
  </tr>
749
+ </tbody>
750
+ </table>
751
+
752
+ <a name="-regexp-pattern"></a>
753
+ ### `regexp`
754
+
755
+ **Supported options:**
756
+ [`uri_decode`](#-available-options--uri_decode),
757
+ [`ignore_unknown_options`](#-available-options--ignore_unknown_options), `check_anchors`.
758
+
759
+ The pattern string (or actual Regexp instance) should not contain anchors (`^` outside of square brackets, `$`, `\A`, `\z`, or `\Z`).
760
+ Anchors will be injected where necessary by Mustermann.
761
+
762
+ By default, Mustermann will raise a `Mustermann::CompileError` if an anchor is encountered.
763
+ If you still want it to contain anchors at your own risk, set the `check_anchors` option to `false`.
764
+
765
+ Using anchors will break [peeking](#-peeking) and [concatenation](#-concatenation).
766
+
767
+ <table>
768
+ <thead>
50
769
  <tr>
51
- <th><a href="mustermann-contrib/README.md#-mustermann-express"><tt>express</tt></a></th>
52
- <td><tt>/:prefix+/:id(\d+)</tt></td>
53
- <td>
54
- <a href="http://expressjs.com/">Express</a>,
55
- <a href="https://pillarjs.github.io/">pillar.js</a>
56
- </td>
57
- <td></td>
770
+ <th>Syntax Element</th>
771
+ <th>Description</th>
58
772
  </tr>
773
+ </thead>
774
+ <tbody>
59
775
  <tr>
60
- <th><a href="mustermann-contrib/README.md#-mustermann-flask"><tt>flask</tt></a></th>
61
- <td><tt>/&lt;prefix&gt;/&lt;int:id&gt;</tt></td>
62
- <td>
63
- <a href="http://flask.pocoo.org/">Flask</a>,
64
- <a href="http://werkzeug.pocoo.org/">Werkzeug</a>
65
- </td>
66
- <td></td>
776
+ <td><i>any string</i></td>
777
+ <td>Interpreted as regular expression.</td>
778
+ </tr>
779
+ </tbody>
780
+ </table>
781
+
782
+ <a name="-sinatra-pattern"></a>
783
+ ### `sinatra`
784
+
785
+ **Supported options:**
786
+ [`capture`](#-available-options--capture),
787
+ [`except`](#-available-options--except),
788
+ [`greedy`](#-available-options--greedy),
789
+ [`space_matches_plus`](#-available-options--space_matches_plus),
790
+ [`uri_decode`](#-available-options--uri_decode),
791
+ [`ignore_unknown_options`](#-available-options--ignore_unknown_options).
792
+
793
+ <table>
794
+ <thead>
795
+ <tr>
796
+ <th>Syntax Element</th>
797
+ <th>Description</th>
67
798
  </tr>
799
+ </thead>
800
+ <tbody>
68
801
  <tr>
69
- <th><a href="mustermann/README.md#-identity-pattern"><tt>identity</tt></a></th>
70
- <td><tt>/image.png</tt></td>
71
- <td>any software using strings</td>
802
+ <td><b>:</b><i>name</i> <i><b>or</b></i> <b>&#123;</b><i>name</i><b>&#125;</b></td>
72
803
  <td>
73
- Exact string matching (no parameter parsing).
804
+ Captures anything but a forward slash in a semi-greedy fashion. Capture is named <i>name</i>.
805
+ Capture behavior can be modified with <tt>capture</tt> and <tt>greedy</tt> option.
74
806
  </td>
75
807
  </tr>
76
808
  <tr>
77
- <th><a href="mustermann-contrib/README.md#-mustermann-pyramid"><tt>pyramid</tt></a></th>
78
- <td><tt>/{prefix:.*}/{id}</tt></td>
809
+ <td><b>*</b><i>name</i> <i><b>or</b></i> <b>&#123;+</b><i>name</i><b>&#125;</b></td>
79
810
  <td>
80
- <a href="http://www.pylonsproject.org/projects/pyramid/about">Pyramid</a>,
81
- <a href="http://www.pylonsproject.org/projects/pylons-framework/about">Pylons</a>
811
+ Captures anything in a non-greedy fashion. Capture is named <i>name</i>.
82
812
  </td>
83
- <td></td>
84
813
  </tr>
85
814
  <tr>
86
- <th><a href="mustermann-contrib/README.md#-mustermann-rails"><tt>rails</tt></a></th>
87
- <td><tt>/:slug(.:ext)</tt></td>
815
+ <td><b>*</b> <i><b>or</b></i> <b>&#123;+splat&#125;</b></td>
88
816
  <td>
89
- <a href="http://rubyonrails.org/">Ruby on Rails</a>,
90
- <a href="https://github.com/rails/journey">Journey</a>,
91
- <a href="https://github.com/joshbuddy/http_router">HTTP Router</a>,
92
- <a href="http://hanamirb.org">Hanami</a>,
93
- <a href="http://www.scalatra.org/">Scalatra</a> (if <a href="http://www.scalatra.org/2.3/guides/http/routes.html#toc_248">configured</a>),
94
- <a href="https://github.com/alisnic/nyny">NYNY</a></td>
95
- <td></td>
817
+ Captures anything in a non-greedy fashion. Capture is named splat.
818
+ It is always an array of captures, as you can use it more than once in a pattern.
819
+ </td>
96
820
  </tr>
97
821
  <tr>
98
- <th><a href="mustermann/README.md#-regexp-pattern"><tt>regexp</tt></a></th>
99
- <td><tt>/(?&lt;slug&gt;[^\/]+)</tt></td>
822
+ <td><b>(</b><i>expression</i><b>)</b></td>
100
823
  <td>
101
- <a href="http://www.geocities.jp/kosako3/oniguruma/">Oniguruma</a>,
102
- <a href="https://github.com/k-takata/Onigmo">Onigmo<a>,
103
- regular expressions
824
+ Enclosed <i>expression</i> is a group. Useful when combined with <tt>?</tt> to make it optional,
825
+ or to separate two elements that would otherwise be parsed as one.
104
826
  </td>
827
+ </tr>
828
+ <tr>
829
+ <td><i>expression</i><b>|</b><i>expression</i><b>|</b><i>...</i></td>
105
830
  <td>
106
- Created when you pass a regexp to <tt>Mustermann.new</tt>.<br>
107
- Does not support expanding or generating templates.
831
+ Will match anything matching the nested expressions. May contain any other syntax element, including captures.
108
832
  </td>
109
833
  </tr>
110
834
  <tr>
111
- <th><a href="mustermann-contrib/README.md#-mustermann-shell"><tt>shell</tt></a></th>
112
- <td><tt>/*.{png,jpg}</tt></td>
113
- <td>Unix Shell (bash, zsh)</td>
114
- <td>Does not support expanding or generating templates.</td>
835
+ <td><i>x</i><b>?</b></td>
836
+ <td>Makes <i>x</i> optional. For instance, <tt>(foo)?</tt> matches <tt>foo</tt> or an empty string.</td>
115
837
  </tr>
116
838
  <tr>
117
- <th><a href="mustermann-contrib/README.md#-mustermann-simple"><tt>simple</tt></a></th>
118
- <td><tt>/:slug.:ext</tt></td>
119
- <td>
120
- <a href="http://www.sinatrarb.com/">Sinatra</a> (1.x),
121
- <a href="http://www.scalatra.org/">Scalatra</a>,
122
- <a href="http://perldancer.org/">Dancer</a>,
123
- <a href="http://twitter.github.io/finatra/">Finatra</a>,
124
- <a href="http://sparkjava.com/">Spark</a>,
125
- <a href="https://github.com/rc1/RCRouter">RCRouter</a>,
126
- <a href="https://github.com/kissjs/kick.js">kick.js</a>
127
- </td>
839
+ <td><b>/</b></td>
128
840
  <td>
129
- Implementation is a direct copy from Sinatra 1.3.<br>
130
- It is the predecessor of <tt>sinatra</tt>.
131
- Does not support expanding or generating templates.
841
+ Matches forward slash. Does not match URI encoded version of forward slash.
132
842
  </td>
133
843
  </tr>
134
844
  <tr>
135
- <th><a href="mustermann/README.md#-sinatra-pattern"><tt>sinatra</tt></a></th>
136
- <td><tt>/:slug(.:ext)?</tt></td>
137
- <td>
138
- <a href="http://www.sinatrarb.com/">Sinatra</a> (2.x),
139
- <a href="http://padrinorb.com/">Padrino</a> (>= 0.13.0),
140
- <a href="https://github.com/namusyaka/pendragon">Pendragon</a>,
141
- <a href="https://github.com/kenichi/angelo">Angelo</a>
142
- </td>
143
- <td>
144
- <u>This is the default</u> and the only type "invented here".<br>
145
- It is a superset of <tt>simple</tt> and has a common subset with
146
- <tt>template</tt> (and others).
147
- </td>
845
+ <td><b>\</b><i>x</i></td>
846
+ <td>Matches <i>x</i> or URI encoded version of <i>x</i>. For instance <tt>\*</tt> matches <tt>*</tt>.</td>
148
847
  </tr>
149
848
  <tr>
150
- <th><a href="mustermann-contrib/README.md#-mustermann-uri-template"><tt>uri-template</tt></a></th>
151
- <td><tt>/{+pre}/{page}{?q}</tt></td>
152
- <td>
153
- <a href="https://tools.ietf.org/html/rfc6570">RFC 6570</a>,
154
- <a href="http://jsonapi.org/">JSON API</a>,
155
- <a href="http://tools.ietf.org/html/draft-nottingham-json-home-02">JSON Home Documents</a>
156
- and <a href="https://code.google.com/p/uri-templates/wiki/Implementations">many more</a>
157
- </td>
158
- <td>Standardized URI templates, can be <a href="mustermann/README.md#-generating-templates">generated</a> from most other types.</td>
849
+ <td><i>any other character</i></td>
850
+ <td>Matches exactly that character or a URI encoded version of it.</td>
159
851
  </tr>
160
852
  </tbody>
161
853
  </table>
162
-
163
- Any software using Mustermann is obviously compatible with at least one of the above.
164
-
165
- ## Requirements
166
-
167
- Mustermann depends on [tool](https://github.com/rkh/tool) (which has been extracted from Mustermann and Sinatra 2.0), and a Ruby 2.2 compatible Ruby implementation.
168
-
169
- It is known to work on MRI 2.2.
170
-
171
- JRuby will hopefully be supported with the release of **JRuby 9000**.
172
-
173
- **Rubinius** is not currently supported. As of Rubinius 2.3.1, a large portion of the specs pass (3870 out of 3943), but certain parts are not working yet.
174
-
175
- If you need Ruby 1.9 support, you might be able to use the **unofficial** [mustermann19](https://rubygems.org/gems/mustermann19) gem based on [namusyaka's fork](https://github.com/namusyaka/mustermann19).
176
-
177
- ## Release History
178
-
179
- Mustermann follows [Semantic Versioning 2.0](http://semver.org/). Anything documented in the README or via YARD and not declared private is part of the public API.
180
-
181
- ### Stable Releases
182
-
183
- * **Mustermann 1.0.2** (2017-02-13)
184
- * Look ahead same patterns as its own when concatenation. Fixes [sinatra/sinatra#1361](https://github.com/sinatra/sinatra/issues/1361) [@namusyaka](https://github.com/namusyaka)
185
- * Improve development support and documentation. [@EdwardBetts](https://github.com/EdwardBetts), [@284km](https://github.com/284km), [@yb66](https://github.com/yb66) and [@garybernhardt](https://github.com/garybernhardt)
186
-
187
- * **Mustermann 1.0.1** (2017-08-26)
188
- #### Docs
189
- * Updating readme to list Ruby 2.2 as minimum [commit](https://github.com/sinatra/mustermann/commit/7c65d9637ed81c194e3d05f0ccf3cfe76f0cf53e) (@cassidycodes)
190
- * Fix rendering of HTML table [commit](https://github.com/sinatra/mustermann/commit/119a61f0e589cb9e917d8c901800a202bb66ff3b) (@stevenwilkin)
191
- * Update summary and description in gemspec file. [commit](https://github.com/sinatra/mustermann/commit/04de221a809527c2be8c3f08c40a4fcd53f2bd53) (@junaruga)
192
- #### Fixes
193
- * avoid infinite loop by removing comments when receiving extended regexp [commit](https://github.com/sinatra/mustermann/commit/fa20301167e1b22882415f1181c5e4e2d76b6ac6) (@namusyaka)
194
- * avoid unintended conflict of namespace [commit](https://github.com/sinatra/mustermann/commit/d3c9531d372522d693fa5f768f13dbaa1d881d88) (@namusyaka)
195
- * use Regexp#source instead of Regexp#inspect [commit](https://github.com/sinatra/mustermann/pull/73/commits/e9213748bda1773b1ad9838ef57a296f92c471e7) (@namusyaka)
196
-
197
- * **Mustermann 1.0.0** (2017-03-05)
198
- * First stable release.
199
- * Includes `mustermann`, and `mustermann-contrib` gems
200
- * Sinatra patterns: Allow | outside of parens.
201
- * Add concatenation support (`Mustermann::Pattern#+`).
202
- * `Mustermann::Sinatra#|` may now generate a Sinatra pattern instead of a real composite.
203
- * Add syntax highlighting support for composite patterns.
204
- * Remove routers (they were out of scope for the main gem).
205
- * Rails patterns: Add Rails 5.0 compatibility mode, make it default.
206
- * Moved `tool` gem `EqualityMap` to `Mustermann::EqualityMap` in core
207
- * Improve documentation.
208
-
209
- ### Development Releases
210
-
211
- * **Mustermann 0.4.0** (2014-11-26)
212
- * More Infos:
213
- [RubyGems.org](https://rubygems.org/gems/mustermann/versions/0.4.0),
214
- [RubyDoc.info](http://www.rubydoc.info/gems/mustermann/0.4.0/frames),
215
- [GitHub.com](https://github.com/rkh/mustermann/tree/v0.4.0)
216
- * Split into multiple gems.
217
- * Add `Pattern#to_proc`.
218
- * Add `Pattern#|`, `Pattern#&` and `Pattern#^`.
219
- * Add `Pattern#peek`, `Pattern#peek_size`, `Pattern#peek_match` and `Pattern#peek_params`.
220
- * Add `Mustermann::StringScanner`.
221
- * Add `Pattern#to_templates`.
222
- * Add `|` syntax to `sinatra` templates.
223
- * Add template style placeholders to `sinatra` templates.
224
- * Add `cake`, `express`, `flask` and `pyramid` patterns.
225
- * Allow passing in additional value behavior directly to `Pattern#expand`.
226
- * Fix expanding of multiple splats.
227
- * Add expanding to `identity` patterns.
228
- * Add `mustermann-fileutils`.
229
- * Make expander accept hashes with string keys.
230
- * Allow named splats to be named splat.
231
- * Support multiple Rails versions.
232
- * Type option can be set to nil to get the default type.
233
- * Add `mustermann-visualizer`.
234
- * **Mustermann 0.3.1** (2014-09-12)
235
- * More Infos:
236
- [RubyGems.org](https://rubygems.org/gems/mustermann/versions/0.3.1),
237
- [RubyDoc.info](http://www.rubydoc.info/gems/mustermann/0.3.1/frames),
238
- [GitHub.com](https://github.com/rkh/mustermann/tree/v0.3.1)
239
- * Speed up pattern generation and matching (thanks [Daniel Mendler](https://github.com/minad))
240
- * Small change so `Mustermann === Mustermann.new('...')` returns `true`.
241
- * **Mustermann 0.3.0** (2014-08-18)
242
- * More Infos:
243
- [RubyGems.org](https://rubygems.org/gems/mustermann/versions/0.3.0),
244
- [RubyDoc.info](http://www.rubydoc.info/gems/mustermann/0.3.0/frames),
245
- [GitHub.com](https://github.com/rkh/mustermann/tree/v0.3.0)
246
- * Add `regexp` pattern.
247
- * Add named splats to Sinatra patterns.
248
- * Add `Mustermann::Mapper`.
249
- * Improve duck typing support.
250
- * Improve documentation.
251
- * **Mustermann 0.2.0** (2013-08-24)
252
- * More Infos:
253
- [RubyGems.org](https://rubygems.org/gems/mustermann/versions/0.2.0),
254
- [RubyDoc.info](http://www.rubydoc.info/gems/mustermann/0.2.0/frames),
255
- [GitHub.com](https://github.com/rkh/mustermann/tree/v0.2.0)
256
- * Add first class expander objects.
257
- * Add params casting for expander.
258
- * Add simple router and rack router.
259
- * Add weak equality map to significantly improve performance.
260
- * Fix Ruby warnings.
261
- * Improve documentation.
262
- * Refactor pattern validation, AST transformations.
263
- * Increase test coverage (from 100%+ to 100%++).
264
- * Improve JRuby compatibility.
265
- * Work around bug in 2.0.0-p0.
266
- * **Mustermann 0.1.0** (2013-05-12)
267
- * More Infos:
268
- [RubyGems.org](https://rubygems.org/gems/mustermann/versions/0.1.0),
269
- [RubyDoc.info](http://www.rubydoc.info/gems/mustermann/0.1.0/frames),
270
- [GitHub.com](https://github.com/rkh/mustermann/tree/v0.1.0)
271
- * Add `Pattern#expand` for generating strings from patterns.
272
- * Add better internal API for working with the AST.
273
- * Improved documentation.
274
- * Avoids parsing the path twice when used as Sinatra extension.
275
- * Better exceptions for unknown pattern types.
276
- * Better handling of edge cases around extend.
277
- * More specs to ensure API stability.
278
- * Largely rework internals of Sinatra, Rails and Template patterns.
279
- * **Mustermann 0.0.1** (2013-04-27)
280
- * More Infos:
281
- [RubyGems.org](https://rubygems.org/gems/mustermann/versions/0.0.1),
282
- [RubyDoc.info](http://www.rubydoc.info/gems/mustermann/0.0.1/frames),
283
- [GitHub.com](https://github.com/rkh/mustermann/tree/v0.0.1)
284
- * Initial Release.