mustermann 1.1.1 → 3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7fdfa1980b36632e06c011f926b33f0d6d8812f72286004b2398a4f31dd9a82
4
- data.tar.gz: 7daa22487d1a56e826fef04f5f63ecef1d67484151612304402e5a01c7f4be33
3
+ metadata.gz: ea330a8bf09165e676628df2668f0afa5d8fd32372bb7b07ed6a286cf274f74c
4
+ data.tar.gz: 58b0252ef3ba1d5bd06b3dceab50c06ba011d98b9e2bc54c6caa314443fa722b
5
5
  SHA512:
6
- metadata.gz: 8d80afba1b13c99bcafc6862ad7dc195a0b8c0ac80279498fb9b8b75ecf6ea290cbe4b90f3f6f60d4e3c52f2f517f5a6059d05993c23179b6b2be22aaca320b8
7
- data.tar.gz: f109d137a09eeb9781c92bfd366b1b421b118753b20ff905f1ab7d161946f254de2e376541c9e74215a7215f30ce0589992a0790d6e6861ae8d5c9606beda08a
6
+ metadata.gz: f9e8638a1cb73cf39256c6cb422d4d1a4601a2d9348aba8361d31083103e0495a843d595b579f08d2614ba1b665b41959a79eaffd869348551a2cb558c1cf1ea
7
+ data.tar.gz: 5b569063e6dd7d3beb3bdd983d4f5c30a9d12ce7b5e06d0f1f215e56004ba678011df824d26a94d5dc136d957c7835e5bcc38081cbbda2d838cfe78b3ca00ec7
data/README.md CHANGED
@@ -377,30 +377,7 @@ mapper['/foo/bar'] # => "/foo/bar"
377
377
  <a name="-sinatra-integration"></a>
378
378
  ## Sinatra Integration
379
379
 
380
- All patterns implement `match`, which means they can be dropped into Sinatra and other Rack routers:
381
-
382
- ``` ruby
383
- require 'sinatra'
384
- require 'mustermann'
385
-
386
- get Mustermann.new('/:foo') do
387
- params[:foo]
388
- end
389
- ```
390
-
391
- In fact, since using this with Sinatra is the main use case, it comes with a build-in extension for **Sinatra 1.x**.
392
-
393
- ``` ruby
394
- require 'sinatra'
395
- require 'mustermann'
396
-
397
- register Mustermann
398
-
399
- # this will use Mustermann rather than the built-in pattern matching
400
- get '/:slug(.ext)?' do
401
- params[:slug]
402
- end
403
- ```
380
+ Mustermann is used in Sinatra by default since version 2.0, for previous versions an [extension](https://github.com/sinatra/mustermann-sinatra-extension) is available.
404
381
 
405
382
  ### Configuration
406
383
 
@@ -12,11 +12,11 @@ module Mustermann
12
12
  class Expander < Translator
13
13
  raises ExpandError
14
14
 
15
- translate Array do |*args|
15
+ translate(Array, &-> (*args) do
16
16
  inject(t.pattern) do |pattern, element|
17
17
  t.add_to(pattern, t(element, *args))
18
18
  end
19
- end
19
+ end.ruby2_keywords)
20
20
 
21
21
  translate :capture do |**options|
22
22
  t.for_capture(node, **options)
@@ -124,6 +124,8 @@ module Mustermann
124
124
  # @see Mustermann::AST::Translator#expand
125
125
  # @!visibility private
126
126
  ruby2_keywords def escape(string, *args)
127
+ return super unless string.respond_to?(:=~)
128
+
127
129
  # URI::Parser is pretty slow, let's not send every string to it, even if it's unnecessary
128
130
  string =~ /\A\w*\Z/ ? string : super
129
131
  end
@@ -35,8 +35,8 @@ module Mustermann
35
35
  # Helper for creating a new instance and calling #parse on it.
36
36
  # @return [Mustermann::AST::Node]
37
37
  # @!visibility private
38
- def self.parse(*args, &block)
39
- new(*args).tap { |n| n.parse(&block) }
38
+ def self.parse(payload = nil, **options, &block)
39
+ new(payload, **options).tap { |n| n.parse(&block) }
40
40
  end
41
41
 
42
42
  # @!visibility private
@@ -108,7 +108,7 @@ module Mustermann
108
108
  # @see Mustermann::AST::Node#parse
109
109
  # @!visibility private
110
110
  def parse
111
- self.payload ||= ""
111
+ self.payload ||= String.new
112
112
  super
113
113
  end
114
114
 
@@ -120,7 +120,7 @@ module Mustermann
120
120
  # @!visibility private
121
121
  def escape(char, parser: URI::DEFAULT_PARSER, escape: parser.regexp[:UNSAFE], also_escape: nil)
122
122
  escape = Regexp.union(also_escape, escape) if also_escape
123
- char =~ escape ? parser.escape(char, Regexp.union(*escape)) : char
123
+ char.to_s =~ escape ? parser.escape(char, Regexp.union(*escape)) : char
124
124
  end
125
125
  end
126
126
  end
@@ -1,50 +1,3 @@
1
1
  # frozen_string_literal: true
2
- require 'sinatra/version'
3
- fail "no need to load the Mustermann extension for #{::Sinatra::VERSION}" if ::Sinatra::VERSION >= '2.0.0'
4
2
 
5
- require 'mustermann'
6
-
7
- module Mustermann
8
- # Sinatra 1.x extension switching default pattern parsing over to Mustermann.
9
- #
10
- # @example With classic Sinatra application
11
- # require 'sinatra'
12
- # require 'mustermann'
13
- #
14
- # register Mustermann
15
- # get('/:id', capture: /\d+/) { ... }
16
- #
17
- # @example With modular Sinatra application
18
- # require 'sinatra/base'
19
- # require 'mustermann'
20
- #
21
- # class MyApp < Sinatra::Base
22
- # register Mustermann
23
- # get('/:id', capture: /\d+/) { ... }
24
- # end
25
- #
26
- # @see file:README.md#Sinatra_Integration "Sinatra Integration" in the README
27
- module Extension
28
- def compile!(verb, path, block, except: nil, capture: nil, pattern: { }, **options)
29
- if path.respond_to? :to_str
30
- pattern[:except] = except if except
31
- pattern[:capture] = capture if capture
32
-
33
- if settings.respond_to? :pattern and settings.pattern?
34
- pattern.merge! settings.pattern do |key, local, global|
35
- next local unless local.is_a? Hash
36
- next global.merge(local) if global.is_a? Hash
37
- Hash.new(global).merge! local
38
- end
39
- end
40
-
41
- path = Mustermann.new(path, **pattern)
42
- condition { params.merge! path.params(captures: Array(params[:captures]), offset: -1) }
43
- end
44
-
45
- super(verb, path, block, options)
46
- end
47
-
48
- private :compile!
49
- end
50
- end
3
+ fail "Mustermann extension for Sinatra has been extracted into its own gem. More information at https://github.com/sinatra/mustermann-sinatra-extension"
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Mustermann
3
- VERSION ||= '1.1.1'
3
+ VERSION ||= '3.0.0'
4
4
  end
data/lib/mustermann.rb CHANGED
@@ -75,8 +75,8 @@ module Mustermann
75
75
  end
76
76
  end
77
77
 
78
- @mutex ||= Mutex.new
79
- @types ||= {}
78
+ @mutex = Mutex.new
79
+ @types = {}
80
80
 
81
81
  # Maps a type to its factory.
82
82
  #
@@ -120,7 +120,6 @@ module Mustermann
120
120
  def self.extend_object(object)
121
121
  return super unless defined? ::Sinatra::Base and object.is_a? Class and object < ::Sinatra::Base
122
122
  require 'mustermann/extension'
123
- object.register Extension
124
123
  end
125
124
  end
126
125
 
data/mustermann.gemspec CHANGED
@@ -10,10 +10,9 @@ Gem::Specification.new do |s|
10
10
  s.summary = %q{Your personal string matching expert.}
11
11
  s.description = %q{A library implementing patterns that behave like regular expressions.}
12
12
  s.license = 'MIT'
13
- s.required_ruby_version = '>= 2.2.0'
13
+ s.required_ruby_version = '>= 2.6.0'
14
14
  s.files = `git ls-files`.split("\n")
15
15
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
16
 
18
17
  s.add_runtime_dependency('ruby2_keywords', '~> 0.0.1')
19
18
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require 'support'
3
3
  require 'mustermann'
4
- require 'mustermann/extension'
5
4
  require 'sinatra/base'
6
5
 
7
6
  describe Mustermann do
@@ -70,11 +69,9 @@ describe Mustermann do
70
69
  describe :extend_object do
71
70
  context 'special behavior for Sinatra only' do
72
71
  example { Object .new.extend(Mustermann).should be_a(Mustermann) }
73
- example { Object .new.extend(Mustermann).should_not be_a(Mustermann::Extension) }
74
72
  example { Class .new.extend(Mustermann).should be_a(Mustermann) }
75
- example { Class .new.extend(Mustermann).should_not be_a(Mustermann::Extension) }
76
- example { Sinatra .new.extend(Mustermann).should_not be_a(Mustermann) }
77
- example { Sinatra .new.extend(Mustermann).should be_a(Mustermann::Extension) }
73
+
74
+ example { expect { Sinatra.new.extend(Mustermann) }.to raise_error(RuntimeError, "Mustermann extension for Sinatra has been extracted into its own gem. More information at https://github.com/sinatra/mustermann-sinatra-extension") }
78
75
  end
79
76
  end
80
77
 
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mustermann
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Haase
8
8
  - Zachary Scott
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-01-03 00:00:00.000000000 Z
12
+ date: 2022-07-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ruby2_keywords
@@ -76,7 +76,6 @@ files:
76
76
  - spec/concat_spec.rb
77
77
  - spec/equality_map_spec.rb
78
78
  - spec/expander_spec.rb
79
- - spec/extension_spec.rb
80
79
  - spec/identity_spec.rb
81
80
  - spec/mapper_spec.rb
82
81
  - spec/mustermann_spec.rb
@@ -90,7 +89,7 @@ homepage: https://github.com/sinatra/mustermann
90
89
  licenses:
91
90
  - MIT
92
91
  metadata: {}
93
- post_install_message:
92
+ post_install_message:
94
93
  rdoc_options: []
95
94
  require_paths:
96
95
  - lib
@@ -98,16 +97,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
98
97
  requirements:
99
98
  - - ">="
100
99
  - !ruby/object:Gem::Version
101
- version: 2.2.0
100
+ version: 2.6.0
102
101
  required_rubygems_version: !ruby/object:Gem::Requirement
103
102
  requirements:
104
103
  - - ">="
105
104
  - !ruby/object:Gem::Version
106
105
  version: '0'
107
106
  requirements: []
108
- rubyforge_project:
109
- rubygems_version: 2.7.3
110
- signing_key:
107
+ rubygems_version: 3.0.3.1
108
+ signing_key:
111
109
  specification_version: 4
112
110
  summary: Your personal string matching expert.
113
111
  test_files:
@@ -116,7 +114,6 @@ test_files:
116
114
  - spec/concat_spec.rb
117
115
  - spec/equality_map_spec.rb
118
116
  - spec/expander_spec.rb
119
- - spec/extension_spec.rb
120
117
  - spec/identity_spec.rb
121
118
  - spec/mapper_spec.rb
122
119
  - spec/mustermann_spec.rb
@@ -1,297 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'support'
3
- require 'mustermann/extension'
4
- require 'sinatra/base'
5
- require 'rack/test'
6
-
7
- describe Mustermann::Extension do
8
- include Rack::Test::Methods
9
-
10
- subject :app do
11
- Sinatra.new do
12
- set :environment, :test
13
- register Mustermann
14
- end
15
- end
16
-
17
- it 'sets up the extension' do
18
- app.should be_a(Mustermann::Extension)
19
- end
20
-
21
- context 'uses Sinatra-style patterns by default' do
22
- before { app.get('/:slug(.:extension)?') { params[:slug] } }
23
- example { get('/foo') .body.should be == 'foo' }
24
- example { get('/foo.') .body.should be == 'foo.' }
25
- example { get('/foo.bar') .body.should be == 'foo' }
26
- example { get('/a%20b') .body.should be == 'a b' }
27
- end
28
-
29
- describe :except do
30
- before { app.get('/auth/*', except: '/auth/login') { 'ok' } }
31
- example { get('/auth/dunno').should be_ok }
32
- example { get('/auth/login').should_not be_ok }
33
- end
34
-
35
- describe :capture do
36
- context 'global' do
37
- before do
38
- app.set(:pattern, capture: { ext: %w[png jpg gif] })
39
- app.get('/:slug(.:ext)?') { params[:slug] }
40
- end
41
-
42
- example { get('/foo.bar').body.should be == 'foo.bar' }
43
- example { get('/foo.png').body.should be == 'foo' }
44
- end
45
-
46
- context 'route local' do
47
- before do
48
- app.set(:pattern, nil)
49
- app.get('/:id', capture: /\d+/) { 'ok' }
50
- end
51
-
52
- example { get('/42').should be_ok }
53
- example { get('/foo').should_not be_ok }
54
- end
55
-
56
- context 'global and route local' do
57
- context 'global is a hash' do
58
- before do
59
- app.set(:pattern, capture: { id: /\d+/ })
60
- app.get('/:id(.:ext)?', capture: { ext: 'png' }) { ?a }
61
- app.get('/:id', capture: { id: 'foo' }) { ?b }
62
- app.get('/:id', capture: :alpha) { ?c }
63
- end
64
-
65
- example { get('/20') .body.should be == ?a }
66
- example { get('/20.png') .body.should be == ?a }
67
- example { get('/foo') .body.should be == ?b }
68
- example { get('/bar') .body.should be == ?c }
69
- end
70
-
71
- context 'global is not a hash' do
72
- before do
73
- app.set(:pattern, capture: /\d+/)
74
- app.get('/:slug(.:ext)?', capture: { ext: 'png' }) { params[:slug] }
75
- app.get('/:slug', capture: :alpha) { 'ok' }
76
- end
77
-
78
- example { get('/20.png').should be_ok }
79
- example { get('/foo.png').should_not be_ok }
80
- example { get('/foo').should be_ok }
81
-
82
- example { get('/20.png') .body.should be == '20' }
83
- example { get('/42') .body.should be == '42' }
84
- example { get('/foo') .body.should be == 'ok' }
85
- end
86
- end
87
- end
88
-
89
- describe :pattern do
90
- describe :except do
91
- before { app.get('/auth/*', pattern: { except: '/auth/login' }) { 'ok' } }
92
- example { get('/auth/dunno').should be_ok }
93
- example { get('/auth/login').should_not be_ok }
94
- end
95
-
96
- describe :capture do
97
- context 'route local' do
98
- before do
99
- app.set(:pattern, nil)
100
- app.get('/:id', pattern: { capture: /\d+/ }) { 'ok' }
101
- end
102
-
103
- example { get('/42').should be_ok }
104
- example { get('/foo').should_not be_ok }
105
- end
106
-
107
- context 'global and route local' do
108
- context 'global is a hash' do
109
- before do
110
- app.set(:pattern, capture: { id: /\d+/ })
111
- app.get('/:id(.:ext)?', pattern: { capture: { ext: 'png' }}) { ?a }
112
- app.get('/:id', pattern: { capture: { id: 'foo' }}) { ?b }
113
- app.get('/:id', pattern: { capture: :alpha }) { ?c }
114
- end
115
-
116
- example { get('/20') .body.should be == ?a }
117
- example { get('/20.png') .body.should be == ?a }
118
- example { get('/foo') .body.should be == ?b }
119
- example { get('/bar') .body.should be == ?c }
120
- end
121
-
122
- context 'global is not a hash' do
123
- before do
124
- app.set(:pattern, capture: /\d+/)
125
- app.get('/:slug(.:ext)?', pattern: { capture: { ext: 'png' }}) { params[:slug] }
126
- app.get('/:slug', pattern: { capture: :alpha }) { 'ok' }
127
- end
128
-
129
- example { get('/20.png').should be_ok }
130
- example { get('/foo.png').should_not be_ok }
131
- example { get('/foo').should be_ok }
132
-
133
- example { get('/20.png') .body.should be == '20' }
134
- example { get('/42') .body.should be == '42' }
135
- example { get('/foo') .body.should be == 'ok' }
136
- end
137
- end
138
- end
139
-
140
- describe :greedy do
141
- context 'default' do
142
- before { app.get('/:name.:ext') { params[:name] }}
143
- example { get('/foo.bar') .body.should be == 'foo' }
144
- example { get('/foo.bar.baz') .body.should be == 'foo.bar' }
145
- end
146
-
147
- context 'enabled' do
148
- before { app.get('/:name.:ext', pattern: { greedy: true }) { params[:name] }}
149
- example { get('/foo.bar') .body.should be == 'foo' }
150
- example { get('/foo.bar.baz') .body.should be == 'foo.bar' }
151
- end
152
-
153
- context 'disabled' do
154
- before { app.get('/:name.:ext', pattern: { greedy: false }) { params[:name] }}
155
- example { get('/foo.bar') .body.should be == 'foo' }
156
- example { get('/foo.bar.baz') .body.should be == 'foo' }
157
- end
158
-
159
- context 'global' do
160
- before do
161
- app.set(:pattern, greedy: false)
162
- app.get('/:name.:ext') { params[:name] }
163
- end
164
-
165
- example { get('/foo.bar') .body.should be == 'foo' }
166
- example { get('/foo.bar.baz') .body.should be == 'foo' }
167
- end
168
- end
169
-
170
- describe :space_matches_plus do
171
- context 'default' do
172
- before { app.get('/foo bar') { 'ok' }}
173
- example { get('/foo%20bar') .should be_ok }
174
- example { get('/foo+bar') .should be_ok }
175
- end
176
-
177
- context 'enabled' do
178
- before { app.get('/foo bar', pattern: { space_matches_plus: true }) { 'ok' }}
179
- example { get('/foo%20bar') .should be_ok }
180
- example { get('/foo+bar') .should be_ok }
181
- end
182
-
183
- context 'disabled' do
184
- before { app.get('/foo bar', pattern: { space_matches_plus: false }) { 'ok' }}
185
- example { get('/foo%20bar') .should be_ok }
186
- example { get('/foo+bar') .should_not be_ok }
187
- end
188
-
189
- context 'global' do
190
- before do
191
- app.set(:pattern, space_matches_plus: false)
192
- app.get('/foo bar') { 'ok' }
193
- end
194
-
195
- example { get('/foo%20bar') .should be_ok }
196
- example { get('/foo+bar') .should_not be_ok }
197
- end
198
- end
199
-
200
- describe :uri_decode do
201
- context 'default' do
202
- before { app.get('/&') { 'ok' }}
203
- example { get('/&') .should be_ok }
204
- example { get('/%26') .should be_ok }
205
- end
206
-
207
- context 'enabled' do
208
- before { app.get('/&', pattern: { uri_decode: true }) { 'ok' }}
209
- example { get('/&') .should be_ok }
210
- example { get('/%26') .should be_ok }
211
- end
212
-
213
- context 'disabled' do
214
- before { app.get('/&', pattern: { uri_decode: false }) { 'ok' }}
215
- example { get('/&') .should be_ok }
216
- example { get('/%26') .should_not be_ok }
217
- end
218
-
219
- context 'global' do
220
- before do
221
- app.set(:pattern, uri_decode: false)
222
- app.get('/&') { 'ok' }
223
- end
224
-
225
- example { get('/&') .should be_ok }
226
- example { get('/%26') .should_not be_ok }
227
- end
228
- end
229
- end
230
-
231
- describe :type do
232
- describe :identity do
233
- before do
234
- app.set(:pattern, type: :identity)
235
- app.get('/:foo') { 'ok' }
236
- end
237
-
238
- example { get('/:foo').should be_ok }
239
- example { get('/foo').should_not be_ok }
240
- end
241
-
242
- describe :rails do
243
- before do
244
- app.set(:pattern, type: :rails)
245
- app.get('/:slug(.:extension)') { params[:slug] }
246
- end
247
-
248
- example { get('/foo') .body.should be == 'foo' }
249
- example { get('/foo.') .body.should be == 'foo.' }
250
- example { get('/foo.bar') .body.should be == 'foo' }
251
- example { get('/a%20b') .body.should be == 'a b' }
252
- end
253
-
254
- describe :shell do
255
- before do
256
- app.set(:pattern, type: :shell)
257
- app.get('/{foo,bar}') { 'ok' }
258
- end
259
-
260
- example { get('/foo').should be_ok }
261
- example { get('/bar').should be_ok }
262
- end
263
-
264
- describe :simple do
265
- before do
266
- app.set(:pattern, type: :simple)
267
- app.get('/(a)') { 'ok' }
268
- end
269
-
270
- example { get('/(a)').should be_ok }
271
- example { get('/a').should_not be_ok }
272
- end
273
-
274
- describe :simple do
275
- before do
276
- app.set(:pattern, type: :template)
277
- app.get('/foo{/segments*}{.ext}') { "%p %p" % [params[:segments], params[:ext]] }
278
- end
279
-
280
- example { get('/foo/a.png').should be_ok }
281
- example { get('/foo/a').should_not be_ok }
282
-
283
- example { get('/foo/a.png').body.should be == '["a"] "png"' }
284
- example { get('/foo/a/b.png').body.should be == '["a", "b"] "png"' }
285
- end
286
- end
287
-
288
- context 'works with filters' do
289
- before do
290
- app.before('/auth/*', except: '/auth/login') { halt 'auth required' }
291
- app.get('/auth/login') { 'please log in' }
292
- end
293
-
294
- example { get('/auth/dunno').body.should be == 'auth required' }
295
- example { get('/auth/login').body.should be == 'please log in' }
296
- end
297
- end