mustermann 0.1.0 → 0.2.0
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/.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
|