object2module 0.1.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/README.rdoc ADDED
@@ -0,0 +1,18 @@
1
+ # Object2module
2
+
3
+ - converts a Class (or the Singleton of an Object) to a Module
4
+ - Includes gen\_extend and gen\_include methods: generalizations
5
+ of Object#extend and Module#include that work with Objects and
6
+ Classes as well as Modules
7
+
8
+ How it works:
9
+
10
+ - First creates an IClass for the Class in question and sets the
11
+ T\_MODULE flag
12
+ - Recursively converts superclasses of the Class to IClasses
13
+ creating a modulified version of the Class's inheritance chain
14
+ - gen\_include/gen\_extend automatically call #to\_module on the
15
+ Class/Object before inclusion/extension.
16
+
17
+
18
+
data/Rakefile ADDED
@@ -0,0 +1,84 @@
1
+ require 'rake/clean'
2
+
3
+ OBJECT2MODULE_VERSION = "0.1.0"
4
+
5
+ $dlext = Config::CONFIG['DLEXT']
6
+
7
+ CLEAN.include("ext/*.#{$dlext}", "ext/*.log", "ext/*.o", "ext/*~", "ext/*#*", "ext/*.obj", "ext/*.def", "ext/*.pdb")
8
+ CLOBBER.include("**/*.#{$dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o", "doc/**")
9
+
10
+ $make_program = if RUBY_PLATFORM =~ /win/
11
+ "nmake"
12
+ else
13
+ "make"
14
+ end
15
+
16
+ task :default => [:build]
17
+
18
+ desc "Build Object2module"
19
+ task :build => :clean do
20
+ chdir("./ext/") do
21
+ ruby "extconf.rb"
22
+ sh "#{$make_program}"
23
+ cp "cobject2module.#{$dlext}", "../lib" , :verbose => true
24
+
25
+ if RUBY_PLATFORM =~ /mswin/
26
+ if RUBY_VERSION =~ /1.9/
27
+ File.rename("../lib/cobject2module.#{$dlext}",
28
+ "../lib/cobject2module.19.#{$dlext}")
29
+ else
30
+ File.rename("../lib/cobject2module.#{$dlext}",
31
+ "../lib/cobject2module.18.#{$dlext}")
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ require 'rake/gempackagetask'
38
+ specification = Gem::Specification.new do |s|
39
+ s.name = "object2module"
40
+ s.summary = "object2module enables ruby classes and objects to be used as modules"
41
+ s.version = OBJECT2MODULE_VERSION
42
+ s.date = Time.now.strftime '%Y-%m-%d'
43
+ s.author = "John Mair (banisterfiend)"
44
+ s.email = 'jrmair@gmail.com'
45
+ s.description = s.summary
46
+ s.require_path = 'lib'
47
+ s.homepage = "http://banisterfiend.wordpress.com"
48
+ s.has_rdoc = true
49
+ s.extra_rdoc_files = ["README.rdoc", "ext/object2module.c"]
50
+ s.rdoc_options << '--main' << 'README.rdoc'
51
+ s.files = ["Rakefile", "lib/object2module.rb", "README.rdoc"] +
52
+ FileList["ext/*.c", "ext/*.h", "ext/*.rb", "test/*.rb"].to_a
53
+
54
+ if RUBY_PLATFORM =~ /mswin/
55
+ s.platform = Gem::Platform::CURRENT
56
+ s.files += ["lib/cobject2module.18.so", "lib/cobject2module.19.so"]
57
+
58
+ else
59
+ s.platform = Gem::Platform::RUBY
60
+ s.extensions = ["ext/extconf.rb"]
61
+ end
62
+ end
63
+
64
+ # gem, rdoc, and test tasks below
65
+
66
+ Rake::GemPackageTask.new(specification) do |package|
67
+ package.need_zip = false
68
+ package.need_tar = false
69
+ end
70
+
71
+ require 'rake/rdoctask'
72
+ Rake::RDocTask.new do |rd|
73
+ rd.main = "README.rdoc"
74
+ rd.rdoc_files.include("README.rdoc", "ext/*.c")
75
+ end
76
+
77
+ require 'rake/testtask'
78
+ Rake::TestTask.new do |t|
79
+ t.test_files = FileList['test/test*.rb']
80
+ t.verbose = true
81
+ end
82
+
83
+
84
+
data/ext/compat.h ADDED
@@ -0,0 +1,18 @@
1
+ /* contains basic macros to facilitate ruby 1.8 and ruby 1.9 compatibility */
2
+
3
+ #ifndef GUARD_COMPAT_H
4
+ #define GUARD_COMPAT_H
5
+
6
+ #include <ruby.h>
7
+
8
+ /* macros for backwards compatibility with 1.8 */
9
+ #ifndef RUBY_19
10
+ # define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
11
+ # define RCLASS_SUPER(c) (RCLASS(c)->super)
12
+ # define RCLASS_IV_TBL(c) (RCLASS(c)->iv_tbl)
13
+ #endif
14
+
15
+ /* a useful macro. cannot use ordinary CLASS_OF as it does not return an lvalue */
16
+ #define KLASS_OF(c) (RBASIC(c)->klass)
17
+
18
+ #endif
data/ext/extconf.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'mkmf'
2
+
3
+ # 1.9 compatibility
4
+ $CPPFLAGS += " -DRUBY_19" if RUBY_VERSION =~ /1.9/
5
+
6
+ create_makefile('cobject2module')
@@ -0,0 +1,215 @@
1
+ /* object2module.c */
2
+ /* (C) John Mair 2009
3
+ * This program is distributed under the terms of the MIT License
4
+ * */
5
+
6
+ #include <ruby.h>
7
+ #include "compat.h"
8
+
9
+ #ifdef RUBY_19
10
+ # include <ruby/st.h>
11
+ #else
12
+ # include <st.h>
13
+ #endif
14
+
15
+ /* class creation. from class.c in 1.9.1 */
16
+ #ifdef RUBY_19
17
+ static VALUE
18
+ class_alloc(VALUE flags, VALUE klass)
19
+ {
20
+ rb_classext_t *ext = ALLOC(rb_classext_t);
21
+ NEWOBJ(obj, struct RClass);
22
+ OBJSETUP(obj, klass, flags);
23
+ obj->ptr = ext;
24
+ RCLASS_IV_TBL(obj) = 0;
25
+ RCLASS_M_TBL(obj) = 0;
26
+ RCLASS_SUPER(obj) = 0;
27
+ RCLASS_IV_INDEX_TBL(obj) = 0;
28
+ return (VALUE)obj;
29
+ }
30
+ #endif
31
+
32
+ /* a modified version of include_class_new from class.c */
33
+ static VALUE
34
+ j_class_new(VALUE module, VALUE sup) {
35
+
36
+ #ifdef RUBY_19
37
+ VALUE klass = class_alloc(T_ICLASS, rb_cClass);
38
+ #else
39
+ NEWOBJ(klass, struct RClass);
40
+ OBJSETUP(klass, rb_cClass, T_ICLASS);
41
+ #endif
42
+
43
+ if (BUILTIN_TYPE(module) == T_ICLASS) {
44
+ module = KLASS_OF(module);
45
+ }
46
+
47
+ if (!RCLASS_IV_TBL(module)) {
48
+
49
+ RCLASS_IV_TBL(module) = (struct st_table *)st_init_numtable();
50
+ }
51
+
52
+ /* assign iv_tbl, m_tbl and super */
53
+ RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);
54
+ RCLASS_SUPER(klass) = sup;
55
+ if(TYPE(module) != T_OBJECT) {
56
+
57
+ RCLASS_M_TBL(klass) = RCLASS_M_TBL(module);
58
+ }
59
+ else {
60
+ RCLASS_M_TBL(klass) = RCLASS_M_TBL(CLASS_OF(module));
61
+ }
62
+
63
+ /* */
64
+
65
+ if (TYPE(module) == T_ICLASS) {
66
+ KLASS_OF(klass) = KLASS_OF(module);
67
+ }
68
+ else {
69
+ KLASS_OF(klass) = module;
70
+ }
71
+
72
+
73
+ if(TYPE(module) != T_OBJECT) {
74
+ OBJ_INFECT(klass, module);
75
+ OBJ_INFECT(klass, sup);
76
+ }
77
+ return (VALUE)klass;
78
+ }
79
+
80
+ static VALUE
81
+ rb_to_module(VALUE self) {
82
+ VALUE rclass, chain_start, jcur, klass;
83
+
84
+ switch(BUILTIN_TYPE(self)) {
85
+ case T_MODULE:
86
+ return self;
87
+ case T_CLASS:
88
+ klass = self;
89
+ break;
90
+ case T_OBJECT:
91
+ default:
92
+ klass = rb_singleton_class(self);
93
+ }
94
+
95
+ chain_start = j_class_new(klass, rb_cObject);
96
+
97
+ KLASS_OF(chain_start) = rb_cModule;
98
+ RBASIC(chain_start)->flags = T_MODULE;
99
+
100
+ jcur = chain_start;
101
+ for(rclass = RCLASS_SUPER(klass); rclass != rb_cObject;
102
+ rclass = RCLASS_SUPER(rclass)) {
103
+
104
+ RCLASS_SUPER(jcur) = j_class_new(rclass, rb_cObject);
105
+ jcur = RCLASS_SUPER(jcur);
106
+ }
107
+
108
+ RCLASS_SUPER(jcur) = (VALUE)NULL;
109
+
110
+ return chain_start;
111
+ }
112
+
113
+ static VALUE
114
+ rb_reset_tbls(VALUE self) {
115
+ RCLASS_IV_TBL(self) = (struct st_table *) 0;
116
+ RCLASS_M_TBL(self) = (struct st_table *) st_init_numtable();
117
+
118
+ return Qnil;
119
+ }
120
+
121
+ /*
122
+ * call-seq:
123
+ * obj.gen_extend(other, ...) => obj
124
+ *
125
+ * Adds to _obj_ the instance methods from each object given as a
126
+ * parameter.
127
+ *
128
+ * class C
129
+ * def hello
130
+ * "Hello from C.\n"
131
+ * end
132
+ * end
133
+ *
134
+ * class Klass
135
+ * def hello
136
+ * "Hello from Klass.\n"
137
+ * end
138
+ * end
139
+ *
140
+ * k = Klass.new
141
+ * k.hello #=> "Hello from Klass.\n"
142
+ * k.gen_extend(C) #=> #<Klass:0x401b3bc8>
143
+ * k.hello #=> "Hello from C.\n"
144
+ */
145
+
146
+ static VALUE
147
+ rb_gen_extend(int argc, VALUE * argv, VALUE self) {
148
+ int i;
149
+
150
+ if (argc == 0) rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)");
151
+
152
+ rb_singleton_class(self);
153
+
154
+ for(i = 0; i < argc; i++) {
155
+ VALUE mod = rb_to_module(argv[i]);
156
+ rb_funcall(mod, rb_intern("extend_object"), 1, self);
157
+ rb_funcall(mod, rb_intern("extended"), 1, self);
158
+
159
+ /* only redirect if argv[i] is not a module */
160
+ if(argv[i] != mod) rb_reset_tbls(mod);
161
+ }
162
+
163
+ return self;
164
+ }
165
+
166
+ /*
167
+ * call-seq:
168
+ * gen_include(other, ...) => self
169
+ *
170
+ * Adds to the implied receiver the instance methods from each object given as a
171
+ * parameter.
172
+ *
173
+ * class C
174
+ * def hello
175
+ * "Hello from C.\n"
176
+ * end
177
+ * end
178
+ *
179
+ * class Klass
180
+ * gen_include(C)
181
+ * end
182
+ *
183
+ * k = Klass.new
184
+ * k.hello #=> "Hello from C.\n"
185
+ */
186
+
187
+ static VALUE
188
+ rb_gen_include(int argc, VALUE * argv, VALUE self) {
189
+ int i;
190
+
191
+ if (argc == 0) rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)");
192
+
193
+ for(i = 0; i < argc; i++) {
194
+ VALUE mod = rb_to_module(argv[i]);
195
+ rb_funcall(mod, rb_intern("append_features"), 1, self);
196
+ rb_funcall(mod, rb_intern("included"), 1, self);
197
+
198
+ if(argv[i] != mod) rb_reset_tbls(mod);
199
+ }
200
+
201
+ return self;
202
+ }
203
+
204
+
205
+ void Init_cobject2module() {
206
+
207
+ /* too dangerous as may result in double free. */
208
+ rb_define_method(rb_cObject, "to_module", rb_to_module , 0);
209
+
210
+ /* these methods are fine */
211
+ rb_define_method(rb_cObject, "gen_extend", rb_gen_extend, -1);
212
+ rb_define_method(rb_cModule, "gen_include", rb_gen_include, -1);
213
+ rb_define_method(rb_cModule, "reset_tbls", rb_reset_tbls, 0);
214
+ }
215
+
@@ -0,0 +1,11 @@
1
+ /* object2module.h */
2
+
3
+ #ifndef GUARD_OBJECT2MODULE_H
4
+ #define GUARD_OBJECT2MODULE_H
5
+
6
+ VALUE rb_gen_include(int argc, VALUE * argv, VALUE self);
7
+ VALUE rb_gen_extend(int argc, VALUE * argv, VALUE self);
8
+ VALUE rb_to_module(VALUE self);
9
+ VALUE rb_reset_tbls(VALUE self);
10
+
11
+ #endif
@@ -0,0 +1,13 @@
1
+ require 'rbconfig'
2
+
3
+ direc = File.dirname(__FILE__)
4
+ dlext = Config::CONFIG['DLEXT']
5
+ begin
6
+ if RUBY_VERSION && RUBY_VERSION =~ /1.9/
7
+ require "#{direc}/cobject2module.19.#{dlext}"
8
+ else
9
+ require "#{direc}/cobject2module.18.#{dlext}"
10
+ end
11
+ rescue LoadError => e
12
+ require "#{direc}/cobject2module.#{dlext}"
13
+ end
@@ -0,0 +1,145 @@
1
+ require 'test/unit'
2
+ require 'object2module'
3
+
4
+ module M
5
+ def m
6
+ "m"
7
+ end
8
+ end
9
+
10
+ class A
11
+ include M
12
+
13
+ def a
14
+ "a"
15
+ end
16
+ end
17
+
18
+ class B < A
19
+ def b
20
+ "b"
21
+ end
22
+ end
23
+
24
+ class C < B
25
+ def c
26
+ "c"
27
+ end
28
+ end
29
+
30
+ # stand-alone class
31
+ class K
32
+ def k
33
+ "k"
34
+ end
35
+ end
36
+
37
+ # another stand-alone class
38
+ class J
39
+ def j
40
+ "j"
41
+ end
42
+ end
43
+
44
+ class Object2ModuleTest < Test::Unit::TestCase
45
+ def test_class_to_module
46
+ assert_instance_of(Module, C.to_module)
47
+ end
48
+
49
+ def test_class_heirarchy
50
+ c = C.to_module
51
+
52
+ h = c.ancestors
53
+ assert_equal(B, h[1])
54
+ assert_equal(A, h[2])
55
+ assert_equal(M, h[3])
56
+ end
57
+
58
+ def test_class_extend
59
+ o = Object.new
60
+ assert_equal(o, o.gen_extend(C))
61
+ end
62
+
63
+ def test_class_extended_methods
64
+ h = C.to_module
65
+ o = Object.new
66
+ o.extend(h)
67
+ assert_equal("a", o.a)
68
+ assert_equal("b", o.b)
69
+ assert_equal("c", o.c)
70
+ assert_equal("m", o.m)
71
+ end
72
+
73
+ def test_object_to_module
74
+ o = C.new
75
+ assert_instance_of(Module, o.to_module)
76
+ end
77
+
78
+ def test_object_heirarchy
79
+ o = C.new
80
+ h = o.to_module.ancestors
81
+ assert_equal(C, h[1])
82
+ assert_equal(B, h[2])
83
+ assert_equal(A, h[3])
84
+ assert_equal(M, h[4])
85
+ end
86
+
87
+ def test_object_extend
88
+ h = C.to_module
89
+ o = Object.new
90
+ assert_equal(o, o.extend(h))
91
+ end
92
+
93
+ def test_object_extended_methods
94
+ o = C.new
95
+ h = o.to_module
96
+ l = Object.new
97
+ l.extend(h)
98
+ assert_equal("a", l.a)
99
+ assert_equal("b", l.b)
100
+ assert_equal("c", l.c)
101
+ assert_equal("m", l.m)
102
+ end
103
+
104
+ def test_gen_extend
105
+ o = Object.new
106
+ o.gen_extend(C)
107
+ assert_equal("a", o.a)
108
+ assert_equal("b", o.b)
109
+ assert_equal("c", o.c)
110
+ assert_equal("m", o.m)
111
+ end
112
+
113
+ def test_gen_include
114
+ k = Class.new
115
+ k.gen_include(C)
116
+ o = k.new
117
+ assert_equal("a", o.a)
118
+ assert_equal("b", o.b)
119
+ assert_equal("c", o.c)
120
+ assert_equal("m", o.m)
121
+ end
122
+
123
+ def test_gen_extend_multi
124
+ o = Object.new
125
+ o.gen_extend(C, K, J)
126
+ assert_equal("a", o.a)
127
+ assert_equal("b", o.b)
128
+ assert_equal("c", o.c)
129
+ assert_equal("m", o.m)
130
+ assert_equal("k", o.k)
131
+ assert_equal("j", o.j)
132
+ end
133
+
134
+ def test_gen_include_multi
135
+ k = Class.new
136
+ k.gen_include(C, K, J)
137
+ o = k.new
138
+ assert_equal("a", o.a)
139
+ assert_equal("b", o.b)
140
+ assert_equal("c", o.c)
141
+ assert_equal("m", o.m)
142
+ assert_equal("k", o.k)
143
+ assert_equal("j", o.j)
144
+ end
145
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: object2module
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - John Mair (banisterfiend)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-09-25 00:00:00 +12:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: object2module enables ruby classes and objects to be used as modules
17
+ email: jrmair@gmail.com
18
+ executables: []
19
+
20
+ extensions:
21
+ - ext/extconf.rb
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ - ext/object2module.c
25
+ files:
26
+ - Rakefile
27
+ - lib/object2module.rb
28
+ - README.rdoc
29
+ - ext/object2module.c
30
+ - ext/object2module.h
31
+ - ext/compat.h
32
+ - ext/extconf.rb
33
+ - test/test_object2module.rb
34
+ has_rdoc: true
35
+ homepage: http://banisterfiend.wordpress.com
36
+ post_install_message:
37
+ rdoc_options:
38
+ - --main
39
+ - README.rdoc
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ requirements: []
55
+
56
+ rubyforge_project:
57
+ rubygems_version: 1.2.0
58
+ signing_key:
59
+ specification_version: 2
60
+ summary: object2module enables ruby classes and objects to be used as modules
61
+ test_files: []
62
+