sequence 0.1.0 → 0.2.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.
data/README.txt CHANGED
@@ -1,3 +1,8 @@
1
+ = sequence
2
+
3
+ * http://sequence.rubyforge.org/
4
+
5
+ == DESCRIPTION:
1
6
  Sequence provides a unified api for access to sequential data types, like
2
7
  Strings, Arrays, Files, IOs, and Enumerations. Each sequence encapsulates
3
8
  some data and a current position within it. Some operations apply to data
@@ -24,6 +29,34 @@ Array-like cursors contain objects.
24
29
 
25
30
 
26
31
 
32
+ == KNOWN PROBLEMS:
33
+ Buffered does not work at all
34
+ Shifting's modify methods don't work reliably
35
+ No unit tests at all for array-like sequences
36
+ (tho Reg's unit test does test OfArray at least somewhat...)
37
+
38
+ == SYNOPSIS:
39
+
40
+ require 'rubygems'
41
+ require 'sequence'
42
+ require 'sequence/indexed'
43
+
44
+ seq="........some arbitrary text............".to_sequence
45
+ seq.pos # => 0
46
+ seq.scan_until /some .* text/ # => "........some arbitrary text"
47
+ seq.pos # => 27
48
+ #and much much more
49
+
50
+ == INSTALL:
51
+
52
+ * Just run: gem install sequence
53
+
54
+ == LICENSE:
55
+
56
+ Copyright (C) 2006,2008 Caleb Clausen
57
+ Distributed under the terms of Ruby's license. (See the file COPYING.)
58
+
59
+ == USING:
27
60
 
28
61
  Stuff that's unworking at the moment is marked with **
29
62
 
@@ -289,7 +322,7 @@ derived sequences:
289
322
  Circular #loops base sequence data over and over
290
323
  SubSeq #extracts a contiguous subset of base sequence
291
324
  #data into a new seq
292
- List (**) #logically concatenates its base sequences
325
+ List #logically concatenates its base sequences
293
326
  Overlay (**) #intercepts writes to the base seq
294
327
  Position #an independant position within the base seq
295
328
 
@@ -308,13 +341,5 @@ Future:
308
341
  IndexedList (**)
309
342
 
310
343
 
311
- known problems:
312
- Some unit tests fail
313
- Buffered does not work at all
314
- Shifting's modify methods don't work reliably
315
- Some write operations failing for List
316
- No unit tests at all for array-like sequences
317
- (tho Reg's unit test does test OfArray at least somewhat...)
318
344
 
319
- Copyright (C) 2006 Caleb Clausen
320
- Distributed under the terms of Ruby's license.
345
+
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2006 Caleb Clausen
1
+ # Copyright (C) 2006,2008 Caleb Clausen
2
2
  # Distributed under the terms of Ruby's license.
3
3
  # = sequence.rb - external iterators with capabilities like a text editor cursor
4
4
  # $Id$
@@ -104,11 +104,13 @@ class Sequence
104
104
 
105
105
  #read data behind the current position, leaving position unchanged
106
106
  def readbehind(len)
107
+ len>pos and len=pos
107
108
  read move( -len)
108
109
  end
109
110
 
110
111
  #read data behind the current position, leaving position just before the data read.
111
112
  def readback(len)
113
+ len>pos and len=pos
112
114
  readahead move( -len )
113
115
  end
114
116
 
@@ -158,7 +160,7 @@ class Sequence
158
160
  #$ and \Z match at the end of the sequence.
159
161
  #when scanning backward, ^ and \A match at the beginning of sequence and $ and
160
162
  #\Z match at the current position.
161
- #^ and $ still match at beginning and end of lines, as usual.
163
+ #^ and $ still match at begining and end of lines, as usual.
162
164
 
163
165
  #when scanning or matching backwards, ^ has some special problems:
164
166
  # these won't work....
@@ -351,7 +353,9 @@ class Sequence
351
353
  # The (positive) amount actually moved is returned (<+len+ if reached beginning/end).
352
354
  def move(len)
353
355
  oldpos=pos
354
- goto oldpos+len
356
+ newpos=oldpos+len
357
+ newpos<0 and newpos=0
358
+ goto newpos
355
359
  return (pos-oldpos).abs
356
360
  end
357
361
  # move to end of the remaining elements.
@@ -1,5 +1,5 @@
1
1
  # $Id$
2
- # Copyright (C) 2006 Caleb Clausen
2
+ # Copyright (C) 2006,2008 Caleb Clausen
3
3
  # Distributed under the terms of Ruby's license.
4
4
 
5
5
  require 'sequence'
@@ -119,50 +119,70 @@ class OfString < Indexed
119
119
 
120
120
  include StringLike
121
121
  def scan(pat)
122
- holding?{case pat
123
- when Regexp:
122
+ case pat
123
+ when Regexp
124
124
  if (m=match pat,true)
125
125
  @pos= m.end(0)
126
- m.to_s
126
+ return m.to_s
127
127
  end
128
- when Integer: (res=@data[@pos])==pat and @pos+=1 and res
129
- when String: @data[@pos...@pos+=pat.size]==pat and pat
130
- end}
128
+ when Integer
129
+ res=@data[@pos]
130
+ if res==pat
131
+ @pos+=1
132
+ return res.chr
133
+ end
134
+ when String
135
+ if @data[@pos...@pos+pat.size]==pat
136
+ @pos+=pat.size
137
+ return pat
138
+ end
139
+ end
131
140
  end
132
141
 
133
142
  def scanback(pat)
134
- holding?{case pat
135
- when Regexp:
136
- if m=matchback(pat,true)
143
+ case pat
144
+ when Regexp
145
+ if (m=matchback pat,true)
137
146
  @pos= m.begin(0)
138
- m.to_s
147
+ return m.to_s
148
+ end
149
+ when Integer
150
+ res=@data[@pos]
151
+ if res==pat
152
+ @pos-=1
153
+ return res.chr
139
154
  end
140
- when Integer: @data[@pos-=1]==pat and pat.chr
141
- when String: @data[@pos-=pat.size,pat.size]==pat and pat
142
- end}
155
+ when String
156
+ if @data[@pos...@pos-pat.size]==pat
157
+ @pos-=pat.size
158
+ return pat
159
+ end
160
+ end
143
161
  end
144
162
 
145
163
  def scan_until(pat)
146
164
  if Regexp===pat
147
- return(if (m=match pat,false)
165
+ if (m=match pat,false)
148
166
  @pos= m.end(0)
149
167
  m.pre_match+m.to_s
150
- end)
168
+ end
169
+ else
170
+ i=@data.index(pat,pos) and
171
+ @data[@pos...@pos=i]
151
172
  end
152
- i=@data.index(pat,pos) or return
153
- @data[@pos...@pos=i]
154
173
  end
155
174
 
156
175
  def scanback_until(pat)
157
176
  if Regexp===pat
158
- return(if (m=matchback pat,true)
177
+ if (m=matchback pat,true)
159
178
  @pos= m.begin(0)
160
179
  m.to_s+m.post_match
161
- end)
180
+ end
181
+ else
182
+ i=@data.rindex(pat,pos) or return
183
+ oldpos=@pos
184
+ @data[@pos=i...oldpos]
162
185
  end
163
- i=@data.rindex(pat,pos) or return
164
- oldpos=@pos
165
- @data[@pos=i...oldpos]
166
186
  end
167
187
 
168
188
  def match pat,anchored=true,len=size
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2006 Caleb Clausen
1
+ # Copyright (C) 2006,2008 Caleb Clausen
2
2
  # Distributed under the terms of Ruby's license.
3
3
  class Sequence
4
4
  class Circular < Sequence; end
@@ -9,7 +9,6 @@ class Sequence
9
9
  @current_idx=0
10
10
  @pos=0
11
11
  @start_pos=[0]
12
- _rebuild_idxs
13
12
 
14
13
  @list=@list.inject([]){|li,seq|
15
14
  Circular===seq and raise 'no circular seqs in lists'
@@ -17,9 +16,12 @@ class Sequence
17
16
  if List===seq then li+seq.list else li<<seq end
18
17
  }
19
18
  @list.each{|seq| seq.on_change_notify(self) }
19
+ _rebuild_idxs
20
20
 
21
21
  extend seqs.first.like
22
22
  end
23
+
24
+ attr :list
23
25
 
24
26
  def change_notification(cu,first,oldsize,newsize)
25
27
  idx=@list.each_with_index{|item,i| cu.equal? item and break i}
@@ -176,12 +178,14 @@ class Sequence
176
178
  def subseq(*)
177
179
  result=super
178
180
  result.instance_eval(& Overlaid)
181
+ return result
179
182
  end
180
183
  end
181
184
  end
182
185
 
183
186
  def modify(*args)
184
187
  result=repldata=args.pop
188
+
185
189
 
186
190
  repllen=repldata.size
187
191
  # unless repldata.empty?
@@ -194,9 +198,15 @@ class Sequence
194
198
  replseqs=[repldata]
195
199
 
196
200
  first,len,only1=_parse_slice_args(*args)
197
-
201
+ if len.zero? and repllen.zero?
202
+ notify_change self,first,len,repllen
203
+ return result
204
+ end
205
+
198
206
  f_idx=first.zero?? 0 : _lookup_idx(first-1)
199
- l_idx=_lookup_idx(first+len)
207
+ last_item_i=first+len-1
208
+ last_item_i=0 if last_item_i<0
209
+ l_idx=_lookup_idx(last_item_i)
200
210
 
201
211
  assert f_idx <= l_idx
202
212
 
@@ -204,11 +214,11 @@ class Sequence
204
214
  fragrest_l=first+len-@start_pos[l_idx]
205
215
 
206
216
  #@list[i] can be nil here... maybe because i==@list.size?
207
- assert fragrest_f < @list[i].size
208
- assert fragrest_l <= @list[l_idx].size unless l_idx == @list.size and fragrest_l.zero?
217
+ assert fragrest_f <= @list[i].size
218
+ # assert fragrest_l <= @list[l_idx].size unless l_idx == @list.size and fragrest_l.zero?
209
219
 
210
220
  #merge replacement data with adjacent seq(s) if also overlaid
211
- if fragrest_f.nonzero?
221
+ if fragrest_f.nonzero? #if inserted chunklet won't be empty
212
222
  replseqs.unshift( item=@list[i].subseq(0...fragrest_f) )
213
223
  if item.respond_to? :overlaid?
214
224
  repldata.prepend item.all_data
@@ -216,7 +226,7 @@ class Sequence
216
226
  end
217
227
  end
218
228
 
219
- if fragrest_l.nonzero?
229
+ if fragrest_l < @list[l_idx].size #if inserted chunklet won't be empty
220
230
  replseqs.push( item=@list[l_idx].subseq(fragrest_l..-1) )
221
231
  if item.respond_to? :overlaid?
222
232
  repldata.append item.all_data
@@ -225,7 +235,7 @@ class Sequence
225
235
  end
226
236
 
227
237
 
228
- replseqs.delete_if{|cu| cu.empty? }
238
+ replseqs.delete_if{|cu| !cu or cu.empty? }
229
239
 
230
240
  #now remove those elements in between and
231
241
  #insert replacement data at the same point
@@ -234,7 +244,7 @@ class Sequence
234
244
  assert f_idx < @list.size
235
245
  assert l_idx <= @list.size
236
246
  assert f_idx <= l_idx
237
- @list[i...l_idx]=replseqs
247
+ @list[i..l_idx]=replseqs
238
248
  #base=f_idx.zero?? 0 : @start_idx[f_idx-1]
239
249
  #@start_idx[f_idx...l_idx]=[base+repldata.size]
240
250
 
@@ -289,4 +299,4 @@ class Sequence
289
299
  # result
290
300
  # end
291
301
  # end
292
- end
302
+ end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2006 Caleb Clausen
1
+ # Copyright (C) 2006,2008 Caleb Clausen
2
2
  # Distributed under the terms of Ruby's license.
3
3
  require 'sequence/subseq'
4
4
 
@@ -54,7 +54,7 @@ class Sequence
54
54
  self.pos-=m.post_match.length+1
55
55
  #'self.' shouldn't be needed... but is
56
56
 
57
- blocks.push m.pre_match if m.pre_match.length>0
57
+ blocks<<m.pre_match if m.pre_match.length>0
58
58
  break
59
59
  end
60
60
  blocks<<block
@@ -217,7 +217,8 @@ class Sequence
217
217
  groups=matchdata.to_a
218
218
  begins=[]
219
219
  ends=[]
220
- (0...matchdata.length).each{|i|
220
+ matchdata.to_a.each_with_index{|substr,i|
221
+ next unless substr
221
222
  begins<<matchdata.begin(i)+pos_adjust
222
223
  ends<<matchdata.end(i)+pos_adjust
223
224
  }
@@ -1,5 +1,5 @@
1
- # Copyright (C) 2006 Caleb Clausen
1
+ # Copyright (C) 2006,2008 Caleb Clausen
2
2
  # Distributed under the terms of Ruby's license.
3
3
  class Sequence
4
- VERSION='0.1.0'
4
+ VERSION='0.2.0'
5
5
  end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2006 Caleb Clausen
1
+ # Copyright (C) 2006,2008 Caleb Clausen
2
2
  # Distributed under the terms of Ruby's license.
3
3
  $VERBOSE=1
4
4
  require 'test/unit'
@@ -210,11 +210,19 @@ $Debug=true
210
210
 
211
211
  class ListRandomized < Indexed
212
212
  def a_seq
213
+ reuse=defined? @saved_lens
214
+ @saved_lens||=[]
215
+ saved_lens=@saved_lens.dup
213
216
  maxchunk=DATA.size/5
214
217
  idx=0
215
218
  list=[]
216
219
  begin
217
- len=rand(maxchunk)+1
220
+ if reuse
221
+ len=saved_lens.shift
222
+ else
223
+ len=rand(maxchunk)+1
224
+ @saved_lens<<len
225
+ end
218
226
  list<<DATA[idx,len].to_sequence
219
227
  idx+=len
220
228
 
@@ -241,12 +249,11 @@ $Debug=true
241
249
  #need to disable tests that move cursor position back or modify data
242
250
  undef_method(*(MOVEPOSMETHODS+MODIFYMETHODS))
243
251
  end
244
-
245
252
 
246
253
  module SmallScanBuffered
247
254
  SequenceTests.constants.each{|k|
248
255
  xk= SequenceTests.const_get(k)
249
- next unless (xk.is_a? Class and xk<=Indexed)
256
+ next unless (xk.is_a? Class and xk<=::SequenceTests::Indexed)
250
257
  const_set k, xk=Class.new(xk)
251
258
  xk.instance_eval do
252
259
  define_method :a_seq do
@@ -257,6 +264,54 @@ $Debug=true
257
264
  end
258
265
  }
259
266
  end
267
+
268
+ module ListWrapped
269
+ SequenceTests.constants.each{|k|
270
+ xk= SequenceTests.const_get(k)
271
+ next unless (xk.is_a? Class and xk<=::SequenceTests::Indexed)
272
+ next if /Circular/===xk.name
273
+ const_set k, xk=Class.new(xk)
274
+ xk.instance_eval do
275
+ define_method :a_seq do
276
+ result=Sequence::List.new([wrappee=super])
277
+ result.pos=wrappee.pos
278
+ return result
279
+ end
280
+ end
281
+ }
282
+ end
283
+
284
+
285
+ module ListWrappedAndChunkReified
286
+ SequenceTests.constants.each{|k|
287
+ xk= SequenceTests.const_get(k)
288
+ next unless (xk.is_a? Class and xk<=::SequenceTests::Indexed)
289
+ next if /Circular/===xk.name
290
+ const_set k, xk=Class.new(xk)
291
+ xk.instance_eval do
292
+ define_method :a_seq do
293
+ result=Sequence::List.new([wrappee=super])
294
+ chunk=rand_pos_pair
295
+ chunk=chunk.first..chunk.last
296
+ result[chunk]=result[chunk]
297
+ result.pos=wrappee.pos
298
+ return result
299
+ end
300
+ end
301
+ }
302
+ class ListMaxxed
303
+ undef test__lookup_idx
304
+ end
305
+ class List
306
+ undef test__lookup_idx
307
+ end
308
+ class IO
309
+ def test_size; end #why can't i just undef it? dunno...
310
+ end
311
+
312
+ end
313
+
314
+
260
315
 
261
316
  =begin disabled for now; too many failures
262
317
  module Buffered
@@ -272,7 +327,6 @@ $Debug=true
272
327
  end
273
328
  }
274
329
  end
275
- =end
276
330
 
277
331
  module Shifting
278
332
  SequenceTests.constants.each{|k|
@@ -287,6 +341,7 @@ $Debug=true
287
341
  end
288
342
  }
289
343
  end
344
+ =end
290
345
 
291
346
  class Indexed
292
347
  RANDOMIZED_METHODS=[:test_slice,:test_insert,:test_delete,:test_modify]
@@ -617,7 +672,7 @@ $Debug=true
617
672
  verify_scan_methods( /th(is|at)/,OFFSET,"that",
618
673
  [%W[that at],[OFFSET,OFFSET+2],
619
674
  "", " tough guy talk\ndon't make you a dog", false] )
620
- =begin
675
+ #=begin
621
676
  _=(seq =a_seq).scan /th(is|at)/
622
677
  assert_equal "that", _
623
678
  verify_aftermatch_status(
@@ -645,13 +700,13 @@ $Debug=true
645
700
  seq,12,%W[that at],[OFFSET,OFFSET+2],
646
701
  "", " tough guy talk\ndon't make you a dog", false
647
702
  )
648
- =end
703
+ #=end
649
704
 
650
705
  verify_scan_until_methods( /[mb]ake/, OFFSET, "that tough guy talk\ndon't ", "make",
651
706
  [%W[make],[OFFSET+26],
652
707
  "that tough guy talk\ndon't "," you a dog", false] )
653
708
 
654
- =begin
709
+ #=begin
655
710
  _=(seq =a_seq).scan_until /[mb]ake/
656
711
  assert_equal "that tough guy talk\ndon't make", _
657
712
  verify_aftermatch_status(
@@ -679,7 +734,7 @@ $Debug=true
679
734
  seq,OFFSET,%W[make],[OFFSET+26],
680
735
  "that tough guy talk\ndon't "," you a dog", false
681
736
  )
682
- =end
737
+ #=end
683
738
 
684
739
  #ok, and now with anchors
685
740
  verify_failmatch_status :scan_until, /[cr]at\Z/
@@ -702,7 +757,7 @@ $Debug=true
702
757
  verify_scan_until_methods( /(d([^d]+))\Z/,OFFSET,"", "that tough guy talk\ndon't make you a dog",
703
758
  [%W[dog dog og],[OFFSET+37,OFFSET+37,OFFSET+38],"that tough guy talk\ndon't make you a ", "", true] )
704
759
 
705
- =begin
760
+ #=begin
706
761
  _=(seq =a_seq).scan_until /(d([^d]+))\Z/
707
762
  assert_equal "that tough guy talk\ndon't make you a dog", _
708
763
  verify_aftermatch_status(
@@ -730,7 +785,7 @@ $Debug=true
730
785
  seq,52,%W[dog dog og],[49,49,50],
731
786
  "that tough guy talk\ndon't make you a ","", true
732
787
  )
733
- =end
788
+ #=end
734
789
  end
735
790
 
736
791
  #implicitly anchored with anchors
@@ -755,7 +810,7 @@ $Debug=true
755
810
  [%W[dog dog og],[OFFSET+37,OFFSET+37,OFFSET+38],"", "", true] )
756
811
 
757
812
 
758
- =begin
813
+ #=begin
759
814
  _=(seq =a_seq)
760
815
  seq.pos=49 #at 'dog'
761
816
  _= seq.scan /(d([^d]+))\Z/
@@ -787,7 +842,7 @@ $Debug=true
787
842
  verify_aftermatch_status(
788
843
  seq,52,%W[dog dog og],[49,49,50],"","", true
789
844
  )
790
- =end
845
+ #=end
791
846
  end
792
847
  #$ as anchor
793
848
  verify_failmatch_status :scan_until, /[cr]at$/
@@ -807,7 +862,7 @@ $Debug=true
807
862
  [%W[dog dog og],[OFFSET+37,OFFSET+37,OFFSET+38],"that tough guy talk\ndon't make you a ", "", true] )
808
863
 
809
864
 
810
- =begin
865
+ #=begin
811
866
  _=(seq =a_seq).scan_until /(d([^d]+))$/
812
867
  assert_equal "that tough guy talk\ndon't make you a dog", _
813
868
  verify_aftermatch_status(
@@ -835,12 +890,12 @@ $Debug=true
835
890
  seq,52,%W[dog dog og],[49,49,50],
836
891
  "that tough guy talk\ndon't make you a ","", true
837
892
  )
838
- =end
893
+ #=end
839
894
  end
840
895
 
841
896
  verify_scan_until_methods( /(st|[bt])alk$/,OFFSET,"", "that tough guy talk",
842
897
  [%W[talk t],[OFFSET+15,OFFSET+15],"that tough guy ","\ndon't make you a dog", false] )
843
- =begin
898
+ #=begin
844
899
  _=(seq =a_seq).scan_until /(st|[bt])alk$/
845
900
  assert_equal "that tough guy talk", _
846
901
  verify_aftermatch_status(seq,31,%W[talk t],[27,27],"that tough guy ","\ndon't make you a dog",false)
@@ -856,7 +911,7 @@ $Debug=true
856
911
  _=(seq =a_seq).skip_until /(st|[bt])alk$/
857
912
  assert_equal 19, _
858
913
  verify_aftermatch_status(seq,31,%W[talk t],[27,27],"that tough guy ","\ndon't make you a dog",false)
859
- =end
914
+ #=end
860
915
  verify_failmatch_status :scan_until, /(bob|talk\Z|(dou(gh)?))/
861
916
  verify_failmatch_status :check_until, /(bob|talk\Z|(dou(gh)?))/
862
917
  verify_failmatch_status :skip_until, /(bob|talk\Z|(dou(gh)?))/
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.0
2
+ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: sequence
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2006-10-05 00:00:00 -07:00
6
+ version: 0.2.0
7
+ date: 2008-08-29 00:00:00 +01:00
8
8
  summary: A single api for reading and writing sequential data types.
9
9
  require_paths:
10
10
  - lib
11
- - test
12
11
  email: sequence-owner @at@ inforadical .dot. net
13
12
  homepage: http://sequence.rubyforge.org/
14
13
  rubyforge_project: sequence
@@ -68,10 +67,12 @@ files:
68
67
  - GPL
69
68
  test_files:
70
69
  - test/test_all.rb
71
- rdoc_options: []
72
-
73
- extra_rdoc_files: []
74
-
70
+ rdoc_options:
71
+ - --main
72
+ - README.txt
73
+ extra_rdoc_files:
74
+ - Manifest.txt
75
+ - README.txt
75
76
  executables: []
76
77
 
77
78
  extensions: []
@@ -86,5 +87,5 @@ dependencies:
86
87
  requirements:
87
88
  - - ">="
88
89
  - !ruby/object:Gem::Version
89
- version: 1.0.5
90
+ version: 1.5.1
90
91
  version: