mustermann 1.1.0 → 2.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: f6e92bdd2542114b33a9f209cf71fdbe0b876b35abe09c1bb7309b640304e105
4
- data.tar.gz: 8146636bb8dba303e828db1379302d3623912670c7cbf4238a24e4b6d766ff70
3
+ metadata.gz: b0181b5f440930f6c4e8308e8e11f5cd0513dc4245a37c69fe06d7a3448e3d48
4
+ data.tar.gz: 467aed81ed5b287a53c29fe7a43eacf375ce4f973b0b9b85d3400ab8c3bb9d80
5
5
  SHA512:
6
- metadata.gz: 5982de41f3bdfa52e627f73a7c54dd4292681cf65acda63306dff7835a4f05126681ff6a0a1912448713d6f9103e55df4c5470368b9724040eb99cdf9190e07e
7
- data.tar.gz: 6a8755d02a86521d0d3e1c68496a54b33ab5c88da85ec920d63b072647f861de36ee156a8b1524ea628b06a3439d940da4570031306763db589ed773b3eff088
6
+ metadata.gz: 8aa6339c6cd99bf69519e1b5be4afcbce878379f66a3fda3c8996b0020941296dccbf9cb51c9a03989e2561ca27709225a9dbadaa9da6d81476522c0a2845fd7
7
+ data.tar.gz: c6171a83ab906b0568516d26475531221196d130ad42b75e766a4200d252c5042fdcb6061a7b9a60980edefdd89e85d46aa1bcbba0cffaa01c66972f669409fc
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
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  require 'mustermann/ast/translator'
3
3
  require 'mustermann/ast/compiler'
4
+ require 'ruby2_keywords'
4
5
 
5
6
  module Mustermann
6
7
  module AST
@@ -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
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  require 'mustermann/ast/node'
3
3
  require 'forwardable'
4
+ require 'ruby2_keywords'
4
5
  require 'strscan'
5
6
 
6
7
  module Mustermann
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  require 'mustermann/ast/node'
3
3
  require 'mustermann/error'
4
+ require 'ruby2_keywords'
4
5
  require 'delegate'
5
6
 
6
7
  module Mustermann
@@ -72,6 +73,7 @@ module Mustermann
72
73
  Class.new(const_get(:NodeTranslator)) do
73
74
  register(*types)
74
75
  define_method(:translate, &block)
76
+ ruby2_keywords :translate
75
77
  end
76
78
  end
77
79
 
@@ -119,7 +121,7 @@ module Mustermann
119
121
  # @!visibility private
120
122
  def escape(char, parser: URI::DEFAULT_PARSER, escape: parser.regexp[:UNSAFE], also_escape: nil)
121
123
  escape = Regexp.union(also_escape, escape) if also_escape
122
- char =~ escape ? parser.escape(char, Regexp.union(*escape)) : char
124
+ char.to_s =~ escape ? parser.escape(char, Regexp.union(*escape)) : char
123
125
  end
124
126
  end
125
127
  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.0'
3
+ VERSION ||= '2.0.0'
4
4
  end
data/lib/mustermann.rb CHANGED
@@ -3,7 +3,6 @@ require 'mustermann/pattern'
3
3
  require 'mustermann/composite'
4
4
  require 'mustermann/concat'
5
5
  require 'thread'
6
- require 'ruby2_keywords'
7
6
 
8
7
  # Namespace and main entry point for the Mustermann library.
9
8
  #
@@ -76,8 +75,8 @@ module Mustermann
76
75
  end
77
76
  end
78
77
 
79
- @mutex ||= Mutex.new
80
- @types ||= {}
78
+ @mutex = Mutex.new
79
+ @types = {}
81
80
 
82
81
  # Maps a type to its factory.
83
82
  #
@@ -121,7 +120,6 @@ module Mustermann
121
120
  def self.extend_object(object)
122
121
  return super unless defined? ::Sinatra::Base and object.is_a? Class and object < ::Sinatra::Base
123
122
  require 'mustermann/extension'
124
- object.register Extension
125
123
  end
126
124
  end
127
125
 
data/mustermann.gemspec CHANGED
@@ -13,7 +13,6 @@ Gem::Specification.new do |s|
13
13
  s.required_ruby_version = '>= 2.2.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.0
4
+ version: 2.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: 2019-12-30 00:00:00.000000000 Z
12
+ date: 2022-07-18 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
@@ -105,8 +104,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
104
  - !ruby/object:Gem::Version
106
105
  version: '0'
107
106
  requirements: []
108
- rubygems_version: 3.0.3
109
- signing_key:
107
+ rubygems_version: 3.2.22
108
+ signing_key:
110
109
  specification_version: 4
111
110
  summary: Your personal string matching expert.
112
111
  test_files:
@@ -115,7 +114,6 @@ test_files:
115
114
  - spec/concat_spec.rb
116
115
  - spec/equality_map_spec.rb
117
116
  - spec/expander_spec.rb
118
- - spec/extension_spec.rb
119
117
  - spec/identity_spec.rb
120
118
  - spec/mapper_spec.rb
121
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