sequence 0.1.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/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
|
+
|