Skip to content
Browse files

Update C extension and test cases to be compatible with Ruby 1.9

  • Loading branch information...
1 parent b150998 commit f683dded4a36ee960e5d50e49c6e2b788ba1d214 @tianyicui tianyicui committed with
Showing with 133 additions and 82 deletions.
  1. +3 −0 .gitignore
  2. +3 −1 README.markdown
  3. +1 −3 Rakefile
  4. +1 −0 ext/mixology/extconf.rb
  5. +111 −67 ext/mixology/mixology.c
  6. +11 −11 test/mixology_test.rb
  7. +3 −0 test/test_helper.rb
View
3 .gitignore
@@ -1,2 +1,5 @@
*.rbc
+*.o
+*.so
+pkg/
View
4 README.markdown
@@ -27,7 +27,7 @@ that's pretty much it. for other examples, take a look at the tests.
implementations
---------------
-* MRI 1.8.x
+* MRI 1.8.x, 1.9.x
* JRuby 1.1.x
collaborators
@@ -37,6 +37,8 @@ collaborators
* anonymous z
* [Dan Manges](http://www.dcmanges.com/blog)
* Clint Bishop
+* [Banister Fiend](http://banisterfiend.wordpress.com/)
+* [Tianyi Cui](http://cuitianyi.com/)
source
------
View
4 Rakefile
@@ -30,11 +30,9 @@ file "ext/mixology/mixology.#{Config::CONFIG['DLEXT']}" do
cp "ext/mixology/mixology.#{Config::CONFIG['DLEXT']}", "lib"
end
-CLEAN.include %w[ext/mixology/Makefile ext/mixology/mixology.bundle lib/mixology.bundle]
+CLEAN.include %w[ext/mixology/Makefile ext/mixology/mixology.bundle ext/mixology/mixology.so lib/mixology.bundle lib/mixology.so ext/mixology/mixology.o]
CLEAN.include %w[ext/mixology/MixableService.class ext/mixology/mixable.jar lib/mixology.jar]
-Gem::manage_gems
-
specification = Gem::Specification.new do |s|
s.name = "mixology"
s.summary = "Mixology enables objects to mixin and unmix modules."
View
1 ext/mixology/extconf.rb
@@ -1,3 +1,4 @@
require "mkmf"
dir_config "mixology"
+$CPPFLAGS += " -DRUBY_19" if RUBY_VERSION =~ /1.9/
create_makefile "mixology"
View
178 ext/mixology/mixology.c
@@ -1,81 +1,125 @@
#include "ruby.h"
-static void remove_nested_module(VALUE klass, VALUE include_class) {
-
- if(RBASIC(RCLASS(klass)->super)->klass != RBASIC(RCLASS(include_class)->super)->klass) {
- return;
- }
- if(RCLASS(RCLASS(include_class)->super)->super && BUILTIN_TYPE(RCLASS(include_class)->super) == T_ICLASS) {
- remove_nested_module(RCLASS(klass)->super, RCLASS(include_class)->super);
- }
- RCLASS(klass)->super = RCLASS(RCLASS(klass)->super)->super;
+/* cannot use ordinary CLASS_OF as it does not return an lvalue */
+#define KLASS_OF(c) (RBASIC(c)->klass)
+
+/* macros for backwards compatibility with 1.8 */
+#ifndef RUBY_19
+# define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
+# define RCLASS_SUPER(c) (RCLASS(c)->super)
+# define RCLASS_IV_TBL(c) (RCLASS(c)->iv_tbl)
+#endif
+
+#ifdef RUBY_19
+static VALUE class_alloc(VALUE flags, VALUE klass)
+{
+ rb_classext_t *ext = ALLOC(rb_classext_t);
+ NEWOBJ(obj, struct RClass);
+ OBJSETUP(obj, klass, flags);
+ obj->ptr = ext;
+ RCLASS_IV_TBL(obj) = 0;
+ RCLASS_M_TBL(obj) = 0;
+ RCLASS_SUPER(obj) = 0;
+ RCLASS_IV_INDEX_TBL(obj) = 0;
+ return (VALUE)obj;
}
+#endif
-static VALUE rb_unmix(VALUE self, VALUE module) {
- VALUE klass;
- for (klass = RBASIC(self)->klass; klass != rb_class_real(klass); klass = RCLASS(klass)->super) {
- VALUE super = RCLASS(klass)->super;
- if (BUILTIN_TYPE(super) == T_ICLASS) {
- if (RBASIC(super)->klass == module) {
- if(RCLASS(module)->super && BUILTIN_TYPE(RCLASS(module)->super) == T_ICLASS)
- remove_nested_module(super, module);
- RCLASS(klass)->super = RCLASS(RCLASS(klass)->super)->super;
- rb_clear_cache();
- }
- }
- }
- return self;
+static void remove_nested_module(VALUE klass, VALUE include_class)
+{
+ if (KLASS_OF(RCLASS_SUPER(klass)) != KLASS_OF(RCLASS_SUPER(include_class))) {
+ return;
+ }
+ if (RCLASS_SUPER(RCLASS_SUPER(include_class)) && BUILTIN_TYPE(RCLASS_SUPER(include_class)) == T_ICLASS) {
+ remove_nested_module(RCLASS_SUPER(klass), RCLASS_SUPER(include_class));
+ }
+ RCLASS_SUPER(klass) = RCLASS_SUPER(RCLASS_SUPER(klass));
}
-static void add_module(VALUE self, VALUE module) {
- VALUE super = RCLASS(rb_singleton_class(self))->super;
- NEWOBJ(klass, struct RClass);
- OBJSETUP(klass, rb_cClass, T_ICLASS);
-
- if (BUILTIN_TYPE(module) == T_ICLASS) {
- module = RBASIC(module)->klass;
- }
- if (!RCLASS(module)->iv_tbl) {
- RCLASS(module)->iv_tbl = (void*)st_init_numtable();
- }
- klass->iv_tbl = RCLASS(module)->iv_tbl;
- klass->m_tbl = RCLASS(module)->m_tbl;
- klass->super = super;
- if (TYPE(module) == T_ICLASS) {
- RBASIC(klass)->klass = RBASIC(module)->klass;
- }
- else {
- RBASIC(klass)->klass = module;
- }
- OBJ_INFECT(klass, module);
- OBJ_INFECT(klass, super);
-
- RCLASS(rb_singleton_class(self))->super = (int)klass;
+static VALUE rb_unmix(VALUE self, VALUE module)
+{
+ VALUE klass;
+
+ /* check that module is valid */
+ if (TYPE(module) != T_MODULE)
+ rb_raise(rb_eArgError, "error: parameter must be a module");
+
+ for (klass = KLASS_OF(self); klass != rb_class_real(klass); klass = RCLASS_SUPER(klass)) {
+ VALUE super = RCLASS_SUPER(klass);
+ if (BUILTIN_TYPE(super) == T_ICLASS) {
+ if (KLASS_OF(super) == module) {
+ if (RCLASS_SUPER(module) && BUILTIN_TYPE(RCLASS_SUPER(module)) == T_ICLASS)
+ remove_nested_module(super, module);
+ RCLASS_SUPER(klass) = RCLASS_SUPER(RCLASS_SUPER(klass));
+ rb_clear_cache();
+ }
+ }
+ }
+ return self;
}
-static VALUE rb_mixin(VALUE self, VALUE module) {
- VALUE nested_modules;
- VALUE nested_module;
- int index;
- rb_unmix(self, module);
+static void add_module(VALUE self, VALUE module)
+{
+ VALUE super = RCLASS_SUPER(rb_singleton_class(self));
- nested_modules = rb_mod_included_modules(module);
- //VALUE nested_modules = rb_mod_included_modules(module);
- for (index = RARRAY(nested_modules)->len; index > 0; index--) {
- nested_module = RARRAY(nested_modules)->ptr[index-1];
- add_module(self, nested_module);
- }
+#ifdef RUBY_19
+ VALUE klass = class_alloc(T_ICLASS, rb_cClass);
+#else
+ NEWOBJ(klass, struct RClass);
+ OBJSETUP(klass, rb_cClass, T_ICLASS);
+#endif
- add_module(self, module);
+ if (BUILTIN_TYPE(module) == T_ICLASS) {
+ module = KLASS_OF(module);
+ }
+ if (!RCLASS_IV_TBL(module)) {
+ RCLASS_IV_TBL(module) = (void*)st_init_numtable();
+ }
- rb_clear_cache();
- return self;
+ RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);
+ RCLASS_M_TBL(klass) = RCLASS_M_TBL(module);
+ RCLASS_SUPER(klass) = super;
+
+ if (TYPE(module) == T_ICLASS) {
+ KLASS_OF(klass) = KLASS_OF(module);
+ } else {
+ KLASS_OF(klass) = module;
+ }
+ OBJ_INFECT(klass, module);
+ OBJ_INFECT(klass, super);
+
+ RCLASS_SUPER(rb_singleton_class(self)) = (VALUE)klass;
}
- void Init_mixology() {
- VALUE Mixology = rb_define_module("Mixology");
- rb_define_method(Mixology, "mixin", rb_mixin, 1);
- rb_define_method(Mixology, "unmix", rb_unmix, 1);
- rb_include_module(rb_cObject, Mixology);
- }
+static VALUE rb_mixin(VALUE self, VALUE module)
+{
+ VALUE nested_modules;
+ int index;
+
+ /* check that module is valid */
+ if (TYPE(module) != T_MODULE)
+ rb_raise(rb_eArgError, "error: parameter must be a module");
+
+ rb_unmix(self, module);
+ nested_modules = rb_mod_included_modules(module);
+
+ for (index = RARRAY_LEN(nested_modules); index > 0; index--) {
+ VALUE nested_module = RARRAY_PTR(nested_modules)[index - 1];
+ add_module(self, nested_module);
+ }
+
+ add_module(self, module);
+
+ rb_clear_cache();
+ return self;
+}
+
+void Init_mixology()
+{
+ VALUE Mixology = rb_define_module("Mixology");
+
+ rb_define_method(Mixology, "mixin", rb_mixin, 1);
+ rb_define_method(Mixology, "unmix", rb_unmix, 1);
+ rb_include_module(rb_cObject, Mixology);
+}
View
22 test/mixology_test.rb
@@ -64,7 +64,7 @@ def test_included_modules_after_mixin
mixin = Module.new
object = Object.new
object.mixin mixin
- assert_equal [mixin, Mixology, Kernel], (class << object; self; end).included_modules
+ assert_equal [mixin, Mixology, PP::ObjectMixin, Kernel], (class << object; self; end).included_modules
end
def test_included_modules_after_unmix
@@ -72,7 +72,7 @@ def test_included_modules_after_unmix
object = Object.new
object.mixin mixin
object.unmix mixin
- assert_equal [Mixology, Kernel], (class << object; self; end).included_modules
+ assert_equal [Mixology, PP::ObjectMixin, Kernel], (class << object; self; end).included_modules
end
def test_included_modules_after_remix
@@ -81,9 +81,9 @@ def test_included_modules_after_remix
object = Object.new
object.mixin mixin_one
object.mixin mixin_two
- assert_equal [mixin_two, mixin_one, Mixology, Kernel], (class << object; self; end).included_modules
+ assert_equal [mixin_two, mixin_one, Mixology, PP::ObjectMixin, Kernel], (class << object; self; end).included_modules
object.mixin mixin_one
- assert_equal [mixin_one, mixin_two, Mixology, Kernel], (class << object; self; end).included_modules
+ assert_equal [mixin_one, mixin_two, Mixology, PP::ObjectMixin, Kernel], (class << object; self; end).included_modules
end
def test_mixin_returns_object
@@ -107,7 +107,7 @@ def test_nested_modules_are_mixedin
mixin = Module.new { include nested_module }
object = Object.new
object.mixin mixin
- assert_equal [mixin, nested_module, Mixology, Kernel], (class << object; self; end).included_modules
+ assert_equal [mixin, nested_module, Mixology, PP::ObjectMixin, Kernel], (class << object; self; end).included_modules
end
def test_nested_modules_are_mixedin_deeply
@@ -120,7 +120,7 @@ def test_nested_modules_are_mixedin_deeply
mixin = Module.new { include nested_module }
object = Object.new
object.mixin mixin
- assert_equal [mixin, nested_module, nested_module_penultimate, nested_module_ultimate, Mixology, Kernel], (class << object; self; end).included_modules
+ assert_equal [mixin, nested_module, nested_module_penultimate, nested_module_ultimate, Mixology, PP::ObjectMixin, Kernel], (class << object; self; end).included_modules
end
def test_nested_modules_are_mixedin_even_if_already_mixed_in
@@ -132,7 +132,7 @@ def test_nested_modules_are_mixedin_even_if_already_mixed_in
object = Object.new
object.mixin nested_module
object.mixin mixin
- assert_equal [mixin, nested_module, nested_module, Mixology, Kernel], (class << object; self; end).included_modules
+ assert_equal [mixin, nested_module, nested_module, Mixology, PP::ObjectMixin, Kernel], (class << object; self; end).included_modules
end
def test_module_is_not_unmixed_if_it_is_outside_nested_chain
@@ -142,7 +142,7 @@ def test_module_is_not_unmixed_if_it_is_outside_nested_chain
object.mixin nested_module
object.mixin mixin
object.unmix mixin
- assert_equal [nested_module, Mixology, Kernel], (class << object; self; end).included_modules
+ assert_equal [nested_module, Mixology, PP::ObjectMixin, Kernel], (class << object; self; end).included_modules
end
def test_nested_modules_are_unmixed
@@ -151,7 +151,7 @@ def test_nested_modules_are_unmixed
object = Object.new
object.mixin mixin
object.unmix mixin
- assert_equal [Mixology, Kernel], (class << object; self; end).included_modules
+ assert_equal [Mixology, PP::ObjectMixin, Kernel], (class << object; self; end).included_modules
end
def test_nested_modules_are_unmixed_deeply
@@ -162,7 +162,7 @@ def test_nested_modules_are_unmixed_deeply
object = Object.new
object.mixin mixin
object.unmix mixin
- assert_equal [Mixology, Kernel], (class << object; self; end).included_modules
+ assert_equal [Mixology, PP::ObjectMixin, Kernel], (class << object; self; end).included_modules
end
def test_unrelated_modules_are_not_unmixed
@@ -173,7 +173,7 @@ def test_unrelated_modules_are_not_unmixed
object.mixin unrelated
object.mixin mixin
object.unmix mixin
- assert_equal [unrelated, Mixology, Kernel], (class << object; self; end).included_modules
+ assert_equal [unrelated, Mixology, PP::ObjectMixin, Kernel], (class << object; self; end).included_modules
end
def rubinius?
View
3 test/test_helper.rb
@@ -1,4 +1,7 @@
require "test/unit"
+# In Ruby 1.9, require test/unit will implicitly require pp, we do it here explicitly to ensure compatibily.
+require "pp"
+
$LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
if defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx"
require "mixology_rubinius"

0 comments on commit f683dde

Please sign in to comment.
Something went wrong with that request. Please try again.