sequence 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/COPYING CHANGED
File without changes
data/GPL CHANGED
File without changes
data/History.txt ADDED
@@ -0,0 +1,27 @@
1
+ === 0.2.1 / 2009-01-07
2
+ * 1 Minor Enhancement:
3
+ * WeakRefSet now conforms to Set's api and tests more closely.
4
+
5
+ * 1 Bugfix:
6
+ * fixed errors in MatchData when matching against a Regexp with an
7
+ optional capture that didn't capture anything .
8
+
9
+ === 0.2.0 / 2008-08-28
10
+
11
+ * 2 Major Enhancements:
12
+ * all tests now pass
13
+ * many small fixes in List; List is believed to actually work in all cases!
14
+
15
+ * 2 Minor Enhancements:
16
+ * cleanup of Indexed#scan*
17
+ * try not to use out of bounds indexes (including negative)
18
+ * more List test data created by wrapping existing data in List(s)
19
+ * enabled some tests which had been failing
20
+
21
+ === 0.1.0 / 2006-10-05
22
+
23
+ * 1 major enhancement
24
+
25
+ * Birthday!
26
+
27
+
data/Manifest.txt CHANGED
@@ -21,7 +21,7 @@ lib/sequence/stringlike.rb
21
21
  lib/sequence/subseq.rb
22
22
  lib/sequence/usedata.rb
23
23
  lib/sequence/version.rb
24
- lib/weakrefset.rb
24
+ lib/sequence/weakrefset.rb
25
25
  test/test.rb
26
26
  test/test_all.rb
27
27
  test/test_changes.rb
@@ -34,3 +34,4 @@ Manifest.txt
34
34
  README.txt
35
35
  COPYING
36
36
  GPL
37
+ History.txt
data/README.txt CHANGED
@@ -49,7 +49,7 @@ No unit tests at all for array-like sequences
49
49
 
50
50
  == INSTALL:
51
51
 
52
- * Just run: gem install sequence
52
+ * Simply: gem install sequence
53
53
 
54
54
  == LICENSE:
55
55
 
data/Rakefile CHANGED
@@ -5,13 +5,20 @@ require 'hoe'
5
5
  require 'lib/sequence/version.rb'
6
6
 
7
7
 
8
-
8
+ if $*==["test"]
9
+ #hack to get 'rake test' to stay in one process
10
+ #which keeps netbeans happy
11
+ $:<<"lib"
12
+ require "test/test_all.rb"
13
+ Test::Unit::AutoRunner.run
14
+ exit
15
+ end
9
16
 
10
17
  Hoe.new("sequence", Sequence::VERSION) do |_|
11
18
 
12
19
  _.author = "Caleb Clausen"
13
20
  _.email = "sequence-owner @at@ inforadical .dot. net"
14
- _.url = "http://sequence.rubyforge.org/"
21
+ _.url = [ "http://sequence.rubyforge.org/", "http://rubyforge.org/projects/sequence"]
15
22
  _.summary = "A single api for reading and writing sequential data types."
16
23
  _.description = <<-END
17
24
  A unified wrapper api for accessing data in Strings, Arrays, Files, IOs,
data/lib/assert.rb CHANGED
File without changes
data/lib/sequence.rb CHANGED
@@ -10,8 +10,9 @@
10
10
 
11
11
  require "forwardable"
12
12
  require 'assert'
13
- require 'weakrefset'
14
13
  require 'sequence/version'
14
+ require 'sequence/weakrefset'
15
+
15
16
 
16
17
  =begin todo
17
18
 
@@ -30,6 +31,8 @@ match/matchback
30
31
 
31
32
  class Sequence
32
33
 
34
+ # WeakRefSet=::Set
35
+ # warn "warning: sequence uses Set instead of WeakRefSet; memory leak results"
33
36
 
34
37
  include Comparable
35
38
  include Enumerable
@@ -81,13 +84,6 @@ class Sequence
81
84
  end
82
85
 
83
86
 
84
- # Return an empty object used for returning a sequence of elements.
85
- # The only method required of this object is << (append to the sequence).
86
- #usually [] or ""
87
- def new_data
88
- data_class.new
89
- end
90
-
91
87
  # attempt to read up to +len+ elements. the position is left just after the data read.
92
88
  # #read may return less than the whole requested amount if less data than requested in
93
89
  #+len+ is available. This can happen at end of file or if more data is simply unavailable
@@ -407,8 +403,8 @@ class Sequence
407
403
  # numeric positions and also be tested
408
404
  def position?(p)
409
405
  case p
410
- when Integer: (-size..size)===p
411
- when Position: equal? p.data
406
+ when Integer; (-size..size)===p
407
+ when Position; equal? p.data
412
408
  else equal? p
413
409
  end
414
410
  end
@@ -443,6 +439,7 @@ class Sequence
443
439
  instance_variables.empty?
444
440
  end
445
441
 
442
+ =begin who needs it?
446
443
  # Compare +other+ (a Position or Integer) to the current position. return +1
447
444
  # for the self is after, -1 for self being before, and 0 for it being at
448
445
  # same location, nil (or false) if other is not a position of self.
@@ -451,6 +448,8 @@ class Sequence
451
448
  elsif position?(other) then pos<=>other.pos
452
449
  end
453
450
  end
451
+ =end
452
+
454
453
  #if passed an integer arg, return a new position decreased by len. if passed
455
454
  # a position, return the distance (number
456
455
  # or elements) from +other+ (a #position) to +self+. This can be +, -, or 0.
@@ -2,6 +2,10 @@
2
2
  # Distributed under the terms of Ruby's license.
3
3
  class Sequence
4
4
  module ArrayLike
5
+ # Return an empty object used for returning a sequence of elements.
6
+ # The only method required of this object is << (append to the sequence).
7
+ #usually [] or ""
8
+ def new_data; [] end
5
9
  def data_class; Array end
6
10
  def like; ArrayLike end
7
11
 
@@ -43,46 +43,6 @@ class Buffered < Sequence
43
43
  def new_data
44
44
  @input.new_data
45
45
  end
46
- =begin
47
- protected
48
- def _delete1after?
49
- v0 = @buffer.delete1after?
50
- v0.nil? && @input && (v0 = @input.read(1)) && (v0 = v0[0])
51
- v0
52
- end
53
- def _delete1before?
54
- v0 = @buffer.delete1before?
55
- v0.nil? && @output_pos>0 && (@output_pos -= 1;v0 = @output.read(-1)) && (v0 = v0[0])
56
- v0
57
- end
58
- def _insert1before(v)
59
- if not position?
60
- len = @buffer.move!(true)
61
- if @output
62
- value = @buffer.read(len,nil)
63
- value << v
64
- @output.write(value)
65
- else
66
- @buffer.read(len,nil) if len
67
- end
68
- @output_pos += (len||0)+1
69
- else
70
- @buffer.insert1before(v)
71
- end
72
- true
73
- end
74
- def _insert1after(v)
75
- @buffer.insert1after(v)
76
- end
77
- public
78
- def close
79
- if @output
80
- @buffer.move!(true)
81
- value = @buffer.read!(false) and @output.write(value)
82
- end
83
- super
84
- end
85
- =end
86
46
  def _default_maxmatchlen; @buffer_size/2 end
87
47
 
88
48
  attr :pos
File without changes
data/lib/sequence/enum.rb CHANGED
File without changes
data/lib/sequence/file.rb CHANGED
File without changes
File without changes
File without changes
File without changes
data/lib/sequence/io.rb CHANGED
@@ -36,7 +36,7 @@ class IO < Sequence
36
36
 
37
37
  undef pos=, _pos=, position, position?, holding, holding?, holding!, readback, readback1
38
38
  undef readahead, readbehind, readahead1, readbehind1, write#, write1
39
- undef goto, move, move!, subseq, reversed, <=>, +, -, succ, pred, begin, end
39
+ undef goto, move, move!, subseq, reversed, +, -, succ, pred, begin, end
40
40
  undef begin!, end!, first, last, slice, [], modify, []=
41
41
 
42
42
 
@@ -99,4 +99,4 @@ class IO < Sequence
99
99
  end
100
100
  end
101
101
  end
102
- end
102
+ end
data/lib/sequence/list.rb CHANGED
File without changes
File without changes
File without changes
@@ -2,7 +2,7 @@
2
2
  # Distributed under the terms of Ruby's license.
3
3
  require 'sequence'
4
4
  require 'sequence/indexed'
5
- reuqire 'sequence/functional'
5
+ require 'sequence/functional'
6
6
  require 'set'
7
7
 
8
8
 
@@ -84,4 +84,4 @@ class Sequence
84
84
  return nil
85
85
  end
86
86
  end
87
- end
87
+ end
File without changes
File without changes
File without changes
File without changes
@@ -4,6 +4,11 @@ require 'sequence/subseq'
4
4
 
5
5
  class Sequence
6
6
  module StringLike
7
+ # Return an empty object used for returning a sequence of elements.
8
+ # The only method required of this object is << (append to the sequence).
9
+ #usually [] or ""
10
+ def new_data; '' end
11
+
7
12
  def data_class; String end
8
13
 
9
14
  def like; StringLike end
@@ -218,9 +223,13 @@ class Sequence
218
223
  begins=[]
219
224
  ends=[]
220
225
  matchdata.to_a.each_with_index{|substr,i|
221
- next unless substr
222
- begins<<matchdata.begin(i)+pos_adjust
223
- ends<<matchdata.end(i)+pos_adjust
226
+ if substr
227
+ begins<<matchdata.begin(i)+pos_adjust
228
+ ends<<matchdata.end(i)+pos_adjust
229
+ else
230
+ begins<<nil
231
+ ends<<nil
232
+ end
224
233
  }
225
234
 
226
235
  #..remove data at group indexes we added above
File without changes
File without changes
@@ -1,5 +1,5 @@
1
1
  # Copyright (C) 2006,2008 Caleb Clausen
2
2
  # Distributed under the terms of Ruby's license.
3
3
  class Sequence
4
- VERSION='0.2.0'
4
+ VERSION='0.2.1'
5
5
  end
@@ -0,0 +1,336 @@
1
+ # $Id$
2
+ # Copyright (C) 2006,2008 Caleb Clausen
3
+ # Distributed under the terms of Ruby's license.
4
+
5
+ #require 'yaml'
6
+ require 'set'
7
+ begin
8
+ require 'weakref'
9
+ rescue Exception
10
+ end
11
+
12
+ # WeakRefSet implements an unordered collection of weak references to objects.
13
+ # These references don't prevent garbage collection on these objects. As these
14
+ # objects are thrown away so does their entry in a WeakRefSet. Immmediate
15
+ # objects are not handled by this class (and wouldn't be useful).
16
+ class Sequence
17
+ class WeakRefSet<Set
18
+ include Enumerable
19
+ # create a new WeakRefSet from an optional Enumerable (of objects)
20
+ # which is optionally processed through a block
21
+ def initialize(items=nil,&block) # :yield: obj
22
+ items=[] if items.nil?
23
+ raise ArgumentError unless items.respond_to? :each
24
+ items=items.map(&block) if block
25
+ replace(items)
26
+ end
27
+ alias initialize_copy initialize
28
+ class<<self
29
+ def [] *items
30
+ new(items)
31
+ end
32
+ end
33
+
34
+ private
35
+ def finalizer(id)
36
+ @ids.delete(id)
37
+ end
38
+
39
+ sss="a string"
40
+ if WeakRef.respond_to? :create_weakref and #rubinius
41
+ WeakRef.create_weakref(sss).at(0).equal?(sss)
42
+
43
+ def ref o
44
+ WeakRef.create_weakref o
45
+ end
46
+ def unref id
47
+ id.at(0)
48
+ rescue Exception
49
+ return nil
50
+ end
51
+
52
+ else
53
+
54
+ def ref o
55
+ o.__id__
56
+ end
57
+ def unref id
58
+ ObjectSpace._id2ref id
59
+ rescue RangeError
60
+ return nil
61
+ end
62
+ end
63
+
64
+ public
65
+
66
+ # add a weak reference to the set
67
+ def add(obj)
68
+ return self if include? obj
69
+ # Symbol===obj || Fixnum===obj || nil==obj || true==obj || false==obj and
70
+ # raise ArgumentError, "no immediates in weakrefset"
71
+ id=ref obj
72
+ case (o2=unref id) #test id for validity
73
+ when Fixnum;
74
+ obj.equal? o2 or raise
75
+ when Symbol,true,false,nil; id=obj #hopefully rare
76
+ else
77
+ obj.equal? o2 or raise
78
+ ObjectSpace.define_finalizer(obj,method(:finalizer))
79
+ end
80
+ @ids[id] = true
81
+ self
82
+ end
83
+ alias << add
84
+
85
+ # iterate over remaining valid objects in the set
86
+ def each
87
+ @ids.each_key { |id|
88
+ case id
89
+ when Integer
90
+ @ids.include?(id) or next
91
+ o = unref(id) or next
92
+ #i don't know where the random symbols come from, but at least they're always symbols...
93
+ else
94
+ o=id
95
+ end
96
+ # case o
97
+ # when Symbol,Fixnum,true,false,nil: warn "immediate value #{o.inspect} found in weakrefset"
98
+ # else
99
+ yield(o)
100
+ # end
101
+ }
102
+ self
103
+ end
104
+
105
+ def to_a
106
+ map{|x| x}
107
+ end
108
+
109
+ def == other
110
+ return true if self.equal? other
111
+ other.is_a? Set and other.size==self.size and
112
+ all?{|x| other.include?(x) }
113
+ end
114
+ alias eql? ==
115
+
116
+ def hash
117
+ result=0
118
+ each{|x| result^=x.hash }
119
+ result
120
+ end
121
+
122
+ # clear the set (return self)
123
+ def clear
124
+ @ids = {}
125
+ self
126
+ end
127
+
128
+ # merge some more objects into the set (return self)
129
+ def merge(enum)
130
+ enum.each { |obj| add(obj) }
131
+ self
132
+ end
133
+
134
+ # replace the objects in the set (return self)
135
+ def replace(enum)
136
+ clear
137
+ merge(enum)
138
+ self
139
+ end
140
+
141
+ # delete an object in the set (return self)
142
+ def delete(obj)
143
+ delete?(obj)
144
+ self
145
+ end
146
+
147
+ # delete an object in the set (return self if obj was found, else nil if nothing deleted)
148
+ def delete?(obj)
149
+ x=include?(obj)
150
+ if x
151
+ fail unless @ids.delete(ref( obj ))||@ids.delete(obj)
152
+ return self
153
+ end
154
+ end
155
+
156
+ # Deletes every element of the set for which block evaluates to
157
+ # true, and returns self.
158
+ def delete_if
159
+ to_a.each { |o| delete(o) if yield(o) }
160
+ self
161
+ end
162
+
163
+ # is this object in the set?
164
+ def include?(obj)
165
+ any?{|x| obj==x}
166
+ end
167
+ alias member? include?
168
+
169
+
170
+ # return a human-readable string showing the set
171
+ def inspect
172
+ #unless $weakrefset_verbose_inspect
173
+ # return sprintf('#<%s:0x%x {...}>', self.class.name, object_id)
174
+ #end
175
+ ids = (Thread.current[:__weakrefset__inspect_key__] ||= [])
176
+
177
+ if ids.include?(object_id)
178
+ return sprintf('#<%s: {...}>', self.class.name)
179
+ end
180
+
181
+ begin
182
+ ids << object_id
183
+ return sprintf('#<%s: {%s}>', self.class.name, to_a.inspect[1..-2])
184
+ ensure
185
+ ids.pop
186
+ Thread.current[:__weakrefset__inspect_key__].empty? and
187
+ Thread.current[:__weakrefset__inspect_key__]=nil
188
+ end
189
+ end
190
+
191
+ if false #this is broken; emits yaml for a hash.
192
+
193
+ YAML::add_domain_type( "inforadical.net,2005", "object:WeakRefSet" ) do |type, val|
194
+ WeakRefSet.new( *val["items"] )
195
+ end
196
+
197
+ def is_complex_yaml?; true end
198
+
199
+ def to_yaml_type; "!inforadical.net,2005/object:WeakRefSet" end
200
+
201
+ alias to_yaml_properties to_a
202
+
203
+ def to_yaml( opts = {} )
204
+ YAML::quick_emit( object_id, opts ) { |out|
205
+ out.map( to_yaml_type ) { |map|
206
+ map.add( "items", to_yaml_properties)
207
+ }
208
+ }
209
+ end
210
+ end
211
+
212
+ # remove some objects from the set (return self)
213
+ def subtract(enum)
214
+ enum.each { |obj| delete(obj) }
215
+ self
216
+ end
217
+
218
+ # Returns a new set containing elements exclusive between the set
219
+ # and the given enumerable object. (set ^ enum) is equivalent to
220
+ # ((set | enum) - (set & enum)).
221
+ def ^(enum)
222
+ enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
223
+ n = self.class.new(enum)
224
+ each { |o| if n.include?(o) then n.delete(o) else n.add(o) end }
225
+ n
226
+ end
227
+
228
+ # any objects in the set still valid?
229
+ def empty?
230
+ @ids.empty?
231
+ end
232
+
233
+ # number of objects in the set still valid
234
+ def size
235
+ @ids.size
236
+ end
237
+ alias length size
238
+ end
239
+ end
240
+
241
+ # :stopdoc:
242
+
243
+ if __FILE__==$0
244
+ require 'benchmark'
245
+ class MyString <String;
246
+ def initialize(*)
247
+ @owner=0
248
+ super
249
+ end
250
+
251
+ end
252
+ class MyObject; end
253
+ class MyClass < Module; end
254
+ weakrefsets = (1..10).map {Sequence::WeakRefSet[]}
255
+ $stdout.sync=true
256
+ obj = nil
257
+ arr=[]
258
+ # srand(2389547343)
259
+ classes=[]
260
+ ObjectSpace.each_object(Class){|ob| classes<<ob}
261
+ maybe_Data=Data if defined? Data #whatever Data is supposed to be, idunno.....
262
+ classes-=[Symbol,Integer,NilClass,FalseClass,TrueClass,Numeric,maybe_Data,Bignum,Fixnum,
263
+ Float,Struct,Method,UnboundMethod,Proc,Thread,Binding,Continuation]
264
+ classes.delete_if{|k| begin k.allocate; rescue; true else false end}
265
+ def shuffle!(arr)
266
+ arr.sort_by{rand}
267
+ end
268
+
269
+ iterations=ARGV[0]||100_000
270
+ iterations=iterations.to_i
271
+
272
+ times = Benchmark.measure {
273
+ iterations.times { |i|
274
+ # print(weakrefs.size>70?"|":((60..70)===weakrefs.size ? ":" : (weakrefs.size>50?',':'.')))
275
+ print "." if 0==i%128
276
+ #obj = (k=classes[rand(classes.size)]).allocate
277
+ obj = (k=MyString).new "X#{rand(i+1)}_#{i}"
278
+ # obj= (k=Object).new
279
+ # obj= (k=MyObject).new
280
+ #obj= (k=MyClass).new
281
+ k==obj.class or raise
282
+ weakrefs=weakrefsets[rand(weakrefsets.size)]
283
+ obj.instance_eval{@owner=weakrefs}
284
+ obj.instance_eval{@owner}.equal? weakrefs or raise
285
+ weakrefs << obj
286
+ weakrefs.include?(obj) or raise
287
+ weakrefs.include?(obj) or raise
288
+ if rand(10).zero?
289
+ weakrefs.delete?(obj) or raise
290
+ !weakrefs.include?(obj) or raise
291
+ elsif rand(4).zero?
292
+ arr<<obj #prevent garbage collection
293
+ end
294
+ if rand(1000).zero?
295
+ shuffle! arr
296
+ arr.slice!(0..rand(arr.size))
297
+ end
298
+ arr.each{|o| o.instance_eval{@owner}.include? o or raise }
299
+ #rand(100).zero? and GC.start
300
+ }
301
+ }
302
+ puts
303
+ GC.start
304
+ weakrefsets.each{|weakrefs|
305
+ weakrefs.clear
306
+ weakrefs.size.zero? or raise
307
+ weakrefs.empty? or raise
308
+ }
309
+ puts(times)
310
+
311
+
312
+
313
+
314
+ class NotReallyWeakRefSet<Sequence::WeakRefSet
315
+ #ensure the items referenced never get gc'd
316
+ class<<self
317
+ @@keeprefs=[]
318
+ def new(*args)
319
+ @@keeprefs.concat args
320
+ super
321
+ end
322
+ end
323
+ end
324
+
325
+ #"now I should reuse Set's original tests, but replacing Set with NotReallyWeakRefSet"
326
+ origset=$:.find{|dir| File.exist? dir+"/set.rb"} +"/set.rb"
327
+ testcode=File.read(origset).split("\n__END__\n",2).last
328
+ testcode=testcode.split("\nclass TC_SortedSet",2).first #hack off some unwanted tests
329
+ testcode.gsub! 'Set', 'NotReallyWeakRefSet'
330
+
331
+ eval testcode
332
+ end
333
+
334
+ # :stopdoc:
335
+
336
+
data/test/test.rb CHANGED
File without changes
data/test/test_all.rb CHANGED
File without changes
data/test/test_changes.rb CHANGED
File without changes
File without changes
data/test/test_rexscan.rb CHANGED
@@ -57,6 +57,7 @@ $Debug=true
57
57
  test_read
58
58
  test_slice
59
59
  test_slice_empty
60
+ test_optional_capture
60
61
  ]
61
62
  MODIFYMETHODS=%w[
62
63
  test_insert
@@ -257,8 +258,8 @@ $Debug=true
257
258
  const_set k, xk=Class.new(xk)
258
259
  xk.instance_eval do
259
260
  define_method :a_seq do
260
- result=super
261
- result.maxmatchlen=6
261
+ result=super()
262
+ result.maxmatchlen=10
262
263
  result
263
264
  end
264
265
  end
@@ -273,7 +274,7 @@ $Debug=true
273
274
  const_set k, xk=Class.new(xk)
274
275
  xk.instance_eval do
275
276
  define_method :a_seq do
276
- result=Sequence::List.new([wrappee=super])
277
+ result=Sequence::List.new([wrappee=super()])
277
278
  result.pos=wrappee.pos
278
279
  return result
279
280
  end
@@ -290,7 +291,7 @@ $Debug=true
290
291
  const_set k, xk=Class.new(xk)
291
292
  xk.instance_eval do
292
293
  define_method :a_seq do
293
- result=Sequence::List.new([wrappee=super])
294
+ result=Sequence::List.new([wrappee=super()])
294
295
  chunk=rand_pos_pair
295
296
  chunk=chunk.first..chunk.last
296
297
  result[chunk]=result[chunk]
@@ -344,6 +345,25 @@ $Debug=true
344
345
  =end
345
346
 
346
347
  class Indexed
348
+ def test_optional_capture
349
+ seq=a_seq
350
+ word=seq.scan /(more of )?that (tough)/
351
+ md=seq.last_match
352
+ assert_equal "that tough", word
353
+ assert_equal "that tough", md[0]
354
+ assert_equal nil, md[1]
355
+ assert_equal "tough", md[2]
356
+
357
+ assert_equal OFFSET, md.begin(0)
358
+ assert_equal OFFSET+10, md.end(0)
359
+ assert_equal nil, md.begin(1)
360
+ assert_equal nil, md.end(1)
361
+ assert_equal OFFSET+5, md.begin(2)
362
+ assert_equal OFFSET+10, md.end(2)
363
+
364
+ end
365
+
366
+
347
367
  RANDOMIZED_METHODS=[:test_slice,:test_insert,:test_delete,:test_modify]
348
368
  undef test_randomized_methods_some_more
349
369
  def test_randomized_methods_some_more n=50
data/test/test_seqrex.rb CHANGED
File without changes
File without changes
metadata CHANGED
@@ -1,33 +1,37 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.4
3
- specification_version: 1
4
2
  name: sequence
5
3
  version: !ruby/object:Gem::Version
6
- version: 0.2.0
7
- date: 2008-08-29 00:00:00 +01:00
8
- summary: A single api for reading and writing sequential data types.
9
- require_paths:
10
- - lib
11
- email: sequence-owner @at@ inforadical .dot. net
12
- homepage: http://sequence.rubyforge.org/
13
- rubyforge_project: sequence
14
- description: A unified wrapper api for accessing data in Strings, Arrays, Files, IOs, and Enumerations. Each sequence encapsulates some data and a current position within it. There are methods for moving the position, reading and writing data (with or without moving the position) forward or backward from the current position (or anywhere at all), scanning for patterns (like StringScanner, but it works in Files too, among others), and saving a position that will remain valid even after data is deleted or inserted elsewhere within the sequence. There are also some utility classes for making sequences reversed or circular, turning one-way sequences into two-way, buffering, and making sequences that are subsets or aggregations of existing sequences.
15
- autorequire:
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
4
+ version: 0.2.1
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
6
  authors:
30
7
  - Caleb Clausen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-06 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.12.2
24
+ version:
25
+ description: A unified wrapper api for accessing data in Strings, Arrays, Files, IOs, and Enumerations. Each sequence encapsulates some data and a current position within it. There are methods for moving the position, reading and writing data (with or without moving the position) forward or backward from the current position (or anywhere at all), scanning for patterns (like StringScanner, but it works in Files too, among others), and saving a position that will remain valid even after data is deleted or inserted elsewhere within the sequence. There are also some utility classes for making sequences reversed or circular, turning one-way sequences into two-way, buffering, and making sequences that are subsets or aggregations of existing sequences.
26
+ email: sequence-owner @at@ inforadical .dot. net
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - Manifest.txt
33
+ - README.txt
34
+ - History.txt
31
35
  files:
32
36
  - lib/assert.rb
33
37
  - lib/sequence.rb
@@ -52,7 +56,7 @@ files:
52
56
  - lib/sequence/subseq.rb
53
57
  - lib/sequence/usedata.rb
54
58
  - lib/sequence/version.rb
55
- - lib/weakrefset.rb
59
+ - lib/sequence/weakrefset.rb
56
60
  - test/test.rb
57
61
  - test/test_all.rb
58
62
  - test/test_changes.rb
@@ -65,27 +69,33 @@ files:
65
69
  - README.txt
66
70
  - COPYING
67
71
  - GPL
68
- test_files:
69
- - test/test_all.rb
72
+ - History.txt
73
+ has_rdoc: true
74
+ homepage: http://sequence.rubyforge.org/
75
+ post_install_message:
70
76
  rdoc_options:
71
77
  - --main
72
78
  - README.txt
73
- extra_rdoc_files:
74
- - Manifest.txt
75
- - README.txt
76
- executables: []
77
-
78
- extensions: []
79
-
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: "0"
86
+ version:
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: "0"
92
+ version:
80
93
  requirements: []
81
94
 
82
- dependencies:
83
- - !ruby/object:Gem::Dependency
84
- name: hoe
85
- version_requirement:
86
- version_requirements: !ruby/object:Gem::Version::Requirement
87
- requirements:
88
- - - ">="
89
- - !ruby/object:Gem::Version
90
- version: 1.5.1
91
- version:
95
+ rubyforge_project: sequence
96
+ rubygems_version: 1.3.1
97
+ signing_key:
98
+ specification_version: 2
99
+ summary: A single api for reading and writing sequential data types.
100
+ test_files:
101
+ - test/test_all.rb
data/lib/weakrefset.rb DELETED
@@ -1,254 +0,0 @@
1
- # $Id$
2
- # Copyright (C) 2006 Caleb Clausen
3
- # Distributed under the terms of Ruby's license.
4
-
5
- require 'yaml'
6
- require 'assert'
7
-
8
- # WeakRefSet implements an unordered collection of weak references to objects.
9
- # These references don't prevent garbage collection on these objects. As these
10
- # objects are thrown away so does their entry in a WeakRefSet. Immmediate
11
- # objects are not handled by this class (and wouldn't be useful).
12
- class WeakRefSet
13
- include Enumerable
14
- # create a new WeakRefSet from an optional Enumerable (of objects)
15
- # which is optionally processed through a block
16
- def initialize(items) # :yield: obj
17
- replace(items)
18
- end
19
- class<<self
20
- def [] *items
21
- new(items)
22
- end
23
- end
24
-
25
- private
26
- def finalizer(id)
27
- @ids.delete(id)
28
- end
29
-
30
- public
31
-
32
-
33
-
34
- # add a weak reference to the set
35
- def add(obj)
36
- Symbol===obj || Fixnum===obj || nil==obj || true==obj || false==obj and
37
- raise ArgumentError, "no immediates in weakrefset"
38
- id=obj.object_id
39
- case (o2=ObjectSpace._id2ref id) #test id for validity
40
- when Symbol,Fixnum,true,false,nil: id=obj #hopefully rare
41
- else obj.equal? o2 or raise
42
- ObjectSpace.define_finalizer(obj,method(:finalizer))
43
- end
44
- @ids[id] = true
45
- self
46
- end
47
- alias << add
48
- # iterate over remaining valid objects in the set
49
- def each
50
- @ids.each_key { |id|
51
- case id
52
- when Integer:
53
- begin
54
- o = ObjectSpace._id2ref(id)
55
- rescue RangeError
56
- next
57
- end
58
- @ids.include?(id) or next
59
- #i don't know where the random symbols come from, but at least they're always symbols...
60
- else
61
- o=id
62
- end
63
- case o
64
- when Symbol,Fixnum,true,false,nil: warn "immediate value #{o.inspect} found in weakrefset"
65
- else yield(o)
66
- end
67
- }
68
- self
69
- end
70
-
71
- def == other
72
- size==other.size and
73
- each{|x|
74
- other.include? x or return
75
- }
76
-
77
- end
78
-
79
- # clear the set (return self)
80
- def clear
81
- @ids = {}
82
- self
83
- end
84
- # merge some more objects into the set (return self)
85
- def merge(enum)
86
- enum.each { |obj| add(obj) }
87
- self
88
- end
89
- # replace the objects in the set (return self)
90
- def replace(enum)
91
- clear
92
- merge(enum)
93
- self
94
- end
95
- # delete an object in the set (return self)
96
- def delete(obj)
97
- delete?(obj)
98
- self
99
- end
100
- # delete an object in the set (return self or nil if nothing deleted)
101
- def delete?(obj)
102
- x=include?(obj) and @ids.delete(x.__id__)||@ids.delete(x) and self
103
- end
104
- # is this object in the set?
105
- def include?(obj)
106
- find{|x| obj==x}
107
- end
108
- alias member? include?
109
-
110
- # return a human-readable string showing the set
111
- def inspect
112
- #unless $weakrefset_verbose_inspect
113
- # return sprintf('#<%s:0x%x {...}>', self.class.name, object_id)
114
- #end
115
- ids = (Thread.current[:__weakrefset__inspect_key__] ||= [])
116
-
117
- if ids.include?(object_id)
118
- return sprintf('#<%s {...}>', self.class.name)
119
- end
120
-
121
- begin
122
- ids << object_id
123
- return sprintf('#<%s {%s}>', self.class.name, to_a.inspect[1..-2])
124
- ensure
125
- ids.pop
126
- Thread.current[:__weakrefset__inspect_key__].empty? and
127
- Thread.current[:__weakrefset__inspect_key__]=nil
128
- end
129
- end
130
-
131
- if false #this is broken; emits yaml for a hash.
132
-
133
- YAML::add_domain_type( "inforadical.net,2005", "object:WeakRefSet" ) do |type, val|
134
- WeakRefSet.new( *val["items"] )
135
- end
136
-
137
- def is_complex_yaml?; true end
138
-
139
- def to_yaml_type; "!inforadical.net,2005/object:WeakRefSet" end
140
-
141
- alias to_yaml_properties to_a
142
-
143
- def to_yaml( opts = {} )
144
- YAML::quick_emit( object_id, opts ) { |out|
145
- out.map( to_yaml_type ) { |map|
146
- map.add( "items", to_yaml_properties)
147
- }
148
- }
149
- end
150
- end
151
-
152
- # remove some objects from the set (return self)
153
- def subtract(enum)
154
- enum.each { |obj| delete(obj) }
155
- self
156
- end
157
- # any objects in the set still valid?
158
- def empty?
159
- @ids.empty?
160
- end
161
- # number of objects in the set still valid
162
- def size
163
- @ids.size
164
- end
165
- alias length size
166
- end
167
-
168
- # :stopdoc:
169
-
170
- if __FILE__==$0
171
- require 'benchmark'
172
- class MyString <String;
173
- def initialize(*)
174
- @owner=0
175
- super
176
- end
177
-
178
- end
179
- class MyObject; end
180
- class MyClass < Module; end
181
- weakrefsets = (1..10).map {WeakRefSet[]}
182
- $stdout.sync=true
183
- obj = nil
184
- arr=[]
185
- # srand(2389547343)
186
- classes=[]
187
- ObjectSpace.each_object(Class){|ob| classes<<ob}
188
- classes-=[Symbol,Integer,NilClass,FalseClass,TrueClass,Numeric,Data,Bignum,Fixnum,
189
- Float,Struct,Method,UnboundMethod,Proc,Thread,Binding,Continuation]
190
- classes.delete_if{|k| begin k.allocate; rescue; true else false end}
191
- def shuffle!(arr)
192
- arr.sort_by{rand}
193
- end
194
- times = Benchmark.measure {
195
- 100000.times { |i|
196
- # print(weakrefs.size>70?"|":((60..70)===weakrefs.size ? ":" : (weakrefs.size>50?',':'.')))
197
- print "." if 0==i%128
198
- #obj = (k=classes[rand(classes.size)]).allocate
199
- obj = (k=MyString).new "X" #*rand(i+1)
200
- # obj= (k=Object).new
201
- # obj= (k=MyObject).new
202
- #obj= (k=MyClass).new
203
- k==obj.class or raise
204
- weakrefs=weakrefsets[rand(weakrefsets.size)]
205
- obj.instance_eval{@owner=weakrefs}
206
- obj.instance_eval{@owner}.equal? weakrefs or raise
207
- weakrefs.each { |o|
208
- # k==o.class or raise "set contained a #{o.class}. i=#{i}. size=#{weakrefs.size}"
209
- (o2=o.instance_eval{@owner})==weakrefs or
210
- raise "expected owner #{weakrefs.map{|w| w.__id__}.inspect}, "+
211
- "got #{o2.inspect}, item #{o}, id #{o.__id__}, obj #{obj.__id__}"
212
- }
213
- weakrefs << obj
214
- weakrefs.each { |o|
215
- # k==o.class or raise "set contained a #{o.class}. i=#{i}. size=#{weakrefs.size}"
216
- (o2=o.instance_eval{@owner})==weakrefs or
217
- raise "expected owner #{weakrefs.map{|w| w.__id__}.inspect}, "+
218
- "got #{o2.inspect}, item #{o}, id #{o.__id__}, obj #{obj.__id__}"
219
- }
220
- weakrefs.include?(obj) or raise
221
- weakrefs.each { |o|
222
- # k==o.class or raise "set contained a #{o.class}. i=#{i}. size=#{weakrefs.size}"
223
- (o2=o.instance_eval{@owner})==weakrefs or
224
- raise "expected owner #{weakrefs.map{|w| w.__id__}.inspect}, "+
225
- "got #{o2.inspect}, item #{o}, id #{o.__id__}, obj #{obj.__id__}"
226
- }
227
- weakrefs.include?(obj) or raise
228
- if rand(10).zero?
229
- weakrefs.delete?(obj) or raise
230
- !weakrefs.include?(obj) or raise
231
- elsif rand(4).zero?
232
- arr<<obj #prevent garbage collection
233
- end
234
- if rand(1000).zero?
235
- shuffle! arr
236
- arr.slice!(0..rand(arr.size))
237
- end
238
- arr.each{|o| o.instance_eval{@owner}.include? o or raise }
239
- #rand(100).zero? and GC.start
240
- }
241
- }
242
- puts
243
- GC.start
244
- weakrefsets.each{|weakrefs|
245
- weakrefs.clear
246
- weakrefs.size.zero? or raise
247
- weakrefs.empty? or raise
248
- }
249
- puts(times)
250
- end
251
-
252
- # :stopdoc:
253
-
254
-