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.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +1239 -0
  3. data/examples/highlighting.rb +35 -0
  4. data/highlighting.png +0 -0
  5. data/irb.png +0 -0
  6. data/lib/mustermann/cake.rb +18 -0
  7. data/lib/mustermann/express.rb +37 -0
  8. data/lib/mustermann/file_utils.rb +217 -0
  9. data/lib/mustermann/file_utils/glob_pattern.rb +39 -0
  10. data/lib/mustermann/fileutils.rb +1 -0
  11. data/lib/mustermann/flask.rb +198 -0
  12. data/lib/mustermann/grape.rb +35 -0
  13. data/lib/mustermann/pyramid.rb +28 -0
  14. data/lib/mustermann/rails.rb +46 -0
  15. data/lib/mustermann/shell.rb +56 -0
  16. data/lib/mustermann/simple.rb +50 -0
  17. data/lib/mustermann/string_scanner.rb +313 -0
  18. data/lib/mustermann/strscan.rb +1 -0
  19. data/lib/mustermann/template.rb +62 -0
  20. data/lib/mustermann/uri_template.rb +1 -0
  21. data/lib/mustermann/versions.rb +46 -0
  22. data/lib/mustermann/visualizer.rb +38 -0
  23. data/lib/mustermann/visualizer/highlight.rb +137 -0
  24. data/lib/mustermann/visualizer/highlighter.rb +37 -0
  25. data/lib/mustermann/visualizer/highlighter/ad_hoc.rb +94 -0
  26. data/lib/mustermann/visualizer/highlighter/ast.rb +102 -0
  27. data/lib/mustermann/visualizer/highlighter/composite.rb +45 -0
  28. data/lib/mustermann/visualizer/highlighter/dummy.rb +18 -0
  29. data/lib/mustermann/visualizer/highlighter/regular.rb +104 -0
  30. data/lib/mustermann/visualizer/pattern_extension.rb +68 -0
  31. data/lib/mustermann/visualizer/renderer/ansi.rb +23 -0
  32. data/lib/mustermann/visualizer/renderer/generic.rb +46 -0
  33. data/lib/mustermann/visualizer/renderer/hansi_template.rb +34 -0
  34. data/lib/mustermann/visualizer/renderer/html.rb +50 -0
  35. data/lib/mustermann/visualizer/renderer/sexp.rb +37 -0
  36. data/lib/mustermann/visualizer/tree.rb +63 -0
  37. data/lib/mustermann/visualizer/tree_renderer.rb +78 -0
  38. data/mustermann-contrib.gemspec +19 -0
  39. data/spec/cake_spec.rb +90 -0
  40. data/spec/express_spec.rb +209 -0
  41. data/spec/file_utils_spec.rb +119 -0
  42. data/spec/flask_spec.rb +361 -0
  43. data/spec/flask_subclass_spec.rb +368 -0
  44. data/spec/grape_spec.rb +747 -0
  45. data/spec/pattern_extension_spec.rb +49 -0
  46. data/spec/pyramid_spec.rb +101 -0
  47. data/spec/rails_spec.rb +647 -0
  48. data/spec/shell_spec.rb +147 -0
  49. data/spec/simple_spec.rb +268 -0
  50. data/spec/string_scanner_spec.rb +271 -0
  51. data/spec/template_spec.rb +841 -0
  52. data/spec/visualizer_spec.rb +199 -0
  53. data/theme.png +0 -0
  54. data/tree.png +0 -0
  55. metadata +126 -0
@@ -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
@@ -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