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.
@@ -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]}"}
@@ -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
@@ -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
+ }
Binary file
@@ -0,0 +1,4 @@
1
+ require 'weakref'
2
+ require 'refqueue'
3
+
4
+ require 'weakling/collections.rb'
@@ -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
@@ -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
+