mustermann-contrib 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 +4 -4
- data/LICENSE +1 -2
- data/README.md +57 -776
- data/lib/mustermann/flask.rb +2 -2
- data/lib/mustermann/mapper.rb +88 -0
- data/lib/mustermann/pattern_cache.rb +50 -0
- data/lib/mustermann/shell.rb +0 -1
- data/lib/mustermann/to_pattern.rb +51 -0
- data/lib/mustermann/visualizer/pattern_extension.rb +0 -14
- metadata +15 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ba766f2be34c126a5c87154b9e9ff3e6d5f5e2f8080f2b29a30850f5634fa91d
|
|
4
|
+
data.tar.gz: 3a62549ac2e49145dca087f9b082fb1957d50293fadb3ef5c84911cdb43b80ee
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: acc416d7cbeddec35cad710634f66a77dc9adbc89a80d493fd6b6e99336c266dca4bc6ee2a9d09fdbf2e358fa6666303016750bd455c620f06381a5d55cf2eb3
|
|
7
|
+
data.tar.gz: 8bccefca2caf7829bf3aa2d8a57fcadf7bed1e4a0ae0d17142a241ba1ffa94d0fd63f01a1cf44f6d2816a446ad048090e20bfe85fd26ff7211f5725170ea0518
|
data/LICENSE
CHANGED
data/README.md
CHANGED
|
@@ -27,177 +27,13 @@ end
|
|
|
27
27
|
<a name="-mustermann-cake"></a>
|
|
28
28
|
# CakePHP Syntax for Mustermann
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
## Overview
|
|
33
|
-
|
|
34
|
-
**Supported options:**
|
|
35
|
-
`capture`, `except`, `greedy`, `space_matches_plus`, `uri_decode`, and `ignore_unknown_options`.
|
|
36
|
-
|
|
37
|
-
**External documentation:**
|
|
38
|
-
[CakePHP 2.0 Routing](http://book.cakephp.org/2.0/en/development/routing.html),
|
|
39
|
-
[CakePHP 3.0 Routing](http://book.cakephp.org/3.0/en/development/routing.html)
|
|
40
|
-
|
|
41
|
-
CakePHP patterns feature captures and unnamed splats. Captures are prefixed with a colon and splats are either a single asterisk (parsing segments into an array) or a double asterisk (parsing segments as a single string).
|
|
42
|
-
|
|
43
|
-
``` ruby
|
|
44
|
-
require 'mustermann/cake'
|
|
45
|
-
|
|
46
|
-
Mustermann.new('/:name/*', type: :cake).params('/a/b/c') # => { name: 'a', splat: ['b', 'c'] }
|
|
47
|
-
Mustermann.new('/:name/**', type: :cake).params('/a/b/c') # => { name: 'a', splat: 'b/c' }
|
|
48
|
-
|
|
49
|
-
pattern = Mustermann.new('/:name')
|
|
50
|
-
|
|
51
|
-
pattern.respond_to? :expand # => true
|
|
52
|
-
pattern.expand(name: 'foo') # => '/foo'
|
|
53
|
-
|
|
54
|
-
pattern.respond_to? :to_templates # => true
|
|
55
|
-
pattern.to_templates # => ['/{name}']
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## Syntax
|
|
59
|
-
|
|
60
|
-
<table>
|
|
61
|
-
<thead>
|
|
62
|
-
<tr>
|
|
63
|
-
<th>Syntax Element</th>
|
|
64
|
-
<th>Description</th>
|
|
65
|
-
</tr>
|
|
66
|
-
</thead>
|
|
67
|
-
<tbody>
|
|
68
|
-
<tr>
|
|
69
|
-
<td><b>:</b><i>name</i></td>
|
|
70
|
-
<td>
|
|
71
|
-
Captures anything but a forward slash in a semi-greedy fashion. Capture is named <i>name</i>.
|
|
72
|
-
Capture behavior can be modified with <tt>capture</tt> and <tt>greedy</tt> option.
|
|
73
|
-
</td>
|
|
74
|
-
</tr>
|
|
75
|
-
<tr>
|
|
76
|
-
<td><b>*</b></td>
|
|
77
|
-
<td>
|
|
78
|
-
Captures anything in a non-greedy fashion. Capture is named splat.
|
|
79
|
-
It is always an array of captures, as you can use it more than once in a pattern.
|
|
80
|
-
</td>
|
|
81
|
-
</tr>
|
|
82
|
-
<tr>
|
|
83
|
-
<td><b>**</b></td>
|
|
84
|
-
<td>
|
|
85
|
-
Captures anything in a non-greedy fashion. Capture is named splat.
|
|
86
|
-
It is always an array of captures, as you can use it more than once in a pattern.
|
|
87
|
-
The value matching a single <tt>**</tt> will be split at slashes when parsed into <tt>params</tt>.
|
|
88
|
-
</td>
|
|
89
|
-
</tr>
|
|
90
|
-
<tr>
|
|
91
|
-
<td><b>/</b></td>
|
|
92
|
-
<td>
|
|
93
|
-
Matches forward slash. Does not match URI encoded version of forward slash.
|
|
94
|
-
</td>
|
|
95
|
-
</tr>
|
|
96
|
-
<tr>
|
|
97
|
-
<td><i>any other character</i></td>
|
|
98
|
-
<td>Matches exactly that character or a URI encoded version of it.</td>
|
|
99
|
-
</tr>
|
|
100
|
-
</tbody>
|
|
101
|
-
</table>
|
|
30
|
+
See [docs/patterns/cake.md](../docs/patterns/cake.md).
|
|
102
31
|
|
|
103
32
|
|
|
104
33
|
<a name="-mustermann-express"></a>
|
|
105
34
|
# Express Syntax for Mustermann
|
|
106
35
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
## Overview
|
|
110
|
-
|
|
111
|
-
**Supported options:**
|
|
112
|
-
`capture`, `except`, `greedy`, `space_matches_plus`, `uri_decode`, and `ignore_unknown_options`.
|
|
113
|
-
|
|
114
|
-
**External documentation:**
|
|
115
|
-
[path-to-regexp](https://github.com/pillarjs/path-to-regexp#path-to-regexp),
|
|
116
|
-
[live demo](http://forbeslindesay.github.io/express-route-tester/)
|
|
117
|
-
|
|
118
|
-
Express patterns feature named captures (with repetition support via suffixes) that start with a colon and can have an optional regular expression constraint or unnamed captures that require a constraint.
|
|
119
|
-
|
|
120
|
-
``` ruby
|
|
121
|
-
require 'mustermann/express'
|
|
122
|
-
|
|
123
|
-
Mustermann.new('/:name/:rest+', type: :express).params('/a/b/c') # => { name: 'a', rest: 'b/c' }
|
|
124
|
-
|
|
125
|
-
pattern = Mustermann.new('/:name', type: :express)
|
|
126
|
-
|
|
127
|
-
pattern.respond_to? :expand # => true
|
|
128
|
-
pattern.expand(name: 'foo') # => '/foo'
|
|
129
|
-
|
|
130
|
-
pattern.respond_to? :to_templates # => true
|
|
131
|
-
pattern.to_templates # => ['/{name}']
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
## Syntax
|
|
135
|
-
|
|
136
|
-
<table>
|
|
137
|
-
<thead>
|
|
138
|
-
<tr>
|
|
139
|
-
<th>Syntax Element</th>
|
|
140
|
-
<th>Description</th>
|
|
141
|
-
</tr>
|
|
142
|
-
</thead>
|
|
143
|
-
<tbody>
|
|
144
|
-
<tr>
|
|
145
|
-
<td><b>:</b><i>name</i></td>
|
|
146
|
-
<td>
|
|
147
|
-
Captures anything but a forward slash in a semi-greedy fashion. Capture is named <i>name</i>.
|
|
148
|
-
Capture behavior can be modified with <tt>capture</tt> and <tt>greedy</tt> option.
|
|
149
|
-
</td>
|
|
150
|
-
</tr>
|
|
151
|
-
<tr>
|
|
152
|
-
<td><b>:</b><i>name</i><b>+</b></td>
|
|
153
|
-
<td>
|
|
154
|
-
Captures one or more segments (with segments being separated by forward slashes).
|
|
155
|
-
Capture is named <i>name</i>.
|
|
156
|
-
Capture behavior can be modified with <tt>capture</tt> option.
|
|
157
|
-
</td>
|
|
158
|
-
</tr>
|
|
159
|
-
<tr>
|
|
160
|
-
<td><b>:</b><i>name</i><b>*</b></td>
|
|
161
|
-
<td>
|
|
162
|
-
Captures zero or more segments (with segments being separated by forward slashes).
|
|
163
|
-
Capture is named <i>name</i>.
|
|
164
|
-
Capture behavior can be modified with <tt>capture</tt> option.
|
|
165
|
-
</td>
|
|
166
|
-
</tr>
|
|
167
|
-
<tr>
|
|
168
|
-
<td><b>:</b><i>name</i><b>?</b></td>
|
|
169
|
-
<td>
|
|
170
|
-
Captures anything but a forward slash in a semi-greedy fashion. Capture is named <i>name</i>.
|
|
171
|
-
Also matches an empty string.
|
|
172
|
-
Capture behavior can be modified with <tt>capture</tt> and <tt>greedy</tt> option.
|
|
173
|
-
</td>
|
|
174
|
-
</tr>
|
|
175
|
-
<tr>
|
|
176
|
-
<td><b>:</b><i>name</i><b>(</b><i>regexp</i><b>)</b></td>
|
|
177
|
-
<td>
|
|
178
|
-
Captures anything matching the <i>regexp</i> regular expression. Capture is named <i>name</i>.
|
|
179
|
-
Capture behavior can be modified with <tt>capture</tt>.
|
|
180
|
-
</td>
|
|
181
|
-
</tr>
|
|
182
|
-
<tr>
|
|
183
|
-
<td><b>(</b><i>regexp</i><b>)</b></td>
|
|
184
|
-
<td>
|
|
185
|
-
Captures anything matching the <i>regexp</i> regular expression. Capture is named splat.
|
|
186
|
-
Capture behavior can be modified with <tt>capture</tt>.
|
|
187
|
-
</td>
|
|
188
|
-
</tr>
|
|
189
|
-
<tr>
|
|
190
|
-
<td><b>/</b></td>
|
|
191
|
-
<td>
|
|
192
|
-
Matches forward slash. Does not match URI encoded version of forward slash.
|
|
193
|
-
</td>
|
|
194
|
-
</tr>
|
|
195
|
-
<tr>
|
|
196
|
-
<td><i>any other character</i></td>
|
|
197
|
-
<td>Matches exactly that character or a URI encoded version of it.</td>
|
|
198
|
-
</tr>
|
|
199
|
-
</tbody>
|
|
200
|
-
</table>
|
|
36
|
+
See [docs/patterns/express.md](../docs/patterns/express.md).
|
|
201
37
|
|
|
202
38
|
<a name="-mustermann-fileutils"></a>
|
|
203
39
|
# FileUtils for Mustermann
|
|
@@ -258,573 +94,72 @@ Mustermann::FileUtils.cp_r(':base.:ext' => ':base.bak.:ext')
|
|
|
258
94
|
Mustermann::FileUtils.ln_s('lib/:name.rb' => 'bin/:name')
|
|
259
95
|
```
|
|
260
96
|
|
|
261
|
-
<a name="-mustermann-
|
|
262
|
-
#
|
|
263
|
-
|
|
264
|
-
This gem implements the `flask` pattern type for Mustermann. It is compatible with [Flask](http://flask.pocoo.org/) and [Werkzeug](http://werkzeug.pocoo.org/).
|
|
97
|
+
<a name="-mustermann-mapper"></a>
|
|
98
|
+
# Mapper for Mustermann
|
|
265
99
|
|
|
266
100
|
## Overview
|
|
267
101
|
|
|
268
|
-
|
|
269
|
-
`capture`, `except`, `greedy`, `space_matches_plus`, `uri_decode`, `converters` and `ignore_unknown_options`
|
|
270
|
-
|
|
271
|
-
**External documentation:**
|
|
272
|
-
[Werkzeug: URL Routing](http://werkzeug.pocoo.org/docs/0.9/routing/)
|
|
102
|
+
`Mustermann::Mapper` transforms strings according to a set of pattern mappings. Each mapping pairs an input pattern (used to extract parameters) with one or more output patterns (used to expand the result). All mappings that match are applied in insertion order.
|
|
273
103
|
|
|
274
104
|
``` ruby
|
|
275
|
-
require 'mustermann/
|
|
276
|
-
|
|
277
|
-
Mustermann.new('/<prefix>/<path:page>', type: :flask).params('/a/b/c') # => { prefix: 'a', page: 'b/c' }
|
|
278
|
-
|
|
279
|
-
pattern = Mustermann.new('/<name>', type: :flask)
|
|
280
|
-
|
|
281
|
-
pattern.respond_to? :expand # => true
|
|
282
|
-
pattern.expand(name: 'foo') # => '/foo'
|
|
283
|
-
|
|
284
|
-
pattern.respond_to? :to_templates # => true
|
|
285
|
-
pattern.to_templates # => ['/{name}']
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
## Syntax
|
|
289
|
-
|
|
290
|
-
<table>
|
|
291
|
-
<thead>
|
|
292
|
-
<tr>
|
|
293
|
-
<th>Syntax Element</th>
|
|
294
|
-
<th>Description</th>
|
|
295
|
-
</tr>
|
|
296
|
-
</thead>
|
|
297
|
-
<tbody>
|
|
298
|
-
<tr>
|
|
299
|
-
<td><b><</b><i>name</i><b>></b></td>
|
|
300
|
-
<td>
|
|
301
|
-
Captures anything but a forward slash in a semi-greedy fashion. Capture is named <i>name</i>.
|
|
302
|
-
Capture behavior can be modified with <tt>capture</tt> and <tt>greedy</tt> option.
|
|
303
|
-
</td>
|
|
304
|
-
</tr>
|
|
305
|
-
<tr>
|
|
306
|
-
<td><b><</b><i>converter</i><b>:</b><i>name</i><b>></b></td>
|
|
307
|
-
<td>
|
|
308
|
-
Captures depending on the converter constraint. Capture is named <i>name</i>.
|
|
309
|
-
Capture behavior can be modified with <tt>capture</tt> and <tt>greedy</tt> option.
|
|
310
|
-
See below.
|
|
311
|
-
</td>
|
|
312
|
-
</tr>
|
|
313
|
-
<tr>
|
|
314
|
-
<td><b><</b><i>converter</i><b>(</b><i>arguments</i><b>):</b><i>name</i><b>></b></td>
|
|
315
|
-
<td>
|
|
316
|
-
Captures depending on the converter constraint. Capture is named <i>name</i>.
|
|
317
|
-
Capture behavior can be modified with <tt>capture</tt> and <tt>greedy</tt> option.
|
|
318
|
-
Arguments are separated by comma. An argument can be a simple string, a string enclosed
|
|
319
|
-
in single or double quotes, or a key value pair (keys and values being separated by an
|
|
320
|
-
equal sign). See below.
|
|
321
|
-
</td>
|
|
322
|
-
</tr>
|
|
323
|
-
<tr>
|
|
324
|
-
<td><b>/</b></td>
|
|
325
|
-
<td>
|
|
326
|
-
Matches forward slash. Does not match URI encoded version of forward slash.
|
|
327
|
-
</td>
|
|
328
|
-
</tr>
|
|
329
|
-
<tr>
|
|
330
|
-
<td><i>any other character</i></td>
|
|
331
|
-
<td>Matches exactly that character or a URI encoded version of it.</td>
|
|
332
|
-
</tr>
|
|
333
|
-
</tbody>
|
|
334
|
-
</table>
|
|
335
|
-
|
|
336
|
-
## Converters
|
|
337
|
-
|
|
338
|
-
### Builtin Converters
|
|
339
|
-
|
|
340
|
-
#### `string`
|
|
341
|
-
|
|
342
|
-
Possible arguments: `minlength`, `maxlength`, `length`
|
|
343
|
-
|
|
344
|
-
Captures anything but a forward slash in a semi-greedy fashion.
|
|
345
|
-
Capture behavior can be modified with <tt>capture</tt> and <tt>greedy</tt> option.
|
|
346
|
-
|
|
347
|
-
This is also the default converter.
|
|
348
|
-
|
|
349
|
-
Examples:
|
|
105
|
+
require 'mustermann/mapper'
|
|
350
106
|
|
|
107
|
+
mapper = Mustermann::Mapper.new("/:page(.:format)?" => ["/:page/view.:format", "/:page/view.html"])
|
|
108
|
+
mapper['/foo'] # => "/foo/view.html"
|
|
109
|
+
mapper['/foo.xml'] # => "/foo/view.xml"
|
|
110
|
+
mapper['/foo/bar'] # => "/foo/bar"
|
|
351
111
|
```
|
|
352
|
-
<name>
|
|
353
|
-
<string:name>
|
|
354
|
-
<string(minlength=3,maxlength=10):slug>
|
|
355
|
-
<string(length=10):slug>
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
#### `int`
|
|
359
|
-
|
|
360
|
-
Possible arguments: `min`, `max`, `fixed_digits`
|
|
361
112
|
|
|
362
|
-
|
|
363
|
-
Captured value will be converted to an Integer.
|
|
364
|
-
|
|
365
|
-
Examples:
|
|
366
|
-
|
|
367
|
-
```
|
|
368
|
-
<int:id>
|
|
369
|
-
<int(min=1,max=5):page>
|
|
370
|
-
<int(fixed_digits=16):uuid>
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
#### `float`
|
|
374
|
-
|
|
375
|
-
Possible arguments: `min`, `max`
|
|
376
|
-
|
|
377
|
-
Captures digits with a dot.
|
|
378
|
-
Captured value will be converted to an Float.
|
|
379
|
-
|
|
380
|
-
Examples:
|
|
381
|
-
|
|
382
|
-
```
|
|
383
|
-
<float:precision>
|
|
384
|
-
<float(min=0,max=1):precision>
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
#### `path`
|
|
388
|
-
|
|
389
|
-
Captures anything in a non-greedy fashion.
|
|
390
|
-
|
|
391
|
-
Example:
|
|
392
|
-
|
|
393
|
-
```
|
|
394
|
-
<path:rest>
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
#### `any`
|
|
398
|
-
|
|
399
|
-
Possible arguments: List of accepted strings.
|
|
400
|
-
|
|
401
|
-
Captures anything that matches one of the arguments exactly.
|
|
402
|
-
|
|
403
|
-
Example:
|
|
404
|
-
|
|
405
|
-
```
|
|
406
|
-
<any(home,search,contact):page>
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
### Custom Converters
|
|
410
|
-
|
|
411
|
-
[Flask patterns](#-pattern-details-flask) support registering custom converters.
|
|
412
|
-
|
|
413
|
-
A converter object may implement any of the following methods:
|
|
414
|
-
|
|
415
|
-
* `convert`: Should return a block converting a string value to whatever value should end up in the `params` hash.
|
|
416
|
-
* `constraint`: Should return a regular expression limiting which input string will match the capture.
|
|
417
|
-
* `new`: Returns an object that may respond to `convert` and/or `constraint` as described above. Any arguments used for the converter inside the pattern will be passed to `new`.
|
|
113
|
+
You can also pass additional values at conversion time to supplement or override captured parameters:
|
|
418
114
|
|
|
419
115
|
``` ruby
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
SimpleConverter = Struct.new(:constraint, :convert)
|
|
423
|
-
id_converter = SimpleConverter.new(/\d/, -> s { s.to_i })
|
|
424
|
-
|
|
425
|
-
class NumConverter
|
|
426
|
-
def initialize(base: 10)
|
|
427
|
-
@base = Integer(base)
|
|
428
|
-
end
|
|
429
|
-
|
|
430
|
-
def convert
|
|
431
|
-
-> s { s.to_i(@base) }
|
|
432
|
-
end
|
|
433
|
-
|
|
434
|
-
def constraint
|
|
435
|
-
@base > 10 ? /[\da-#{(@base-1).to_s(@base)}]/ : /[0-#{@base-1}]/
|
|
436
|
-
end
|
|
437
|
-
end
|
|
438
|
-
|
|
439
|
-
pattern = Mustermann.new('/<id:id>/<num(base=8):oct>/<num(base=16):hex>',
|
|
440
|
-
type: :flask, converters: { id: id_converter, num: NumConverter})
|
|
441
|
-
|
|
442
|
-
pattern.params('/10/12/f1') # => {"id"=>10, "oct"=>10, "hex"=>241}
|
|
116
|
+
mapper = Mustermann::Mapper.new("/:example" => "(/:prefix)?/:example.html")
|
|
117
|
+
mapper['/foo', prefix: 'en'] # => "/en/foo.html"
|
|
443
118
|
```
|
|
444
119
|
|
|
445
|
-
|
|
120
|
+
## Building a Mapper
|
|
446
121
|
|
|
447
|
-
|
|
122
|
+
Mappings can be supplied as a hash, added via `[]=`, or built with a block:
|
|
448
123
|
|
|
449
124
|
``` ruby
|
|
450
|
-
|
|
451
|
-
Mustermann::
|
|
125
|
+
# Hash argument
|
|
126
|
+
mapper = Mustermann::Mapper.new("/:a" => "/:a.html", "/:a/:b" => "/:b/:a")
|
|
452
127
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
There is a handy syntax for quickly creating new converter classes: When you pass a block instead of a converter object, it will yield a generic converter with setters and getters for `convert` and `constraint`, and any arguments passed to the converter.
|
|
128
|
+
# Block (zero-argument, returns a hash)
|
|
129
|
+
mapper = Mustermann::Mapper.new { { "/:a" => "/:a.html" } }
|
|
458
130
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
Mustermann::Flask.register_converter(:id) do |converter|
|
|
463
|
-
converter.constraint = /\d/
|
|
464
|
-
converter.convert = -> s { s.to_i }
|
|
131
|
+
# Block (one-argument, imperative)
|
|
132
|
+
mapper = Mustermann::Mapper.new do |m|
|
|
133
|
+
m["/:a"] = "/:a.html"
|
|
465
134
|
end
|
|
466
135
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
end
|
|
471
|
-
|
|
472
|
-
pattern = Mustermann.new('/<id:id>/<num(base=8):oct>/<num(base=16):hex>', type: :flask)
|
|
473
|
-
pattern.params('/10/12/f1') # => {"id"=>10, "oct"=>10, "hex"=>241}
|
|
136
|
+
# Incremental
|
|
137
|
+
mapper = Mustermann::Mapper.new
|
|
138
|
+
mapper["/:a"] = "/:a.html"
|
|
474
139
|
```
|
|
475
140
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
Registering global converters will make these available for all Flask patterns. It might even override already registered converters. This global state might break unrelated code.
|
|
479
|
-
|
|
480
|
-
It is therefore recommended that, if you don't want to pass in the converters option for every pattern, you create your own subclass of `Mustermann::Flask`.
|
|
481
|
-
|
|
482
|
-
``` ruby
|
|
483
|
-
require 'mustermann/flask'
|
|
484
|
-
|
|
485
|
-
MyFlask = Class.new(Mustermann::Flask)
|
|
141
|
+
The output value may be a String, a `Mustermann::Pattern`, an `Array` of either (tried in order until one expands successfully), or a `Mustermann::Expander` directly.
|
|
486
142
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
converter.convert = -> s { s.to_i }
|
|
490
|
-
end
|
|
491
|
-
|
|
492
|
-
MyFlask.register_converter(:num) do |converter, base: 10|
|
|
493
|
-
converter.constraint = base > 10 ? /[\da-#{(@base-1).to_s(base)}]/ : /[0-#{base-1}]/
|
|
494
|
-
converter.convert = -> s { s.to_i(base) }
|
|
495
|
-
end
|
|
496
|
-
|
|
497
|
-
pattern = MyFlask.new('/<id:id>/<num(base=8):oct>/<num(base=16):hex>')
|
|
498
|
-
pattern.params('/10/12/f1') # => {"id"=>10, "oct"=>10, "hex"=>241}
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
You can even register this type for usage with `Mustermann.new`:
|
|
143
|
+
<a name="-mustermann-flask"></a>
|
|
144
|
+
# Flask Syntax for Mustermann
|
|
502
145
|
|
|
503
|
-
|
|
504
|
-
Mustermann.register(:my_flask, MyFlask)
|
|
505
|
-
pattern = Mustermann.new('/<id:id>/<num(base=8):oct>/<num(base=16):hex>', type: :my_flask)
|
|
506
|
-
pattern.params('/10/12/f1') # => {"id"=>10, "oct"=>10, "hex"=>241}
|
|
507
|
-
```
|
|
146
|
+
See [docs/patterns/flask.md](../docs/patterns/flask.md).
|
|
508
147
|
|
|
509
148
|
<a name="-mustermann-pyramid"></a>
|
|
510
149
|
# Pyramid Syntax for Mustermann
|
|
511
150
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
## Overview
|
|
515
|
-
|
|
516
|
-
**Supported options:**
|
|
517
|
-
`capture`, `except`, `greedy`, `space_matches_plus`, `uri_decode` and `ignore_unknown_options`
|
|
518
|
-
|
|
519
|
-
**External Documentation:** [Pylons Framework: URL Configuration](http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/configuration.html#url-config), [Pylons Book: Routes in Detail](http://pylonsbook.com/en/1.0/urls-routing-and-dispatch.html#routes-in-detail), [Pyramid: Route Pattern Syntax](http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/narr/urldispatch.html#route-pattern-syntax)
|
|
520
|
-
|
|
521
|
-
``` ruby
|
|
522
|
-
require 'mustermann/pyramid'
|
|
523
|
-
|
|
524
|
-
Mustermann.new('/{prefix}/*suffix', type: :pyramid).params('/a/b/c') # => { prefix: 'a', suffix: ['b', 'c'] }
|
|
525
|
-
|
|
526
|
-
pattern = Mustermann.new('/{name}', type: :pyramid)
|
|
527
|
-
|
|
528
|
-
pattern.respond_to? :expand # => true
|
|
529
|
-
pattern.expand(name: 'foo') # => '/foo'
|
|
530
|
-
|
|
531
|
-
pattern.respond_to? :to_templates # => true
|
|
532
|
-
pattern.to_templates # => ['/{name}']
|
|
533
|
-
```
|
|
534
|
-
|
|
535
|
-
## Syntax
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
<table>
|
|
539
|
-
<thead>
|
|
540
|
-
<tr>
|
|
541
|
-
<th>Syntax Element</th>
|
|
542
|
-
<th>Description</th>
|
|
543
|
-
</tr>
|
|
544
|
-
</thead>
|
|
545
|
-
<tbody>
|
|
546
|
-
<tr>
|
|
547
|
-
<td><b>{</b><i>name</i><b>}</b></td>
|
|
548
|
-
<td>
|
|
549
|
-
Captures anything but a forward slash in a semi-greedy fashion. Capture is named <i>name</i>.
|
|
550
|
-
Capture behavior can be modified with <tt>capture</tt> and <tt>greedy</tt> option.
|
|
551
|
-
</td>
|
|
552
|
-
</tr>
|
|
553
|
-
<tr>
|
|
554
|
-
<td><b>{</b><i>name</i><b>:</b><i>regexp</i><b>}</b></td>
|
|
555
|
-
<td>
|
|
556
|
-
Captures anything matching the <i>regexp</i> regular expression. Capture is named <i>name</i>.
|
|
557
|
-
Capture behavior can be modified with <tt>capture</tt>.
|
|
558
|
-
</td>
|
|
559
|
-
</tr>
|
|
560
|
-
<tr>
|
|
561
|
-
<td><b>*</b><i>name</i></td>
|
|
562
|
-
<td>
|
|
563
|
-
Captures anything in a non-greedy fashion. Capture is named <i>name</i>.
|
|
564
|
-
</td>
|
|
565
|
-
</tr>
|
|
566
|
-
<tr>
|
|
567
|
-
<td><b>/</b></td>
|
|
568
|
-
<td>
|
|
569
|
-
Matches forward slash. Does not match URI encoded version of forward slash.
|
|
570
|
-
</td>
|
|
571
|
-
</tr>
|
|
572
|
-
<tr>
|
|
573
|
-
<td><i>any other character</i></td>
|
|
574
|
-
<td>Matches exactly that character or a URI encoded version of it.</td>
|
|
575
|
-
</tr>
|
|
576
|
-
</tbody>
|
|
577
|
-
</table>
|
|
578
|
-
|
|
579
|
-
<a name="-mustermann-rails"></a>
|
|
580
|
-
# Rails Syntax for Mustermann
|
|
581
|
-
|
|
582
|
-
This gem implements the `rails` pattern type for Mustermann. 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>
|
|
583
|
-
|
|
584
|
-
## Overview
|
|
585
|
-
|
|
586
|
-
**Supported options:**
|
|
587
|
-
`capture`, `except`, `greedy`, `space_matches_plus`, `uri_decode`, `version`, and `ignore_unknown_options`.
|
|
588
|
-
|
|
589
|
-
**External documentation:**
|
|
590
|
-
[Ruby on Rails Guides: Routing](http://guides.rubyonrails.org/routing.html).
|
|
591
|
-
|
|
592
|
-
``` ruby
|
|
593
|
-
require 'mustermann'
|
|
594
|
-
|
|
595
|
-
pattern = Mustermann.new('/:example', type: :rails)
|
|
596
|
-
pattern === "/foo.bar" # => true
|
|
597
|
-
pattern === "/foo/bar" # => false
|
|
598
|
-
pattern.params("/foo.bar") # => { "example" => "foo.bar" }
|
|
599
|
-
pattern.params("/foo/bar") # => nil
|
|
600
|
-
|
|
601
|
-
pattern = Mustermann.new('/:example(/:optional)', type: :rails)
|
|
602
|
-
pattern === "/foo.bar" # => true
|
|
603
|
-
pattern === "/foo/bar" # => true
|
|
604
|
-
pattern.params("/foo.bar") # => { "example" => "foo.bar", "optional" => nil }
|
|
605
|
-
pattern.params("/foo/bar") # => { "example" => "foo", "optional" => "bar" }
|
|
606
|
-
|
|
607
|
-
pattern = Mustermann.new('/*example', type: :rails)
|
|
608
|
-
pattern === "/foo.bar" # => true
|
|
609
|
-
pattern === "/foo/bar" # => true
|
|
610
|
-
pattern.params("/foo.bar") # => { "example" => "foo.bar" }
|
|
611
|
-
pattern.params("/foo/bar") # => { "example" => "foo/bar" }
|
|
612
|
-
```
|
|
613
|
-
|
|
614
|
-
## Rails Compatibility
|
|
615
|
-
|
|
616
|
-
Rails syntax changed over time. You can target different Ruby on Rails versions by setting the `version` option to the desired Rails version.
|
|
617
|
-
|
|
618
|
-
The default is `4.2`. Versions prior to `2.3` are not supported.
|
|
619
|
-
|
|
620
|
-
``` ruby
|
|
621
|
-
require 'mustermann'
|
|
622
|
-
Mustermann.new('/', type: :rails, version: "2.3")
|
|
623
|
-
Mustermann.new('/', type: :rails, version: "3.0.0")
|
|
624
|
-
|
|
625
|
-
require 'rails'
|
|
626
|
-
Mustermann.new('/', type: :rails, version: Rails::VERSION::STRING)
|
|
627
|
-
```
|
|
628
|
-
|
|
629
|
-
## Syntax
|
|
630
|
-
|
|
631
|
-
<table>
|
|
632
|
-
<thead>
|
|
633
|
-
<tr>
|
|
634
|
-
<th>Syntax Element</th>
|
|
635
|
-
<th>Description</th>
|
|
636
|
-
</tr>
|
|
637
|
-
</thead>
|
|
638
|
-
<tbody>
|
|
639
|
-
<tr>
|
|
640
|
-
<td><b>:</b><i>name</i></td>
|
|
641
|
-
<td>
|
|
642
|
-
Captures anything but a forward slash in a semi-greedy fashion. Capture is named <i>name</i>.
|
|
643
|
-
Capture behavior can be modified with tt>capture</tt> and <tt>greedy</tt> option.
|
|
644
|
-
</td>
|
|
645
|
-
</tr>
|
|
646
|
-
<tr>
|
|
647
|
-
<td><b>*</b><i>name</i></td>
|
|
648
|
-
<td>
|
|
649
|
-
Captures anything in a non-greedy fashion. Capture is named <i>name</i>.
|
|
650
|
-
</td>
|
|
651
|
-
</tr>
|
|
652
|
-
<tr>
|
|
653
|
-
<td><b>(</b><i>expression</i><b>)</b></td>
|
|
654
|
-
<td>Enclosed <i>expression</i> is optional. Not available in 2.3 compatibility mode.</td>
|
|
655
|
-
</tr>
|
|
656
|
-
<tr>
|
|
657
|
-
<td><b>/</b></td>
|
|
658
|
-
<td>
|
|
659
|
-
Matches forward slash. Does not match URI encoded version of forward slash.
|
|
660
|
-
</td>
|
|
661
|
-
</tr>
|
|
662
|
-
<tr>
|
|
663
|
-
<td><b>\</b><i>x</i></td>
|
|
664
|
-
<td>
|
|
665
|
-
In 3.x compatibility mode and starting with 4.2:
|
|
666
|
-
Matches <i>x</i> or URI encoded version of <i>x</i>. For instance <tt>\*</tt> matches <tt>*</tt>.<br>
|
|
667
|
-
In 4.0 or 4.1 compatibility mode:
|
|
668
|
-
<b>\</b> is ignored, <i>x</i> is parsed normally.<br>
|
|
669
|
-
</td>
|
|
670
|
-
</tr>
|
|
671
|
-
<tr>
|
|
672
|
-
<td><i>expression</i> <b>|</b> <i>expression</i></td>
|
|
673
|
-
<td>
|
|
674
|
-
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>
|
|
675
|
-
5.0 mode: It will match if any of the nested expressions matches.
|
|
676
|
-
</td>
|
|
677
|
-
</tr>
|
|
678
|
-
<tr>
|
|
679
|
-
<td><i>any other character</i></td>
|
|
680
|
-
<td>Matches exactly that character or a URI encoded version of it.</td>
|
|
681
|
-
</tr>
|
|
682
|
-
</tbody>
|
|
683
|
-
</table>
|
|
151
|
+
See [docs/patterns/pyramid.md](../docs/patterns/pyramid.md).
|
|
684
152
|
|
|
685
153
|
<a name="-mustermann-shell"></a>
|
|
686
154
|
# Shell Syntax for Mustermann
|
|
687
155
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
## Overview
|
|
691
|
-
|
|
692
|
-
**Supported options:** `uri_decode` and `ignore_unknown_options`.
|
|
693
|
-
|
|
694
|
-
**External documentation:** [Ruby's fnmatch](http://www.ruby-doc.org/core-2.1.4/File.html#method-c-fnmatch), [Wikipedia: Glob (programming)](http://en.wikipedia.org/wiki/Glob_(programming))
|
|
695
|
-
|
|
696
|
-
``` ruby
|
|
697
|
-
require 'mustermann'
|
|
698
|
-
|
|
699
|
-
pattern = Mustermann.new('/*', type: :shell)
|
|
700
|
-
pattern === "/foo.bar" # => true
|
|
701
|
-
pattern === "/foo/bar" # => false
|
|
702
|
-
|
|
703
|
-
pattern = Mustermann.new('/**/*', type: :shell)
|
|
704
|
-
pattern === "/foo.bar" # => true
|
|
705
|
-
pattern === "/foo/bar" # => true
|
|
706
|
-
|
|
707
|
-
pattern = Mustermann.new('/{foo,bar}', type: :shell)
|
|
708
|
-
pattern === "/foo" # => true
|
|
709
|
-
pattern === "/bar" # => true
|
|
710
|
-
pattern === "/baz" # => false
|
|
711
|
-
```
|
|
712
|
-
|
|
713
|
-
## Syntax
|
|
714
|
-
|
|
715
|
-
<table>
|
|
716
|
-
<thead>
|
|
717
|
-
<tr>
|
|
718
|
-
<th>Syntax Element</th>
|
|
719
|
-
<th>Description</th>
|
|
720
|
-
</tr>
|
|
721
|
-
</thead>
|
|
722
|
-
<tbody>
|
|
723
|
-
<tr>
|
|
724
|
-
<td><b>*</b></td>
|
|
725
|
-
<td>Matches anything but a slash.</td>
|
|
726
|
-
</tr>
|
|
727
|
-
<tr>
|
|
728
|
-
<td><b>**</b></td>
|
|
729
|
-
<td>Matches anything.</td>
|
|
730
|
-
</tr>
|
|
731
|
-
<tr>
|
|
732
|
-
<td><b>[</b><i>set</i><b>]</b></td>
|
|
733
|
-
<td>Matches one character in <i>set</i>.</td>
|
|
734
|
-
</tr>
|
|
735
|
-
<tr>
|
|
736
|
-
<td><b>{</b><i>a</i>,<i>b</i><b>}</b></td>
|
|
737
|
-
<td>Matches <i>a</i> or <i>b</i>.</td>
|
|
738
|
-
</tr>
|
|
739
|
-
<tr>
|
|
740
|
-
<td><b>\</b><i>x</i></td>
|
|
741
|
-
<td>Matches <i>x</i> or URI encoded version of <i>x</i>. For instance <tt>\*</tt> matches <tt>*</tt>.</td>
|
|
742
|
-
</tr>
|
|
743
|
-
<tr>
|
|
744
|
-
<td><i>any other character</i></td>
|
|
745
|
-
<td>Matches exactly that character or a URI encoded version of it.</td>
|
|
746
|
-
</tr>
|
|
747
|
-
</tbody>
|
|
748
|
-
</table>
|
|
156
|
+
See [docs/patterns/shell.md](../docs/patterns/shell.md).
|
|
749
157
|
|
|
750
158
|
|
|
751
159
|
<a name="-mustermann-simple"></a>
|
|
752
160
|
# Simple Syntax for Mustermann
|
|
753
161
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
## Overview
|
|
757
|
-
|
|
758
|
-
**Supported options:**
|
|
759
|
-
`greedy`, `space_matches_plus`, `uri_decode` and `ignore_unknown_options`.
|
|
760
|
-
|
|
761
|
-
This is useful for porting an application that relies on this behavior to a later Sinatra version and to make sure Sinatra 2.0 patterns do not decrease performance. Simple patterns internally use the same code older Sinatra versions used for compiling the pattern. Error messages for broken patterns will therefore not be as informative as for other pattern implementations.
|
|
762
|
-
|
|
763
|
-
``` ruby
|
|
764
|
-
require 'mustermann'
|
|
765
|
-
|
|
766
|
-
pattern = Mustermann.new('/:example', type: :simple)
|
|
767
|
-
pattern === "/foo.bar" # => true
|
|
768
|
-
pattern === "/foo/bar" # => false
|
|
769
|
-
pattern.params("/foo.bar") # => { "example" => "foo.bar" }
|
|
770
|
-
pattern.params("/foo/bar") # => nil
|
|
771
|
-
|
|
772
|
-
pattern = Mustermann.new('/:example/?:optional?', type: :simple)
|
|
773
|
-
pattern === "/foo.bar" # => true
|
|
774
|
-
pattern === "/foo/bar" # => true
|
|
775
|
-
pattern.params("/foo.bar") # => { "example" => "foo.bar", "optional" => nil }
|
|
776
|
-
pattern.params("/foo/bar") # => { "example" => "foo", "optional" => "bar" }
|
|
777
|
-
|
|
778
|
-
pattern = Mustermann.new('/*', type: :simple)
|
|
779
|
-
pattern === "/foo.bar" # => true
|
|
780
|
-
pattern === "/foo/bar" # => true
|
|
781
|
-
pattern.params("/foo.bar") # => { "splat" => ["foo.bar"] }
|
|
782
|
-
pattern.params("/foo/bar") # => { "splat" => ["foo/bar"] }
|
|
783
|
-
```
|
|
784
|
-
|
|
785
|
-
## Syntax
|
|
786
|
-
|
|
787
|
-
<table>
|
|
788
|
-
<thead>
|
|
789
|
-
<tr>
|
|
790
|
-
<th>Syntax Element</th>
|
|
791
|
-
<th>Description</th>
|
|
792
|
-
</tr>
|
|
793
|
-
</thead>
|
|
794
|
-
<tbody>
|
|
795
|
-
<tr>
|
|
796
|
-
<td><b>:</b><i>name</i></td>
|
|
797
|
-
<td>
|
|
798
|
-
Captures anything but a forward slash in a greedy fashion. Capture is named <i>name</i>.
|
|
799
|
-
</td>
|
|
800
|
-
</tr>
|
|
801
|
-
<tr>
|
|
802
|
-
<td><b>*</b></td>
|
|
803
|
-
<td>
|
|
804
|
-
Captures anything in a non-greedy fashion. Capture is named splat.
|
|
805
|
-
It is always an array of captures, as you can use <tt>*</tt> more than once in a pattern.
|
|
806
|
-
</td>
|
|
807
|
-
</tr>
|
|
808
|
-
<tr>
|
|
809
|
-
<td><i>x</i><b>?</b></td>
|
|
810
|
-
<td>Makes <i>x</i> optional. For instance <tt>foo?</tt> matches <tt>foo</tt> or <tt>fo</tt>.</td>
|
|
811
|
-
</tr>
|
|
812
|
-
<tr>
|
|
813
|
-
<td><b>/</b></td>
|
|
814
|
-
<td>
|
|
815
|
-
Matches forward slash. Does not match URI encoded version of forward slash.
|
|
816
|
-
</td>
|
|
817
|
-
</tr>
|
|
818
|
-
<tr>
|
|
819
|
-
<td><i>any special character</i></td>
|
|
820
|
-
<td>Matches exactly that character or a URI encoded version of it.</td>
|
|
821
|
-
</tr>
|
|
822
|
-
<tr>
|
|
823
|
-
<td><i>any other character</i></td>
|
|
824
|
-
<td>Matches exactly that character.</td>
|
|
825
|
-
</tr>
|
|
826
|
-
</tbody>
|
|
827
|
-
</table>
|
|
162
|
+
See [docs/patterns/simple.md](../docs/patterns/simple.md).
|
|
828
163
|
|
|
829
164
|
<a name="-mustermann-strscan"></a>
|
|
830
165
|
# String Scanner for Mustermann
|
|
@@ -866,91 +201,47 @@ You can also pass in default options for ad hoc patterns when creating the scann
|
|
|
866
201
|
scanner = Mustermann::StringScanner.new(input, type: :shell)
|
|
867
202
|
```
|
|
868
203
|
|
|
869
|
-
<a name="-mustermann-
|
|
870
|
-
#
|
|
871
|
-
|
|
872
|
-
This gem implements the `uri-template` (or `template`) pattern type for Mustermann. It is compatible with [RFC 6570](https://tools.ietf.org/html/rfc6570) (level 4), [JSON API](http://jsonapi.org/), [JSON Home Documents](http://tools.ietf.org/html/draft-nottingham-json-home-02) and [many more](https://code.google.com/p/uri-templates/wiki/Implementations)
|
|
204
|
+
<a name="-mustermann-to-pattern"></a>
|
|
205
|
+
# `to_pattern` for Mustermann
|
|
873
206
|
|
|
874
207
|
## Overview
|
|
875
208
|
|
|
876
|
-
|
|
877
|
-
`capture`, `except`, `greedy`, `space_matches_plus`, `uri_decode`, and `ignore_unknown_options`.
|
|
878
|
-
|
|
879
|
-
Please keep the following in mind:
|
|
880
|
-
|
|
881
|
-
> "Some URI Templates can be used in reverse for the purpose of variable matching: comparing the template to a fully formed URI in order to extract the variable parts from that URI and assign them to the named variables. Variable matching only works well if the template expressions are delimited by the beginning or end of the URI or by characters that cannot be part of the expansion, such as reserved characters surrounding a simple string expression. In general, regular expression languages are better suited for variable matching."
|
|
882
|
-
> — *RFC 6570, Sec 1.5: "Limitations"*
|
|
209
|
+
`mustermann/to_pattern` adds a `to_pattern` method to `String`, `Symbol`, `Regexp`, `Array`, and `Mustermann::Pattern`, and provides the `Mustermann::ToPattern` mixin so you can add the same method to your own classes.
|
|
883
210
|
|
|
884
211
|
``` ruby
|
|
885
|
-
require 'mustermann'
|
|
212
|
+
require 'mustermann/to_pattern'
|
|
886
213
|
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
pattern.params("/foo/bar") # => nil
|
|
892
|
-
|
|
893
|
-
pattern = Mustermann.new("{/segments*}/{page}{.ext,cmpr:2}", type: :template)
|
|
894
|
-
pattern.params("/a/b/c.tar.gz") # => {"segments"=>["a","b"], "page"=>"c", "ext"=>"tar", "cmpr"=>"gz"}
|
|
214
|
+
"/foo".to_pattern # => #<Mustermann::Sinatra:"/foo">
|
|
215
|
+
"/foo".to_pattern(type: :rails) # => #<Mustermann::Rails:"/foo">
|
|
216
|
+
%r{/foo}.to_pattern # => #<Mustermann::Regular:"\\/foo">
|
|
217
|
+
"/foo".to_pattern.to_pattern # => #<Mustermann::Sinatra:"/foo">
|
|
895
218
|
```
|
|
896
219
|
|
|
897
|
-
##
|
|
220
|
+
## `Mustermann::ToPattern` mixin
|
|
898
221
|
|
|
899
|
-
|
|
222
|
+
Include `Mustermann::ToPattern` in any class to get a `to_pattern` method driven by its `to_s` output:
|
|
900
223
|
|
|
901
224
|
``` ruby
|
|
902
|
-
require 'mustermann'
|
|
903
|
-
|
|
904
|
-
Mustermann.new('/:name').to_templates # => ['/{name}']
|
|
905
|
-
```
|
|
225
|
+
require 'mustermann/to_pattern'
|
|
906
226
|
|
|
907
|
-
|
|
227
|
+
class MyRoute
|
|
228
|
+
include Mustermann::ToPattern
|
|
908
229
|
|
|
909
|
-
|
|
910
|
-
|
|
230
|
+
def to_s
|
|
231
|
+
"/users/:id"
|
|
232
|
+
end
|
|
233
|
+
end
|
|
911
234
|
|
|
912
|
-
|
|
235
|
+
MyRoute.new.to_pattern # => #<Mustermann::Sinatra:"/users/:id">
|
|
236
|
+
MyRoute.new.to_pattern(type: :rails) # => #<Mustermann::Rails:"/users/:id">
|
|
913
237
|
```
|
|
914
238
|
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
<
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
<th>Description</th>
|
|
922
|
-
</tr>
|
|
923
|
-
</thead>
|
|
924
|
-
<tbody>
|
|
925
|
-
<tr>
|
|
926
|
-
<td><b>{</b><i>o</i> <i>var</i> <i>m</i><b>,</b> <i>var</i> <i>m</i><b>,</b> ...<b>}</b></td>
|
|
927
|
-
<td>
|
|
928
|
-
Captures expansion.
|
|
929
|
-
Operator <i>o</i>: <code>+ # . / ; ? &</tt> or none.
|
|
930
|
-
Modifier <i>m</i>: <code>:num *</tt> or none.
|
|
931
|
-
</td>
|
|
932
|
-
</tr>
|
|
933
|
-
<tr>
|
|
934
|
-
<td><b>/</b></td>
|
|
935
|
-
<td>
|
|
936
|
-
Matches forward slash. Does not match URI encoded version of forward slash.
|
|
937
|
-
</td>
|
|
938
|
-
</tr>
|
|
939
|
-
<tr>
|
|
940
|
-
<td><i>any other character</i></td>
|
|
941
|
-
<td>Matches exactly that character or a URI encoded version of it.</td>
|
|
942
|
-
</tr>
|
|
943
|
-
</tbody>
|
|
944
|
-
</table>
|
|
945
|
-
|
|
946
|
-
The operators `+` and `#` will always match non-greedy, whereas all other operators match semi-greedy by default.
|
|
947
|
-
All modifiers and operators are supported. However, it does not parse lists as single values without the *explode* modifier (aka *star*).
|
|
948
|
-
Parametric operators (`;`, `?` and `&`) currently only match parameters in given order.
|
|
949
|
-
|
|
950
|
-
Note that it differs from URI templates in that it takes the unescaped version of special character instead of the escaped version.
|
|
951
|
-
|
|
952
|
-
If you reuse the exact same templates and expose them via an external API meant for expansion,
|
|
953
|
-
you should set `uri_decode` to `false` in order to conform with the specification.
|
|
239
|
+
If your class wraps another object (via `__getobj__`, as in `Delegator` subclasses), `to_pattern` will unwrap it before converting.
|
|
240
|
+
|
|
241
|
+
<a name="-mustermann-uri-template"></a>
|
|
242
|
+
# URI Template Syntax for Mustermann
|
|
243
|
+
|
|
244
|
+
See [docs/patterns/template.md](../docs/patterns/template.md).
|
|
954
245
|
|
|
955
246
|
|
|
956
247
|
<a name="-mustermann-visualizer"></a>
|
|
@@ -1127,15 +418,6 @@ The **s-expression like syntax** looks as follows:
|
|
|
1127
418
|
* Full strings are Ruby strings enclosed by double quotes.
|
|
1128
419
|
* Spaces before or after parens are optional.
|
|
1129
420
|
|
|
1130
|
-
### IRB/Pry integration
|
|
1131
|
-
|
|
1132
|
-
When `mustermann` is being loaded from within an IRB or Pry session, it will automatically load `mustermann/visualizer` too, if possible.
|
|
1133
|
-
When displayed as result, it will be highlighted.
|
|
1134
|
-
|
|
1135
|
-

|
|
1136
|
-
|
|
1137
|
-
In Pry, this will even work when nested inside other objects (like as element on an array).
|
|
1138
|
-
|
|
1139
421
|
## Tree Rendering
|
|
1140
422
|
|
|
1141
423
|

|
|
@@ -1152,4 +434,3 @@ For patterns not based on an AST (shell, simple, regexp), it will print out a si
|
|
|
1152
434
|
pattern (not AST based) "/example"
|
|
1153
435
|
|
|
1154
436
|
It will display a tree for identity patterns. While these are not based on an AST internally, Mustermann supports generating an AST for these patterns.
|
|
1155
|
-
|
data/lib/mustermann/flask.rb
CHANGED
|
@@ -106,7 +106,7 @@ module Mustermann
|
|
|
106
106
|
|
|
107
107
|
# Allows you to register your own converters.
|
|
108
108
|
#
|
|
109
|
-
# It is
|
|
109
|
+
# It is recommended to use this on a subclass, so to not influence other subsystems
|
|
110
110
|
# using flask templates.
|
|
111
111
|
#
|
|
112
112
|
# The object passed in as converter can implement #convert and/or #constraint.
|
|
@@ -135,7 +135,7 @@ module Mustermann
|
|
|
135
135
|
# MyPattern.new("/<up:name>").params('/foo') # => { "name" => "FOO" }
|
|
136
136
|
#
|
|
137
137
|
# @example with converter class
|
|
138
|
-
# require 'mustermann/
|
|
138
|
+
# require 'mustermann/flask'
|
|
139
139
|
#
|
|
140
140
|
# class MyPattern < Mustermann::Flask
|
|
141
141
|
# class Converter
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'mustermann'
|
|
3
|
+
require 'mustermann/expander'
|
|
4
|
+
require 'mustermann/set'
|
|
5
|
+
|
|
6
|
+
module Mustermann
|
|
7
|
+
# A mapper allows mapping one string to another based on pattern parsing and expanding.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# require 'mustermann/mapper'
|
|
11
|
+
# mapper = Mustermann::Mapper.new("/:foo" => "/:foo.html")
|
|
12
|
+
# mapper['/example'] # => "/example.html"
|
|
13
|
+
class Mapper
|
|
14
|
+
# Creates a new mapper.
|
|
15
|
+
#
|
|
16
|
+
# @overload initialize(**options)
|
|
17
|
+
# @param options [Hash] options The options hash
|
|
18
|
+
# @yield block for generating mappings as a hash
|
|
19
|
+
# @yieldreturn [Hash] see {#update}
|
|
20
|
+
#
|
|
21
|
+
# @example
|
|
22
|
+
# require 'mustermann/mapper'
|
|
23
|
+
# Mustermann::Mapper.new(type: :rails) {{
|
|
24
|
+
# "/:foo" => ["/:foo.html", "/:foo.:format"]
|
|
25
|
+
# }}
|
|
26
|
+
#
|
|
27
|
+
# @overload initialize(**options)
|
|
28
|
+
# @param options [Hash] options The options hash
|
|
29
|
+
# @yield block for generating mappings as a hash
|
|
30
|
+
# @yieldparam mapper [Mustermann::Mapper] the mapper instance
|
|
31
|
+
#
|
|
32
|
+
# @example
|
|
33
|
+
# require 'mustermann/mapper'
|
|
34
|
+
# Mustermann::Mapper.new(type: :rails) do |mapper|
|
|
35
|
+
# mapper["/:foo"] = ["/:foo.html", "/:foo.:format"]
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# @overload initialize(map = {}, **options)
|
|
39
|
+
# @param map [Hash] see {#update}
|
|
40
|
+
# @param [Hash] options The options hash
|
|
41
|
+
#
|
|
42
|
+
# @example map before options
|
|
43
|
+
# require 'mustermann/mapper'
|
|
44
|
+
# Mustermann::Mapper.new({"/:foo" => "/:foo.html"}, type: :rails)
|
|
45
|
+
def initialize(map = {}, additional_values: :ignore, **options, &block)
|
|
46
|
+
@options = options
|
|
47
|
+
@additional_values = additional_values
|
|
48
|
+
@set = Set.new(use_trie: false, use_cache: false, **options)
|
|
49
|
+
block.arity == 0 ? update(yield) : yield(self) if block
|
|
50
|
+
update(map) if map
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Add multiple mappings.
|
|
54
|
+
#
|
|
55
|
+
# @param map [Hash{String, Pattern: String, Pattern, Arry<String, Pattern>, Expander}] the mapping
|
|
56
|
+
def update(map)
|
|
57
|
+
map.to_h.each_pair do |input, output|
|
|
58
|
+
output = Expander.new(*output, additional_values: @additional_values, **@options) unless output.is_a? Expander
|
|
59
|
+
@set.add(input, output)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @return [Hash{Patttern: Expander}] Hash version of the mapper.
|
|
64
|
+
def to_h = @set.patterns.to_h { [_1, @set[_1]] }
|
|
65
|
+
|
|
66
|
+
# Convert a string according to mappings. You can pass in additional params.
|
|
67
|
+
#
|
|
68
|
+
# @example mapping with and without additional parameters
|
|
69
|
+
# mapper = Mustermann::Mapper.new("/:example" => "(/:prefix)?/:example.html")
|
|
70
|
+
#
|
|
71
|
+
def convert(input, values = {})
|
|
72
|
+
@set.match_all(input).inject(input) do |current, m|
|
|
73
|
+
params = Hash[values.merge(m.params).map { |k, v| [k.to_s, v] }]
|
|
74
|
+
m.value.expandable?(params) ? m.value.expand(params) : current
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Add a single mapping.
|
|
79
|
+
#
|
|
80
|
+
# @param key [String, Pattern] format of the input string
|
|
81
|
+
# @param value [String, Pattern, Arry<String, Pattern>, Expander] format of the output string
|
|
82
|
+
def []=(key, value)
|
|
83
|
+
update key => value
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
alias_method :[], :convert
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'set'
|
|
3
|
+
require 'thread'
|
|
4
|
+
require 'mustermann'
|
|
5
|
+
|
|
6
|
+
module Mustermann
|
|
7
|
+
# A simple, persistent cache for creating repositories.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# require 'mustermann/pattern_cache'
|
|
11
|
+
# cache = Mustermann::PatternCache.new
|
|
12
|
+
#
|
|
13
|
+
# # use this instead of Mustermann.new
|
|
14
|
+
# pattern = cache.create_pattern("/:name", type: :rails)
|
|
15
|
+
#
|
|
16
|
+
# @note
|
|
17
|
+
# {Mustermann::Pattern.new} (which is used by {Mustermann.new}) will reuse instances that have
|
|
18
|
+
# not yet been garbage collected. You only need an extra cache if you do not keep a reference to
|
|
19
|
+
# the patterns around.
|
|
20
|
+
#
|
|
21
|
+
# @api private
|
|
22
|
+
class PatternCache
|
|
23
|
+
# @param [Hash] pattern_options default options used for {#create_pattern}
|
|
24
|
+
def initialize(**pattern_options)
|
|
25
|
+
@cached = ::Set.new
|
|
26
|
+
@mutex = Mutex.new
|
|
27
|
+
@pattern_options = pattern_options
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @param (see Mustermann.new)
|
|
31
|
+
# @return (see Mustermann.new)
|
|
32
|
+
# @raise (see Mustermann.new)
|
|
33
|
+
# @see Mustermann.new
|
|
34
|
+
def create_pattern(string, **pattern_options)
|
|
35
|
+
pattern = Mustermann.new(string, **pattern_options, **@pattern_options)
|
|
36
|
+
@mutex.synchronize { @cached.add(pattern) } unless @cached.include? pattern
|
|
37
|
+
pattern
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Removes all pattern instances from the cache.
|
|
41
|
+
def clear
|
|
42
|
+
@mutex.synchronize { @cached.clear }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @return [Integer] number of currently cached patterns
|
|
46
|
+
def size
|
|
47
|
+
@mutex.synchronize { @cached.size }
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
data/lib/mustermann/shell.rb
CHANGED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'mustermann'
|
|
3
|
+
|
|
4
|
+
module Mustermann
|
|
5
|
+
# Mixin for adding {#to_pattern} ducktyping to objects.
|
|
6
|
+
#
|
|
7
|
+
# @example
|
|
8
|
+
# require 'mustermann/to_pattern'
|
|
9
|
+
#
|
|
10
|
+
# class Foo
|
|
11
|
+
# include Mustermann::ToPattern
|
|
12
|
+
#
|
|
13
|
+
# def to_s
|
|
14
|
+
# ":foo/:bar"
|
|
15
|
+
# end
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# Foo.new.to_pattern # => #<Mustermann::Sinatra:":foo/:bar">
|
|
19
|
+
#
|
|
20
|
+
# By default included into String, Symbol, Regexp, Array and {Mustermann::Pattern}.
|
|
21
|
+
module ToPattern
|
|
22
|
+
PRIMITIVES = [String, Symbol, Array, Regexp, Mustermann::Pattern]
|
|
23
|
+
private_constant :PRIMITIVES
|
|
24
|
+
|
|
25
|
+
# Converts the object into a {Mustermann::Pattern}.
|
|
26
|
+
#
|
|
27
|
+
# @example converting a string
|
|
28
|
+
# ":name.png".to_pattern # => #<Mustermann::Sinatra:":name.png">
|
|
29
|
+
#
|
|
30
|
+
# @example converting a string with options
|
|
31
|
+
# "/*path".to_pattern(type: :rails) # => #<Mustermann::Rails:"/*path">
|
|
32
|
+
#
|
|
33
|
+
# @example converting a regexp
|
|
34
|
+
# /.*/.to_pattern # => #<Mustermann::Regular:".*">
|
|
35
|
+
#
|
|
36
|
+
# @example converting a pattern
|
|
37
|
+
# Mustermann.new("foo").to_pattern # => #<Mustermann::Sinatra:"foo">
|
|
38
|
+
#
|
|
39
|
+
# @param [Hash] options The options hash.
|
|
40
|
+
# @return [Mustermann::Pattern] pattern corresponding to object.
|
|
41
|
+
def to_pattern(**options)
|
|
42
|
+
input = self if PRIMITIVES.any? { |p| self.is_a? p }
|
|
43
|
+
input ||= __getobj__ if respond_to?(:__getobj__)
|
|
44
|
+
Mustermann.new(input || to_s, **options)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
PRIMITIVES.each do |klass|
|
|
48
|
+
append_features(klass)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -44,26 +44,12 @@ module Mustermann
|
|
|
44
44
|
caller_locations.first.label == 'puts' ? to_ansi : super
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
# If invoked directly by IRB, same as {#color_inspect}, otherwise same as {Mustermann::Pattern#inspect}.
|
|
48
|
-
def inspect
|
|
49
|
-
caller_locations.first.base_label == '<module:IRB>' ? color_inspect : super
|
|
50
|
-
end
|
|
51
|
-
|
|
52
47
|
# @return [String] ANSI colorized version of {Mustermann::Pattern#inspect}
|
|
53
48
|
def color_inspect(base_color = nil, **theme)
|
|
54
49
|
base_color ||= Highlight::DEFAULT_THEME[:base01]
|
|
55
50
|
template = is_a?(Composite) ? "*#<%p:(*%s*)>*" : "*#<%p:*%s*>*"
|
|
56
51
|
Hansi.render(template, self.class, to_ansi(inspect: true, **theme), {"*" => base_color})
|
|
57
52
|
end
|
|
58
|
-
|
|
59
|
-
# If invoked directly by IRB, same as {#color_inspect}, otherwise same as Object#pretty_print.
|
|
60
|
-
def pretty_print(q)
|
|
61
|
-
if q.class.name.to_s[/[^:]+$/] == "ColorPrinter"
|
|
62
|
-
q.text(color_inspect, inspect.length)
|
|
63
|
-
else
|
|
64
|
-
super
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
53
|
end
|
|
68
54
|
end
|
|
69
55
|
end
|
metadata
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mustermann-contrib
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 4.0.0.alpha
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Konstantin Haase
|
|
8
|
+
- Kunpei Sakai
|
|
9
|
+
- Patrik Ragnarsson
|
|
10
|
+
- Jordan Owens
|
|
8
11
|
- Zachary Scott
|
|
9
12
|
bindir: bin
|
|
10
13
|
cert_chain: []
|
|
@@ -16,14 +19,14 @@ dependencies:
|
|
|
16
19
|
requirements:
|
|
17
20
|
- - '='
|
|
18
21
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
22
|
+
version: 4.0.0.alpha
|
|
20
23
|
type: :runtime
|
|
21
24
|
prerelease: false
|
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
26
|
requirements:
|
|
24
27
|
- - '='
|
|
25
28
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
29
|
+
version: 4.0.0.alpha
|
|
27
30
|
- !ruby/object:Gem::Dependency
|
|
28
31
|
name: hansi
|
|
29
32
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -52,12 +55,15 @@ files:
|
|
|
52
55
|
- lib/mustermann/file_utils/glob_pattern.rb
|
|
53
56
|
- lib/mustermann/fileutils.rb
|
|
54
57
|
- lib/mustermann/flask.rb
|
|
58
|
+
- lib/mustermann/mapper.rb
|
|
59
|
+
- lib/mustermann/pattern_cache.rb
|
|
55
60
|
- lib/mustermann/pyramid.rb
|
|
56
61
|
- lib/mustermann/shell.rb
|
|
57
62
|
- lib/mustermann/simple.rb
|
|
58
63
|
- lib/mustermann/string_scanner.rb
|
|
59
64
|
- lib/mustermann/strscan.rb
|
|
60
65
|
- lib/mustermann/template.rb
|
|
66
|
+
- lib/mustermann/to_pattern.rb
|
|
61
67
|
- lib/mustermann/uri_template.rb
|
|
62
68
|
- lib/mustermann/visualizer.rb
|
|
63
69
|
- lib/mustermann/visualizer/highlight.rb
|
|
@@ -78,7 +84,11 @@ files:
|
|
|
78
84
|
homepage: https://github.com/sinatra/mustermann
|
|
79
85
|
licenses:
|
|
80
86
|
- MIT
|
|
81
|
-
metadata:
|
|
87
|
+
metadata:
|
|
88
|
+
bug_tracker_uri: https://github.com/sinatra/mustermann/issues
|
|
89
|
+
changelog_uri: https://github.com/sinatra/mustermann/blob/main/CHANGELOG.md
|
|
90
|
+
documentation_uri: https://github.com/sinatra/mustermann/tree/main/mustermann-contrib#readme
|
|
91
|
+
source_code_uri: https://github.com/sinatra/mustermann/tree/main/mustermann-contrib
|
|
82
92
|
rdoc_options: []
|
|
83
93
|
require_paths:
|
|
84
94
|
- lib
|
|
@@ -86,7 +96,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
86
96
|
requirements:
|
|
87
97
|
- - ">="
|
|
88
98
|
- !ruby/object:Gem::Version
|
|
89
|
-
version:
|
|
99
|
+
version: 3.3.0
|
|
90
100
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
101
|
requirements:
|
|
92
102
|
- - ">="
|