cursor 0.6 → 0.8

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.
@@ -0,0 +1,71 @@
1
+ # $Id: position.rb,v 1.3 2005/07/18 14:46:28 eric_mahurin Exp $
2
+
3
+ require 'cursor'
4
+
5
+ class Cursor
6
+ module UseNext
7
+ class Position < Cursor::Position # :nodoc:
8
+ def initialize(parent,reverse=false)
9
+ @parent = parent
10
+ @anchor_after = reverse
11
+ if @anchor_after && !@parent.skip1after
12
+ @pos = nil
13
+ else
14
+ @pos = @parent.__send__(:pos)
15
+ end
16
+ prop(nil,@parent.prop)
17
+ end
18
+ def pos(reverse=false)
19
+ if reverse.nil? ? @anchor_after : reverse
20
+ @pos && (@pos.to_i-@parent.size).nonzero? || -0.0
21
+ else
22
+ @pos || @parent.size
23
+ end
24
+ end
25
+ def pos=(p)
26
+ if (p.nonzero?||1.0/p)<0
27
+ @pos = p.to_i.nonzero?
28
+ @pos += @parent.size if @pos
29
+ @anchor_after = true
30
+ p
31
+ else
32
+ @anchor_after = false
33
+ @pos = p
34
+ end
35
+ end
36
+ protected
37
+ def _deletion(pos,len=1,reverse=false,eof=nil)
38
+ if @pos
39
+ if @pos==pos
40
+ @anchor_after = false
41
+ elsif @pos>pos
42
+ @pos -= len
43
+ if @pos<pos
44
+ @pos = pos
45
+ if reverse
46
+ @anchor_after=true
47
+ eof = !@parent.skip1after if eof.nil?
48
+ @pos = nil if eof
49
+ else
50
+ @anchor_after = false
51
+ end
52
+ elsif @pos==pos && !@anchor_after
53
+ @anchor_after = true
54
+ eof = !@parent.skip1after if eof.nil?
55
+ @pos = nil if eof
56
+ end
57
+ end
58
+ end
59
+ eof
60
+ end
61
+ def _insertion(pos,len=1,dummy=nil)
62
+ if @pos and @pos>=pos+(@anchor_after ? 0 : 1)
63
+ @pos += len
64
+ end
65
+ nil
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+
@@ -0,0 +1,42 @@
1
+ # $Id: useposition.rb,v 1.10 2005/07/15 22:34:42 eric_mahurin Exp $
2
+
3
+ ;
4
+
5
+ class Cursor
6
+ # Mixin for derived classes to use #position as the basis for After/Before methods.
7
+ # See Cursor for a description of these methods.
8
+ module UsePosition # :nodoc:
9
+ def read1after
10
+ position(false) { read1next }
11
+ end
12
+ def read1before
13
+ position(true) { read1prev }
14
+ end
15
+ def skip1after
16
+ position(false) { skip1next }
17
+ end
18
+ def skip1before
19
+ position(true) { skip1prev }
20
+ end
21
+ def write1after(v)
22
+ position(false) { write1next(v) }
23
+ end
24
+ def write1before(v)
25
+ position(true) { write1prev(v) }
26
+ end
27
+ def write1after!(v)
28
+ position(false) { write1next!(v) }
29
+ end
30
+ def write1before!(v)
31
+ position(true) { write1prev!(v) }
32
+ end
33
+ def write1after?(v)
34
+ position(false) { write1next?(v) }
35
+ end
36
+ def write1before?(v)
37
+ position(true) { write1prev?(v) }
38
+ end
39
+ end
40
+ end
41
+
42
+
@@ -0,0 +1,126 @@
1
+ # $Id: usereadwrite.rb,v 1.13 2005/07/15 22:34:42 eric_mahurin Exp $
2
+
3
+ ;
4
+
5
+ class Cursor
6
+ # Mixin for derived classes to use these methods as the basis for others:
7
+ # #read1next, #read1prev, #write1next, #write1prev,
8
+ # #_delete1after?, #delete1before?, #_insert1before, #_insert1after.
9
+ # See Cursor for a description of these methods.
10
+ module UseReadWrite # :nodoc:
11
+ protected
12
+ def _delete1after
13
+ _delete1after?.nil? ? nil : true
14
+ end
15
+ def _delete1before
16
+ _delete1before?.nil? ? nil : true
17
+ end
18
+ public
19
+ def delete1after
20
+ _delete1after && (@positions && _adjust_delete;true)
21
+ end
22
+ def delete1before
23
+ _delete1before && (@positions && _adjust_delete;true)
24
+ end
25
+ def delete1after?
26
+ v0 = _delete1after?
27
+ v0.nil? || @positions && _adjust_delete
28
+ v0
29
+ end
30
+ def delete1before?
31
+ v0 = _delete1before?
32
+ v0.nil? || @positions && _adjust_delete
33
+ v0
34
+ end
35
+ def insert1before(v)
36
+ @positions && _adjust_insert
37
+ _insert1before(v)
38
+ end
39
+ def insert1after(v)
40
+ @positions && _adjust_insert
41
+ _insert1after(v)
42
+ end
43
+ def write1next!(v)
44
+ write1next(v) || insert1before(v)
45
+ end
46
+ def write1prev!(v)
47
+ write1prev(v) || insert1after(v)
48
+ end
49
+
50
+ def skip1next
51
+ read1next.nil? ? nil : true
52
+ end
53
+ def skip1prev
54
+ read1prev.nil? ? nil : true
55
+ end
56
+ def write1next?(v)
57
+ v0 = read1after
58
+ v0.nil? || write1next(v)
59
+ v0
60
+ end
61
+ def write1prev?(v)
62
+ v0 = read1before
63
+ v0.nil? || write1prev(v)
64
+ v0
65
+ end
66
+
67
+ def read1after
68
+ v0 = read1next
69
+ v0.nil? || skip1prev
70
+ v0
71
+ end
72
+ def read1before
73
+ v0 = read1prev
74
+ v0.nil? || skip1next
75
+ v0
76
+ end
77
+ def skip1after
78
+ skip1next && skip1prev
79
+ end
80
+ def skip1before
81
+ skip1prev && skip1next
82
+ end
83
+ def write1after(v)
84
+ write1next(v) && skip1prev
85
+ end
86
+ def write1after!(v)
87
+ write1next!(v)
88
+ skip1prev
89
+ end
90
+ def write1before(v)
91
+ write1prev(v) && skip1next
92
+ end
93
+ def write1before!(v)
94
+ write1prev!(v)
95
+ skip1next
96
+ end
97
+ def write1after?(v)
98
+ v0 = write1next?(v)
99
+ v0.nil? || skip1prev
100
+ v0
101
+ end
102
+ def write1before?(v)
103
+ v0 = write1prev?(v)
104
+ v0.nil? || skip1next
105
+ v0
106
+ end
107
+ def scan1next(v)
108
+ v0 = read1next
109
+ (v0.nil? || v==v0) ? v0 : (skip1prev;nil)
110
+ end
111
+ def scan1prev(v)
112
+ v0 = read1prev
113
+ (v0.nil? || v==v0) ? v0 : (skip1next;nil)
114
+ end
115
+ def modify1next(r)
116
+ v0 = read1after
117
+ (v0.nil? || (v = r[v0]).nil?) ? nil : (write1next(v);v0)
118
+ end
119
+ def modify1prev(r)
120
+ v0 = read1before
121
+ (v0.nil? || (v = r[v0]).nil?) ? nil : (write1prev(v);v0)
122
+ end
123
+ end
124
+ end
125
+
126
+
data/duck.rb ADDED
@@ -0,0 +1,31 @@
1
+ # $Id: duck.rb,v 1.3 2005/07/21 15:15:38 eric_mahurin Exp $
2
+
3
+ class Object
4
+ # Return a new object that maps methods the original object to different
5
+ # names. The arguments are a list alternating new and old method names
6
+ # (strings or symbols). If an odd number (usually one) of arguments is given,
7
+ # the last old method is assumed to be the original object itself -
8
+ # hopefully a Proc or Method and it is used to map to the new name in the
9
+ # new object.
10
+ def duck(*new_old)
11
+ obj = Object.new
12
+ klass = (class << obj;self;end)
13
+ until new_old.empty?
14
+ new,old = new_old.slice!(0,2)
15
+ klass.__send__(:define_method,new,&(old ? self.method(old) : self))
16
+ end
17
+ obj
18
+ end
19
+ # Return a new object that maps a hash of name=>proc to the methods of the
20
+ # object.
21
+ def self.duck(methods)
22
+ obj = self.new
23
+ klass = (class << obj;self;end)
24
+ methods.each { |name,proc|
25
+ klass.__send__(:define_method,name,&proc)
26
+ }
27
+ obj
28
+ end
29
+ end
30
+
31
+
@@ -0,0 +1,50 @@
1
+ # $Id: regexp_cursor.rb,v 1.2 2005/07/21 15:20:48 eric_mahurin Exp $
2
+
3
+ require 'strscan'
4
+
5
+ class Regexp
6
+ # Scan the cursor for the regexp and return what was matched or +nil+ for
7
+ # a mismatch. The regexp will be implicitly anchored at the cursor location.
8
+ # Unless +hold+ or a mismatch, the cursor will be advanced to a point right
9
+ # after the match. +len+ should be the max length that the regexp can match or
10
+ # zero to look at everything. A negative +len+ (including -0.0) will scan
11
+ # the cursor in reverse.
12
+ def scan_cursor(cursor,len=0,hold=false)
13
+ reverse = (len.nonzero?||1.0/len)<0
14
+ buffer = len.zero? ? cursor.read!(reverse,true,"") : cursor.read(len,true,"")
15
+ buffer or return
16
+ scanner = StringScanner.new(buffer)
17
+ ret = scanner.scan(self)
18
+ if ret
19
+ len = scanner.pos
20
+ cursor.skip(reverse ? -len : +len) if !hold
21
+ end
22
+ ret
23
+ end
24
+ # Scan the cursor until it matches the regexp and what was scanned up to and
25
+ # including the match or +nil+ if it never matched.
26
+ # Unless +hold+ or a mismatch, the cursor will be advanced to a point right
27
+ # after the match. +len+ should be the start buffer size of what to look at
28
+ # from the cursor or zero to look at everything at once. A negative +len+
29
+ # (including -0.0) will scan the cursor in reverse.
30
+ def scan_cursor_until(cursor,len=1,hold=false)
31
+ reverse = (len.nonzero?||1.0/len)<0
32
+ buffer = ""
33
+ scanner = StringScanner.new(buffer)
34
+ if len.zero?
35
+ buffer = cursor.read!(reverse,true,buffer) or return
36
+ ret = scanner.scan_until(self)
37
+ else
38
+ while cursor.read(len,false,buffer)
39
+ ret = scanner.scan_until(self) and break(ret)
40
+ len *= 2
41
+ end
42
+ len = buffer.length
43
+ end
44
+ len = (hold ? 0 : scanner.pos)-len
45
+ cursor.skip(reverse ? -len : +len) if len.nonzero?
46
+ ret
47
+ end
48
+ end
49
+
50
+
@@ -0,0 +1,130 @@
1
+ # $Id: weakrefset.rb,v 1.5 2005/06/29 15:22:38 eric_mahurin Exp $
2
+
3
+ # WeakRefSet implements an unordered collection of weak references to objects.
4
+ # These references don't prevent garbage collection on these objects. As these
5
+ # objects are thrown away so does their entry in a WeakRefSet. Immmediate
6
+ # objects are not handled by this class (and wouldn't be useful).
7
+ class WeakRefSet
8
+ include Enumerable
9
+ private
10
+ def finalizer(id)
11
+ @ids.delete(id >> 1)
12
+ end
13
+ public
14
+ # create a new WeakRefSet from an optional Enumerable (of objects)
15
+ # which is optionally processed through a block
16
+ def initialize(enum=[],&block) # :yield: obj
17
+ replace(enum.collect(&block))
18
+ end
19
+ # add a weak reference to the set
20
+ def add(obj)
21
+ @ids[obj.__id__ >> 1] = true
22
+ ObjectSpace.define_finalizer(obj,method(:finalizer))
23
+ self
24
+ end
25
+ alias << add
26
+ # iterate over remaining valid objects in the set
27
+ def each(&block)
28
+ @ids.each_key { |id|
29
+ begin
30
+ o = ObjectSpace._id2ref(id << 1)
31
+ rescue RangeError
32
+ next
33
+ end
34
+ block.call(o) if @ids.include?(id)
35
+ }
36
+ nil
37
+ end
38
+ # clear the set (return self)
39
+ def clear
40
+ @ids = {}
41
+ self
42
+ end
43
+ # merge some more objects into the set (return self)
44
+ def merge(enum)
45
+ enum.each { |obj| add(obj) }
46
+ self
47
+ end
48
+ # replace the objects in the set (return self)
49
+ def replace(enum)
50
+ clear
51
+ merge(enum)
52
+ self
53
+ end
54
+ # delete an object in the set (return self)
55
+ def delete(obj)
56
+ @ids.delete(obj.__id__ >> 1)
57
+ self
58
+ end
59
+ # delete an object in the set (return self or nil if nothing deleted)
60
+ def delete?(obj)
61
+ @ids.delete(obj.__id__ >> 1)&&self
62
+ end
63
+ # any objects in the set still valid?
64
+ def empty?
65
+ each { return(false) }
66
+ true
67
+ end
68
+ # is this object in the set?
69
+ def include?(obj)
70
+ @ids.include?(obj.__id__ >> 1)
71
+ end
72
+ alias member? include?
73
+ # return a string showing the object classes and ids
74
+ def inspect
75
+ s = sprintf("#<#{self.class}:0x%x {",__id__ << 1)
76
+ s += collect { |obj| obj.inspect }.join(", ")
77
+ s + "}>"
78
+ end
79
+ # remove some objects from the set (return self)
80
+ def subtract(enum)
81
+ enum.each { |obj| delete(obj) }
82
+ self
83
+ end
84
+ # number of objects in the set still valid
85
+ def size
86
+ n=0
87
+ each { n+=1 }
88
+ n
89
+ end
90
+ alias length size
91
+ end
92
+
93
+ # :stopdoc:
94
+
95
+ if __FILE__==$0
96
+ require 'benchmark'
97
+ MyString = Class.new(String)
98
+ weakrefs = WeakRefSet.new
99
+ $stdout.sync=true
100
+ obj = nil
101
+ times = Benchmark.measure {
102
+ 10000.times { |i|
103
+ print(".")
104
+ obj = MyString.new("X"*rand(i+1))
105
+ weakrefs << obj
106
+ weakrefs.each { |o|
107
+ MyString==o.class or raise
108
+ }
109
+ weakrefs.include?(obj) or raise
110
+ if rand(10).zero?
111
+ weakrefs.delete?(obj) or raise
112
+ !weakrefs.include?(obj) or raise
113
+ end
114
+ }
115
+ }
116
+ puts
117
+ p(weakrefs)
118
+ p((weakrefs.size.nonzero? or raise))
119
+ weakrefs.empty? and raise
120
+ GC.start
121
+ p(weakrefs)
122
+ p(weakrefs.clear)
123
+ weakrefs.size.zero? or raise
124
+ weakrefs.empty? or raise
125
+ puts(times)
126
+ end
127
+
128
+ # :stopdoc:
129
+
130
+