motion-strscan 0.5.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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +63 -0
  3. data/lib/motion-strscan/string.rb +20 -0
  4. data/lib/motion-strscan/strscan.rb +676 -0
  5. data/lib/motion-strscan/version.rb +3 -0
  6. data/lib/motion-strscan.rb +8 -0
  7. data/spec/helpers/it_behaves_like.rb +27 -0
  8. data/spec/string_spec/_shared/slice.rb +244 -0
  9. data/spec/string_spec/byteslice_spec.rb +21 -0
  10. data/spec/strscan_spec/_shared/bol.rb +25 -0
  11. data/spec/strscan_spec/_shared/concat.rb +31 -0
  12. data/spec/strscan_spec/_shared/eos.rb +17 -0
  13. data/spec/strscan_spec/_shared/extract_range.rb +22 -0
  14. data/spec/strscan_spec/_shared/extract_range_matched.rb +22 -0
  15. data/spec/strscan_spec/_shared/get_byte.rb +28 -0
  16. data/spec/strscan_spec/_shared/matched_size.rb +21 -0
  17. data/spec/strscan_spec/_shared/peek.rb +44 -0
  18. data/spec/strscan_spec/_shared/pos.rb +83 -0
  19. data/spec/strscan_spec/_shared/rest_size.rb +18 -0
  20. data/spec/strscan_spec/_shared/terminate.rb +17 -0
  21. data/spec/strscan_spec/append_spec.rb +7 -0
  22. data/spec/strscan_spec/beginning_of_line_spec.rb +3 -0
  23. data/spec/strscan_spec/bol_spec.rb +3 -0
  24. data/spec/strscan_spec/check_spec.rb +13 -0
  25. data/spec/strscan_spec/check_until_spec.rb +14 -0
  26. data/spec/strscan_spec/clear_spec.rb +21 -0
  27. data/spec/strscan_spec/concat_spec.rb +7 -0
  28. data/spec/strscan_spec/dup_spec.rb +36 -0
  29. data/spec/strscan_spec/element_reference_spec.rb +46 -0
  30. data/spec/strscan_spec/empty_spec.rb +21 -0
  31. data/spec/strscan_spec/eos_spec.rb +3 -0
  32. data/spec/strscan_spec/exist_spec.rb +21 -0
  33. data/spec/strscan_spec/get_byte_spec.rb +3 -0
  34. data/spec/strscan_spec/getbyte_spec.rb +23 -0
  35. data/spec/strscan_spec/getch_spec.rb +41 -0
  36. data/spec/strscan_spec/initialize_spec.rb +25 -0
  37. data/spec/strscan_spec/inspect_spec.rb +17 -0
  38. data/spec/strscan_spec/match_spec.rb +25 -0
  39. data/spec/strscan_spec/matched_size_spec.rb +3 -0
  40. data/spec/strscan_spec/matched_spec.rb +37 -0
  41. data/spec/strscan_spec/matchedsize_spec.rb +23 -0
  42. data/spec/strscan_spec/must_C_version_spec.rb +5 -0
  43. data/spec/strscan_spec/peek_spec.rb +4 -0
  44. data/spec/strscan_spec/peep_spec.rb +21 -0
  45. data/spec/strscan_spec/pointer_spec.rb +7 -0
  46. data/spec/strscan_spec/pos_spec.rb +7 -0
  47. data/spec/strscan_spec/post_match_spec.rb +24 -0
  48. data/spec/strscan_spec/pre_match_spec.rb +37 -0
  49. data/spec/strscan_spec/reset_spec.rb +12 -0
  50. data/spec/strscan_spec/rest_size_spec.rb +3 -0
  51. data/spec/strscan_spec/rest_spec.rb +44 -0
  52. data/spec/strscan_spec/restsize_spec.rb +21 -0
  53. data/spec/strscan_spec/scan_full_spec.rb +27 -0
  54. data/spec/strscan_spec/scan_spec.rb +50 -0
  55. data/spec/strscan_spec/scan_until_spec.rb +20 -0
  56. data/spec/strscan_spec/search_full_spec.rb +27 -0
  57. data/spec/strscan_spec/skip_spec.rb +15 -0
  58. data/spec/strscan_spec/skip_until_spec.rb +15 -0
  59. data/spec/strscan_spec/string_spec.rb +37 -0
  60. data/spec/strscan_spec/terminate_spec.rb +3 -0
  61. data/spec/strscan_spec/unscan_spec.rb +26 -0
  62. metadata +172 -0
@@ -0,0 +1,7 @@
1
+ describe "StringScanner#concat" do
2
+ it_behaves_like(:strscan_concat, :concat)
3
+ end
4
+
5
+ describe "StringScanner#concat when passed a Fixnum" do
6
+ it_behaves_like(:strscan_concat_fixnum, :concat)
7
+ end
@@ -0,0 +1,36 @@
1
+ describe "StringScanner#dup" do
2
+ before do
3
+ @string = "this is a test"
4
+ @orig_s = StringScanner.new(@string)
5
+ end
6
+
7
+ it "copies the passed StringScanner's content to self" do
8
+ s = @orig_s.dup
9
+ s.string.should == @string
10
+ end
11
+
12
+ it "copies the passed StringSCanner's position to self" do
13
+ @orig_s.pos = 5
14
+ s = @orig_s.dup
15
+ s.pos.should.equal(5)
16
+ end
17
+
18
+ it "copies previous match state" do
19
+ @orig_s.scan(/\w+/)
20
+ @orig_s.scan(/\s/)
21
+
22
+ @orig_s.pre_match.should == "this"
23
+
24
+ s = @orig_s.dup
25
+ s.pre_match.should == "this"
26
+
27
+ s.unscan
28
+ s.scan(/\s/).should == " "
29
+ end
30
+
31
+ it "copies the passed StringScanner scan pointer to self" do
32
+ @orig_s.terminate
33
+ s = @orig_s.dup
34
+ s.eos?.should.be_true
35
+ end
36
+ end
@@ -0,0 +1,46 @@
1
+ describe "StringScanner#[]" do
2
+ before do
3
+ @s = StringScanner.new("Fri Jun 13 2008 22:43")
4
+ end
5
+
6
+ it "returns nil if there is no current match" do
7
+ @s[0].should == nil
8
+ end
9
+
10
+ it "returns the n-th subgroup in the most recent match" do
11
+ @s.scan(/(\w+) (\w+) (\d+) /)
12
+ @s[0].should == "Fri Jun 13 "
13
+ @s[1].should == "Fri"
14
+ @s[2].should == "Jun"
15
+ @s[3].should == "13"
16
+ @s[-3].should == "Fri"
17
+ @s[-2].should == "Jun"
18
+ @s[-1].should == "13"
19
+ end
20
+
21
+ it "returns nil if index is outside of self" do
22
+ @s.scan(/(\w+) (\w+) (\d+) /)
23
+ @s[5].should == nil
24
+ @s[-5].should == nil
25
+ end
26
+
27
+ it "calls to_int on the given index" do
28
+ @s.scan(/(\w+) (\w+) (\d+) /)
29
+ @s[0.5].should == "Fri Jun 13 "
30
+ end
31
+
32
+ it "raises a TypeError if the given index is nil" do
33
+ @s.scan(/(\w+) (\w+) (\d+) /)
34
+ lambda { @s[nil]}.should.raise(TypeError)
35
+ end
36
+
37
+ it "raises a TypeError when a String is as argument" do
38
+ @s.scan(/(\w+) (\w+) (\d+) /)
39
+ lambda { @s["Fri"]}.should.raise(TypeError)
40
+ end
41
+
42
+ it "raises a TypeError when a Range is as argument" do
43
+ @s.scan(/(\w+) (\w+) (\d+) /)
44
+ lambda { @s[0..2]}.should.raise(TypeError)
45
+ end
46
+ end
@@ -0,0 +1,21 @@
1
+ describe "StringScanner#empty?" do
2
+ it_behaves_like(:strscan_eos, :empty?)
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.empty?
11
+ # }.should complain(/empty?.*obsolete.*eos?/)
12
+ #
13
+ # lambda {
14
+ # $VERBOSE = false
15
+ # s.empty?
16
+ # }.should_not complain
17
+ # ensure
18
+ # $VERBOSE = old
19
+ # end
20
+ # end
21
+ end
@@ -0,0 +1,3 @@
1
+ describe "StringScanner#eos?" do
2
+ it_behaves_like(:strscan_eos, :eos?)
3
+ end
@@ -0,0 +1,21 @@
1
+ describe "StringScanner#exist?" do
2
+ before do
3
+ @s = StringScanner.new("This is a test")
4
+ end
5
+
6
+ it "returns the index of the first occurrence of the given pattern" do
7
+ @s.exist?(/s/).should == 4
8
+ @s.scan(/This is/)
9
+ @s.exist?(/s/).should == 6
10
+ end
11
+
12
+ it "returns 0 if the pattern is empty" do
13
+ @s.exist?(//).should == 0
14
+ end
15
+
16
+ it "returns nil if the pattern isn't found in the string" do
17
+ @s.exist?(/S/).should == nil
18
+ @s.scan(/This is/)
19
+ @s.exist?(/i/).should == nil
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ describe "StringScanner#get_byte" do
2
+ it_behaves_like :strscan_get_byte, :get_byte
3
+ end
@@ -0,0 +1,23 @@
1
+ describe "StringScanner#getbyte" do
2
+ it_behaves_like :strscan_get_byte, :getbyte
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.getbyte
11
+ # }.should complain(/getbyte.*obsolete.*get_byte/)
12
+ #
13
+ # lambda {
14
+ # $VERBOSE = false
15
+ # s.getbyte
16
+ # }.should_not complain
17
+ # ensure
18
+ # $VERBOSE = old
19
+ # end
20
+ # end
21
+
22
+ it_behaves_like :extract_range, :getbyte
23
+ end
@@ -0,0 +1,41 @@
1
+ describe "StringScanner#getch" do
2
+ before do
3
+ @kcode = $KCODE
4
+ end
5
+
6
+ after do
7
+ $KCODE = @kcode
8
+ end
9
+
10
+ it "scans one character and returns it" do
11
+ s = StringScanner.new('abc')
12
+ s.getch.should == "a"
13
+ s.getch.should == "b"
14
+ s.getch.should == "c"
15
+ end
16
+
17
+ # it "is multi-byte character sensitive" do
18
+ # $KCODE = 'EUC'
19
+ #
20
+ # # Japanese hiragana "A" in EUC-JP
21
+ # # src = "\244\242".encode("euc-jp")
22
+ # src = "\244\242".force_encoding("euc-jp")
23
+ #
24
+ # s = StringScanner.new(src)
25
+ # s.getch.should == src
26
+ # end
27
+
28
+ it "returns nil at the end of the string" do
29
+ # empty string case
30
+ s = StringScanner.new('')
31
+ s.getch.should == nil
32
+ s.getch.should == nil
33
+
34
+ # non-empty string case
35
+ s = StringScanner.new('a')
36
+ s.getch # skip one
37
+ s.getch.should == nil
38
+ end
39
+
40
+ it_behaves_like :extract_range, :getch
41
+ end
@@ -0,0 +1,25 @@
1
+ describe "StringScanner#initialize" do
2
+ before do
3
+ @s = StringScanner.new("This is a test")
4
+ end
5
+
6
+ # it "is a private method" do
7
+ # StringScanner.should.be.a.private_instance_method(:initialize)
8
+ # end
9
+
10
+ it "returns an instance of StringScanner" do
11
+ @s.should.be.kind_of(StringScanner)
12
+ @s.tainted?.should.be_false
13
+ @s.eos?.should.be_false
14
+ end
15
+
16
+ # it "converts the argument into a string using #to_str" do
17
+ # m = mock(:str)
18
+ #
19
+ # s = "test"
20
+ # m.should_receive(:to_str).and_return(s)
21
+ #
22
+ # scan = StringScanner.new(m)
23
+ # scan.string.should == s
24
+ # end
25
+ end
@@ -0,0 +1,17 @@
1
+ describe "StringScanner#inspect" do
2
+ before do
3
+ @s = StringScanner.new("This is a test")
4
+ end
5
+
6
+ it "returns a String object" do
7
+ @s.inspect.should.be.kind_of(String)
8
+ end
9
+
10
+ it "returns a string that represents the StringScanner object" do
11
+ @s.inspect.should == "#<StringScanner 0/14 @ \"This ...\">"
12
+ @s.scan_until /is/
13
+ @s.inspect.should == "#<StringScanner 4/14 \"This\" @ \" is a...\">"
14
+ @s.terminate
15
+ @s.inspect.should == "#<StringScanner fin>"
16
+ end
17
+ end
@@ -0,0 +1,25 @@
1
+ describe "StringScanner#match?" do
2
+ before do
3
+ @s = StringScanner.new("This is a test")
4
+ end
5
+
6
+ it "returns the length of the match and the scan pointer is not advanced" do
7
+ @s.match?(/\w+/).should == 4
8
+ @s.match?(/\w+/).should == 4
9
+ @s.pos.should == 0
10
+ end
11
+
12
+ it "returns nil if there's no match" do
13
+ @s.match?(/\d+/).should == nil
14
+ @s.match?(/\s+/).should == nil
15
+ end
16
+
17
+ it "effects pre_match" do
18
+ @s.scan(/\w+/)
19
+ @s.scan(/\s/)
20
+
21
+ @s.pre_match.should == "This"
22
+ @s.match?(/\w+/)
23
+ @s.pre_match.should == "This "
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ describe "StringScanner#matched_size" do
2
+ it_behaves_like(:strscan_matched_size, :matched_size)
3
+ end
@@ -0,0 +1,37 @@
1
+ describe "StringScanner#matched" do
2
+ before do
3
+ @s = StringScanner.new("This is a test")
4
+ end
5
+
6
+ it "returns the last matched string" do
7
+ @s.match?(/\w+/)
8
+ @s.matched.should == "This"
9
+ @s.getch
10
+ @s.matched.should == "T"
11
+ @s.get_byte
12
+ @s.matched.should == "h"
13
+ end
14
+
15
+ it "returns nil if there's no match" do
16
+ @s.match?(/\d+/)
17
+ @s.matched.should == nil
18
+ end
19
+
20
+ it_behaves_like :extract_range_matched, :matched
21
+ end
22
+
23
+ describe "StringScanner#matched?" do
24
+ before do
25
+ @s = StringScanner.new("This is a test")
26
+ end
27
+
28
+ it "returns true if the last match was successful" do
29
+ @s.match?(/\w+/)
30
+ @s.matched?.should.be_true
31
+ end
32
+
33
+ it "returns false if there's no match" do
34
+ @s.match?(/\d+/)
35
+ @s.matched?.should.be_false
36
+ end
37
+ end
@@ -0,0 +1,23 @@
1
+ # ruby_version_is "" ... "1.9" do
2
+ describe "StringScanner#matchedsize" do
3
+ it_behaves_like(:strscan_matched_size, :matchedsize)
4
+
5
+ # it "warns in verbose mode that the method is obsolete" do
6
+ # s = StringScanner.new("abc")
7
+ # begin
8
+ # old = $VERBOSE
9
+ # lambda {
10
+ # $VERBOSE = true
11
+ # s.matchedsize
12
+ # }.should complain(/matchedsize.*obsolete.*matched_size/)
13
+ #
14
+ # lambda {
15
+ # $VERBOSE = false
16
+ # s.matchedsize
17
+ # }.should_not complain
18
+ # ensure
19
+ # $VERBOSE = old
20
+ # end
21
+ # end
22
+ end
23
+ # end
@@ -0,0 +1,5 @@
1
+ describe "StringScanner.must_C_version" do
2
+ it "returns self" do
3
+ StringScanner.must_C_version.should == StringScanner
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ describe "StringScanner#peek" do
2
+ it_behaves_like(:strscan_peek, :peek)
3
+ end
4
+
@@ -0,0 +1,21 @@
1
+ describe "StringScanner#peep" do
2
+ it_behaves_like(:strscan_peek, :peep)
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.peep(1)
11
+ # }.should complain(/peep.*obsolete.*peek/)
12
+ #
13
+ # lambda {
14
+ # $VERBOSE = false
15
+ # s.peep(1)
16
+ # }.should_not complain
17
+ # ensure
18
+ # $VERBOSE = old
19
+ # end
20
+ # end
21
+ end
@@ -0,0 +1,7 @@
1
+ describe "StringScanner#pointer" do
2
+ it_behaves_like(:strscan_pos, :pointer)
3
+ end
4
+
5
+ describe "StringScanner#pointer=" do
6
+ it_behaves_like(:strscan_pos_set, :pointer=)
7
+ end
@@ -0,0 +1,7 @@
1
+ describe "StringScanner#pos" do
2
+ it_behaves_like(:strscan_pos, :pos)
3
+ end
4
+
5
+ describe "StringScanner#pos=" do
6
+ it_behaves_like(:strscan_pos_set, :pos=)
7
+ end
@@ -0,0 +1,24 @@
1
+ describe "StringScanner#post_match" do
2
+ before do
3
+ @s = StringScanner.new("This is a test")
4
+ end
5
+
6
+ it "returns the post-match (in the regular expression sense) of the last scan" do
7
+ @s.post_match.should == nil
8
+ @s.scan(/\w+\s/)
9
+ @s.post_match.should == "is a test"
10
+ @s.getch
11
+ @s.post_match.should == "s a test"
12
+ @s.get_byte
13
+ @s.post_match.should == " a test"
14
+ @s.get_byte
15
+ @s.post_match.should == "a test"
16
+ end
17
+
18
+ it "returns nil if there's no match" do
19
+ @s.scan(/\s+/)
20
+ @s.post_match.should == nil
21
+ end
22
+
23
+ it_behaves_like :extract_range_matched, :post_match
24
+ end
@@ -0,0 +1,37 @@
1
+ describe "StringScanner#pre_match" do
2
+ before do
3
+ @s = StringScanner.new("This is a test")
4
+ end
5
+
6
+ it "returns the pre-match (in the regular expression sense) of the last scan" do
7
+ @s.pre_match.should == nil
8
+ @s.scan(/\w+\s/)
9
+ @s.pre_match.should == ""
10
+ @s.getch
11
+ @s.pre_match.should == "This "
12
+ @s.get_byte
13
+ @s.pre_match.should == "This i"
14
+ @s.get_byte
15
+ @s.pre_match.should == "This is"
16
+ end
17
+
18
+ it "returns nil if there's no match" do
19
+ @s.scan(/\s+/)
20
+ @s.pre_match.should == nil
21
+ end
22
+
23
+ it "is more than just the data from the last match" do
24
+ @s.scan(/\w+/)
25
+ @s.scan_until(/a te/)
26
+ @s.pre_match.should == "This is "
27
+ end
28
+
29
+ it "is not changed when the scanner's position changes" do
30
+ @s.scan_until(/\s+/)
31
+ @s.pre_match.should == "This"
32
+ @s.pos -= 1
33
+ @s.pre_match.should == "This"
34
+ end
35
+
36
+ it_behaves_like :extract_range_matched, :pre_match
37
+ end
@@ -0,0 +1,12 @@
1
+ describe "StringScanner#reset" do
2
+ before do
3
+ @s = StringScanner.new("This is a test")
4
+ end
5
+
6
+ it "reset the scan pointer and clear matching data" do
7
+ @s.scan(/This/)
8
+ @s.reset
9
+ @s.pos.should == 0
10
+ @s.matched.should == nil
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ describe "StringScanner#rest_size" do
2
+ it_behaves_like(:strscan_rest_size, :rest_size)
3
+ end
@@ -0,0 +1,44 @@
1
+ describe "StringScanner#rest" do
2
+ before do
3
+ @s = StringScanner.new("This is a test")
4
+ end
5
+
6
+ it "returns the rest of the string" do
7
+ @s.scan(/This\s+/)
8
+ @s.rest.should == "is a test"
9
+ end
10
+
11
+ it "returns self in the reset position" do
12
+ @s.reset
13
+ @s.rest.should == @s.string
14
+ end
15
+
16
+ it "returns an empty string in the terminate position" do
17
+ @s.terminate
18
+ @s.rest.should == ""
19
+ end
20
+
21
+ it_behaves_like :extract_range_matched, :rest
22
+
23
+ end
24
+
25
+ describe "StringScanner#rest?" do
26
+ before do
27
+ @s = StringScanner.new("This is a test")
28
+ end
29
+
30
+ it "returns true if there is more data in the string" do
31
+ @s.rest?.should.be_true
32
+ @s.scan(/This/)
33
+ @s.rest?.should.be_true
34
+ end
35
+
36
+ it "returns false if there is no more data in the string" do
37
+ @s.terminate
38
+ @s.rest?.should.be_false
39
+ end
40
+
41
+ it "is the opposite of eos?" do
42
+ @s.rest?.should.not == @s.eos?
43
+ end
44
+ end
@@ -0,0 +1,21 @@
1
+ describe "StringScanner#restsize" do
2
+ it_behaves_like(:strscan_rest_size, :restsize)
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.restsize
11
+ # }.should complain(/restsize.*obsolete.*rest_size/)
12
+ #
13
+ # lambda {
14
+ # $VERBOSE = false
15
+ # s.restsize
16
+ # }.should_not complain
17
+ # ensure
18
+ # $VERBOSE = old
19
+ # end
20
+ # end
21
+ end
@@ -0,0 +1,27 @@
1
+ describe "StringScanner#scan_full" do
2
+ before do
3
+ @s = StringScanner.new("This is a test")
4
+ end
5
+
6
+ it "returns the number of bytes advanced" do
7
+ orig_pos = @s.pos
8
+ @s.scan_full(/This/, false, false).should == 4
9
+ @s.pos.should == orig_pos
10
+ end
11
+
12
+ it "returns the number of bytes advanced and advances the scan pointer if the second argument is true" do
13
+ @s.scan_full(/This/, true, false).should == 4
14
+ @s.pos.should == 4
15
+ end
16
+
17
+ it "returns the matched string if the third argument is true" do
18
+ orig_pos = @s.pos
19
+ @s.scan_full(/This/, false, true).should == "This"
20
+ @s.pos.should == orig_pos
21
+ end
22
+
23
+ it "returns the matched string if the third argument is true and advances the scan pointer if the second argument is true" do
24
+ @s.scan_full(/This/, true, true).should == "This"
25
+ @s.pos.should == 4
26
+ end
27
+ end
@@ -0,0 +1,50 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ describe "StringScanner#scan" do
4
+ before do
5
+ @s = StringScanner.new("This is a test")
6
+ end
7
+
8
+ it "returns the matched string" do
9
+ @s.scan(/\w+/).should == "This"
10
+ @s.scan(/.../).should == " is"
11
+ @s.scan(//).should == ""
12
+ @s.scan(/\s+/).should == " "
13
+ end
14
+
15
+ # ruby_version_is "1.9" do
16
+ it "returns the matched string for a multi byte string" do
17
+ m = StringScanner.new("Привет!")
18
+ m.scan(/[А-Яа-я]+/).should == "Привет"
19
+ m.rest.should == "!"
20
+ end
21
+ # end
22
+
23
+ it "treats ^ as matching from the beginning of the current position" do
24
+ @s.scan(/\w+/).should == "This"
25
+ @s.scan(/^\d/).should == nil
26
+ @s.scan(/^\s/).should == " "
27
+ end
28
+
29
+ it "returns nil if there's no match" do
30
+ @s.scan(/\d/).should == nil
31
+ end
32
+
33
+ it "returns nil when there is no more to scan" do
34
+ @s.scan(/[\w\s]+/).should == "This is a test"
35
+ @s.scan(/\w+/).should == nil
36
+ end
37
+
38
+ it "returns an empty string when the pattern matches empty" do
39
+ @s.scan(/.*/).should == "This is a test"
40
+ @s.scan(/.*/).should == ""
41
+ @s.scan(/./).should == nil
42
+ end
43
+
44
+ it "raises a TypeError if pattern isn't a Regexp" do
45
+ lambda { @s.scan("aoeu") }.should.raise(TypeError)
46
+ lambda { @s.scan(5) }.should.raise(TypeError)
47
+ lambda { @s.scan(:test) }.should.raise(TypeError)
48
+ # lambda { @s.scan(mock('x')) }.should.raise(TypeError)
49
+ end
50
+ end
@@ -0,0 +1,20 @@
1
+ describe "StringScanner#scan_until" do
2
+ before do
3
+ @s = StringScanner.new("This is a test")
4
+ end
5
+
6
+ it "returns the substring up to and including the end of the match" do
7
+ @s.scan_until(/a/).should == "This is a"
8
+ @s.pre_match.should == "This is "
9
+ @s.post_match.should == " test"
10
+ end
11
+
12
+ it "returns nil if there's no match" do
13
+ @s.scan_until(/\d/).should == nil
14
+ end
15
+
16
+ it "can match anchors properly" do
17
+ @s.scan(/T/)
18
+ @s.scan_until(/^h/).should == "h"
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ describe "StringScanner#search_full" do
2
+ before do
3
+ @s = StringScanner.new("This is a test")
4
+ end
5
+
6
+ it "returns the number of bytes advanced" do
7
+ orig_pos = @s.pos
8
+ @s.search_full(/This/, false, false).should == 4
9
+ @s.pos.should == orig_pos
10
+ end
11
+
12
+ it "returns the number of bytes advanced and advances the scan pointer if the second argument is true" do
13
+ @s.search_full(/This/, true, false).should == 4
14
+ @s.pos.should == 4
15
+ end
16
+
17
+ it "returns the matched string if the third argument is true" do
18
+ orig_pos = @s.pos
19
+ @s.search_full(/This/, false, true).should == "This"
20
+ @s.pos.should == orig_pos
21
+ end
22
+
23
+ it "returns the matched string if the third argument is true and advances the scan pointer if the second argument is true" do
24
+ @s.search_full(/This/, true, true).should == "This"
25
+ @s.pos.should == 4
26
+ end
27
+ end