mustermann 3.0.4 → 4.0.1

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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -2
  3. data/README.md +238 -261
  4. data/lib/mustermann/ast/compiler.rb +137 -29
  5. data/lib/mustermann/ast/converters.rb +41 -0
  6. data/lib/mustermann/ast/expander.rb +6 -7
  7. data/lib/mustermann/ast/fast_pattern.rb +122 -0
  8. data/lib/mustermann/ast/param_scanner.rb +38 -6
  9. data/lib/mustermann/ast/parser.rb +2 -3
  10. data/lib/mustermann/ast/pattern.rb +29 -6
  11. data/lib/mustermann/ast/template_generator.rb +2 -2
  12. data/lib/mustermann/ast/transformer.rb +7 -0
  13. data/lib/mustermann/ast/translator.rb +14 -5
  14. data/lib/mustermann/ast/validation.rb +1 -1
  15. data/lib/mustermann/composite.rb +26 -7
  16. data/lib/mustermann/concat.rb +17 -6
  17. data/lib/mustermann/error.rb +1 -0
  18. data/lib/mustermann/expander.rb +28 -6
  19. data/lib/mustermann/hybrid.rb +50 -0
  20. data/lib/mustermann/identity.rb +1 -1
  21. data/lib/mustermann/match.rb +155 -0
  22. data/lib/mustermann/pattern.rb +30 -35
  23. data/lib/mustermann/rails.rb +63 -0
  24. data/lib/mustermann/regexp_based.rb +70 -9
  25. data/lib/mustermann/regular.rb +1 -1
  26. data/lib/mustermann/router.rb +104 -0
  27. data/lib/mustermann/set/cache.rb +47 -0
  28. data/lib/mustermann/set/linear.rb +32 -0
  29. data/lib/mustermann/set/match.rb +23 -0
  30. data/lib/mustermann/set/strict_order.rb +29 -0
  31. data/lib/mustermann/set/trie.rb +282 -0
  32. data/lib/mustermann/set.rb +447 -0
  33. data/lib/mustermann/sinatra/safe_renderer.rb +1 -1
  34. data/lib/mustermann/sinatra/try_convert.rb +49 -11
  35. data/lib/mustermann/sinatra.rb +35 -11
  36. data/lib/mustermann/version.rb +1 -1
  37. data/lib/mustermann/versions.rb +47 -0
  38. data/lib/mustermann.rb +38 -12
  39. metadata +31 -45
  40. data/bench/capturing.rb +0 -57
  41. data/bench/regexp.rb +0 -21
  42. data/bench/simple_vs_sinatra.rb +0 -23
  43. data/bench/template_vs_addressable.rb +0 -26
  44. data/bench/uri_parser_object.rb +0 -16
  45. data/lib/mustermann/extension.rb +0 -3
  46. data/lib/mustermann/mapper.rb +0 -91
  47. data/lib/mustermann/pattern_cache.rb +0 -50
  48. data/lib/mustermann/simple_match.rb +0 -49
  49. data/lib/mustermann/to_pattern.rb +0 -51
  50. data/mustermann.gemspec +0 -18
  51. data/spec/ast_spec.rb +0 -15
  52. data/spec/composite_spec.rb +0 -163
  53. data/spec/concat_spec.rb +0 -127
  54. data/spec/equality_map_spec.rb +0 -42
  55. data/spec/expander_spec.rb +0 -123
  56. data/spec/identity_spec.rb +0 -127
  57. data/spec/mapper_spec.rb +0 -77
  58. data/spec/mustermann_spec.rb +0 -81
  59. data/spec/pattern_spec.rb +0 -54
  60. data/spec/regexp_based_spec.rb +0 -9
  61. data/spec/regular_spec.rb +0 -119
  62. data/spec/simple_match_spec.rb +0 -11
  63. data/spec/sinatra_spec.rb +0 -836
  64. data/spec/to_pattern_spec.rb +0 -70
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+ module Mustermann
3
+ # Mixin that adds support for multiple versions of the same type.
4
+ # @see Mustermann::Rails
5
+ # @!visibility private
6
+ module Versions
7
+ # Checks if class has mulitple versions available and picks one that matches the version option.
8
+ # @!visibility private
9
+ def new(*args, version: nil, **options)
10
+ return super(*args, **options) unless versions.any?
11
+ self[version].new(*args, **options)
12
+ end
13
+
14
+ # @return [Hash] version to subclass mapping.
15
+ # @!visibility private
16
+ def versions
17
+ @versions ||= {}
18
+ end
19
+
20
+ # Defines a new version.
21
+ # @!visibility private
22
+ def version(*list, inherit_from: nil, &block)
23
+ superclass = self[inherit_from] || self
24
+ subclass = Class.new(superclass, &block)
25
+ list.each { |v| versions[v] = subclass }
26
+ end
27
+
28
+ # Resolve a subclass for a given version string.
29
+ # @!visibility private
30
+ def [](version)
31
+ return versions.values.last unless version
32
+ detected = versions.detect { |v,_| version.start_with?(v) }
33
+ raise ArgumentError, 'unsupported version %p' % version unless detected
34
+ detected.last
35
+ end
36
+
37
+ # @!visibility private
38
+ def name
39
+ super || superclass.name
40
+ end
41
+
42
+ # @!visibility private
43
+ def inspect
44
+ name
45
+ end
46
+ end
47
+ end
data/lib/mustermann.rb CHANGED
@@ -113,21 +113,47 @@ module Mustermann
113
113
 
114
114
  # @!visibility private
115
115
  def self.normalized_type(type)
116
- type.to_s.gsub('-', '_').downcase
116
+ @normalized_types ||= {}
117
+ @normalized_types[type] ||= type.to_s.gsub('-', '_').downcase
117
118
  end
118
119
 
119
120
  # @!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'
121
+ def self.dedup(object)
122
+ return object.freeze unless @dedup
123
+ # need to check this first because JRuby raises on @dedup.key?(nil)
124
+ case object
125
+ when nil, true, false, Integer, Float, Symbol, Module
126
+ return object
127
+ end
128
+
129
+ canonical = @dedup.getkey(object)
130
+ return canonical if canonical
131
+
132
+ # Build deduplicated copies so callers' arrays and hashes, which may be
133
+ # frozen or still in use, are never modified.
134
+ case object
135
+ when Array
136
+ object = object.map { |o| dedup(o) }
137
+ @dedup[object.freeze] = true
138
+ when Hash
139
+ object = object.to_h { |k, v| [dedup(k), dedup(v)] }
140
+ @dedup[object.freeze] = true
141
+ when String
142
+ @dedup[-object] = true
143
+ else
144
+ @dedup[object.freeze] = true
145
+ end
146
+ object
123
147
  end
124
- end
125
148
 
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)\)$}
149
+ @dedup = defined?(ObjectSpace::WeakKeyMap) ? ObjectSpace::WeakKeyMap.new : false
150
+
151
+ # @!visibility private
152
+ EMPTY_STRING = dedup(-'')
153
+
154
+ # @!visibility private
155
+ EMPTY_ARRAY = dedup([])
156
+
157
+ # @!visibility private
158
+ EMPTY_HASH = dedup({})
132
159
  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: 3.0.4
4
+ version: 4.0.1
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
- - !ruby/object:Gem::Dependency
14
- name: ruby2_keywords
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
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/extension.rb
49
+ - lib/mustermann/hybrid.rb
59
50
  - lib/mustermann/identity.rb
60
- - lib/mustermann/mapper.rb
51
+ - lib/mustermann/match.rb
61
52
  - lib/mustermann/pattern.rb
62
- - lib/mustermann/pattern_cache.rb
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/simple_match.rb
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.gemspec
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: 2.6.0
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: 3.6.9
92
+ rubygems_version: 4.0.20
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
@@ -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
@@ -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)
@@ -1,3 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- fail "Mustermann extension for Sinatra has been extracted into its own gem. More information at https://github.com/sinatra/mustermann-sinatra-extension"
@@ -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