weak_hash 1.0.0
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/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +47 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/lib/rk_weak_hash.rb +42 -0
- data/lib/simple_weak_hash.rb +68 -0
- data/lib/weak_hash.rb +80 -0
- data/scripts/benchmark.rb +61 -0
- data/spec/rk_weak_hash_spec.rb +16 -0
- data/spec/simple_weak_hash_spec.rb +16 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/weak_hash_spec.rb +31 -0
- metadata +104 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Emmanuel Oga
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
= weak_hash
|
2
|
+
|
3
|
+
A Weak Hash is a hash that stores references to objects
|
4
|
+
while retaining the garbage collector's ability to
|
5
|
+
reclaim the object.
|
6
|
+
|
7
|
+
The API is similar to that of a Hash:
|
8
|
+
|
9
|
+
object = Object.new
|
10
|
+
|
11
|
+
wh = WeakHash.new
|
12
|
+
wh["value"] = object
|
13
|
+
|
14
|
+
wh["value"] # => object
|
15
|
+
|
16
|
+
object = nil
|
17
|
+
wh["value"] # => object (if garbage collector has not collected the object yet)
|
18
|
+
|
19
|
+
GC.start; GC.start # very probable that the object is collected now.
|
20
|
+
|
21
|
+
wh["value"] # => nil
|
22
|
+
|
23
|
+
== Credits
|
24
|
+
|
25
|
+
This gem is based on two blog posts by Mauricio Fernández, including code by
|
26
|
+
him and Robert Klemme:
|
27
|
+
|
28
|
+
http://eigenclass.org/hiki/weakhash+and+weakref
|
29
|
+
http://eigenclass.org/hiki/deferred-finalizers-in-Ruby
|
30
|
+
|
31
|
+
I wrapped this on a gem for convenience, replaced a Thread.critical call
|
32
|
+
on SimpleWeakHash with a mutex (for making it work with 1.9) and
|
33
|
+
added some very simple specs.
|
34
|
+
|
35
|
+
== Note on Patches/Pull Requests
|
36
|
+
|
37
|
+
* Fork the project.
|
38
|
+
* Make your feature addition or bug fix.
|
39
|
+
* Add tests for it. This is important so I don't break it in a
|
40
|
+
future version unintentionally.
|
41
|
+
* Commit, do not mess with rakefile, version, or history.
|
42
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
43
|
+
* Send me a pull request. Bonus points for topic branches.
|
44
|
+
|
45
|
+
== Copyright
|
46
|
+
|
47
|
+
Copyright (c) 2010 Emmanuel Oga. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "weak_hash"
|
8
|
+
gem.summary = %Q{Weak Hash implementation}
|
9
|
+
gem.description = %Q{a hash that stores objects until they are garbage collected}
|
10
|
+
gem.email = "EmmanuelOga@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/EmmanuelOga/weak_hash"
|
12
|
+
gem.authors = ["Emmanuel Oga"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
gem.add_development_dependency "yard", ">= 0"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'spec/rake/spectask'
|
23
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
24
|
+
spec.libs << 'lib' << 'spec'
|
25
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
26
|
+
end
|
27
|
+
|
28
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
31
|
+
spec.rcov = true
|
32
|
+
end
|
33
|
+
|
34
|
+
task :spec => :check_dependencies
|
35
|
+
|
36
|
+
task :default => :spec
|
37
|
+
|
38
|
+
begin
|
39
|
+
require 'yard'
|
40
|
+
YARD::Rake::YardocTask.new
|
41
|
+
rescue LoadError
|
42
|
+
task :yardoc do
|
43
|
+
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
44
|
+
end
|
45
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/lib/rk_weak_hash.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# NOTE:
|
2
|
+
# RKWeakHash is based on two blog posts by Mauricio Fernández,
|
3
|
+
# including code by him and Robert Klemme. The RKWeakHash
|
4
|
+
# class is attributed to Robert (hence the RK prefix).
|
5
|
+
|
6
|
+
require 'delegate'
|
7
|
+
require 'weakref'
|
8
|
+
|
9
|
+
RKWeakHash = DelegateClass(Hash)
|
10
|
+
|
11
|
+
# This is a weak hash similar in semantics to SimpleWeakHash but
|
12
|
+
# implemented using the standard libraries 'delegate' and 'weakref'.
|
13
|
+
# In theory using DelegateClass and WeakRef should make this work
|
14
|
+
# slower than the alternative implementation (SimpleWeakHash).
|
15
|
+
class RKWeakHash
|
16
|
+
|
17
|
+
# note: I added this method so I could provide a default value
|
18
|
+
# (a new Hash) instead of demanding it from the user.
|
19
|
+
def initialize(cache = Hash.new)
|
20
|
+
super(cache)
|
21
|
+
end
|
22
|
+
|
23
|
+
def []=(key,val) # !> method redefined; discarding old []=
|
24
|
+
__getobj__[WeakRef.new(key)] = WeakRef.new(val)
|
25
|
+
end
|
26
|
+
|
27
|
+
def [](key) # !> method redefined; discarding old []
|
28
|
+
__getobj__[WeakRef.new(key)]
|
29
|
+
end
|
30
|
+
|
31
|
+
def each(&b) # !> method redefined; discarding old each
|
32
|
+
__getobj__.each do |k,v|
|
33
|
+
b[k.__getobj__, v.__getobj__] unless k.__getobj__.nil?
|
34
|
+
end
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def cleanup
|
39
|
+
delete_if {|k,v| k.__getobj__.nil?}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# NOTE:
|
2
|
+
# SimpleWeakHash is based on two blog posts by Mauricio Fernández,
|
3
|
+
# including code by him and Robert Klemme. SimpleWeakHash was created by
|
4
|
+
# Mauricio Fernández.
|
5
|
+
|
6
|
+
# SimpleWeakHash is a weak hash with more relaxed semantics than a WeakHash:
|
7
|
+
#
|
8
|
+
# * the key->value associations can disappear at any time
|
9
|
+
# * all existent associations are wiped out when the GC kicks in
|
10
|
+
#
|
11
|
+
# In particular, it removes the tacit requirement that an association remain
|
12
|
+
# alive as long as there is an external reference (i.e. outside the hash) to
|
13
|
+
# either the key or the value. The advantage is increased speed.
|
14
|
+
#
|
15
|
+
class SimpleWeakHash
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@valid = false
|
19
|
+
@mutex = Mutex.new
|
20
|
+
end
|
21
|
+
|
22
|
+
# retrieve object with the given key
|
23
|
+
# returns the object if present and it has not been
|
24
|
+
# garbage collected. Otherwise it returns nil.
|
25
|
+
def [](key)
|
26
|
+
__get_hash__[key]
|
27
|
+
end
|
28
|
+
|
29
|
+
# "store" object into the weak hash using the given key
|
30
|
+
# a weak reference is stored so the object stays references
|
31
|
+
# as long as it isn't garbage collected.
|
32
|
+
def []=(key, value)
|
33
|
+
__get_hash__[key] = value
|
34
|
+
end
|
35
|
+
|
36
|
+
# an addition to Mauricio's implementation,
|
37
|
+
# simple method that act's like Hash#update method.
|
38
|
+
def update(hash)
|
39
|
+
hash.each { |key, val| send(:[]=, key, val) }
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# This used to use Thread.critical, but that's no longer available on ruby 1.9
|
46
|
+
# so I replaced it with a Mutex.
|
47
|
+
def __get_hash__
|
48
|
+
@mutex.synchronize do
|
49
|
+
set_internal_hash unless @valid
|
50
|
+
recover_hash
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def recover_hash
|
55
|
+
ObjectSpace._id2ref(@hash_id)
|
56
|
+
rescue RangeError
|
57
|
+
set_internal_hash
|
58
|
+
ObjectSpace._id2ref(@hash_id)
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_internal_hash
|
62
|
+
hash = {}
|
63
|
+
@hash_id = hash.object_id
|
64
|
+
@valid = true
|
65
|
+
ObjectSpace.define_finalizer hash, lambda { |id| @valid = id != @hash_id }
|
66
|
+
hash = nil
|
67
|
+
end
|
68
|
+
end
|
data/lib/weak_hash.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# NOTE:
|
2
|
+
# WeakHash is based on two blog posts by Mauricio Fernández,
|
3
|
+
# including code by him and Robert Klemme. WeakHash was created by
|
4
|
+
# Mauricio Fernández.
|
5
|
+
|
6
|
+
# This is a Hash where an association is removed as soon as either the key or
|
7
|
+
# the value are GCed.
|
8
|
+
#
|
9
|
+
# When storing a value, the key is cloned and used in an internal hash
|
10
|
+
# (the cache) referetting to the object_id of the corresponding value.
|
11
|
+
#
|
12
|
+
class WeakHash
|
13
|
+
|
14
|
+
attr_reader :cache
|
15
|
+
|
16
|
+
def initialize( cache = Hash.new )
|
17
|
+
@cache = cache
|
18
|
+
@key_map = {}
|
19
|
+
@rev_cache = Hash.new{|h,k| h[k] = {}}
|
20
|
+
|
21
|
+
@reclaim_value = lambda do |value_id|
|
22
|
+
if @rev_cache.has_key? value_id
|
23
|
+
@rev_cache[value_id].each_key{|key| @cache.delete key}
|
24
|
+
@rev_cache.delete value_id
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
@reclaim_key = lambda do |key_id|
|
29
|
+
if @key_map.has_key? key_id
|
30
|
+
@cache.delete @key_map[key_id]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# retrieve object with the given key
|
36
|
+
# returns the object if present and it has not been
|
37
|
+
# garbage collected. Otherwise it returns nil.
|
38
|
+
def []( key )
|
39
|
+
value_id = @cache[key]
|
40
|
+
return ObjectSpace._id2ref(value_id) unless value_id.nil?
|
41
|
+
nil
|
42
|
+
rescue RangeError
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
|
46
|
+
# "store" object into the weak hash using the given key
|
47
|
+
# a weak reference is stored so the object stays references
|
48
|
+
# as long as it isn't garbage collected.
|
49
|
+
def []=( key, value )
|
50
|
+
case key
|
51
|
+
when Fixnum, Symbol, true, false
|
52
|
+
key2 = key
|
53
|
+
else
|
54
|
+
key2 = key.dup
|
55
|
+
end
|
56
|
+
|
57
|
+
@rev_cache[value.object_id][key2] = true
|
58
|
+
@cache[key2] = value.object_id
|
59
|
+
@key_map[key.object_id] = key2
|
60
|
+
|
61
|
+
begin
|
62
|
+
ObjectSpace.define_finalizer(value, @reclaim_value)
|
63
|
+
rescue ArgumentError
|
64
|
+
# Some objects will never be reclaimed by ObjectSpace, e.g. Fixnums
|
65
|
+
end
|
66
|
+
|
67
|
+
begin
|
68
|
+
ObjectSpace.define_finalizer(key, @reclaim_key)
|
69
|
+
rescue ArgumentError
|
70
|
+
# Some objects will never be reclaimed by ObjectSpace, e.g. Fixnums
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# an addition to Mauricio's implementation,
|
75
|
+
# simple method that act's like Hash#update method.
|
76
|
+
def update(hash)
|
77
|
+
hash.each { |key, val| send(:[]=, key, val) }
|
78
|
+
self
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), "../lib"))
|
4
|
+
|
5
|
+
require 'weak_hash'
|
6
|
+
require 'rk_weak_hash'
|
7
|
+
require 'simple_weak_hash'
|
8
|
+
|
9
|
+
TIMES = 100_000
|
10
|
+
|
11
|
+
Benchmark.bmbm(30) do |bm|
|
12
|
+
|
13
|
+
wh1 = RKWeakHash.new({})
|
14
|
+
wh2 = WeakHash.new
|
15
|
+
wh3 = SimpleWeakHash.new
|
16
|
+
|
17
|
+
bm.report("RKWeakHash init") { TIMES.times{ |i| wh1[i.to_s] = i.to_s } }
|
18
|
+
bm.report("WeakHash init") { TIMES.times{ |i| wh2[i.to_s] = i.to_s } }
|
19
|
+
bm.report("SimpleWeakHash init"){ TIMES.times{ |i| wh3[i.to_s] = i.to_s } }
|
20
|
+
|
21
|
+
vals = (0..100).inject({}) { |s,x| s[x] = x; s }
|
22
|
+
|
23
|
+
bm.report("RKWeakHash lookup") do
|
24
|
+
wh1.update(vals)
|
25
|
+
vals.each{|i| wh1[i]}
|
26
|
+
end
|
27
|
+
|
28
|
+
bm.report("WeakHash lookup") do
|
29
|
+
wh2.update(vals)
|
30
|
+
vals.each{|i| wh2[i]}
|
31
|
+
end
|
32
|
+
|
33
|
+
bm.report("SimpleWeakHash lookup") do
|
34
|
+
wh3.update(vals)
|
35
|
+
vals.each{|i| wh3[i]}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
__END__
|
40
|
+
▸ ruby -v
|
41
|
+
ruby 1.9.1p376 (2009-12-07 revision 26041) [x86_64-linux]
|
42
|
+
|
43
|
+
▸ uname -a
|
44
|
+
Linux goingmerry 2.6.32-ARCH #1 SMP PREEMPT Thu Jan 7 22:28:29 CET 2010 x86_64 AMD Athlon(tm) 64 X2 Dual Core Processor 6000+ AuthenticAMD GNU/Linux
|
45
|
+
|
46
|
+
Rehearsal -----------------------------------------------------------------
|
47
|
+
RKWeakHash init 6.680000 0.070000 6.750000 ( 6.771348)
|
48
|
+
WeakHash init 2.170000 0.030000 2.200000 ( 2.209112)
|
49
|
+
SimpleWeakHash init 0.530000 0.000000 0.530000 ( 0.533288)
|
50
|
+
RKWeakHash lookup 0.000000 0.000000 0.000000 ( 0.000874)
|
51
|
+
WeakHash lookup 0.010000 0.000000 0.010000 ( 0.003856)
|
52
|
+
SimpleWeakHash lookup 0.000000 0.000000 0.000000 ( 0.000454)
|
53
|
+
-------------------------------------------------------- total: 9.490000sec
|
54
|
+
|
55
|
+
user system total real
|
56
|
+
RKWeakHash init 12.980000 0.050000 13.030000 ( 13.025488)
|
57
|
+
WeakHash init 2.750000 0.020000 2.770000 ( 2.771461)
|
58
|
+
SimpleWeakHash init 0.300000 0.000000 0.300000 ( 0.307679)
|
59
|
+
RKWeakHash lookup 0.000000 0.000000 0.000000 ( 0.000906)
|
60
|
+
WeakHash lookup 0.010000 0.000000 0.010000 ( 0.003932)
|
61
|
+
SimpleWeakHash lookup 0.000000 0.000000 0.000000 ( 0.000408)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe RKWeakHash do
|
4
|
+
before do
|
5
|
+
@key = "key"
|
6
|
+
@value = "value"
|
7
|
+
@weak_hash = RKWeakHash.new
|
8
|
+
|
9
|
+
@weak_hash[@key] = @value
|
10
|
+
end
|
11
|
+
|
12
|
+
it "stores objects until a garbage collection happens" do
|
13
|
+
GC.start; GC.start
|
14
|
+
@weak_hash[@key].should_not == @value
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe SimpleWeakHash do
|
4
|
+
before do
|
5
|
+
@key = "key"
|
6
|
+
@value = "value"
|
7
|
+
@weak_hash = SimpleWeakHash.new
|
8
|
+
|
9
|
+
@weak_hash[@key] = @value
|
10
|
+
end
|
11
|
+
|
12
|
+
it "stores objects until a garbage collection happens" do
|
13
|
+
GC.start; GC.start
|
14
|
+
@weak_hash[@key].should_not == @value
|
15
|
+
end
|
16
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'weak_hash'
|
4
|
+
require 'rk_weak_hash'
|
5
|
+
require 'simple_weak_hash'
|
6
|
+
require 'spec'
|
7
|
+
require 'spec/autorun'
|
8
|
+
|
9
|
+
Spec::Runner.configure do |config|
|
10
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe WeakHash do
|
4
|
+
before do
|
5
|
+
@key = "key"
|
6
|
+
@value = "value"
|
7
|
+
@weak_hash = WeakHash.new
|
8
|
+
|
9
|
+
@weak_hash[@key] = @value
|
10
|
+
end
|
11
|
+
|
12
|
+
it "stores objects until the key is garbage collected" do
|
13
|
+
1.upto(10) do
|
14
|
+
@weak_hash[@key].should == @value
|
15
|
+
end
|
16
|
+
|
17
|
+
@key = nil
|
18
|
+
GC.start; GC.start
|
19
|
+
@weak_hash[@key].should_not == @value
|
20
|
+
end
|
21
|
+
|
22
|
+
it "stores objects until the value is garbage collected" do
|
23
|
+
1.upto(10) do
|
24
|
+
@weak_hash[@key].should == @value
|
25
|
+
end
|
26
|
+
|
27
|
+
@value = nil
|
28
|
+
GC.start; GC.start
|
29
|
+
@weak_hash[@key].should_not == @value
|
30
|
+
end
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: weak_hash
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Emmanuel Oga
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-03-08 00:00:00 -03:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rspec
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 2
|
30
|
+
- 9
|
31
|
+
version: 1.2.9
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: yard
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
version: "0"
|
44
|
+
type: :development
|
45
|
+
version_requirements: *id002
|
46
|
+
description: a hash that stores objects until they are garbage collected
|
47
|
+
email: EmmanuelOga@gmail.com
|
48
|
+
executables: []
|
49
|
+
|
50
|
+
extensions: []
|
51
|
+
|
52
|
+
extra_rdoc_files:
|
53
|
+
- LICENSE
|
54
|
+
- README.rdoc
|
55
|
+
files:
|
56
|
+
- .document
|
57
|
+
- .gitignore
|
58
|
+
- LICENSE
|
59
|
+
- README.rdoc
|
60
|
+
- Rakefile
|
61
|
+
- VERSION
|
62
|
+
- lib/rk_weak_hash.rb
|
63
|
+
- lib/simple_weak_hash.rb
|
64
|
+
- lib/weak_hash.rb
|
65
|
+
- scripts/benchmark.rb
|
66
|
+
- spec/rk_weak_hash_spec.rb
|
67
|
+
- spec/simple_weak_hash_spec.rb
|
68
|
+
- spec/spec_helper.rb
|
69
|
+
- spec/weak_hash_spec.rb
|
70
|
+
has_rdoc: true
|
71
|
+
homepage: http://github.com/EmmanuelOga/weak_hash
|
72
|
+
licenses: []
|
73
|
+
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options:
|
76
|
+
- --charset=UTF-8
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
segments:
|
84
|
+
- 0
|
85
|
+
version: "0"
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
requirements: []
|
94
|
+
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 1.3.6
|
97
|
+
signing_key:
|
98
|
+
specification_version: 3
|
99
|
+
summary: Weak Hash implementation
|
100
|
+
test_files:
|
101
|
+
- spec/rk_weak_hash_spec.rb
|
102
|
+
- spec/spec_helper.rb
|
103
|
+
- spec/weak_hash_spec.rb
|
104
|
+
- spec/simple_weak_hash_spec.rb
|