mustermann 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/README.md +166 -16
- data/Rakefile +1 -1
- data/bench/capturing.rb +4 -4
- data/bench/regexp.rb +21 -0
- data/lib/mustermann/ast/expander.rb +9 -3
- data/lib/mustermann/ast/node.rb +0 -1
- data/lib/mustermann/ast/parser.rb +5 -6
- data/lib/mustermann/ast/pattern.rb +17 -21
- data/lib/mustermann/ast/transformer.rb +31 -23
- data/lib/mustermann/ast/translator.rb +2 -2
- data/lib/mustermann/ast/validation.rb +8 -5
- data/lib/mustermann/caster.rb +116 -0
- data/lib/mustermann/equality_map.rb +46 -0
- data/lib/mustermann/expander.rb +169 -0
- data/lib/mustermann/pattern.rb +7 -4
- data/lib/mustermann/regexp_based.rb +2 -2
- data/lib/mustermann/router.rb +9 -0
- data/lib/mustermann/router/rack.rb +47 -0
- data/lib/mustermann/router/simple.rb +142 -0
- data/lib/mustermann/shell.rb +9 -2
- data/lib/mustermann/simple.rb +2 -2
- data/lib/mustermann/version.rb +1 -1
- data/mustermann.gemspec +1 -0
- data/spec/expander_spec.rb +77 -0
- data/spec/router/rack_spec.rb +39 -0
- data/spec/router/simple_spec.rb +30 -0
- data/spec/support/coverage.rb +12 -14
- data/spec/support/pattern.rb +10 -3
- metadata +30 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b65ce2df601cc3924de9e697d1cde09019b4185
|
4
|
+
data.tar.gz: f562a51c35fdcb064b2901ccfcffe87ee6417be5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 700b01ee1c08b312d6914d386e0c3abcda85d4c630ef4c1393e57730d85f5e9debe3ce15c7f28670f51cedf2247e1e2ac6dff72d592ca1f009962fcc30a4248a
|
7
|
+
data.tar.gz: 85b14c218fedd69b702fa45cefdad5f54bfe87d3eb13d8c74b717caee1e219ef64252524e2ca608b1b044447ed746b049f5a48e534612ee40ef0fa503d9c8f33
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -27,14 +27,6 @@ pattern = Mustermann.new('/:prefix/*.*')
|
|
27
27
|
pattern.params('/a/b.c') # => { "prefix" => "a", splat => ["b", "c"] }
|
28
28
|
```
|
29
29
|
|
30
|
-
Similarly, it is also possible to generate a string from a pattern by expanding it with such a hash:
|
31
|
-
|
32
|
-
``` ruby
|
33
|
-
pattern = Mustermann.new('/:file(.:ext)?')
|
34
|
-
pattern.expand(file: 'pony') # => "/pony"
|
35
|
-
pattern.expand(file: 'pony', ext: 'jpg') # => "/pony.jpg"
|
36
|
-
```
|
37
|
-
|
38
30
|
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.
|
39
31
|
|
40
32
|
## Types and Options
|
@@ -60,6 +52,7 @@ The available types are:
|
|
60
52
|
<th>Description</th>
|
61
53
|
<th>Example</th>
|
62
54
|
<th>Available Options</th>
|
55
|
+
<th>Additional Features</th>
|
63
56
|
</tr>
|
64
57
|
</thead>
|
65
58
|
<tbody>
|
@@ -71,6 +64,7 @@ The available types are:
|
|
71
64
|
<a href="#ignore_unknown_options"><tt>ignore_unknown_options</tt></a>,
|
72
65
|
<a href="#uri_decode"><tt>uri_decode</tt></a>
|
73
66
|
</td>
|
67
|
+
<td></td>
|
74
68
|
</tr>
|
75
69
|
<tr>
|
76
70
|
<th><a href="#rails"><tt>rails</tt></a></th>
|
@@ -84,6 +78,9 @@ The available types are:
|
|
84
78
|
<a href="#space_matches_plus"><tt>space_matches_plus</tt></a>,
|
85
79
|
<a href="#uri_decode"><tt>uri_decode</tt></a>
|
86
80
|
</td>
|
81
|
+
<td>
|
82
|
+
<a href="#pattern_expanding">Expanding</a>
|
83
|
+
</td>
|
87
84
|
</tr>
|
88
85
|
<tr>
|
89
86
|
<th><a href="#shell"><tt>shell</tt></th>
|
@@ -93,6 +90,7 @@ The available types are:
|
|
93
90
|
<a href="#ignore_unknown_options"><tt>ignore_unknown_options</tt></a>,
|
94
91
|
<a href="#uri_decode"><tt>uri_decode</tt></a>
|
95
92
|
</td>
|
93
|
+
<td></td>
|
96
94
|
</tr>
|
97
95
|
<tr>
|
98
96
|
<th><a href="#simple"><tt>simple</tt></a></th>
|
@@ -104,6 +102,7 @@ The available types are:
|
|
104
102
|
<a href="#space_matches_plus"><tt>space_matches_plus</tt></a>,
|
105
103
|
<a href="#uri_decode"><tt>uri_decode</tt></a>
|
106
104
|
</td>
|
105
|
+
<td></td>
|
107
106
|
</tr>
|
108
107
|
<tr>
|
109
108
|
<th><a href="#sinatra"><tt>sinatra</tt></a></th>
|
@@ -117,6 +116,9 @@ The available types are:
|
|
117
116
|
<a href="#space_matches_plus"><tt>space_matches_plus</tt></a>,
|
118
117
|
<a href="#uri_decode"><tt>uri_decode</tt></a>
|
119
118
|
</td>
|
119
|
+
<td>
|
120
|
+
<a href="#pattern_expanding">Expanding</a>
|
121
|
+
</td>
|
120
122
|
</tr>
|
121
123
|
<tr>
|
122
124
|
<th><a href="#template"><tt>template</tt></a></th>
|
@@ -130,6 +132,9 @@ The available types are:
|
|
130
132
|
<a href="#space_matches_plus"><tt>space_matches_plus</tt></a>,
|
131
133
|
<a href="#uri_decode"><tt>uri_decode</tt></a>
|
132
134
|
</td>
|
135
|
+
<td>
|
136
|
+
<a href="#pattern_expanding">Expanding</a>
|
137
|
+
</td>
|
133
138
|
</tr>
|
134
139
|
</tbody>
|
135
140
|
</table>
|
@@ -257,6 +262,89 @@ end
|
|
257
262
|
* It would introduce breaking changes, even though these would be minor
|
258
263
|
* Like Sinatra 2.0, Mustermann requires Ruby 2.0 or newer
|
259
264
|
|
265
|
+
<a name="pattern_expanding"></a>
|
266
|
+
## Expanding
|
267
|
+
|
268
|
+
Similarly to parsing, it is also possible to generate a string from a pattern by expanding it with a hash.
|
269
|
+
For simple expansions, you can use `Pattern#expand`.
|
270
|
+
|
271
|
+
``` ruby
|
272
|
+
pattern = Mustermann.new('/:file(.:ext)?')
|
273
|
+
pattern.expand(file: 'pony') # => "/pony"
|
274
|
+
pattern.expand(file: 'pony', ext: 'jpg') # => "/pony.jpg"
|
275
|
+
pattern.expand(ext: 'jpg') # raises Mustermann::ExpandError
|
276
|
+
```
|
277
|
+
|
278
|
+
Expanding can be useful for instance when implementing link helpers.
|
279
|
+
|
280
|
+
### Expander Objects
|
281
|
+
|
282
|
+
To get fine-grained control over expansion, you can use `Mustermann::Expander` directly.
|
283
|
+
|
284
|
+
You can create an expander object directly from a string:
|
285
|
+
|
286
|
+
``` ruby
|
287
|
+
require 'mustermann/expander'
|
288
|
+
expander = Mustermann::Expander("/:file.jpg")
|
289
|
+
expander.expand(file: 'pony') # => "/pony.jpg"
|
290
|
+
|
291
|
+
expander = Mustermann::Expander(":file(.:ext)", type: :rails)
|
292
|
+
expander.expand(file: 'pony', ext: 'jpg') # => "/pony.jpg"
|
293
|
+
```
|
294
|
+
|
295
|
+
Or you can pass it a pattern instance:
|
296
|
+
|
297
|
+
``` ruby
|
298
|
+
require 'mustermann'
|
299
|
+
pattern = Mustermann.new("/:file")
|
300
|
+
|
301
|
+
require 'mustermann/expander'
|
302
|
+
expander = Mustermann::Expander.new(pattern)
|
303
|
+
```
|
304
|
+
|
305
|
+
### Expanding Multiple Patterns
|
306
|
+
|
307
|
+
You can add patterns to an expander object via `<<`:
|
308
|
+
|
309
|
+
``` ruby
|
310
|
+
expander = Mustermann::Expander.new
|
311
|
+
expander << "/users/:user_id"
|
312
|
+
expander << "/pages/:page_id"
|
313
|
+
|
314
|
+
expander.expand(user_id: 15) # => "/users/15"
|
315
|
+
expander.expand(page_id: 58) # => "/pages/58"
|
316
|
+
```
|
317
|
+
|
318
|
+
You can set pattern options when creating the expander:
|
319
|
+
|
320
|
+
``` ruby
|
321
|
+
expander = Mustermann::Expander.new(type: :template)
|
322
|
+
expander << "/users/{user_id}"
|
323
|
+
expander << "/pages/{page_id}"
|
324
|
+
```
|
325
|
+
|
326
|
+
Additionally, it is possible to combine patterns of different types:
|
327
|
+
|
328
|
+
``` ruby
|
329
|
+
expander = Mustermann::Expander.new
|
330
|
+
expander << Mustermann.new("/users/{user_id}", type: :template)
|
331
|
+
expander << Mustermann.new("/pages/:page_id", type: :rails)
|
332
|
+
```
|
333
|
+
|
334
|
+
### Handling Additional Values
|
335
|
+
|
336
|
+
The handling of additional values passed in to `expand` can be changed by setting the `additional_values` option:
|
337
|
+
|
338
|
+
``` ruby
|
339
|
+
expander = Mustermann::Expander.new("/:slug", additional_values: :raise)
|
340
|
+
expander.expand(slug: "foo", value: "bar") # raises Mustermann::ExpandError
|
341
|
+
|
342
|
+
expander = Mustermann::Expander.new("/:slug", additional_values: :ignore)
|
343
|
+
expander.expand(slug: "foo", value: "bar") # => "/foo"
|
344
|
+
|
345
|
+
expander = Mustermann::Expander.new("/:slug", additional_values: :append)
|
346
|
+
expander.expand(slug: "foo", value: "bar") # => "/foo?value=bar"
|
347
|
+
```
|
260
348
|
|
261
349
|
## Partial Loading and Thread Safety
|
262
350
|
|
@@ -645,13 +733,56 @@ you should set `uri_decode` to `false` in order to conform with the specificatio
|
|
645
733
|
|
646
734
|
If you are looking for an alternative implementation that also supports expanding, check out [addressable](http://addressable.rubyforge.org/).
|
647
735
|
|
736
|
+
## Routers
|
737
|
+
|
738
|
+
Mustermann comes with basic router implementations that will call certain callbacks depending on the input.
|
739
|
+
|
740
|
+
### Simple Router
|
741
|
+
|
742
|
+
The simple router chooses callbacks based on an input string.
|
743
|
+
|
744
|
+
``` ruby
|
745
|
+
require 'mustermann/router/simple'
|
746
|
+
|
747
|
+
router = Mustermann::Router::Simple.new(default: 42)
|
748
|
+
router.on(':name', capture: :digit) { |string| string.to_i }
|
749
|
+
router.call("23") # => 23
|
750
|
+
router.call("example") # => 42
|
751
|
+
```
|
752
|
+
|
753
|
+
### Rack Router
|
754
|
+
|
755
|
+
This is not a full replacement for Rails, Sinatra, Cuba, etc, as it only cares about path based routing.
|
756
|
+
|
757
|
+
``` ruby
|
758
|
+
require 'mustermann/router/rack'
|
759
|
+
|
760
|
+
router = Mustermann::Router::Rack do
|
761
|
+
on '/' do |env|
|
762
|
+
[200, {'Content-Type' => 'text/plain'}, ['Hello World!']]
|
763
|
+
end
|
764
|
+
|
765
|
+
on '/:name' do |env|
|
766
|
+
name = env['mustermann.params']['name']
|
767
|
+
[200, {'Content-Type' => 'text/plain'}, ["Hello #{name}!"]]
|
768
|
+
end
|
769
|
+
|
770
|
+
on '/something/*', call: SomeApp
|
771
|
+
end
|
772
|
+
|
773
|
+
# in a config.ru
|
774
|
+
run router
|
775
|
+
```
|
776
|
+
|
648
777
|
## Requirements
|
649
778
|
|
650
779
|
Mustermann has no dependencies besides a Ruby 2.0 compatible Ruby implementation.
|
651
780
|
|
652
781
|
It is known to work on **MRI 2.0** and **MRI trunk**.
|
653
|
-
|
654
|
-
**
|
782
|
+
|
783
|
+
**JRuby** is not yet fully supported. It is possible to run large parts of Mustermann by passing in `--2.0 -X-C` starting from JRuby 1.7.4. See [issue #2](https://github.com/rkh/mustermann/issues/2) for up to date information.
|
784
|
+
|
785
|
+
**Rubinius** is not yet able to parse the Mustermann source code. See [issue #14](https://github.com/rkh/mustermann/issues/14) for up to date information.
|
655
786
|
|
656
787
|
## Release History
|
657
788
|
|
@@ -664,13 +795,26 @@ As there has been no stable release yet, the API might still change, though I co
|
|
664
795
|
|
665
796
|
### Development Releases
|
666
797
|
|
667
|
-
* **Mustermann 0.0
|
798
|
+
* **Mustermann 0.2.0** (2013-08-24)
|
668
799
|
* More Infos:
|
669
|
-
[RubyGems.org](http://rubygems.org/gems/mustermann/versions/0.0
|
670
|
-
[RubyDoc.info](rubydoc.info/gems/mustermann/0.0
|
671
|
-
[GitHub.com](https://github.com/rkh/mustermann/tree/v0.0
|
672
|
-
*
|
800
|
+
[RubyGems.org](http://rubygems.org/gems/mustermann/versions/0.2.0),
|
801
|
+
[RubyDoc.info](http://rubydoc.info/gems/mustermann/0.2.0/frames),
|
802
|
+
[GitHub.com](https://github.com/rkh/mustermann/tree/v0.2.0)
|
803
|
+
* Add first class expander objects.
|
804
|
+
* Add params casting for expander.
|
805
|
+
* Add simple router and rack router.
|
806
|
+
* Add weak equality map to significantly improve performance.
|
807
|
+
* Fix Ruby warnings.
|
808
|
+
* Improve documentation.
|
809
|
+
* Refactor pattern validation, AST transformations.
|
810
|
+
* Increase test coverage (from 100%+ to 100%++).
|
811
|
+
* Improve JRuby compatibility.
|
812
|
+
* Work around bug in 2.0.0-p0.
|
673
813
|
* **Mustermann 0.1.0** (2013-05-12)
|
814
|
+
* More Infos:
|
815
|
+
[RubyGems.org](http://rubygems.org/gems/mustermann/versions/0.1.0),
|
816
|
+
[RubyDoc.info](http://rubydoc.info/gems/mustermann/0.1.0/frames),
|
817
|
+
[GitHub.com](https://github.com/rkh/mustermann/tree/v0.1.0)
|
674
818
|
* Add `Pattern#expand` for generating strings from patterns.
|
675
819
|
* Add better internal API for working with the AST.
|
676
820
|
* Improved documentation.
|
@@ -679,9 +823,15 @@ As there has been no stable release yet, the API might still change, though I co
|
|
679
823
|
* Better handling of edge cases around extend.
|
680
824
|
* More specs to ensure API stability.
|
681
825
|
* Largely rework internals of Sinatra, Rails and Template patterns.
|
826
|
+
* **Mustermann 0.0.1** (2013-04-27)
|
827
|
+
* More Infos:
|
828
|
+
[RubyGems.org](http://rubygems.org/gems/mustermann/versions/0.0.1),
|
829
|
+
[RubyDoc.info](http://rubydoc.info/gems/mustermann/0.0.1/frames),
|
830
|
+
[GitHub.com](https://github.com/rkh/mustermann/tree/v0.0.1)
|
831
|
+
* Initial Release.
|
682
832
|
|
683
833
|
### Upcoming Releases
|
684
834
|
|
685
|
-
* **Mustermann 0.
|
835
|
+
* **Mustermann 0.3.0** (next release with new features)
|
686
836
|
* **Mustermann 1.0.0** (before Sinatra 2.0)
|
687
837
|
* First stable release.
|
data/Rakefile
CHANGED
data/bench/capturing.rb
CHANGED
@@ -7,14 +7,14 @@ require 'addressable/template'
|
|
7
7
|
|
8
8
|
|
9
9
|
Mustermann.register(:regexp, Class.new(Mustermann::RegexpBased) {
|
10
|
-
def compile(
|
11
|
-
Regexp.new(string)
|
10
|
+
def compile(**options)
|
11
|
+
Regexp.new(@string)
|
12
12
|
end
|
13
13
|
}, load: false)
|
14
14
|
|
15
15
|
Mustermann.register(:addressable, Class.new(Mustermann::RegexpBased) {
|
16
|
-
def compile(
|
17
|
-
Addressable::Template.new(string)
|
16
|
+
def compile(**options)
|
17
|
+
Addressable::Template.new(@string)
|
18
18
|
end
|
19
19
|
}, load: false)
|
20
20
|
|
data/bench/regexp.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
|
3
|
+
puts " atomic vs normal segments ".center(52, '=')
|
4
|
+
|
5
|
+
types = {
|
6
|
+
normal: /\A\/(?:a|%61)\/(?<b>[^\/\?#]+)(?:\/(?<c>[^\/\?#]+))?\Z/,
|
7
|
+
atomic: /\A\/(?:a|%61)\/(?<b>(?>[^\/\?#]+))(?:\/(?<c>(?>[^\/\?#]+)))?\Z/
|
8
|
+
}
|
9
|
+
|
10
|
+
Benchmark.bmbm do |x|
|
11
|
+
types.each do |name, regexp|
|
12
|
+
string = "/a/" << ?a * 10000 << "/" << ?a * 5000
|
13
|
+
fail unless regexp.match(string)
|
14
|
+
string << "/"
|
15
|
+
fail if regexp.match(string)
|
16
|
+
|
17
|
+
x.report name.to_s do
|
18
|
+
100.times { regexp.match(string) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -81,6 +81,12 @@ module Mustermann
|
|
81
81
|
pattern % values.values_at(*keys)
|
82
82
|
end
|
83
83
|
|
84
|
+
# @see Mustermann::Expander#with_rest
|
85
|
+
# @!visibility private
|
86
|
+
def expandable_keys(keys)
|
87
|
+
mappings.keys.select { |k| (k - keys).empty? }.max_by(&:size) || keys
|
88
|
+
end
|
89
|
+
|
84
90
|
# helper method for raising an error for unexpandable values
|
85
91
|
# @!visibility private
|
86
92
|
def error_for(values)
|
@@ -91,17 +97,17 @@ module Mustermann
|
|
91
97
|
# @see Mustermann::AST::Translator#expand
|
92
98
|
# @!visibility private
|
93
99
|
def escape(string, *args)
|
94
|
-
# URI::Parser is pretty slow, let's not had every string to it, even if it's
|
100
|
+
# URI::Parser is pretty slow, let's not had every string to it, even if it's unnecessary
|
95
101
|
string =~ /\A\w*\Z/ ? string : super
|
96
102
|
end
|
97
103
|
|
98
|
-
# Turns a sprintf pattern into our secret internal data
|
104
|
+
# Turns a sprintf pattern into our secret internal data structure.
|
99
105
|
# @!visibility private
|
100
106
|
def pattern(string = "", *keys, **filters)
|
101
107
|
[[keys, string, filters]]
|
102
108
|
end
|
103
109
|
|
104
|
-
# Creates the product of two of our secret internal data
|
110
|
+
# Creates the product of two of our secret internal data structures.
|
105
111
|
# @!visibility private
|
106
112
|
def add_to(list, result)
|
107
113
|
list << [[], ""] if list.empty?
|
data/lib/mustermann/ast/node.rb
CHANGED
@@ -9,7 +9,6 @@ module Mustermann
|
|
9
9
|
# @!visibility private
|
10
10
|
class Parser
|
11
11
|
# @param [String] string to be parsed
|
12
|
-
# @param [Hash] **options parse options
|
13
12
|
# @return [Mustermann::AST::Node] parse tree for string
|
14
13
|
# @!visibility private
|
15
14
|
def self.parse(string)
|
@@ -64,7 +63,7 @@ module Mustermann
|
|
64
63
|
block ? type.parse(*args, &block) : type.new(*args)
|
65
64
|
end
|
66
65
|
|
67
|
-
# Create a node for a character we don't have an
|
66
|
+
# Create a node for a character we don't have an explicit rule for.
|
68
67
|
#
|
69
68
|
# @param [String] char the character
|
70
69
|
# @return [Mustermann::AST::Node] the node
|
@@ -88,9 +87,9 @@ module Mustermann
|
|
88
87
|
# @return [Mustermann::AST::Node] node with suffix
|
89
88
|
# @!visibility private
|
90
89
|
def read_suffix(element)
|
91
|
-
self.class.suffix.inject(element) do |
|
92
|
-
next
|
93
|
-
instance_exec(payload,
|
90
|
+
self.class.suffix.inject(element) do |ele, (regexp, callback)|
|
91
|
+
next ele unless payload = scan(regexp)
|
92
|
+
instance_exec(payload, ele, &callback)
|
94
93
|
end
|
95
94
|
end
|
96
95
|
|
@@ -122,7 +121,7 @@ module Mustermann
|
|
122
121
|
# Helper for raising an exception for an unexpected character.
|
123
122
|
# Will read character from buffer if buffer is passed in.
|
124
123
|
#
|
125
|
-
# @param [String, nil] char the
|
124
|
+
# @param [String, nil] char the unexpected character
|
126
125
|
# @raise [Mustermann::ParseError, Exception]
|
127
126
|
# @!visibility private
|
128
127
|
def unexpected(char = getch, exception: ParseError)
|
@@ -2,8 +2,10 @@ require 'mustermann/ast/parser'
|
|
2
2
|
require 'mustermann/ast/compiler'
|
3
3
|
require 'mustermann/ast/transformer'
|
4
4
|
require 'mustermann/ast/validation'
|
5
|
-
|
5
|
+
|
6
6
|
require 'mustermann/regexp_based'
|
7
|
+
require 'mustermann/equality_map'
|
8
|
+
require 'mustermann/expander'
|
7
9
|
|
8
10
|
module Mustermann
|
9
11
|
# @see Mustermann::AST::Pattern
|
@@ -15,14 +17,9 @@ module Mustermann
|
|
15
17
|
|
16
18
|
extend Forwardable, SingleForwardable
|
17
19
|
single_delegate on: :parser, suffix: :parser
|
18
|
-
instance_delegate %i[parser compiler transformer validation
|
20
|
+
instance_delegate %i[parser compiler transformer validation] => 'self.class'
|
19
21
|
instance_delegate parse: :parser, transform: :transformer, validate: :validation
|
20
22
|
|
21
|
-
# @api private
|
22
|
-
# @return [#expand] expander object for pattern
|
23
|
-
# @!visibility private
|
24
|
-
attr_accessor :expander
|
25
|
-
|
26
23
|
# @api private
|
27
24
|
# @return [#parse] parser object for pattern
|
28
25
|
# @!visibility private
|
@@ -53,25 +50,22 @@ module Mustermann
|
|
53
50
|
Validation
|
54
51
|
end
|
55
52
|
|
56
|
-
# @api private
|
57
|
-
# @return [#new] expander factory for pattern
|
58
53
|
# @!visibility private
|
59
|
-
def
|
60
|
-
Expander
|
61
|
-
end
|
62
|
-
|
63
|
-
# @!visibility private
|
64
|
-
def compile(string, **options)
|
65
|
-
self.expander = expander_class.new
|
54
|
+
def compile(**options)
|
66
55
|
options[:except] &&= parse options[:except]
|
67
|
-
|
68
|
-
expander.add(ast)
|
69
|
-
compiler.compile(ast, **options)
|
56
|
+
compiler.compile(to_ast, **options)
|
70
57
|
rescue CompileError => error
|
71
|
-
error.message << ": %p" % string
|
58
|
+
error.message << ": %p" % @string
|
72
59
|
raise error
|
73
60
|
end
|
74
61
|
|
62
|
+
# Internal AST representation of pattern.
|
63
|
+
# @!visibility private
|
64
|
+
def to_ast
|
65
|
+
@ast_cache ||= EqualityMap.new
|
66
|
+
@ast_cache.fetch(@string) { validate(transform(parse(@string))) }
|
67
|
+
end
|
68
|
+
|
75
69
|
# All AST-based pattern implementations support expanding.
|
76
70
|
#
|
77
71
|
# @example (see Mustermann::Pattern#expand)
|
@@ -79,8 +73,10 @@ module Mustermann
|
|
79
73
|
# @return (see Mustermann::Pattern#expand)
|
80
74
|
# @raise (see Mustermann::Pattern#expand)
|
81
75
|
# @see Mustermann::Pattern#expand
|
76
|
+
# @see Mustermann::Expander
|
82
77
|
def expand(**values)
|
83
|
-
expander.
|
78
|
+
@expander ||= Mustermann::Expander.new(self)
|
79
|
+
@expander.expand(**values)
|
84
80
|
end
|
85
81
|
|
86
82
|
private :compile
|