free 0.1.2 → 0.2.0pre1

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY CHANGED
@@ -1,2 +1,10 @@
1
+ 4/1/2011 version 0.2.0
2
+ * added destructors
3
+ * added greater error checking
4
+
5
+ 3/1/2011 version 0.1.2
6
+ * added 1.8 and 1.9 support
7
+ * now compiles on linux
8
+
1
9
  2/1/2011 version 0.1.0
2
10
  * first release
data/README.md CHANGED
@@ -9,16 +9,17 @@ free provides the `Object#free` method enabling a user to garbage
9
9
  collect an object on demand and free all its internal structures.
10
10
 
11
11
  * Install the [gem](https://rubygems.org/gems/free)
12
- * Read the [documentation](http://rdoc.info/github/banister/free/master/file/README.markdown)
12
+ * Read the [documentation](http://rdoc.info/github/banister/free/master/file/README.md)
13
13
  * See the [source code](http://github.com/banister/free)
14
14
 
15
- Example:
16
- --------
15
+ Example: Freeing a String
16
+ -------------------------
17
17
 
18
18
  Let's free a String:
19
19
 
20
20
  hello = "hello world"
21
21
  id = hello.object_id
22
+
22
23
  hello.free
23
24
 
24
25
  # Note we go through the id as accessing the freed object directly
@@ -26,20 +27,36 @@ Let's free a String:
26
27
  ObjectSpace._id2ref(id) #=> RangeError: _id2ref': 0x1c1a63c is recycled object
27
28
 
28
29
 
30
+ Example: Destructors
31
+ --------------------
32
+
33
+ Free also supports object destructors. If the `__destruct__` method is
34
+ implemented on the object being freed it will be called before freeing
35
+ takes place; and the return value of `free` will be the return value of `__destruct__`:
36
+
37
+ o = Object.new
38
+ def o.__destruct__
39
+ :killed
40
+ end
41
+
42
+ o.free #=> :killed
43
+
29
44
  Features and limitations
30
45
  -------------------------
31
46
 
32
47
  ### Features
33
48
 
34
- * Can free any object (except immediate values, that do not need
35
- freeing)
36
- * Works in both Ruby 1.8 and 1.9, MRI and YARV only.
49
+ * Can free any object (but be careful, see below)
50
+ * Works in both Ruby 1.8 and 1.9.
51
+ * Some protection from freeing critical objects and immediate values.
52
+ * Supports object destructors
37
53
 
38
54
  ### Limitations
39
55
 
40
56
  * Beta software, beware.
41
- * Can be dangerous - `free` will force garbage collection on an object
42
- even if references to it still exist. Trying to access an already freed object may result in unexpected behaviour or segfaults.
57
+ * Supports MRI and YARV only.
58
+ * Not complete protection from freeing silly things, e.g core classes. Be sensible :)
59
+ * Can be dangerous - `free` will force garbage collection on an object even if references to it still exist. Trying to access an already freed object may result in unexpected behaviour or segfaults.
43
60
 
44
61
  Contact
45
62
  -------
@@ -46,10 +46,6 @@ typedef struct RVALUE {
46
46
  struct SCOPE scope;
47
47
  #endif
48
48
  } as;
49
- #ifdef GC_DEBUG
50
- const char *file;
51
- int line;
52
- #endif
53
49
  } RVALUE;
54
50
 
55
51
  #define RANY(o) ((RVALUE*)(o))
@@ -97,16 +93,55 @@ make_deferred(RVALUE *p)
97
93
 
98
94
  VALUE object_free(VALUE obj)
99
95
  {
100
- #ifdef RUBY_19
101
- switch (BUILTIN_TYPE(obj)) {
96
+ ID id_destructor = rb_intern("__destruct__");
97
+
98
+ /* value returned by destructor */
99
+ VALUE destruct_value = Qnil;
100
+
101
+ /* prevent freeing of immediates */
102
+ switch (TYPE(obj)) {
102
103
  case T_NIL:
103
104
  case T_FIXNUM:
104
105
  case T_TRUE:
105
106
  case T_FALSE:
106
- rb_bug("obj_free() called for broken object");
107
+ case T_SYMBOL:
108
+ rb_raise(rb_eTypeError, "obj_free() called for immediate value");
107
109
  break;
108
110
  }
109
111
 
112
+ /* prevent freeing of *some* critical objects */
113
+ if ((obj == rb_cObject) ||
114
+ (obj == rb_cClass) ||
115
+ (obj == rb_cModule) ||
116
+ (obj == rb_cSymbol) ||
117
+ (obj == rb_cFixnum) ||
118
+ (obj == rb_cFloat) ||
119
+ (obj == rb_cString) ||
120
+ (obj == rb_cRegexp) ||
121
+ (obj == rb_cInteger) ||
122
+ (obj == rb_cArray) ||
123
+ (obj == rb_cNilClass) ||
124
+ (obj == rb_cFalseClass) ||
125
+ (obj == rb_cTrueClass) ||
126
+ (obj == rb_cNumeric) ||
127
+ (obj == rb_cBignum) ||
128
+ (obj == rb_cStruct))
129
+ rb_raise(rb_eTypeError, "obj_free() called for critical object");
130
+
131
+ /* run destructor (if one is defined) */
132
+ if (rb_respond_to(obj, id_destructor))
133
+ destruct_value = rb_funcall(obj, id_destructor, 0);
134
+
135
+ #ifdef RUBY_19
136
+ switch (BUILTIN_TYPE(obj)) {
137
+ case T_NIL:
138
+ case T_FIXNUM:
139
+ case T_TRUE:
140
+ case T_FALSE:
141
+ rb_bug("obj_free() called for broken object");
142
+ break;
143
+ }
144
+
110
145
  if (FL_TEST(obj, FL_EXIVAR)) {
111
146
  rb_free_generic_ivar((VALUE)obj);
112
147
  FL_UNSET(obj, FL_EXIVAR);
@@ -346,7 +381,7 @@ VALUE object_free(VALUE obj)
346
381
 
347
382
  rb_gc_force_recycle(obj);
348
383
 
349
- return Qnil;
384
+ return destruct_value;
350
385
  }
351
386
 
352
387
  void
@@ -9,10 +9,15 @@ require "#{direc}/free/version"
9
9
  module Free
10
10
 
11
11
  # Force garbage collection on an object and free its internal structures.
12
- # @return nil
12
+ # @return [nil, Object] Return value of \_\_destruct\_\_ method (if
13
+ # defined) or nil (if no \_\_destruct\_\_ method)
13
14
  # @example
14
15
  # h = "hello"
15
- # h.free
16
+ # def h.__destruct__
17
+ # :killed
18
+ # end
19
+ #
20
+ # h.free #=> :killed
16
21
  def free() end
17
22
  end
18
23
 
@@ -1,3 +1,3 @@
1
1
  module Free
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0pre1"
3
3
  end
@@ -32,4 +32,33 @@ describe Free do
32
32
  (ObjectSpace._id2ref(id) != v || lambda { ObjectSpace._id2ref(id) } rescue true).should == true
33
33
  end
34
34
  end
35
+
36
+ it 'should run destructor before freeing object' do
37
+ o = Object.new
38
+
39
+ def o.__destruct__
40
+ :killed
41
+ end
42
+
43
+ o.free.should == :killed
44
+ end
45
+
46
+ it 'should return nil if no destructor specified' do
47
+ o = Object.new
48
+ o.free.should == nil
49
+ end
50
+
51
+ it 'should raise when trying to free immediate values' do
52
+ [nil, 0, true, false, :symbol].each do |v|
53
+ lambda { v.free }.should.raise TypeError
54
+ end
55
+ end
56
+
57
+ it 'should raise when trying to free critical objects' do
58
+ [Object, Class, Module, Symbol, Fixnum, Float,
59
+ String, Regexp, Integer, Array, NilClass, FalseClass,
60
+ TrueClass, Numeric, Bignum, Struct].each do |v|
61
+ lambda { v.free }.should.raise TypeError
62
+ end
63
+ end
35
64
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: free
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
5
- prerelease: false
4
+ prerelease: true
6
5
  segments:
7
6
  - 0
8
- - 1
9
7
  - 2
10
- version: 0.1.2
8
+ - 0pre1
9
+ version: 0.2.0pre1
11
10
  platform: ruby
12
11
  authors:
13
12
  - John Mair (banisterfiend)
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2011-01-03 00:00:00 +13:00
17
+ date: 2011-01-04 00:00:00 +13:00
19
18
  default_executable:
20
19
  dependencies: []
21
20
 
@@ -72,19 +71,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
72
71
  requirements:
73
72
  - - ">="
74
73
  - !ruby/object:Gem::Version
75
- hash: 3
76
74
  segments:
77
75
  - 0
78
76
  version: "0"
79
77
  required_rubygems_version: !ruby/object:Gem::Requirement
80
78
  none: false
81
79
  requirements:
82
- - - ">="
80
+ - - ">"
83
81
  - !ruby/object:Gem::Version
84
- hash: 3
85
82
  segments:
86
- - 0
87
- version: "0"
83
+ - 1
84
+ - 3
85
+ - 1
86
+ version: 1.3.1
88
87
  requirements: []
89
88
 
90
89
  rubyforge_project: