wref 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +8 -4
- data/Gemfile.lock +68 -18
- data/README.md +65 -0
- data/VERSION +1 -1
- data/lib/wref.rb +38 -271
- data/lib/wref/implementations/id_class_unique.rb +50 -0
- data/lib/wref/implementations/java_weak_reference.rb +26 -0
- data/lib/wref/implementations/ref.rb +24 -0
- data/lib/wref/implementations/weak_ref.rb +53 -0
- data/lib/wref/implementations/weakling.rb +31 -0
- data/lib/wref/map.rb +175 -0
- data/shippable.yml +12 -0
- data/spec/implementations/id_class_unique_spec.rb +6 -0
- data/spec/implementations/java_weak_reference_spec.rb +6 -0
- data/spec/implementations/ref_spec.rb +6 -0
- data/spec/implementations/weak_ref_spec.rb +6 -0
- data/spec/implementations/weakling_spec.rb +6 -0
- data/spec/spec_helper.rb +10 -3
- data/spec/support/garbage_collector_helper.rb +33 -0
- data/spec/support/map_collection.rb +87 -0
- data/spec/support/user.rb +8 -0
- data/spec/support/wref_collection.rb +68 -0
- data/spec/wref_spec.rb +5 -63
- data/wref.gemspec +42 -19
- metadata +74 -43
- data/README.rdoc +0 -19
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e9470b819c7b11a7787df0b977af91b0d1a20af2
|
4
|
+
data.tar.gz: 1abbd729851f77a36f5ebe0f8def73d73b5bd8d3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5c6fb6e08a0822a3d8a09b73f1390040b73af795dee23a2921e6600f28be809d6d05c9b321bb7f9b11b715e2f30dbca964b23269ee357da9ec85f447e6096a57
|
7
|
+
data.tar.gz: d5fa295fd268ee4e1f995384ff1c1e850b8c702d23804dd816b646d6775bf8f482e3a694f4ef652281468482813bfca3654050977ab41c0d6ed4f15898ba9f90
|
data/Gemfile
CHANGED
@@ -6,8 +6,12 @@ source "http://rubygems.org"
|
|
6
6
|
# Add dependencies to develop your gem here.
|
7
7
|
# Include everything needed to run rake, tests, features, etc.
|
8
8
|
group :development do
|
9
|
-
gem "rspec", "~> 2.
|
10
|
-
gem "
|
11
|
-
gem "
|
12
|
-
gem "
|
9
|
+
gem "rspec", "~> 3.2.0"
|
10
|
+
gem "bundler", "~> 1.9.2"
|
11
|
+
gem "jeweler", "~> 1.8.8"
|
12
|
+
gem "highline", "~> 1.6.21"
|
13
|
+
gem "weakling"
|
14
|
+
gem "ref"
|
13
15
|
end
|
16
|
+
|
17
|
+
gem "codeclimate-test-reporter", group: :test, require: nil
|
data/Gemfile.lock
CHANGED
@@ -1,31 +1,81 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
addressable (2.3.8)
|
5
|
+
builder (3.2.2)
|
6
|
+
codeclimate-test-reporter (0.4.7)
|
7
|
+
simplecov (>= 0.7.1, < 1.0.0)
|
8
|
+
diff-lcs (1.2.5)
|
9
|
+
docile (1.1.5)
|
10
|
+
faraday (0.8.9)
|
11
|
+
multipart-post (~> 1.2.0)
|
12
|
+
git (1.2.9.1)
|
13
|
+
github_api (0.10.1)
|
14
|
+
addressable
|
15
|
+
faraday (~> 0.8.1)
|
16
|
+
hashie (>= 1.2)
|
17
|
+
multi_json (~> 1.4)
|
18
|
+
nokogiri (~> 1.5.2)
|
19
|
+
oauth2
|
20
|
+
hashie (3.4.1)
|
21
|
+
highline (1.6.21)
|
22
|
+
jeweler (1.8.8)
|
23
|
+
builder
|
7
24
|
bundler (~> 1.0)
|
8
25
|
git (>= 1.2.5)
|
26
|
+
github_api (= 0.10.1)
|
27
|
+
highline (>= 1.6.15)
|
28
|
+
nokogiri (= 1.5.10)
|
9
29
|
rake
|
10
30
|
rdoc
|
11
|
-
json (1.
|
12
|
-
|
13
|
-
|
31
|
+
json (1.8.2)
|
32
|
+
json (1.8.2-java)
|
33
|
+
jwt (1.4.1)
|
34
|
+
multi_json (1.11.0)
|
35
|
+
multi_xml (0.5.5)
|
36
|
+
multipart-post (1.2.0)
|
37
|
+
nokogiri (1.5.10)
|
38
|
+
nokogiri (1.5.10-java)
|
39
|
+
oauth2 (1.0.0)
|
40
|
+
faraday (>= 0.8, < 0.10)
|
41
|
+
jwt (~> 1.0)
|
42
|
+
multi_json (~> 1.3)
|
43
|
+
multi_xml (~> 0.5)
|
44
|
+
rack (~> 1.2)
|
45
|
+
rack (1.6.0)
|
46
|
+
rake (10.4.2)
|
47
|
+
rdoc (4.2.0)
|
14
48
|
json (~> 1.4)
|
15
|
-
|
16
|
-
|
17
|
-
rspec-
|
18
|
-
rspec-
|
19
|
-
|
20
|
-
rspec-
|
21
|
-
|
22
|
-
rspec-
|
49
|
+
ref (1.0.5)
|
50
|
+
rspec (3.2.0)
|
51
|
+
rspec-core (~> 3.2.0)
|
52
|
+
rspec-expectations (~> 3.2.0)
|
53
|
+
rspec-mocks (~> 3.2.0)
|
54
|
+
rspec-core (3.2.2)
|
55
|
+
rspec-support (~> 3.2.0)
|
56
|
+
rspec-expectations (3.2.0)
|
57
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
58
|
+
rspec-support (~> 3.2.0)
|
59
|
+
rspec-mocks (3.2.1)
|
60
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
61
|
+
rspec-support (~> 3.2.0)
|
62
|
+
rspec-support (3.2.2)
|
63
|
+
simplecov (0.9.2)
|
64
|
+
docile (~> 1.1.0)
|
65
|
+
multi_json (~> 1.0)
|
66
|
+
simplecov-html (~> 0.9.0)
|
67
|
+
simplecov-html (0.9.0)
|
68
|
+
weakling (0.0.3)
|
23
69
|
|
24
70
|
PLATFORMS
|
71
|
+
java
|
25
72
|
ruby
|
26
73
|
|
27
74
|
DEPENDENCIES
|
28
|
-
bundler (
|
29
|
-
|
30
|
-
|
31
|
-
|
75
|
+
bundler (~> 1.9.2)
|
76
|
+
codeclimate-test-reporter
|
77
|
+
highline (~> 1.6.21)
|
78
|
+
jeweler (~> 1.8.8)
|
79
|
+
ref
|
80
|
+
rspec (~> 3.2.0)
|
81
|
+
weakling
|
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
[![Build Status](https://api.shippable.com/projects/540e7b9f3479c5ea8f9ec25e/badge?branchName=master)](https://app.shippable.com/projects/540e7b9f3479c5ea8f9ec25e/builds/latest)
|
2
|
+
[![Code Climate](https://codeclimate.com/github/kaspernj/wref/badges/gpa.svg)](https://codeclimate.com/github/kaspernj/wref)
|
3
|
+
[![Test Coverage](https://codeclimate.com/github/kaspernj/wref/badges/coverage.svg)](https://codeclimate.com/github/kaspernj/wref)
|
4
|
+
|
5
|
+
# Wref
|
6
|
+
|
7
|
+
Weak references for Ruby
|
8
|
+
|
9
|
+
## Install
|
10
|
+
|
11
|
+
Add to your Gemfile and bundle
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem "wref"
|
15
|
+
```
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
### Make a new weak reference
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
str = "Test"
|
23
|
+
weak_ref = Wref.new(str)
|
24
|
+
```
|
25
|
+
|
26
|
+
### Check if reference is still alive
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
weak_ref.alive? #=> true | false
|
30
|
+
```
|
31
|
+
|
32
|
+
### Weak map
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
weak_map = Wref::Map.new
|
36
|
+
map[1] = str
|
37
|
+
```
|
38
|
+
|
39
|
+
### Check if key is valid in a weak map.
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
weak_map.valid?(1) #=> true | false
|
43
|
+
```
|
44
|
+
|
45
|
+
### Get from a key
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
weak_map.get(1) #=> "Test" | Error - Wref::Recycled
|
49
|
+
```
|
50
|
+
|
51
|
+
## Contributing to wref
|
52
|
+
|
53
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
54
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
55
|
+
* Fork the project.
|
56
|
+
* Start a feature/bugfix branch.
|
57
|
+
* Commit and push until you are happy with your contribution.
|
58
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
59
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
60
|
+
|
61
|
+
## Copyright
|
62
|
+
|
63
|
+
Copyright (c) 2012 Kasper Johansen. See LICENSE.txt for
|
64
|
+
further details.
|
65
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.7
|
data/lib/wref.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "
|
1
|
+
require "weakref"
|
2
2
|
|
3
3
|
#A simple weak-reference framework with mapping. Only handles the referencing of objects.
|
4
4
|
#===Examples
|
@@ -15,292 +15,59 @@ require "java" if RUBY_ENGINE == "jruby"
|
|
15
15
|
# print "The user has been removed from memory."
|
16
16
|
# end
|
17
17
|
class Wref
|
18
|
-
#
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
18
|
+
#This error is raised when an object in a wref has been garbage-collected.
|
19
|
+
class Recycled < RuntimeError; end
|
20
|
+
|
21
|
+
autoload :Map, "#{File.dirname(__FILE__)}/wref/map"
|
22
|
+
|
23
|
+
class Implementations
|
24
|
+
dir = "#{File.dirname(__FILE__)}/wref/implementations"
|
25
|
+
|
26
|
+
autoload :IdClassUnique, "#{dir}/id_class_unique"
|
27
|
+
autoload :JavaWeakReference, "#{dir}/java_weak_reference"
|
28
|
+
autoload :Ref, "#{dir}/ref"
|
29
|
+
autoload :Weakling, "#{dir}/weakling"
|
30
|
+
autoload :WeakRef, "#{dir}/weak_ref"
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :implementation, :weak_ref
|
34
|
+
|
27
35
|
#Initializes various variables.
|
28
|
-
def initialize(
|
29
|
-
if
|
30
|
-
|
31
|
-
@weakref = WeakRef.new(obj)
|
36
|
+
def initialize(object, args = {})
|
37
|
+
if args[:impl]
|
38
|
+
@implementation = args[:impl]
|
32
39
|
elsif RUBY_ENGINE == "jruby"
|
33
|
-
@
|
40
|
+
@implementation = :JavaWeakReference
|
34
41
|
else
|
35
|
-
@
|
36
|
-
@class_name = obj.class.name.to_sym
|
37
|
-
ObjectSpace.define_finalizer(obj, self.method(:destroy))
|
38
|
-
|
39
|
-
if obj.respond_to?(:__object_unique_id__)
|
40
|
-
@unique_id = obj.__object_unique_id__
|
41
|
-
end
|
42
|
+
@implementation = :IdClassUnique
|
42
43
|
end
|
44
|
+
|
45
|
+
@weak_ref = Wref::Implementations.const_get(implementation).new(object)
|
43
46
|
end
|
44
|
-
|
45
|
-
#Destroyes most variables on the object, releasing memory and returning 'Wref::Recycled' all the time. It takes arguments because it can be called from destructor of the original object. It doesnt use the arguments for anything.
|
46
|
-
def destroy(*args)
|
47
|
-
@id = nil
|
48
|
-
@class_name = nil
|
49
|
-
@unique_id = nil
|
50
|
-
@weakref = nil
|
51
|
-
end
|
52
|
-
|
47
|
+
|
53
48
|
#Returns the object that this weak reference holds or raises Wref::Recycled.
|
54
49
|
# begin
|
55
|
-
#
|
56
|
-
#
|
50
|
+
# object = wref.get!
|
51
|
+
# puts "Object still exists in memory."
|
57
52
|
# rescue Wref::Recycled
|
58
|
-
#
|
53
|
+
# puts "Object has been garbage-collected."
|
59
54
|
# end
|
60
|
-
def get
|
61
|
-
begin
|
62
|
-
if USE_NATIVE_RUBY_IMPLEMENTATION
|
63
|
-
begin
|
64
|
-
return @weakref.__getobj__
|
65
|
-
rescue => e
|
66
|
-
raise Wref::Recycled if e.class.name == "RefError"
|
67
|
-
raise e
|
68
|
-
end
|
69
|
-
elsif RUBY_ENGINE == "jruby"
|
70
|
-
raise Wref::Recycled if !@weakref
|
71
|
-
obj = @weakref.get
|
72
|
-
|
73
|
-
if obj == nil
|
74
|
-
raise Wref::Recycled
|
75
|
-
else
|
76
|
-
return obj
|
77
|
-
end
|
78
|
-
else
|
79
|
-
raise Wref::Recycled if !@class_name or !@id
|
80
|
-
obj = ObjectSpace._id2ref(@id)
|
81
|
-
|
82
|
-
#Some times this class-name will be nil for some reason - knj
|
83
|
-
obj_class_name = obj.class.name
|
84
|
-
|
85
|
-
if !obj_class_name or @class_name != obj_class_name.to_sym or @id != obj.__id__
|
86
|
-
raise Wref::Recycled
|
87
|
-
end
|
88
|
-
|
89
|
-
if @unique_id
|
90
|
-
raise Wref::Recycled if !obj.respond_to?(:__object_unique_id__) or obj.__object_unique_id__ != @unique_id
|
91
|
-
end
|
92
|
-
|
93
|
-
return obj
|
94
|
-
end
|
95
|
-
rescue RangeError, TypeError
|
96
|
-
raise Wref::Recycled
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
#The same as the normal 'get' but returns nil instead of raising Wref::Cycled-error.
|
101
55
|
def get!
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
56
|
+
@weak_ref.get!
|
57
|
+
end
|
58
|
+
|
59
|
+
#The same as the normal 'get!' but returns nil instead of raising Wref::Cycled-error.
|
60
|
+
def get
|
61
|
+
@weak_ref.get
|
107
62
|
end
|
108
|
-
|
63
|
+
|
109
64
|
#Returns true if the reference is still alive.
|
110
65
|
# print "The object still exists in memory." if wref.alive?
|
111
66
|
def alive?
|
112
|
-
|
113
|
-
self.get
|
114
|
-
return true
|
115
|
-
rescue Wref::Recycled
|
116
|
-
return false
|
117
|
-
end
|
67
|
+
@weak_ref.alive?
|
118
68
|
end
|
119
|
-
|
69
|
+
|
120
70
|
#Makes Wref compatible with the normal WeakRef.
|
121
71
|
alias weakref_alive? alive?
|
122
72
|
alias __getobj__ get
|
123
73
|
end
|
124
|
-
|
125
|
-
#A weak hash-map.
|
126
|
-
#===Examples
|
127
|
-
# map = Wref_map.new
|
128
|
-
# map[1] = obj
|
129
|
-
# obj = nil
|
130
|
-
#
|
131
|
-
# sleep 0.5
|
132
|
-
#
|
133
|
-
# begin
|
134
|
-
# obj = map[1]
|
135
|
-
# print "Object still exists in memory."
|
136
|
-
# rescue Wref::Recycled
|
137
|
-
# print "Object has been garbage-collected."
|
138
|
-
# end
|
139
|
-
#
|
140
|
-
# obj = map.get!(1)
|
141
|
-
# print "Object still exists in memory." if obj
|
142
|
-
class Wref_map
|
143
|
-
def initialize(args = nil)
|
144
|
-
@map = {}
|
145
|
-
@ids = {}
|
146
|
-
@mutex = Mutex.new
|
147
|
-
end
|
148
|
-
|
149
|
-
#Sets a new object in the map with a given ID.
|
150
|
-
def set(id, obj)
|
151
|
-
wref = Wref.new(obj)
|
152
|
-
|
153
|
-
@mutex.synchronize do
|
154
|
-
@map[id] = wref
|
155
|
-
@ids[obj.__id__] = id
|
156
|
-
end
|
157
|
-
|
158
|
-
#JRuby cant handle this atm... Dunno why...
|
159
|
-
if RUBY_ENGINE != "jruby"
|
160
|
-
ObjectSpace.define_finalizer(obj, self.method(:delete_by_id))
|
161
|
-
end
|
162
|
-
|
163
|
-
return nil
|
164
|
-
end
|
165
|
-
|
166
|
-
#Returns a object by ID or raises a RefError.
|
167
|
-
#===Examples
|
168
|
-
# begin
|
169
|
-
# obj = map[1]
|
170
|
-
# print "Object still exists in memory."
|
171
|
-
# rescue Wref::Recycled
|
172
|
-
# print "Object has been garbage-collected."
|
173
|
-
# end
|
174
|
-
def get(id)
|
175
|
-
begin
|
176
|
-
wref = nil
|
177
|
-
@mutex.synchronize do
|
178
|
-
raise Wref::Recycled if !@map.key?(id)
|
179
|
-
wref = @map[id]
|
180
|
-
end
|
181
|
-
|
182
|
-
return wref.get
|
183
|
-
rescue Wref::Recycled => e
|
184
|
-
self.delete(id)
|
185
|
-
raise e
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
#The same as 'get' but returns nil instead of WeakRef-error. This can be used to avoid writing lots of code.
|
190
|
-
#===Examples
|
191
|
-
# obj = map.get!(1)
|
192
|
-
# print "Object still exists in memory." if obj
|
193
|
-
def get!(id)
|
194
|
-
begin
|
195
|
-
return self.get(id)
|
196
|
-
rescue Wref::Recycled
|
197
|
-
return nil
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
#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.
|
202
|
-
def clean
|
203
|
-
keys = nil
|
204
|
-
@mutex.synchronize do
|
205
|
-
keys = @map.keys
|
206
|
-
end
|
207
|
-
|
208
|
-
keys.each do |key|
|
209
|
-
begin
|
210
|
-
self.get(key) #this will remove the key if the object no longer exists.
|
211
|
-
rescue Wref::Recycled
|
212
|
-
#ignore.
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
return nil
|
217
|
-
end
|
218
|
-
|
219
|
-
#Returns true if a given key exists and the object it holds is alive.
|
220
|
-
def valid?(key)
|
221
|
-
@mutex.synchronize do
|
222
|
-
return false if !@map.key?(key)
|
223
|
-
end
|
224
|
-
|
225
|
-
begin
|
226
|
-
@map[key].get
|
227
|
-
return true
|
228
|
-
rescue Wref::Recycled
|
229
|
-
return false
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
#Returns true if the given key exists in the hash.
|
234
|
-
#===Examples
|
235
|
-
# print "Key exists but we dont know if the value has been garbage-collected." if map.key?(1)
|
236
|
-
def key?(key)
|
237
|
-
@mutex.synchronize do
|
238
|
-
return @map.key?(key)
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
#Returns the length of the hash. This may not be true since invalid objects is also counted.
|
243
|
-
def length
|
244
|
-
@mutex.synchronize do
|
245
|
-
return @map.length
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
#Cleans the hash and returns the length. This is slower but more accurate than the ordinary length that just returns the hash-length.
|
250
|
-
def length_valid
|
251
|
-
self.clean
|
252
|
-
return self.length
|
253
|
-
end
|
254
|
-
|
255
|
-
#Deletes a key in the hash.
|
256
|
-
def delete(key)
|
257
|
-
@mutex.synchronize do
|
258
|
-
wref = @map[key]
|
259
|
-
@ids.delete(wref.id) if wref
|
260
|
-
@map.delete(key)
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
#This method is supposed to remove objects when finalizer is called by ObjectSpace.
|
265
|
-
def delete_by_id(object_id)
|
266
|
-
@mutex.synchronize do
|
267
|
-
id = @ids[object_id]
|
268
|
-
@map.delete(id)
|
269
|
-
@ids.delete(object_id)
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
#Iterates over every valid object in the weak map.
|
274
|
-
#===Examples
|
275
|
-
# map.each do |obj|
|
276
|
-
# puts "Object alive: #{obj}"
|
277
|
-
# end
|
278
|
-
def each(&block)
|
279
|
-
enum = Enumerator.new do |yielder|
|
280
|
-
ids = nil
|
281
|
-
@mutex.synchronize do
|
282
|
-
ids = @map.keys
|
283
|
-
end
|
284
|
-
|
285
|
-
ids.each do |id|
|
286
|
-
if obj = self.get!(id)
|
287
|
-
yielder << [id, obj]
|
288
|
-
end
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
if block
|
293
|
-
enum.each(&block)
|
294
|
-
else
|
295
|
-
return enum
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
#Make it hash-compatible.
|
300
|
-
alias has_key? key?
|
301
|
-
alias [] get
|
302
|
-
alias []= set
|
303
|
-
end
|
304
|
-
|
305
|
-
#This error is raised when an object in a wref has been garbage-collected.
|
306
|
-
class Wref::Recycled < RuntimeError; end
|