wref 0.0.6 → 0.0.7

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,50 @@
1
+ class Wref::Implementations::IdClassUnique
2
+ def initialize(object)
3
+ @id = object.__id__
4
+ @class_name = object.class.name.to_sym
5
+ ObjectSpace.define_finalizer(object, method(:destroy))
6
+ @unique_id = object.__wref_unique_id__ if object.respond_to?(:__wref_unique_id__)
7
+ end
8
+
9
+ def get!
10
+ object = get
11
+ raise ::Wref::Recycled unless object
12
+ return object
13
+ end
14
+
15
+ def get
16
+ return nil if !@class_name || !@id
17
+ object = ObjectSpace._id2ref(@id)
18
+
19
+ #Some times this class-name will be nil for some reason - knj
20
+ object_class_name = object.class.name
21
+
22
+ if !object_class_name || @class_name != object_class_name.to_sym || @id != object.__id__
23
+ destroy
24
+ return nil
25
+ end
26
+
27
+ if @unique_id
28
+ destroy
29
+ return nil if !object.respond_to?(:__wref_unique_id__) || object.__wref_unique_id__ != @unique_id
30
+ end
31
+
32
+ return object
33
+ end
34
+
35
+ def alive?
36
+ if get
37
+ return true
38
+ else
39
+ return false
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def destroy(*args)
46
+ @id = nil
47
+ @class_name = nil
48
+ @unique_id = nil
49
+ end
50
+ end
@@ -0,0 +1,26 @@
1
+ class Wref::Implementations::JavaWeakReference
2
+ def initialize(object)
3
+ require "java"
4
+ @weakref = java.lang.ref.WeakReference.new(object)
5
+ end
6
+
7
+ def get
8
+ return @weakref.get
9
+ end
10
+
11
+ def get!
12
+ object = @weakref.get
13
+ raise Wref::Recycled if object == nil
14
+ return object
15
+ end
16
+
17
+ def alive?
18
+ object = @weakref.get
19
+
20
+ if object == nil
21
+ return false
22
+ else
23
+ return true
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ class Wref::Implementations::Ref
2
+ def initialize(object)
3
+ require "ref"
4
+ @ref = ::Ref::WeakReference.new(object)
5
+ end
6
+
7
+ def get
8
+ @ref.object
9
+ end
10
+
11
+ def get!
12
+ object = @ref.object
13
+ raise Wref::Recycled unless object
14
+ return object
15
+ end
16
+
17
+ def alive?
18
+ if @ref.object
19
+ return true
20
+ else
21
+ return false
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,53 @@
1
+ class Wref::Implementations::WeakRef
2
+ def initialize(object)
3
+ require "weakref"
4
+ @id = object.__id__
5
+ @class_name = object.class.name.to_sym
6
+ @weak_ref = ::WeakRef.new(object)
7
+ ObjectSpace.define_finalizer(object, method(:destroy))
8
+ end
9
+
10
+ def get
11
+ return nil unless @id
12
+
13
+ begin
14
+ object = @weak_ref.__getobj__
15
+ rescue WeakRef::RefError
16
+ destroy
17
+ return nil
18
+ end
19
+
20
+ object_class_name = object.class.name
21
+
22
+ if !object_class_name || @class_name != object_class_name.to_sym || @id != object.__id__
23
+ destroy
24
+ return nil
25
+ end
26
+
27
+ return object
28
+ end
29
+
30
+ def get!
31
+ if object = get
32
+ return object
33
+ else
34
+ raise Wref::Recycled
35
+ end
36
+ end
37
+
38
+ def alive?
39
+ if @weak_ref.weakref_alive? && get
40
+ return true
41
+ else
42
+ return false
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def destroy(*args)
49
+ @id = nil
50
+ @class_name = nil
51
+ @unique_id = nil
52
+ end
53
+ end
@@ -0,0 +1,31 @@
1
+ class Wref::Implementations::Weakling
2
+ def initialize(object)
3
+ require "weakling"
4
+ @weak_ref = ::Weakling::WeakRef.new(object)
5
+ end
6
+
7
+ def get
8
+ begin
9
+ @weak_ref.get
10
+ rescue ::WeakRef::RefError, ::Java::JavaLang::NullPointerException
11
+ return nil
12
+ end
13
+ end
14
+
15
+ def get!
16
+ begin
17
+ @weak_ref.get
18
+ rescue ::WeakRef::RefError, ::Java::JavaLang::NullPointerException
19
+ raise Wref::Recycled
20
+ end
21
+ end
22
+
23
+ def alive?
24
+ begin
25
+ @weak_ref.get
26
+ return true
27
+ rescue ::WeakRef::RefError, ::Java::JavaLang::NullPointerException
28
+ return false
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,175 @@
1
+ #A weak hash-map.
2
+ #===Examples
3
+ # map = Wref::Map.new
4
+ # map[1] = obj
5
+ # obj = nil
6
+ #
7
+ # sleep 0.5
8
+ #
9
+ # begin
10
+ # obj = map[1]
11
+ # print "Object still exists in memory."
12
+ # rescue Wref::Recycled
13
+ # print "Object has been garbage-collected."
14
+ # end
15
+ #
16
+ # obj = map.get(1)
17
+ # print "Object still exists in memory." if obj
18
+ class Wref::Map
19
+ def initialize(args = {})
20
+ require "monitor"
21
+
22
+ @map = {}
23
+ @mutex = Monitor.new
24
+ @impl = args[:impl]
25
+ end
26
+
27
+ #Sets a new object in the map with a given ID.
28
+ def set(id, obj)
29
+ wref = Wref.new(obj, impl: @impl)
30
+
31
+ @mutex.synchronize do
32
+ @map[id] = wref
33
+ end
34
+
35
+ return nil
36
+ end
37
+
38
+ #Returns an object by ID or raises a RefError.
39
+ #===Examples
40
+ # begin
41
+ # obj = map.get!(1)
42
+ # print "Object still exists in memory."
43
+ # rescue Wref::Recycled
44
+ # print "Object has been garbage-collected."
45
+ # end
46
+ def get!(id)
47
+ wref = nil
48
+ @mutex.synchronize do
49
+ raise Wref::Recycled unless @map.key?(id)
50
+ wref = @map[id]
51
+ end
52
+
53
+ if object = wref.get
54
+ return object
55
+ else
56
+ delete(id)
57
+ raise Wref::Recycled
58
+ end
59
+ end
60
+
61
+ #The same as 'get!' but returns nil instead of WeakRef-error. This can be used to avoid writing lots of code.
62
+ #===Examples
63
+ # obj = map.get(1)
64
+ # print "Object still exists in memory." if obj
65
+ def get(id)
66
+ begin
67
+ return get!(id)
68
+ rescue Wref::Recycled
69
+ return nil
70
+ end
71
+ end
72
+
73
+ #Scans the whole map and removes dead references. After the implementation of automatic clean-up by using ObjectSpace.define_finalizer, there should be no reason to call this method.
74
+ def clean
75
+ keys = nil
76
+ @mutex.synchronize do
77
+ keys = @map.keys
78
+ end
79
+
80
+ keys.each do |key|
81
+ begin
82
+ get(key) #this will remove the key if the object no longer exists.
83
+ rescue Wref::Recycled
84
+ #ignore.
85
+ end
86
+ end
87
+
88
+ return nil
89
+ end
90
+
91
+ #Returns true if a given key exists and the object it holds is alive.
92
+ def valid?(key)
93
+ @mutex.synchronize do
94
+ return false unless @map.key?(key)
95
+ end
96
+
97
+ begin
98
+ @map[key].get
99
+ return true
100
+ rescue Wref::Recycled
101
+ return false
102
+ end
103
+ end
104
+
105
+ #Returns true if the given key exists in the hash.
106
+ #===Examples
107
+ # print "Key exists but we dont know if the value has been garbage-collected." if map.key?(1)
108
+ def key?(key)
109
+ @mutex.synchronize do
110
+ if @map.key?(key) && get(key)
111
+ return true
112
+ else
113
+ return false
114
+ end
115
+ end
116
+ end
117
+
118
+ #Returns the length of the hash. This may not be true since invalid objects is also counted.
119
+ def length
120
+ @mutex.synchronize do
121
+ return @map.length
122
+ end
123
+ end
124
+
125
+ #Cleans the hash and returns the length. This is slower but more accurate than the ordinary length that just returns the hash-length.
126
+ def length_valid
127
+ clean
128
+ return length
129
+ end
130
+
131
+ #Deletes a key in the hash.
132
+ def delete(key)
133
+ @mutex.synchronize do
134
+ wref = @map[key]
135
+ object = @map.delete(key)
136
+
137
+ if object
138
+ return object.get
139
+ else
140
+ return nil
141
+ end
142
+ end
143
+ end
144
+
145
+ #Iterates over every valid object in the weak map.
146
+ #===Examples
147
+ # map.each do |obj|
148
+ # puts "Object alive: #{obj}"
149
+ # end
150
+ def each(&block)
151
+ enum = Enumerator.new do |yielder|
152
+ ids = nil
153
+ @mutex.synchronize do
154
+ ids = @map.keys
155
+ end
156
+
157
+ ids.each do |id|
158
+ if obj = get(id)
159
+ yielder << [id, obj]
160
+ end
161
+ end
162
+ end
163
+
164
+ if block
165
+ enum.each(&block)
166
+ else
167
+ return enum
168
+ end
169
+ end
170
+
171
+ #Make it hash-compatible.
172
+ alias has_key? key?
173
+ alias [] get
174
+ alias []= set
175
+ end
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - ruby-head
4
+ - ruby-2.1-head
5
+ - ruby-2.0-head
6
+ - ruby-1.9.3-head
7
+ - ruby-1.9.2-head
8
+ - jruby-head
9
+ script:
10
+ - CODECLIMATE_REPO_TOKEN=23d002ad9b86687a067e6bbc81320cd979ffad756d1be69ca4e24c1038ee19a6 bundle exec rspec
11
+ notifications:
12
+ email: false
@@ -0,0 +1,6 @@
1
+ require "spec_helper"
2
+
3
+ describe Wref::Implementations::IdClassUnique do
4
+ it_should_behave_like "wref" unless RUBY_ENGINE == "jruby"
5
+ it_should_behave_like "map" unless RUBY_ENGINE == "jruby"
6
+ end
@@ -0,0 +1,6 @@
1
+ require "spec_helper"
2
+
3
+ describe Wref::Implementations::JavaWeakReference do
4
+ it_should_behave_like "wref" if RUBY_ENGINE == "jruby"
5
+ it_should_behave_like "map" if RUBY_ENGINE == "jruby"
6
+ end
@@ -0,0 +1,6 @@
1
+ require "spec_helper"
2
+
3
+ describe Wref::Implementations::Ref do
4
+ it_should_behave_like "wref"
5
+ it_should_behave_like "map"
6
+ end
@@ -0,0 +1,6 @@
1
+ require "spec_helper"
2
+
3
+ describe Wref::Implementations::WeakRef do
4
+ it_should_behave_like "wref"
5
+ it_should_behave_like "map"
6
+ end
@@ -0,0 +1,6 @@
1
+ require "spec_helper"
2
+
3
+ describe Wref::Implementations::Weakling do
4
+ it_should_behave_like "wref" if RUBY_ENGINE == "jruby"
5
+ it_should_behave_like "map" if RUBY_ENGINE == "jruby"
6
+ end
@@ -1,12 +1,19 @@
1
+ require "codeclimate-test-reporter"
2
+ CodeClimate::TestReporter.start
3
+
1
4
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
5
  $LOAD_PATH.unshift(File.dirname(__FILE__))
3
- require 'rspec'
4
- require 'wref'
6
+ require "rspec"
7
+ require "wref"
8
+ require "weakling" if RUBY_ENGINE == "jruby"
9
+ require "ref"
5
10
 
6
11
  # Requires supporting files with custom matchers and macros, etc,
7
12
  # in ./support/ and its subdirectories.
8
13
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
14
 
10
15
  RSpec.configure do |config|
11
-
16
+ config.expect_with :rspec do |c|
17
+ c.syntax = [:should, :expect]
18
+ end
12
19
  end
@@ -0,0 +1,33 @@
1
+ module GarbageCollectorHelper
2
+ def force_garbage_collect
3
+ GC.enable
4
+
5
+ sleep 0.01
6
+
7
+ if RUBY_ENGINE == "jruby"
8
+ java.lang.System.gc
9
+ else
10
+ if RUBY_VERSION.start_with?("2")
11
+ GC.start(full_mark: true, immediate_sweep: true)
12
+ else
13
+ GC.start
14
+ end
15
+ end
16
+
17
+ sleep 0.01
18
+
19
+ GC.disable
20
+ end
21
+
22
+ def force_garbage_collection
23
+ force_garbage_collect
24
+
25
+ 10000.times do
26
+ some_str = User.new("User #{Digest::MD5.hexdigest(Time.now.to_f.to_s)}")
27
+ weak_ref = described_class.new(some_str)
28
+ some_str = nil
29
+ end
30
+
31
+ force_garbage_collect
32
+ end
33
+ end