mustermann 3.0.4 → 4.0.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/LICENSE +1 -2
- data/README.md +238 -261
- data/lib/mustermann/ast/compiler.rb +128 -30
- data/lib/mustermann/ast/converters.rb +41 -0
- data/lib/mustermann/ast/expander.rb +4 -5
- data/lib/mustermann/ast/fast_pattern.rb +122 -0
- data/lib/mustermann/ast/param_scanner.rb +38 -6
- data/lib/mustermann/ast/parser.rb +2 -3
- data/lib/mustermann/ast/pattern.rb +26 -4
- data/lib/mustermann/ast/transformer.rb +7 -0
- data/lib/mustermann/ast/translator.rb +11 -7
- data/lib/mustermann/composite.rb +25 -6
- data/lib/mustermann/concat.rb +16 -5
- data/lib/mustermann/error.rb +1 -0
- data/lib/mustermann/expander.rb +26 -4
- data/lib/mustermann/hybrid.rb +50 -0
- data/lib/mustermann/match.rb +155 -0
- data/lib/mustermann/pattern.rb +27 -32
- data/lib/mustermann/rails.rb +63 -0
- data/lib/mustermann/regexp_based.rb +70 -9
- data/lib/mustermann/router.rb +104 -0
- data/lib/mustermann/set/cache.rb +48 -0
- data/lib/mustermann/set/linear.rb +32 -0
- data/lib/mustermann/set/match.rb +23 -0
- data/lib/mustermann/set/strict_order.rb +29 -0
- data/lib/mustermann/set/trie.rb +270 -0
- data/lib/mustermann/set.rb +445 -0
- data/lib/mustermann/sinatra/safe_renderer.rb +1 -1
- data/lib/mustermann/sinatra/try_convert.rb +49 -11
- data/lib/mustermann/sinatra.rb +35 -11
- data/lib/mustermann/version.rb +1 -1
- data/lib/mustermann/versions.rb +47 -0
- data/lib/mustermann.rb +0 -15
- metadata +31 -45
- data/bench/capturing.rb +0 -57
- data/bench/regexp.rb +0 -21
- data/bench/simple_vs_sinatra.rb +0 -23
- data/bench/template_vs_addressable.rb +0 -26
- data/bench/uri_parser_object.rb +0 -16
- data/lib/mustermann/extension.rb +0 -3
- data/lib/mustermann/mapper.rb +0 -91
- data/lib/mustermann/pattern_cache.rb +0 -50
- data/lib/mustermann/simple_match.rb +0 -49
- data/lib/mustermann/to_pattern.rb +0 -51
- data/mustermann.gemspec +0 -18
- data/spec/ast_spec.rb +0 -15
- data/spec/composite_spec.rb +0 -163
- data/spec/concat_spec.rb +0 -127
- data/spec/equality_map_spec.rb +0 -42
- data/spec/expander_spec.rb +0 -123
- data/spec/identity_spec.rb +0 -127
- data/spec/mapper_spec.rb +0 -77
- data/spec/mustermann_spec.rb +0 -81
- data/spec/pattern_spec.rb +0 -54
- data/spec/regexp_based_spec.rb +0 -9
- data/spec/regular_spec.rb +0 -119
- data/spec/simple_match_spec.rb +0 -11
- data/spec/sinatra_spec.rb +0 -836
- data/spec/to_pattern_spec.rb +0 -70
data/lib/mustermann.rb
CHANGED
|
@@ -115,19 +115,4 @@ module Mustermann
|
|
|
115
115
|
def self.normalized_type(type)
|
|
116
116
|
type.to_s.gsub('-', '_').downcase
|
|
117
117
|
end
|
|
118
|
-
|
|
119
|
-
# @!visibility private
|
|
120
|
-
def self.extend_object(object)
|
|
121
|
-
return super unless defined? ::Sinatra::Base and object.is_a? Class and object < ::Sinatra::Base
|
|
122
|
-
require 'mustermann/extension'
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
# :nocov:
|
|
127
|
-
begin
|
|
128
|
-
require 'mustermann/visualizer' if defined?(Pry) or defined?(IRB)
|
|
129
|
-
rescue LoadError => error
|
|
130
|
-
raise error unless error.path == 'mustermann/visualizer'
|
|
131
|
-
$stderr.puts(error.message) if caller_locations[1].absolute_path =~ %r{/lib/pry/|/irb/|^\((?:irb|pry)\)$}
|
|
132
118
|
end
|
|
133
|
-
# :nocov:
|
metadata
CHANGED
|
@@ -1,30 +1,24 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mustermann
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 4.0.0
|
|
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: []
|
|
11
14
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
|
-
dependencies:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
version: 0.0.1
|
|
20
|
-
type: :runtime
|
|
21
|
-
prerelease: false
|
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
-
requirements:
|
|
24
|
-
- - "~>"
|
|
25
|
-
- !ruby/object:Gem::Version
|
|
26
|
-
version: 0.0.1
|
|
27
|
-
description: A library implementing patterns that behave like regular expressions.
|
|
15
|
+
dependencies: []
|
|
16
|
+
description: |
|
|
17
|
+
Mustermann is your personal string matching expert. As an expert in the field of strings and patterns,
|
|
18
|
+
Mustermann keeps its runtime dependencies to a minimum and is fully covered with specs and documentation.
|
|
19
|
+
|
|
20
|
+
Given a string pattern, Mustermann will turn it into an object that behaves like a regular expression
|
|
21
|
+
and has comparable performance characteristics.
|
|
28
22
|
email: sinatrarb@googlegroups.com
|
|
29
23
|
executables: []
|
|
30
24
|
extensions: []
|
|
@@ -32,15 +26,12 @@ extra_rdoc_files: []
|
|
|
32
26
|
files:
|
|
33
27
|
- LICENSE
|
|
34
28
|
- README.md
|
|
35
|
-
- bench/capturing.rb
|
|
36
|
-
- bench/regexp.rb
|
|
37
|
-
- bench/simple_vs_sinatra.rb
|
|
38
|
-
- bench/template_vs_addressable.rb
|
|
39
|
-
- bench/uri_parser_object.rb
|
|
40
29
|
- lib/mustermann.rb
|
|
41
30
|
- lib/mustermann/ast/boundaries.rb
|
|
42
31
|
- lib/mustermann/ast/compiler.rb
|
|
32
|
+
- lib/mustermann/ast/converters.rb
|
|
43
33
|
- lib/mustermann/ast/expander.rb
|
|
34
|
+
- lib/mustermann/ast/fast_pattern.rb
|
|
44
35
|
- lib/mustermann/ast/node.rb
|
|
45
36
|
- lib/mustermann/ast/param_scanner.rb
|
|
46
37
|
- lib/mustermann/ast/parser.rb
|
|
@@ -55,40 +46,35 @@ files:
|
|
|
55
46
|
- lib/mustermann/equality_map.rb
|
|
56
47
|
- lib/mustermann/error.rb
|
|
57
48
|
- lib/mustermann/expander.rb
|
|
58
|
-
- lib/mustermann/
|
|
49
|
+
- lib/mustermann/hybrid.rb
|
|
59
50
|
- lib/mustermann/identity.rb
|
|
60
|
-
- lib/mustermann/
|
|
51
|
+
- lib/mustermann/match.rb
|
|
61
52
|
- lib/mustermann/pattern.rb
|
|
62
|
-
- lib/mustermann/
|
|
53
|
+
- lib/mustermann/rails.rb
|
|
63
54
|
- lib/mustermann/regexp.rb
|
|
64
55
|
- lib/mustermann/regexp_based.rb
|
|
65
56
|
- lib/mustermann/regular.rb
|
|
66
|
-
- lib/mustermann/
|
|
57
|
+
- lib/mustermann/router.rb
|
|
58
|
+
- lib/mustermann/set.rb
|
|
59
|
+
- lib/mustermann/set/cache.rb
|
|
60
|
+
- lib/mustermann/set/linear.rb
|
|
61
|
+
- lib/mustermann/set/match.rb
|
|
62
|
+
- lib/mustermann/set/strict_order.rb
|
|
63
|
+
- lib/mustermann/set/trie.rb
|
|
67
64
|
- lib/mustermann/sinatra.rb
|
|
68
65
|
- lib/mustermann/sinatra/parser.rb
|
|
69
66
|
- lib/mustermann/sinatra/safe_renderer.rb
|
|
70
67
|
- lib/mustermann/sinatra/try_convert.rb
|
|
71
|
-
- lib/mustermann/to_pattern.rb
|
|
72
68
|
- lib/mustermann/version.rb
|
|
73
|
-
- mustermann.
|
|
74
|
-
- spec/ast_spec.rb
|
|
75
|
-
- spec/composite_spec.rb
|
|
76
|
-
- spec/concat_spec.rb
|
|
77
|
-
- spec/equality_map_spec.rb
|
|
78
|
-
- spec/expander_spec.rb
|
|
79
|
-
- spec/identity_spec.rb
|
|
80
|
-
- spec/mapper_spec.rb
|
|
81
|
-
- spec/mustermann_spec.rb
|
|
82
|
-
- spec/pattern_spec.rb
|
|
83
|
-
- spec/regexp_based_spec.rb
|
|
84
|
-
- spec/regular_spec.rb
|
|
85
|
-
- spec/simple_match_spec.rb
|
|
86
|
-
- spec/sinatra_spec.rb
|
|
87
|
-
- spec/to_pattern_spec.rb
|
|
69
|
+
- lib/mustermann/versions.rb
|
|
88
70
|
homepage: https://github.com/sinatra/mustermann
|
|
89
71
|
licenses:
|
|
90
72
|
- MIT
|
|
91
|
-
metadata:
|
|
73
|
+
metadata:
|
|
74
|
+
bug_tracker_uri: https://github.com/sinatra/mustermann/issues
|
|
75
|
+
changelog_uri: https://github.com/sinatra/mustermann/blob/main/CHANGELOG.md
|
|
76
|
+
documentation_uri: https://github.com/sinatra/mustermann/tree/main/mustermann#readme
|
|
77
|
+
source_code_uri: https://github.com/sinatra/mustermann/tree/main/mustermann
|
|
92
78
|
rdoc_options: []
|
|
93
79
|
require_paths:
|
|
94
80
|
- lib
|
|
@@ -96,14 +82,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
96
82
|
requirements:
|
|
97
83
|
- - ">="
|
|
98
84
|
- !ruby/object:Gem::Version
|
|
99
|
-
version:
|
|
85
|
+
version: 3.3.0
|
|
100
86
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
87
|
requirements:
|
|
102
88
|
- - ">="
|
|
103
89
|
- !ruby/object:Gem::Version
|
|
104
90
|
version: '0'
|
|
105
91
|
requirements: []
|
|
106
|
-
rubygems_version:
|
|
92
|
+
rubygems_version: 4.0.6
|
|
107
93
|
specification_version: 4
|
|
108
94
|
summary: Your personal string matching expert.
|
|
109
95
|
test_files: []
|
data/bench/capturing.rb
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
$:.unshift File.expand_path('../lib', __dir__)
|
|
2
|
-
|
|
3
|
-
require 'benchmark'
|
|
4
|
-
require 'mustermann'
|
|
5
|
-
require 'mustermann/regexp_based'
|
|
6
|
-
require 'addressable/template'
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Mustermann.register(:regexp, Class.new(Mustermann::RegexpBased) {
|
|
10
|
-
def compile(**options)
|
|
11
|
-
Regexp.new(@string)
|
|
12
|
-
end
|
|
13
|
-
}, load: false)
|
|
14
|
-
|
|
15
|
-
Mustermann.register(:addressable, Class.new(Mustermann::RegexpBased) {
|
|
16
|
-
def compile(**options)
|
|
17
|
-
Addressable::Template.new(@string)
|
|
18
|
-
end
|
|
19
|
-
}, load: false)
|
|
20
|
-
|
|
21
|
-
list = [
|
|
22
|
-
[:sinatra, '/*/:name' ],
|
|
23
|
-
[:rails, '/*prefix/:name' ],
|
|
24
|
-
[:simple, '/*/:name' ],
|
|
25
|
-
[:template, '{/prefix*}/{name}' ],
|
|
26
|
-
[:regexp, '\A\/(?<splat>.*?)\/(?<name>[^\/\?#]+)\Z' ],
|
|
27
|
-
[:addressable, '{/prefix*}/{name}' ]
|
|
28
|
-
]
|
|
29
|
-
|
|
30
|
-
def self.assert(value)
|
|
31
|
-
fail unless value
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
string = '/a/b/c/d'
|
|
35
|
-
name = 'd'
|
|
36
|
-
|
|
37
|
-
GC.disable
|
|
38
|
-
|
|
39
|
-
puts "Compilation:"
|
|
40
|
-
Benchmark.bmbm do |x|
|
|
41
|
-
list.each do |type, pattern|
|
|
42
|
-
x.report(type) { 1_000.times { Mustermann.new(pattern, type: type) } }
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
puts "", "Matching with two captures (one splat, one normal):"
|
|
47
|
-
Benchmark.bmbm do |x|
|
|
48
|
-
list.each do |type, pattern|
|
|
49
|
-
pattern = Mustermann.new(pattern, type: type)
|
|
50
|
-
x.report type do
|
|
51
|
-
10_000.times do
|
|
52
|
-
match = pattern.match(string)
|
|
53
|
-
assert match[:name] == name
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
data/bench/regexp.rb
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
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
|
data/bench/simple_vs_sinatra.rb
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
$:.unshift File.expand_path('../lib', __dir__)
|
|
2
|
-
|
|
3
|
-
require 'benchmark'
|
|
4
|
-
require 'mustermann/simple'
|
|
5
|
-
require 'mustermann/sinatra'
|
|
6
|
-
|
|
7
|
-
[Mustermann::Simple, Mustermann::Sinatra].each do |klass|
|
|
8
|
-
puts "", " #{klass} ".center(64, '=')
|
|
9
|
-
Benchmark.bmbm do |x|
|
|
10
|
-
no_capture = klass.new("/simple")
|
|
11
|
-
x.report("no captures, match") { 1_000.times { no_capture.match('/simple') } }
|
|
12
|
-
x.report("no captures, miss") { 1_000.times { no_capture.match('/miss') } }
|
|
13
|
-
|
|
14
|
-
simple = klass.new("/:name")
|
|
15
|
-
x.report("simple, match") { 1_000.times { simple.match('/simple').captures } }
|
|
16
|
-
x.report("simple, miss") { 1_000.times { simple.match('/mi/ss') } }
|
|
17
|
-
|
|
18
|
-
splat = klass.new("/*")
|
|
19
|
-
x.report("splat, match") { 1_000.times { splat.match("/a/b/c").captures } }
|
|
20
|
-
x.report("splat, miss") { 1_000.times { splat.match("/a/b/c.miss") } }
|
|
21
|
-
end
|
|
22
|
-
puts
|
|
23
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
$:.unshift File.expand_path('../lib', __dir__)
|
|
2
|
-
|
|
3
|
-
require 'benchmark'
|
|
4
|
-
require 'mustermann/template'
|
|
5
|
-
require 'addressable/template'
|
|
6
|
-
|
|
7
|
-
[Mustermann::Template, Addressable::Template].each do |klass|
|
|
8
|
-
puts "", " #{klass} ".center(64, '=')
|
|
9
|
-
Benchmark.bmbm do |x|
|
|
10
|
-
no_capture = klass.new("/simple")
|
|
11
|
-
x.report("no captures, match") { 1_000.times { no_capture.match('/simple') } }
|
|
12
|
-
x.report("no captures, miss") { 1_000.times { no_capture.match('/miss') } }
|
|
13
|
-
|
|
14
|
-
simple = klass.new("/{match}")
|
|
15
|
-
x.report("simple, match") { 1_000.times { simple.match('/simple').captures } }
|
|
16
|
-
x.report("simple, miss") { 1_000.times { simple.match('/mi/ss') } }
|
|
17
|
-
|
|
18
|
-
explode = klass.new("{/segments*}")
|
|
19
|
-
x.report("explode, match") { 1_000.times { explode.match("/a/b/c").captures } }
|
|
20
|
-
x.report("explode, miss") { 1_000.times { explode.match("/a/b/c.miss") } }
|
|
21
|
-
|
|
22
|
-
expand = klass.new("/prefix/{foo}/something/{bar}")
|
|
23
|
-
x.report("expand") { 100.times { expand.expand(foo: 'foo', bar: 'bar').to_s } }
|
|
24
|
-
end
|
|
25
|
-
puts
|
|
26
|
-
end
|
data/bench/uri_parser_object.rb
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
require "objspace"
|
|
2
|
-
require "uri"
|
|
3
|
-
require_relative "../lib/mustermann/ast/translator"
|
|
4
|
-
|
|
5
|
-
translator = Mustermann::AST::Translator.new
|
|
6
|
-
translator.escape("foo")
|
|
7
|
-
|
|
8
|
-
h1 = ObjectSpace.each_object.inject(Hash.new 0) { |h, o| h[o.class] += 1; h }
|
|
9
|
-
|
|
10
|
-
100.times do
|
|
11
|
-
translator.escape("foo")
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
h2 = ObjectSpace.each_object.inject(Hash.new 0) { |h, o| h[o.class] += 1; h }
|
|
15
|
-
|
|
16
|
-
raise if (h2[URI::RFC2396_Parser] - h1[URI::RFC2396_Parser] != 0)
|
data/lib/mustermann/extension.rb
DELETED
data/lib/mustermann/mapper.rb
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
require 'mustermann'
|
|
3
|
-
require 'mustermann/expander'
|
|
4
|
-
|
|
5
|
-
module Mustermann
|
|
6
|
-
# A mapper allows mapping one string to another based on pattern parsing and expanding.
|
|
7
|
-
#
|
|
8
|
-
# @example
|
|
9
|
-
# require 'mustermann/mapper'
|
|
10
|
-
# mapper = Mustermann::Mapper.new("/:foo" => "/:foo.html")
|
|
11
|
-
# mapper['/example'] # => "/example.html"
|
|
12
|
-
class Mapper
|
|
13
|
-
# Creates a new mapper.
|
|
14
|
-
#
|
|
15
|
-
# @overload initialize(**options)
|
|
16
|
-
# @param options [Hash] options The options hash
|
|
17
|
-
# @yield block for generating mappings as a hash
|
|
18
|
-
# @yieldreturn [Hash] see {#update}
|
|
19
|
-
#
|
|
20
|
-
# @example
|
|
21
|
-
# require 'mustermann/mapper'
|
|
22
|
-
# Mustermann::Mapper.new(type: :rails) {{
|
|
23
|
-
# "/:foo" => ["/:foo.html", "/:foo.:format"]
|
|
24
|
-
# }}
|
|
25
|
-
#
|
|
26
|
-
# @overload initialize(**options)
|
|
27
|
-
# @param options [Hash] options The options hash
|
|
28
|
-
# @yield block for generating mappings as a hash
|
|
29
|
-
# @yieldparam mapper [Mustermann::Mapper] the mapper instance
|
|
30
|
-
#
|
|
31
|
-
# @example
|
|
32
|
-
# require 'mustermann/mapper'
|
|
33
|
-
# Mustermann::Mapper.new(type: :rails) do |mapper|
|
|
34
|
-
# mapper["/:foo"] = ["/:foo.html", "/:foo.:format"]
|
|
35
|
-
# end
|
|
36
|
-
#
|
|
37
|
-
# @overload initialize(map = {}, **options)
|
|
38
|
-
# @param map [Hash] see {#update}
|
|
39
|
-
# @param [Hash] options The options hash
|
|
40
|
-
#
|
|
41
|
-
# @example map before options
|
|
42
|
-
# require 'mustermann/mapper'
|
|
43
|
-
# Mustermann::Mapper.new({"/:foo" => "/:foo.html"}, type: :rails)
|
|
44
|
-
def initialize(map = {}, additional_values: :ignore, **options, &block)
|
|
45
|
-
@map = []
|
|
46
|
-
@options = options
|
|
47
|
-
@additional_values = additional_values
|
|
48
|
-
block.arity == 0 ? update(yield) : yield(self) if block
|
|
49
|
-
update(map) if map
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Add multiple mappings.
|
|
53
|
-
#
|
|
54
|
-
# @param map [Hash{String, Pattern: String, Pattern, Arry<String, Pattern>, Expander}] the mapping
|
|
55
|
-
def update(map)
|
|
56
|
-
map.to_h.each_pair do |input, output|
|
|
57
|
-
input = Mustermann.new(input, **@options)
|
|
58
|
-
output = Expander.new(*output, additional_values: @additional_values, **@options) unless output.is_a? Expander
|
|
59
|
-
@map << [input, output]
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# @return [Hash{Patttern: Expander}] Hash version of the mapper.
|
|
64
|
-
def to_h
|
|
65
|
-
Hash[@map]
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Convert a string according to mappings. You can pass in additional params.
|
|
69
|
-
#
|
|
70
|
-
# @example mapping with and without additional parameters
|
|
71
|
-
# mapper = Mustermann::Mapper.new("/:example" => "(/:prefix)?/:example.html")
|
|
72
|
-
#
|
|
73
|
-
def convert(input, values = {})
|
|
74
|
-
@map.inject(input) do |current, (pattern, expander)|
|
|
75
|
-
params = pattern.params(current)
|
|
76
|
-
params &&= Hash[values.merge(params).map { |k,v| [k.to_s, v] }]
|
|
77
|
-
expander.expandable?(params) ? expander.expand(params) : current
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# Add a single mapping.
|
|
82
|
-
#
|
|
83
|
-
# @param key [String, Pattern] format of the input string
|
|
84
|
-
# @param value [String, Pattern, Arry<String, Pattern>, Expander] format of the output string
|
|
85
|
-
def []=(key, value)
|
|
86
|
-
update key => value
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
alias_method :[], :convert
|
|
90
|
-
end
|
|
91
|
-
end
|
|
@@ -1,50 +0,0 @@
|
|
|
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
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
module Mustermann
|
|
3
|
-
# Fakes MatchData for patterns that do not support capturing.
|
|
4
|
-
# @see http://ruby-doc.org/core-2.0/MatchData.html MatchData
|
|
5
|
-
class SimpleMatch
|
|
6
|
-
# @api private
|
|
7
|
-
def initialize(string = "", names: [], captures: [])
|
|
8
|
-
@string = string.dup
|
|
9
|
-
@names = names
|
|
10
|
-
@captures = captures
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# @return [String] the string that was matched against
|
|
14
|
-
def to_s
|
|
15
|
-
@string.dup
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# @return [Array<String>] empty array for imitating MatchData interface
|
|
19
|
-
def names
|
|
20
|
-
@names.dup
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# @return [Array<String>] empty array for imitating MatchData interface
|
|
24
|
-
def captures
|
|
25
|
-
@captures.dup
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# @return [nil] imitates MatchData interface
|
|
29
|
-
def [](*args)
|
|
30
|
-
args.map! do |arg|
|
|
31
|
-
next arg unless arg.is_a? Symbol or arg.is_a? String
|
|
32
|
-
names.index(arg.to_s)
|
|
33
|
-
end
|
|
34
|
-
@captures[*args]
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# @!visibility private
|
|
38
|
-
def +(other)
|
|
39
|
-
SimpleMatch.new(@string + other.to_s,
|
|
40
|
-
names: @names + other.names,
|
|
41
|
-
captures: @captures + other.captures)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# @return [String] string representation
|
|
45
|
-
def inspect
|
|
46
|
-
"#<%p %p>" % [self.class, @string]
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
@@ -1,51 +0,0 @@
|
|
|
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
|
data/mustermann.gemspec
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
$:.unshift File.expand_path("../lib", __FILE__)
|
|
2
|
-
require "mustermann/version"
|
|
3
|
-
|
|
4
|
-
Gem::Specification.new do |s|
|
|
5
|
-
s.name = "mustermann"
|
|
6
|
-
s.version = Mustermann::VERSION
|
|
7
|
-
s.authors = ["Konstantin Haase", "Zachary Scott"]
|
|
8
|
-
s.email = "sinatrarb@googlegroups.com"
|
|
9
|
-
s.homepage = "https://github.com/sinatra/mustermann"
|
|
10
|
-
s.summary = %q{Your personal string matching expert.}
|
|
11
|
-
s.description = %q{A library implementing patterns that behave like regular expressions.}
|
|
12
|
-
s.license = 'MIT'
|
|
13
|
-
s.required_ruby_version = '>= 2.6.0'
|
|
14
|
-
s.files = `git ls-files`.split("\n")
|
|
15
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
16
|
-
|
|
17
|
-
s.add_runtime_dependency('ruby2_keywords', '~> 0.0.1')
|
|
18
|
-
end
|
data/spec/ast_spec.rb
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
require 'support'
|
|
3
|
-
require 'mustermann/ast/node'
|
|
4
|
-
|
|
5
|
-
describe Mustermann::AST do
|
|
6
|
-
describe :type do
|
|
7
|
-
example { Mustermann::AST::Node[:char].type .should be == :char }
|
|
8
|
-
example { Mustermann::AST::Node[:char].new.type .should be == :char }
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
describe :min_size do
|
|
12
|
-
example { Mustermann::AST::Node[:char].new.min_size.should be == 1 }
|
|
13
|
-
example { Mustermann::AST::Node[:node].new.min_size.should be == 0 }
|
|
14
|
-
end
|
|
15
|
-
end
|