weakling 0.0.1
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/README.txt +58 -0
- data/Rakefile +20 -0
- data/examples/id_hash.rb +24 -0
- data/examples/refqueue_use.rb +13 -0
- data/ext/RefqueueService.java +12 -0
- data/ext/org/jruby/ext/RefQueueLibrary.java +173 -0
- data/lib/refqueue.jar +0 -0
- data/lib/weakling.rb +4 -0
- data/lib/weakling/collections.rb +41 -0
- data/weakling.gemspec +15 -0
- metadata +72 -0
data/README.txt
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
weakling: a collection of weakref utilities for Ruby
|
2
|
+
|
3
|
+
== Summary ==
|
4
|
+
|
5
|
+
This library provides:
|
6
|
+
|
7
|
+
* a modified WeakRef implementation for JRuby that supports a reference queue
|
8
|
+
* a WeakRef::RefQueue class
|
9
|
+
* a weak-valued ID map to replace typical uses of _id2ref
|
10
|
+
|
11
|
+
In the future it may provide additional features like a generic WeakHash or other
|
12
|
+
reference types like soft and phantom references.
|
13
|
+
|
14
|
+
== Usage ==
|
15
|
+
|
16
|
+
Just require 'weakling'. It will require 'weakref' along with the refqueue JRuby
|
17
|
+
extension and the weakling/collections library containing the weak id hash.
|
18
|
+
|
19
|
+
== RefQueue Example ==
|
20
|
+
|
21
|
+
require 'weakling'
|
22
|
+
require 'java'
|
23
|
+
|
24
|
+
q = WeakRef::RefQueue.new
|
25
|
+
wr = WeakRef.new(Object.new, q)
|
26
|
+
puts "weakref object: #{wr.__id__}"
|
27
|
+
|
28
|
+
puts "running GC"
|
29
|
+
java.lang.System.gc
|
30
|
+
|
31
|
+
puts "weakref alive?: #{wr.weakref_alive?}"
|
32
|
+
puts "weakref object from queue: #{q.poll.__id__}"
|
33
|
+
|
34
|
+
== WeakRef::IdHash Example ==
|
35
|
+
|
36
|
+
require 'weakling'
|
37
|
+
|
38
|
+
wh = WeakRef::IdHash.new
|
39
|
+
|
40
|
+
ary = (1..10).to_a.map {Object.new}
|
41
|
+
ids = ary.map {|o| wh.add(o)}
|
42
|
+
|
43
|
+
puts "all items in weak_id_hash:"
|
44
|
+
ids.each {|i| puts "#{i} = #{wh[i]}"}
|
45
|
+
|
46
|
+
puts "dereferencing objects"
|
47
|
+
ary = nil
|
48
|
+
|
49
|
+
puts "forcing GC"
|
50
|
+
begin
|
51
|
+
require 'java'
|
52
|
+
java.lang.System.gc
|
53
|
+
rescue
|
54
|
+
GC.start
|
55
|
+
end
|
56
|
+
|
57
|
+
puts "all items in weak id hash:"
|
58
|
+
ids.each {|i| puts "#{i} = #{wh[i]}"}
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'ant'
|
2
|
+
|
3
|
+
directory "pkg/classes"
|
4
|
+
|
5
|
+
task :clean do
|
6
|
+
rm_rf "pkg/classes"
|
7
|
+
rm_rf "lib/refqueue.jar"
|
8
|
+
end
|
9
|
+
|
10
|
+
task :compile => "pkg/classes" do |t|
|
11
|
+
ant.javac :srcdir => "ext", :destdir => t.prerequisites.first,
|
12
|
+
:source => "1.5", :target => "1.5", :debug => true,
|
13
|
+
:classpath => "${java.class.path}:${sun.boot.class.path}"
|
14
|
+
end
|
15
|
+
|
16
|
+
task :jar => :compile do
|
17
|
+
ant.jar :basedir => "pkg/classes", :destfile => "lib/refqueue.jar", :includes => "**/*.class"
|
18
|
+
end
|
19
|
+
|
20
|
+
task :package => :jar
|
data/examples/id_hash.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'weakling'
|
2
|
+
|
3
|
+
wh = WeakRef::IdHash.new
|
4
|
+
|
5
|
+
ary = (1..10).to_a.map {Object.new}
|
6
|
+
ids = ary.map {|o| wh.add(o)}
|
7
|
+
|
8
|
+
puts "all items in weak_id_hash:"
|
9
|
+
ids.each {|i| puts "#{i} = #{wh[i]}"}
|
10
|
+
|
11
|
+
puts "dereferencing objects"
|
12
|
+
ary = nil
|
13
|
+
|
14
|
+
puts "forcing GC"
|
15
|
+
begin
|
16
|
+
require 'java'
|
17
|
+
java.lang.System.gc
|
18
|
+
rescue LoadError
|
19
|
+
# not on JRuby, use GC.start
|
20
|
+
GC.start
|
21
|
+
end
|
22
|
+
|
23
|
+
puts "all items in weak id hash:"
|
24
|
+
ids.each {|i| puts "#{i} = #{wh[i]}"}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'weakling'
|
2
|
+
require 'java'
|
3
|
+
|
4
|
+
q = WeakRef::RefQueue.new
|
5
|
+
wr = WeakRef.new(Object.new, q)
|
6
|
+
puts "weakref object: #{wr.__id__}"
|
7
|
+
|
8
|
+
puts "running GC"
|
9
|
+
java.lang.System.gc
|
10
|
+
|
11
|
+
puts "weakref alive?: #{wr.weakref_alive?}"
|
12
|
+
puts "weakref object from queue: #{q.poll.__id__}"
|
13
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import java.io.IOException;
|
2
|
+
|
3
|
+
import org.jruby.Ruby;
|
4
|
+
import org.jruby.runtime.load.BasicLibraryService;
|
5
|
+
|
6
|
+
public class RefqueueService implements BasicLibraryService {
|
7
|
+
public boolean basicLoad(final Ruby runtime) throws IOException {
|
8
|
+
new org.jruby.ext.RefQueueLibrary().load(runtime, false);
|
9
|
+
return true;
|
10
|
+
}
|
11
|
+
}
|
12
|
+
|
@@ -0,0 +1,173 @@
|
|
1
|
+
package org.jruby.ext;
|
2
|
+
|
3
|
+
import java.io.IOException;
|
4
|
+
import java.lang.ref.ReferenceQueue;
|
5
|
+
import java.lang.ref.WeakReference;
|
6
|
+
import org.jruby.Ruby;
|
7
|
+
import org.jruby.RubyClass;
|
8
|
+
import org.jruby.RubyException;
|
9
|
+
import org.jruby.RubyKernel;
|
10
|
+
import org.jruby.RubyObject;
|
11
|
+
import org.jruby.anno.JRubyMethod;
|
12
|
+
import org.jruby.anno.JRubyClass;
|
13
|
+
import org.jruby.exceptions.RaiseException;
|
14
|
+
import org.jruby.javasupport.util.RuntimeHelpers;
|
15
|
+
import org.jruby.runtime.Block;
|
16
|
+
import org.jruby.runtime.ObjectAllocator;
|
17
|
+
import org.jruby.runtime.ThreadContext;
|
18
|
+
import org.jruby.runtime.Visibility;
|
19
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
20
|
+
import org.jruby.runtime.load.Library;
|
21
|
+
|
22
|
+
/**
|
23
|
+
* This library adds reference queue support to JRuby's weakrefs by adding a
|
24
|
+
* RefQueue class that wraps a Java ReferenceQueue and replacing the built-in
|
25
|
+
* WeakRef impl with a new one that's aware of RefQueue.
|
26
|
+
*
|
27
|
+
* @author headius
|
28
|
+
*/
|
29
|
+
public class RefQueueLibrary implements Library {
|
30
|
+
public void load(Ruby runtime, boolean wrap) throws IOException {
|
31
|
+
RubyKernel.require(runtime.getKernel(), runtime.newString("weakref"), Block.NULL_BLOCK);
|
32
|
+
|
33
|
+
RubyClass weakrefClass = (RubyClass)runtime.getClassFromPath("WeakRef");
|
34
|
+
weakrefClass.setAllocator(WEAKREF_ALLOCATOR);
|
35
|
+
weakrefClass.defineAnnotatedMethods(WeakRef.class);
|
36
|
+
|
37
|
+
RubyClass refQueueClass = runtime.defineClassUnder("RefQueue", runtime.getObject(), REFQUEUE_ALLOCATOR, weakrefClass);
|
38
|
+
refQueueClass.defineAnnotatedMethods(RefQueue.class);
|
39
|
+
}
|
40
|
+
|
41
|
+
private static final ObjectAllocator WEAKREF_ALLOCATOR = new ObjectAllocator() {
|
42
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
43
|
+
return new WeakRef(runtime, klazz);
|
44
|
+
}
|
45
|
+
};
|
46
|
+
|
47
|
+
private static final ObjectAllocator REFQUEUE_ALLOCATOR = new ObjectAllocator() {
|
48
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
49
|
+
return new RefQueue(runtime, klazz);
|
50
|
+
}
|
51
|
+
};
|
52
|
+
|
53
|
+
@JRubyClass(name="RefQueue", parent="Object")
|
54
|
+
public static class RefQueue extends RubyObject {
|
55
|
+
private final ReferenceQueue queue;
|
56
|
+
|
57
|
+
public RefQueue(Ruby runtime, RubyClass klass) {
|
58
|
+
super(runtime, klass);
|
59
|
+
queue = new ReferenceQueue();
|
60
|
+
}
|
61
|
+
|
62
|
+
public ReferenceQueue getQueue() {
|
63
|
+
return queue;
|
64
|
+
}
|
65
|
+
|
66
|
+
@JRubyMethod
|
67
|
+
public IRubyObject poll() {
|
68
|
+
return returnable(queue.poll());
|
69
|
+
}
|
70
|
+
|
71
|
+
@JRubyMethod
|
72
|
+
public IRubyObject remove() {
|
73
|
+
try {
|
74
|
+
return returnable(queue.remove());
|
75
|
+
} catch (InterruptedException ie) {
|
76
|
+
// ignore
|
77
|
+
return getRuntime().getNil();
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
@JRubyMethod
|
82
|
+
public IRubyObject remove(IRubyObject timeout) {
|
83
|
+
try {
|
84
|
+
return returnable(queue.remove(timeout.convertToInteger().getLongValue()));
|
85
|
+
} catch (InterruptedException ie) {
|
86
|
+
// ignore
|
87
|
+
return getRuntime().getNil();
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
private IRubyObject returnable(Object result) {
|
92
|
+
RubyWeakReference ref = (RubyWeakReference)result;
|
93
|
+
if (ref == null) return getRuntime().getNil();
|
94
|
+
return ref.getWeakRef();
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
public static class RubyWeakReference extends WeakReference<IRubyObject> {
|
99
|
+
private final WeakRef ref;
|
100
|
+
public RubyWeakReference(IRubyObject obj, WeakRef ref) {
|
101
|
+
super(obj);
|
102
|
+
this.ref = ref;
|
103
|
+
}
|
104
|
+
public RubyWeakReference(IRubyObject obj, WeakRef ref, ReferenceQueue queue) {
|
105
|
+
super(obj, queue);
|
106
|
+
this.ref = ref;
|
107
|
+
}
|
108
|
+
public WeakRef getWeakRef() {
|
109
|
+
return ref;
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
public static class WeakRef extends RubyObject {
|
114
|
+
private RubyWeakReference ref;
|
115
|
+
|
116
|
+
public WeakRef(Ruby runtime, RubyClass klazz) {
|
117
|
+
super(runtime, klazz);
|
118
|
+
}
|
119
|
+
|
120
|
+
@JRubyMethod(name = "__getobj__")
|
121
|
+
public IRubyObject getobj() {
|
122
|
+
IRubyObject obj = ref.get();
|
123
|
+
|
124
|
+
if (obj == null) {
|
125
|
+
// FIXME weakref.rb also does caller(2) here for the backtrace
|
126
|
+
throw newRefError("Illegal Reference - probably recycled");
|
127
|
+
}
|
128
|
+
|
129
|
+
return obj;
|
130
|
+
}
|
131
|
+
|
132
|
+
// This is only here to replace the "new" in JRuby's weakref, which
|
133
|
+
// doesn't really need to be there.
|
134
|
+
@JRubyMethod(name = "new", required = 1, optional = 1, meta = true)
|
135
|
+
public static IRubyObject newInstance(IRubyObject clazz, IRubyObject[] args) {
|
136
|
+
WeakRef weakRef = (WeakRef)((RubyClass)clazz).allocate();
|
137
|
+
|
138
|
+
weakRef.callInit(args, Block.NULL_BLOCK);
|
139
|
+
|
140
|
+
return weakRef;
|
141
|
+
}
|
142
|
+
|
143
|
+
@JRubyMethod(name = "initialize", frame = true, visibility = Visibility.PRIVATE)
|
144
|
+
public IRubyObject initialize(ThreadContext context, IRubyObject obj) {
|
145
|
+
ref = new RubyWeakReference(obj, this);
|
146
|
+
|
147
|
+
return RuntimeHelpers.invokeSuper(context, this, obj, Block.NULL_BLOCK);
|
148
|
+
}
|
149
|
+
|
150
|
+
@JRubyMethod(name = "initialize", frame = true, visibility = Visibility.PRIVATE)
|
151
|
+
public IRubyObject initialize(ThreadContext context, IRubyObject obj, IRubyObject queue) {
|
152
|
+
if (!(queue instanceof RefQueue)) {
|
153
|
+
throw getRuntime().newTypeError("WeakRef can only queue into a RefQueue");
|
154
|
+
}
|
155
|
+
ref = new RubyWeakReference(obj, this, ((RefQueue)queue).getQueue());
|
156
|
+
|
157
|
+
return RuntimeHelpers.invokeSuper(context, this, obj, Block.NULL_BLOCK);
|
158
|
+
}
|
159
|
+
|
160
|
+
@JRubyMethod(name = "weakref_alive?")
|
161
|
+
public IRubyObject weakref_alive_p() {
|
162
|
+
return ref.get() != null ? getRuntime().getTrue() : getRuntime().getFalse();
|
163
|
+
}
|
164
|
+
|
165
|
+
private RaiseException newRefError(String message) {
|
166
|
+
RubyException exception =
|
167
|
+
(RubyException)getRuntime().getClass("RefError").newInstance(getRuntime().getCurrentContext(),
|
168
|
+
new IRubyObject[] {getRuntime().newString(message)}, Block.NULL_BLOCK);
|
169
|
+
|
170
|
+
return new RaiseException(exception);
|
171
|
+
}
|
172
|
+
}
|
173
|
+
}
|
data/lib/refqueue.jar
ADDED
Binary file
|
data/lib/weakling.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'weakref'
|
2
|
+
require 'refqueue'
|
3
|
+
|
4
|
+
class WeakRef::IdHash
|
5
|
+
def initialize
|
6
|
+
@hash = Hash.new
|
7
|
+
@queue = WeakRef::RefQueue.new
|
8
|
+
end
|
9
|
+
|
10
|
+
class IdWeakRef < WeakRef
|
11
|
+
attr_accessor :id
|
12
|
+
def initialize(obj, queue)
|
13
|
+
super(obj, queue)
|
14
|
+
@id = obj.__id__
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](id)
|
19
|
+
_cleanup
|
20
|
+
if wr = @hash[id]
|
21
|
+
return wr.__getobj__ rescue nil
|
22
|
+
end
|
23
|
+
|
24
|
+
return nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def add(object)
|
28
|
+
_cleanup
|
29
|
+
wr = IdWeakRef.new(object, @queue)
|
30
|
+
|
31
|
+
@hash[wr.id] = wr
|
32
|
+
|
33
|
+
return wr.id
|
34
|
+
end
|
35
|
+
|
36
|
+
def _cleanup
|
37
|
+
while ref = @queue.poll
|
38
|
+
@hash.delete(ref.id)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/weakling.gemspec
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{weakling}
|
5
|
+
s.version = "0.0.1"
|
6
|
+
s.authors = ["Charles Oliver Nutter"]
|
7
|
+
s.date = Time.now.strftime('YYYY-MM-DD')
|
8
|
+
s.description = "A modified WeakRef impl for JRuby plus some weakref-related tools"
|
9
|
+
s.email = ["headius@headius.com"]
|
10
|
+
s.files = Dir['{lib,ext,examples,test}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}']
|
11
|
+
s.homepage = "http://github.com/headius/weakling"
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.summary = "A modified WeakRef impl for JRuby plus some weakref-related tools"
|
14
|
+
s.test_files = Dir["test/test*.rb"]
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: weakling
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Charles Oliver Nutter
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-03-11 18:25:16.468000 -06:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: A modified WeakRef impl for JRuby plus some weakref-related tools
|
22
|
+
email:
|
23
|
+
- headius@headius.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- lib/refqueue.jar
|
32
|
+
- lib/weakling.rb
|
33
|
+
- lib/weakling/collections.rb
|
34
|
+
- ext/RefqueueService.java
|
35
|
+
- ext/org/jruby/ext/RefQueueLibrary.java
|
36
|
+
- examples/id_hash.rb
|
37
|
+
- examples/refqueue_use.rb
|
38
|
+
- README.txt
|
39
|
+
- weakling.gemspec
|
40
|
+
- Rakefile
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://github.com/headius/weakling
|
43
|
+
licenses: []
|
44
|
+
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.3.6
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: A modified WeakRef impl for JRuby plus some weakref-related tools
|
71
|
+
test_files: []
|
72
|
+
|