weakling 0.0.4-java
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/HISTORY.txt +16 -0
- data/README.txt +60 -0
- data/Rakefile +28 -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 +164 -0
- data/lib/refqueue.jar +0 -0
- data/lib/weakling.rb +2 -0
- data/lib/weakling/collections.rb +48 -0
- data/weakling.gemspec +16 -0
- metadata +75 -0
data/HISTORY.txt
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
== 0.0.3 ==
|
2
|
+
|
3
|
+
* Moved all classes under Weakling module
|
4
|
+
* WeakRef no longer extends Delegate
|
5
|
+
* WeakRef#__getobj__ is now just #get
|
6
|
+
* IdHash now includes Enumerable
|
7
|
+
* Added specs for most behavior
|
8
|
+
|
9
|
+
== 0.0.2 ==
|
10
|
+
|
11
|
+
* Minor compatibility tweak for the WeakRef replacement impl, to match JRuby
|
12
|
+
|
13
|
+
== 0.0.1 ==
|
14
|
+
|
15
|
+
* Initial release
|
16
|
+
* RefQueue and IdHash support
|
data/README.txt
ADDED
@@ -0,0 +1,60 @@
|
|
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
|
+
The weakling repository is at http://github.com/headius/weakling.
|
15
|
+
|
16
|
+
== Usage ==
|
17
|
+
|
18
|
+
Just require 'weakling'. It will require 'weakref' along with the refqueue JRuby
|
19
|
+
extension and the weakling/collections library containing the weak id hash.
|
20
|
+
|
21
|
+
== RefQueue Example ==
|
22
|
+
|
23
|
+
require 'weakling'
|
24
|
+
require 'java'
|
25
|
+
|
26
|
+
q = WeakRef::RefQueue.new
|
27
|
+
wr = WeakRef.new(Object.new, q)
|
28
|
+
puts "weakref object: #{wr.__id__}"
|
29
|
+
|
30
|
+
puts "running GC"
|
31
|
+
java.lang.System.gc
|
32
|
+
|
33
|
+
puts "weakref alive?: #{wr.weakref_alive?}"
|
34
|
+
puts "weakref object from queue: #{q.poll.__id__}"
|
35
|
+
|
36
|
+
== WeakRef::IdHash Example ==
|
37
|
+
|
38
|
+
require 'weakling'
|
39
|
+
|
40
|
+
wh = WeakRef::IdHash.new
|
41
|
+
|
42
|
+
ary = (1..10).to_a.map {Object.new}
|
43
|
+
ids = ary.map {|o| wh.add(o)}
|
44
|
+
|
45
|
+
puts "all items in weak_id_hash:"
|
46
|
+
ids.each {|i| puts "#{i} = #{wh[i]}"}
|
47
|
+
|
48
|
+
puts "dereferencing objects"
|
49
|
+
ary = nil
|
50
|
+
|
51
|
+
puts "forcing GC"
|
52
|
+
begin
|
53
|
+
require 'java'
|
54
|
+
java.lang.System.gc
|
55
|
+
rescue
|
56
|
+
GC.start
|
57
|
+
end
|
58
|
+
|
59
|
+
puts "all items in weak id hash:"
|
60
|
+
ids.each {|i| puts "#{i} = #{wh[i]}"}
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'ant'
|
2
|
+
|
3
|
+
directory "pkg/classes"
|
4
|
+
|
5
|
+
desc "Clean up build artifacts"
|
6
|
+
task :clean do
|
7
|
+
rm_rf "pkg/classes"
|
8
|
+
rm_rf "lib/refqueue.jar"
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "Compile the extension"
|
12
|
+
task :compile => "pkg/classes" do |t|
|
13
|
+
ant.javac :srcdir => "ext", :destdir => t.prerequisites.first,
|
14
|
+
:source => "1.5", :target => "1.5", :debug => true,
|
15
|
+
:classpath => "${java.class.path}:${sun.boot.class.path}"
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Build the jar"
|
19
|
+
task :jar => :compile do
|
20
|
+
ant.jar :basedir => "pkg/classes", :destfile => "lib/refqueue.jar", :includes => "**/*.class"
|
21
|
+
end
|
22
|
+
|
23
|
+
task :package => :jar
|
24
|
+
|
25
|
+
desc "Run the specs"
|
26
|
+
task :spec => :jar do
|
27
|
+
ruby "-S", "spec", "spec"
|
28
|
+
end
|
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,164 @@
|
|
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.RubyModule;
|
11
|
+
import org.jruby.RubyObject;
|
12
|
+
import org.jruby.anno.JRubyMethod;
|
13
|
+
import org.jruby.anno.JRubyClass;
|
14
|
+
import org.jruby.exceptions.RaiseException;
|
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
|
+
// only used for RefError
|
32
|
+
RubyKernel.require(runtime.getKernel(), runtime.newString("weakref"), Block.NULL_BLOCK);
|
33
|
+
|
34
|
+
RubyModule weaklingModule = runtime.getOrCreateModule("Weakling");
|
35
|
+
RubyClass weakrefClass = runtime.defineClassUnder("WeakRef", runtime.getObject(), WEAKREF_ALLOCATOR, weaklingModule);
|
36
|
+
weakrefClass.setAllocator(WEAKREF_ALLOCATOR);
|
37
|
+
weakrefClass.defineAnnotatedMethods(WeakRef.class);
|
38
|
+
|
39
|
+
RubyClass refQueueClass = runtime.defineClassUnder("RefQueue", runtime.getObject(), REFQUEUE_ALLOCATOR, weaklingModule);
|
40
|
+
refQueueClass.defineAnnotatedMethods(RefQueue.class);
|
41
|
+
}
|
42
|
+
|
43
|
+
private static final ObjectAllocator WEAKREF_ALLOCATOR = new ObjectAllocator() {
|
44
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
45
|
+
return new WeakRef(runtime, klazz);
|
46
|
+
}
|
47
|
+
};
|
48
|
+
|
49
|
+
private static final ObjectAllocator REFQUEUE_ALLOCATOR = new ObjectAllocator() {
|
50
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
51
|
+
return new RefQueue(runtime, klazz);
|
52
|
+
}
|
53
|
+
};
|
54
|
+
|
55
|
+
@JRubyClass(name="RefQueue", parent="Object")
|
56
|
+
public static class RefQueue extends RubyObject {
|
57
|
+
private final ReferenceQueue queue;
|
58
|
+
|
59
|
+
public RefQueue(Ruby runtime, RubyClass klass) {
|
60
|
+
super(runtime, klass);
|
61
|
+
queue = new ReferenceQueue();
|
62
|
+
}
|
63
|
+
|
64
|
+
public ReferenceQueue getQueue() {
|
65
|
+
return queue;
|
66
|
+
}
|
67
|
+
|
68
|
+
@JRubyMethod
|
69
|
+
public IRubyObject poll() {
|
70
|
+
return returnable(queue.poll());
|
71
|
+
}
|
72
|
+
|
73
|
+
@JRubyMethod
|
74
|
+
public IRubyObject remove() {
|
75
|
+
try {
|
76
|
+
return returnable(queue.remove());
|
77
|
+
} catch (InterruptedException ie) {
|
78
|
+
// ignore
|
79
|
+
return getRuntime().getNil();
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
@JRubyMethod
|
84
|
+
public IRubyObject remove(IRubyObject timeout) {
|
85
|
+
try {
|
86
|
+
return returnable(queue.remove(timeout.convertToInteger().getLongValue()));
|
87
|
+
} catch (InterruptedException ie) {
|
88
|
+
// ignore
|
89
|
+
return getRuntime().getNil();
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
private IRubyObject returnable(Object result) {
|
94
|
+
RubyWeakReference ref = (RubyWeakReference)result;
|
95
|
+
if (ref == null) return getRuntime().getNil();
|
96
|
+
return ref.getWeakRef();
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
public static class RubyWeakReference extends WeakReference<IRubyObject> {
|
101
|
+
private final WeakRef ref;
|
102
|
+
public RubyWeakReference(IRubyObject obj, WeakRef ref) {
|
103
|
+
super(obj);
|
104
|
+
this.ref = ref;
|
105
|
+
}
|
106
|
+
public RubyWeakReference(IRubyObject obj, WeakRef ref, ReferenceQueue queue) {
|
107
|
+
super(obj, queue);
|
108
|
+
this.ref = ref;
|
109
|
+
}
|
110
|
+
public WeakRef getWeakRef() {
|
111
|
+
return ref;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
public static class WeakRef extends RubyObject {
|
116
|
+
private RubyWeakReference ref;
|
117
|
+
|
118
|
+
public WeakRef(Ruby runtime, RubyClass klazz) {
|
119
|
+
super(runtime, klazz);
|
120
|
+
}
|
121
|
+
|
122
|
+
@JRubyMethod(name = "get")
|
123
|
+
public IRubyObject get() {
|
124
|
+
IRubyObject obj = ref.get();
|
125
|
+
|
126
|
+
if (obj == null) {
|
127
|
+
// FIXME weakref.rb also does caller(2) here for the backtrace
|
128
|
+
throw newRefError("Illegal Reference - probably recycled");
|
129
|
+
}
|
130
|
+
|
131
|
+
return obj;
|
132
|
+
}
|
133
|
+
|
134
|
+
@JRubyMethod(name = "initialize", frame = true, visibility = Visibility.PRIVATE)
|
135
|
+
public IRubyObject initialize(ThreadContext context, IRubyObject obj) {
|
136
|
+
ref = new RubyWeakReference(obj, this);
|
137
|
+
|
138
|
+
return context.getRuntime().getNil();
|
139
|
+
}
|
140
|
+
|
141
|
+
@JRubyMethod(name = "initialize", frame = true, visibility = Visibility.PRIVATE)
|
142
|
+
public IRubyObject initialize(ThreadContext context, IRubyObject obj, IRubyObject queue) {
|
143
|
+
if (!(queue instanceof RefQueue)) {
|
144
|
+
throw getRuntime().newTypeError("WeakRef can only queue into a RefQueue");
|
145
|
+
}
|
146
|
+
ref = new RubyWeakReference(obj, this, ((RefQueue)queue).getQueue());
|
147
|
+
|
148
|
+
return context.getRuntime().getNil();
|
149
|
+
}
|
150
|
+
|
151
|
+
@JRubyMethod(name = "weakref_alive?")
|
152
|
+
public IRubyObject weakref_alive_p() {
|
153
|
+
return ref.get() != null ? getRuntime().getTrue() : getRuntime().getFalse();
|
154
|
+
}
|
155
|
+
|
156
|
+
private RaiseException newRefError(String message) {
|
157
|
+
RubyException exception =
|
158
|
+
(RubyException)getRuntime().getClass("RefError").newInstance(getRuntime().getCurrentContext(),
|
159
|
+
new IRubyObject[] {getRuntime().newString(message)}, Block.NULL_BLOCK);
|
160
|
+
|
161
|
+
return new RaiseException(exception);
|
162
|
+
}
|
163
|
+
}
|
164
|
+
}
|
data/lib/refqueue.jar
ADDED
Binary file
|
data/lib/weakling.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'refqueue'
|
2
|
+
|
3
|
+
module Weakling
|
4
|
+
class IdHash
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@hash = Hash.new
|
9
|
+
@queue = Weakling::RefQueue.new
|
10
|
+
end
|
11
|
+
|
12
|
+
class IdWeakRef < Weakling::WeakRef
|
13
|
+
attr_accessor :id
|
14
|
+
def initialize(obj, queue)
|
15
|
+
super(obj, queue)
|
16
|
+
@id = obj.__id__
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](id)
|
21
|
+
_cleanup
|
22
|
+
if wr = @hash[id]
|
23
|
+
return wr.get rescue nil
|
24
|
+
end
|
25
|
+
|
26
|
+
return nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def add(object)
|
30
|
+
_cleanup
|
31
|
+
wr = IdWeakRef.new(object, @queue)
|
32
|
+
|
33
|
+
@hash[wr.id] = wr
|
34
|
+
|
35
|
+
return wr.id
|
36
|
+
end
|
37
|
+
|
38
|
+
def _cleanup
|
39
|
+
while ref = @queue.poll
|
40
|
+
@hash.delete(ref.id)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def each
|
45
|
+
@hash.each {|id, wr| obj = wr.get rescue nil; yield [id,obj] if obj}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/weakling.gemspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{weakling}
|
5
|
+
s.version = "0.0.4"
|
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
|
+
s.platform = "java"
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: weakling
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 4
|
9
|
+
version: 0.0.4
|
10
|
+
platform: java
|
11
|
+
authors:
|
12
|
+
- Charles Oliver Nutter
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-06-03 18:51:00.994000 -05: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
|
+
- HISTORY.txt
|
39
|
+
- README.txt
|
40
|
+
- weakling.gemspec
|
41
|
+
- Rakefile
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: http://github.com/headius/weakling
|
44
|
+
licenses: []
|
45
|
+
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
segments:
|
57
|
+
- 0
|
58
|
+
version: "0"
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
segments:
|
65
|
+
- 0
|
66
|
+
version: "0"
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.3.7
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: A modified WeakRef impl for JRuby plus some weakref-related tools
|
74
|
+
test_files: []
|
75
|
+
|