motion-strscan 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +63 -0
- data/lib/motion-strscan/string.rb +20 -0
- data/lib/motion-strscan/strscan.rb +676 -0
- data/lib/motion-strscan/version.rb +3 -0
- data/lib/motion-strscan.rb +8 -0
- data/spec/helpers/it_behaves_like.rb +27 -0
- data/spec/string_spec/_shared/slice.rb +244 -0
- data/spec/string_spec/byteslice_spec.rb +21 -0
- data/spec/strscan_spec/_shared/bol.rb +25 -0
- data/spec/strscan_spec/_shared/concat.rb +31 -0
- data/spec/strscan_spec/_shared/eos.rb +17 -0
- data/spec/strscan_spec/_shared/extract_range.rb +22 -0
- data/spec/strscan_spec/_shared/extract_range_matched.rb +22 -0
- data/spec/strscan_spec/_shared/get_byte.rb +28 -0
- data/spec/strscan_spec/_shared/matched_size.rb +21 -0
- data/spec/strscan_spec/_shared/peek.rb +44 -0
- data/spec/strscan_spec/_shared/pos.rb +83 -0
- data/spec/strscan_spec/_shared/rest_size.rb +18 -0
- data/spec/strscan_spec/_shared/terminate.rb +17 -0
- data/spec/strscan_spec/append_spec.rb +7 -0
- data/spec/strscan_spec/beginning_of_line_spec.rb +3 -0
- data/spec/strscan_spec/bol_spec.rb +3 -0
- data/spec/strscan_spec/check_spec.rb +13 -0
- data/spec/strscan_spec/check_until_spec.rb +14 -0
- data/spec/strscan_spec/clear_spec.rb +21 -0
- data/spec/strscan_spec/concat_spec.rb +7 -0
- data/spec/strscan_spec/dup_spec.rb +36 -0
- data/spec/strscan_spec/element_reference_spec.rb +46 -0
- data/spec/strscan_spec/empty_spec.rb +21 -0
- data/spec/strscan_spec/eos_spec.rb +3 -0
- data/spec/strscan_spec/exist_spec.rb +21 -0
- data/spec/strscan_spec/get_byte_spec.rb +3 -0
- data/spec/strscan_spec/getbyte_spec.rb +23 -0
- data/spec/strscan_spec/getch_spec.rb +41 -0
- data/spec/strscan_spec/initialize_spec.rb +25 -0
- data/spec/strscan_spec/inspect_spec.rb +17 -0
- data/spec/strscan_spec/match_spec.rb +25 -0
- data/spec/strscan_spec/matched_size_spec.rb +3 -0
- data/spec/strscan_spec/matched_spec.rb +37 -0
- data/spec/strscan_spec/matchedsize_spec.rb +23 -0
- data/spec/strscan_spec/must_C_version_spec.rb +5 -0
- data/spec/strscan_spec/peek_spec.rb +4 -0
- data/spec/strscan_spec/peep_spec.rb +21 -0
- data/spec/strscan_spec/pointer_spec.rb +7 -0
- data/spec/strscan_spec/pos_spec.rb +7 -0
- data/spec/strscan_spec/post_match_spec.rb +24 -0
- data/spec/strscan_spec/pre_match_spec.rb +37 -0
- data/spec/strscan_spec/reset_spec.rb +12 -0
- data/spec/strscan_spec/rest_size_spec.rb +3 -0
- data/spec/strscan_spec/rest_spec.rb +44 -0
- data/spec/strscan_spec/restsize_spec.rb +21 -0
- data/spec/strscan_spec/scan_full_spec.rb +27 -0
- data/spec/strscan_spec/scan_spec.rb +50 -0
- data/spec/strscan_spec/scan_until_spec.rb +20 -0
- data/spec/strscan_spec/search_full_spec.rb +27 -0
- data/spec/strscan_spec/skip_spec.rb +15 -0
- data/spec/strscan_spec/skip_until_spec.rb +15 -0
- data/spec/strscan_spec/string_spec.rb +37 -0
- data/spec/strscan_spec/terminate_spec.rb +3 -0
- data/spec/strscan_spec/unscan_spec.rb +26 -0
- metadata +172 -0
@@ -0,0 +1,244 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
shared :string_slice do
|
4
|
+
|
5
|
+
it "returns the character code of the character at the given index" do
|
6
|
+
"hello".send(@method, 0).should == ?h
|
7
|
+
"hello".send(@method, -1).should == ?o
|
8
|
+
end
|
9
|
+
|
10
|
+
it "returns nil if index is outside of self" do
|
11
|
+
"hello".send(@method, 20).should == nil
|
12
|
+
"hello".send(@method, -20).should == nil
|
13
|
+
|
14
|
+
# TODO "".send(@method, 0).should == nil
|
15
|
+
"".send(@method, -1).should == nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it "calls to_int on the given index" do
|
19
|
+
"hello".send(@method, 0.5).should == ?h
|
20
|
+
|
21
|
+
obj = 1.0
|
22
|
+
obj.respond_to?(:to_int).should == true
|
23
|
+
"hello".send(@method, obj).should == ?e
|
24
|
+
end
|
25
|
+
|
26
|
+
it "raises a TypeError if the given index is nil" do
|
27
|
+
lambda { "hello".send(@method, nil) }.should.raise(TypeError)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "raises a TypeError if the given index can't be converted to an Integer" do
|
31
|
+
# lambda { "hello".send(@method, mock('x')) }.should.raise(TypeError)
|
32
|
+
lambda { "hello".send(@method, {})}.should.raise(TypeError)
|
33
|
+
lambda { "hello".send(@method, [])}.should.raise(TypeError)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
shared :string_slice_index_length do
|
39
|
+
it "returns the substring starting at the given index with the given length" do
|
40
|
+
"hello there".send(@method, 0,0).should == ""
|
41
|
+
"hello there".send(@method, 0,1).should == "h"
|
42
|
+
"hello there".send(@method, 0,3).should == "hel"
|
43
|
+
"hello there".send(@method, 0,6).should == "hello "
|
44
|
+
"hello there".send(@method, 0,9).should == "hello the"
|
45
|
+
"hello there".send(@method, 0,12).should == "hello there"
|
46
|
+
|
47
|
+
"hello there".send(@method, 1,0).should == ""
|
48
|
+
"hello there".send(@method, 1,1).should == "e"
|
49
|
+
"hello there".send(@method, 1,3).should == "ell"
|
50
|
+
"hello there".send(@method, 1,6).should == "ello t"
|
51
|
+
"hello there".send(@method, 1,9).should == "ello ther"
|
52
|
+
"hello there".send(@method, 1,12).should == "ello there"
|
53
|
+
|
54
|
+
"hello there".send(@method, 3,0).should == ""
|
55
|
+
"hello there".send(@method, 3,1).should == "l"
|
56
|
+
"hello there".send(@method, 3,3).should == "lo "
|
57
|
+
"hello there".send(@method, 3,6).should == "lo the"
|
58
|
+
"hello there".send(@method, 3,9).should == "lo there"
|
59
|
+
|
60
|
+
"hello there".send(@method, 4,0).should == ""
|
61
|
+
"hello there".send(@method, 4,3).should == "o t"
|
62
|
+
"hello there".send(@method, 4,6).should == "o ther"
|
63
|
+
"hello there".send(@method, 4,9).should == "o there"
|
64
|
+
|
65
|
+
"foo".send(@method, 2,1).should == "o"
|
66
|
+
"foo".send(@method, 3,0).should == ""
|
67
|
+
"foo".send(@method, 3,1).should == ""
|
68
|
+
|
69
|
+
"".send(@method, 0,0).should == ""
|
70
|
+
"".send(@method, 0,1).should == ""
|
71
|
+
|
72
|
+
"x".send(@method, 0,0).should == ""
|
73
|
+
"x".send(@method, 0,1).should == "x"
|
74
|
+
"x".send(@method, 1,0).should == ""
|
75
|
+
"x".send(@method, 1,1).should == ""
|
76
|
+
|
77
|
+
"x".send(@method, -1,0).should == ""
|
78
|
+
"x".send(@method, -1,1).should == "x"
|
79
|
+
|
80
|
+
"hello there".send(@method, -3,2).should == "er"
|
81
|
+
end
|
82
|
+
|
83
|
+
it "always taints resulting strings when self is tainted" do
|
84
|
+
str = "hello world"
|
85
|
+
str.taint
|
86
|
+
|
87
|
+
str.send(@method, 0,0).tainted?.should == true
|
88
|
+
str.send(@method, 0,1).tainted?.should == true
|
89
|
+
str.send(@method, 2,1).tainted?.should == true
|
90
|
+
end
|
91
|
+
|
92
|
+
it "returns nil if the offset falls outside of self" do
|
93
|
+
"hello there".send(@method, 20,3).should == nil
|
94
|
+
"hello there".send(@method, -20,3).should == nil
|
95
|
+
|
96
|
+
"".send(@method, 1,0).should == nil
|
97
|
+
"".send(@method, 1,1).should == nil
|
98
|
+
|
99
|
+
"".send(@method, -1,0).should == nil
|
100
|
+
"".send(@method, -1,1).should == nil
|
101
|
+
|
102
|
+
"x".send(@method, 2,0).should == nil
|
103
|
+
"x".send(@method, 2,1).should == nil
|
104
|
+
|
105
|
+
"x".send(@method, -2,0).should == nil
|
106
|
+
"x".send(@method, -2,1).should == nil
|
107
|
+
end
|
108
|
+
|
109
|
+
it "returns nil if the length is negative" do
|
110
|
+
"hello there".send(@method, 4,-3).should == nil
|
111
|
+
"hello there".send(@method, -4,-3).should == nil
|
112
|
+
end
|
113
|
+
|
114
|
+
it "calls to_int on the given index and the given length" do
|
115
|
+
"hello".send(@method, 0.5, 1).should == "h"
|
116
|
+
"hello".send(@method, 0.5, 2.5).should == "he"
|
117
|
+
"hello".send(@method, 1, 2.5).should == "el"
|
118
|
+
|
119
|
+
# obj = mock('2')
|
120
|
+
# obj.should_receive(:to_int).exactly(4).times.and_return(2)
|
121
|
+
|
122
|
+
# "hello".send(@method, obj, 1).should == "l"
|
123
|
+
# "hello".send(@method, obj, obj).should == "ll"
|
124
|
+
# "hello".send(@method, 0, obj).should == "he"
|
125
|
+
end
|
126
|
+
|
127
|
+
it "raises a TypeError when idx or length can't be converted to an integer" do
|
128
|
+
lambda { "hello".send(@method, 'x', 0) }.should.raise(TypeError)
|
129
|
+
lambda { "hello".send(@method, 0, 'x') }.should.raise(TypeError)
|
130
|
+
|
131
|
+
# I'm deliberately including this here.
|
132
|
+
# It means that str.send(@method, other, idx) isn't supported.
|
133
|
+
lambda { "hello".send(@method, "", 0) }.should.raise(TypeError)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "raises a TypeError when the given index or the given length is nil" do
|
137
|
+
lambda { "hello".send(@method, 1, nil) }.should.raise(TypeError)
|
138
|
+
lambda { "hello".send(@method, nil, 1) }.should.raise(TypeError)
|
139
|
+
lambda { "hello".send(@method, nil, nil) }.should.raise(TypeError)
|
140
|
+
end
|
141
|
+
|
142
|
+
# it "returns subclass instances" do
|
143
|
+
# s = StringSpecs::MyString.new("hello")
|
144
|
+
# s.send(@method, 0,0).should be_kind_of(StringSpecs::MyString)
|
145
|
+
# s.send(@method, 0,4).should be_kind_of(StringSpecs::MyString)
|
146
|
+
# s.send(@method, 1,4).should be_kind_of(StringSpecs::MyString)
|
147
|
+
# end
|
148
|
+
end
|
149
|
+
|
150
|
+
shared :string_slice_range do
|
151
|
+
it "returns the substring given by the offsets of the range" do
|
152
|
+
"hello there".send(@method, 1..1).should == "e"
|
153
|
+
"hello there".send(@method, 1..3).should == "ell"
|
154
|
+
"hello there".send(@method, 1...3).should == "el"
|
155
|
+
"hello there".send(@method, -4..-2).should == "her"
|
156
|
+
"hello there".send(@method, -4...-2).should == "he"
|
157
|
+
"hello there".send(@method, 5..-1).should == " there"
|
158
|
+
"hello there".send(@method, 5...-1).should == " ther"
|
159
|
+
|
160
|
+
"".send(@method, 0..0).should == ""
|
161
|
+
|
162
|
+
"x".send(@method, 0..0).should == "x"
|
163
|
+
"x".send(@method, 0..1).should == "x"
|
164
|
+
"x".send(@method, 0...1).should == "x"
|
165
|
+
"x".send(@method, 0..-1).should == "x"
|
166
|
+
|
167
|
+
"x".send(@method, 1..1).should == ""
|
168
|
+
"x".send(@method, 1..-1).should == ""
|
169
|
+
end
|
170
|
+
|
171
|
+
it "returns nil if the beginning of the range falls outside of self" do
|
172
|
+
"hello there".send(@method, 12..-1).should == nil
|
173
|
+
"hello there".send(@method, 20..25).should == nil
|
174
|
+
"hello there".send(@method, 20..1).should == nil
|
175
|
+
"hello there".send(@method, -20..1).should == nil
|
176
|
+
"hello there".send(@method, -20..-1).should == nil
|
177
|
+
|
178
|
+
"".send(@method, -1..-1).should == nil
|
179
|
+
"".send(@method, -1...-1).should == nil
|
180
|
+
"".send(@method, -1..0).should == nil
|
181
|
+
"".send(@method, -1...0).should == nil
|
182
|
+
end
|
183
|
+
|
184
|
+
it "returns an empty string if range.begin is inside self and > real end" do
|
185
|
+
"hello there".send(@method, 1...1).should == ""
|
186
|
+
"hello there".send(@method, 4..2).should == ""
|
187
|
+
"hello".send(@method, 4..-4).should == ""
|
188
|
+
"hello there".send(@method, -5..-6).should == ""
|
189
|
+
"hello there".send(@method, -2..-4).should == ""
|
190
|
+
"hello there".send(@method, -5..-6).should == ""
|
191
|
+
"hello there".send(@method, -5..2).should == ""
|
192
|
+
|
193
|
+
"".send(@method, 0...0).should == ""
|
194
|
+
"".send(@method, 0..-1).should == ""
|
195
|
+
"".send(@method, 0...-1).should == ""
|
196
|
+
|
197
|
+
"x".send(@method, 0...0).should == ""
|
198
|
+
"x".send(@method, 0...-1).should == ""
|
199
|
+
"x".send(@method, 1...1).should == ""
|
200
|
+
"x".send(@method, 1...-1).should == ""
|
201
|
+
end
|
202
|
+
|
203
|
+
it "always taints resulting strings when self is tainted" do
|
204
|
+
str = "hello world"
|
205
|
+
str.taint
|
206
|
+
|
207
|
+
str.send(@method, 0..0).tainted?.should == true
|
208
|
+
str.send(@method, 0...0).tainted?.should == true
|
209
|
+
str.send(@method, 0..1).tainted?.should == true
|
210
|
+
str.send(@method, 0...1).tainted?.should == true
|
211
|
+
str.send(@method, 2..3).tainted?.should == true
|
212
|
+
str.send(@method, 2..0).tainted?.should == true
|
213
|
+
end
|
214
|
+
|
215
|
+
# it "returns subclass instances" do
|
216
|
+
# s = StringSpecs::MyString.new("hello")
|
217
|
+
# s.send(@method, 0...0).should be_kind_of(StringSpecs::MyString)
|
218
|
+
# s.send(@method, 0..4).should be_kind_of(StringSpecs::MyString)
|
219
|
+
# s.send(@method, 1..4).should be_kind_of(StringSpecs::MyString)
|
220
|
+
# end
|
221
|
+
#
|
222
|
+
# it "calls to_int on range arguments" do
|
223
|
+
# from = mock('from')
|
224
|
+
# to = mock('to')
|
225
|
+
#
|
226
|
+
# # So we can construct a range out of them...
|
227
|
+
# from.should_receive(:<=>).twice.and_return(0)
|
228
|
+
#
|
229
|
+
# from.should_receive(:to_int).twice.and_return(1)
|
230
|
+
# to.should_receive(:to_int).twice.and_return(-2)
|
231
|
+
#
|
232
|
+
# "hello there".send(@method, from..to).should == "ello ther"
|
233
|
+
# "hello there".send(@method, from...to).should == "ello the"
|
234
|
+
# end
|
235
|
+
#
|
236
|
+
# it "works with Range subclasses" do
|
237
|
+
# a = "GOOD"
|
238
|
+
# range_incl = StringSpecs::MyRange.new(1, 2)
|
239
|
+
# range_excl = StringSpecs::MyRange.new(-3, -1, true)
|
240
|
+
#
|
241
|
+
# a.send(@method, range_incl).should == "OO"
|
242
|
+
# a.send(@method, range_excl).should == "OO"
|
243
|
+
# end
|
244
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
describe "String#byteslice" do
|
2
|
+
# it "needs to reviewed for spec completeness"
|
3
|
+
|
4
|
+
it_behaves_like :string_slice, :byteslice
|
5
|
+
end
|
6
|
+
|
7
|
+
describe "String#byteslice with index, length" do
|
8
|
+
it_behaves_like :string_slice_index_length, :byteslice
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "String#byteslice with Range" do
|
12
|
+
it_behaves_like :string_slice_range, :byteslice
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "String#byteslice on on non ASCII strings" do
|
16
|
+
it "returns byteslice of unicode strings" do
|
17
|
+
"\u3042".byteslice(1).should == "\x81".force_encoding("UTF-8")
|
18
|
+
"\u3042".byteslice(1, 2).should == "\x81\x82".force_encoding("UTF-8")
|
19
|
+
"\u3042".byteslice(1..2).should == "\x81\x82".force_encoding("UTF-8")
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
shared :strscan_bol do
|
2
|
+
it "returns true if the scan pointer is at the beginning of the line, false otherwise" do
|
3
|
+
s = StringScanner.new("This is a test")
|
4
|
+
s.send(@method).should.be_true
|
5
|
+
s.scan(/This/)
|
6
|
+
s.send(@method).should.be_false
|
7
|
+
s.terminate
|
8
|
+
s.send(@method).should.be_false
|
9
|
+
|
10
|
+
s = StringScanner.new("hello\nworld")
|
11
|
+
s.bol?.should.be_true
|
12
|
+
s.scan(/\w+/)
|
13
|
+
s.bol?.should.be_false
|
14
|
+
s.scan(/\n/)
|
15
|
+
s.bol?.should.be_true
|
16
|
+
s.unscan
|
17
|
+
s.bol?.should.be_false
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns true if the scan pointer is at the end of the line of an empty string." do
|
21
|
+
s = StringScanner.new('')
|
22
|
+
s.terminate
|
23
|
+
s.send(@method).should.be_true
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
shared :strscan_concat do
|
2
|
+
it "concatenates the given argument to self and returns self" do
|
3
|
+
s = StringScanner.new("hello ")
|
4
|
+
s.send(@method, 'world').should == s
|
5
|
+
s.string.should == "hello world"
|
6
|
+
s.eos?.should.be_false
|
7
|
+
end
|
8
|
+
|
9
|
+
it "raises a TypeError if the given argument can't be converted to a String" do
|
10
|
+
lambda { a = StringScanner.new('hello').send(@method, :world) }.should.raise(TypeError)
|
11
|
+
# lambda { a = StringScanner.new('hello').send(@method, mock('x')) }.should.raise(TypeError)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
shared :strscan_concat_fixnum do
|
16
|
+
it "raises a TypeError" do
|
17
|
+
a = StringScanner.new("hello world")
|
18
|
+
lambda { a.send(@method, 333) }.should.raise(TypeError)
|
19
|
+
b = StringScanner.new("")
|
20
|
+
lambda { b.send(@method, (256 * 3 + 64)) }.should.raise(TypeError)
|
21
|
+
lambda { b.send(@method, -200) }.should.raise(TypeError)
|
22
|
+
end
|
23
|
+
|
24
|
+
# it "doesn't call to_int on the argument" do
|
25
|
+
# x = mock('x')
|
26
|
+
# x.respond_to?(:to_int).should == false
|
27
|
+
#
|
28
|
+
# lambda { "".send(@method, x) }.should.raise(TypeError)
|
29
|
+
# end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
shared :strscan_eos do
|
2
|
+
before do
|
3
|
+
@s = StringScanner.new("This is a test")
|
4
|
+
end
|
5
|
+
|
6
|
+
it "Returns true if the scan pointer is at the end of the string" do
|
7
|
+
@s.terminate
|
8
|
+
@s.send(@method).should.be_true
|
9
|
+
|
10
|
+
s = StringScanner.new('')
|
11
|
+
s.send(@method).should.be_true
|
12
|
+
end
|
13
|
+
|
14
|
+
it "Returns false if the scan pointer is not at the end of the string" do
|
15
|
+
@s.send(@method).should.be_false
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
shared :extract_range do
|
2
|
+
it "returns an instance of String when passed a String subclass" do
|
3
|
+
cls = Class.new(String)
|
4
|
+
sub = cls.new("abc")
|
5
|
+
|
6
|
+
s = StringScanner.new(sub)
|
7
|
+
ch = s.send(@method)
|
8
|
+
ch.should.not.be.kind_of(cls)
|
9
|
+
ch.should.be.an.instance_of(String)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "taints the returned String if the input was tainted" do
|
13
|
+
str = 'abc'
|
14
|
+
str.taint
|
15
|
+
|
16
|
+
s = StringScanner.new(str)
|
17
|
+
|
18
|
+
s.send(@method).tainted?.should.be_true
|
19
|
+
s.send(@method).tainted?.should.be_true
|
20
|
+
s.send(@method).tainted?.should.be_true
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
shared :extract_range_matched do
|
2
|
+
it "returns an instance of String when passed a String subclass" do
|
3
|
+
cls = Class.new(String)
|
4
|
+
sub = cls.new("abc")
|
5
|
+
|
6
|
+
s = StringScanner.new(sub)
|
7
|
+
s.scan(/\w{1}/)
|
8
|
+
|
9
|
+
ch = s.send(@method)
|
10
|
+
ch.should.not.be.kind_of(cls)
|
11
|
+
ch.should.be.an.instance_of(String)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "taints the returned String if the input was tainted" do
|
15
|
+
str = 'abc'
|
16
|
+
str.taint
|
17
|
+
|
18
|
+
s = StringScanner.new(str)
|
19
|
+
s.scan(/\w{1}/)
|
20
|
+
s.send(@method).tainted?.should.be_true
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
shared :strscan_get_byte do
|
2
|
+
it "scans one byte and returns it" do
|
3
|
+
s = StringScanner.new('abc5.')
|
4
|
+
s.send(@method).should == 'a'
|
5
|
+
s.send(@method).should == 'b'
|
6
|
+
s.send(@method).should == 'c'
|
7
|
+
s.send(@method).should == '5'
|
8
|
+
s.send(@method).should == '.'
|
9
|
+
end
|
10
|
+
|
11
|
+
it "is not multi-byte character sensitive" do
|
12
|
+
s = StringScanner.new("\244\242")
|
13
|
+
s.send(@method).should == "\244"
|
14
|
+
s.send(@method).should == "\242"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns nil at the end of the string" do
|
18
|
+
# empty string case
|
19
|
+
s = StringScanner.new('')
|
20
|
+
s.send(@method).should == nil
|
21
|
+
s.send(@method).should == nil
|
22
|
+
|
23
|
+
# non-empty string case
|
24
|
+
s = StringScanner.new('a')
|
25
|
+
s.send(@method) # skip one
|
26
|
+
s.send(@method).should == nil
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
shared :strscan_matched_size do
|
2
|
+
before do
|
3
|
+
@s = StringScanner.new("This is a test")
|
4
|
+
end
|
5
|
+
|
6
|
+
it "returns the size of the most recent match" do
|
7
|
+
@s.check /This/
|
8
|
+
@s.send(@method).should == 4
|
9
|
+
@s.send(@method).should == 4
|
10
|
+
@s.scan //
|
11
|
+
@s.send(@method).should == 0
|
12
|
+
end
|
13
|
+
|
14
|
+
it "returns nil if there was no recent match" do
|
15
|
+
@s.send(@method).should == nil
|
16
|
+
@s.check /\d+/
|
17
|
+
@s.send(@method).should == nil
|
18
|
+
@s.terminate
|
19
|
+
@s.send(@method).should == nil
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
shared :strscan_peek do
|
2
|
+
before do
|
3
|
+
@s = StringScanner.new('This is a test')
|
4
|
+
end
|
5
|
+
|
6
|
+
it "returns at most the specified number of characters from the current position" do
|
7
|
+
@s.send(@method, 4).should == "This"
|
8
|
+
@s.pos.should == 0
|
9
|
+
@s.pos = 5
|
10
|
+
@s.send(@method, 2).should == "is"
|
11
|
+
@s.send(@method, 1000).should == "is a test"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "returns an empty string when the passed argument is zero" do
|
15
|
+
@s.send(@method, 0).should == ""
|
16
|
+
end
|
17
|
+
|
18
|
+
it "raises a ArgumentError when the passed argument is negative" do
|
19
|
+
lambda { @s.send(@method, -2) }.should.raise(ArgumentError)
|
20
|
+
end
|
21
|
+
|
22
|
+
# it "raises a RangeError when the passed argument is a Bignum" do
|
23
|
+
# lambda { @s.send(@method, bignum_value) }.should.raise(RangeError)
|
24
|
+
# end
|
25
|
+
|
26
|
+
it "returns an instance of String when passed a String subclass" do
|
27
|
+
cls = Class.new(String)
|
28
|
+
sub = cls.new("abc")
|
29
|
+
|
30
|
+
s = StringScanner.new(sub)
|
31
|
+
|
32
|
+
ch = s.send(@method, 1)
|
33
|
+
ch.should.not.be.kind_of(cls)
|
34
|
+
ch.should.be.an.instance_of(String)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "taints the returned String if the input was tainted" do
|
38
|
+
str = 'abc'
|
39
|
+
str.taint
|
40
|
+
|
41
|
+
s = StringScanner.new(str)
|
42
|
+
s.send(@method, 1).tainted?.should.be_true
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
shared :strscan_pos do
|
4
|
+
before do
|
5
|
+
@s = StringScanner.new("This is a test")
|
6
|
+
@m = StringScanner.new("cölorfül")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "returns the position of the scan pointer" do
|
10
|
+
@s.send(@method).should == 0
|
11
|
+
@s.scan_until /This is/
|
12
|
+
@s.send(@method).should == 7
|
13
|
+
@s.get_byte
|
14
|
+
@s.send(@method).should == 8
|
15
|
+
@s.terminate
|
16
|
+
@s.send(@method).should == 14
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns the position of the scan pointer for multibyte string" do
|
20
|
+
@m.send(@method).should == 0
|
21
|
+
@m.scan_until /cö/
|
22
|
+
@m.send(@method).should == 3
|
23
|
+
@m.get_byte
|
24
|
+
@m.send(@method).should == 4
|
25
|
+
@m.terminate
|
26
|
+
@m.send(@method).should == 10
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns 0 in the reset position" do
|
30
|
+
@s.reset
|
31
|
+
@s.send(@method).should == 0
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns the length of the string in the terminate position" do
|
35
|
+
@s.terminate
|
36
|
+
@s.send(@method).should == @s.string.length
|
37
|
+
end
|
38
|
+
|
39
|
+
it "returns the `bytesize` for multibyte string in the terminate position" do
|
40
|
+
@m.terminate
|
41
|
+
@m.send(@method).should == @m.string.bytesize
|
42
|
+
@m.send(@method).should >= @m.string.length
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
shared :strscan_pos_set do
|
47
|
+
before do
|
48
|
+
@s = StringScanner.new("This is a test")
|
49
|
+
@m = StringScanner.new("cölorfül")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "modify the scan pointer" do
|
53
|
+
@s.send(@method, 5)
|
54
|
+
@s.rest.should == "is a test"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "can poin position that greater than string length for multibyte string" do
|
58
|
+
@m.send(@method, 9)
|
59
|
+
@m.rest.should == "l"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "positions from the end if the argument is negative" do
|
63
|
+
@s.send(@method, -2)
|
64
|
+
@s.rest.should == "st"
|
65
|
+
@s.pos.should == 12
|
66
|
+
end
|
67
|
+
|
68
|
+
it "positions from the end if the argument is negative for multibyte string" do
|
69
|
+
@m.send(@method, -3)
|
70
|
+
@m.rest.should == "ül"
|
71
|
+
@m.pos.should == 7
|
72
|
+
end
|
73
|
+
|
74
|
+
it "raises a RangeError if position too far backward" do
|
75
|
+
lambda {
|
76
|
+
@s.send(@method, -20)
|
77
|
+
}.should.raise(RangeError)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "raises a RangeError when the passed argument is out of range" do
|
81
|
+
lambda { @s.send(@method, 20) }.should.raise(RangeError)
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
shared :strscan_rest_size do
|
2
|
+
before do
|
3
|
+
@s = StringScanner.new('This is a test')
|
4
|
+
end
|
5
|
+
|
6
|
+
it "Returns the length of the rest of the string" do
|
7
|
+
@s.send(@method).should == 14
|
8
|
+
@s.scan(/This/)
|
9
|
+
@s.send(@method).should == 10
|
10
|
+
@s.terminate
|
11
|
+
@s.send(@method).should == 0
|
12
|
+
end
|
13
|
+
|
14
|
+
it "is equivalent to rest.size" do
|
15
|
+
@s.scan(/This/)
|
16
|
+
@s.send(@method).should == @s.rest.size
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
shared :strscan_terminate do
|
4
|
+
it "set the scan pointer to the end of the string and clear matching data." do
|
5
|
+
s = StringScanner.new('This is a test')
|
6
|
+
s.send(@method)
|
7
|
+
s.bol?.should.be_false
|
8
|
+
s.eos?.should.be_true
|
9
|
+
end
|
10
|
+
|
11
|
+
it "set the scan pointer to the end of the string and clear matching data for multibyte string." do
|
12
|
+
s = StringScanner.new('cölorfül')
|
13
|
+
s.send(@method)
|
14
|
+
s.bol?.should.be_false
|
15
|
+
s.eos?.should.be_true
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
describe "StringScanner#check" do
|
2
|
+
before do
|
3
|
+
@s = StringScanner.new("This is a test")
|
4
|
+
end
|
5
|
+
|
6
|
+
it "returns the value that scan would return, without advancing the scan pointer" do
|
7
|
+
@s.check(/This/).should == "This"
|
8
|
+
@s.matched.should == "This"
|
9
|
+
@s.pos.should == 0
|
10
|
+
@s.check(/is/).should == nil
|
11
|
+
@s.matched.should == nil
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# require 'strscan'
|
2
|
+
|
3
|
+
describe "StringScanner#check_until" do
|
4
|
+
before do
|
5
|
+
@s = StringScanner.new("This is a test")
|
6
|
+
end
|
7
|
+
|
8
|
+
it "returns the same value of scan_until, but don't advances the scan pointer" do
|
9
|
+
@s.check_until(/a/).should == "This is a"
|
10
|
+
@s.pos.should == 0
|
11
|
+
@s.matched.should == "a"
|
12
|
+
@s.check_until(/test/).should == "This is a test"
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
describe "StringScanner#clear" do
|
2
|
+
it_behaves_like(:strscan_terminate, :clear)
|
3
|
+
|
4
|
+
# it "warns in verbose mode that the method is obsolete" do
|
5
|
+
# s = StringScanner.new("abc")
|
6
|
+
# begin
|
7
|
+
# old = $VERBOSE
|
8
|
+
# lambda {
|
9
|
+
# $VERBOSE = true
|
10
|
+
# s.clear
|
11
|
+
# }.should complain(/clear.*obsolete.*terminate/)
|
12
|
+
#
|
13
|
+
# lambda {
|
14
|
+
# $VERBOSE = false
|
15
|
+
# s.clear
|
16
|
+
# }.should_not complain
|
17
|
+
# ensure
|
18
|
+
# $VERBOSE = old
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
end
|