include_complete 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ 1/11/2010 *NAME CHANGE* TO include_complete, version reset to 0.1.0
2
+ * now called include_complete
3
+ 22/10/2010 version 0.2.2
4
+ * refactored compat.h, incorporated test for 1.9
5
+ * created inline static function create_class() in compat.h
6
+ 20/10/2010 version 0.2.1
7
+ * constant lookup should now work
8
+ * added real_extend and tests
9
+ 15/10/2010 version 0.1.7
10
+ * should be properly working with normal Module#include now
11
+ * no more segfaults?
12
+ * added more tests
13
+ 6/10/2010 version 0.1.3
14
+ * fixed native gem
15
+ * moved more version-dependant code to compat.h
16
+ 5/10/2010 version 0.1.2
17
+ * added 1.8 support
18
+ * added bacon tests
19
+ 4/10/10 version 0.1.0
20
+ * release! This is still beta, not 100% tested yet..but appears to work OK so far
@@ -0,0 +1,40 @@
1
+ Include Complete
2
+ ----------------
3
+
4
+ (c) John Mair (banisterfiend)
5
+ MIT license
6
+
7
+ Removes the shackles from Module#include - use Module#real_include to
8
+ bring in singleton classes from modules. No more ugly ClassMethods and
9
+ included() hook hacks.
10
+
11
+ ** This is BETA software and has not yet been thoroughly tested, use
12
+ at own risk **
13
+
14
+ install the gem: **for testing purposes only**
15
+ `gem install include_complete`
16
+
17
+ example:
18
+
19
+ module M
20
+ # class method
21
+ def self.hello
22
+ puts "hello!"
23
+ end
24
+
25
+ # instance method
26
+ def bye
27
+ puts "bye!"
28
+ end
29
+ end
30
+
31
+ class A
32
+ include_complete M
33
+ end
34
+
35
+ # invoke class method
36
+ A.hello #=> hello!
37
+
38
+ # invoke instance method
39
+ A.new.bye #=> bye!
40
+
@@ -0,0 +1,59 @@
1
+ $LOAD_PATH.unshift File.join(File.expand_path(__FILE__), '..')
2
+
3
+ direc = File.dirname(__FILE__)
4
+ dlext = Config::CONFIG['DLEXT']
5
+
6
+ require 'rake/clean'
7
+ require 'rake/gempackagetask'
8
+ require './lib/include_complete/version'
9
+
10
+ CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o", "ext/**/*~", "ext/**/*#*", "ext/**/*.obj", "ext/**/*.def", "ext/**/*.pdb")
11
+ CLOBBER.include("**/*.#{dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o")
12
+
13
+ def apply_spec_defaults(s)
14
+ s.name = "include_complete"
15
+ s.summary = "Fixing the limitations in traditional Module#include"
16
+ s.version = IncludeComplete::VERSION
17
+ s.date = Time.now.strftime '%Y-%m-%d'
18
+ s.author = "John Mair (banisterfiend)"
19
+ s.email = 'jrmair@gmail.com'
20
+ s.description = s.summary
21
+ s.require_path = 'lib'
22
+ s.homepage = "http://banisterfiend.wordpress.com"
23
+ s.has_rdoc = 'yard'
24
+ s.files = FileList["Rakefile", "README.markdown", "CHANGELOG",
25
+ "lib/**/*.rb", "ext/**/extconf.rb", "ext/**/*.h",
26
+ "ext/**/*.c", "test/**/*.rb"].to_a
27
+ end
28
+
29
+ task :test do
30
+ sh "bacon -k #{direc}/test/test.rb"
31
+ end
32
+
33
+ [:mingw32, :mswin32].each do |v|
34
+ namespace v do
35
+ spec = Gem::Specification.new do |s|
36
+ apply_spec_defaults(s)
37
+ s.platform = "i386-#{v}"
38
+ s.files += FileList["lib/**/*.#{dlext}"].to_a
39
+ end
40
+
41
+ Rake::GemPackageTask.new(spec) do |pkg|
42
+ pkg.need_zip = false
43
+ pkg.need_tar = false
44
+ end
45
+ end
46
+ end
47
+
48
+ namespace :ruby do
49
+ spec = Gem::Specification.new do |s|
50
+ apply_spec_defaults(s)
51
+ s.platform = Gem::Platform::RUBY
52
+ s.extensions = ["ext/include_complete/extconf.rb"]
53
+ end
54
+
55
+ Rake::GemPackageTask.new(spec) do |pkg|
56
+ pkg.need_zip = false
57
+ pkg.need_tar = false
58
+ end
59
+ end
@@ -0,0 +1,57 @@
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
+ /* test for 1.9 */
9
+ #if !defined(RUBY_19) && defined(ROBJECT_EMBED_LEN_MAX)
10
+ # define RUBY_19
11
+ #endif
12
+
13
+ /* macros for backwards compatibility with 1.8 */
14
+ #ifndef RUBY_19
15
+ # define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
16
+ # define RCLASS_SUPER(c) (RCLASS(c)->super)
17
+ # define RCLASS_IV_TBL(c) (RCLASS(c)->iv_tbl)
18
+ # define OBJ_UNTRUSTED OBJ_TAINTED
19
+ # include "st.h"
20
+ #endif
21
+
22
+ #ifdef RUBY_19
23
+ inline static VALUE
24
+ class_alloc(VALUE flags, VALUE klass)
25
+ {
26
+ rb_classext_t *ext = ALLOC(rb_classext_t);
27
+ NEWOBJ(obj, struct RClass);
28
+ OBJSETUP(obj, klass, flags);
29
+ obj->ptr = ext;
30
+ RCLASS_IV_TBL(obj) = 0;
31
+ RCLASS_M_TBL(obj) = 0;
32
+ RCLASS_SUPER(obj) = 0;
33
+ RCLASS_IV_INDEX_TBL(obj) = 0;
34
+ return (VALUE)obj;
35
+ }
36
+ #endif
37
+
38
+ inline static VALUE
39
+ create_class(VALUE flags, VALUE klass)
40
+ {
41
+ #ifdef RUBY_19
42
+ VALUE new_klass = class_alloc(flags, klass);
43
+ #else
44
+ NEWOBJ(new_klass, struct RClass);
45
+ OBJSETUP(new_klass, klass, flags);
46
+ #endif
47
+
48
+ return (VALUE)new_klass;
49
+ }
50
+
51
+ # define FALSE 0
52
+ # define TRUE 1
53
+
54
+ /* a useful macro. cannot use ordinary CLASS_OF as it does not return an lvalue */
55
+ #define KLASS_OF(c) (RBASIC(c)->klass)
56
+
57
+ #endif
@@ -0,0 +1,6 @@
1
+ require 'mkmf'
2
+
3
+ # let's use c99
4
+ $CFLAGS += " -std=c99"
5
+
6
+ create_makefile('include_complete')
@@ -0,0 +1,11 @@
1
+ /* (c) 2010 John Mair (banisterfiend), MIT license */
2
+
3
+ void Init_patched_include(void);
4
+ void Init_include_complete_one(void);
5
+
6
+ void
7
+ Init_include_complete()
8
+ {
9
+ Init_include_complete_one();
10
+ Init_patched_include();
11
+ }
@@ -0,0 +1,151 @@
1
+ /* (c) 2010 John Mair (banisterfiend), MIT license */
2
+ /* */
3
+ /* include a module (and its singleton) into an inheritance chain */
4
+ /* only includes a single module, see include_complete.rb for multi-module version */
5
+
6
+ #include <ruby.h>
7
+ #include "compat.h"
8
+
9
+ static VALUE
10
+ class_to_s(VALUE self)
11
+ {
12
+ VALUE attached = rb_iv_get(self, "__attached__");
13
+
14
+ if (attached)
15
+ return rb_mod_name(rb_iv_get(attached, "__module__"));
16
+ else
17
+ return rb_mod_name(rb_iv_get(self, "__module__"));
18
+ }
19
+
20
+ /* totally hacked up version of include_class_new() from class.c; brings in singletons into inheritance chain */
21
+ static VALUE
22
+ include_class_new(VALUE module, VALUE super)
23
+ {
24
+ /* base case for recursion */
25
+ if (module == rb_singleton_class(rb_cModule))
26
+ return module;
27
+
28
+ if (TYPE(module) == T_ICLASS) {
29
+
30
+ /* include_complete */
31
+ if (!NIL_P(rb_iv_get(module, "__module__")))
32
+ module = rb_iv_get(module, "__module__");
33
+
34
+ /* ordinary Module#include */
35
+ else
36
+ module = KLASS_OF(module);
37
+ }
38
+
39
+ /* allocate iclass */
40
+ VALUE klass = create_class(T_ICLASS, rb_singleton_class(rb_cModule));
41
+
42
+ /* if the module hasn't yet got an ivtbl, create it */
43
+ if (!RCLASS_IV_TBL(module))
44
+ RCLASS_IV_TBL(module) = st_init_numtable();
45
+
46
+ /* we want to point to the original ivtbl for normal modules, so that we bring in constants */
47
+ RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);
48
+
49
+ /* we want to point to the original module's mtbl */
50
+ RCLASS_M_TBL(klass) = RCLASS_M_TBL(module);
51
+ RCLASS_SUPER(klass) = super;
52
+
53
+ if (TYPE(module) == T_MODULE || FL_TEST(module, FL_SINGLETON))
54
+ rb_iv_set((VALUE)klass, "__module__", module);
55
+
56
+ /* create IClass for module's singleton */
57
+ /* if super is 0 then we're including into a module (not a class), so treat as special case */
58
+ VALUE meta = include_class_new(KLASS_OF(module), super ? KLASS_OF(super) : rb_cModule);
59
+
60
+ /* don't mess with (Module) */
61
+ if (meta != rb_singleton_class(rb_cModule)) {
62
+
63
+ /* set it as a singleton */
64
+ FL_SET(meta, FL_SINGLETON);
65
+
66
+ /* we want a fresh ivtbl for singleton classes (so we can redefine __attached__) */
67
+ RCLASS_IV_TBL(meta) = st_init_numtable();
68
+
69
+ /* attach singleton to module */
70
+ rb_iv_set(meta, "__attached__", (VALUE)klass);
71
+
72
+ /* attach the #to_s method to the metaclass (so #ancestors doesn't look weird) */
73
+ rb_define_singleton_method(meta, "to_s", class_to_s, 0);
74
+ }
75
+ /* assign the metaclass to module's klass */
76
+ KLASS_OF(klass) = meta;
77
+
78
+ OBJ_INFECT(klass, module);
79
+ OBJ_INFECT(klass, super);
80
+
81
+ return (VALUE)klass;
82
+ }
83
+
84
+ static VALUE
85
+ rb_include_complete_module_one(VALUE klass, VALUE module)
86
+ {
87
+ VALUE p, c;
88
+ int changed = 0;
89
+
90
+ rb_frozen_class_p(klass);
91
+ if (!OBJ_UNTRUSTED(klass)) {
92
+ rb_secure(4);
93
+ }
94
+
95
+ if (TYPE(module) != T_MODULE) {
96
+ Check_Type(module, T_MODULE);
97
+ }
98
+
99
+ OBJ_INFECT(klass, module);
100
+ c = klass;
101
+
102
+ /* ensure singleton classes exist, both for includer and includee */
103
+ rb_singleton_class(module);
104
+ rb_singleton_class(klass);
105
+
106
+ while (module) {
107
+ int superclass_seen = FALSE;
108
+
109
+ if (RCLASS_M_TBL(klass) == RCLASS_M_TBL(module))
110
+ rb_raise(rb_eArgError, "cyclic include detected");
111
+ /* ignore if the module included already in superclasses */
112
+ for (p = RCLASS_SUPER(klass); p; p = RCLASS_SUPER(p)) {
113
+ switch (BUILTIN_TYPE(p)) {
114
+ case T_ICLASS:
115
+ if (RCLASS_M_TBL(p) == RCLASS_M_TBL(module)) {
116
+ if (!superclass_seen) {
117
+ c = p; /* move insertion point */
118
+ }
119
+ goto skip;
120
+ }
121
+ break;
122
+ case T_CLASS:
123
+ superclass_seen = TRUE;
124
+ break;
125
+ }
126
+ }
127
+
128
+ /* we're including the module, so create the iclass */
129
+ VALUE imod = include_class_new(module, RCLASS_SUPER(c));
130
+
131
+ /* module gets included directly above c, so set the super */
132
+ RCLASS_SUPER(c) = imod;
133
+
134
+ /* also do the same for parallel inheritance chain (singleton classes) */
135
+ RCLASS_SUPER(KLASS_OF(c)) = KLASS_OF(imod);
136
+ c = imod;
137
+
138
+ if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries)
139
+ changed = 1;
140
+ skip:
141
+ module = RCLASS_SUPER(module);
142
+ }
143
+ if (changed) rb_clear_cache();
144
+
145
+ return Qnil;
146
+ }
147
+
148
+ void
149
+ Init_include_complete_one() {
150
+ rb_define_method(rb_cModule, "include_complete_one", rb_include_complete_module_one, 1);
151
+ }
@@ -0,0 +1,109 @@
1
+ /* (c) 2010 John Mair (banisterfiend), MIT license */
2
+ /* patches Module#include to work correctly with real_include */
3
+
4
+ #include <ruby.h>
5
+ #include "compat.h"
6
+
7
+ /* patched to work well with real_include */
8
+ static VALUE
9
+ include_class_new(VALUE module, VALUE super)
10
+ {
11
+ VALUE klass = create_class(T_ICLASS, rb_cClass);
12
+
13
+ if (BUILTIN_TYPE(module) == T_ICLASS) {
14
+
15
+ /***************************************************************************** */
16
+ /* This is the only change required, everything else is (pretty much) copypasta from class.c */
17
+ /* correct for real_include'd modules */
18
+ if (!NIL_P(rb_iv_get(module, "__module__")))
19
+ module = rb_iv_get(module, "__module__");
20
+ else
21
+ module = RBASIC(module)->klass;
22
+ /***************************************************************************** */
23
+
24
+ }
25
+ if (!RCLASS_IV_TBL(module)) {
26
+ RCLASS_IV_TBL(module) = st_init_numtable();
27
+ }
28
+ RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);
29
+ RCLASS_M_TBL(klass) = RCLASS_M_TBL(module);
30
+ RCLASS_SUPER(klass) = super;
31
+ if (TYPE(module) == T_ICLASS) {
32
+ RBASIC(klass)->klass = RBASIC(module)->klass;
33
+ }
34
+ else {
35
+ RBASIC(klass)->klass = module;
36
+ }
37
+ OBJ_INFECT(klass, module);
38
+ OBJ_INFECT(klass, super);
39
+
40
+ return (VALUE)klass;
41
+ }
42
+
43
+ static void
44
+ rb_patched_include_module(VALUE klass, VALUE module)
45
+ {
46
+ VALUE p, c;
47
+ int changed = 0;
48
+
49
+ rb_frozen_class_p(klass);
50
+ if (!OBJ_UNTRUSTED(klass)) {
51
+ rb_secure(4);
52
+ }
53
+
54
+ if (TYPE(module) != T_MODULE) {
55
+ Check_Type(module, T_MODULE);
56
+ }
57
+
58
+ OBJ_INFECT(klass, module);
59
+ c = klass;
60
+ while (module) {
61
+ int superclass_seen = FALSE;
62
+
63
+ if (RCLASS_M_TBL(klass) == RCLASS_M_TBL(module))
64
+ rb_raise(rb_eArgError, "cyclic include detected");
65
+ /* ignore if the module included already in superclasses */
66
+ for (p = RCLASS_SUPER(klass); p; p = RCLASS_SUPER(p)) {
67
+ switch (BUILTIN_TYPE(p)) {
68
+ case T_ICLASS:
69
+ if (RCLASS_M_TBL(p) == RCLASS_M_TBL(module)) {
70
+ if (!superclass_seen) {
71
+ c = p; /* move insertion point */
72
+ }
73
+ goto skip;
74
+ }
75
+ break;
76
+ case T_CLASS:
77
+ superclass_seen = TRUE;
78
+ break;
79
+ }
80
+ }
81
+ c = RCLASS_SUPER(c) = include_class_new(module, RCLASS_SUPER(c));
82
+ if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries)
83
+ changed = 1;
84
+ skip:
85
+ module = RCLASS_SUPER(module);
86
+ }
87
+ if (changed) rb_clear_cache();
88
+ }
89
+
90
+ static VALUE
91
+ rb_patched_mod_append_features(VALUE module, VALUE include)
92
+ {
93
+ switch (TYPE(include)) {
94
+ case T_CLASS:
95
+ case T_MODULE:
96
+ break;
97
+ default:
98
+ Check_Type(include, T_CLASS);
99
+ break;
100
+ }
101
+ rb_patched_include_module(include, module);
102
+
103
+ return module;
104
+ }
105
+
106
+ void
107
+ Init_patched_include() {
108
+ rb_define_method(rb_cModule, "append_features", rb_patched_mod_append_features, 1);
109
+ }
@@ -0,0 +1,62 @@
1
+ # (c) 2010 John Mair (banisterfiend), MIT license
2
+
3
+ direc = File.dirname(__FILE__)
4
+
5
+ begin
6
+ if RUBY_VERSION && RUBY_VERSION =~ /1.9/
7
+ require "#{direc}/1.9/include_complete"
8
+ else
9
+ require "#{direc}/1.8/include_complete"
10
+ end
11
+ rescue LoadError => e
12
+ require 'rbconfig'
13
+ dlext = Config::CONFIG['DLEXT']
14
+ require "#{direc}/include_complete.#{dlext}"
15
+ end
16
+
17
+ require "#{direc}/include_complete/version"
18
+
19
+
20
+ class Module
21
+
22
+ # include modules (and their singletons) into an
23
+ # inheritance chain
24
+ # @param [Module] mods Modules to include_complete
25
+ # @return Returns the receiver
26
+ # @example
27
+ # module M
28
+ # def self.hello
29
+ # puts "hello"
30
+ # end
31
+ # end
32
+ # class C
33
+ # include_complete M
34
+ # end
35
+ # C.hello #=> "hello"
36
+ def include_complete(*mods)
37
+ mods.each do |mod|
38
+ include_complete_one mod
39
+ end
40
+ self
41
+ end
42
+ end
43
+
44
+ class Object
45
+
46
+ # extend modules (and their singletons) into an
47
+ # inheritance chain
48
+ # @param [Module] mods Modules to extend_complete
49
+ # @return Returns the receiver
50
+ # @example
51
+ # module M
52
+ # def self.hello
53
+ # puts "hello"
54
+ # end
55
+ # end
56
+ # o = Object.new
57
+ # o.extend_complete M
58
+ # o.singleton_class.hello #=> "hello"
59
+ def extend_complete(*mods)
60
+ class << self; self; end.send(:include_complete, *mods)
61
+ end
62
+ end
@@ -0,0 +1,3 @@
1
+ module IncludeComplete
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,14 @@
1
+ require '../lib/real_include'
2
+
3
+ 5000.times {
4
+ m = Module.new
5
+ n = Module.new
6
+ k = Module.new
7
+ n.real_include m
8
+ k.real_include n
9
+
10
+ c = Class.new
11
+ c.real_include k
12
+ }
13
+
14
+ "stress test passed!".display
@@ -0,0 +1,262 @@
1
+ direc = File.dirname(__FILE__)
2
+
3
+ require 'rubygems'
4
+ require "#{direc}/../lib/include_complete"
5
+ require 'bacon'
6
+
7
+ puts "Testing IncludeComplete version #{IncludeComplete::VERSION}..."
8
+ puts "Ruby version #{RUBY_VERSION}"
9
+
10
+ describe 'Including a module into a class using include_complete' do
11
+ before do
12
+ @m = Module.new {
13
+ def self.class_method
14
+ :class_method
15
+ end
16
+
17
+ def instance_method
18
+ :instance_method
19
+ end
20
+ }
21
+
22
+ @m::CONST = :const
23
+
24
+ @c = Class.new
25
+
26
+ @c.send(:include_complete, @m)
27
+ end
28
+
29
+ it 'should make class methods accessible to class' do
30
+ @c.class_method.should.equal :class_method
31
+ end
32
+
33
+ it 'should make instance methods accessible to instances of the class' do
34
+ obj = @c.new
35
+ obj.instance_method.should.equal :instance_method
36
+ end
37
+
38
+ it 'should make constants accessible to the class' do
39
+ lambda { @c::CONST }.should.not.raise NameError
40
+ end
41
+ end
42
+
43
+ describe 'Extending a module into a class using extend_complete' do
44
+ before do
45
+ @m = Module.new {
46
+ def self.class_method
47
+ :class_method
48
+ end
49
+
50
+ def instance_method
51
+ :instance_method
52
+ end
53
+ }
54
+
55
+ @m::CONST = :const
56
+
57
+ @c = Class.new
58
+
59
+ @c.send(:extend_complete, @m)
60
+ end
61
+
62
+ it 'should make instance methods from the module available as class methods on the class' do
63
+ @c.instance_method.should.equal :instance_method
64
+ end
65
+
66
+ it 'should make class methods from the module available as class methods on the singleton class' do
67
+ class << @c; self; end.class_method.should.equal :class_method
68
+ end
69
+ end
70
+
71
+
72
+ describe 'Including a module into a module and then into a class using include_complete' do
73
+ before do
74
+ @m1 = Module.new {
75
+ def self.class_method1
76
+ :class_method1
77
+ end
78
+
79
+ def instance_method1
80
+ :instance_method1
81
+ end
82
+ }
83
+
84
+ @m1::CONST1 = :const1
85
+
86
+ @m2 = Module.new {
87
+ def self.class_method2
88
+ :class_method2
89
+ end
90
+
91
+ def instance_method2
92
+ :instance_method2
93
+ end
94
+ }
95
+ @m2.send(:include_complete, @m1)
96
+
97
+ @m2::CONST2 = :const2
98
+
99
+ @c = Class.new
100
+
101
+ @c.send(:include_complete, @m2)
102
+ end
103
+
104
+ it 'should make class methods on m1 accessible to m2' do
105
+ @m2.class_method1.should.equal :class_method1
106
+ end
107
+
108
+ it 'should make constants on m1 and m2 accessible to class' do
109
+ lambda { @c::CONST1 == :const1 }.should.not.raise NameError
110
+ lambda { @m2::CONST1 == :const1 }.should.not.raise NameError
111
+ lambda { @c::CONST2 == :const2 }.should.not.raise NameError
112
+ end
113
+
114
+ it 'should make class methods on modules m1 and m2 accessible to class' do
115
+ @c.class_method1.should.equal :class_method1
116
+ @c.class_method2.should.equal :class_method2
117
+ end
118
+
119
+ it 'should make instance methods on modules m1 and m2 accessible to instances of class' do
120
+ obj = @c.new
121
+
122
+ obj.instance_method1.should.equal :instance_method1
123
+ obj.instance_method2.should.equal :instance_method2
124
+ end
125
+
126
+ it 'should make ancestor chain "look" accurate' do
127
+ @m1 = Module.new {
128
+ def self.class_method1
129
+ :class_method1
130
+ end
131
+
132
+ def instance_method1
133
+ :instance_method1
134
+ end
135
+ }
136
+
137
+ Object.const_set(:M1, @m1)
138
+
139
+ @m2 = Module.new {
140
+ def self.class_method2
141
+ :class_method2
142
+ end
143
+
144
+ def instance_method2
145
+ :instance_method2
146
+ end
147
+ }
148
+ Object.const_set(:M2, @m2)
149
+
150
+ @m2.send(:include_complete, @m1)
151
+
152
+ @c = Class.new
153
+
154
+ @c.send(:include_complete, @m2)
155
+
156
+ @c.ancestors[1].to_s.should.equal M2.name
157
+ @c.class_method1.should.equal :class_method1
158
+ @c.class_method2.should.equal :class_method2
159
+ end
160
+
161
+ it 'should work if real_including a module that has another module included using Module#include' do
162
+ @m1 = Module.new {
163
+ def self.class_method1
164
+ :class_method1
165
+ end
166
+
167
+ def instance_method1
168
+ :instance_method1
169
+ end
170
+ }
171
+
172
+ Object.const_set(:N1, @m1)
173
+
174
+ @m2 = Module.new {
175
+ def self.class_method2
176
+ :class_method2
177
+ end
178
+
179
+ def instance_method2
180
+ :instance_method2
181
+ end
182
+ }
183
+ Object.const_set(:N2, @m2)
184
+
185
+ @m2.send(:include, @m1)
186
+
187
+ @c = Class.new
188
+
189
+ @c.send(:include_complete, @m2)
190
+
191
+ @c.ancestors[1].to_s.should.equal N2.name
192
+ @c.ancestors[2].to_s.should.equal N1.name
193
+ @c.class_method1.should.equal :class_method1
194
+ @c.class_method2.should.equal :class_method2
195
+ end
196
+
197
+ it 'should work if Module#including a module that has another module included using include_complete' do
198
+ @m1 = Module.new {
199
+ def self.class_method1
200
+ :class_method1
201
+ end
202
+
203
+ def instance_method1
204
+ :instance_method1
205
+ end
206
+ }
207
+
208
+ Object.const_set(:K1, @m1)
209
+
210
+ @m2 = Module.new {
211
+ def self.class_method2
212
+ :class_method2
213
+ end
214
+
215
+ def instance_method2
216
+ :instance_method2
217
+ end
218
+ }
219
+ Object.const_set(:K2, @m2)
220
+
221
+ @m2.send(:include_complete, @m1)
222
+
223
+ @c = Class.new
224
+
225
+ @c.send(:include, @m2)
226
+
227
+ @c.ancestors[1].should.equal K2
228
+ @c.ancestors[2].should.equal K1
229
+ @c.new.instance_method1.should.equal :instance_method1
230
+ @c.new.instance_method2.should.equal :instance_method2
231
+ end
232
+
233
+
234
+ it 'should work with multiple modules passed to include_complete' do
235
+ @m1 = Module.new {
236
+ def self.class_method1
237
+ :class_method1
238
+ end
239
+
240
+ def instance_method1
241
+ :instance_method1
242
+ end
243
+ }
244
+
245
+ @m2 = Module.new {
246
+ def self.class_method2
247
+ :class_method2
248
+ end
249
+
250
+ def instance_method2
251
+ :instance_method2
252
+ end
253
+ }
254
+
255
+ @c = Class.new
256
+ @c.send(:include_complete, @m2, @m1)
257
+
258
+ @c.class_method1.should.equal :class_method1
259
+ @c.class_method2.should.equal :class_method2
260
+ end
261
+
262
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: include_complete
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - John Mair (banisterfiend)
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-01 00:00:00 +13:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Fixing the limitations in traditional Module#include
23
+ email: jrmair@gmail.com
24
+ executables: []
25
+
26
+ extensions:
27
+ - ext/include_complete/extconf.rb
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - Rakefile
32
+ - README.markdown
33
+ - CHANGELOG
34
+ - lib/include_complete/version.rb
35
+ - lib/include_complete.rb
36
+ - ext/include_complete/extconf.rb
37
+ - ext/include_complete/compat.h
38
+ - ext/include_complete/include_complete.c
39
+ - ext/include_complete/include_complete_one.c
40
+ - ext/include_complete/patched_include.c
41
+ - test/stress_test.rb
42
+ - test/test.rb
43
+ has_rdoc: yard
44
+ homepage: http://banisterfiend.wordpress.com
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options: []
49
+
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.7
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Fixing the limitations in traditional Module#include
77
+ test_files: []
78
+