mustermann-contrib 1.0.0.beta2
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 +7 -0
- data/README.md +1239 -0
- data/examples/highlighting.rb +35 -0
- data/highlighting.png +0 -0
- data/irb.png +0 -0
- data/lib/mustermann/cake.rb +18 -0
- data/lib/mustermann/express.rb +37 -0
- data/lib/mustermann/file_utils.rb +217 -0
- data/lib/mustermann/file_utils/glob_pattern.rb +39 -0
- data/lib/mustermann/fileutils.rb +1 -0
- data/lib/mustermann/flask.rb +198 -0
- data/lib/mustermann/grape.rb +35 -0
- data/lib/mustermann/pyramid.rb +28 -0
- data/lib/mustermann/rails.rb +46 -0
- data/lib/mustermann/shell.rb +56 -0
- data/lib/mustermann/simple.rb +50 -0
- data/lib/mustermann/string_scanner.rb +313 -0
- data/lib/mustermann/strscan.rb +1 -0
- data/lib/mustermann/template.rb +62 -0
- data/lib/mustermann/uri_template.rb +1 -0
- data/lib/mustermann/versions.rb +46 -0
- data/lib/mustermann/visualizer.rb +38 -0
- data/lib/mustermann/visualizer/highlight.rb +137 -0
- data/lib/mustermann/visualizer/highlighter.rb +37 -0
- data/lib/mustermann/visualizer/highlighter/ad_hoc.rb +94 -0
- data/lib/mustermann/visualizer/highlighter/ast.rb +102 -0
- data/lib/mustermann/visualizer/highlighter/composite.rb +45 -0
- data/lib/mustermann/visualizer/highlighter/dummy.rb +18 -0
- data/lib/mustermann/visualizer/highlighter/regular.rb +104 -0
- data/lib/mustermann/visualizer/pattern_extension.rb +68 -0
- data/lib/mustermann/visualizer/renderer/ansi.rb +23 -0
- data/lib/mustermann/visualizer/renderer/generic.rb +46 -0
- data/lib/mustermann/visualizer/renderer/hansi_template.rb +34 -0
- data/lib/mustermann/visualizer/renderer/html.rb +50 -0
- data/lib/mustermann/visualizer/renderer/sexp.rb +37 -0
- data/lib/mustermann/visualizer/tree.rb +63 -0
- data/lib/mustermann/visualizer/tree_renderer.rb +78 -0
- data/mustermann-contrib.gemspec +19 -0
- data/spec/cake_spec.rb +90 -0
- data/spec/express_spec.rb +209 -0
- data/spec/file_utils_spec.rb +119 -0
- data/spec/flask_spec.rb +361 -0
- data/spec/flask_subclass_spec.rb +368 -0
- data/spec/grape_spec.rb +747 -0
- data/spec/pattern_extension_spec.rb +49 -0
- data/spec/pyramid_spec.rb +101 -0
- data/spec/rails_spec.rb +647 -0
- data/spec/shell_spec.rb +147 -0
- data/spec/simple_spec.rb +268 -0
- data/spec/string_scanner_spec.rb +271 -0
- data/spec/template_spec.rb +841 -0
- data/spec/visualizer_spec.rb +199 -0
- data/theme.png +0 -0
- data/tree.png +0 -0
- metadata +126 -0
data/spec/shell_spec.rb
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'support'
|
2
|
+
require 'mustermann/shell'
|
3
|
+
|
4
|
+
describe Mustermann::Shell do
|
5
|
+
extend Support::Pattern
|
6
|
+
|
7
|
+
pattern '' do
|
8
|
+
it { should match('') }
|
9
|
+
it { should_not match('/') }
|
10
|
+
|
11
|
+
it { should_not respond_to(:expand) }
|
12
|
+
it { should_not respond_to(:to_templates) }
|
13
|
+
end
|
14
|
+
|
15
|
+
pattern '/' do
|
16
|
+
it { should match('/') }
|
17
|
+
it { should_not match('/foo') }
|
18
|
+
|
19
|
+
example { pattern.params('/').should be == {} }
|
20
|
+
example { pattern.params('').should be_nil }
|
21
|
+
end
|
22
|
+
|
23
|
+
pattern '/foo' do
|
24
|
+
it { should match('/foo') }
|
25
|
+
it { should_not match('/bar') }
|
26
|
+
it { should_not match('/foo.bar') }
|
27
|
+
end
|
28
|
+
|
29
|
+
pattern '/foo/bar' do
|
30
|
+
it { should match('/foo/bar') }
|
31
|
+
it { should match('/foo%2Fbar') }
|
32
|
+
it { should match('/foo%2fbar') }
|
33
|
+
end
|
34
|
+
|
35
|
+
pattern '/*/bar' do
|
36
|
+
it { should match('/foo/bar') }
|
37
|
+
it { should match('/bar/bar') }
|
38
|
+
it { should match('/foo%2Fbar') }
|
39
|
+
it { should match('/foo%2fbar') }
|
40
|
+
it { should_not match('/foo/foo/bar') }
|
41
|
+
it { should_not match('/bar/foo') }
|
42
|
+
end
|
43
|
+
|
44
|
+
pattern '/**/foo' do
|
45
|
+
it { should match('/a/b/c/foo') }
|
46
|
+
it { should match('/a/b/c/foo') }
|
47
|
+
it { should match('/a/.b/c/foo') }
|
48
|
+
it { should match('/a/.b/c/foo') }
|
49
|
+
end
|
50
|
+
|
51
|
+
pattern '/:foo' do
|
52
|
+
it { should match('/:foo') }
|
53
|
+
it { should match('/%3Afoo') }
|
54
|
+
it { should_not match('/foo') }
|
55
|
+
it { should_not match('/foo?') }
|
56
|
+
it { should_not match('/foo/bar') }
|
57
|
+
it { should_not match('/') }
|
58
|
+
it { should_not match('/foo/') }
|
59
|
+
end
|
60
|
+
|
61
|
+
pattern '/föö' do
|
62
|
+
it { should match("/f%C3%B6%C3%B6") }
|
63
|
+
end
|
64
|
+
|
65
|
+
pattern '/test$/' do
|
66
|
+
it { should match('/test$/') }
|
67
|
+
end
|
68
|
+
|
69
|
+
pattern '/te+st/' do
|
70
|
+
it { should match('/te+st/') }
|
71
|
+
it { should_not match('/test/') }
|
72
|
+
it { should_not match('/teest/') }
|
73
|
+
end
|
74
|
+
|
75
|
+
pattern "/path with spaces" do
|
76
|
+
it { should match('/path%20with%20spaces') }
|
77
|
+
it { should_not match('/path%2Bwith%2Bspaces') }
|
78
|
+
it { should_not match('/path+with+spaces') }
|
79
|
+
end
|
80
|
+
|
81
|
+
pattern '/foo&bar' do
|
82
|
+
it { should match('/foo&bar') }
|
83
|
+
end
|
84
|
+
|
85
|
+
pattern '/test.bar' do
|
86
|
+
it { should match('/test.bar') }
|
87
|
+
it { should_not match('/test0bar') }
|
88
|
+
end
|
89
|
+
|
90
|
+
pattern '/{foo,bar}' do
|
91
|
+
it { should match('/foo') }
|
92
|
+
it { should match('/bar') }
|
93
|
+
it { should_not match('/foobar') }
|
94
|
+
end
|
95
|
+
|
96
|
+
pattern '/foo/bar', uri_decode: false do
|
97
|
+
it { should match('/foo/bar') }
|
98
|
+
it { should_not match('/foo%2Fbar') }
|
99
|
+
it { should_not match('/foo%2fbar') }
|
100
|
+
end
|
101
|
+
|
102
|
+
pattern "/path with spaces", uri_decode: false do
|
103
|
+
it { should_not match('/path%20with%20spaces') }
|
104
|
+
it { should_not match('/path%2Bwith%2Bspaces') }
|
105
|
+
it { should_not match('/path+with+spaces') }
|
106
|
+
end
|
107
|
+
|
108
|
+
describe :=~ do
|
109
|
+
example { '/foo'.should be =~ Mustermann::Shell.new('/foo') }
|
110
|
+
end
|
111
|
+
|
112
|
+
context "peeking" do
|
113
|
+
subject(:pattern) { Mustermann::Shell.new("foo*/") }
|
114
|
+
|
115
|
+
describe :peek_size do
|
116
|
+
example { pattern.peek_size("foo bar/blah") .should be == "foo bar/".size }
|
117
|
+
example { pattern.peek_size("foo%20bar/blah") .should be == "foo%20bar/".size }
|
118
|
+
example { pattern.peek_size("/foo bar") .should be_nil }
|
119
|
+
|
120
|
+
context 'with just * as pattern' do
|
121
|
+
subject(:pattern) { Mustermann::Shell.new('*') }
|
122
|
+
example { pattern.peek_size('foo') .should be == 3 }
|
123
|
+
example { pattern.peek_size('foo/bar') .should be == 3 }
|
124
|
+
example { pattern.peek_size('foo/bar/baz') .should be == 3 }
|
125
|
+
example { pattern.peek_size('foo/bar/baz/blah') .should be == 3 }
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe :peek_match do
|
130
|
+
example { pattern.peek_match("foo bar/blah") .to_s .should be == "foo bar/" }
|
131
|
+
example { pattern.peek_match("foo%20bar/blah") .to_s .should be == "foo%20bar/" }
|
132
|
+
example { pattern.peek_match("/foo bar") .should be_nil }
|
133
|
+
end
|
134
|
+
|
135
|
+
describe :peek_params do
|
136
|
+
example { pattern.peek_params("foo bar/blah") .should be == [{}, "foo bar/".size] }
|
137
|
+
example { pattern.peek_params("foo%20bar/blah") .should be == [{}, "foo%20bar/".size] }
|
138
|
+
example { pattern.peek_params("/foo bar") .should be_nil }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "highlighting" do
|
143
|
+
let(:pattern) { Mustermann::Shell.new("/**,*/\\*/{a,b}") }
|
144
|
+
subject(:sexp) { Mustermann::Visualizer.highlight(pattern).to_sexp }
|
145
|
+
it { should be == '(root (separator /) (special *) (special *) (char ,) (special *) (separator /) (escaped "\\\\" (escaped_char *)) (separator /) (union { (root (char a)) ,(root (char b)) }))' }
|
146
|
+
end
|
147
|
+
end
|
data/spec/simple_spec.rb
ADDED
@@ -0,0 +1,268 @@
|
|
1
|
+
require 'support'
|
2
|
+
require 'mustermann/simple'
|
3
|
+
require 'mustermann/visualizer'
|
4
|
+
|
5
|
+
describe Mustermann::Simple do
|
6
|
+
extend Support::Pattern
|
7
|
+
|
8
|
+
pattern '' do
|
9
|
+
it { should match('') }
|
10
|
+
it { should_not match('/') }
|
11
|
+
|
12
|
+
it { should_not respond_to(:expand) }
|
13
|
+
it { should_not respond_to(:to_templates) }
|
14
|
+
end
|
15
|
+
|
16
|
+
pattern '/' do
|
17
|
+
it { should match('/') }
|
18
|
+
it { should_not match('/foo') }
|
19
|
+
end
|
20
|
+
|
21
|
+
pattern '/foo' do
|
22
|
+
it { should match('/foo') }
|
23
|
+
it { should_not match('/bar') }
|
24
|
+
it { should_not match('/foo.bar') }
|
25
|
+
end
|
26
|
+
|
27
|
+
pattern '/foo/bar' do
|
28
|
+
it { should match('/foo/bar') }
|
29
|
+
it { should_not match('/foo%2Fbar') }
|
30
|
+
it { should_not match('/foo%2fbar') }
|
31
|
+
end
|
32
|
+
|
33
|
+
pattern '/:foo' do
|
34
|
+
it { should match('/foo') .capturing foo: 'foo' }
|
35
|
+
it { should match('/bar') .capturing foo: 'bar' }
|
36
|
+
it { should match('/foo.bar') .capturing foo: 'foo.bar' }
|
37
|
+
it { should match('/%0Afoo') .capturing foo: '%0Afoo' }
|
38
|
+
it { should match('/foo%2Fbar') .capturing foo: 'foo%2Fbar' }
|
39
|
+
|
40
|
+
it { should_not match('/foo?') }
|
41
|
+
it { should_not match('/foo/bar') }
|
42
|
+
it { should_not match('/') }
|
43
|
+
it { should_not match('/foo/') }
|
44
|
+
end
|
45
|
+
|
46
|
+
pattern '/föö' do
|
47
|
+
it { should match("/f%C3%B6%C3%B6") }
|
48
|
+
end
|
49
|
+
|
50
|
+
pattern "/:foo/:bar" do
|
51
|
+
it { should match('/foo/bar') .capturing foo: 'foo', bar: 'bar' }
|
52
|
+
it { should match('/foo.bar/bar.foo') .capturing foo: 'foo.bar', bar: 'bar.foo' }
|
53
|
+
it { should match('/user@example.com/name') .capturing foo: 'user@example.com', bar: 'name' }
|
54
|
+
it { should match('/10.1/te.st') .capturing foo: '10.1', bar: 'te.st' }
|
55
|
+
it { should match('/10.1.2/te.st') .capturing foo: '10.1.2', bar: 'te.st' }
|
56
|
+
|
57
|
+
it { should_not match('/foo%2Fbar') }
|
58
|
+
it { should_not match('/foo%2fbar') }
|
59
|
+
|
60
|
+
example { pattern.params('/bar/foo').should be == {"foo" => "bar", "bar" => "foo"} }
|
61
|
+
example { pattern.params('').should be_nil }
|
62
|
+
end
|
63
|
+
|
64
|
+
pattern '/hello/:person' do
|
65
|
+
it { should match('/hello/Frank').capturing person: 'Frank' }
|
66
|
+
end
|
67
|
+
|
68
|
+
pattern '/?:foo?/?:bar?' do
|
69
|
+
it { should match('/hello/world') .capturing foo: 'hello', bar: 'world' }
|
70
|
+
it { should match('/hello') .capturing foo: 'hello', bar: nil }
|
71
|
+
it { should match('/') .capturing foo: nil, bar: nil }
|
72
|
+
it { should match('') .capturing foo: nil, bar: nil }
|
73
|
+
|
74
|
+
it { should_not match('/hello/world/') }
|
75
|
+
end
|
76
|
+
|
77
|
+
pattern '/*' do
|
78
|
+
it { should match('/') .capturing splat: '' }
|
79
|
+
it { should match('/foo') .capturing splat: 'foo' }
|
80
|
+
it { should match('/foo/bar') .capturing splat: 'foo/bar' }
|
81
|
+
|
82
|
+
example { pattern.params('/foo').should be == {"splat" => ["foo"]} }
|
83
|
+
end
|
84
|
+
|
85
|
+
pattern '/:foo/*' do
|
86
|
+
it { should match("/foo/bar/baz") .capturing foo: 'foo', splat: 'bar/baz' }
|
87
|
+
it { should match("/foo/") .capturing foo: 'foo', splat: '' }
|
88
|
+
it { should match('/h%20w/h%20a%20y') .capturing foo: 'h%20w', splat: 'h%20a%20y' }
|
89
|
+
it { should_not match('/foo') }
|
90
|
+
|
91
|
+
example { pattern.params('/bar/foo').should be == {"splat" => ["foo"], "foo" => "bar"} }
|
92
|
+
example { pattern.params('/bar/foo/f%20o').should be == {"splat" => ["foo/f o"], "foo" => "bar"} }
|
93
|
+
end
|
94
|
+
|
95
|
+
pattern '/test$/' do
|
96
|
+
it { should match('/test$/') }
|
97
|
+
end
|
98
|
+
|
99
|
+
pattern '/te+st/' do
|
100
|
+
it { should match('/te+st/') }
|
101
|
+
it { should_not match('/test/') }
|
102
|
+
it { should_not match('/teest/') }
|
103
|
+
end
|
104
|
+
|
105
|
+
pattern "/path with spaces" do
|
106
|
+
it { should match('/path%20with%20spaces') }
|
107
|
+
it { should match('/path%2Bwith%2Bspaces') }
|
108
|
+
it { should match('/path+with+spaces') }
|
109
|
+
end
|
110
|
+
|
111
|
+
pattern '/foo&bar' do
|
112
|
+
it { should match('/foo&bar') }
|
113
|
+
end
|
114
|
+
|
115
|
+
pattern '/*/:foo/*/*' do
|
116
|
+
it { should match('/bar/foo/bling/baz/boom') }
|
117
|
+
|
118
|
+
it "should capture all splat parts" do
|
119
|
+
match = pattern.match('/bar/foo/bling/baz/boom')
|
120
|
+
match.captures.should be == ['bar', 'foo', 'bling', 'baz/boom']
|
121
|
+
match.names.should be == ['splat', 'foo']
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should map to proper params' do
|
125
|
+
pattern.params('/bar/foo/bling/baz/boom').should be == {
|
126
|
+
"foo" => "foo", "splat" => ['bar', 'bling', 'baz/boom']
|
127
|
+
}
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
pattern '/test.bar' do
|
132
|
+
it { should match('/test.bar') }
|
133
|
+
it { should_not match('/test0bar') }
|
134
|
+
end
|
135
|
+
|
136
|
+
pattern '/:file.:ext' do
|
137
|
+
it { should match('/pony.jpg') .capturing file: 'pony', ext: 'jpg' }
|
138
|
+
it { should match('/pony%2Ejpg') .capturing file: 'pony', ext: 'jpg' }
|
139
|
+
it { should match('/pony%2ejpg') .capturing file: 'pony', ext: 'jpg' }
|
140
|
+
|
141
|
+
it { should match('/pony%E6%AD%A3%2Ejpg') .capturing file: 'pony%E6%AD%A3', ext: 'jpg' }
|
142
|
+
it { should match('/pony%e6%ad%a3%2ejpg') .capturing file: 'pony%e6%ad%a3', ext: 'jpg' }
|
143
|
+
it { should match('/pony正%2Ejpg') .capturing file: 'pony正', ext: 'jpg' }
|
144
|
+
it { should match('/pony正%2ejpg') .capturing file: 'pony正', ext: 'jpg' }
|
145
|
+
it { should match('/pony正..jpg') .capturing file: 'pony正.', ext: 'jpg' }
|
146
|
+
|
147
|
+
it { should_not match('/.jpg') }
|
148
|
+
end
|
149
|
+
|
150
|
+
pattern '/:id/test.bar' do
|
151
|
+
it { should match('/3/test.bar') .capturing id: '3' }
|
152
|
+
it { should match('/2/test.bar') .capturing id: '2' }
|
153
|
+
it { should match('/2E/test.bar') .capturing id: '2E' }
|
154
|
+
it { should match('/2e/test.bar') .capturing id: '2e' }
|
155
|
+
it { should match('/%2E/test.bar') .capturing id: '%2E' }
|
156
|
+
end
|
157
|
+
|
158
|
+
pattern '/10/:id' do
|
159
|
+
it { should match('/10/test') .capturing id: 'test' }
|
160
|
+
it { should match('/10/te.st') .capturing id: 'te.st' }
|
161
|
+
end
|
162
|
+
|
163
|
+
pattern '/10.1/:id' do
|
164
|
+
it { should match('/10.1/test') .capturing id: 'test' }
|
165
|
+
it { should match('/10.1/te.st') .capturing id: 'te.st' }
|
166
|
+
end
|
167
|
+
|
168
|
+
pattern '/foo?' do
|
169
|
+
it { should match('/fo') }
|
170
|
+
it { should match('/foo') }
|
171
|
+
it { should_not match('') }
|
172
|
+
it { should_not match('/') }
|
173
|
+
it { should_not match('/f') }
|
174
|
+
it { should_not match('/fooo') }
|
175
|
+
end
|
176
|
+
|
177
|
+
pattern '/:fOO' do
|
178
|
+
it { should match('/a').capturing fOO: 'a' }
|
179
|
+
end
|
180
|
+
|
181
|
+
pattern '/:_X' do
|
182
|
+
it { should match('/a').capturing _X: 'a' }
|
183
|
+
end
|
184
|
+
|
185
|
+
pattern '/:f00' do
|
186
|
+
it { should match('/a').capturing f00: 'a' }
|
187
|
+
end
|
188
|
+
|
189
|
+
pattern '/:foo.?' do
|
190
|
+
it { should match('/a.').capturing foo: 'a.' }
|
191
|
+
it { should match('/xy').capturing foo: 'xy' }
|
192
|
+
end
|
193
|
+
|
194
|
+
pattern '/(a)' do
|
195
|
+
it { should match('/(a)') }
|
196
|
+
it { should_not match('/a') }
|
197
|
+
end
|
198
|
+
|
199
|
+
pattern '/:foo.?', greedy: false do
|
200
|
+
it { should match('/a.').capturing foo: 'a' }
|
201
|
+
it { should match('/xy').capturing foo: 'xy' }
|
202
|
+
end
|
203
|
+
|
204
|
+
pattern '/foo?', uri_decode: false do
|
205
|
+
it { should match('/foo') }
|
206
|
+
it { should match('/fo') }
|
207
|
+
it { should_not match('/foo?') }
|
208
|
+
end
|
209
|
+
|
210
|
+
pattern '/foo/bar', uri_decode: false do
|
211
|
+
it { should match('/foo/bar') }
|
212
|
+
it { should_not match('/foo%2Fbar') }
|
213
|
+
it { should_not match('/foo%2fbar') }
|
214
|
+
end
|
215
|
+
|
216
|
+
pattern "/path with spaces", uri_decode: false do
|
217
|
+
it { should match('/path with spaces') }
|
218
|
+
it { should_not match('/path%20with%20spaces') }
|
219
|
+
it { should_not match('/path%2Bwith%2Bspaces') }
|
220
|
+
it { should_not match('/path+with+spaces') }
|
221
|
+
end
|
222
|
+
|
223
|
+
pattern "/path with spaces", space_matches_plus: false do
|
224
|
+
it { should match('/path%20with%20spaces') }
|
225
|
+
it { should_not match('/path%2Bwith%2Bspaces') }
|
226
|
+
it { should_not match('/path+with+spaces') }
|
227
|
+
end
|
228
|
+
|
229
|
+
context 'error handling' do
|
230
|
+
example '? at beginning of route' do
|
231
|
+
expect { Mustermann::Simple.new('?foobar') }.
|
232
|
+
to raise_error(Mustermann::ParseError)
|
233
|
+
end
|
234
|
+
|
235
|
+
example 'invalid capture name' do
|
236
|
+
expect { Mustermann::Simple.new('/:1a/') }.
|
237
|
+
to raise_error(Mustermann::CompileError)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
context "peeking" do
|
242
|
+
subject(:pattern) { Mustermann::Simple.new(":name") }
|
243
|
+
|
244
|
+
describe :peek_size do
|
245
|
+
example { pattern.peek_size("foo bar/blah") .should be == "foo bar".size }
|
246
|
+
example { pattern.peek_size("foo%20bar/blah") .should be == "foo%20bar".size }
|
247
|
+
example { pattern.peek_size("/foo bar") .should be_nil }
|
248
|
+
end
|
249
|
+
|
250
|
+
describe :peek_match do
|
251
|
+
example { pattern.peek_match("foo bar/blah") .to_s .should be == "foo bar" }
|
252
|
+
example { pattern.peek_match("foo%20bar/blah") .to_s .should be == "foo%20bar" }
|
253
|
+
example { pattern.peek_match("/foo bar") .should be_nil }
|
254
|
+
end
|
255
|
+
|
256
|
+
describe :peek_params do
|
257
|
+
example { pattern.peek_params("foo bar/blah") .should be == [{"name" => "foo bar"}, "foo bar".size] }
|
258
|
+
example { pattern.peek_params("foo%20bar/blah") .should be == [{"name" => "foo bar"}, "foo%20bar".size] }
|
259
|
+
example { pattern.peek_params("/foo bar") .should be_nil }
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
context "highlighting" do
|
264
|
+
let(:pattern) { Mustermann::Simple.new("/:name?/*") }
|
265
|
+
subject(:sexp) { Mustermann::Visualizer.highlight(pattern).to_sexp }
|
266
|
+
it { should be == "(root (separator /) (capture : (name name)) (optional ?) (separator /) (splat *))" }
|
267
|
+
end
|
268
|
+
end
|
@@ -0,0 +1,271 @@
|
|
1
|
+
require 'support'
|
2
|
+
require 'mustermann/string_scanner'
|
3
|
+
|
4
|
+
describe Mustermann::StringScanner do
|
5
|
+
include Support::ScanMatcher
|
6
|
+
|
7
|
+
subject(:scanner) { Mustermann::StringScanner.new(example_string) }
|
8
|
+
let(:example_string) { "foo bar" }
|
9
|
+
|
10
|
+
describe :scan do
|
11
|
+
it { should scan("foo") }
|
12
|
+
it { should scan(/foo/) }
|
13
|
+
it { should scan(:name) }
|
14
|
+
it { should scan(":name") }
|
15
|
+
|
16
|
+
it { should_not scan(" ") }
|
17
|
+
it { should_not scan("bar") }
|
18
|
+
|
19
|
+
example do
|
20
|
+
should scan("foo")
|
21
|
+
should scan(" ")
|
22
|
+
should scan("bar")
|
23
|
+
end
|
24
|
+
|
25
|
+
example do
|
26
|
+
scanner.position = 4
|
27
|
+
should scan("bar")
|
28
|
+
end
|
29
|
+
|
30
|
+
example do
|
31
|
+
should scan("foo")
|
32
|
+
scanner.reset
|
33
|
+
should scan("foo")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe :check do
|
38
|
+
it { should check("foo") }
|
39
|
+
it { should check(/foo/) }
|
40
|
+
it { should check(:name) }
|
41
|
+
it { should check(":name") }
|
42
|
+
|
43
|
+
it { should_not check(" ") }
|
44
|
+
it { should_not check("bar") }
|
45
|
+
|
46
|
+
example do
|
47
|
+
should check("foo")
|
48
|
+
should_not check(" ")
|
49
|
+
should_not check("bar")
|
50
|
+
should check("foo")
|
51
|
+
end
|
52
|
+
|
53
|
+
example do
|
54
|
+
scanner.position = 4
|
55
|
+
should check("bar")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe :scan_until do
|
60
|
+
it { should scan_until("foo") }
|
61
|
+
it { should scan_until(":name") }
|
62
|
+
it { should scan_until(" ") }
|
63
|
+
it { should scan_until("bar") }
|
64
|
+
it { should_not scan_until("baz") }
|
65
|
+
|
66
|
+
example do
|
67
|
+
should scan_until(" ")
|
68
|
+
should check("bar")
|
69
|
+
end
|
70
|
+
|
71
|
+
example do
|
72
|
+
should scan_until(" ")
|
73
|
+
scanner.reset
|
74
|
+
should scan("foo")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe :check_until do
|
79
|
+
it { should check_until("foo") }
|
80
|
+
it { should check_until(":name") }
|
81
|
+
it { should check_until(" ") }
|
82
|
+
it { should check_until("bar") }
|
83
|
+
it { should_not check_until("baz") }
|
84
|
+
|
85
|
+
example do
|
86
|
+
should check_until(" ")
|
87
|
+
should_not check("bar")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe :getch do
|
92
|
+
example { scanner.getch.should be == "f" }
|
93
|
+
|
94
|
+
example do
|
95
|
+
scanner.scan("foo")
|
96
|
+
scanner.getch.should be == " "
|
97
|
+
should scan("bar")
|
98
|
+
end
|
99
|
+
|
100
|
+
example do
|
101
|
+
scanner.getch
|
102
|
+
scanner.reset
|
103
|
+
should scan("foo")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe :<< do
|
108
|
+
example do
|
109
|
+
should_not scan_until("baz")
|
110
|
+
scanner << " baz"
|
111
|
+
scanner.to_s.should be == "foo bar baz"
|
112
|
+
should scan_until("baz")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe :eos? do
|
117
|
+
it { should_not be_eos }
|
118
|
+
example do
|
119
|
+
scanner.position = 7
|
120
|
+
should be_eos
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe :beginning_of_line? do
|
125
|
+
let(:example_string) { "foo\nbar" }
|
126
|
+
it { should be_beginning_of_line }
|
127
|
+
|
128
|
+
example do
|
129
|
+
scanner.position = 2
|
130
|
+
should_not be_beginning_of_line
|
131
|
+
end
|
132
|
+
|
133
|
+
example do
|
134
|
+
scanner.position = 3
|
135
|
+
should_not be_beginning_of_line
|
136
|
+
end
|
137
|
+
|
138
|
+
example do
|
139
|
+
scanner.position = 4
|
140
|
+
should be_beginning_of_line
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe :rest do
|
145
|
+
example { scanner.rest.should be == "foo bar" }
|
146
|
+
example do
|
147
|
+
scanner.position = 4
|
148
|
+
scanner.rest.should be == "bar"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe :rest_size do
|
153
|
+
example { scanner.rest_size.should be == 7 }
|
154
|
+
example do
|
155
|
+
scanner.position = 4
|
156
|
+
scanner.rest_size.should be == 3
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe :peek do
|
161
|
+
example { scanner.peek(3).should be == "foo" }
|
162
|
+
|
163
|
+
example do
|
164
|
+
scanner.peek(3).should be == "foo"
|
165
|
+
scanner.peek(3).should be == "foo"
|
166
|
+
end
|
167
|
+
|
168
|
+
example do
|
169
|
+
scanner.position = 4
|
170
|
+
scanner.peek(3).should be == "bar"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe :inspect do
|
175
|
+
example { scanner.inspect.should be == '#<Mustermann::StringScanner 0/7 @ "foo bar">' }
|
176
|
+
example do
|
177
|
+
scanner.position = 4
|
178
|
+
scanner.inspect.should be == '#<Mustermann::StringScanner 4/7 @ "foo bar">'
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe :[] do
|
183
|
+
example do
|
184
|
+
should scan(:name)
|
185
|
+
scanner['name'].should be == "foo bar"
|
186
|
+
end
|
187
|
+
|
188
|
+
example do
|
189
|
+
should scan(:name, capture: /\S+/)
|
190
|
+
scanner['name'].should be == "foo"
|
191
|
+
should scan(" :name", capture: /\S+/)
|
192
|
+
scanner['name'].should be == "bar"
|
193
|
+
end
|
194
|
+
|
195
|
+
example do
|
196
|
+
should scan(":a", capture: /\S+/)
|
197
|
+
should scan(" :b", capture: /\S+/)
|
198
|
+
scanner['a'].should be == "foo"
|
199
|
+
scanner['b'].should be == "bar"
|
200
|
+
end
|
201
|
+
|
202
|
+
example do
|
203
|
+
a = scanner.scan(":a", capture: /\S+/)
|
204
|
+
b = scanner.scan(" :b", capture: /\S+/)
|
205
|
+
a.params['a'].should be == 'foo'
|
206
|
+
b.params['b'].should be == 'bar'
|
207
|
+
a.params['b'].should be_nil
|
208
|
+
b.params['a'].should be_nil
|
209
|
+
end
|
210
|
+
|
211
|
+
example do
|
212
|
+
result = scanner.check(":a", capture: /\S+/)
|
213
|
+
result.params['a'].should be == 'foo'
|
214
|
+
scanner['a'].should be_nil
|
215
|
+
end
|
216
|
+
|
217
|
+
example do
|
218
|
+
should scan(:name)
|
219
|
+
scanner.reset
|
220
|
+
scanner['name'].should be_nil
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
describe :unscan do
|
225
|
+
example do
|
226
|
+
should scan(:name, capture: /\S+/)
|
227
|
+
scanner['name'].should be == "foo"
|
228
|
+
should scan(" :name", capture: /\S+/)
|
229
|
+
scanner['name'].should be == "bar"
|
230
|
+
scanner.unscan
|
231
|
+
scanner['name'].should be == "foo"
|
232
|
+
scanner.rest.should be == " bar"
|
233
|
+
end
|
234
|
+
|
235
|
+
example do
|
236
|
+
should scan_until(" ")
|
237
|
+
scanner.unscan
|
238
|
+
scanner.rest.should be == "foo bar"
|
239
|
+
end
|
240
|
+
|
241
|
+
example do
|
242
|
+
expect { scanner.unscan }.to raise_error(Mustermann::StringScanner::ScanError,
|
243
|
+
'unscan failed: previous match record not exist')
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
describe :terminate do
|
248
|
+
example do
|
249
|
+
scanner.terminate
|
250
|
+
scanner.should be_eos
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe :to_h do
|
255
|
+
example { scanner.to_h.should be == {} }
|
256
|
+
example do
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
describe :to_s do
|
261
|
+
example { scanner.to_s.should be == "foo bar" }
|
262
|
+
end
|
263
|
+
|
264
|
+
describe :clear_cache do
|
265
|
+
example do
|
266
|
+
scanner.scan("foo")
|
267
|
+
Mustermann::StringScanner.clear_cache
|
268
|
+
Mustermann::StringScanner.cache_size.should be == 0
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|