sequence 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: