sequence 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +58 -0
- data/GPL +340 -0
- data/Manifest.txt +36 -0
- data/README.txt +320 -0
- data/Rakefile +32 -0
- data/lib/assert.rb +16 -0
- data/lib/sequence/arraylike.rb +57 -0
- data/lib/sequence/buffered.rb +188 -0
- data/lib/sequence/circular.rb +272 -0
- data/lib/sequence/enum.rb +260 -0
- data/lib/sequence/file.rb +172 -0
- data/lib/sequence/functional.rb +152 -0
- data/lib/sequence/generator.rb +290 -0
- data/lib/sequence/indexed.rb +234 -0
- data/lib/sequence/io.rb +102 -0
- data/lib/sequence/list.rb +292 -0
- data/lib/sequence/ofhash.rb +38 -0
- data/lib/sequence/ofobjectivars.rb +29 -0
- data/lib/sequence/ofobjectmethods.rb +87 -0
- data/lib/sequence/position.rb +100 -0
- data/lib/sequence/reversed.rb +180 -0
- data/lib/sequence/shifting.rb +190 -0
- data/lib/sequence/singleitem.rb +50 -0
- data/lib/sequence/stringlike.rb +482 -0
- data/lib/sequence/subseq.rb +90 -0
- data/lib/sequence/usedata.rb +35 -0
- data/lib/sequence/version.rb +5 -0
- data/lib/sequence.rb +721 -0
- data/lib/weakrefset.rb +254 -0
- data/test/test.rb +609 -0
- data/test/test_all.rb +6 -0
- data/test/test_changes.rb +44 -0
- data/test/test_circulars.rb +89 -0
- data/test/test_rexscan.rb +899 -0
- data/test/test_seqrex.rb +204 -0
- data/test/test_sequences.rb +106 -0
- metadata +90 -0
data/lib/sequence/io.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# Copyright (C) 2006 Caleb Clausen
|
2
|
+
# Distributed under the terms of Ruby's license.
|
3
|
+
require 'sequence/stringlike'
|
4
|
+
require 'fcntl'
|
5
|
+
|
6
|
+
class Sequence
|
7
|
+
|
8
|
+
#external iterator over data in an general IO object (a pipe, console, socket, serial port, or the like).
|
9
|
+
#For Files, please use Sequence::File instead, as it is more capable.
|
10
|
+
#This Sequence class can only go forward, and can only read, it cannot write to the data stream.
|
11
|
+
#Thus many of Sequence's usual methods will not work with this class.
|
12
|
+
#At the moment, this even includes #scan and friends, tho I will try to make those work somewhat.
|
13
|
+
#Also note that this is one of the few Sequence classes that might return less that the amount asked
|
14
|
+
#for in a read, even if not at the end of file.
|
15
|
+
#Due to use of nonblocking io, this might not work on windows.
|
16
|
+
#The value of #size in this sequence continually increases over its lifetime, and it isn't possible to
|
17
|
+
#know the final value beforehand. Likewise, #eof? may return false even tho it's destined to return
|
18
|
+
#true at the same position. This is because the 'other end' may not have closed the IO, even if there's
|
19
|
+
#no more data to send.
|
20
|
+
#
|
21
|
+
#if you need to be able to scan forward and back, consider wrapping the IO in a Buffered or Shifting
|
22
|
+
#Sequence.
|
23
|
+
class IO < Sequence
|
24
|
+
include StringLike
|
25
|
+
def initialize(io)
|
26
|
+
@io=io
|
27
|
+
@pos=0
|
28
|
+
|
29
|
+
@io.fcntl(::Fcntl::F_SETFL, ::Fcntl::O_NONBLOCK)
|
30
|
+
#I gather this won't work on windows....
|
31
|
+
|
32
|
+
@fragment=''
|
33
|
+
end
|
34
|
+
|
35
|
+
attr :pos
|
36
|
+
|
37
|
+
undef pos=, _pos=, position, position?, holding, holding?, holding!, readback, readback1
|
38
|
+
undef readahead, readbehind, readahead1, readbehind1, write#, write1
|
39
|
+
undef goto, move, move!, subseq, reversed, <=>, +, -, succ, pred, begin, end
|
40
|
+
undef begin!, end!, first, last, slice, [], modify, []=
|
41
|
+
|
42
|
+
|
43
|
+
def size
|
44
|
+
#refill fragment if needed
|
45
|
+
@fragment=@io.sysread(4096) if @fragment.empty?
|
46
|
+
|
47
|
+
return @pos+@fragment.size
|
48
|
+
end
|
49
|
+
|
50
|
+
def more_data?
|
51
|
+
#refill fragment if needed
|
52
|
+
@fragment=@io.sysread(4096) if @fragment.empty?
|
53
|
+
|
54
|
+
return !eof
|
55
|
+
end
|
56
|
+
|
57
|
+
def eof?;
|
58
|
+
@fragment.empty? and #need to be at buffer end
|
59
|
+
@io.eof?
|
60
|
+
end
|
61
|
+
|
62
|
+
def read len
|
63
|
+
if len<= @fragment.size
|
64
|
+
@pos+=len
|
65
|
+
@fragment.slice! 0,len
|
66
|
+
else
|
67
|
+
result=@fragment
|
68
|
+
len-=@fragment.size
|
69
|
+
|
70
|
+
readlen=len
|
71
|
+
rem=len%4096
|
72
|
+
rem.nonzero? and readlen+=4096-rem
|
73
|
+
|
74
|
+
@fragment=@io.sysread(readlen)
|
75
|
+
result+=@fragment.slice!(0,len)
|
76
|
+
@pos+=result.size
|
77
|
+
result
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def match pat
|
82
|
+
@fragment.size>=scanbuflen or @fragment<<@io.sysread(4096)
|
83
|
+
result=@fragment.match(pat)
|
84
|
+
result if result.begin(0).zero?
|
85
|
+
end
|
86
|
+
|
87
|
+
def _pos=newpos
|
88
|
+
newpos<pos and raise ArgumentError
|
89
|
+
if newpos<=@pos+@fragment.size
|
90
|
+
len=newpos-@pos
|
91
|
+
@fragment.slice!(0,len)
|
92
|
+
@pos=newpos
|
93
|
+
else
|
94
|
+
len=newpos-(@pos+@fragment.size)
|
95
|
+
len > 10*4096 and raise ArgumentError
|
96
|
+
@fragment=''
|
97
|
+
tossit=@io.sysread(len)
|
98
|
+
@pos=newpos-(len-tossit.size)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,292 @@
|
|
1
|
+
# Copyright (C) 2006 Caleb Clausen
|
2
|
+
# Distributed under the terms of Ruby's license.
|
3
|
+
class Sequence
|
4
|
+
class Circular < Sequence; end
|
5
|
+
class List < Sequence
|
6
|
+
def initialize(seqs)
|
7
|
+
seqs.empty? and raise ArgumentError
|
8
|
+
@list=seqs
|
9
|
+
@current_idx=0
|
10
|
+
@pos=0
|
11
|
+
@start_pos=[0]
|
12
|
+
_rebuild_idxs
|
13
|
+
|
14
|
+
@list=@list.inject([]){|li,seq|
|
15
|
+
Circular===seq and raise 'no circular seqs in lists'
|
16
|
+
Sequence===seq or raise ArgumentError
|
17
|
+
if List===seq then li+seq.list else li<<seq end
|
18
|
+
}
|
19
|
+
@list.each{|seq| seq.on_change_notify(self) }
|
20
|
+
|
21
|
+
extend seqs.first.like
|
22
|
+
end
|
23
|
+
|
24
|
+
def change_notification(cu,first,oldsize,newsize)
|
25
|
+
idx=@list.each_with_index{|item,i| cu.equal? item and break i}
|
26
|
+
diff=newsize-oldsize
|
27
|
+
(idx+1...@start_pos.size).each{|i|
|
28
|
+
@start_pos[i]+=diff
|
29
|
+
}
|
30
|
+
@pos=_adjust_pos_on_change(@pos, first,oldsize,newsize)
|
31
|
+
@current_idx=_lookup_idx @pos
|
32
|
+
notify_change(self,@start_pos[idx]+first,oldsize,newsize)
|
33
|
+
end
|
34
|
+
|
35
|
+
def _rebuild_idxs(start=1)
|
36
|
+
seed=@start_pos[0...start]
|
37
|
+
seed.empty? and seed=[0]
|
38
|
+
start==0 and start=1
|
39
|
+
@start_pos=(start..@list.size).inject(seed){|arr,i|
|
40
|
+
arr<<arr.last+@list[i-1].size
|
41
|
+
}
|
42
|
+
#@start_pos.pop
|
43
|
+
|
44
|
+
#maybe update @current_idx too?
|
45
|
+
end
|
46
|
+
=begin
|
47
|
+
def _lookup_idx(pos)
|
48
|
+
low=0;high=@start_pos.size-1
|
49
|
+
while(high>low+1)
|
50
|
+
mid=(low+high)/2
|
51
|
+
this_pos,next_pos=*@start_pos[mid,2]
|
52
|
+
if pos<this_pos
|
53
|
+
high=mid # - 1 ??
|
54
|
+
elsif pos<next_pos
|
55
|
+
return mid
|
56
|
+
elsif pos==next_pos
|
57
|
+
return mid+1
|
58
|
+
else
|
59
|
+
low=mid + 1
|
60
|
+
end
|
61
|
+
end
|
62
|
+
low
|
63
|
+
end
|
64
|
+
=end
|
65
|
+
def _lookup_idx(pos)
|
66
|
+
pos==size and return @list.size-1
|
67
|
+
assert((0...size)===pos)
|
68
|
+
assert @start_pos.size==@list.size+1
|
69
|
+
low=0;high=@start_pos.size-1
|
70
|
+
assert @start_pos[low]<=pos
|
71
|
+
assert @start_pos[high]>pos
|
72
|
+
while(high>low+1)
|
73
|
+
assert @start_pos[low]<=pos
|
74
|
+
assert @start_pos[high]>pos
|
75
|
+
mid=(low+high)/2
|
76
|
+
case pos<=>@start_pos[mid]
|
77
|
+
when -1: high=mid
|
78
|
+
when 0: break low=mid
|
79
|
+
when 1: low=mid
|
80
|
+
end
|
81
|
+
end
|
82
|
+
assert @start_pos[low]<=pos
|
83
|
+
assert @start_pos[low+1]>pos
|
84
|
+
low
|
85
|
+
end
|
86
|
+
|
87
|
+
def readahead(len)
|
88
|
+
idx=_lookup_idx(pos)
|
89
|
+
result=@list[idx][pos-@start_pos[idx],len] || new_data
|
90
|
+
len-=result.size
|
91
|
+
assert len>=0
|
92
|
+
i=nil
|
93
|
+
(idx+1).upto(@list.size-1){|i|
|
94
|
+
break(result+=@list[i][0,len]) if len<@list[i].size
|
95
|
+
result+=@list[i].all_data
|
96
|
+
len-=@list[i].size
|
97
|
+
}
|
98
|
+
result
|
99
|
+
end
|
100
|
+
|
101
|
+
def read(len)
|
102
|
+
result=readahead(len)
|
103
|
+
move result.size
|
104
|
+
result
|
105
|
+
end
|
106
|
+
|
107
|
+
def holding
|
108
|
+
oldpos,oldidx=@pos,@current_idx
|
109
|
+
begin
|
110
|
+
yield self
|
111
|
+
ensure
|
112
|
+
@pos,@current_idx=oldpos,oldidx
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
#like #holding, but position is reset only if block returns false or nil (or
|
117
|
+
#raises an exception).
|
118
|
+
def holding?
|
119
|
+
oldpos,oldidx=@pos,@current_idx
|
120
|
+
begin
|
121
|
+
result=yield self
|
122
|
+
ensure
|
123
|
+
(@pos,@current_idx=oldpos,oldidx) unless result
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
#like #holding, but block is instance_eval'd in the seq.
|
128
|
+
def holding! &block
|
129
|
+
oldpos,oldidx=@pos,@current_idx
|
130
|
+
begin
|
131
|
+
instance_eval self, &block
|
132
|
+
ensure
|
133
|
+
@pos,@current_idx=oldpos,oldidx
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
attr :pos
|
138
|
+
|
139
|
+
def _pos=pos
|
140
|
+
@pos=pos
|
141
|
+
assert((0..size)===pos)
|
142
|
+
@current_idx= _lookup_idx(pos)
|
143
|
+
end
|
144
|
+
|
145
|
+
def size
|
146
|
+
@start_pos.last
|
147
|
+
end
|
148
|
+
|
149
|
+
def eof?
|
150
|
+
@pos>=size
|
151
|
+
end
|
152
|
+
|
153
|
+
def + other
|
154
|
+
return super unless ::Sequence===other
|
155
|
+
return List[*@list+[other]]
|
156
|
+
end
|
157
|
+
|
158
|
+
def _fragment_discard_after(pos)
|
159
|
+
idx=_lookup_idx(pos)
|
160
|
+
pos-=@start_pos[idx]
|
161
|
+
@list[idx]=@list[idx].subseq(0...pos)
|
162
|
+
return idx
|
163
|
+
end
|
164
|
+
|
165
|
+
def _fragment_discard_before(pos)
|
166
|
+
idx=_lookup_idx(pos)
|
167
|
+
pos-=@start_pos[idx]
|
168
|
+
@list[idx]=@list[idx].subseq(pos..-1)
|
169
|
+
return idx
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
Overlaid =proc do
|
174
|
+
class<<self
|
175
|
+
def overlaid?; true end
|
176
|
+
def subseq(*)
|
177
|
+
result=super
|
178
|
+
result.instance_eval(& Overlaid)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def modify(*args)
|
184
|
+
result=repldata=args.pop
|
185
|
+
|
186
|
+
repllen=repldata.size
|
187
|
+
# unless repldata.empty?
|
188
|
+
repldata=repldata.dup.to_sequence
|
189
|
+
|
190
|
+
|
191
|
+
#mark replacement data as overlaid
|
192
|
+
repldata.instance_eval(&Overlaid)
|
193
|
+
# end
|
194
|
+
replseqs=[repldata]
|
195
|
+
|
196
|
+
first,len,only1=_parse_slice_args(*args)
|
197
|
+
|
198
|
+
f_idx=first.zero?? 0 : _lookup_idx(first-1)
|
199
|
+
l_idx=_lookup_idx(first+len)
|
200
|
+
|
201
|
+
assert f_idx <= l_idx
|
202
|
+
|
203
|
+
fragrest_f=first-@start_pos[i=_lookup_idx(first)]
|
204
|
+
fragrest_l=first+len-@start_pos[l_idx]
|
205
|
+
|
206
|
+
#@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?
|
209
|
+
|
210
|
+
#merge replacement data with adjacent seq(s) if also overlaid
|
211
|
+
if fragrest_f.nonzero?
|
212
|
+
replseqs.unshift( item=@list[i].subseq(0...fragrest_f) )
|
213
|
+
if item.respond_to? :overlaid?
|
214
|
+
repldata.prepend item.all_data
|
215
|
+
replseqs.shift
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
if fragrest_l.nonzero?
|
220
|
+
replseqs.push( item=@list[l_idx].subseq(fragrest_l..-1) )
|
221
|
+
if item.respond_to? :overlaid?
|
222
|
+
repldata.append item.all_data
|
223
|
+
replseqs.pop
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
replseqs.delete_if{|cu| cu.empty? }
|
229
|
+
|
230
|
+
#now remove those elements in between and
|
231
|
+
#insert replacement data at the same point
|
232
|
+
assert f_idx >= 0
|
233
|
+
assert l_idx >= 0
|
234
|
+
assert f_idx < @list.size
|
235
|
+
assert l_idx <= @list.size
|
236
|
+
assert f_idx <= l_idx
|
237
|
+
@list[i...l_idx]=replseqs
|
238
|
+
#base=f_idx.zero?? 0 : @start_idx[f_idx-1]
|
239
|
+
#@start_idx[f_idx...l_idx]=[base+repldata.size]
|
240
|
+
|
241
|
+
|
242
|
+
|
243
|
+
|
244
|
+
#rebuild indeces after altered part
|
245
|
+
_rebuild_idxs(f_idx)
|
246
|
+
@pos=_adjust_pos_on_change(@pos, first,len,result.size)
|
247
|
+
@current_idx=_lookup_idx @pos
|
248
|
+
|
249
|
+
notify_change(self,first,len,repllen)
|
250
|
+
result
|
251
|
+
end
|
252
|
+
|
253
|
+
|
254
|
+
def append(data)
|
255
|
+
if @list.last.overlaid?
|
256
|
+
@list.last.append data
|
257
|
+
return self
|
258
|
+
end
|
259
|
+
data=data.dup.to_sequence
|
260
|
+
data.instance_eval(&Overlaid)
|
261
|
+
@list<<data
|
262
|
+
@start_pos<<@start_pos.last+data.size
|
263
|
+
notify_change(self,@start_pos[-2], 0, data.size)
|
264
|
+
self
|
265
|
+
end
|
266
|
+
def prepend(data)
|
267
|
+
if @list.first.overlaid?
|
268
|
+
@list.first.prepend data
|
269
|
+
return self
|
270
|
+
end
|
271
|
+
data=data.dup.to_sequence
|
272
|
+
data.instance_eval(&Overlaid)
|
273
|
+
@list[0,0]=data
|
274
|
+
|
275
|
+
#insert data.size into beginning of @start_pos
|
276
|
+
sz=data.size
|
277
|
+
@start_pos=@start_pos.map{|n| n+sz}
|
278
|
+
@start_pos[0,0]=0
|
279
|
+
|
280
|
+
notify_change(self,0, 0, data.size)
|
281
|
+
self
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
# class Indexed
|
286
|
+
# def subseq(*args)
|
287
|
+
# result=super
|
288
|
+
# result and respond_to? :overlaid? and def result.overlaid?; true end
|
289
|
+
# result
|
290
|
+
# end
|
291
|
+
# end
|
292
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Copyright (C) 2006 Caleb Clausen
|
2
|
+
# Distributed under the terms of Ruby's license.
|
3
|
+
require 'sequence'
|
4
|
+
require 'sequence/indexed'
|
5
|
+
|
6
|
+
class Sequence
|
7
|
+
class OfHash < OfArray
|
8
|
+
def initialize(hash,exceptions=[],include_default=false,modifiable=false)
|
9
|
+
@hash=hash
|
10
|
+
hash=hash.dup
|
11
|
+
exceptions.each{|exc| hash.delete exc }
|
12
|
+
@data=hash.inject([]){|l,pair| l+pair}
|
13
|
+
@data<<hash.default if include_default
|
14
|
+
@data.freeze unless modifiable
|
15
|
+
end
|
16
|
+
|
17
|
+
def modify(*args)
|
18
|
+
repldata=args.pop
|
19
|
+
start,len,only1=_parse_slice_args(*args)
|
20
|
+
len==1 or raise "scalar modifications to hashes only!"
|
21
|
+
if @data.size.%(2).nonzero? and @data.size.-(1)==start
|
22
|
+
@hash.default=repldata.first
|
23
|
+
elsif start.%(2).zero? #key
|
24
|
+
@hash[repldata.first]=@hash.delete @data[start]
|
25
|
+
else #value
|
26
|
+
@hash[@data[start-1]]=repldata.first
|
27
|
+
end
|
28
|
+
@data[first]=repldata.first
|
29
|
+
repldata
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Hash
|
35
|
+
def to_sequence(include_default=false)
|
36
|
+
Sequence::OfHash.new(self,include_default)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Copyright (C) 2006 Caleb Clausen
|
2
|
+
# Distributed under the terms of Ruby's license.
|
3
|
+
require 'sequence'
|
4
|
+
require 'sequence/indexed'
|
5
|
+
|
6
|
+
|
7
|
+
class Sequence
|
8
|
+
class OfObjectIvars < OfArray
|
9
|
+
def initialize(obj,exceptions=[],modifiable=false)
|
10
|
+
@obj=obj
|
11
|
+
ivars=obj.instance_variables - exceptions
|
12
|
+
@data=ivars.inject([]){|l,name| l.push name,obj.instance_variable_get(name)}
|
13
|
+
@data.freeze unless modifiable
|
14
|
+
end
|
15
|
+
|
16
|
+
def modify(*args)
|
17
|
+
repldata=args.pop
|
18
|
+
start,len,only1=_parse_slice_args(*args)
|
19
|
+
len==1 or raise "scalar modifications to objects only!"
|
20
|
+
assert start.%(2).nonzero? #not a name
|
21
|
+
|
22
|
+
@obj.instance_variable_set(@data[start-1],repldata.first)
|
23
|
+
@data[start]=repldata.first
|
24
|
+
repldata
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# Copyright (C) 2006 Caleb Clausen
|
2
|
+
# Distributed under the terms of Ruby's license.
|
3
|
+
require 'sequence'
|
4
|
+
require 'sequence/indexed'
|
5
|
+
reuqire 'sequence/functional'
|
6
|
+
require 'set'
|
7
|
+
|
8
|
+
|
9
|
+
class Sequence
|
10
|
+
class OfObjectMethods < OfArray
|
11
|
+
def initialize obj, exceptions=[], extras=[] #,modifiable=false
|
12
|
+
@obj=obj
|
13
|
+
methods=obj.public_methods.-(Functional.nonfunctions_of(obj)).-(exceptions)
|
14
|
+
methods.reject!{|name| /[!=]$/==name }
|
15
|
+
@data.concat extras.map{|x| Symbol===x ? x.to_s : x }
|
16
|
+
@data=methods.inject([]){|l,name| l+[name,nil]}
|
17
|
+
#@data.freeze unless modifiable
|
18
|
+
|
19
|
+
@is_exception=0
|
20
|
+
@is_reified=0
|
21
|
+
end
|
22
|
+
|
23
|
+
def is_exception?(index) @is_exception&(1<<index/2) == 0 end
|
24
|
+
def set_exception!(index) @is_exception|= 1<<index/2 end
|
25
|
+
|
26
|
+
def is_reified?(index) @is_reified&(1<<index/2) == 0 end
|
27
|
+
def set_reified!(index) @is_reified|= 1<<index/2 end
|
28
|
+
|
29
|
+
def modify(*args)
|
30
|
+
repldata=args.pop
|
31
|
+
start,len,only1=_parse_slice_args(*args)
|
32
|
+
len==1 or raise ArgumentError,"scalar modifications to objects only!"
|
33
|
+
start.%(2).nonzero? or raise ArgumentError, "OfObjectMethods#modify will not change method names!"
|
34
|
+
|
35
|
+
if Array===@data[start-1]
|
36
|
+
if @data[start-1].first.to_s=='[]'
|
37
|
+
@obj.send(:[]=, @data[1..-1],repldata)
|
38
|
+
else raise ArgumentError, "trying to call settor with extra args"
|
39
|
+
end
|
40
|
+
else
|
41
|
+
|
42
|
+
@obj.send(@data[start-1]+"=",repldata.first)
|
43
|
+
@data[start]=repldata.first
|
44
|
+
end
|
45
|
+
repldata
|
46
|
+
end
|
47
|
+
|
48
|
+
def reify_from_index(i)
|
49
|
+
#if the call raises an exception, store the exception instead of the result
|
50
|
+
#and remember (in @is_exception) that this particular result is an exception
|
51
|
+
if is_reified? i
|
52
|
+
raise @data[i+1] if is_exception? i
|
53
|
+
return
|
54
|
+
end
|
55
|
+
set_reified! i
|
56
|
+
begin
|
57
|
+
@data[i+1]=
|
58
|
+
if Array===@data[i]
|
59
|
+
@obj.send(*@data[i])
|
60
|
+
else
|
61
|
+
@obj.send(@data[i])
|
62
|
+
end
|
63
|
+
rescue Exception=>exc
|
64
|
+
set_exception!(i)
|
65
|
+
@data[i+1]=exc
|
66
|
+
raise
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def reify(itemref)
|
71
|
+
|
72
|
+
if itemref.is_a? String or itemref.is_a? Symbol
|
73
|
+
i=0
|
74
|
+
begin
|
75
|
+
i=@data.index(itemref.to_s,i)
|
76
|
+
i or @data.push itemref.to_s, nil
|
77
|
+
end while i and i%2!=0
|
78
|
+
reify_from_index(i)
|
79
|
+
elsif itemref.is_a? Integer and itemref>=0 and itemref%2==0
|
80
|
+
reify_from_index(itemref)
|
81
|
+
else
|
82
|
+
raise ArgumentError
|
83
|
+
end
|
84
|
+
return nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# $Id$
|
2
|
+
# Copyright (C) 2006 Caleb Clausen
|
3
|
+
# Distributed under the terms of Ruby's license.
|
4
|
+
|
5
|
+
require 'sequence'
|
6
|
+
require 'sequence/usedata'
|
7
|
+
|
8
|
+
class Sequence
|
9
|
+
# Objects in this class are mainly used to simply mark/remember the location
|
10
|
+
# of a parent sequence. But, this class also has the fully functionality of the
|
11
|
+
# parent. When this child wants to do an operation, it uses the parent to
|
12
|
+
# do it and returns the parent to where it was.
|
13
|
+
class Position < UseData # :nodoc:
|
14
|
+
def initialize(parent,pos=parent.pos)
|
15
|
+
Position===parent and raise ArgumentError
|
16
|
+
@data = parent
|
17
|
+
@pos = _normalize_pos pos
|
18
|
+
extend parent.like
|
19
|
+
prop(nil,parent.prop)
|
20
|
+
@data.on_change_notify self
|
21
|
+
end
|
22
|
+
|
23
|
+
def change_notification data,first,oldsize,newsize
|
24
|
+
assert @data==data
|
25
|
+
@pos=_adjust_pos_on_change @pos,first,oldsize,newsize
|
26
|
+
|
27
|
+
notify_change self,first,oldsize,newsize
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
def _pos=(p)
|
35
|
+
@pos = p
|
36
|
+
end
|
37
|
+
def position(pos=@pos)
|
38
|
+
@data.position(pos)
|
39
|
+
end
|
40
|
+
|
41
|
+
# undef_method(:_delete_position)
|
42
|
+
|
43
|
+
def_delegators :@data, :size, :data_class, :[], :[]=, :slice
|
44
|
+
def_delegators :@data, :new_data, :all_data, :pos?, :position?
|
45
|
+
def_delegators :@data, :begin, :end, :empty?, :index, :rindex, :slice!
|
46
|
+
def_delegators :@data, :modify, :append, :prepend, :overwrite
|
47
|
+
def_delegators :@data, :insert, :delete, :push, :pop, :shift, :unshift
|
48
|
+
|
49
|
+
alias dup position
|
50
|
+
|
51
|
+
def nearbegin(len,at=pos)
|
52
|
+
@data.nearbegin(len,at)
|
53
|
+
end
|
54
|
+
|
55
|
+
def nearend(len,at=pos)
|
56
|
+
@data.nearend(len,at)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
def eof?; @pos>=size end
|
62
|
+
|
63
|
+
attr_reader :data,:pos
|
64
|
+
|
65
|
+
|
66
|
+
def closed?
|
67
|
+
super or @data.closed?
|
68
|
+
end
|
69
|
+
|
70
|
+
def close
|
71
|
+
@data._delete_position(self)
|
72
|
+
super
|
73
|
+
end
|
74
|
+
=begin ***
|
75
|
+
protected
|
76
|
+
def _deletion(pos,len=1,reverse=false,dummy=nil)
|
77
|
+
if @pos==pos
|
78
|
+
@anchor_after = false
|
79
|
+
elsif @pos>pos
|
80
|
+
@pos -= len
|
81
|
+
if @pos<pos
|
82
|
+
@pos = pos
|
83
|
+
@anchor_after = !reverse
|
84
|
+
elsif @pos==pos
|
85
|
+
@anchor_after = true
|
86
|
+
end
|
87
|
+
end
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
def _insertion(pos,len=1,dummmy=nil)
|
91
|
+
if @pos>=pos+(@anchor_after ? 0 : 1)
|
92
|
+
@pos += len
|
93
|
+
end
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
=end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|