├── rice ├── .gitignore ├── Class.ipp ├── Module.ipp ├── Identifier.cpp ├── Class.hpp ├── Object.hpp ├── Data_Type.hpp ├── Arg.hpp ├── Data_Object.hpp ├── Module.hpp ├── to_from_ruby.hpp ├── Builtin_Object.hpp ├── Exception_Base.hpp ├── Exception_Base.ipp ├── detail │ ├── ruby_version_code.hpp.in │ ├── env.hpp │ ├── Exception_Handler.hpp │ ├── default_allocation_func.ipp │ ├── node.hpp │ ├── win32.hpp │ ├── demangle.hpp │ ├── st.hpp │ ├── cfp.hpp │ ├── method_data.hpp │ ├── to_ruby.hpp │ ├── check_ruby_type.hpp │ ├── Not_Copyable.hpp │ ├── object_call.ipp.mustache │ ├── default_allocation_func.hpp │ ├── Wrapped_Function.hpp │ ├── protect.cpp │ ├── define_method_and_auto_wrap.hpp │ ├── check_ruby_type.cpp │ ├── cfp.ipp │ ├── to_ruby.ipp │ ├── creation_funcs.ipp │ ├── define_method_and_auto_wrap.ipp │ ├── traits.hpp │ ├── object_call.hpp.mustache │ ├── protect.hpp │ ├── from_ruby.hpp │ ├── creation_funcs.hpp │ ├── demangle.cpp │ ├── from_ruby.ipp │ ├── Exception_Handler.ipp │ ├── wrap_function.hpp.mustache │ ├── ruby.hpp │ ├── wrap_function.ipp.mustache │ ├── Iterator.hpp │ ├── Caster.hpp │ ├── Exception_Handler_defn.hpp │ ├── method_data.cpp │ ├── Arguments.hpp │ ├── Auto_Function_Wrapper.hpp.mustache │ ├── Auto_Member_Function_Wrapper.hpp.mustache │ └── object_call.hpp ├── Data_Type_fwd.hpp ├── Address_Registration_Guard.hpp ├── Director.cpp ├── Exception.hpp ├── ruby_mark.hpp ├── Object.ipp ├── Symbol.cpp ├── Arg_operators.cpp ├── Arg_operators.hpp ├── Identifier.ipp ├── Struct.ipp ├── global_function.ipp ├── Jump_Tag.hpp ├── Address_Registration_Guard.cpp ├── Exception_Base_defn.hpp ├── code_gen │ ├── object_call.rb │ ├── gen.rb │ ├── protect.rb │ ├── wrap_function.rb │ ├── constructor.rb │ ├── auto_member_function_wrapper.rb │ ├── auto_function_wrapper.rb │ └── rice_template.rb ├── Require_Guard.hpp ├── Symbol.ipp ├── global_function.hpp ├── Address_Registration_Guard.ipp ├── Builtin_Object.ipp ├── Identifier.hpp ├── Class.cpp ├── Director.hpp ├── Data_Type.cpp ├── Exception.cpp ├── config.hpp.in ├── protect.hpp.mustache ├── Symbol.hpp ├── Module.cpp ├── Builtin_Object_defn.hpp ├── String.cpp ├── Exception_defn.hpp ├── to_from_ruby_defn.hpp ├── Constructor.hpp.mustache ├── Class_defn.hpp ├── Address_Registration_Guard_defn.hpp ├── String.hpp ├── Module_defn.hpp ├── rubypp.rb ├── Struct.cpp ├── ruby_try_catch.hpp ├── Makefile.am ├── Enum.hpp ├── Data_Object.ipp ├── Object.cpp ├── Arg_impl.hpp ├── protect.ipp.mustache ├── Data_Object_defn.hpp └── Struct.hpp ├── ruby ├── Makefile.am └── lib │ ├── .gitignore │ ├── version.rb │ └── Makefile.am ├── test ├── .gitignore ├── ext │ ├── t1 │ │ ├── extconf.rb │ │ ├── Foo.hpp │ │ └── t1.cpp │ ├── t2 │ │ ├── extconf.rb │ │ └── t2.cpp │ └── Makefile.am ├── test_Jump_Tag.cpp ├── test_multiple_extensions_same_class.rb ├── test_multiple_extensions.rb ├── test_multiple_extensions_with_inheritance.rb ├── test_Address_Registration_Guard.cpp ├── test_Exception.cpp ├── test_rice.rb ├── test_Memory_Management.cpp ├── test_Symbol.cpp ├── test_Identifier.cpp ├── Makefile.am ├── test_Builtin_Object.cpp ├── test_String.cpp ├── test_global_functions.cpp ├── test_Constructor.cpp ├── unittest.cpp └── test_Object.cpp ├── sample ├── map │ ├── extconf.rb │ ├── test.rb │ └── map.cpp ├── enum │ ├── extconf.rb │ ├── test.rb │ └── sample_enum.cpp ├── inheritance │ ├── extconf.rb │ ├── test.rb │ └── animals.cpp └── Makefile.am ├── bootstrap ├── README.mingw ├── BUILDING ├── TODO-ac ├── .travis.yml ├── .gitignore ├── Rakefile ├── post-autoconf.rb ├── Makefile.am ├── post-automake.rb ├── configure.ac ├── COPYING ├── CONTRIBUTORS.md ├── TODO ├── ANNOUNCE ├── extconf.rb ├── rice.gemspec └── ruby.ac /rice/.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | stamp-h1 3 | -------------------------------------------------------------------------------- /ruby/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = lib 2 | -------------------------------------------------------------------------------- /ruby/lib/.gitignore: -------------------------------------------------------------------------------- 1 | mkmf-rice.rb 2 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | unittest 2 | vm_unittest 3 | -------------------------------------------------------------------------------- /ruby/lib/version.rb: -------------------------------------------------------------------------------- 1 | module Rice 2 | VERSION = "2.1.2" 3 | end 4 | -------------------------------------------------------------------------------- /test/ext/t1/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf-rice' 2 | create_makefile('t1') 3 | -------------------------------------------------------------------------------- /test/ext/t2/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf-rice' 2 | create_makefile('t2') 3 | -------------------------------------------------------------------------------- /sample/map/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf-rice' 2 | create_makefile('map') 3 | 4 | -------------------------------------------------------------------------------- /ruby/lib/Makefile.am: -------------------------------------------------------------------------------- 1 | rubydir = @RUBY_SITELIBDIR@ 2 | 3 | ruby_DATA = mkmf-rice.rb 4 | -------------------------------------------------------------------------------- /sample/enum/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf-rice' 2 | create_makefile('sample_enum') 3 | 4 | -------------------------------------------------------------------------------- /sample/inheritance/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf-rice' 2 | create_makefile('animals') 3 | 4 | -------------------------------------------------------------------------------- /sample/map/test.rb: -------------------------------------------------------------------------------- 1 | require 'map' 2 | m = Std::Map.new 3 | m[0] = 1 4 | m[1] = 2 5 | m[3] = 3 6 | m.each { |x| p x } 7 | 8 | -------------------------------------------------------------------------------- /rice/Class.ipp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Class__ipp_ 2 | #define Rice__Class__ipp_ 3 | 4 | #include "Module.ipp" 5 | 6 | #endif // Rice__Class__ipp_ 7 | -------------------------------------------------------------------------------- /rice/Module.ipp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Module__ipp_ 2 | #define Rice__Module__ipp_ 3 | 4 | #include "Module_impl.ipp" 5 | 6 | #endif // Rice__Module__ipp_ 7 | -------------------------------------------------------------------------------- /rice/Identifier.cpp: -------------------------------------------------------------------------------- 1 | #include "Symbol.hpp" 2 | 3 | Rice::Identifier:: 4 | Identifier(Symbol const & symbol) 5 | : id_(SYM2ID(symbol.value())) 6 | { 7 | } 8 | 9 | -------------------------------------------------------------------------------- /sample/enum/test.rb: -------------------------------------------------------------------------------- 1 | require 'sample_enum' 2 | 3 | Sample_Enum.each { |x| p x } 4 | s = Sample_Enum::FOO 5 | puts s 6 | puts s.inspect 7 | puts s < Sample_Enum::BAR 8 | 9 | -------------------------------------------------------------------------------- /rice/Class.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Class__hpp_ 2 | #define Rice__Class__hpp_ 3 | 4 | #include "Class_defn.hpp" 5 | #include "Class.ipp" 6 | 7 | #endif // Rice__Class__hpp_ 8 | 9 | -------------------------------------------------------------------------------- /rice/Object.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Object__hpp_ 2 | #define Rice__Object__hpp_ 3 | 4 | #include "Object_defn.hpp" 5 | #include "Object.ipp" 6 | 7 | #endif // Rice__Object__hpp_ 8 | 9 | -------------------------------------------------------------------------------- /sample/inheritance/test.rb: -------------------------------------------------------------------------------- 1 | require 'animals' 2 | 3 | [ Bear, Dog, Rabbit].each do |klass| 4 | animal = klass.new 5 | puts "A #{animal.name} says: #{animal.speak}" 6 | end 7 | 8 | -------------------------------------------------------------------------------- /test/ext/t1/Foo.hpp: -------------------------------------------------------------------------------- 1 | #ifndef T1__FOO__HPP_ 2 | #define T1__FOO__HPP_ 3 | 4 | class Foo 5 | { 6 | public: 7 | int foo() { return 42; } 8 | }; 9 | 10 | #endif // T1__FOO__HPP_ 11 | -------------------------------------------------------------------------------- /rice/Data_Type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Data_Type__hpp_ 2 | #define Rice__Data_Type__hpp_ 3 | 4 | #include "Data_Type_defn.hpp" 5 | #include "Data_Type.ipp" 6 | 7 | #endif // Rice__Data_Type__hpp_ 8 | 9 | -------------------------------------------------------------------------------- /rice/Arg.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Arg__hpp_ 2 | #define Rice__Arg__hpp_ 3 | 4 | #include "Arg_impl.hpp" 5 | #include "detail/Arguments.hpp" 6 | #include "Arg_operators.hpp" 7 | 8 | #endif // Rice__Arg__hpp_ 9 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -f configure 3 | find . -name 'Makefile.in' | xargs rm -f 4 | autoreconf --install --verbose 5 | touch rice/config.hpp.in 6 | ruby post-autoconf.rb 7 | ruby post-automake.rb 8 | 9 | -------------------------------------------------------------------------------- /rice/Data_Object.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Data_Object__hpp_ 2 | #define Rice__Data_Object__hpp_ 3 | 4 | #include "Data_Object_defn.hpp" 5 | #include "Data_Object.ipp" 6 | 7 | #endif // Rice__Data_Object__hpp_ 8 | 9 | -------------------------------------------------------------------------------- /rice/Module.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__builtin__Module__hpp_ 2 | #define Rice__builtin__Module__hpp_ 3 | 4 | #include "Module_defn.hpp" 5 | #include "Module.ipp" 6 | 7 | #endif // Rice__builtin__Module__hpp_ 8 | 9 | -------------------------------------------------------------------------------- /rice/to_from_ruby.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__to_from_ruby__hpp_ 2 | #define Rice__to_from_ruby__hpp_ 3 | 4 | #include "to_from_ruby_defn.hpp" 5 | #include "to_from_ruby.ipp" 6 | 7 | #endif // Rice__to_from_ruby__hpp_ 8 | 9 | -------------------------------------------------------------------------------- /test/ext/t2/t2.cpp: -------------------------------------------------------------------------------- 1 | #include "../t1/Foo.hpp" 2 | #include "rice/Data_Type.hpp" 3 | 4 | using namespace Rice; 5 | 6 | extern "C" 7 | void Init_t2() 8 | { 9 | volatile Data_Type foo; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /rice/Builtin_Object.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Builtin_Object__hpp_ 2 | #define Rice__Builtin_Object__hpp_ 3 | 4 | #include "Builtin_Object_defn.hpp" 5 | #include "Builtin_Object.ipp" 6 | 7 | #endif // Rice__Builtin_Object__hpp_ 8 | 9 | -------------------------------------------------------------------------------- /rice/Exception_Base.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Exception_Base__hpp_ 2 | #define Rice__Exception_Base__hpp_ 3 | 4 | #include "Exception_Base_defn.hpp" 5 | #include "Exception_Base.ipp" 6 | 7 | #endif // Rice__Exception_Base__hpp_ 8 | 9 | -------------------------------------------------------------------------------- /rice/Exception_Base.ipp: -------------------------------------------------------------------------------- 1 | #include "Object.hpp" 2 | 3 | inline Rice::Exception_Base:: 4 | Exception_Base(VALUE v) 5 | : Object(v) 6 | { 7 | } 8 | 9 | inline Rice::Exception_Base:: 10 | ~Exception_Base() throw() 11 | { 12 | } 13 | 14 | -------------------------------------------------------------------------------- /rice/detail/ruby_version_code.hpp.in: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__ruby_version_code__hpp 2 | #define Rice__detail__ruby_version_code__hpp 3 | 4 | #define RICE__RUBY_VERSION_CODE @RUBY_VERSION_CODE@ 5 | 6 | #endif // Rice__detail__ruby_version_code__hpp 7 | -------------------------------------------------------------------------------- /rice/Data_Type_fwd.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Data_Type_fwd__hpp_ 2 | #define Rice__Data_Type_fwd__hpp_ 3 | 4 | namespace Rice 5 | { 6 | 7 | template 8 | class Data_Type; 9 | 10 | } // Rice 11 | 12 | #endif // Rice__Data_Type_fwd__hpp_ 13 | -------------------------------------------------------------------------------- /rice/detail/env.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__env__hpp_ 2 | #define Rice__detail__env__hpp_ 3 | 4 | /** 5 | * Helper header for the env.h ruby include file, which does 6 | * not have extern "C" 7 | */ 8 | 9 | #include "ruby_version_code.hpp" 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /rice/detail/Exception_Handler.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__Exception_Handler__hpp_ 2 | #define Rice__detail__Exception_Handler__hpp_ 3 | 4 | #include "Exception_Handler_defn.hpp" 5 | #include "Exception_Handler.ipp" 6 | 7 | #endif // Rice__detail__Exception_Handler__hpp_ 8 | 9 | -------------------------------------------------------------------------------- /rice/detail/default_allocation_func.ipp: -------------------------------------------------------------------------------- 1 | #include "../Data_Object.hpp" 2 | 3 | template 4 | VALUE Rice::detail:: 5 | default_allocation_func(VALUE klass) 6 | { 7 | Data_Object m(static_cast(0), klass); 8 | return m.value(); 9 | } 10 | 11 | 12 | -------------------------------------------------------------------------------- /rice/detail/node.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__node__hpp_ 2 | #define Rice__detail__node__hpp_ 3 | 4 | /** 5 | * Helper header for the node.h ruby include file, which does 6 | * not have extern "C" 7 | */ 8 | 9 | extern "C" { 10 | #include "node.h" 11 | } 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /rice/Address_Registration_Guard.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Address_Registration_Guard__hpp_ 2 | #define Rice__Address_Registration_Guard__hpp_ 3 | 4 | #include "Address_Registration_Guard_defn.hpp" 5 | #include "Address_Registration_Guard.ipp" 6 | 7 | #endif // Rice__Address_Registration_Guard__hpp_ 8 | -------------------------------------------------------------------------------- /test/test_Jump_Tag.cpp: -------------------------------------------------------------------------------- 1 | #include "unittest.hpp" 2 | #include "rice/Jump_Tag.hpp" 3 | 4 | using namespace Rice; 5 | 6 | TESTSUITE(Jump_Tag); 7 | 8 | SETUP(Jump_Tag) 9 | { 10 | } 11 | 12 | TESTCASE(construct) 13 | { 14 | Jump_Tag jump_tag(42); 15 | ASSERT_EQUAL(42, jump_tag.tag); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /rice/Director.cpp: -------------------------------------------------------------------------------- 1 | #include "Director.hpp" 2 | 3 | namespace Rice { 4 | 5 | Director::Director(Object self) { 6 | self_ = self; 7 | } 8 | 9 | void Director::raisePureVirtual() const { 10 | rb_raise(rb_eNotImpError, "Cannot call super() into a pure-virtual C++ method"); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /rice/Exception.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Exception__hpp_ 2 | #define Rice__Exception__hpp_ 3 | 4 | namespace Rice { 5 | class Exception; 6 | } 7 | 8 | #include "Exception_defn.hpp" 9 | #include "Exception_Base.hpp" 10 | #include "Address_Registration_Guard.hpp" 11 | 12 | #endif // Rice__Exception__hpp_ 13 | 14 | -------------------------------------------------------------------------------- /test/ext/t1/t1.cpp: -------------------------------------------------------------------------------- 1 | #include "Foo.hpp" 2 | 3 | #include "rice/Data_Type.hpp" 4 | #include "rice/Constructor.hpp" 5 | 6 | using namespace Rice; 7 | 8 | extern "C" 9 | void Init_t1() 10 | { 11 | define_class("Foo") 12 | .define_constructor(Constructor()) 13 | .define_method("foo", &Foo::foo); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /README.mingw: -------------------------------------------------------------------------------- 1 | Assuming you are using the one-click installer, you can build against it 2 | using mingw by configuring with the following command: 3 | 4 | $ CPPFLAGS=-D_MSC_VER=1200 LIBS=-lmsvcp60 ./configure 5 | 6 | Rice includes a number of customizations to allow it to work in this 7 | configuration. See [ruby-core:8264] for more details. 8 | 9 | -------------------------------------------------------------------------------- /BUILDING: -------------------------------------------------------------------------------- 1 | Before building anything, you'll need to run autotools: 2 | 3 | ./bootstrap 4 | 5 | Then, to build rice exactly as rubygems will: 6 | 7 | ruby extconf.rb && make 8 | 9 | This will ensure that certain flags and parameters are passed to configure 10 | according to the ruby version you are using and the platform you are building on 11 | -------------------------------------------------------------------------------- /TODO-ac: -------------------------------------------------------------------------------- 1 | rice/Makefile.am - should include files and sources be searched for or 2 | explicitly listed? 3 | pkgconfig support? 4 | why does doxygen check for perl? 5 | don't append -I../rice to CPPFLAGS when building tests (shouldn't depend 6 | on relative location within build tree) 7 | print ruby config options as they are found 8 | should PACKAGE_NAME et al be put into config.hpp? 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | rvm: 2 | - 2.0 3 | - 2.1 4 | - 2.2 5 | - 2.3 6 | - 2.4 7 | - ruby-head 8 | before_script: 9 | - gem install minitest 10 | - sh bootstrap 11 | - ruby extconf.rb 12 | - make 13 | script: "export LD_LIBRARY_PATH=`rvm config-get libdir`:$LD_LIBRARY_PATH && rake" 14 | branches: 15 | only: 16 | - master 17 | matrix: 18 | allow_failures: 19 | - rvm: ruby-head 20 | -------------------------------------------------------------------------------- /rice/ruby_mark.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ruby_mark__hpp 2 | #define ruby_mark__hpp 3 | 4 | //! Default function to call to mark a data object. 5 | /*! This function can be specialized for a particular type to override 6 | * the default behavior (which is to not mark any additional objects). 7 | */ 8 | template 9 | void ruby_mark(T * /* obj */) 10 | { 11 | } 12 | 13 | #endif // ruby_mark__hpp 14 | -------------------------------------------------------------------------------- /rice/detail/win32.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__win32__hpp_ 2 | #define Rice__detail__win32__hpp_ 3 | 4 | /*! \file 5 | * \brief Undefine all the evil macros that are defined in win32.h 6 | */ 7 | 8 | // None of these macros are used in Ruby header files 9 | #undef bind 10 | #undef read 11 | #undef write 12 | #undef send 13 | #undef recv 14 | #undef times 15 | 16 | #endif // Rice__detail__win32__hpp_ 17 | -------------------------------------------------------------------------------- /rice/detail/demangle.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__demangle__hpp_ 2 | #define Rice__detail__demangle__hpp_ 3 | 4 | #include 5 | 6 | namespace Rice 7 | { 8 | 9 | namespace detail 10 | { 11 | 12 | std::string demangle(char const * mangled_name); 13 | std::string demangle(std::string const & mangled_name); 14 | 15 | } // detail 16 | 17 | } // Rice 18 | 19 | #endif // Rice__detail__demangle__hpp_ 20 | -------------------------------------------------------------------------------- /test/test_multiple_extensions_same_class.rb: -------------------------------------------------------------------------------- 1 | $: << File.join(File.dirname(__FILE__), 'ext') 2 | 3 | require 'rubygems' 4 | gem 'minitest' 5 | require 'minitest/autorun' 6 | 7 | class MultipleExtensionsSameClassTest < Minitest::Test 8 | def test_multiple_extensions_same_class 9 | require 't1/t1' 10 | require 't2/t2' 11 | 12 | foo = Foo.new 13 | assert_equal 42, foo.foo 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /rice/Object.ipp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Object__ipp_ 2 | #define Rice__Object__ipp_ 3 | 4 | #include "protect.hpp" 5 | #include "detail/ruby.hpp" 6 | 7 | #include "detail/object_call.ipp" 8 | 9 | template 10 | void Rice::Object:: 11 | iv_set( 12 | Identifier name, 13 | T const & value) 14 | { 15 | protect(rb_ivar_set, *this, name.id(), to_ruby(value)); 16 | } 17 | 18 | #endif // Rice__Object__ipp_ 19 | 20 | -------------------------------------------------------------------------------- /rice/Symbol.cpp: -------------------------------------------------------------------------------- 1 | #include "Symbol.hpp" 2 | 3 | namespace 4 | { 5 | VALUE check_type(Rice::Object value, int type) 6 | { 7 | rb_check_type(value, type); 8 | return Qnil; 9 | } 10 | } 11 | 12 | Rice::Symbol:: 13 | Symbol(VALUE v) 14 | : Object(v) 15 | { 16 | protect(check_type, v, T_SYMBOL); 17 | } 18 | 19 | Rice::Symbol:: 20 | Symbol(Object v) 21 | : Object(v) 22 | { 23 | protect(check_type, v, T_SYMBOL); 24 | } 25 | 26 | -------------------------------------------------------------------------------- /rice/detail/st.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Exc_Ruby___cpp__st__hpp_ 2 | #define Exc_Ruby___cpp__st__hpp_ 3 | 4 | /*! \file 5 | * \brief Hacks to allow functions in st.h to be called from C++ 6 | * programs. 7 | */ 8 | 9 | #include "ruby.hpp" 10 | 11 | // Ruby doesn't put extern "C" around st.h 12 | 13 | extern "C" 14 | { 15 | #ifdef RUBY_VM 16 | #include "ruby/st.h" 17 | #else 18 | #include "st.h" 19 | #endif 20 | } 21 | 22 | #endif // Exc_Ruby___cpp__st__hpp_ 23 | -------------------------------------------------------------------------------- /rice/detail/cfp.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__cfp__hpp_ 2 | #define Rice__detail__cfp__hpp_ 3 | 4 | #include "ruby.hpp" 5 | 6 | namespace Rice 7 | { 8 | 9 | namespace detail 10 | { 11 | 12 | VALUE * cfp(); 13 | 14 | VALUE & cfp_data_memo_node_and_pc(VALUE * cfp); 15 | VALUE & cfp_self(VALUE * cfp); 16 | VALUE & cfp_method_class(VALUE * cfp); 17 | 18 | } // detail 19 | 20 | } // Rice 21 | 22 | #include "cfp.ipp" 23 | 24 | #endif // Rice__detail__cfp__hpp_ 25 | -------------------------------------------------------------------------------- /rice/Arg_operators.cpp: -------------------------------------------------------------------------------- 1 | #include "Arg_impl.hpp" 2 | #include "detail/Arguments.hpp" 3 | #include "Arg_operators.hpp" 4 | 5 | namespace Rice { 6 | 7 | Arguments* operator,(Arg arg1, Arg arg2) 8 | { 9 | Arguments* a = new Arguments(); 10 | a->add(arg1); 11 | a->add(arg2); 12 | return a; 13 | } 14 | 15 | Arguments* operator,(Arguments* arguments, Arg arg) 16 | { 17 | arguments->add(arg); 18 | return arguments; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /rice/detail/method_data.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__method_data__hpp 2 | #define Rice__detail__method_data__hpp 3 | 4 | #include "ruby.hpp" 5 | 6 | namespace Rice 7 | { 8 | 9 | namespace detail 10 | { 11 | 12 | VALUE define_method_with_data( 13 | VALUE klass, ID id, VALUE (*cfunc)(ANYARGS), int arity, VALUE data); 14 | 15 | VALUE method_data(); 16 | 17 | } // namespace detail 18 | 19 | } // namespace Rice 20 | 21 | #endif // Rice__detail__method_data__hpp 22 | -------------------------------------------------------------------------------- /test/test_multiple_extensions.rb: -------------------------------------------------------------------------------- 1 | $: << File.join(File.dirname(__FILE__), '..', 'sample') 2 | 3 | require 'rubygems' 4 | gem 'minitest' 5 | require 'minitest/autorun' 6 | 7 | class MultipleExtensionTest < Minitest::Test 8 | def test_multiple_extensions 9 | # Rinse 10 | require 'map/map' 11 | m = Std::Map.new 12 | m[0] = 1 13 | 14 | # And repeat 15 | require 'enum/sample_enum' 16 | m = Std::Map.new 17 | m[0] = 1 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /rice/detail/to_ruby.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__to_ruby__hpp_ 2 | #define Rice__detail__to_ruby__hpp_ 3 | 4 | namespace Rice 5 | { 6 | namespace detail 7 | { 8 | template 9 | struct to_ruby_ 10 | { 11 | static Rice::Object convert(T const & x); 12 | }; 13 | 14 | template 15 | struct to_ruby_ 16 | { 17 | static Rice::Object convert(T * x); 18 | }; 19 | } // detail 20 | } // Rice 21 | 22 | #endif // Rice__detail__to_ruby__hpp_ 23 | -------------------------------------------------------------------------------- /rice/detail/check_ruby_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__check_ruby_type__hpp_ 2 | #define Rice__detail__check_ruby_type__hpp_ 3 | 4 | #include "ruby.hpp" 5 | 6 | namespace Rice 7 | { 8 | 9 | namespace detail 10 | { 11 | 12 | // Throws an exception if the given object is not of type klass. 13 | void check_ruby_type( 14 | VALUE value, 15 | VALUE klass, 16 | bool include_super); 17 | 18 | } // namespace detail 19 | 20 | } // namespace Rice 21 | 22 | #endif // Rice__detail__check_ruby_type__hpp_ 23 | 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | Makefile.in 3 | aclocal.m4 4 | autom4te.cache 5 | rice/config.hpp 6 | rice/README.doxygen 7 | rice/detail/ruby_version_code.hpp 8 | config.log 9 | config.status 10 | config.guess 11 | config.sub 12 | configure 13 | depcomp 14 | install-sh 15 | missing 16 | test-driver 17 | pkg 18 | *.o 19 | *.so 20 | *.log 21 | .deps 22 | *~ 23 | .*.swp 24 | doc 25 | *.dSYM 26 | *.bundle 27 | 28 | # Msys / mingw generated files 29 | mkinstalldirs 30 | *.def 31 | *.exe 32 | 33 | ruby/lib/include 34 | ruby/lib/lib 35 | 36 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | $: << File.expand_path(File.dirname(__FILE__)) 2 | require 'rubygems' 3 | require 'rubygems/package_task' 4 | require 'yaml' 5 | require 'ruby/lib/version' 6 | 7 | task :default => :test 8 | 9 | desc "Run unit tests" 10 | task :test do 11 | cd "test" do 12 | ruby "test_rice.rb" 13 | end 14 | end 15 | 16 | desc "Build the documentation" 17 | task :doc do 18 | sh "make doc" 19 | end 20 | 21 | # Gemspec kept externally 22 | eval(File.read("rice.gemspec")) 23 | Gem::PackageTask.new($spec) do |pkg| 24 | end 25 | -------------------------------------------------------------------------------- /rice/Arg_operators.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Arg_Operators_hpp_ 2 | #define Rice__Arg_Operators_hpp_ 3 | 4 | namespace Rice 5 | { 6 | 7 | //! Build the list of Arg objects into an Arguments object 8 | /*! Take a list of Arg objects and build up a single Argument 9 | * object used later in method dispatch 10 | */ 11 | Arguments* operator,(Arg arg1, Arg arg2); 12 | 13 | /*! @see operator,(Arg, Arg) 14 | */ 15 | Arguments* operator,(Arguments* arguments, Arg arg); 16 | 17 | } 18 | 19 | #endif // Rice__Arg_Operators_hpp_ 20 | -------------------------------------------------------------------------------- /rice/Identifier.ipp: -------------------------------------------------------------------------------- 1 | inline Rice::Identifier:: 2 | Identifier(ID id) 3 | : id_(id) 4 | { 5 | } 6 | 7 | inline Rice::Identifier:: 8 | Identifier(char const * s) 9 | : id_(rb_intern(s)) 10 | { 11 | } 12 | 13 | inline char const * 14 | Rice::Identifier:: 15 | c_str() const 16 | { 17 | return rb_id2name(id_); 18 | } 19 | 20 | inline std::string 21 | Rice::Identifier:: 22 | str() const 23 | { 24 | return c_str(); 25 | } 26 | 27 | inline VALUE 28 | Rice::Identifier:: 29 | to_sym() const 30 | { 31 | return ID2SYM(id_); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /rice/detail/Not_Copyable.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Not_Copyable__hpp_ 2 | #define Rice__Not_Copyable__hpp_ 3 | 4 | namespace Rice 5 | { 6 | 7 | namespace detail 8 | { 9 | 10 | // Inherit from Not_Copyable to prevent copying instances of a class. 11 | class Not_Copyable 12 | { 13 | public: 14 | Not_Copyable() { } 15 | 16 | private: 17 | Not_Copyable(Not_Copyable const &); 18 | Not_Copyable & operator=(Not_Copyable const &); 19 | }; 20 | 21 | } // namespace detail 22 | 23 | } // namespace Rice 24 | 25 | #endif // Rice__Not_Copyable__hpp_ 26 | -------------------------------------------------------------------------------- /rice/Struct.ipp: -------------------------------------------------------------------------------- 1 | namespace Rice 2 | { 3 | 4 | template 5 | inline Object Struct::Instance:: 6 | operator[](T index) 7 | { 8 | return rb_struct_aref(value(), ULONG2NUM(index)); 9 | } 10 | 11 | template<> 12 | inline Object Struct::Instance:: 13 | operator[](Identifier member) 14 | { 15 | size_t index = type_.offset_of(member); 16 | return (*this)[index]; 17 | } 18 | 19 | template<> 20 | inline Object Struct::Instance:: 21 | operator[](char const * name) 22 | { 23 | return (*this)[Identifier(name)]; 24 | } 25 | 26 | } // Rice 27 | -------------------------------------------------------------------------------- /rice/global_function.ipp: -------------------------------------------------------------------------------- 1 | #include "detail/define_method_and_auto_wrap.hpp" 2 | 3 | template 4 | void Rice::define_global_function( 5 | char const * name, 6 | Func_T func, 7 | Arguments* arguments) 8 | { 9 | Module(rb_mKernel).define_module_function(name, func, arguments); 10 | } 11 | 12 | template 13 | void Rice::define_global_function( 14 | char const * name, 15 | Func_T func, 16 | Arg const& arg) 17 | { 18 | Arguments* args = new Arguments(); 19 | args->add(arg); 20 | define_global_function(name, func, args); 21 | } 22 | 23 | -------------------------------------------------------------------------------- /rice/detail/object_call.ipp.mustache: -------------------------------------------------------------------------------- 1 | // This is a generated file. DO NOT EDIT!! 2 | #include "../protect.hpp" 3 | #include "../to_from_ruby.hpp" 4 | 5 | inline Rice::Object Rice::Object:: 6 | call(Identifier id) const 7 | { 8 | VALUE args[] = { }; 9 | return protect(rb_funcall2, value(), id, 0, args); 10 | } 11 | 12 | {{#entries}} 13 | template<{{typenames}}> 14 | inline Rice::Object Rice::Object:: 15 | call(Identifier id, {{arguments}}) const 16 | { 17 | VALUE args[] = { {{to_rubies}} }; 18 | return protect(rb_funcall2, value(), id, {{arg_count}}, args); 19 | } 20 | 21 | {{/entries}} 22 | -------------------------------------------------------------------------------- /rice/Jump_Tag.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Jump_Tag__hpp_ 2 | #define Rice__Jump_Tag__hpp_ 3 | 4 | namespace Rice 5 | { 6 | 7 | //! A placeholder for Ruby longjmp data. 8 | /*! When a Ruby exception is caught, the tag used for the longjmp is stored in 9 | * a Jump_Tag, then later passed to rb_jump_tag() when there is no more 10 | * C++ code to pass over. 11 | */ 12 | struct Jump_Tag 13 | { 14 | //! Construct a Jump_Tag with tag t. 15 | Jump_Tag(int t) : tag(t) { } 16 | 17 | //! The tag being held. 18 | int tag; 19 | }; 20 | 21 | } // namespace Rice 22 | 23 | #endif // Rice__Jump_Tag__hpp_ 24 | 25 | -------------------------------------------------------------------------------- /post-autoconf.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | require 'find' 3 | 4 | def process(file) 5 | puts "Post-processing #{file}" 6 | File.open(file) do |input| 7 | File.open("#{file}.pp", "w") do |output| 8 | input.each_line do |line| 9 | yield output, line 10 | end 11 | end 12 | end 13 | FileUtils.mv("#{file}.pp", "#{file}") 14 | end 15 | 16 | process("configure") do |out, line| 17 | # autoconf doesn't properly enclose $srcdir and $am_aux_dir in quotes 18 | line.gsub!(/([^"'])(\$srcdir)/, '\1"\2"') 19 | line.gsub!(/([^"'])(\$am_aux_dir)/, '\1\"\2\"') 20 | out.puts line 21 | end 22 | FileUtils.chmod(0700, "configure") 23 | -------------------------------------------------------------------------------- /rice/Address_Registration_Guard.cpp: -------------------------------------------------------------------------------- 1 | #include "Address_Registration_Guard.hpp" 2 | 3 | bool Rice::Address_Registration_Guard::enabled = true; 4 | bool Rice::Address_Registration_Guard::exit_handler_registered = false; 5 | 6 | static void disable_all_guards(VALUE) 7 | { 8 | Rice::Address_Registration_Guard::disable(); 9 | } 10 | 11 | void Rice::Address_Registration_Guard::registerExitHandler() 12 | { 13 | if (exit_handler_registered) return; 14 | rb_set_end_proc(&disable_all_guards, Qnil); 15 | exit_handler_registered = true; 16 | } 17 | 18 | void Rice::Address_Registration_Guard::disable() 19 | { 20 | enabled = false; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /rice/detail/default_allocation_func.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__default_allocation_func__hpp_ 2 | #define Rice__detail__default_allocation_func__hpp_ 3 | 4 | namespace Rice 5 | { 6 | 7 | namespace detail 8 | { 9 | 10 | //! A default implementation of an allocate_func. This function does no 11 | //! actual allocation; the initialize_func can later do the real 12 | //! allocation with: DATA_PTR(self) = new Type(arg1, arg2, ...) 13 | template 14 | VALUE default_allocation_func(VALUE klass); 15 | 16 | } // detail 17 | 18 | } // Rice 19 | 20 | #include "default_allocation_func.ipp" 21 | 22 | #endif // Rice__detail__default_allocation_func__hpp_ 23 | 24 | -------------------------------------------------------------------------------- /rice/Exception_Base_defn.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Exception_Base_defn__hpp_ 2 | #define Rice__Exception_Base_defn__hpp_ 3 | 4 | #include "Object_defn.hpp" 5 | 6 | namespace Rice 7 | { 8 | 9 | //! An abstract interface for Exception 10 | /*! This class exists to prevent a circular reference between 11 | * Exception.hpp and ruby_try_catch.hpp 12 | */ 13 | class Exception_Base 14 | : public std::exception 15 | , public Object 16 | { 17 | public: 18 | Exception_Base(VALUE v); 19 | 20 | virtual ~Exception_Base() throw() = 0; 21 | 22 | virtual char const * what() const throw() = 0; 23 | }; 24 | 25 | } // Rice 26 | 27 | #endif // Rice__Exception_Base_defn__hpp_ 28 | -------------------------------------------------------------------------------- /rice/code_gen/object_call.rb: -------------------------------------------------------------------------------- 1 | require "rice_template" 2 | 3 | class ObjectCallHpp < RiceTemplate 4 | 5 | cpp_detail_file "object_call.hpp" 6 | 7 | def entry(c) 8 | { 9 | :typenames => build(c, "typename T{{i}}"), 10 | :arguments => build(c, "T{{i}} arg{{i}}") 11 | } 12 | end 13 | 14 | end 15 | 16 | class ObjectCallIpp < RiceTemplate 17 | 18 | cpp_detail_file "object_call.ipp" 19 | 20 | def entry(c) 21 | { 22 | :typenames => build(c, "typename T{{i}}"), 23 | :arguments => build(c, "T{{i}} arg{{i}}"), 24 | :to_rubies => build(c, "to_ruby(arg{{i}})"), 25 | :arg_count => c 26 | } 27 | end 28 | 29 | end 30 | -------------------------------------------------------------------------------- /rice/detail/Wrapped_Function.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__Wrapped_Function__hpp_ 2 | #define Rice__detail__Wrapped_Function__hpp_ 3 | 4 | #include "ruby.hpp" 5 | 6 | namespace Rice 7 | { 8 | 9 | namespace detail 10 | { 11 | 12 | class Wrapped_Function 13 | { 14 | public: 15 | Wrapped_Function(RUBY_METHOD_FUNC func, int arity) 16 | : func_(func) 17 | , arity_(arity) 18 | { 19 | } 20 | 21 | RUBY_METHOD_FUNC func() const { return func_; } 22 | int arity() const { return arity_; } 23 | 24 | private: 25 | RUBY_METHOD_FUNC func_; 26 | int arity_; 27 | }; 28 | 29 | } // detail 30 | 31 | } // Rice 32 | 33 | #endif // Rice__detail__Wrapped_Function__hpp_ 34 | -------------------------------------------------------------------------------- /rice/detail/protect.cpp: -------------------------------------------------------------------------------- 1 | #include "protect.hpp" 2 | #include "../Exception.hpp" 3 | #include "../Jump_Tag.hpp" 4 | 5 | #ifndef TAG_RAISE 6 | #define TAG_RAISE 0x6 7 | #endif 8 | 9 | VALUE Rice::detail:: 10 | protect( 11 | RUBY_VALUE_FUNC f, 12 | VALUE arg) 13 | { 14 | int state = 0; 15 | VALUE retval = rb_protect(f, arg, &state); 16 | if(state != 0) 17 | { 18 | VALUE err = rb_errinfo(); 19 | if(state == TAG_RAISE && RTEST(err)) 20 | { 21 | // TODO: convert NoMemoryError into bad_alloc? 22 | rb_set_errinfo(Rice::Nil); 23 | throw Rice::Exception(err); 24 | } 25 | throw Jump_Tag(state); 26 | } 27 | return retval; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /test/test_multiple_extensions_with_inheritance.rb: -------------------------------------------------------------------------------- 1 | $: << File.join(File.dirname(__FILE__), '..', 'sample') 2 | 3 | require 'rubygems' 4 | gem 'minitest' 5 | require 'minitest/autorun' 6 | 7 | class MultipleExtensionTest < Minitest::Test 8 | def test_multiple_extensions_with_inheritance 9 | # Load a library that uses inheritance 10 | require 'inheritance/animals' 11 | 12 | # Then load a different library 13 | require 'enum/sample_enum' 14 | 15 | # And make sure we can call methods in the base class on a derived 16 | # instance 17 | dog = Dog.new 18 | assert_equal dog.name, "Dog" 19 | assert_equal dog.speak, "Woof woof" 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = foreign 1.5 2 | SUBDIRS = rice test sample ruby 3 | 4 | include doxygen.am 5 | 6 | doc: doxygen-doc 7 | 8 | noinst_EXTRA = rice/README.doxygen 9 | 10 | DX_EXTRA_DEPEND = rice/README.doxygen 11 | 12 | EXTRA_DIST = \ 13 | README.mingw \ 14 | post-autoconf.rb \ 15 | post-automake.rb \ 16 | bootstrap \ 17 | Doxyfile \ 18 | ruby.ac \ 19 | doxygen.ac \ 20 | doxygen.am \ 21 | doc 22 | 23 | rice/README.doxygen: README.md 24 | @echo Generating documentation 25 | @$(RUBY) -e 'File.open("README.md") { |i| File.open("rice/README.doxygen", "w") { |o| o.puts "/*! #{i.gets}"; i.each_line { |l| o.puts " #{l}" if l !~ /^\\comment/ and l !~ /^vim:/ }; o.puts " */" } }'.md 26 | 27 | -------------------------------------------------------------------------------- /rice/Require_Guard.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Require_Guard__hpp_ 2 | #define Rice__Require_Guard__hpp_ 3 | 4 | /*! \def RICE_REQUIRE_GUARD 5 | * \brief Put this inside your Init_module function to keep it from 6 | * being required more than once with the same name (if you use 7 | * Rice, and your module is initialized more than once, an 8 | * exception will be thrown). 9 | */ 10 | #define RICE_REQUIRE_GUARD \ 11 | static bool Rice__module_initialized = false; \ 12 | if(Rice__module_initialized) \ 13 | { \ 14 | return; \ 15 | } \ 16 | /* TODO: If module initialization fails, it's not possible to */ \ 17 | /* retry */ \ 18 | Rice__module_initialized = true 19 | 20 | #endif // Rice__Require_Guard__hpp_ 21 | 22 | -------------------------------------------------------------------------------- /post-automake.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | require 'find' 3 | 4 | def process(file) 5 | puts "Post-processing #{file}" 6 | File.open(file) do |input| 7 | File.open("#{file}.pp", "w") do |output| 8 | input.each_line do |line| 9 | yield output, line 10 | end 11 | end 12 | end 13 | FileUtils.mv("#{file}.pp", "#{file}") 14 | end 15 | 16 | Find.find(".") do |file| 17 | if file =~ /Makefile.in$/ then 18 | process(file) do |out, line| 19 | # automake doesn't properly enclose $distdir in quotes 20 | if line !~ /echo / then 21 | line.gsub!(/([^"'])(\$\(distdir\))/, '\1"\2"') 22 | end 23 | line.gsub!(/(\$\(MKDIR_P\).*`)/, 'eval \1') 24 | out.puts line 25 | end 26 | end 27 | end 28 | 29 | -------------------------------------------------------------------------------- /rice/detail/define_method_and_auto_wrap.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__define_method_and_auto_wrap__hpp_ 2 | #define Rice__detail__define_method_and_auto_wrap__hpp_ 3 | 4 | #include "ruby.hpp" 5 | #include "../Data_Object.hpp" 6 | #include "../Identifier.hpp" 7 | #include "Arguments.hpp" 8 | 9 | namespace Rice 10 | { 11 | 12 | namespace detail 13 | { 14 | 15 | class Exception_Handler; 16 | 17 | template 18 | void define_method_and_auto_wrap( 19 | VALUE klass, 20 | Identifier name, 21 | Fun_T function, 22 | Data_Object handler, 23 | Arguments* arguments = 0); 24 | 25 | } // detail 26 | 27 | } // Rice 28 | 29 | #include "define_method_and_auto_wrap.ipp" 30 | 31 | #endif // Rice__detail__define_method_and_auto_wrap__hpp_ 32 | -------------------------------------------------------------------------------- /rice/detail/check_ruby_type.cpp: -------------------------------------------------------------------------------- 1 | #include "check_ruby_type.hpp" 2 | #include "../Exception.hpp" 3 | 4 | void Rice::detail:: 5 | check_ruby_type( 6 | VALUE value, 7 | VALUE klass, 8 | bool include_super 9 | ) 10 | { 11 | if( !rb_obj_is_kind_of(value, klass) || 12 | (!include_super && rb_obj_class(value) != klass)) 13 | { 14 | // Not sure why this stuff can't be chained 15 | VALUE gotV = protect(rb_mod_name, rb_obj_class(value)); 16 | char* got = StringValuePtr(gotV); 17 | VALUE exptV = protect(rb_mod_name, klass); 18 | char* expected = StringValuePtr(exptV); 19 | 20 | throw Exception( 21 | rb_eTypeError, 22 | "wrong argument type %s (expected %s)", 23 | got, expected 24 | ); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /rice/code_gen/gen.rb: -------------------------------------------------------------------------------- 1 | $:.unshift File.expand_path(File.dirname(__FILE__)) 2 | require 'object_call' 3 | require 'protect' 4 | require 'constructor' 5 | require 'wrap_function' 6 | require 'auto_function_wrapper' 7 | require 'auto_member_function_wrapper' 8 | 9 | # For each defined template generation system, we need to tell 10 | # them to generate the C++ code and write it out to the appropriate file. 11 | [ 12 | ObjectCallHpp, 13 | ObjectCallIpp, 14 | ProtectHpp, 15 | ProtectIpp, 16 | ConstructorHpp, 17 | WrapFunctionHpp, 18 | WrapFunctionIpp, 19 | AutoFunctionWrapperHpp, 20 | AutoFunctionWrapperIpp, 21 | AutoMemberFunctionWrapperHpp, 22 | AutoMemberFunctionWrapperIpp 23 | ].each do |klass| 24 | puts "Generating #{klass.out_file}" 25 | klass.render_to_file 26 | end 27 | 28 | puts "Code generation complete" 29 | -------------------------------------------------------------------------------- /rice/Symbol.ipp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Symbol__ipp_ 2 | #define Rice__Symbol__ipp_ 3 | 4 | #include "protect.hpp" 5 | #include "detail/ruby.hpp" 6 | 7 | inline Rice::Symbol:: 8 | Symbol(char const * s) 9 | : Object(ID2SYM(rb_intern(s))) 10 | { 11 | } 12 | 13 | inline Rice::Symbol:: 14 | Symbol(std::string const & s) 15 | : Object(ID2SYM(rb_intern(s.c_str()))) 16 | { 17 | } 18 | 19 | inline Rice::Symbol:: 20 | Symbol(Identifier id) 21 | : Object(ID2SYM(id)) 22 | { 23 | } 24 | 25 | inline char const * Rice::Symbol:: 26 | c_str() const 27 | { 28 | return to_id().c_str(); 29 | } 30 | 31 | inline std::string Rice::Symbol:: 32 | str() const 33 | { 34 | return to_id().str(); 35 | } 36 | 37 | inline Rice::Identifier Rice::Symbol:: 38 | to_id() const 39 | { 40 | return rb_to_id(value()); 41 | } 42 | 43 | #endif // Rice__Symbol__ipp_ 44 | 45 | -------------------------------------------------------------------------------- /rice/global_function.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__global_function__hpp_ 2 | #define Rice__global_function__hpp_ 3 | 4 | #include "Arg.hpp" 5 | 6 | namespace Rice 7 | { 8 | 9 | /** 10 | * Helper forwarder method to easily wrap 11 | * globally available functions. This simply 12 | * forwards off a call to define_module_function 13 | * on rb_mKernel 14 | */ 15 | template 16 | void define_global_function( 17 | char const * name, 18 | Func_T func, 19 | Arguments* arguments = 0); 20 | 21 | // FIXME: See Module::define_method with Arg 22 | template 23 | void define_global_function( 24 | char const * name, 25 | Func_T func, 26 | Arg const& arg); 27 | 28 | 29 | } // Rice 30 | 31 | #include "global_function.ipp" 32 | 33 | #endif // Rice__global_function__hpp_ 34 | -------------------------------------------------------------------------------- /rice/code_gen/protect.rb: -------------------------------------------------------------------------------- 1 | require "rice_template" 2 | 3 | class ProtectHpp < RiceTemplate 4 | 5 | cpp_file "protect.hpp" 6 | 7 | def entry(num) 8 | { 9 | :typenames => build(num, "typename T{{i}}"), 10 | :arguments => build(num, "T{{i}} const & t{{i}}") 11 | } 12 | end 13 | 14 | end 15 | 16 | class ProtectIpp < RiceTemplate 17 | 18 | cpp_file "protect.ipp" 19 | 20 | def entry(c) 21 | { 22 | :count => c, 23 | :typenames => build(c, "typename T{{i}}"), 24 | :types => build(c, "T{{i}}"), 25 | :arguments => build(c, "T{{i}} const & t{{i}}"), 26 | :members => build(c, "T{{i}} const & t{{i}}_", "; "), 27 | :supercalls => build(c, "t{{i}}_(t{{i}})"), 28 | :call_args => build(c, "t{{i}}"), 29 | :member_call_args => build(c, "t{{i}}_") 30 | } 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /rice/detail/cfp.ipp: -------------------------------------------------------------------------------- 1 | namespace detail 2 | { 3 | 4 | struct rb_thread_struct 5 | { 6 | VALUE self; 7 | void *vm; 8 | VALUE *stack; 9 | unsigned long stack_size; 10 | VALUE *cfp; 11 | /* ... */ 12 | }; 13 | 14 | typedef struct rb_thread_struct rb_thread_t; 15 | 16 | } // namespace detail 17 | 18 | extern "C" detail::rb_thread_t * ruby_current_thread; 19 | 20 | inline 21 | VALUE * 22 | Rice::detail:: 23 | cfp() 24 | { 25 | return ruby_current_thread->cfp; 26 | } 27 | 28 | inline 29 | VALUE & 30 | Rice::detail:: 31 | cfp_data_memo_node_and_pc(VALUE * cfp) 32 | { 33 | return cfp[0]; 34 | } 35 | 36 | inline 37 | VALUE & 38 | Rice::detail:: 39 | cfp_self(VALUE * cfp) 40 | { 41 | return cfp[5]; 42 | } 43 | 44 | inline 45 | VALUE & 46 | Rice::detail:: 47 | cfp_method_class(VALUE * cfp) 48 | { 49 | return cfp[11]; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /rice/detail/to_ruby.ipp: -------------------------------------------------------------------------------- 1 | #include "../Data_Object.hpp" 2 | 3 | template 4 | Rice::Object 5 | Rice::detail::to_ruby_:: 6 | convert(T const & x) 7 | { 8 | if(Data_Type::is_bound()) 9 | { 10 | return Rice::Data_Object(new T(x), Rice::Data_Type::klass()); 11 | } 12 | else 13 | { 14 | std::string s("Unable to convert "); 15 | s += demangle(typeid(T *).name()); 16 | throw std::invalid_argument(s.c_str()); 17 | } 18 | } 19 | 20 | template 21 | Rice::Object 22 | Rice::detail::to_ruby_:: 23 | convert(T * x) 24 | { 25 | if(Data_Type::is_bound()) 26 | { 27 | Data_Object obj(x); 28 | return obj; 29 | } 30 | else 31 | { 32 | std::string s("Unable to convert "); 33 | s += demangle(typeid(T *).name()); 34 | throw std::invalid_argument(s.c_str()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /rice/detail/creation_funcs.ipp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__creation_funcs__ipp_ 2 | #define Rice__detail__creation_funcs__ipp_ 3 | 4 | namespace Rice 5 | { 6 | 7 | namespace detail 8 | { 9 | 10 | template 11 | inline void define_creation_funcs( 12 | Class const & klass, 13 | RUBY_VALUE_FUNC allocate_func, 14 | Initialize_Func_T initialize_func) 15 | { 16 | rb_define_alloc_func(klass, allocate_func); 17 | klass.define_method("initialize", initialize_func); 18 | } 19 | 20 | inline void undef_alloc_func(Class const & klass) 21 | { 22 | rb_undef_alloc_func(klass); 23 | } 24 | 25 | inline void undef_creation_funcs(Class const & klass) 26 | { 27 | undef_alloc_func(klass); 28 | rb_undef_method(klass, "initialize"); 29 | } 30 | 31 | } // namespace detail 32 | 33 | } // namespace Rice 34 | 35 | #endif // Rice__detail__creation_funcs__ipp_ 36 | 37 | -------------------------------------------------------------------------------- /rice/detail/define_method_and_auto_wrap.ipp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__define_method_and_auto_wrap__ipp_ 2 | #define Rice__detail__define_method_and_auto_wrap__ipp_ 3 | 4 | #include "wrap_function.hpp" 5 | #include "method_data.hpp" 6 | #include "Exception_Handler_defn.hpp" 7 | #include "../protect.hpp" 8 | 9 | template 10 | void Rice::detail:: 11 | define_method_and_auto_wrap( 12 | VALUE klass, 13 | Identifier name, 14 | Fun_T function, 15 | Data_Object handler, 16 | Arguments* arguments) 17 | { 18 | Data_Object f( 19 | wrap_function(function, handler, arguments), 20 | rb_cObject); 21 | Rice::protect( 22 | define_method_with_data, 23 | klass, 24 | name.id(), 25 | f->func(), 26 | -1, 27 | f); 28 | } 29 | 30 | #endif // Rice__detail__define_method_and_auto_wrap__ipp_ 31 | -------------------------------------------------------------------------------- /rice/detail/traits.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__traits__hpp_ 2 | #define Rice__detail__traits__hpp_ 3 | 4 | namespace Rice 5 | { 6 | namespace detail 7 | { 8 | 9 | /** 10 | * Remove const from a type 11 | */ 12 | template 13 | struct remove_const { typedef T Type; }; 14 | 15 | template 16 | struct remove_const { typedef T Type; }; 17 | 18 | /** 19 | * Remove a reference from a type 20 | */ 21 | template 22 | struct remove_ref { typedef T Type; }; 23 | 24 | template 25 | struct remove_ref { typedef T Type; }; 26 | 27 | /** 28 | * Do both of the above in one easy step 29 | */ 30 | template 31 | struct sanitize 32 | { 33 | typedef T Type; 34 | //typedef typename remove_const< 35 | //typename remove_ref::Type 36 | //>::Type Type; 37 | }; 38 | 39 | } 40 | } 41 | 42 | 43 | #endif // Rice__detail__traits__hpp_ 44 | -------------------------------------------------------------------------------- /rice/detail/object_call.hpp.mustache: -------------------------------------------------------------------------------- 1 | // This is a generated file. DO NOT EDIT!! 2 | #ifdef DOXYGEN 3 | 4 | //! Call the Ruby method specified by 'id' on object 'obj'. 5 | /*! Pass in arguments (arg1, arg2, ...). The arguments will be converted to 6 | * Ruby objects with to_ruby<>. The return value will automatically be 7 | * converted to type Retval_T with from_ruby<>. 8 | * 9 | * E.g.: 10 | * \code 11 | * float y = x.call("foo", z, 42); 12 | * \endcode 13 | */ 14 | template 15 | Retval_T call(Identifier id, T1 arg1, T2 arg2, ...) const; 16 | 17 | //! Version of call which defaults to Object return type. 18 | Object call(Identifier id, T1 arg1, T2 arg2, ...) const; 19 | #else 20 | 21 | Object call(Identifier id) const; 22 | 23 | {{#entries}} 24 | template<{{typenames}}> 25 | Object call(Identifier id, {{arguments}}) const; 26 | 27 | {{/entries}} 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /rice/detail/protect.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__protect__hpp_ 2 | #define Rice__detail__protect__hpp_ 3 | 4 | #include "ruby.hpp" 5 | 6 | /*! \file 7 | * \brief Functions for making exception-safe calls into Ruby code. 8 | * These are the building blocks for building other exception-safe 9 | * helper functions. 10 | */ 11 | 12 | namespace Rice 13 | { 14 | 15 | namespace detail 16 | { 17 | 18 | //! Call the given function, converting Ruby exceptions to C++ 19 | //! exceptions. 20 | /*! Call the function f with the parameter arg If f raises a Ruby 21 | * exception, then the exception is re-thrown as an Exception. If f 22 | * exits with any other non-zero tag (e.g. a Symbol is thrown), then the 23 | * tag is re-thrown as a Jump_Tag. 24 | */ 25 | VALUE protect( 26 | RUBY_VALUE_FUNC f, 27 | VALUE arg); 28 | 29 | } // namespace detail 30 | 31 | } // namespace Rice 32 | 33 | #endif // Rice__detail__protect__hpp_ 34 | 35 | -------------------------------------------------------------------------------- /rice/detail/from_ruby.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__from_ruby__hpp_ 2 | #define Rice__detail__from_ruby__hpp_ 3 | 4 | namespace Rice 5 | { 6 | namespace detail 7 | { 8 | template 9 | struct from_ruby_ 10 | { 11 | typedef T Retval_T; 12 | 13 | static T convert(Rice::Object x); 14 | }; 15 | 16 | template 17 | struct from_ruby_ 18 | { 19 | typedef T * Retval_T; 20 | 21 | static T * convert(Rice::Object x); 22 | }; 23 | 24 | template 25 | struct from_ruby_ 26 | { 27 | typedef T const * Retval_T; 28 | 29 | static T const * convert(Rice::Object x); 30 | }; 31 | 32 | template 33 | struct from_ruby_ 34 | { 35 | typedef T & Retval_T; 36 | 37 | static T & convert(Rice::Object x); 38 | }; 39 | } // detail 40 | } // Rice 41 | 42 | #endif // Rice__detail__from_ruby__hpp_ 43 | 44 | -------------------------------------------------------------------------------- /test/test_Address_Registration_Guard.cpp: -------------------------------------------------------------------------------- 1 | #include "unittest.hpp" 2 | #include "rice/Address_Registration_Guard.hpp" 3 | 4 | using namespace Rice; 5 | 6 | TESTSUITE(Address_Registration_Guard); 7 | 8 | SETUP(Address_Registration_Guard) 9 | { 10 | ruby_init(); 11 | } 12 | 13 | TESTCASE(register_address) 14 | { 15 | VALUE v = Qnil; 16 | Address_Registration_Guard g(&v); 17 | } 18 | 19 | TESTCASE(register_object) 20 | { 21 | Object o; 22 | Address_Registration_Guard g(&o); 23 | } 24 | 25 | TESTCASE(get_address) 26 | { 27 | VALUE v = Qnil; 28 | Address_Registration_Guard g(&v); 29 | ASSERT_EQUAL(&v, g.address()); 30 | } 31 | 32 | TESTCASE(swap) 33 | { 34 | VALUE v = Qnil; 35 | VALUE v2 = Qnil; 36 | Address_Registration_Guard g(&v); 37 | Address_Registration_Guard g2(&v2); 38 | g.swap(g2); 39 | ASSERT_EQUAL(&v, g2.address()); 40 | ASSERT_EQUAL(&v2, g.address()); 41 | // TODO: ensure addresses are still registered 42 | } 43 | 44 | -------------------------------------------------------------------------------- /rice/Address_Registration_Guard.ipp: -------------------------------------------------------------------------------- 1 | #include "Object.hpp" 2 | #include 3 | 4 | inline Rice::Address_Registration_Guard:: 5 | Address_Registration_Guard(VALUE * address) 6 | : address_(address) 7 | { 8 | registerExitHandler(); 9 | rb_gc_register_address(address); 10 | } 11 | 12 | inline Rice::Address_Registration_Guard:: 13 | Address_Registration_Guard(Object * object) 14 | : address_(const_cast(&object->value())) 15 | { 16 | registerExitHandler(); 17 | rb_gc_register_address(address_); 18 | } 19 | 20 | inline Rice::Address_Registration_Guard:: 21 | ~Address_Registration_Guard() 22 | { 23 | if (enabled) 24 | rb_gc_unregister_address(address_); 25 | } 26 | 27 | inline VALUE * Rice::Address_Registration_Guard:: 28 | address() const 29 | { 30 | return address_; 31 | } 32 | 33 | inline void Rice::Address_Registration_Guard:: 34 | swap(Rice::Address_Registration_Guard & other) 35 | { 36 | std::swap(address_, other.address_); 37 | } 38 | -------------------------------------------------------------------------------- /test/ext/Makefile.am: -------------------------------------------------------------------------------- 1 | RUBY_EXTCONF_OPTIONS = -I@RICE_ROOT@/ruby/lib 2 | EXTCONF_OPTIONS = --with-cppflags="-I@RICE_ROOT@" --with-libpath="@RICE_ROOT@/rice" 3 | 4 | EXTRA_DIST = \ 5 | t1/extconf.rb \ 6 | t1/t1.cpp \ 7 | t2/extconf.rb \ 8 | t2/t2.cpp 9 | 10 | all: 11 | 12 | t1/Makefile: t1/extconf.rb ../../config.status ../../ruby/lib/mkmf-rice.rb 13 | @RUBY@ $(RUBY_EXTCONF_OPTIONS) -C t1 extconf.rb $(EXTCONF_OPTIONS) 14 | 15 | t2/Makefile: t2/extconf.rb ../../config.status ../../ruby/lib/mkmf-rice.rb 16 | @RUBY@ $(RUBY_EXTCONF_OPTIONS) -C t2 extconf.rb $(EXTCONF_OPTIONS) 17 | 18 | all: t1_all t2_all 19 | 20 | t1_all: t1/Makefile 21 | ${MAKE} -C t1 all 22 | 23 | t2_all: t2/Makefile 24 | ${MAKE} -C t2 all 25 | 26 | clean: t1_clean t2_clean 27 | 28 | t1_clean: t1/Makefile 29 | ${MAKE} -C t1 clean 30 | 31 | t2_clean: t2/Makefile 32 | ${MAKE} -C t2 clean 33 | 34 | distclean: t1_distclean t2_distclean 35 | 36 | t1_distclean: t1/Makefile 37 | ${MAKE} -C t1 distclean 38 | 39 | t2_distclean: t2/Makefile 40 | ${MAKE} -C t2 distclean 41 | 42 | -------------------------------------------------------------------------------- /rice/code_gen/wrap_function.rb: -------------------------------------------------------------------------------- 1 | require "rice_template" 2 | 3 | class WrapFunctionHpp < RiceTemplate 4 | 5 | cpp_detail_file "wrap_function.hpp" 6 | 7 | def entry(num) 8 | { 9 | :typenames => build(num, "typename Arg{{i}}_T"), 10 | :self_typenames => ["typename Self_T", build(num - 1, "typename Arg{{i}}_T", nil)].flatten.join(", "), 11 | :argument_types => build(num, "Arg{{i}}_T"), 12 | :self_argument_types => build(num - 1, "Arg{{i}}_T") 13 | } 14 | end 15 | 16 | end 17 | 18 | class WrapFunctionIpp < RiceTemplate 19 | 20 | cpp_detail_file "wrap_function.ipp" 21 | 22 | def entry(num) 23 | { 24 | :typenames => build(num, "typename Arg{{i}}_T"), 25 | :self_typenames => ["typename Self_T", build(num - 1, "typename Arg{{i}}_T", nil)].flatten.join(", "), 26 | :argument_types => build(num, "Arg{{i}}_T"), 27 | :self_argument_types => build(num - 1, "Arg{{i}}_T"), 28 | :self_arg_types_with_self => ["Self_T", build(num - 1, "Arg{{i}}_T", nil)].flatten.join(", ") 29 | } 30 | end 31 | 32 | end 33 | -------------------------------------------------------------------------------- /rice/detail/creation_funcs.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__creation_funcs__hpp_ 2 | #define Rice__detail__creation_funcs__hpp_ 3 | 4 | namespace Rice 5 | { 6 | 7 | class Class; 8 | 9 | namespace detail 10 | { 11 | 12 | //! Like define_alloc_func, but allows the user to define an 13 | //! "initialize" method too. 14 | template 15 | void define_creation_funcs( 16 | Class const & klass, 17 | RUBY_VALUE_FUNC allocate_func, 18 | Initialize_Func_T initialize_func); 19 | 20 | //! This is just the opposite of define_alloc_func. It can be 21 | //! used to create a class that cannot be instantiated by the user. 22 | void undef_alloc_func( 23 | Class const & klass); 24 | 25 | //! This is just the opposite of define_creation_func. It can be 26 | //! used to create a class that cannot be instantiated by the user. 27 | void undef_creation_funcs( 28 | Class const & klass); 29 | 30 | } // namespace detail 31 | 32 | } // namespace Rice 33 | 34 | #include "creation_funcs.ipp" 35 | 36 | #endif // Rice__detail__creation_funcs__hpp_ 37 | 38 | -------------------------------------------------------------------------------- /rice/detail/demangle.cpp: -------------------------------------------------------------------------------- 1 | #include "demangle.hpp" 2 | 3 | #ifdef __GNUC__ 4 | #include 5 | #include 6 | #include 7 | #endif 8 | 9 | std::string 10 | Rice::detail:: 11 | demangle(char const * mangled_name) 12 | { 13 | #ifdef __GNUC__ 14 | struct Helper 15 | { 16 | Helper( 17 | char const * mangled_name) 18 | : name_(0) 19 | { 20 | int status = 0; 21 | name_ = abi::__cxa_demangle(mangled_name, 0, 0, &status); 22 | } 23 | 24 | ~Helper() 25 | { 26 | std::free(name_); 27 | } 28 | 29 | char * name_; 30 | 31 | private: 32 | Helper(Helper const &); 33 | void operator=(Helper const &); 34 | }; 35 | 36 | Helper helper(mangled_name); 37 | if(helper.name_) 38 | { 39 | return helper.name_; 40 | } 41 | else 42 | { 43 | return mangled_name; 44 | } 45 | #else 46 | return mangled_name; 47 | #endif 48 | } 49 | 50 | 51 | std::string 52 | Rice::detail:: 53 | demangle(std::string const & mangled_name) 54 | { 55 | return demangle(mangled_name.c_str()); 56 | } 57 | -------------------------------------------------------------------------------- /test/test_Exception.cpp: -------------------------------------------------------------------------------- 1 | #include "unittest.hpp" 2 | #include "rice/Exception.hpp" 3 | #include "rice/String.hpp" 4 | 5 | using namespace Rice; 6 | 7 | TESTSUITE(Exception); 8 | 9 | SETUP(Exception) 10 | { 11 | ruby_init(); 12 | } 13 | 14 | TESTCASE(construct_from_exception_object) 15 | { 16 | VALUE v = protect(rb_exc_new2, rb_eRuntimeError, "foo"); 17 | Exception ex(v); 18 | ASSERT_EQUAL(ex.value(), v); 19 | } 20 | 21 | TESTCASE(copy_construct) 22 | { 23 | VALUE v = protect(rb_exc_new2, rb_eRuntimeError, "foo"); 24 | Exception ex1(v); 25 | Exception ex2(v); 26 | ASSERT_EQUAL(ex2.value(), v); 27 | } 28 | 29 | TESTCASE(construct_from_format_string) 30 | { 31 | Exception ex(rb_eRuntimeError, "%s", "foo"); 32 | ASSERT_EQUAL(ex.class_of(), Object(rb_eRuntimeError)); 33 | } 34 | 35 | TESTCASE(message) 36 | { 37 | Exception ex(rb_eRuntimeError, "%s", "foo"); 38 | ASSERT_EQUAL(String("foo"), ex.message()); 39 | } 40 | 41 | TESTCASE(what) 42 | { 43 | const char* foo = "foo"; 44 | Exception ex(rb_eRuntimeError, "%s", "foo"); 45 | ASSERT_EQUAL(foo, ex.what()); 46 | } 47 | 48 | -------------------------------------------------------------------------------- /test/test_rice.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | gem 'minitest' 3 | require 'minitest/autorun' 4 | require 'rbconfig' 5 | 6 | class RiceTest < Minitest::Test 7 | # TODO: probably a better way to find this out... 8 | VERBOSE = ARGV.include?('-v') 9 | 10 | EXEEXT = RbConfig::CONFIG['EXEEXT'] 11 | RUBY = RbConfig::CONFIG['RUBY_INSTALL_NAME'] 12 | 13 | def test_unittest 14 | run_external_test("./unittest#{EXEEXT}") 15 | end 16 | 17 | def test_multiple_extensions 18 | run_external_test("#{RUBY} test_multiple_extensions.rb") 19 | end 20 | 21 | def test_multiple_extensions_with_inheritance 22 | run_external_test("#{RUBY} test_multiple_extensions_with_inheritance.rb") 23 | end 24 | 25 | def test_multiple_extensions_same_class 26 | run_external_test("#{RUBY} test_multiple_extensions_same_class.rb") 27 | end 28 | 29 | def run_external_test(executable) 30 | if VERBOSE then 31 | system(executable) 32 | else 33 | result = `#{executable}` 34 | if $? != 0 then 35 | puts result 36 | end 37 | end 38 | raise "Error: $?" if $? != 0 39 | end 40 | end 41 | 42 | -------------------------------------------------------------------------------- /rice/Builtin_Object.ipp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Builtin_Object__ipp_ 2 | #define Rice__Builtin_Object__ipp_ 3 | 4 | #include "Object.hpp" 5 | #include "protect.hpp" 6 | #include "detail/check_ruby_type.hpp" 7 | 8 | #include 9 | 10 | namespace Rice 11 | { 12 | 13 | namespace detail 14 | { 15 | inline VALUE check_type(Object value, int type) 16 | { 17 | rb_check_type(value, type); 18 | return Qnil; 19 | } 20 | } 21 | 22 | template 23 | inline Builtin_Object:: 24 | Builtin_Object(Object value) 25 | : Object(value) 26 | , obj_((RObject*)(value.value())) 27 | { 28 | protect(detail::check_type, value, Builtin_Type); 29 | } 30 | 31 | template 32 | inline Builtin_Object:: 33 | Builtin_Object(Builtin_Object const & other) 34 | : Object(other.value()) 35 | , obj_(other.obj_) 36 | { 37 | } 38 | 39 | template 40 | inline void Builtin_Object:: 41 | swap(Builtin_Object & ref) 42 | { 43 | std::swap(obj_, ref.obj_); 44 | Object::swap(ref); 45 | } 46 | 47 | } // namespace Rice 48 | 49 | #endif // Rice__Builtin_Object__ipp_ 50 | 51 | -------------------------------------------------------------------------------- /sample/enum/sample_enum.cpp: -------------------------------------------------------------------------------- 1 | #include "rice/Enum.hpp" 2 | #include "rice/ruby_try_catch.hpp" 3 | 4 | using namespace Rice; 5 | 6 | namespace 7 | { 8 | 9 | enum Sample_Enum 10 | { 11 | SE_FOO = 1, 12 | SE_BAR = 42, 13 | SE_BAZ = 100, 14 | }; 15 | 16 | Rice::Enum sample_enum_type; 17 | 18 | char const * description(Sample_Enum e) 19 | { 20 | switch(e) 21 | { 22 | case SE_FOO: return "Fairly Ordinary Object"; 23 | case SE_BAR: return "Beginner's All-purpose Ratchet"; 24 | case SE_BAZ: return "Better than A Zebra"; 25 | } 26 | return "???"; 27 | } 28 | 29 | } // namespace 30 | 31 | template<> 32 | Sample_Enum from_ruby(Object x) 33 | { 34 | Data_Object d(x, sample_enum_type); 35 | return *d; 36 | } 37 | 38 | extern "C" 39 | void Init_sample_enum() 40 | { 41 | RUBY_TRY 42 | { 43 | sample_enum_type = 44 | define_enum("Sample_Enum") 45 | .define_value("FOO", SE_FOO) 46 | .define_value("BAR", SE_BAR) 47 | .define_value("BAZ", SE_BAZ); 48 | 49 | sample_enum_type 50 | .define_method("description", description); 51 | } 52 | RUBY_CATCH 53 | } 54 | 55 | -------------------------------------------------------------------------------- /test/test_Memory_Management.cpp: -------------------------------------------------------------------------------- 1 | #include "unittest.hpp" 2 | #include "rice/String.hpp" 3 | #include "rice/Class.hpp" 4 | #include "rice/global_function.hpp" 5 | 6 | using namespace Rice; 7 | 8 | TESTSUITE(Memory_Management); 9 | 10 | SETUP(Memory_Management) 11 | { 12 | ruby_init(); 13 | } 14 | 15 | namespace 16 | { 17 | class TestClass { 18 | double tmp; 19 | public: 20 | TestClass() {tmp=0;} 21 | 22 | double getTmp() { 23 | return tmp; 24 | } 25 | 26 | void setTmp(double x) { 27 | tmp = x; 28 | } 29 | }; 30 | 31 | TestClass returnTestClass() { 32 | TestClass x = TestClass(); 33 | x.setTmp(8); 34 | return x; 35 | } 36 | } 37 | 38 | TESTCASE(allows_copy_contructors_to_work) 39 | { 40 | define_class("TestClass") 41 | .define_method("tmp=", &TestClass::setTmp) 42 | .define_method("tmp", &TestClass::getTmp); 43 | 44 | define_global_function("return_test_class", &returnTestClass); 45 | 46 | Module m = define_module("TestingModule"); 47 | 48 | Object result = m.instance_eval("return_test_class.tmp"); 49 | ASSERT_EQUAL(8.0, from_ruby(result.value())); 50 | } 51 | -------------------------------------------------------------------------------- /rice/Identifier.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Identifier__hpp_ 2 | #define Rice__Identifier__hpp_ 3 | 4 | #include "detail/ruby.hpp" 5 | #include 6 | 7 | namespace Rice 8 | { 9 | 10 | class Symbol; 11 | 12 | //! A wrapper for the ID type 13 | /*! An ID is ruby's internal representation of a Symbol object. 14 | */ 15 | class Identifier 16 | { 17 | public: 18 | //! Construct a new Identifier from an ID. 19 | Identifier(ID id); 20 | 21 | //! Construct a new Identifier from a Symbol. 22 | Identifier(Symbol const & symbol); 23 | 24 | //! Construct a new Identifier from a string. 25 | Identifier(char const * s = ""); 26 | 27 | //! Return a string representation of the Identifier. 28 | char const * c_str() const; 29 | 30 | //! Return a string representation of the Identifier. 31 | std::string str() const; 32 | 33 | //! Return the underlying ID 34 | ID id() const { return id_; } 35 | 36 | //! Return the underlying ID 37 | operator ID() const { return id_; } 38 | 39 | //! Return the ID as a Symbol 40 | VALUE to_sym() const; 41 | 42 | private: 43 | ID id_; 44 | }; 45 | 46 | } // namespace Rice 47 | 48 | #include "Identifier.ipp" 49 | 50 | #endif // Rice__Identifier__hpp_ 51 | -------------------------------------------------------------------------------- /rice/Class.cpp: -------------------------------------------------------------------------------- 1 | #include "Class.hpp" 2 | #include "Exception.hpp" 3 | #include "detail/creation_funcs.hpp" 4 | 5 | Rice::Class:: 6 | Class() 7 | : Module_impl() 8 | { 9 | } 10 | 11 | Rice::Class:: 12 | Class(VALUE v) 13 | : Module_impl(v) 14 | { 15 | if(::rb_type(v) != T_CLASS) 16 | { 17 | throw Exception( 18 | rb_eTypeError, 19 | "Expected a Class but got a %s", 20 | rb_class2name(CLASS_OF(v))); // TODO: might raise an exception 21 | } 22 | } 23 | 24 | Rice::Class & Rice::Class:: 25 | undef_creation_funcs() 26 | { 27 | detail::undef_creation_funcs(*this); 28 | return *this; 29 | } 30 | 31 | Rice::Class Rice:: 32 | define_class_under( 33 | Rice::Object module, 34 | char const * name, 35 | Rice::Object superclass) 36 | { 37 | VALUE v = rb_define_class_under(module, name, superclass); 38 | return Class(v); 39 | } 40 | 41 | Rice::Class Rice:: 42 | define_class( 43 | char const * name, 44 | Rice::Object superclass) 45 | { 46 | VALUE v = rb_define_class(name, superclass); 47 | return Class(v); 48 | } 49 | 50 | Rice::Class Rice:: 51 | anonymous_class( 52 | Rice::Object superclass) 53 | { 54 | VALUE v = Class(rb_cClass).call("new"); 55 | return Class(v); 56 | } 57 | 58 | -------------------------------------------------------------------------------- /rice/Director.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Director__hpp_ 2 | #define Rice__Director__hpp_ 3 | 4 | #include "Object.hpp" 5 | 6 | namespace Rice { 7 | 8 | /** 9 | * A Director works exactly as a SWIG %director works (thus the name). 10 | * You use this class to help build proxy classes so that polymorphism 11 | * works from C++ into Ruby. See the main README for how this class works. 12 | */ 13 | class Director 14 | { 15 | public: 16 | //! Construct new Director. Needs the Ruby object so that the 17 | // proxy class can call methods on that object. 18 | Director(Object self); 19 | 20 | virtual ~Director() { } 21 | 22 | //! Raise a ruby exception when a call comes through for a pure virtual method 23 | /*! If a Ruby script calls 'super' on a method that's otherwise a pure virtual 24 | * method, use this method to throw an exception in this case. 25 | */ 26 | void raisePureVirtual() const; 27 | 28 | //! Get the Ruby object linked to this C++ instance 29 | Object getSelf() const { return self_; } 30 | 31 | private: 32 | 33 | // Save the Ruby object related to the instance of this class 34 | Object self_; 35 | 36 | }; 37 | } 38 | 39 | #endif // Rice__Director__hpp_ 40 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(rice, 1.1) 2 | AC_CONFIG_SRCDIR(rice) 3 | AM_INIT_AUTOMAKE([subdir-objects]) 4 | 5 | AC_CONFIG_HEADERS(rice/config.hpp) 6 | 7 | AC_LANG(C++) 8 | AC_PROG_CXX 9 | AC_PROG_RANLIB 10 | 11 | RICE_CPPFLAGS="$CPPFLAGS" 12 | AC_SUBST(RICE_CPPFLAGS) 13 | 14 | RICE_LDFLAGS="$LDFLAGS" 15 | AC_SUBST(RICE_LDFLAGS) 16 | 17 | AC_MINGW32 18 | if test x"${MINGW32}"x = xyesx; then 19 | RICE_USING_MINGW32="true" 20 | else 21 | RICE_USING_MINGW32="false" 22 | fi 23 | 24 | m4_include(check_stdcxx_11.ac) 25 | AX_CXX_COMPILE_STDCXX_11(,optional) 26 | 27 | AC_SUBST(RICE_USING_MINGW32) 28 | 29 | m4_include(ruby.ac) 30 | RB_INIT_RUBY 31 | 32 | m4_include(doxygen.ac) 33 | DX_HTML_FEATURE(ON) 34 | DX_CHM_FEATURE(OFF) 35 | DX_CHI_FEATURE(OFF) 36 | DX_MAN_FEATURE(OFF) 37 | DX_RTF_FEATURE(OFF) 38 | DX_XML_FEATURE(OFF) 39 | DX_PDF_FEATURE(OFF) 40 | DX_PS_FEATURE(OFF) 41 | DX_INIT_DOXYGEN(rice, Doxyfile, doc) 42 | 43 | RICE_SAMPLES="enum map inheritance" 44 | AC_SUBST(RICE_SAMPLES) 45 | 46 | RICE_ROOT=`pwd` 47 | AC_SUBST(RICE_ROOT) 48 | 49 | AC_CONFIG_FILES(Makefile rice/Makefile test/Makefile sample/Makefile 50 | ruby/Makefile ruby/lib/Makefile test/ext/Makefile 51 | ruby/lib/mkmf-rice.rb rice/detail/ruby_version_code.hpp) 52 | AC_OUTPUT 53 | 54 | dnl Work around a bug in older versions of Rubygems 55 | chmod +x install-sh 56 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2017 Paul Brannan , 2 | Jason Roelofs 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /rice/Data_Type.cpp: -------------------------------------------------------------------------------- 1 | #include "Data_Type.hpp" 2 | 3 | Rice::Data_Type_Base::Casters * Rice::Data_Type_Base::casters_ = 0; 4 | 5 | Rice::Data_Type_Base:: 6 | Data_Type_Base() 7 | : Module_impl() 8 | { 9 | } 10 | 11 | Rice::Data_Type_Base:: 12 | Data_Type_Base(VALUE v) 13 | : Module_impl(v) 14 | { 15 | } 16 | 17 | Rice::Data_Type_Base:: 18 | ~Data_Type_Base() 19 | { 20 | } 21 | 22 | Rice::Data_Type_Base::Casters & 23 | Rice::Data_Type_Base:: 24 | casters() 25 | { 26 | // Initialize the casters_ if it is null 27 | if (!casters_) 28 | { 29 | // First, see if it has been previously registered with the 30 | // interpreter (possibly by another extension) 31 | Class object(rb_cObject); 32 | Object casters_object(object.attr_get("__rice_casters__")); 33 | 34 | if (casters_object.is_nil()) 35 | { 36 | // If it is unset, then set it for the first time 37 | Data_Object casters( 38 | new Casters, 39 | rb_cObject); 40 | object.iv_set("__rice_casters__", casters); 41 | casters_ = casters.get(); 42 | } 43 | else 44 | { 45 | // If it is set, then use the existing value 46 | Data_Object casters( 47 | casters_object); 48 | casters_ = casters.get(); 49 | } 50 | } 51 | 52 | return *casters_; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /rice/Exception.cpp: -------------------------------------------------------------------------------- 1 | #include "Exception.hpp" 2 | #include "protect.hpp" 3 | #include "to_from_ruby.hpp" 4 | #include "detail/ruby.hpp" 5 | 6 | #ifdef HAVE_STDARG_PROTOTYPES 7 | #include 8 | #define va_init_list(a,b) va_start(a,b) 9 | #else 10 | #include 11 | #define va_init_list(a,b) va_start(a) 12 | #endif 13 | 14 | Rice::Exception:: 15 | Exception(VALUE e) 16 | : Exception_Base(e) 17 | , message_(Qnil) 18 | , message_guard_(&message_) 19 | { 20 | } 21 | 22 | Rice::Exception:: 23 | Exception(Exception const & other) 24 | : Exception_Base(other) 25 | , message_(other.message_) 26 | , message_guard_(&message_) 27 | { 28 | } 29 | 30 | Rice::Exception:: 31 | Exception(Object exc, char const * fmt, ...) 32 | : Exception_Base(Qnil) 33 | , message_(Qnil) 34 | , message_guard_(&message_) 35 | { 36 | va_list args; 37 | char buf[BUFSIZ]; 38 | 39 | va_init_list(args, fmt); 40 | vsnprintf(buf, BUFSIZ, fmt, args); 41 | buf[BUFSIZ - 1] = '\0'; 42 | va_end(args); 43 | 44 | set_value(protect(rb_exc_new2, exc, buf)); 45 | } 46 | 47 | Rice::String Rice::Exception:: 48 | message() const 49 | { 50 | return protect(rb_funcall, value(), rb_intern("message"), 0); 51 | } 52 | 53 | char const * Rice::Exception:: 54 | what() const throw() 55 | { 56 | message_ = message(); 57 | return from_ruby(message_).c_str(); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /test/test_Symbol.cpp: -------------------------------------------------------------------------------- 1 | #include "unittest.hpp" 2 | #include "rice/Symbol.hpp" 3 | #include "rice/Identifier.hpp" 4 | 5 | using namespace Rice; 6 | 7 | TESTSUITE(Symbol); 8 | 9 | SETUP(Symbol) 10 | { 11 | ruby_init(); 12 | } 13 | 14 | TESTCASE(construct_from_symbol) 15 | { 16 | VALUE v = ID2SYM(rb_intern("foo")); 17 | Symbol symbol(v); 18 | ASSERT_EQUAL(v, symbol.value()); 19 | } 20 | 21 | TESTCASE(construct_from_identifier) 22 | { 23 | Identifier identifier("FOO"); 24 | Symbol symbol(identifier); 25 | ASSERT_EQUAL(ID2SYM(rb_intern("FOO")), symbol.value()); 26 | } 27 | 28 | TESTCASE(construct_from_string) 29 | { 30 | Symbol symbol("Foo"); 31 | ASSERT_EQUAL(ID2SYM(rb_intern("Foo")), symbol.value()); 32 | } 33 | 34 | TESTCASE(default_construct) 35 | { 36 | Symbol symbol; 37 | ASSERT_EQUAL(ID2SYM(rb_intern("")), symbol.value()); 38 | } 39 | 40 | TESTCASE(copy_construct) 41 | { 42 | Symbol symbol1("Foo"); 43 | Symbol symbol2(symbol1); 44 | ASSERT_EQUAL(ID2SYM(rb_intern("Foo")), symbol2.value()); 45 | } 46 | 47 | TESTCASE(c_str) 48 | { 49 | Symbol symbol("Foo"); 50 | ASSERT_EQUAL("Foo", symbol.c_str()); 51 | } 52 | 53 | TESTCASE(str) 54 | { 55 | Symbol symbol("Foo"); 56 | ASSERT_EQUAL(std::string("Foo"), symbol.str()); 57 | } 58 | 59 | TESTCASE(to_id) 60 | { 61 | Symbol symbol("Foo"); 62 | ASSERT_EQUAL(Identifier("Foo"), symbol.to_id()); 63 | } 64 | -------------------------------------------------------------------------------- /rice/config.hpp.in: -------------------------------------------------------------------------------- 1 | /* rice/config.hpp.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* define if the compiler supports basic C++11 syntax */ 4 | #undef HAVE_CXX11 5 | 6 | /* Define to 1 if you have the header file. */ 7 | #undef HAVE_ENV_H 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #undef HAVE_NODE_H 11 | 12 | /* Define to 1 if you have the header file. */ 13 | #undef HAVE_RUBY_H 14 | 15 | /* Define to 1 if you have the header file. */ 16 | #undef HAVE_RUBY_NODE_H 17 | 18 | /* Define to 1 if you have the header file. */ 19 | #undef HAVE_VERSION_H 20 | 21 | /* Name of package */ 22 | #undef PACKAGE 23 | 24 | /* Define to the address where bug reports for this package should be sent. */ 25 | #undef PACKAGE_BUGREPORT 26 | 27 | /* Define to the full name of this package. */ 28 | #undef PACKAGE_NAME 29 | 30 | /* Define to the full name and version of this package. */ 31 | #undef PACKAGE_STRING 32 | 33 | /* Define to the one symbol short name of this package. */ 34 | #undef PACKAGE_TARNAME 35 | 36 | /* Define to the home page for this package. */ 37 | #undef PACKAGE_URL 38 | 39 | /* Define to the version of this package. */ 40 | #undef PACKAGE_VERSION 41 | 42 | /* Define this macro to use ruby/node.h */ 43 | #undef REALLY_HAVE_RUBY_NODE_H 44 | 45 | /* Version number of package */ 46 | #undef VERSION 47 | -------------------------------------------------------------------------------- /rice/protect.hpp.mustache: -------------------------------------------------------------------------------- 1 | #ifndef Rice__protect__hpp_ 2 | #define Rice__protect__hpp_ 3 | 4 | // This is a generated file. DO NOT EDIT!! 5 | 6 | 7 | // This causes problems with certain C++ libraries 8 | #undef TYPE 9 | 10 | #include "Object_defn.hpp" 11 | namespace Rice 12 | { 13 | 14 | #ifdef DOXYGEN 15 | /*! \file 16 | * \brief A collection of functions (overloaded on number of 17 | * arguments) for calling C functions that might raise Ruby exceptions. 18 | */ 19 | 20 | //! Call the C function f with arguments (arg1, arg2, ...). 21 | /*! E.g.: 22 | * \code 23 | * VALUE x = protect(rb_ary_new); 24 | * protect(rb_ary_push, x, INT2NUM(42)); 25 | * \endcode 26 | * 27 | * Note that this function makes copies of all of its arguments; it 28 | * does not take anything by reference. All of the copies are const so 29 | * that protect will not work if f takes a non-const 30 | * reference to any of its arguments (though you can use non-const 31 | * pointers). 32 | */ 33 | VALUE protect(Function f, T1 arg1, T2 arg2, ...); 34 | #else 35 | 36 | template 37 | VALUE protect(Fun fun); 38 | 39 | {{#entries}} 40 | template 41 | VALUE protect(Fun fun, {{{arguments}}}); 42 | 43 | {{/entries}} 44 | 45 | #endif // DOXYGEN 46 | 47 | } // namespace Rice 48 | 49 | #include "protect.ipp" 50 | 51 | #endif // Rice__protect__hpp_ 52 | 53 | -------------------------------------------------------------------------------- /rice/code_gen/constructor.rb: -------------------------------------------------------------------------------- 1 | require "rice_template" 2 | 3 | class ConstructorHpp < RiceTemplate 4 | 5 | cpp_file "Constructor.hpp" 6 | 7 | def void_templates 8 | build(MAX_ARGS + 1, "typename Arg{{i}}_T=void") 9 | end 10 | 11 | def voids(count = MAX_ARGS) 12 | count < 1 ? 13 | "" : 14 | (["void"] * (count)).join(", ") 15 | end 16 | 17 | def voids_self(count = MAX_ARGS) 18 | voids(count - 1) 19 | end 20 | 21 | # We need to types of constructors here. One that takes 22 | # regular parameters and one that can take self as the first 23 | # parameter. 24 | def selfs 25 | [ 26 | {:add_self => false, :with_self => "", :self_type => ""}, 27 | {:add_self => true, :with_self => "self, ", :self_type => "Object, ", :max_args => MAX_ARGS - 1} 28 | ] 29 | end 30 | 31 | def entry(c) 32 | arg_count = MAX_ARGS - c 33 | arg_count -= 1 if self[:add_self] 34 | 35 | { 36 | :typenames => build(c, "typename Arg{{i}}_T"), 37 | :parameters => build(c, "Arg{{i}}_T arg{{i}}"), 38 | :arguments => build(c, "arg{{i}}"), 39 | :types_and_voids_list => build_types_and_voids(c, arg_count) 40 | } 41 | end 42 | 43 | def build_types_and_voids(c, rest) 44 | types = build(c, "Arg{{i}}_T", nil) 45 | voids = build(rest, "void", nil) 46 | 47 | [types, voids].flatten.join(", ") 48 | end 49 | 50 | end 51 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | Contributors 2 | ============ 3 | 4 | I'd like to thank the following people for their help in making Rice what it is today. 5 | 6 | * [Paul Brannon (cout)](https://github.com/cout) for initially building and releasing this library as open source. 7 | * [Sylvain Joyeux (doudou)](https://github.com/doudou) for [PR #23](https://github.com/jasonroelofs/rice/pull/23) and [PR #68](https://github.com/jasonroelofs/rice/pull/68) 8 | * [Pat McNally (patmcnally)](https://github.com/patmcnally) for [PR #38](https://github.com/jasonroelofs/rice/pull/38) 9 | * [Victor Costan (pwnall)](https://github.com/pwnall) for [PR #54](https://github.com/jasonroelofs/rice/pull/54) 10 | * [Zachary Salzbank (zsalzbank)](https://github.com/zsalzbank) for [PR #55](https://github.com/jasonroelofs/rice/pull/55) 11 | * [Chai Zhenhua (chaizhenhua)](https://github.com/jasonroelofs/rice/pull/58) for [PR #58](https://github.com/jasonroelofs/rice/pull/58) 12 | * [Alexander Rüedlinger (lexruee)](https://github.com/lexruee) for [PR #81](https://github.com/jasonroelofs/rice/pull/81) 13 | * [ryannevell](https://github.com/ryannevell) for [PR #98](https://github.com/jasonroelofs/rice/pull/98) 14 | * [Samu Voutilainen (smarre)](https://github.com/Smarre) for [PR #102](https://github.com/jasonroelofs/rice/pull/102) 15 | * [Harald Sitter (apachelogger)](https://github.com/apachelogger) for [PR #104](https://github.com/jasonroelofs/rice/pull/104) 16 | -------------------------------------------------------------------------------- /rice/detail/from_ruby.ipp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__from_ruby__ipp_ 2 | #define Rice__detail__from_ruby__ipp_ 3 | 4 | #include "../Data_Type.hpp" 5 | #include "../String.hpp" 6 | #include "demangle.hpp" 7 | #include 8 | 9 | template 10 | T Rice::detail::from_ruby_:: 11 | convert(Rice::Object x) 12 | { 13 | if(rb_type(x.value()) == T_DATA) 14 | { 15 | return *Data_Type::from_ruby(x); 16 | } 17 | else 18 | { 19 | std::string s("Unable to convert "); 20 | s += x.class_of().name().c_str(); 21 | s += " to "; 22 | s += demangle(typeid(T).name()); 23 | throw std::invalid_argument(s.c_str()); 24 | } 25 | } 26 | 27 | template 28 | T * Rice::detail::from_ruby_:: 29 | convert(Rice::Object x) 30 | { 31 | if(rb_type(x.value()) == T_DATA) 32 | { 33 | return Data_Type::from_ruby(x); 34 | } 35 | else 36 | { 37 | std::string s("Unable to convert "); 38 | s += x.class_of().name().c_str(); 39 | s += " to "; 40 | s += demangle(typeid(T *).name()); 41 | throw std::invalid_argument(s.c_str()); 42 | } 43 | } 44 | 45 | template 46 | T const * Rice::detail::from_ruby_:: 47 | convert(Rice::Object x) 48 | { 49 | return from_ruby(x); 50 | } 51 | 52 | template 53 | T & Rice::detail::from_ruby_:: 54 | convert(Rice::Object x) 55 | { 56 | return *from_ruby(x); 57 | } 58 | 59 | #endif // Rice__detail__from_ruby__ipp_ 60 | 61 | -------------------------------------------------------------------------------- /rice/code_gen/auto_member_function_wrapper.rb: -------------------------------------------------------------------------------- 1 | require "rice_template" 2 | 3 | class AutoMemberFunctionWrapperHpp < RiceTemplate 4 | 5 | cpp_detail_file "Auto_Member_Function_Wrapper.hpp" 6 | 7 | def entry(num) 8 | typenames = typenames_with_return = build(num, "typename Arg{{i}}_T") 9 | specs_with_return = "" 10 | specs = "" 11 | 12 | if num == self.iterations + 1 13 | specs_with_return = "" 14 | typenames_with_return = build(num, "typename Arg{{i}}_T = void") 15 | end 16 | 17 | { 18 | :typenames_with_return => typenames_with_return, 19 | :specs_with_return => specs_with_return, 20 | :typenames => typenames, 21 | :specs => specs, 22 | :num_args => num 23 | } 24 | end 25 | 26 | end 27 | 28 | class AutoMemberFunctionWrapperIpp < RiceTemplate 29 | 30 | cpp_detail_file "Auto_Member_Function_Wrapper.ipp" 31 | 32 | def entry(num) 33 | { 34 | :typenames => build(num, "typename Arg{{i}}_T"), 35 | :types => build(num, "Arg{{i}}_T"), 36 | :vargs => build(num, "varg{{i}}"), 37 | :scan_args => build(num, "&varg{{i}}"), 38 | :call_args => build(num, "arg{{i}}"), 39 | :arguments => arguments(num) 40 | } 41 | end 42 | 43 | protected 44 | 45 | def arguments(num) 46 | args = [] 47 | num.times do |count| 48 | args << { 49 | :count => count 50 | } 51 | end 52 | 53 | args 54 | end 55 | 56 | end 57 | -------------------------------------------------------------------------------- /sample/Makefile.am: -------------------------------------------------------------------------------- 1 | RUBY_EXTCONF_OPTIONS = -I@RICE_ROOT@/ruby/lib 2 | EXTCONF_OPTIONS = --with-cppflags="-I@RICE_ROOT@" --with-libpath="@RICE_ROOT@/rice" 3 | 4 | EXTRA_DIST = \ 5 | enum/extconf.rb \ 6 | enum/sample_enum.cpp \ 7 | enum/test.rb \ 8 | map/extconf.rb \ 9 | map/map.cpp \ 10 | map/test.rb \ 11 | inheritance/extconf.rb \ 12 | inheritance/animals.cpp \ 13 | inheritance/test.rb 14 | 15 | enum/Makefile: enum/extconf.rb ../config.status ../ruby/lib/mkmf-rice.rb 16 | @RUBY@ $(RUBY_EXTCONF_OPTIONS) -C enum extconf.rb $(EXTCONF_OPTIONS) 17 | 18 | map/Makefile: map/extconf.rb ../config.status ../ruby/lib/mkmf-rice.rb 19 | @RUBY@ $(RUBY_EXTCONF_OPTIONS) -C map extconf.rb $(EXTCONF_OPTIONS) 20 | 21 | inheritance/Makefile: inheritance/extconf.rb ../config.status ../ruby/lib/mkmf-rice.rb 22 | @RUBY@ $(RUBY_EXTCONF_OPTIONS) -C inheritance extconf.rb $(EXTCONF_OPTIONS) 23 | 24 | all: enum/Makefile map/Makefile inheritance/Makefile all_extensions 25 | 26 | all_extensions: $(addsuffix /Makefile,$(RICE_SAMPLES)) 27 | @for sample in $(RICE_SAMPLES); \ 28 | do \ 29 | ${MAKE} -C $${sample} all; \ 30 | done 31 | 32 | clean: enum/Makefile map/Makefile inheritance/Makefile clean_extensions 33 | 34 | clean_extensions: 35 | @for sample in $(RICE_SAMPLES); \ 36 | do \ 37 | ${MAKE} -C $${sample} clean; \ 38 | done 39 | 40 | distclean: enum/Makefile map/Makefile inheritance/Makefile distclean_extensions 41 | 42 | distclean_extensions: 43 | @for sample in $(RICE_SAMPLES); 44 | do \ 45 | ${MAKE} -C $${sample} distclean; \ 46 | done 47 | 48 | -------------------------------------------------------------------------------- /test/test_Identifier.cpp: -------------------------------------------------------------------------------- 1 | #include "unittest.hpp" 2 | #include "rice/Identifier.hpp" 3 | #include "rice/Symbol.hpp" 4 | 5 | using namespace Rice; 6 | 7 | TESTSUITE(Identifier); 8 | 9 | SETUP(Identifier) 10 | { 11 | ruby_init(); 12 | } 13 | 14 | TESTCASE(construct_from_id) 15 | { 16 | ID id = rb_intern("foo"); 17 | Identifier identifier(id); 18 | ASSERT_EQUAL(id, identifier.id()); 19 | } 20 | 21 | TESTCASE(construct_from_symbol) 22 | { 23 | Symbol symbol("FOO"); 24 | Identifier identifier(symbol); 25 | ASSERT_EQUAL(rb_intern("FOO"), identifier.id()); 26 | } 27 | 28 | TESTCASE(construct_from_c_string) 29 | { 30 | Identifier identifier("Foo"); 31 | ASSERT_EQUAL(rb_intern("Foo"), identifier.id()); 32 | } 33 | 34 | TESTCASE(default_construct) 35 | { 36 | Identifier identifier; 37 | ASSERT_EQUAL(rb_intern(""), identifier.id()); 38 | } 39 | 40 | TESTCASE(copy_construct) 41 | { 42 | Identifier identifier1("Foo"); 43 | Identifier identifier2(identifier1); 44 | ASSERT_EQUAL(rb_intern("Foo"), identifier2.id()); 45 | } 46 | 47 | TESTCASE(c_str) 48 | { 49 | Identifier identifier("Foo"); 50 | ASSERT_EQUAL("Foo", identifier.c_str()); 51 | } 52 | 53 | TESTCASE(str) 54 | { 55 | Identifier identifier("Foo"); 56 | ASSERT_EQUAL(std::string("Foo"), identifier.str()); 57 | } 58 | 59 | TESTCASE(implicit_conversion_to_id) 60 | { 61 | Identifier identifier("Foo"); 62 | ASSERT_EQUAL(rb_intern("Foo"), static_cast(identifier)); 63 | } 64 | 65 | TESTCASE(to_sym) 66 | { 67 | Identifier identifier("Foo"); 68 | ASSERT_EQUAL(Symbol("Foo"), Symbol(identifier.to_sym())); 69 | } 70 | 71 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = unittest 2 | 3 | SUBDIRS = ext 4 | 5 | TESTS = unittest 6 | 7 | 8 | check: run_multiple_extensions_test 9 | 10 | .PHONY: run_multiple_extensions_test 11 | 12 | run_multiple_extensions_test: 13 | $(RUBY) test_multiple_extensions.rb 14 | 15 | 16 | check: run_multiple_extensions_with_inheritance_test 17 | 18 | .PHONY: run_multiple_extensions_with_inheritance_test 19 | 20 | run_multiple_extensions_with_inheritance_test: 21 | $(RUBY) test_multiple_extensions_with_inheritance.rb 22 | 23 | 24 | check: run_multiple_extensions_same_class_test 25 | 26 | .PHONY: run_multiple_extensions_same_class_test 27 | 28 | run_multiple_extensions_same_class_test: 29 | $(RUBY) test_multiple_extensions_same_class.rb 30 | 31 | 32 | unittest_SOURCES = \ 33 | unittest.cpp \ 34 | test_Address_Registration_Guard.cpp \ 35 | test_Array.cpp \ 36 | test_Builtin_Object.cpp \ 37 | test_Class.cpp \ 38 | test_Constructor.cpp \ 39 | test_Data_Object.cpp \ 40 | test_Data_Type.cpp \ 41 | test_Director.cpp \ 42 | test_Enum.cpp \ 43 | test_Exception.cpp \ 44 | test_Hash.cpp \ 45 | test_Identifier.cpp \ 46 | test_Jump_Tag.cpp \ 47 | test_Memory_Management.cpp \ 48 | test_Module.cpp \ 49 | test_Object.cpp \ 50 | test_String.cpp \ 51 | test_Struct.cpp \ 52 | test_Symbol.cpp \ 53 | test_To_From_Ruby.cpp \ 54 | test_global_functions.cpp 55 | 56 | AM_CPPFLAGS = \ 57 | -I.. \ 58 | $(RUBY_CFLAGS) 59 | $(RUBY_CPPFLAGS) 60 | 61 | AM_CXXLAGS = \ 62 | $(RUBY_CXXFLAGS) 63 | 64 | AM_LDFLAGS = \ 65 | $(RUBY_LDFLAGS) \ 66 | -L../rice 67 | 68 | LIBS = \ 69 | -lrice \ 70 | $(RUBY_LIBS) \ 71 | $(RUBY_LIBRUBYARG) 72 | 73 | -------------------------------------------------------------------------------- /rice/detail/Exception_Handler.ipp: -------------------------------------------------------------------------------- 1 | #include "../Data_Type_defn.hpp" 2 | 3 | inline 4 | Rice::detail::Exception_Handler:: 5 | Exception_Handler( 6 | Data_Object next_exception_handler) 7 | : next_exception_handler_(next_exception_handler) 8 | , next_exception_handler_guard_(&next_exception_handler_) 9 | { 10 | } 11 | 12 | inline 13 | Rice::detail::Exception_Handler:: 14 | ~Exception_Handler() 15 | { 16 | } 17 | 18 | inline 19 | VALUE 20 | Rice::detail::Exception_Handler:: 21 | call_next_exception_handler() const 22 | { 23 | return next_exception_handler_->handle_exception(); 24 | } 25 | 26 | inline Rice::detail::Default_Exception_Handler:: 27 | Default_Exception_Handler() 28 | : Exception_Handler( 29 | Data_Object(0, rb_cObject)) 30 | { 31 | } 32 | 33 | inline 34 | VALUE 35 | Rice::detail::Default_Exception_Handler:: 36 | handle_exception() const 37 | { 38 | throw; 39 | } 40 | 41 | template 42 | inline 43 | Rice::detail::Functor_Exception_Handler:: 44 | Functor_Exception_Handler( 45 | Functor_T handler, 46 | Data_Object next_exception_handler) 47 | : Exception_Handler(next_exception_handler) 48 | , handler_(handler) 49 | { 50 | } 51 | 52 | template 53 | inline 54 | VALUE 55 | Rice::detail::Functor_Exception_Handler:: 56 | handle_exception() const 57 | { 58 | try 59 | { 60 | return call_next_exception_handler(); 61 | } 62 | catch(Exception_T const & ex) 63 | { 64 | handler_(ex); 65 | throw; 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /rice/Symbol.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Symbol__hpp_ 2 | #define Rice__Symbol__hpp_ 3 | 4 | #include "Identifier.hpp" 5 | #include "Object.hpp" 6 | #include "detail/ruby.hpp" 7 | #include 8 | 9 | namespace Rice 10 | { 11 | 12 | //! A wrapper for ruby's Symbol class. 13 | /*! Symbols are internal identifiers in ruby. They are singletons and 14 | * can be thought of as frozen strings. They differ from an Identifier 15 | * in that they are in fact real Objects, but they can be converted 16 | * back and forth between Identifier and Symbol. 17 | */ 18 | class Symbol 19 | : public Object 20 | { 21 | public: 22 | //! Wrap an existing symbol. 23 | Symbol(VALUE v); 24 | 25 | //! Wrap an existing symbol. 26 | Symbol(Object v); 27 | 28 | //! Construct a Symbol from an Identifier. 29 | Symbol(Identifier id); 30 | 31 | //! Construct a Symbol from a null-terminated C string. 32 | Symbol(char const * s = ""); 33 | 34 | //! Construct a Symbol from an std::string. 35 | Symbol(std::string const & s); 36 | 37 | //! Return a string representation of the Symbol. 38 | char const * c_str() const; 39 | 40 | //! Return a string representation of the Symbol. 41 | std::string str() const; 42 | 43 | //! Return the Symbol as an Identifier. 44 | Identifier to_id() const; 45 | }; 46 | 47 | } // namespace Rice 48 | 49 | template<> 50 | inline 51 | Rice::Symbol from_ruby(Rice::Object x) 52 | { 53 | return Rice::Symbol(x); 54 | } 55 | 56 | template<> 57 | inline 58 | Rice::Object to_ruby(Rice::Symbol const & x) 59 | { 60 | return x; 61 | } 62 | 63 | #include "Symbol.ipp" 64 | 65 | #endif // Rice__Symbol__hpp_ 66 | 67 | -------------------------------------------------------------------------------- /rice/Module.cpp: -------------------------------------------------------------------------------- 1 | #include "Module.hpp" 2 | #include "Symbol.hpp" 3 | #include "String.hpp" 4 | #include "Array.hpp" 5 | #include "Exception.hpp" 6 | #include "protect.hpp" 7 | 8 | Rice::Module:: 9 | Module() 10 | : Module_impl(rb_cObject) 11 | { 12 | } 13 | 14 | Rice::Module:: 15 | Module(VALUE v) 16 | : Module_impl(v) 17 | { 18 | if(::rb_type(v) != T_CLASS && ::rb_type(v) != T_MODULE) 19 | { 20 | throw Exception( 21 | rb_eTypeError, 22 | "Expected a Module but got a %s", 23 | rb_class2name(CLASS_OF(v))); // TODO: might raise an exception 24 | } 25 | } 26 | 27 | Rice::String Rice::Module:: 28 | name() const 29 | { 30 | Object name = rb_mod_name(*this); 31 | if(name.is_nil()) 32 | { 33 | // 1.9 34 | return String(""); 35 | } 36 | else 37 | { 38 | return name; 39 | } 40 | } 41 | 42 | Rice::Module Rice:: 43 | define_module_under( 44 | Rice::Object module, 45 | char const * name) 46 | { 47 | VALUE v = rb_define_module_under(module, name); 48 | return Module(v); 49 | } 50 | 51 | Rice::Module Rice:: 52 | define_module( 53 | char const * name) 54 | { 55 | VALUE v = rb_define_module(name); 56 | return Module(v); 57 | } 58 | 59 | Rice::Module Rice:: 60 | anonymous_module() 61 | { 62 | return Module(protect(rb_module_new)); 63 | } 64 | 65 | void Rice::Module:: 66 | swap(Rice::Module & other) 67 | { 68 | Module_base::swap(other); 69 | } 70 | 71 | Rice::Array 72 | Rice::Module:: 73 | ancestors() const 74 | { 75 | return protect(rb_mod_ancestors, *this); 76 | } 77 | 78 | Rice::Class 79 | Rice::Module:: 80 | singleton_class() const 81 | { 82 | return CLASS_OF(value()); 83 | } 84 | 85 | -------------------------------------------------------------------------------- /rice/Builtin_Object_defn.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Builtin_Object_defn__hpp_ 2 | #define Rice__Builtin_Object_defn__hpp_ 3 | 4 | #include "Object_defn.hpp" 5 | #include "detail/ruby.hpp" 6 | 7 | namespace Rice 8 | { 9 | 10 | //! A smartpointer-like wrapper for Ruby builtin objects. 11 | /*! A builtin object is one of Ruby's internal types, e.g. RArray or 12 | * RString. Every builtin type structure has a corresponding integer 13 | * type number (e.g T_ARRAY for RArray or T_STRING for RString). This 14 | * class is a wrapper for those types of objects, primarily useful as a 15 | * base class for other wrapper classes like Array and Hash. 16 | */ 17 | template 18 | class Builtin_Object 19 | : public Object 20 | { 21 | public: 22 | //! Wrap an already allocated Ruby object. 23 | /*! Checks to see if the object is an object of type Builtin_Type; a 24 | * C++ exception is thrown if this is not the case. 25 | * \param value the object to be wrapped. 26 | */ 27 | Builtin_Object(Object value); 28 | 29 | //! Make a copy of a Builtin_Object 30 | /*! \param other the Builtin_Object to be copied. 31 | */ 32 | Builtin_Object(Builtin_Object const & other); 33 | 34 | RObject & operator*() const { return *obj_; } //!< Return a reference to obj_ 35 | RObject * operator->() const { return obj_; } //!< Return a pointer to obj_ 36 | RObject * get() const { return obj_; } //!< Return a pointer to obj_ 37 | 38 | //! Swap with another builtin object of the same type 39 | /*! \param ref the object with which to swap. 40 | */ 41 | void swap(Builtin_Object & ref); 42 | 43 | private: 44 | RObject * obj_; 45 | }; 46 | 47 | } // namespace Rice 48 | 49 | #endif // Rice__Builtin_Object_defn__hpp_ 50 | 51 | -------------------------------------------------------------------------------- /rice/detail/wrap_function.hpp.mustache: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__wrap_function__hpp_ 2 | #define Rice__detail__wrap_function__hpp_ 3 | 4 | // This is a generated file. DO NOT EDIT!! 5 | 6 | 7 | // This causes problems with certain C++ libraries 8 | #undef TYPE 9 | 10 | #include "Exception_Handler.hpp" 11 | #include "Wrapped_Function.hpp" 12 | #include "../Object_defn.hpp" 13 | #include "../Data_Object.hpp" 14 | #include "Arguments.hpp" 15 | 16 | namespace Rice 17 | { 18 | 19 | namespace detail 20 | { 21 | 22 | #ifdef DOXYGEN 23 | 24 | #else 25 | 26 | template 27 | Wrapped_Function * wrap_function( 28 | Ret_T (*func)(), 29 | Data_Object handler = Rice::Nil, 30 | Arguments* arguments = 0); 31 | 32 | {{#entries}} 33 | template 34 | Wrapped_Function * wrap_function( 35 | Ret_T (*func)({{argument_types}}), 36 | Data_Object handler = Rice::Nil, 37 | Arguments* arguments = 0); 38 | 39 | template 40 | Wrapped_Function * wrap_function( 41 | Ret_T (Self_T::*func)({{self_argument_types}}), 42 | Data_Object handler = Rice::Nil, 43 | Arguments* arguments = 0); 44 | 45 | template 46 | Wrapped_Function * wrap_function( 47 | Ret_T (Self_T::*func)({{self_argument_types}}) const, 48 | Data_Object handler = Rice::Nil, 49 | Arguments* arguments = 0); 50 | 51 | // --------------------------------------------------------------------- 52 | 53 | {{/entries}} 54 | #endif // DOXYGEN 55 | 56 | } // namespace detail 57 | 58 | } // namespace Rice 59 | 60 | #include "wrap_function.ipp" 61 | 62 | #endif // Rice__detail__wrap_function__hpp_ 63 | 64 | -------------------------------------------------------------------------------- /sample/inheritance/animals.cpp: -------------------------------------------------------------------------------- 1 | #include "rice/Data_Type.hpp" 2 | #include "rice/Constructor.hpp" 3 | 4 | using namespace Rice; 5 | 6 | class Organism 7 | { 8 | public: 9 | virtual ~Organism() = 0; 10 | virtual char const * name() = 0; 11 | }; 12 | 13 | Organism:: 14 | ~Organism() 15 | { 16 | } 17 | 18 | class Animal 19 | : public Organism 20 | { 21 | public: 22 | virtual ~Animal() = 0; 23 | virtual char const * speak() = 0; 24 | }; 25 | 26 | Animal:: 27 | ~Animal() 28 | { 29 | } 30 | 31 | class Bear 32 | : public Animal 33 | { 34 | public: 35 | virtual char const * name() 36 | { 37 | return "Bear"; 38 | } 39 | 40 | virtual char const * speak() 41 | { 42 | return "I'm smarter than the average bear"; 43 | } 44 | }; 45 | 46 | class Dog 47 | : public Animal 48 | { 49 | public: 50 | virtual char const * name() 51 | { 52 | return "Dog"; 53 | } 54 | 55 | virtual char const * speak() 56 | { 57 | return "Woof woof"; 58 | } 59 | }; 60 | 61 | class Rabbit 62 | : public Animal 63 | { 64 | public: 65 | virtual char const * name() 66 | { 67 | return "Rabbit"; 68 | } 69 | 70 | virtual char const * speak() 71 | { 72 | return "What's up, doc?"; 73 | } 74 | }; 75 | 76 | extern "C" 77 | void Init_animals(void) 78 | { 79 | RUBY_TRY 80 | { 81 | define_class("Organism") 82 | .define_method("name", &Organism::name); 83 | 84 | define_class("Animal") 85 | .define_method("speak", &Animal::speak); 86 | 87 | define_class("Bear") 88 | .define_constructor(Constructor()); 89 | 90 | define_class("Dog") 91 | .define_constructor(Constructor()); 92 | 93 | define_class("Rabbit") 94 | .define_constructor(Constructor()); 95 | } 96 | RUBY_CATCH 97 | } 98 | 99 | -------------------------------------------------------------------------------- /test/test_Builtin_Object.cpp: -------------------------------------------------------------------------------- 1 | #include "unittest.hpp" 2 | #include "rice/Builtin_Object.hpp" 3 | #include "rice/Class.hpp" 4 | 5 | using namespace Rice; 6 | 7 | TESTSUITE(Builtin_Object); 8 | 9 | SETUP(Builtin_Object) 10 | { 11 | ruby_init(); 12 | } 13 | 14 | TESTCASE(construct_with_object) 15 | { 16 | Class c(rb_cObject); 17 | Object o(c.call("new")); 18 | Builtin_Object b(o); 19 | ASSERT_EQUAL(o.value(), b.value()); 20 | ASSERT_EQUAL(T_OBJECT, rb_type(b.value())); 21 | ASSERT_EQUAL(rb_cObject, b.class_of().value()); 22 | ASSERT_EQUAL(rb_cObject, CLASS_OF(b.value())); 23 | } 24 | 25 | TESTCASE(copy_construct) 26 | { 27 | Class c(rb_cObject); 28 | Object o(c.call("new")); 29 | Builtin_Object b(o); 30 | Builtin_Object b2(b); 31 | ASSERT_EQUAL(o.value(), b2.value()); 32 | ASSERT_EQUAL(T_OBJECT, rb_type(b2.value())); 33 | ASSERT_EQUAL(rb_cObject, b2.class_of().value()); 34 | ASSERT_EQUAL(rb_cObject, CLASS_OF(b2.value())); 35 | } 36 | 37 | TESTCASE(dereference) 38 | { 39 | Class c(rb_cObject); 40 | Object o(c.call("new")); 41 | Builtin_Object b(o); 42 | ASSERT_EQUAL(ROBJECT(o.value()), &*b); 43 | } 44 | 45 | TESTCASE(arrow) 46 | { 47 | Class c(rb_cObject); 48 | Object o(c.call("new")); 49 | Builtin_Object b(o); 50 | ASSERT_EQUAL(rb_cObject, b->basic.klass); 51 | } 52 | 53 | TESTCASE(get) 54 | { 55 | Class c(rb_cObject); 56 | Object o(c.call("new")); 57 | Builtin_Object b(o); 58 | ASSERT_EQUAL(ROBJECT(o.value()), b.get()); 59 | } 60 | 61 | TESTCASE(swap) 62 | { 63 | Class c(rb_cObject); 64 | Object o1(c.call("new")); 65 | Builtin_Object b1(o1); 66 | Object o2(c.call("new")); 67 | Builtin_Object b2(o2); 68 | b1.swap(b2); 69 | ASSERT_EQUAL(b1.value(), o2.value()); 70 | ASSERT_EQUAL(b2.value(), o1.value()); 71 | } 72 | -------------------------------------------------------------------------------- /rice/code_gen/auto_function_wrapper.rb: -------------------------------------------------------------------------------- 1 | require "rice_template" 2 | 3 | class AutoFunctionWrapperHpp < RiceTemplate 4 | 5 | cpp_detail_file "Auto_Function_Wrapper.hpp" 6 | 7 | def entry(num) 8 | typenames = typenames_with_return = build(num, "typename Arg{{i}}_T") 9 | specs_with_return = "" 10 | specs = "" 11 | 12 | if num == self.iterations + 1 13 | specs_with_return = "" 14 | typenames_with_return = build(num, "typename Arg{{i}}_T = void") 15 | end 16 | 17 | { 18 | :typenames_with_return => typenames_with_return, 19 | :specs_with_return => specs_with_return, 20 | :typenames => typenames, 21 | :specs => specs, 22 | :num_args => num 23 | } 24 | end 25 | 26 | end 27 | 28 | class AutoFunctionWrapperIpp < RiceTemplate 29 | 30 | cpp_detail_file "Auto_Function_Wrapper.ipp" 31 | 32 | def entry(num) 33 | { 34 | :typenames => build(num, "typename Arg{{i}}_T"), 35 | :types => build(num, "Arg{{i}}_T"), 36 | :vargs => build(num, "varg{{i}}"), 37 | :scan_args => build(num, "&varg{{i}}"), 38 | :call_args => build(num, "arg{{i}}"), 39 | :self_arguments => self_arguments(num), 40 | :arguments => arguments(num) 41 | } 42 | end 43 | 44 | protected 45 | 46 | def arguments(num) 47 | args = [] 48 | num.times do |count| 49 | args << { 50 | :count => count 51 | } 52 | end 53 | 54 | args 55 | end 56 | 57 | def self_arguments(num) 58 | args = [] 59 | (num - 1).times do |count| 60 | args << { 61 | :in_type => "Arg#{count + 1}_T", 62 | :out_type => "Arg#{count+ 1}_Type", 63 | :arg => "arg#{count + 1}", 64 | :count => count 65 | } 66 | end 67 | 68 | args 69 | end 70 | 71 | end 72 | -------------------------------------------------------------------------------- /rice/String.cpp: -------------------------------------------------------------------------------- 1 | #include "String.hpp" 2 | #include "Builtin_Object.hpp" 3 | #include "protect.hpp" 4 | #include "detail/ruby.hpp" 5 | 6 | #ifdef HAVE_STDARG_PROTOTYPES 7 | #include 8 | #define va_init_list(a,b) va_start(a,b) 9 | #else 10 | #include 11 | #define va_init_list(a,b) va_start(a) 12 | #endif 13 | 14 | Rice::String:: 15 | String() 16 | : Builtin_Object(protect(rb_str_new2, "")) 17 | { 18 | } 19 | 20 | Rice::String:: 21 | String(VALUE v) 22 | : Builtin_Object(v) 23 | { 24 | } 25 | 26 | Rice::String:: 27 | String(Object v) 28 | : Builtin_Object(v) 29 | { 30 | } 31 | 32 | Rice::String:: 33 | String(char const * s) 34 | : Builtin_Object(protect(rb_str_new2, s)) 35 | { 36 | } 37 | 38 | Rice::String:: 39 | String(std::string const & s) 40 | : Builtin_Object(protect(rb_str_new, s.data(), s.length())) 41 | { 42 | } 43 | 44 | Rice::String:: 45 | String(Identifier id) 46 | : Builtin_Object(protect(rb_str_new2, id.c_str())) 47 | { 48 | } 49 | 50 | Rice::String Rice::String:: 51 | format(char const * fmt, ...) 52 | { 53 | va_list args; 54 | char buf[BUFSIZ]; 55 | 56 | va_init_list(args, fmt); 57 | vsnprintf(buf, BUFSIZ, fmt, args); 58 | buf[BUFSIZ - 1] = '\0'; 59 | va_end(args); 60 | 61 | String s = String(buf); 62 | return s; 63 | } 64 | 65 | size_t Rice::String:: 66 | length() const 67 | { 68 | return RSTRING_LEN(value()); 69 | } 70 | 71 | char Rice::String:: 72 | operator[](ptrdiff_t index) const 73 | { 74 | return RSTRING_PTR(value())[index]; 75 | } 76 | 77 | char const * Rice::String:: 78 | c_str() const 79 | { 80 | return RSTRING_PTR(value()); 81 | } 82 | 83 | std::string Rice::String:: 84 | str() const 85 | { 86 | return std::string(RSTRING_PTR(value()), length()); 87 | } 88 | 89 | Rice::Identifier Rice::String:: 90 | intern() const 91 | { 92 | return rb_intern(c_str()); 93 | } 94 | 95 | -------------------------------------------------------------------------------- /rice/detail/ruby.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__ruby__hpp_ 2 | #define Rice__detail__ruby__hpp_ 3 | 4 | /*! \file 5 | * \brief Hacks for addressing incompatibilities between various Ruby 6 | * versions. 7 | */ 8 | 9 | #include 10 | 11 | // missing.h that comes with the one-click installer doesn't properly 12 | // check for double-definition of isinf 13 | #ifdef isinf 14 | #define HAVE_ISINF 15 | #endif 16 | 17 | #include "ruby_version_code.hpp" 18 | 19 | #include 20 | 21 | #ifdef WIN32 22 | #include "win32.hpp" 23 | #endif 24 | 25 | // This causes problems with certain C++ libraries 26 | #undef TYPE 27 | 28 | //! A function that takes a VALUE as a parameter and returns a VALUE. 29 | // TODO: Casting from a C++ function to an extern "C" function won't 30 | // work on all platforms. I'm not sure what to do about this. 31 | extern "C" typedef VALUE (*RUBY_VALUE_FUNC)(VALUE); 32 | 33 | // Fix Ruby RUBY_METHOD_FUNC from macro to typedef 34 | #if defined(RUBY_METHOD_FUNC) 35 | # undef RUBY_METHOD_FUNC 36 | extern "C" typedef VALUE (*RUBY_METHOD_FUNC)(ANYARGS); 37 | #endif 38 | 39 | #ifndef RSTRING_LEN 40 | #define RSTRING_LEN(str) RSTRING(str)->len 41 | #endif 42 | 43 | #ifndef RSTRING_PTR 44 | #define RSTRING_PTR(str) RSTRING(str)->ptr 45 | #endif 46 | 47 | #ifndef RARRAY_LEN 48 | #define RARRAY_LEN(arr) RARRAY(arr)->len 49 | #endif 50 | 51 | #ifndef RARRAY_PTR 52 | #define RARRAY_PTR(arr) RARRAY(arr)->ptr 53 | #endif 54 | 55 | #ifndef RHASH_TBL 56 | #define RHASH_TBL(hsh) RHASH(hsh)->tbl 57 | #endif 58 | 59 | #ifndef RCLASS_M_TBL 60 | #define RCLASS_M_TBL(c) RCLASS(c)->m_tbl 61 | #endif 62 | 63 | // ruby.h has a few defines that conflict with Visual Studio's STL 64 | #if defined(_MSC_VER) 65 | #undef write 66 | #undef read 67 | #undef bind 68 | #endif 69 | 70 | #ifdef HAVE_CXX11 71 | #define std_unique_ptr std::unique_ptr 72 | #else 73 | #define std_unique_ptr std::auto_ptr 74 | #endif 75 | 76 | #endif // Rice__detail__ruby__hpp_ 77 | 78 | -------------------------------------------------------------------------------- /sample/map/map.cpp: -------------------------------------------------------------------------------- 1 | #include "rice/Data_Type.hpp" 2 | #include "rice/Constructor.hpp" 3 | 4 | #include 5 | 6 | using namespace Rice; 7 | 8 | namespace 9 | { 10 | 11 | class Map 12 | { 13 | private: 14 | struct Ruby_Value_Compare 15 | { 16 | bool operator()(Object lhs, Object rhs) const 17 | { 18 | Object result = lhs.call("<", rhs); 19 | return result.test(); 20 | } 21 | }; 22 | 23 | typedef std::map Value_Map; 24 | 25 | public: 26 | Object bracket(Object k) 27 | { 28 | Value_Map::iterator it = map_.find(k); 29 | return it == map_.end() ? Object(Qnil) : it->second; 30 | } 31 | 32 | Object bracket_equals(Object k, Object v) 33 | { 34 | map_[k] = v; 35 | return Qnil; 36 | } 37 | 38 | Value_Map::iterator begin() { return map_.begin(); } 39 | Value_Map::iterator end() { return map_.end(); } 40 | 41 | typedef Value_Map::value_type value_type; 42 | typedef Value_Map::iterator iterator; 43 | 44 | private: 45 | Value_Map map_; 46 | }; 47 | 48 | Data_Type rb_cMap; 49 | 50 | } // namespace 51 | 52 | template<> 53 | Object to_ruby(Map::value_type const & p) 54 | { 55 | return protect(rb_assoc_new, p.first, p.second); 56 | } 57 | 58 | #include 59 | extern "C" 60 | void Init_map(void) 61 | { 62 | RUBY_TRY 63 | { 64 | Map::iterator (Map::*begin)() = &Map::begin; 65 | Map::iterator (Map::*end)() = &Map::end; 66 | Rice::Module rb_mStd = define_module("Std"); 67 | 68 | // TODO: no delete method on the map, because I'm not sure how to 69 | // make delete work properly while iterating 70 | rb_cMap = 71 | define_class_under(rb_mStd, "Map") 72 | .define_constructor(Constructor()) 73 | .define_method("[]", &Map::bracket) 74 | .define_method("[]=", &Map::bracket_equals) 75 | .define_iterator(begin, end) 76 | .include_module(rb_mEnumerable) 77 | ; 78 | } 79 | RUBY_CATCH 80 | } 81 | 82 | -------------------------------------------------------------------------------- /rice/Exception_defn.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Exception_defn__hpp_ 2 | #define Rice__Exception_defn__hpp_ 3 | 4 | #include "Exception_Base_defn.hpp" 5 | #include "String.hpp" 6 | #include "Address_Registration_Guard_defn.hpp" 7 | 8 | #include 9 | #include "detail/ruby.hpp" 10 | 11 | namespace Rice 12 | { 13 | 14 | //! A placeholder for Ruby exceptions. 15 | /*! You can use this to safely throw a Ruby exception using C++ syntax: 16 | * \code 17 | * VALUE foo(VALUE self) { 18 | * RUBY_TRY { 19 | * throw Rice::Exception(rb_eMyException, "uh oh!"); 20 | * RUBY_CATCH 21 | * } 22 | * \endcode 23 | */ 24 | class Exception 25 | : public Exception_Base 26 | { 27 | public: 28 | //! Construct a Exception with the exception e. 29 | explicit Exception(VALUE e); 30 | 31 | //! Copy constructor. 32 | Exception(Exception const & other); 33 | 34 | //! Construct a Exception with printf-style formatting. 35 | /*! \param exc either an exception object or a class that inherits 36 | * from Exception. 37 | * \param fmt a printf-style format string 38 | * \param ... the arguments to the format string. 39 | */ 40 | Exception(Object exc, char const * fmt, ...); 41 | 42 | //! Destructor 43 | virtual ~Exception() throw() { } 44 | 45 | //! Get the message the exception holds 46 | /*! \return the result of calling message() on the underlying 47 | * exception object. 48 | */ 49 | String message() const; 50 | 51 | //! Get message as a char const *. 52 | /*! If message is a non-string object, then this function will attempt 53 | * to throw an exception (which it can't do because of the no-throw 54 | * specification). 55 | * \return the underlying C pointer of the underlying message object. 56 | */ 57 | virtual char const * what() const throw(); 58 | 59 | private: 60 | // Keep message around in case someone calls what() and then the GC 61 | // gets invoked. 62 | mutable VALUE message_; 63 | Address_Registration_Guard message_guard_; 64 | }; 65 | 66 | } // namespace Rice 67 | 68 | #endif // Rice__Exception_defn__hpp_ 69 | 70 | -------------------------------------------------------------------------------- /rice/to_from_ruby_defn.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__to_from_ruby_defn__hpp_ 2 | #define Rice__to_from_ruby_defn__hpp_ 3 | 4 | #include "Object_defn.hpp" 5 | #include "detail/from_ruby.hpp" 6 | #include "detail/to_ruby.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // --------------------------------------------------------------------- 13 | 14 | //! Convert a Ruby object to C++. 15 | /*! If the Ruby object can be converted to an immediate value, returns a 16 | * copy of the Ruby object. If the Ruby object is holding a C++ 17 | * object and the type specified is a pointer to that type, returns a 18 | * pointer to that object. 19 | * 20 | * Conversions from ruby to a pointer type are automatically generated 21 | * when a type is bound using Data_Type. If no conversion exists an 22 | * exception is thrown. 23 | * 24 | * \param T the C++ type to which to convert. 25 | * \param x the Ruby object to convert. 26 | * \return a C++ representation of the Ruby object. 27 | * 28 | * Example: 29 | * \code 30 | * Object x = INT2NUM(42); 31 | * std::cout << from_ruby(x); 32 | * 33 | * Data_Object foo(new Foo); 34 | * Object obj(foo); 35 | * std::cout << *from_ruby(obj) << std::endl; 36 | * \endcode 37 | */ 38 | template 39 | inline 40 | typename Rice::detail::from_ruby_::Retval_T from_ruby(Rice::Object x) 41 | { 42 | return Rice::detail::from_ruby_::convert(x); 43 | } 44 | 45 | //! Convert a C++ object to Ruby. 46 | /*! If x is a pointer, wraps the pointee as a Ruby object. If x is an 47 | * Object, returns x. 48 | * 49 | * If no conversion exists a compile-time error is generated. 50 | * 51 | * \param x the object to convert. 52 | * \return a Ruby representation of the C++ object. 53 | * 54 | * Example: 55 | * \code 56 | * rb_p(to_ruby(42)); 57 | * 58 | * Foo * p_foo = new Foo(); 59 | * rb_p(to_ruby(p_foo)); 60 | * \endcode 61 | */ 62 | template 63 | inline 64 | Rice::Object to_ruby(T const & x) 65 | { 66 | return Rice::detail::to_ruby_::convert(x); 67 | } 68 | 69 | #endif // Rice__to_from_ruby_defn__hpp_ 70 | 71 | -------------------------------------------------------------------------------- /rice/detail/wrap_function.ipp.mustache: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__wrap_function__ipp_ 2 | #define Rice__detail__wrap_function__ipp_ 3 | 4 | // This is a generated file. DO NOT EDIT!! 5 | 6 | 7 | // This causes problems with certain C++ libraries 8 | #undef TYPE 9 | 10 | #include "Auto_Function_Wrapper.hpp" 11 | #include "Auto_Member_Function_Wrapper.hpp" 12 | namespace Rice 13 | { 14 | 15 | namespace detail 16 | { 17 | 18 | template 19 | Wrapped_Function * wrap_function( 20 | Ret_T (*func)(), 21 | Data_Object handler, 22 | Arguments* arguments) 23 | { 24 | typedef Ret_T (*Func)(); 25 | return new Auto_Function_Wrapper(func, handler, arguments); 26 | } 27 | 28 | {{#entries}} 29 | template 30 | Wrapped_Function * wrap_function( 31 | Ret_T (*func)({{argument_types}}), 32 | Data_Object handler, 33 | Arguments* arguments) 34 | { 35 | typedef Ret_T (*Func)({{argument_types}}); 36 | return new Auto_Function_Wrapper(func, handler, arguments); 37 | } 38 | 39 | template 40 | Wrapped_Function * wrap_function( 41 | Ret_T (Self_T::*func)({{self_argument_types}}), 42 | Data_Object handler, 43 | Arguments* arguments) 44 | { 45 | typedef Ret_T (Self_T::*Func)({{self_argument_types}}); 46 | return new Auto_Member_Function_Wrapper(func, handler, arguments); 47 | } 48 | 49 | template 50 | Wrapped_Function * wrap_function( 51 | Ret_T (Self_T::*func)({{self_argument_types}}) const, 52 | Data_Object handler, 53 | Arguments* arguments) 54 | { 55 | typedef Ret_T (Self_T::*Func)({{self_argument_types}}) const; 56 | return new Auto_Member_Function_Wrapper(func, handler, arguments); 57 | } 58 | 59 | // --------------------------------------------------------------------- 60 | 61 | {{/entries}} 62 | } // namespace detail 63 | 64 | } // namespace Rice 65 | 66 | 67 | #endif // Rice__detail__wrap_function__ipp_ 68 | 69 | -------------------------------------------------------------------------------- /rice/detail/Iterator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__Iterator__hpp_ 2 | #define Rice__detail__Iterator__hpp_ 3 | 4 | #include "method_data.hpp" 5 | #include "ruby.hpp" 6 | #include "../protect.hpp" 7 | #include "../Data_Object.hpp" 8 | #include "../Identifier.hpp" 9 | 10 | namespace Rice 11 | { 12 | 13 | namespace detail 14 | { 15 | 16 | class Iterator 17 | { 18 | public: 19 | virtual ~Iterator() { } 20 | 21 | virtual VALUE call_impl(VALUE self) = 0; 22 | 23 | static VALUE call(VALUE self) 24 | { 25 | VALUE data = (VALUE)method_data(); 26 | Data_Object iterator( 27 | data, 28 | Data_Type()); 29 | return iterator->call_impl(self); 30 | } 31 | }; 32 | 33 | template 34 | class Iterator_Impl 35 | : public Iterator 36 | { 37 | public: 38 | Iterator_Impl( 39 | Iterator_T (T::*begin)(), 40 | Iterator_T (T::*end)(), 41 | Data_Type data_type) 42 | : begin_(begin) 43 | , end_(end) 44 | , data_type_(data_type) 45 | { 46 | } 47 | 48 | virtual VALUE call_impl(VALUE self) 49 | { 50 | Data_Object obj(self, data_type_); 51 | Iterator_T it = (*obj.*begin_)(); 52 | Iterator_T end = (*obj.*end_)(); 53 | for(; it != end; ++it) 54 | { 55 | Rice::protect(rb_yield, to_ruby(*it)); 56 | } 57 | return self; 58 | } 59 | 60 | private: 61 | Iterator_T (T::*begin_)(); 62 | Iterator_T (T::*end_)(); 63 | Data_Type data_type_; 64 | }; 65 | 66 | template 67 | void define_iterator( 68 | Module klass, 69 | Identifier name, 70 | Iterator_T (T::*begin)(), 71 | Iterator_T (T::*end)()) 72 | { 73 | Data_Type iterator_klass; 74 | Data_Object iterator( 75 | new Iterator_Impl( 76 | begin, 77 | end, 78 | Data_Type(klass)), 79 | iterator_klass); 80 | define_method_with_data( 81 | klass, 82 | name, 83 | (RUBY_METHOD_FUNC)iterator->call, 84 | 0, 85 | iterator); 86 | } 87 | 88 | } // namespace detail 89 | 90 | } // namespace Rice 91 | 92 | #endif // Rice__detail__Iterator__hpp_ 93 | 94 | -------------------------------------------------------------------------------- /rice/Constructor.hpp.mustache: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Constructor__hpp_ 2 | #define Rice__Constructor__hpp_ 3 | 4 | // This is a generated file. DO NOT EDIT!! 5 | 6 | 7 | // This causes problems with certain C++ libraries 8 | #undef TYPE 9 | 10 | #include "to_from_ruby_defn.hpp" 11 | #include "detail/method_data.hpp" 12 | namespace Rice 13 | { 14 | #ifdef DOXYGEN 15 | //! Define a Type's Constructor and it's arguments. 16 | /*! E.g. for the default constructor on a Type: 17 | \code 18 | define_class() 19 | .define_constructor(Constructor()); 20 | \endcode 21 | * 22 | * The first template type must be the type being wrapped. 23 | * Afterwards any extra types must match the appropriate constructor 24 | * to be used in C++ when constructing the object. 25 | * 26 | * For more information, see Rice::Data_Type::define_constructor. 27 | */ 28 | template 29 | class Constructor 30 | { 31 | }; 32 | 33 | #else 34 | 35 | template 36 | class Constructor 37 | { 38 | private: 39 | Constructor() 40 | { 41 | } 42 | }; 43 | 44 | template 45 | class Constructor 46 | { 47 | public: 48 | static void construct(Object self) 49 | { 50 | DATA_PTR(self.value()) = new T(); 51 | } 52 | }; 53 | 54 | 55 | template 56 | class Constructor 57 | { 58 | public: 59 | static void construct(Object self) 60 | { 61 | DATA_PTR(self.value()) = new T(self); 62 | } 63 | }; 64 | 65 | {{#selfs}} 66 | {{#entries}} 67 | 68 | {{! The extra 'void' at the end here is a work around to a bug with GCC}} 69 | template 70 | class Constructor 71 | { 72 | public: 73 | static void construct(Object self, {{parameters}}) 74 | { 75 | DATA_PTR(self.value()) = new T({{with_self}}{{arguments}}); 76 | } 77 | }; 78 | 79 | {{/entries}} 80 | {{/selfs}} 81 | 82 | #endif // DOXYGEN 83 | 84 | } // namespace Rice 85 | 86 | 87 | #endif // Rice__Constructor__hpp_ 88 | 89 | -------------------------------------------------------------------------------- /rice/Class_defn.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Class_defn__hpp_ 2 | #define Rice__Class_defn__hpp_ 3 | 4 | #include "Object_defn.hpp" 5 | #include "Module_impl.hpp" 6 | #include "Module_defn.hpp" 7 | #include "to_from_ruby_defn.hpp" 8 | #include "Identifier.hpp" 9 | 10 | /*! 11 | * \example inheritance/animals.cpp 12 | */ 13 | 14 | namespace Rice 15 | { 16 | 17 | //! A helper for defining a Class and its methods. 18 | /*! This class provides a C++-style interface to ruby's Class class and 19 | * for defining methods on that class. 20 | */ 21 | class Class 22 | : public Module_impl 23 | { 24 | public: 25 | //! Default construct a new class wrapper and initialize it to 26 | //! rb_cObject. 27 | Class(); 28 | 29 | //! Construct a new class wrapper from a ruby object of type T_CLASS. 30 | Class(VALUE v); 31 | 32 | //! Disallow creation of an instance from Ruby code. 33 | /*! Undefines the singleton method allocate (or new, if using a 34 | * version of ruby prior to 1.7) and the instance method initialize. 35 | */ 36 | Class & undef_creation_funcs(); 37 | }; 38 | 39 | //! Define a new class in the namespace given by module. 40 | /*! \param module the Module in which to define the class. 41 | * \param name the name of the class. 42 | * \param superclass the base class to use. 43 | * \return the new class. 44 | */ 45 | Class define_class_under( 46 | Object module, 47 | char const * name, 48 | Object superclass = rb_cObject); 49 | 50 | //! Define a new class in the default namespace. 51 | /*! \param name the name of the class. 52 | * \param superclass the base class to use. 53 | * \return the new class. 54 | */ 55 | Class define_class( 56 | char const * name, 57 | Object superclass = rb_cObject); 58 | 59 | //! Create a new anonymous class. 60 | /*! \param superclass the base class to use. 61 | * \return the new class. 62 | */ 63 | Class anonymous_class( 64 | Object superclass = rb_cObject); 65 | 66 | } // namespace Rice 67 | 68 | template<> 69 | inline 70 | Rice::Class from_ruby(Rice::Object x) 71 | { 72 | return Rice::Class(x); 73 | } 74 | 75 | template<> 76 | inline 77 | Rice::Object to_ruby(Rice::Class const & x) 78 | { 79 | return x; 80 | } 81 | 82 | #endif // Rice__Class_defn__hpp_ 83 | 84 | -------------------------------------------------------------------------------- /rice/Address_Registration_Guard_defn.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Address_Registration_Guard_defn__hpp_ 2 | #define Rice__Address_Registration_Guard_defn__hpp_ 3 | 4 | #include "Object_defn.hpp" 5 | #include "detail/ruby.hpp" 6 | #include "detail/Not_Copyable.hpp" 7 | 8 | namespace Rice 9 | { 10 | 11 | //! A guard to register a given address with the GC. 12 | /*! Calls rb_gc_register_address upon construction and 13 | * rb_gc_unregister_address upon destruction. 14 | * For example: 15 | * \code 16 | * Class Foo 17 | * { 18 | * public: 19 | * Foo() 20 | * : string_(rb_str_new2()) 21 | * , guard_(&string_); 22 | * 23 | * private: 24 | * VALUE string_; 25 | * Address_Registration_Guard guard_; 26 | * }; 27 | * \endcode 28 | */ 29 | class Address_Registration_Guard 30 | : private detail::Not_Copyable 31 | { 32 | public: 33 | //! Register an address with the GC. 34 | /* \param address The address to register with the GC. The address 35 | * must point to a valid ruby object (RObject). 36 | */ 37 | Address_Registration_Guard(VALUE * address); 38 | 39 | //! Register an Object with the GC. 40 | /*! \param object The Object to register with the GC. The object must 41 | * not be destroyed before the Address_Registration_Guard is 42 | * destroyed. 43 | */ 44 | Address_Registration_Guard(Object * object); 45 | 46 | //! Unregister an address/Object with the GC. 47 | /*! Destruct an Address_Registration_Guard. The address registered 48 | * with the Address_Registration_Guard when it was constructed will 49 | * be unregistered from the GC. 50 | */ 51 | ~Address_Registration_Guard(); 52 | 53 | //! Get the address that is registered with the GC. 54 | VALUE * address() const; 55 | 56 | //! Swap with another Address_Registration_Guard. 57 | void swap(Address_Registration_Guard & other); 58 | 59 | /** Called during Ruby's exit process since we should not call 60 | * rb_gc unregister_address there 61 | */ 62 | static void disable(); 63 | 64 | private: 65 | static bool enabled; 66 | static bool exit_handler_registered; 67 | 68 | static void registerExitHandler(); 69 | 70 | VALUE * address_; 71 | }; 72 | 73 | } // namespace Rice 74 | 75 | #endif // Rice__Address_Registration_Guard_defn__hpp_ 76 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Auto_Function_Wrapper: Clean up argument definitions 2 | 3 | Implicit and other type conversions: 4 | 5 | The idea here is that we can tell Rice which types have been defined to have 6 | automatic conversions. For example, Ogre::Degree and Ogre::Radian are defined 7 | to be used interchangably, and any numerical conversions happen in each class. 8 | 9 | boost::python exposes a completely seperate declaration method: implicitly_convertible 10 | I'm going to try having it as a method on Data_Type, but I may need to go the same route 11 | depending on if bi-directional requires this, say: 12 | 13 | implicitly_convertible(); 14 | implicitly_convertible(); 15 | 16 | Due to Rice's and Ruby's differing handling of defined types and fundamental types (int, float, etc), 17 | special care needs to be taken to ensure both conversions work 18 | 19 | I want to be able to do: 20 | 21 | struct Real 22 | { 23 | Real(int x) 24 | : v(x) 25 | {} 26 | 27 | operator int() const 28 | { 29 | return v; 30 | } 31 | 32 | int v; 33 | }; 34 | 35 | define_class("Real") 36 | .define_constructor(Constructor()) 37 | .implicit_cast_to(); 38 | 39 | or if there were a defined type that Real converts to and from: 40 | 41 | define_class("Real") 42 | .define_constructor(Constructor()) 43 | .implicit_cast_to(); 44 | 45 | define_class("Fake") 46 | .define_constructor(Constructor()) 47 | .implicit_cast_to(); 48 | 49 | So the steps I'll need to take to make this work correctly are as follows: 50 | 51 | T from_ruby(Rice::Object x) 52 | - Check for direct match (exists) 53 | - Change casters to a multimap 54 | - Build new caster for implicit type conversion 55 | - Might need two ways of this: constructor or cast method. 56 | 57 | - Check for any implicit casts for type T 58 | - Try to build the list so that I don't have to actually cast anything 59 | unless I know it's the right type to cast to 60 | - How do I know what type I'm casting from? (the case of Real being given a FixNum) 61 | - Defined types to Defined types will be much simpler I believe 62 | 63 | -------------------------------------------------------------------------------- /rice/code_gen/rice_template.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'mustache' 3 | 4 | RICE_HOME = File.expand_path(File.join(File.dirname(__FILE__), "..")) 5 | 6 | MAX_ARGS = 15 7 | 8 | class RiceTemplate < Mustache 9 | # Error out on unfound tags 10 | self.raise_on_context_miss = true 11 | 12 | # Select a mustache file in rice/ 13 | def self.cpp_file(file) 14 | self.template_file = File.join(RICE_HOME, "#{file}.mustache") 15 | end 16 | 17 | # Select a mustache file in rice/detail/ 18 | def self.cpp_detail_file(file) 19 | self.template_file = File.join(RICE_HOME, "detail", "#{file}.mustache") 20 | end 21 | 22 | # Return the out the resulting file to be written to 23 | def self.out_file 24 | self.template_file.gsub(/\.mustache/, "") 25 | end 26 | 27 | # Render this template and print out to .out_file 28 | def self.render_to_file 29 | File.open(self.out_file, "w+") do |f| 30 | f.write(render) 31 | end 32 | end 33 | 34 | ## 35 | # Template helper methods 36 | ## 37 | 38 | # All templates need to implement this method to define 39 | # exactly what an entry contains 40 | def entry 41 | raise "Template must implement this method" 42 | end 43 | 44 | # How many iterations are we running? 45 | def iterations 46 | self[:max_args] || MAX_ARGS 47 | end 48 | 49 | # Every template needs to loop over a set called 'entries' 50 | def entries 51 | e = [] 52 | self.iterations.times do |i| 53 | e << entry(i + 1) 54 | end 55 | e 56 | end 57 | 58 | # Can loop over the entries in reverse order 59 | def reverse_entries 60 | e = [] 61 | self.iterations.downto(0) do |i| 62 | e << entry(i + 1) 63 | end 64 | e 65 | end 66 | 67 | # Build _count_ number of _template_ strings and return 68 | # the list as a comma delimited array. 69 | # 70 | # template is expected to be a valid Mustache template. 71 | # This template should use {{i}} for the counter number. 72 | # 73 | # If seperator is present, returns a string. If nil, returns 74 | # the array. 75 | def build(count, template, seperator = ", ") 76 | args = [] 77 | 78 | count.times do |i| 79 | args << Mustache.render(template, {:i => i}) 80 | end 81 | 82 | if seperator 83 | args.join(seperator) 84 | else 85 | args 86 | end 87 | end 88 | 89 | end 90 | -------------------------------------------------------------------------------- /rice/String.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__String__hpp_ 2 | #define Rice__String__hpp_ 3 | 4 | #include "Identifier.hpp" 5 | #include "Builtin_Object_defn.hpp" 6 | #include "to_from_ruby_defn.hpp" 7 | #include "detail/ruby.hpp" 8 | #include 9 | 10 | namespace Rice 11 | { 12 | 13 | //! A Wraper for the ruby String class. 14 | /*! This class provides a C++-style interface to ruby's String class and 15 | * its associated rb_str_* functions. 16 | * 17 | * Example: 18 | * \code 19 | * String s(String::format("%s: %d", "foo", 42)); 20 | * std::cout << s.length() << std::endl; 21 | * \endcode 22 | */ 23 | class String 24 | : public Builtin_Object 25 | { 26 | public: 27 | //! Construct a new string. 28 | String(); 29 | 30 | //! Wrap an existing string. 31 | String(VALUE v); 32 | 33 | //! Wrap an existing string. 34 | String(Object v); 35 | 36 | //! Construct a String from an Identifier. 37 | String(Identifier id); 38 | 39 | //! Construct a String from a null-terminated C string. 40 | String(char const * s); 41 | 42 | //! Construct a String from an std::string. 43 | String(std::string const & s); 44 | 45 | //! Format a string using printf-style formatting. 46 | static String format(char const * s, ...); 47 | 48 | //! Get the length of the String. 49 | /*! \return the length of the string. 50 | */ 51 | size_t length() const; 52 | 53 | //! Get the character at the given index. 54 | /*! \param index the desired index. 55 | * \return the character at the given index. 56 | */ 57 | char operator[](ptrdiff_t index) const; 58 | 59 | //! Return a pointer to the beginning of the underlying C string. 60 | char const * c_str() const; 61 | 62 | //! Return a copy of the string as an std::string. 63 | std::string str() const; 64 | 65 | //! Create an Identifier from the String. 66 | /*! Calls rb_intern to create an ID. 67 | * \return an Identifier holding the ID returned from rb_intern. 68 | */ 69 | Identifier intern() const; 70 | }; 71 | 72 | } // namespace Rice 73 | 74 | template<> 75 | inline 76 | Rice::String from_ruby(Rice::Object x) 77 | { 78 | return Rice::String(x); 79 | } 80 | 81 | template<> 82 | inline 83 | Rice::Object to_ruby(Rice::String const & x) 84 | { 85 | return x; 86 | } 87 | 88 | #include "Builtin_Object.ipp" 89 | 90 | #endif // Rice__String__hpp_ 91 | 92 | -------------------------------------------------------------------------------- /rice/Module_defn.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Module_defn__hpp_ 2 | #define Rice__Module_defn__hpp_ 3 | 4 | #include "Object_defn.hpp" 5 | #include "Module_impl.hpp" 6 | #include "to_from_ruby_defn.hpp" 7 | #include 8 | 9 | namespace Rice 10 | { 11 | 12 | class Array; 13 | class Class; 14 | class String; 15 | 16 | //! A helper for defining a Module and its methods. 17 | /*! This class provides a C++-style interface to ruby's Module class and 18 | * for defining methods on that module. 19 | * 20 | * Many of the methods are defined in Module_impl.hpp so that they can 21 | * return a reference to the most derived type. 22 | */ 23 | class Module 24 | // TODO: we can't inherit from Builtin_Object, because Class needs 25 | // type T_CLASS and Module needs type T_MODULE 26 | : public Module_impl 27 | { 28 | public: 29 | //! Default construct a Module and initialize it to rb_cObject. 30 | Module(); 31 | 32 | //! Construct a Module from an existing Module object. 33 | Module(VALUE v); 34 | 35 | //! Return the name of the module. 36 | String name() const; 37 | 38 | //! Swap with another Module. 39 | void swap(Module & other); 40 | 41 | //! Return an array containing the Module's ancestors. 42 | /*! You will need to include Array.hpp to use this function. 43 | */ 44 | Array ancestors() const; 45 | 46 | //! Return the module's singleton class. 47 | /*! You will need to include Class.hpp to use this function. 48 | */ 49 | Class singleton_class() const; 50 | }; 51 | 52 | //! Define a new module in the namespace given by module. 53 | /*! \param module the module in which to define the new module. 54 | * \param name the name of the new module. 55 | */ 56 | Module define_module_under( 57 | Object module, 58 | char const * name); 59 | 60 | //! Define a new module in the default namespace. 61 | /*! \param name the name of the new module. 62 | */ 63 | Module define_module( 64 | char const * name); 65 | 66 | //! Create a new anonymous module. 67 | /*! \return the new module. 68 | */ 69 | Module anonymous_module(); 70 | 71 | } // namespace Rice 72 | 73 | template<> 74 | inline 75 | Rice::Module from_ruby(Rice::Object x) 76 | { 77 | return Rice::Module(x); 78 | } 79 | 80 | template<> 81 | inline 82 | Rice::Object to_ruby(Rice::Module const & x) 83 | { 84 | return x; 85 | } 86 | 87 | #endif // Rice__Module_defn__hpp_ 88 | 89 | -------------------------------------------------------------------------------- /rice/detail/Caster.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__Caster__hpp_ 2 | #define Rice__detail__Caster__hpp_ 3 | 4 | #include "../Module.hpp" 5 | #include 6 | 7 | namespace Rice 8 | { 9 | 10 | namespace detail 11 | { 12 | 13 | class Abstract_Caster 14 | { 15 | public: 16 | virtual void * cast_to_base(void * derived, Module type) const = 0; 17 | virtual ~Abstract_Caster() { } 18 | }; 19 | 20 | template 21 | class Caster 22 | : public Abstract_Caster 23 | { 24 | public: 25 | Caster(Abstract_Caster * base_caster, Module type) 26 | : base_caster_(base_caster) 27 | , type_(type) 28 | { 29 | } 30 | 31 | protected: 32 | virtual void * cast_to_base(void * derived, Module type) const 33 | { 34 | if(type.value() == type_.value()) 35 | { 36 | Derived_T * d(static_cast(derived)); 37 | return static_cast(d); 38 | } 39 | else 40 | { 41 | if(base_caster_) 42 | { 43 | return base_caster_->cast_to_base(derived, type); 44 | } 45 | else 46 | { 47 | std::string s = "bad cast. No caster found for "; 48 | s += type_.name().str(); 49 | throw std::runtime_error(s); 50 | } 51 | } 52 | } 53 | 54 | private: 55 | Abstract_Caster * base_caster_; 56 | Module type_; 57 | }; 58 | 59 | template 60 | class Implicit_Caster 61 | : public Abstract_Caster 62 | { 63 | public: 64 | Implicit_Caster(Abstract_Caster * base_caster, Module type) 65 | : base_caster_(base_caster) 66 | , type_(type) 67 | { 68 | } 69 | 70 | protected: 71 | virtual void * cast_to_base(void * derived, Module type) const 72 | { 73 | if(type.value() == type_.value()) 74 | { 75 | return new To_T( *static_cast(derived) ); 76 | } 77 | else 78 | { 79 | if(base_caster_) 80 | { 81 | return base_caster_->cast_to_base(derived, type); 82 | } 83 | else 84 | { 85 | std::string s = "bad cast. No implicit caster found for "; 86 | s += type_.name().str(); 87 | throw std::runtime_error(s); 88 | } 89 | } 90 | } 91 | 92 | private: 93 | Abstract_Caster * base_caster_; 94 | Module type_; 95 | }; 96 | 97 | 98 | 99 | } // detail 100 | 101 | } // Rice 102 | 103 | #endif //Rice__detail__Caster__hpp_ 104 | -------------------------------------------------------------------------------- /test/test_String.cpp: -------------------------------------------------------------------------------- 1 | #include "unittest.hpp" 2 | #include "rice/String.hpp" 3 | #include "rice/global_function.hpp" 4 | 5 | using namespace Rice; 6 | 7 | TESTSUITE(String); 8 | 9 | SETUP(String) 10 | { 11 | ruby_init(); 12 | } 13 | 14 | TESTCASE(default_construct) 15 | { 16 | String s; 17 | ASSERT_EQUAL(T_STRING, rb_type(s)); 18 | ASSERT_EQUAL("", RSTRING_PTR(s.value())); 19 | } 20 | 21 | TESTCASE(construct_from_value) 22 | { 23 | String s(rb_str_new2("foo")); 24 | ASSERT_EQUAL(T_STRING, rb_type(s)); 25 | ASSERT_EQUAL("foo", RSTRING_PTR(s.value())); 26 | } 27 | 28 | TESTCASE(construct_from_object) 29 | { 30 | Object o(rb_str_new2("foo")); 31 | String s(o); 32 | ASSERT_EQUAL(T_STRING, rb_type(s)); 33 | ASSERT_EQUAL("foo", RSTRING_PTR(s.value())); 34 | } 35 | 36 | TESTCASE(construct_from_identifier) 37 | { 38 | String s(Identifier("foo")); 39 | ASSERT_EQUAL(T_STRING, rb_type(s)); 40 | ASSERT_EQUAL("foo", RSTRING_PTR(s.value())); 41 | } 42 | 43 | TESTCASE(construct_from_c_string) 44 | { 45 | String s("foo"); 46 | ASSERT_EQUAL(T_STRING, rb_type(s)); 47 | ASSERT_EQUAL("foo", RSTRING_PTR(s.value())); 48 | } 49 | 50 | TESTCASE(construct_from_std_string) 51 | { 52 | String s(std::string("foo")); 53 | ASSERT_EQUAL(T_STRING, rb_type(s)); 54 | ASSERT_EQUAL("foo", RSTRING_PTR(s.value())); 55 | } 56 | 57 | TESTCASE(format) 58 | { 59 | String s(String::format("%s %d", "foo", 42)); 60 | ASSERT_EQUAL(T_STRING, rb_type(s)); 61 | ASSERT_EQUAL("foo 42", RSTRING_PTR(s.value())); 62 | } 63 | 64 | TESTCASE(length) 65 | { 66 | String s("foo"); 67 | ASSERT_EQUAL(3u, s.length()); 68 | } 69 | 70 | TESTCASE(bracket) 71 | { 72 | String s("foo"); 73 | ASSERT_EQUAL('f', s[0]); 74 | ASSERT_EQUAL('o', s[1]); 75 | ASSERT_EQUAL('o', s[2]); 76 | } 77 | 78 | TESTCASE(c_str) 79 | { 80 | String s("foo"); 81 | ASSERT_EQUAL(RSTRING_PTR(s.value()), s.c_str()); 82 | } 83 | 84 | TESTCASE(str) 85 | { 86 | String s("foo"); 87 | ASSERT_EQUAL(std::string("foo"), s.str()); 88 | } 89 | 90 | TESTCASE(intern) 91 | { 92 | String s("foo"); 93 | ASSERT_EQUAL(Identifier("foo"), s.intern()); 94 | } 95 | 96 | /** 97 | * Issue 59 - Copy constructor compilation problem. 98 | */ 99 | 100 | namespace { 101 | void testStringArg(Object self, String string) { 102 | } 103 | } 104 | 105 | TESTCASE(use_string_in_wrapped_function) { 106 | define_global_function("test_string_arg", &testStringArg); 107 | } 108 | -------------------------------------------------------------------------------- /rice/rubypp.rb: -------------------------------------------------------------------------------- 1 | class Preprocessor 2 | def initialize(input, output, filename) 3 | @input = input 4 | @output = output 5 | @filename = filename 6 | @linenum = 1 7 | end 8 | 9 | def getline 10 | line = @input.gets 11 | @linenum += 1 if not line.nil? 12 | return line 13 | end 14 | 15 | def preprocess 16 | success = false 17 | begin 18 | loop do 19 | line = getline 20 | break if line.nil? 21 | case line 22 | when /(.*[^\\]|^)\#\{(.*?)\}(.*)/ 23 | puts "#{$1}#{evaluate($2, @linenum)}#{$3}" 24 | when /^\#ruby\s+<<(.*)/ 25 | marker = $1 26 | str = '' 27 | evalstart = @linenum 28 | loop do 29 | line = getline 30 | if line.nil? then 31 | raise "End of input without #{marker}" 32 | end 33 | break if line.chomp == marker 34 | str << line 35 | end 36 | result = evaluate(str, evalstart) 37 | puts result if not result.nil? 38 | when /^\#ruby\s+(.*)/ 39 | str = line = $1 40 | while line[-1] == ?\\ 41 | str.chop! 42 | line = getline 43 | break if line.nil? 44 | line.chomp! 45 | str << line 46 | end 47 | result = evaluate(str, @linenum) 48 | puts result if not result.nil? 49 | else 50 | puts line 51 | end 52 | end 53 | success = true 54 | ensure 55 | if not success then 56 | $stderr.puts "Error on line #{@linenum}:" 57 | end 58 | end 59 | end 60 | 61 | def evaluate(str, linenum) 62 | result = eval(str, TOPLEVEL_BINDING, @filename, linenum) 63 | success = true 64 | return result 65 | end 66 | 67 | def puts(line='') 68 | @output.puts(line) 69 | end 70 | end 71 | 72 | def puts(line='') 73 | $preprocessor.puts(line) 74 | end 75 | 76 | def rubypp(input_file, output_file) 77 | input = input_file ? File.open(input_file) : $stdin 78 | output = output_file ? File.open(output_file, 'w') : $stdout 79 | 80 | success = false 81 | begin 82 | $preprocessor = Preprocessor.new(input, output, input_file || "(stdin)") 83 | $preprocessor.preprocess() 84 | success = true 85 | ensure 86 | if not success then 87 | File.unlink(output_file) rescue Errno::ENOENT 88 | end 89 | end 90 | end 91 | 92 | if __FILE__ == $0 then 93 | input_file = ARGV[0] 94 | output_file = ARGV[1] 95 | rubypp(input_file, output_file) 96 | end 97 | 98 | -------------------------------------------------------------------------------- /ANNOUNCE: -------------------------------------------------------------------------------- 1 | Rice: Ruby Interface for C++ Extensions 2 | ======================================== 3 | 4 | What is Rice? 5 | 6 | Rice is a C++ interface to Ruby's C API. It provides a type-safe and 7 | exception-safe interface in order to make embedding Ruby and writing 8 | Ruby extensions with C++ easier. It is similar to Boost.Python in many 9 | ways, but also attempts to provide an object-oriented interface to all 10 | of the Ruby C API. 11 | 12 | 13 | What's New? 14 | 15 | * Ruby 2.2 support 16 | Potential breaking changes. Ruby 2.2 removed RHash as a public accessible struct 17 | and as such I changed all of the Builtin_Objects to work directly off of RObject 18 | instead of the specifics (RArray, RStruct, RString, etc). If you've been using these 19 | objects directly I recommend using either the Rice API or Ruby's CAPI instead for 20 | future compatibility. 21 | 22 | Supported Platforms: 23 | 24 | * Linux 25 | * Mac OS X 26 | 27 | * While Windows has been known to work with MinGW / MSYS, I haven't 28 | been able to keep this testing up as of late. Would appreciate any help 29 | here. 30 | 31 | 32 | What Rice gives you: 33 | 34 | * A simple C++-based syntax for wrapping and defining classes 35 | * Automatic conversion of exceptions between C++ and Ruby 36 | * Smart pointers for handling garbage collection 37 | * Wrappers for most builtin types to simplify calling code 38 | 39 | Documentation: http://jasonroelofs.github.io/rice 40 | 41 | Project Page: http://github.com/jasonroelofs/rice 42 | 43 | Mailing List: rice@librelist.com 44 | First email will be used as subscription and dropped. 45 | 46 | 47 | How do you get Rice? 48 | 49 | gem install rice 50 | 51 | Note: Rice does require a C++ compiler. See the Documentation page for more details. 52 | 53 | 54 | How simple of a syntax? 55 | 56 | wrapper.cpp 57 | 58 | #include 59 | #include 60 | 61 | class MyWrapper { 62 | public: 63 | MyWrapper() { } 64 | 65 | void doThis() { } 66 | int doThat(int a, float b) { } 67 | }; 68 | 69 | extern "C" 70 | void Init_wrapper() 71 | { 72 | define_class("MyWrapper") 73 | .define_constructor(Constructor()) 74 | .define_method("do_this", &MyWrapper::doThis) 75 | .define_method("do_that", &MyWrapper::doThat); 76 | } 77 | 78 | extconf.rb 79 | 80 | require 'mkmf-rice' 81 | create_makefile("wrapper") 82 | 83 | test.rb 84 | 85 | require 'wrapper' 86 | c = MyWrapper.new 87 | c.do_this 88 | c.do_that(1, 2.0) 89 | -------------------------------------------------------------------------------- /rice/detail/Exception_Handler_defn.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__Exception_Handler_defn__hpp_ 2 | #define Rice__detail__Exception_Handler_defn__hpp_ 3 | 4 | #include "ruby.h" 5 | #undef TYPE 6 | 7 | #include "Not_Copyable.hpp" 8 | #include "../Address_Registration_Guard_defn.hpp" 9 | #include "../Data_Object_defn.hpp" 10 | 11 | namespace Rice 12 | { 13 | 14 | namespace detail 15 | { 16 | 17 | // A class for converting C++ exceptions to ruby exceptions. It's used 18 | // like this: 19 | // 20 | // try 21 | // { 22 | // } 23 | // catch(...) 24 | // { 25 | // handler->handle_exception(); 26 | // } 27 | // 28 | // If an exception is thrown the handler will pass the exception up the 29 | // chain, then the last handler in the chain will throw the exception 30 | // down the chain until a lower handler can handle it, e.g.: 31 | // 32 | // try 33 | // { 34 | // return call_next_exception_handler(); 35 | // } 36 | // catch(MyException const & ex) 37 | // { 38 | // throw Rice::Exception(rb_cMyException, "%s", ex.what()); 39 | // } 40 | // 41 | class Exception_Handler 42 | : public Rice::detail::Not_Copyable 43 | { 44 | public: 45 | Exception_Handler( 46 | Data_Object next_exception_handler); 47 | 48 | virtual ~Exception_Handler(); 49 | 50 | virtual VALUE handle_exception() const = 0; 51 | 52 | VALUE call_next_exception_handler() const; 53 | 54 | private: 55 | Data_Object next_exception_handler_; 56 | Address_Registration_Guard next_exception_handler_guard_; 57 | }; 58 | 59 | // The default exception handler just rethrows the exception. If there 60 | // are other handlers in the chain, they will try to handle the rethrown 61 | // exception. 62 | class Default_Exception_Handler 63 | : public Exception_Handler 64 | { 65 | public: 66 | Default_Exception_Handler(); 67 | 68 | virtual VALUE handle_exception() const; 69 | }; 70 | 71 | // An exception handler that takes a functor as an argument. The 72 | // functor should throw a Rice::Exception to handle the exception. If 73 | // the functor does not handle the exception, the exception will be 74 | // re-thrown. 75 | template 76 | class Functor_Exception_Handler 77 | : public Exception_Handler 78 | { 79 | public: 80 | Functor_Exception_Handler( 81 | Functor_T handler, 82 | Data_Object next_exception_handler); 83 | 84 | private: 85 | virtual VALUE handle_exception() const; 86 | 87 | private: 88 | Functor_T handler_; 89 | }; 90 | 91 | } // namespace detail 92 | 93 | } // namespace Rice 94 | 95 | #endif // Rice__detail__Exception_Handler_defn__hpp_ 96 | 97 | -------------------------------------------------------------------------------- /extconf.rb: -------------------------------------------------------------------------------- 1 | # To allow Rice to be installed on non-system installs of Ruby (rbenv or rvm), 2 | # the rice gem uses the extconf version of deployment 3 | # rather than configure. This file will get the appropriate values from CONFIG 4 | # for the Ruby that this library is being installed into and generate 5 | # the proper arguments to ./configure. 6 | # 7 | # With this, installing on any of the Ruby versions installed on a machine is as 8 | # easy as /path/to/the/gem install rice. 9 | 10 | $:.unshift File.expand_path(File.dirname(__FILE__)) 11 | 12 | require 'rbconfig' 13 | require 'ruby/lib/version.rb' 14 | 15 | prefix_dir = File.join(File.dirname(File.expand_path(__FILE__)), "ruby", "lib") 16 | with_ruby = File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["RUBY_INSTALL_NAME"]) 17 | 18 | other_opts = "" 19 | env = "" 20 | 21 | if RbConfig::CONFIG["ENABLE_SHARED"] == "no" 22 | abort <= 10 54 | arch = RbConfig::CONFIG["arch"].split("-")[0] 55 | 56 | if arch == "universal" 57 | arch = `uname -m`.strip 58 | end 59 | 60 | other_opts = "--disable-dependency-tracking" 61 | env = "ARCHFLAGS='-arch #{arch}' CPPFLAGS='-arch #{arch}'" 62 | else 63 | arch = `uname -p`.chomp 64 | env = "ARCHFLAGS='-arch #{arch}' CPPFLAGS='-arch #{arch}'" 65 | end 66 | end 67 | 68 | system "sh bootstrap" 69 | system "#{env} sh configure --with-ruby=#{with_ruby} --prefix=#{prefix_dir} #{other_opts}" 70 | -------------------------------------------------------------------------------- /rice/Struct.cpp: -------------------------------------------------------------------------------- 1 | #include "Struct.hpp" 2 | #include "Symbol.hpp" 3 | 4 | #include 5 | 6 | Rice::Struct:: 7 | Struct() 8 | : Module_impl(rb_cObject) 9 | , members_() 10 | , members_guard_(&members_) 11 | , member_offset_() 12 | , member_offset_guard_(&member_offset_) 13 | { 14 | } 15 | 16 | Rice::Struct:: 17 | Struct(Rice::Struct const & s) 18 | : Module_impl(s) 19 | , members_(s.members_.value()) 20 | , members_guard_(&members_) 21 | , member_offset_(s.member_offset_.value()) 22 | , member_offset_guard_(&member_offset_) 23 | { 24 | } 25 | 26 | Rice::Struct:: 27 | ~Struct() 28 | { 29 | } 30 | 31 | Rice::Struct & Rice::Struct:: 32 | initialize( 33 | Module module, 34 | Identifier name) 35 | { 36 | Class struct_class(rb_cStruct); 37 | Object type = struct_class.vcall("new", members_); 38 | 39 | set_value(type); 40 | module.const_set(name, type); 41 | 42 | return *this; 43 | } 44 | 45 | Rice::Struct & Rice::Struct:: 46 | define_member( 47 | Identifier name) 48 | { 49 | if(value() != rb_cObject) 50 | { 51 | throw std::runtime_error("struct is already initialized"); 52 | } 53 | 54 | // TODO: not exception-safe 55 | Symbol ruby_name(name); 56 | member_offset_[ruby_name] = members_.size(); 57 | members_.push(ruby_name); 58 | 59 | return *this; 60 | } 61 | 62 | size_t Rice::Struct:: 63 | offset_of(Identifier name) const 64 | { 65 | Symbol ruby_name(name); 66 | return from_ruby(member_offset_[ruby_name]); 67 | } 68 | 69 | void Rice::Struct:: 70 | swap(Rice::Struct & other) 71 | { 72 | members_.swap(other.members_); 73 | members_guard_.swap(other.members_guard_); 74 | member_offset_.swap(other.member_offset_); 75 | member_offset_guard_.swap(other.member_offset_guard_); 76 | Class::swap(other); 77 | } 78 | 79 | Rice::Struct::Instance 80 | Rice::Struct:: 81 | new_instance(Array args) const 82 | { 83 | Object instance = const_cast(this)->vcall("new", args); 84 | return Instance(*this, instance); 85 | } 86 | 87 | Rice::Struct::Instance:: 88 | Instance( 89 | Struct const & type, 90 | Array args) 91 | : Builtin_Object(type.new_instance(args)) 92 | , type_(type) 93 | { 94 | } 95 | 96 | Rice::Struct::Instance:: 97 | Instance( 98 | Struct const & type, 99 | Object s) 100 | : Builtin_Object(s) 101 | , type_(type) 102 | { 103 | } 104 | 105 | void Rice::Struct::Instance:: 106 | swap(Instance & other) 107 | { 108 | type_.swap(other.type_); 109 | Builtin_Object::swap(other); 110 | } 111 | 112 | Rice::Struct Rice:: 113 | define_struct() 114 | { 115 | return Struct(); 116 | } 117 | 118 | -------------------------------------------------------------------------------- /rice/detail/method_data.cpp: -------------------------------------------------------------------------------- 1 | #include "method_data.hpp" 2 | #include "ruby.hpp" 3 | 4 | // TODO: This is silly, autoconf... 5 | #undef PACKAGE_NAME 6 | #undef PACKAGE_STRING 7 | #undef PACKAGE_TARNAME 8 | #undef PACKAGE_VERSION 9 | #include "../config.hpp" 10 | 11 | #define RICE_ID rb_intern("__rice__") 12 | 13 | VALUE 14 | Rice::detail:: 15 | method_data() 16 | { 17 | ID id; 18 | VALUE klass; 19 | if (!rb_frame_method_id_and_class(&id, &klass)) 20 | { 21 | rb_raise( 22 | rb_eRuntimeError, 23 | "Cannot get method id and class for function"); 24 | } 25 | 26 | if (rb_type(klass) == T_ICLASS) { 27 | klass = rb_class_of(klass); 28 | } 29 | 30 | VALUE store = rb_ivar_get(klass, RICE_ID); 31 | return (store == Qnil) ? Qnil : rb_ivar_get(store, id); 32 | } 33 | 34 | 35 | // Define a method and attach data to it. 36 | // The method looks to ruby like a normal aliased CFUNC, with a modified 37 | // origin class. 38 | // 39 | // How this works: 40 | // 41 | // To store method data and have it registered with the GC, we need a 42 | // "slot" to put it in. This "slot" must be recognized and marked by 43 | // the garbage collector. There happens to be such a place we can put 44 | // data, and it has to do with aliased methods. When Ruby creates an 45 | // alias for a method, it stores a reference to the original class in 46 | // the method entry. The form of the method entry differs from ruby 47 | // version to ruby version, but the concept is the same across all of 48 | // them. 49 | // 50 | // In Rice, we make use of this by attach the data to a dummy object 51 | // (store) in the class variables table. 52 | // 53 | // When Ruby makes a method call, it stores the class Object and method 54 | // ID in the current stack frame. When Ruby calls into Rice, we grab 55 | // the class and method ID from the stack frame, then pull the data out 56 | // of the class. The data item is then used to determine how to convert 57 | // arguments and return type, how to handle exceptions, etc. 58 | // 59 | VALUE 60 | Rice::detail:: 61 | define_method_with_data( 62 | VALUE klass, ID id, VALUE (*cfunc)(ANYARGS), int arity, VALUE data) 63 | { 64 | VALUE store = rb_attr_get(klass, RICE_ID); 65 | 66 | if (store == Qnil) { 67 | store = rb_obj_alloc(rb_cObject); 68 | // store is stored in the instance variables table with 69 | // name "__rice__". 70 | // since "__rice__" does not have the @ prefix, 71 | // so it can never be read at the Ruby level. 72 | rb_ivar_set(klass, RICE_ID, store); 73 | } 74 | 75 | rb_ivar_set(store, id, data); 76 | 77 | // Create the aliased method on the origin class 78 | rb_define_method( 79 | klass, 80 | rb_id2name(id), 81 | cfunc, 82 | arity); 83 | 84 | return Qnil; 85 | } 86 | 87 | -------------------------------------------------------------------------------- /rice.gemspec: -------------------------------------------------------------------------------- 1 | $:.unshift File.expand_path(File.dirname(__FILE__)) 2 | require 'ruby/lib/version' 3 | 4 | $spec = Gem::Specification.new do |s| 5 | s.name = 'rice' 6 | s.version = Rice::VERSION 7 | s.license = "MIT" 8 | s.summary = 'Ruby Interface for C++ Extensions' 9 | s.homepage = 'https://github.com/jasonroelofs/rice' 10 | s.authors = ['Paul Brannan', 'Jason Roelofs'] 11 | s.email = ['curlypaul924@gmail.com', 'jasonroelofs@gmail.com'] 12 | 13 | s.description = <<-END 14 | Rice is a C++ interface to Ruby's C API. It provides a type-safe and 15 | exception-safe interface in order to make embedding Ruby and writing 16 | Ruby extensions with C++ easier. It is similar to Boost.Python in many 17 | ways, but also attempts to provide an object-oriented interface to all 18 | of the Ruby C API. 19 | END 20 | 21 | s.extensions = ['extconf.rb'] 22 | 23 | s.test_files = [ 24 | 'test/test_rice.rb', 25 | ] 26 | 27 | s.extra_rdoc_files = [ 'README.md' ] 28 | 29 | s.require_paths = [ 'ruby/lib' ] 30 | 31 | patterns = [ 32 | # Documentation 33 | 'COPYING', 34 | 'README', 35 | 'README.mingw', 36 | 37 | # Doxygen 38 | 'Doxyfile', 39 | 'doxygen.ac', 40 | 'doxygen.am', 41 | 42 | 'extconf.rb', 43 | 44 | # Autoconf 45 | 'bootstrap', 46 | 'check_stdcxx_11.ac', 47 | 'configure.ac', 48 | 'configure', 49 | 'config.guess', 50 | 'config.sub', 51 | 'depcomp', 52 | 'doxygen.ac', 53 | 'doxygen.am', 54 | 'install-sh', 55 | 'missing', 56 | 'post-autoconf.rb', 57 | 'post-automake.rb', 58 | 'ruby.ac', 59 | 'aclocal.m4', 60 | 61 | # Makefiles 62 | 'Rakefile', 63 | 'Makefile.am', 64 | 'Makefile.in', 65 | 'rice/Makefile.am', 66 | 'rice/Makefile.in', 67 | 'ruby/Makefile.am', 68 | 'ruby/Makefile.in', 69 | 'ruby/lib/Makefile.am', 70 | 'ruby/lib/Makefile.in', 71 | 'sample/Makefile.am', 72 | 'sample/Makefile.in', 73 | 'test/Makefile.am', 74 | 'test/Makefile.in', 75 | 76 | # C++ source files 77 | 'rice/*.?pp', 78 | 'rice/*.rb', 79 | 'rice/config.hpp.in', 80 | 'rice/detail/*.?pp', 81 | 'rice/detail/ruby_version_code.hpp.in', 82 | 83 | # Library files 84 | 'ruby/lib/mkmf-rice.rb.in', 85 | 'ruby/lib/version.rb', 86 | 87 | # Samples 88 | 'sample/enum/extconf.rb', 89 | 'sample/enum/*.?pp', 90 | 'sample/enum/*.rb', 91 | 'sample/map/extconf.rb', 92 | 'sample/map/*.?pp', 93 | 'sample/map/*.rb', 94 | 'sample/inheritance/extconf.rb', 95 | 'sample/inheritance/*.?pp', 96 | 'sample/inheritance/*.rb', 97 | 98 | # Test source files 99 | 'test/*.?pp', 100 | 'test/ext/Makefile.am', 101 | 'test/ext/Makefile.in', 102 | 'test/ext/t1/extconf.rb', 103 | 'test/ext/t1/*.*pp', 104 | 'test/ext/t2/extconf.rb', 105 | 'test/ext/t2/*.*pp' 106 | ] 107 | 108 | s.files = patterns.collect { |p| Dir.glob(p) }.flatten 109 | end 110 | -------------------------------------------------------------------------------- /rice/ruby_try_catch.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__ruby_try_catch__hpp_ 2 | #define Rice__ruby_try_catch__hpp_ 3 | 4 | #include "Exception_Base_defn.hpp" 5 | #include "Jump_Tag.hpp" 6 | #include "detail/ruby.hpp" 7 | #include 8 | 9 | /*! \def RUBY_TRY 10 | * \brief Start a block to catch Ruby exceptions and rethrow them. 11 | */ 12 | // Goto is used here to avoid having to use a second try/catch block (we 13 | // can't rb_exc_raise directly out of the catch blocks below, since the 14 | // exceptions will not get properly cleaned up). 15 | // The labels are located before the try and not after it so the function can't 16 | // "fall through" into the exception-handling code accidentally. 17 | #define RUBY_TRY \ 18 | VALUE Rice__ruby_exc = Qnil; \ 19 | int Rice__ruby_jump_tag = 0; \ 20 | \ 21 | goto start_of_RUBY_TRY; \ 22 | \ 23 | Rice__ruby_exception: \ 24 | rb_exc_raise(Rice__ruby_exc); \ 25 | Rice__ruby_jump_tag: \ 26 | rb_jump_tag(Rice__ruby_jump_tag); \ 27 | \ 28 | start_of_RUBY_TRY: \ 29 | try 30 | 31 | /*! \def RUBY_RETHROW(ex) 32 | * \brief Given a Ruby exception as a VALUE, safely raise the exception as a 33 | * Ruby exception. This should be used inside a RUBY_TRY/RUBY_CATCH 34 | * block. 35 | */ 36 | #define RUBY_RETHROW(ex) \ 37 | Rice__ruby_exc = ex; \ 38 | goto Rice__ruby_exception; 39 | 40 | /*! \def RUBY_CATCH 41 | * \brief End a RUBY_TRY block. 42 | */ 43 | #define RUBY_CATCH \ 44 | catch(::Rice::Exception_Base const & ex) \ 45 | { \ 46 | RUBY_RETHROW(ex.value()); \ 47 | } \ 48 | catch(::Rice::Jump_Tag const & ex) \ 49 | { \ 50 | Rice__ruby_jump_tag = ex.tag; \ 51 | goto Rice__ruby_jump_tag; \ 52 | } \ 53 | catch(std::bad_alloc const & ex) \ 54 | { \ 55 | /* This won't work quite right if the rb_exc_new2 fails; not */ \ 56 | /* much we can do about that, since Ruby doesn't give us access */ \ 57 | /* to a pre-allocated NoMemoryError object */ \ 58 | RUBY_RETHROW(rb_exc_new2(rb_eNoMemError, ex.what())); \ 59 | } \ 60 | catch(std::invalid_argument const & ex) \ 61 | { \ 62 | /* This can raise a NoMemoryError in VERY rare circumstances */ \ 63 | RUBY_RETHROW(rb_exc_new2(rb_eArgError, ex.what())); \ 64 | } \ 65 | catch(std::domain_error const & ex) \ 66 | { \ 67 | /* This can raise a NoMemoryError in VERY rare circumstances */ \ 68 | RUBY_RETHROW(rb_exc_new2(rb_eFloatDomainError, ex.what())); \ 69 | } \ 70 | catch(std::out_of_range const & ex) \ 71 | { \ 72 | /* This can raise a NoMemoryError in VERY rare circumstances */ \ 73 | RUBY_RETHROW(rb_exc_new2(rb_eRangeError, ex.what())); \ 74 | } \ 75 | catch(std::exception const & ex) \ 76 | { \ 77 | /* This can raise a NoMemoryError in VERY rare circumstances */ \ 78 | RUBY_RETHROW(rb_exc_new2(rb_eRuntimeError, ex.what())); \ 79 | } \ 80 | catch(...) \ 81 | { \ 82 | RUBY_RETHROW(rb_exc_new2(rb_eRuntimeError, "unknown C++ exception thrown")); \ 83 | } \ 84 | 85 | #endif // Rice__ruby_try_catch__hpp_ 86 | 87 | -------------------------------------------------------------------------------- /rice/detail/Arguments.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Arguments__hpp_ 2 | #define Rice__Arguments__hpp_ 3 | 4 | #include "../Arg_impl.hpp" 5 | #include 6 | #include 7 | #include "../to_from_ruby_defn.hpp" 8 | 9 | namespace Rice { 10 | 11 | class Arguments 12 | { 13 | public: 14 | Arguments() { 15 | required_ = 0; 16 | optional_ = 0; 17 | } 18 | 19 | ~Arguments() { 20 | } 21 | 22 | /** 23 | * Get the full argument count of this 24 | * list of arguments. 25 | * Returns -1 no defined arguments 26 | */ 27 | int count() { 28 | if(required_ == 0 && optional_ == 0) { 29 | return -1; 30 | } else { 31 | return required_ + optional_; 32 | } 33 | } 34 | 35 | /** 36 | * Get the rb_scan_args format string for this 37 | * list of arguments. 38 | * In the case of no Args (default case), this 39 | * method uses the passed in full argument count 40 | */ 41 | std::string formatString(int fullArgCount) 42 | { 43 | std::stringstream s; 44 | if(required_ == 0 && optional_ == 0) 45 | { 46 | s << fullArgCount << 0; 47 | } 48 | else 49 | { 50 | s << required_ << optional_; 51 | } 52 | 53 | return s.str(); 54 | } 55 | 56 | /** 57 | * Add a defined Arg to this list of Arguments 58 | */ 59 | void add(const Arg& arg) 60 | { 61 | args_.push_back(arg); 62 | 63 | if(arg.hasDefaultValue()) 64 | { 65 | optional_++; 66 | } 67 | else 68 | { 69 | required_++; 70 | } 71 | } 72 | 73 | /** 74 | * Is the argument at the request location an optional 75 | * argument? 76 | */ 77 | bool isOptional(unsigned int pos) 78 | { 79 | if(required_ == 0 && optional_ == 0) 80 | { 81 | return false; 82 | } 83 | if(pos >= args_.size()) 84 | { 85 | return false; 86 | } 87 | return args_[pos].hasDefaultValue(); 88 | } 89 | 90 | /** 91 | * Given a position, a type, and a ruby VALUE, figure out 92 | * what argument value we need to return according to 93 | * defaults and if that VALUE is nil or not 94 | */ 95 | template 96 | Arg_T getArgumentOrDefault(int pos, VALUE in) 97 | { 98 | if(isOptional(pos) && NIL_P(in)) 99 | { 100 | return args_[pos].getDefaultValue(); 101 | } 102 | else 103 | { 104 | return from_ruby(in); 105 | } 106 | } 107 | 108 | private: 109 | std::vector args_; 110 | 111 | /** Keep counts of required and optional parameters */ 112 | int required_; 113 | int optional_; 114 | }; 115 | 116 | } 117 | 118 | #endif // Rice__Arguments__hpp_ 119 | -------------------------------------------------------------------------------- /rice/Makefile.am: -------------------------------------------------------------------------------- 1 | lib_LIBRARIES = librice.a 2 | 3 | librice_a_SOURCES = \ 4 | Class.cpp \ 5 | Data_Type.cpp \ 6 | Director.cpp \ 7 | Exception.cpp \ 8 | Identifier.cpp \ 9 | Module.cpp \ 10 | Object.cpp \ 11 | String.cpp \ 12 | Struct.cpp \ 13 | Symbol.cpp \ 14 | Arg_operators.cpp \ 15 | Address_Registration_Guard.cpp \ 16 | detail/check_ruby_type.cpp \ 17 | detail/demangle.cpp \ 18 | detail/method_data.cpp \ 19 | detail/protect.cpp 20 | 21 | nobase_include_HEADERS = \ 22 | Address_Registration_Guard.hpp \ 23 | Address_Registration_Guard.ipp \ 24 | Address_Registration_Guard_defn.hpp \ 25 | Array.hpp \ 26 | Array.ipp \ 27 | Arg.hpp \ 28 | Arg_impl.hpp \ 29 | Arg_operators.hpp \ 30 | Builtin_Object.hpp \ 31 | Builtin_Object.ipp \ 32 | Builtin_Object_defn.hpp \ 33 | Class.hpp \ 34 | Class.ipp \ 35 | Class_defn.hpp \ 36 | Constructor.hpp \ 37 | Data_Object.hpp \ 38 | Data_Object.ipp \ 39 | Data_Object_defn.hpp \ 40 | Data_Type.hpp \ 41 | Data_Type.ipp \ 42 | Data_Type_defn.hpp \ 43 | Data_Type_fwd.hpp \ 44 | Director.hpp \ 45 | Enum.hpp \ 46 | Enum.ipp \ 47 | Exception.hpp \ 48 | Exception_defn.hpp \ 49 | Exception_Base.hpp \ 50 | Exception_Base.ipp \ 51 | Exception_Base_defn.hpp \ 52 | Hash.hpp \ 53 | Hash.ipp \ 54 | Identifier.hpp \ 55 | Identifier.ipp \ 56 | Jump_Tag.hpp \ 57 | Makefile \ 58 | Module.hpp \ 59 | Module.ipp \ 60 | Module_defn.hpp \ 61 | Module_impl.hpp \ 62 | Module_impl.ipp \ 63 | Object.hpp \ 64 | Object.ipp \ 65 | Object_defn.hpp \ 66 | Require_Guard.hpp \ 67 | String.hpp \ 68 | Struct.hpp \ 69 | Struct.ipp \ 70 | Symbol.hpp \ 71 | Symbol.ipp \ 72 | global_function.hpp \ 73 | global_function.ipp \ 74 | protect.hpp \ 75 | protect.ipp \ 76 | ruby_try_catch.hpp \ 77 | to_from_ruby.hpp \ 78 | to_from_ruby.ipp \ 79 | to_from_ruby_defn.hpp \ 80 | ruby_mark.hpp \ 81 | detail/Auto_Function_Wrapper.hpp \ 82 | detail/Auto_Function_Wrapper.ipp \ 83 | detail/Auto_Member_Function_Wrapper.hpp \ 84 | detail/Auto_Member_Function_Wrapper.ipp \ 85 | detail/Arguments.hpp \ 86 | detail/Caster.hpp \ 87 | detail/Exception_Handler.hpp \ 88 | detail/Exception_Handler.ipp \ 89 | detail/Exception_Handler_defn.hpp \ 90 | detail/Iterator.hpp \ 91 | detail/Not_Copyable.hpp \ 92 | detail/Wrapped_Function.hpp \ 93 | detail/check_ruby_type.hpp \ 94 | detail/creation_funcs.hpp \ 95 | detail/creation_funcs.ipp \ 96 | detail/default_allocation_func.hpp \ 97 | detail/default_allocation_func.ipp \ 98 | detail/define_method_and_auto_wrap.hpp \ 99 | detail/define_method_and_auto_wrap.ipp \ 100 | detail/demangle.hpp \ 101 | detail/env.hpp \ 102 | detail/from_ruby.hpp \ 103 | detail/from_ruby.ipp \ 104 | detail/method_data.hpp \ 105 | detail/node.hpp \ 106 | detail/object_call.hpp \ 107 | detail/object_call.ipp \ 108 | detail/protect.hpp \ 109 | detail/ruby.hpp \ 110 | detail/st.hpp \ 111 | detail/traits.hpp \ 112 | detail/to_ruby.hpp \ 113 | detail/to_ruby.ipp \ 114 | detail/win32.hpp \ 115 | detail/wrap_function.hpp \ 116 | detail/wrap_function.ipp \ 117 | detail/ruby_version_code.hpp 118 | 119 | includedir = ${prefix}/include/rice 120 | 121 | AM_CPPFLAGS = @RUBY_CPPFLAGS@ 122 | 123 | AM_CXXFLAGS = @RUBY_CXXFLAGS@ 124 | 125 | -------------------------------------------------------------------------------- /test/test_global_functions.cpp: -------------------------------------------------------------------------------- 1 | #include "unittest.hpp" 2 | #include "rice/global_function.hpp" 3 | 4 | using namespace Rice; 5 | 6 | TESTSUITE(GlobalFunction); 7 | 8 | SETUP(GlobalFunction) 9 | { 10 | ruby_init(); 11 | } 12 | 13 | namespace { 14 | 15 | bool method_to_wrap_called = false; 16 | void method_to_wrap(Object self) { 17 | method_to_wrap_called = true; 18 | } 19 | 20 | int method_with_args_arg0; 21 | 22 | void method_with_args(Object self, int arg) { 23 | method_with_args_arg0 = arg; 24 | } 25 | 26 | } 27 | 28 | TESTCASE(exposes_global_functions) 29 | { 30 | define_global_function("method_to_wrap", &method_to_wrap); 31 | Module m = Module(rb_mKernel); 32 | m.call("method_to_wrap"); 33 | 34 | ASSERT(method_to_wrap_called); 35 | } 36 | 37 | TESTCASE(exposes_global_functions_with_arguments) 38 | { 39 | define_global_function("method_with_args", &method_with_args); 40 | Module m = Module(rb_mKernel); 41 | m.call("method_with_args", 10); 42 | 43 | ASSERT_EQUAL(10, method_with_args_arg0); 44 | } 45 | 46 | namespace 47 | { 48 | int defaults_method_one_arg1; 49 | int defaults_method_one_arg2; 50 | bool defaults_method_one_arg3 = false; 51 | 52 | void defaults_method_one(int arg1, int arg2 = 3, bool arg3 = true) 53 | { 54 | defaults_method_one_arg1 = arg1; 55 | defaults_method_one_arg2 = arg2; 56 | defaults_method_one_arg3 = arg3; 57 | } 58 | 59 | int defaults_returns(int arg1, int arg2 = 3) 60 | { 61 | return arg1 * arg2; 62 | } 63 | } 64 | 65 | TESTCASE(default_arguments_for_define_global_function) 66 | { 67 | define_global_function("foo", &defaults_method_one, (Arg("arg1"), Arg("arg2") = (int)3, Arg("arg3") = (bool)true)); 68 | Module m(rb_mKernel); 69 | 70 | m.call("foo", 2); 71 | 72 | ASSERT_EQUAL(2, defaults_method_one_arg1); 73 | ASSERT_EQUAL(3, defaults_method_one_arg2); 74 | ASSERT(defaults_method_one_arg3); 75 | 76 | m.call("foo", 11, 10); 77 | 78 | ASSERT_EQUAL(11, defaults_method_one_arg1); 79 | ASSERT_EQUAL(10, defaults_method_one_arg2); 80 | ASSERT(defaults_method_one_arg3); 81 | 82 | m.call("foo", 22, 33, false); 83 | 84 | ASSERT_EQUAL(22, defaults_method_one_arg1); 85 | ASSERT_EQUAL(33, defaults_method_one_arg2); 86 | ASSERT(!defaults_method_one_arg3); 87 | } 88 | 89 | TESTCASE(default_arguments_for_define_global_function_and_returning) 90 | { 91 | define_global_function("foo_ret", &defaults_returns, (Arg("arg1"), Arg("arg2") = (int)3)); 92 | Module m(rb_mKernel); 93 | 94 | Object o = m.call("foo_ret", 2); 95 | ASSERT_EQUAL(INT2NUM(6), o.value()); 96 | 97 | o = m.call("foo_ret", 5, 10); 98 | ASSERT_EQUAL(INT2NUM(50), o.value()); 99 | } 100 | 101 | namespace { 102 | int the_one_default_arg = 0; 103 | void method_with_one_default_arg(int num = 4) { 104 | the_one_default_arg = num; 105 | } 106 | } 107 | 108 | TESTCASE(single_default_argument) 109 | { 110 | define_global_function("foo", &method_with_one_default_arg, (Arg("num") = (int)4)); 111 | Module m(rb_mKernel); 112 | m.call("foo"); 113 | ASSERT_EQUAL(4, the_one_default_arg); 114 | } 115 | -------------------------------------------------------------------------------- /test/test_Constructor.cpp: -------------------------------------------------------------------------------- 1 | #include "unittest.hpp" 2 | #include "rice/Constructor.hpp" 3 | #include "rice/Data_Type.hpp" 4 | 5 | #include "rice/detail/env.hpp" 6 | 7 | #include 8 | using namespace std; 9 | 10 | using namespace Rice; 11 | 12 | TESTSUITE(Constructor); 13 | 14 | namespace 15 | { 16 | class Default_Constructible 17 | { 18 | public: 19 | Default_Constructible() 20 | { 21 | } 22 | }; 23 | } 24 | 25 | TESTCASE(default_constructor) 26 | { 27 | Data_Type rb_cDefault_Constructible( 28 | anonymous_class()); 29 | rb_cDefault_Constructible 30 | .define_constructor(Constructor()); 31 | Object o = rb_cDefault_Constructible.call("new"); 32 | ASSERT_EQUAL(rb_cDefault_Constructible, o.class_of()); 33 | } 34 | 35 | 36 | namespace 37 | { 38 | class Non_Default_Constructible 39 | { 40 | public: 41 | Non_Default_Constructible(int i) 42 | : i_(i) 43 | { 44 | } 45 | 46 | int i() const 47 | { 48 | return i_; 49 | } 50 | 51 | private: 52 | int i_; 53 | }; 54 | } 55 | 56 | TESTCASE(non_default_constructor) 57 | { 58 | Data_Type rb_cNon_Default_Constructible( 59 | anonymous_class()); 60 | rb_cNon_Default_Constructible 61 | .define_constructor(Constructor()); 62 | Data_Object o = 63 | rb_cNon_Default_Constructible.call("new", 42); 64 | ASSERT_EQUAL(rb_cNon_Default_Constructible, o.class_of()); 65 | ASSERT_EQUAL(42, o->i()); 66 | } 67 | 68 | namespace 69 | { 70 | int withArgsX; 71 | float withArgsY; 72 | bool withArgsYes; 73 | 74 | class WithDefaultArgs 75 | { 76 | public: 77 | WithDefaultArgs(int x, float y = 2.0, bool yes = false) 78 | { 79 | withArgsX = x; 80 | withArgsY = y; 81 | withArgsYes = yes; 82 | } 83 | }; 84 | 85 | int withArgX; 86 | class WithOneArg 87 | { 88 | public: 89 | WithOneArg(int x = 14) { 90 | withArgX = x; 91 | } 92 | }; 93 | } 94 | 95 | TESTCASE(constructor_supports_default_arguments) 96 | { 97 | Class klass = define_class("WithDefaultArgs"). 98 | define_constructor(Constructor(), 99 | ( Arg("x"), Arg("y") = (float)2.0, Arg("yes") = (bool)false )); 100 | 101 | klass.call("new", 4); 102 | ASSERT_EQUAL(4, withArgsX); 103 | ASSERT_EQUAL(2.0, withArgsY); 104 | ASSERT_EQUAL(false, withArgsYes); 105 | 106 | klass.call("new", 5, 3.0); 107 | ASSERT_EQUAL(5, withArgsX); 108 | ASSERT_EQUAL(3.0, withArgsY); 109 | ASSERT_EQUAL(false, withArgsYes); 110 | 111 | klass.call("new", 7, 12.0, true); 112 | ASSERT_EQUAL(7, withArgsX); 113 | ASSERT_EQUAL(12.0, withArgsY); 114 | ASSERT_EQUAL(true, withArgsYes); 115 | } 116 | 117 | TESTCASE(constructor_supports_single_default_argument) 118 | { 119 | Class klass = define_class("WithOneArg"). 120 | define_constructor(Constructor(), 121 | ( Arg("x") = 14 )); 122 | 123 | klass.call("new"); 124 | ASSERT_EQUAL(14, withArgX); 125 | 126 | klass.call("new", 6); 127 | ASSERT_EQUAL(6, withArgX); 128 | } 129 | -------------------------------------------------------------------------------- /rice/Enum.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Enum__hpp_ 2 | #define Rice__Enum__hpp_ 3 | 4 | #include "to_from_ruby_defn.hpp" 5 | #include "Address_Registration_Guard.hpp" 6 | #include "Array.hpp" 7 | #include "Hash.hpp" 8 | #include "String.hpp" 9 | #include "Module.hpp" 10 | #include "Data_Type.hpp" 11 | 12 | namespace Rice 13 | { 14 | 15 | //! Default traits for the Enum class template. 16 | template 17 | struct Default_Enum_Traits 18 | { 19 | //! Converts the enum value to a long. 20 | static long as_long(Enum_T value); 21 | }; 22 | 23 | /*! 24 | * \example enum/sample_enum.cpp 25 | */ 26 | 27 | //! A wrapper for enumerated types. 28 | /*! Provides a simple type-safe wrapper for enumerated types. At the 29 | * ruby level, the class will have convenience methods for iterating 30 | * over all the defined enum values, converting the values to strings, 31 | * and more. 32 | * 33 | * \param Enum_T the enumerated type 34 | * \param Enum_Traits specifies the traits of the enumerated type. 35 | * 36 | * Example: 37 | * \code 38 | * enum Color { Red, Green, Blue }; 39 | * Enum rb_cColor = define_enum("Color") 40 | * .define_value("Red", Red) 41 | * .define_value("Green", Green) 42 | * .define_value("Blue", Blue); 43 | * \endcode 44 | */ 45 | template > 46 | class Enum 47 | : public Module_impl, Enum > 48 | { 49 | public: 50 | //! Default constructor. 51 | Enum(); 52 | 53 | //! Construct and initialize. 54 | Enum( 55 | char const * name, 56 | Module module = rb_cObject); 57 | 58 | //! Copy constructor. 59 | Enum(Enum const & other); 60 | 61 | //! Assignment operator. 62 | Enum & operator=(Enum const & other); 63 | 64 | //! Destructor. 65 | virtual ~Enum(); 66 | 67 | //! Define a new enum value. 68 | /*! \param name the name of the enum value. 69 | * \param value the value to associate with name. 70 | * \return *this 71 | */ 72 | Enum & define_value( 73 | char const * name, 74 | Enum_T value); 75 | 76 | void swap(Enum & other); 77 | 78 | private: 79 | //! Initialize the enum type. 80 | /*! Must be called only once. 81 | * \param name the name of the class to define 82 | * \param module the module in which to place the enum class. 83 | * \return *this 84 | */ 85 | Enum & initialize( 86 | char const * name, 87 | Module module = rb_cObject); 88 | 89 | private: 90 | static Object each(Object self); 91 | static Object to_s(Object self); 92 | static Object to_i(Object self); 93 | static Object inspect(Object self); 94 | static Object compare(Object lhs, Object rhs); 95 | static Object eql(Object lhs, Object rhs); 96 | static Object hash(Object self); 97 | static Object from_int(Class klass, Object i); 98 | 99 | private: 100 | Array enums_; 101 | Address_Registration_Guard enums_guard_; 102 | 103 | Hash names_; 104 | Address_Registration_Guard names_guard_; 105 | }; 106 | 107 | template 108 | Enum define_enum( 109 | char const * name, 110 | Module module = rb_cObject); 111 | 112 | } // namespace Rice 113 | 114 | #include "Enum.ipp" 115 | 116 | #endif // Rice__Enum__hpp_ 117 | 118 | -------------------------------------------------------------------------------- /rice/Data_Object.ipp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Data_Object__ipp_ 2 | #define Rice__Data_Object__ipp_ 3 | 4 | #include "detail/check_ruby_type.hpp" 5 | #include "protect.hpp" 6 | 7 | #include 8 | 9 | template 10 | const typename Rice::Default_Mark_Function::Ruby_Data_Func 11 | Rice::Default_Mark_Function::mark = ruby_mark; 12 | 13 | namespace Rice 14 | { 15 | 16 | namespace detail 17 | { 18 | 19 | inline VALUE data_wrap_struct( 20 | VALUE klass, 21 | RUBY_DATA_FUNC mark, 22 | RUBY_DATA_FUNC free, 23 | void * obj) 24 | { 25 | return Data_Wrap_Struct(klass, mark, free, obj); 26 | } 27 | 28 | template 29 | inline VALUE wrap( 30 | VALUE klass, 31 | typename Data_Object::Ruby_Data_Func mark, 32 | typename Data_Object::Ruby_Data_Func free, 33 | T * obj) 34 | { 35 | // We cast to obj void* here before passing to Data_Wrap_Struct, 36 | // becuase otherwise compilation will fail if obj is const. It's safe 37 | // to do this, because unwrap() will always add the const back when 38 | // the object is unwrapped. 39 | return Rice::protect(data_wrap_struct, 40 | klass, 41 | reinterpret_cast(mark), 42 | reinterpret_cast(free), 43 | (void *)obj); 44 | } 45 | 46 | template 47 | inline VALUE data_get_struct(VALUE value, T * * obj) 48 | { 49 | Data_Get_Struct(value, T, *obj); 50 | return Qnil; 51 | } 52 | 53 | template 54 | inline T * unwrap(VALUE value) 55 | { 56 | T * obj; 57 | Rice::protect(data_get_struct, value, &obj); 58 | return obj; 59 | } 60 | 61 | } // namespace detail 62 | 63 | } // namespace Rice 64 | 65 | template 66 | inline Rice::Data_Object:: 67 | Data_Object( 68 | T * obj, 69 | VALUE klass, 70 | Ruby_Data_Func mark_func, 71 | Ruby_Data_Func free_func) 72 | : Object(detail::wrap(klass, mark_func, free_func, obj)) 73 | , obj_(obj) 74 | { 75 | } 76 | 77 | template 78 | inline Rice::Data_Object:: 79 | Data_Object( 80 | Object value) 81 | : Object(value) 82 | , obj_(detail::unwrap(value)) 83 | { 84 | Data_Type klass; 85 | check_cpp_type(klass); 86 | detail::check_ruby_type(value, klass, true); 87 | } 88 | 89 | template 90 | template 91 | inline Rice::Data_Object:: 92 | Data_Object( 93 | Object value, 94 | Data_Type const & klass) 95 | : Object(value) 96 | , obj_(detail::unwrap(value)) 97 | { 98 | check_cpp_type(klass); 99 | detail::check_ruby_type(value, klass, true); 100 | } 101 | 102 | template 103 | inline Rice::Data_Object:: 104 | Data_Object(Data_Object const & other) 105 | : Object(other.value()) 106 | , obj_(other.obj_) 107 | { 108 | } 109 | 110 | template 111 | template 112 | inline void Rice::Data_Object:: 113 | swap(Data_Object & ref) 114 | { 115 | std::swap(obj_, ref.obj_); 116 | Object::swap(ref); 117 | } 118 | 119 | template 120 | inline void Rice::Data_Object:: 121 | check_cpp_type(Data_Type const & /* klass */) 122 | { 123 | } 124 | 125 | template 126 | Rice::Object Rice::detail::to_ruby_ >:: 127 | convert(Rice::Data_Object const & x) 128 | { 129 | return x; 130 | } 131 | 132 | #endif // Rice__Data_Object__ipp_ 133 | 134 | -------------------------------------------------------------------------------- /rice/detail/Auto_Function_Wrapper.hpp.mustache: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__Auto_Function_Wrapper__hpp_ 2 | #define Rice__detail__Auto_Function_Wrapper__hpp_ 3 | 4 | // This is a generated file. DO NOT EDIT!! 5 | 6 | 7 | // This causes problems with certain C++ libraries 8 | #undef TYPE 9 | 10 | #include "Exception_Handler_defn.hpp" 11 | 12 | namespace Rice 13 | { 14 | 15 | namespace detail 16 | { 17 | 18 | #ifdef DOXYGEN 19 | 20 | #else 21 | 22 | {{#reverse_entries}} 23 | template 24 | class Auto_Function_Wrapper{{{specs_with_return}}} 25 | : public Wrapped_Function 26 | { 27 | public: 28 | typedef Func_T Func; 29 | 30 | static const int Num_Args = {{num_args}}; 31 | 32 | Auto_Function_Wrapper( 33 | Func func, 34 | Data_Object handler, 35 | Arguments* arguments = 0); 36 | 37 | ~Auto_Function_Wrapper(); 38 | 39 | static VALUE call(int argc, VALUE* args, VALUE self); 40 | 41 | private: 42 | Func func_; 43 | Data_Object handler_; 44 | Address_Registration_Guard handler_guard_; 45 | Arguments* arguments_; 46 | }; 47 | 48 | template 49 | class Auto_Function_Wrapper{{{specs}}} 50 | : public Wrapped_Function 51 | { 52 | public: 53 | typedef Func_T Func; 54 | 55 | static const int Num_Args = {{num_args}}; 56 | 57 | Auto_Function_Wrapper( 58 | Func func, 59 | Data_Object handler, 60 | Arguments* arguments = 0); 61 | 62 | ~Auto_Function_Wrapper(); 63 | 64 | static VALUE call(int argc, VALUE* args, VALUE self); 65 | 66 | private: 67 | Func func_; 68 | Data_Object handler_; 69 | Address_Registration_Guard handler_guard_; 70 | Arguments* arguments_; 71 | }; 72 | 73 | // --------------------------------------------------------------------- 74 | {{/reverse_entries}} 75 | 76 | template 77 | class Auto_Function_Wrapper 78 | : public Wrapped_Function 79 | { 80 | public: 81 | // typedef void (*Func)(); 82 | typedef Func_T Func; 83 | 84 | static const int Num_Args = 0; 85 | 86 | Auto_Function_Wrapper( 87 | Func func, 88 | Data_Object handler, 89 | Arguments* arguments = new Arguments()); 90 | 91 | ~Auto_Function_Wrapper(); 92 | 93 | static VALUE call(); 94 | 95 | private: 96 | Func func_; 97 | Data_Object handler_; 98 | Arguments* arguments_; 99 | }; 100 | 101 | template 102 | class Auto_Function_Wrapper 103 | : public Wrapped_Function 104 | { 105 | public: 106 | // typedef void (*Func)(); 107 | typedef Func_T Func; 108 | 109 | static const int Num_Args = 0; 110 | 111 | Auto_Function_Wrapper( 112 | Func func, 113 | Data_Object handler, 114 | Arguments* arguments = new Arguments()); 115 | 116 | ~Auto_Function_Wrapper(); 117 | 118 | static VALUE call(); 119 | 120 | private: 121 | Func func_; 122 | Data_Object handler_; 123 | Arguments* arguments_; 124 | }; 125 | 126 | #endif // DOXYGEN 127 | 128 | } // namespace detail 129 | 130 | } // namespace Rice 131 | 132 | #include "Auto_Function_Wrapper.ipp" 133 | 134 | #endif // Rice__detail__Auto_Function_Wrapper__hpp_ 135 | 136 | -------------------------------------------------------------------------------- /test/unittest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "unittest.hpp" 4 | 5 | size_t assertions; 6 | 7 | namespace 8 | { 9 | 10 | typedef std::map Test_Suites; 11 | Test_Suite * last_test_suite; 12 | 13 | Test_Suites & test_suites() 14 | { 15 | static Test_Suites test_suites; 16 | return test_suites; 17 | } 18 | 19 | } // namespace 20 | 21 | Test_Suite & test_suite() 22 | { 23 | return *last_test_suite; 24 | } 25 | 26 | void new_test_suite(std::string const & name) 27 | { 28 | test_suites()[name] = Test_Suite(name); 29 | last_test_suite = &test_suites()[name]; 30 | } 31 | 32 | std::ostream & operator<<(std::ostream & out, Failure const & failure) 33 | { 34 | out << "" << failure.test_suite_name_ << ":" << failure.test_case_name_ << ": " << failure.what_; 35 | return out; 36 | } 37 | 38 | Test_Suite:: 39 | Test_Suite(std::string const & name) 40 | : name_(name) 41 | , setup_(0) 42 | , teardown_(0) 43 | { 44 | } 45 | 46 | void Test_Suite:: 47 | run(Test_Result & result) 48 | { 49 | for(Test_Cases::iterator it = test_cases_.begin(), 50 | end = test_cases_.end(); 51 | it != end; 52 | ++it) 53 | { 54 | try 55 | { 56 | std::cout << "" << name() << ":" << it->name() << " "; 57 | std::cout.flush(); 58 | if(setup_) 59 | { 60 | setup_(); 61 | } 62 | it->run(); 63 | std::cout << "."; 64 | } 65 | catch(Assertion_Failed const & ex) 66 | { 67 | std::cout << "F"; 68 | result.add_failure(Failure(name(), it->name(), ex.what())); 69 | } 70 | catch(std::exception const & ex) 71 | { 72 | std::cout << "E"; 73 | result.add_error(Failure(name(), it->name(), ex.what())); 74 | } 75 | catch(...) 76 | { 77 | std::cout << "E"; 78 | result.add_error(Failure(name(), it->name(), "Unknown exception")); 79 | } 80 | if(teardown_) 81 | { 82 | teardown_(); 83 | } 84 | std::cout << std::endl; 85 | } 86 | } 87 | 88 | int main() 89 | { 90 | Test_Result result; 91 | size_t num_tests = 0; 92 | 93 | for(Test_Suites::iterator it = test_suites().begin(), 94 | end = test_suites().end(); 95 | it != end; 96 | ++it) 97 | { 98 | it->second.run(result); 99 | num_tests += it->second.size(); 100 | } 101 | 102 | std::cout << std::endl; 103 | 104 | std::cout << num_tests << " test(s), " 105 | << assertions << " assertion(s), " 106 | << result.errors().size() << " error(s), " 107 | << result.failures().size() << " failure(s)" 108 | << std::endl; 109 | 110 | if(result.errors().size() > 0) 111 | { 112 | std::cout << std::endl << "Errors:" << std::endl; 113 | for(std::vector::const_iterator it = result.errors().begin(), 114 | end = result.errors().end(); 115 | it != end; 116 | ++it) 117 | { 118 | std::cout << *it << std::endl; 119 | } 120 | } 121 | 122 | if(result.failures().size() > 0) 123 | { 124 | std::cout << std::endl << "Failures:" << std::endl; 125 | for(std::vector::const_iterator it = result.failures().begin(), 126 | end = result.failures().end(); 127 | it != end; 128 | ++it) 129 | { 130 | std::cout << *it << std::endl; 131 | } 132 | } 133 | 134 | return (int)result.errors().size() + (int)result.failures().size(); 135 | } 136 | 137 | -------------------------------------------------------------------------------- /rice/detail/Auto_Member_Function_Wrapper.hpp.mustache: -------------------------------------------------------------------------------- 1 | #ifndef Rice__detail__Auto_Member_Function_Wrapper__hpp_ 2 | #define Rice__detail__Auto_Member_Function_Wrapper__hpp_ 3 | 4 | // This is a generated file. DO NOT EDIT!! 5 | 6 | 7 | // This causes problems with certain C++ libraries 8 | #undef TYPE 9 | 10 | namespace Rice 11 | { 12 | 13 | namespace detail 14 | { 15 | 16 | #ifdef DOXYGEN 17 | 18 | #else 19 | 20 | {{#reverse_entries}} 21 | template 22 | class Auto_Member_Function_Wrapper{{{specs_with_return}}} 23 | : public Wrapped_Function 24 | { 25 | public: 26 | typedef Func_T Func; 27 | 28 | static const int Num_Args = {{num_args}}; 29 | 30 | Auto_Member_Function_Wrapper( 31 | Func func, 32 | Data_Object handler, 33 | Arguments* arguments = 0); 34 | 35 | ~Auto_Member_Function_Wrapper(); 36 | 37 | static VALUE call(int argc, VALUE* argv, VALUE self); 38 | 39 | private: 40 | Func func_; 41 | Data_Object handler_; 42 | Address_Registration_Guard handler_guard_; 43 | Arguments* arguments_; 44 | }; 45 | 46 | template 47 | class Auto_Member_Function_Wrapper{{{specs}}} 48 | : public Wrapped_Function 49 | { 50 | public: 51 | typedef Func_T Func; 52 | 53 | static const int Num_Args = {{num_args}}; 54 | 55 | Auto_Member_Function_Wrapper( 56 | Func func, 57 | Data_Object handler, 58 | Arguments* arguments = 0); 59 | 60 | ~Auto_Member_Function_Wrapper(); 61 | 62 | static VALUE call(int argc, VALUE* argv, VALUE self); 63 | 64 | private: 65 | Func func_; 66 | Data_Object handler_; 67 | Address_Registration_Guard handler_guard_; 68 | Arguments* arguments_; 69 | }; 70 | 71 | // --------------------------------------------------------------------- 72 | {{/reverse_entries}} 73 | 74 | template 75 | class Auto_Member_Function_Wrapper 76 | : public Wrapped_Function 77 | { 78 | public: 79 | typedef Func_T Func; 80 | 81 | static const int Num_Args = 0; 82 | 83 | Auto_Member_Function_Wrapper( 84 | Func func, 85 | Data_Object handler, 86 | Arguments* arguments = 0); 87 | 88 | ~Auto_Member_Function_Wrapper(); 89 | 90 | static VALUE call(int argc, VALUE* argv, VALUE self); 91 | 92 | private: 93 | Func func_; 94 | Data_Object handler_; 95 | Address_Registration_Guard handler_guard_; 96 | Arguments* arguments_; 97 | }; 98 | 99 | template 100 | class Auto_Member_Function_Wrapper 101 | : public Wrapped_Function 102 | { 103 | public: 104 | typedef Func_T Func; 105 | 106 | static const int Num_Args = 0; 107 | 108 | Auto_Member_Function_Wrapper( 109 | Func func, 110 | Data_Object handler, 111 | Arguments* arguments = 0); 112 | 113 | ~Auto_Member_Function_Wrapper(); 114 | 115 | static VALUE call(int argc, VALUE* argv, VALUE self); 116 | 117 | private: 118 | Func func_; 119 | Data_Object handler_; 120 | Address_Registration_Guard handler_guard_; 121 | Arguments* arguments_; 122 | }; 123 | 124 | // --------------------------------------------------------------------- 125 | #endif // DOXYGEN 126 | 127 | } // namespace detail 128 | 129 | } // namespace Rice 130 | 131 | #include "Auto_Member_Function_Wrapper.ipp" 132 | 133 | #endif // Rice__detail__Auto_Member_Function_Wrapper__hpp_ 134 | 135 | -------------------------------------------------------------------------------- /rice/Object.cpp: -------------------------------------------------------------------------------- 1 | #include "Object.hpp" 2 | #include "Class.hpp" 3 | #include "String.hpp" 4 | #include "Array.hpp" 5 | 6 | #include 7 | #include 8 | 9 | namespace Rice 10 | { 11 | 12 | Object const Nil(Qnil); 13 | Object const True(Qtrue); 14 | Object const False(Qfalse); 15 | Object const Undef(Qundef); 16 | 17 | } 18 | 19 | Rice::Class Rice::Object:: 20 | class_of() const { 21 | return rb_class_of(value_); 22 | } 23 | 24 | int Rice::Object:: 25 | compare(Object const & other) const 26 | { 27 | Object result = call("<=>", other); 28 | return from_ruby(result); 29 | } 30 | 31 | void Rice::Object:: 32 | freeze() 33 | { 34 | protect(rb_obj_freeze, value()); 35 | } 36 | 37 | bool Rice::Object:: 38 | is_frozen() const 39 | { 40 | return bool(OBJ_FROZEN(value())); 41 | } 42 | 43 | Rice::String Rice::Object:: 44 | to_s() const { 45 | return call("to_s"); 46 | } 47 | 48 | Rice::String Rice::Object:: 49 | inspect() const { 50 | return call("inspect"); 51 | } 52 | 53 | void Rice::Object:: 54 | swap(Rice::Object & other) 55 | { 56 | std::swap(value_, other.value_); 57 | } 58 | 59 | Rice::Object Rice::Object:: 60 | instance_eval(String const & s) 61 | { 62 | VALUE argv[] = { s.value() }; 63 | return protect(rb_obj_instance_eval, 1, &argv[0], *this); 64 | } 65 | 66 | int Rice::Object:: 67 | rb_type() const 68 | { 69 | return ::rb_type(*this); 70 | } 71 | 72 | bool Rice::Object:: 73 | is_a(Object klass) const 74 | { 75 | Object result = protect(rb_obj_is_kind_of, *this, klass); 76 | return result.test(); 77 | } 78 | 79 | bool Rice::Object:: 80 | respond_to(Identifier id) const 81 | { 82 | return bool(rb_respond_to(*this, id)); 83 | } 84 | 85 | bool Rice::Object:: 86 | is_instance_of(Object klass) const 87 | { 88 | Object result = protect(rb_obj_is_instance_of, *this, klass); 89 | return result.test(); 90 | } 91 | 92 | Rice::Object Rice::Object:: 93 | iv_get( 94 | Identifier name) const 95 | { 96 | return protect(rb_ivar_get, *this, name.id()); 97 | } 98 | 99 | Rice::Object Rice::Object:: 100 | attr_get( 101 | Identifier name) const 102 | { 103 | return protect(rb_attr_get, *this, name.id()); 104 | } 105 | 106 | Rice::Object Rice::Object:: 107 | vcall( 108 | Identifier id, 109 | Array args) 110 | { 111 | std::vector a(args.size()); 112 | 113 | Array::const_iterator it = args.begin(); 114 | Array::const_iterator end = args.end(); 115 | 116 | for(int i = 0 ;it != end; i++, ++it) { 117 | a[i] = it->value(); 118 | } 119 | 120 | return protect(rb_funcall3, *this, id, (int)args.size(), &a[0]); 121 | } 122 | 123 | void Rice::Object:: 124 | mark() const 125 | { 126 | rb_gc_mark(*this); 127 | } 128 | 129 | void Rice::Object:: 130 | set_value(VALUE v) 131 | { 132 | value_ = v; 133 | } 134 | 135 | std::ostream & Rice:: 136 | operator<<(std::ostream & out, Rice::Object const & obj) 137 | { 138 | String s(obj.to_s()); 139 | out << s.c_str(); 140 | return out; 141 | } 142 | 143 | bool Rice:: 144 | operator==(Rice::Object const & lhs, Rice::Object const & rhs) 145 | { 146 | Object result = lhs.call("==", rhs); 147 | return result.test(); 148 | } 149 | 150 | bool Rice:: 151 | operator!=(Rice::Object const & lhs, Rice::Object const & rhs) 152 | { 153 | return !(lhs == rhs); 154 | } 155 | 156 | bool Rice:: 157 | operator<(Rice::Object const & lhs, Rice::Object const & rhs) 158 | { 159 | Object result = lhs.call("<", rhs); 160 | return result.test(); 161 | } 162 | 163 | bool Rice:: 164 | operator>(Rice::Object const & lhs, Rice::Object const & rhs) 165 | { 166 | Object result = lhs.call(">", rhs); 167 | return result.test(); 168 | } 169 | 170 | -------------------------------------------------------------------------------- /rice/Arg_impl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Arg_Impl_hpp_ 2 | #define Rice__Arg_Impl_hpp_ 3 | 4 | namespace Rice { 5 | 6 | //! Helper for defining default arguments of a method 7 | /*! This class exposes the ability to define the default values of a 8 | * wrapped method. Inspired by how Boost.Python handles keyword and 9 | * default arguments, the syntax is simple: 10 | * 11 | * \code 12 | * define_method( 13 | * "method", 14 | * &method, 15 | * (Arg("arg1"), Arg("arg2") = 3, Arg("arg3") = true) 16 | * ); 17 | * \endcode 18 | * 19 | * which means "for method &method, it takes 3 arguments 20 | * [arg1, arg2, arg3]. Of these arguments, arg2's default is 3 21 | * and arg3's default is true. 22 | * 23 | * It may be required to explicitly cast the type of the default 24 | * value to prevent compilation errors. 25 | */ 26 | class Arg 27 | { 28 | public: 29 | //! Initialize a new Arg with the name of the argument 30 | /*! We require the name of the argument because 1) it makes code 31 | * easier to read and 2) hopefully Ruby gets keyword arguments 32 | * in the future and this means Rice will be ready for it. 33 | */ 34 | Arg(const char* name) 35 | : name_(name) 36 | , defaultValue(0) 37 | {} 38 | 39 | //! Copy Constructor 40 | Arg(const Arg& other) 41 | : name_(other.name()), 42 | defaultValue(other.defaultValue ? other.defaultValue->clone() : 0) 43 | {} 44 | 45 | virtual ~Arg() 46 | { 47 | if(defaultValue) { 48 | delete defaultValue; 49 | } 50 | } 51 | 52 | //! Set the default value for this Arg 53 | /*! Set the default value for this argument. 54 | * If this isn't called on this Arg, then this 55 | * Arg is required in the method call. 56 | * 57 | * \param val the value to store as default 58 | */ 59 | template 60 | Arg& operator=(Arg_Type val) 61 | { 62 | defaultValue = new type(val); 63 | return *this; 64 | } 65 | 66 | //! Check if this Arg has a default value associated with it 67 | bool hasDefaultValue() const { 68 | return defaultValue != 0; 69 | } 70 | 71 | //! Return the default value associated with this Arg 72 | /*! \return the type saved to this Arg 73 | */ 74 | template 75 | Arg_Type getDefaultValue() 76 | { 77 | return static_cast< type* >(defaultValue)->held; 78 | } 79 | 80 | //! Get the name of this Arg 81 | const char* name() const 82 | { 83 | return name_; 84 | } 85 | 86 | private: 87 | 88 | //! Name of the argument 89 | const char* name_; 90 | 91 | /** 92 | * The following is a stripped down version of 93 | * Boost.Any. 94 | */ 95 | 96 | class type_base 97 | { 98 | public: 99 | virtual ~type_base() {} 100 | virtual type_base* clone() const = 0; 101 | }; 102 | 103 | template 104 | class type : public type_base 105 | { 106 | public: 107 | type(Type value) 108 | :held(value) 109 | {} 110 | 111 | virtual ~type() { } 112 | 113 | virtual type_base* clone() const 114 | { 115 | return new type(held); 116 | } 117 | 118 | Type held; 119 | }; 120 | 121 | public: 122 | 123 | //! Our saved default value 124 | type_base* defaultValue; 125 | }; 126 | 127 | } 128 | 129 | #endif // Rice__Arg_Impl_hpp_ 130 | -------------------------------------------------------------------------------- /rice/detail/object_call.hpp: -------------------------------------------------------------------------------- 1 | // This is a generated file. DO NOT EDIT!! 2 | #ifdef DOXYGEN 3 | 4 | //! Call the Ruby method specified by 'id' on object 'obj'. 5 | /*! Pass in arguments (arg1, arg2, ...). The arguments will be converted to 6 | * Ruby objects with to_ruby<>. The return value will automatically be 7 | * converted to type Retval_T with from_ruby<>. 8 | * 9 | * E.g.: 10 | * \code 11 | * float y = x.call("foo", z, 42); 12 | * \endcode 13 | */ 14 | template 15 | Retval_T call(Identifier id, T1 arg1, T2 arg2, ...) const; 16 | 17 | //! Version of call which defaults to Object return type. 18 | Object call(Identifier id, T1 arg1, T2 arg2, ...) const; 19 | #else 20 | 21 | Object call(Identifier id) const; 22 | 23 | template 24 | Object call(Identifier id, T0 arg0) const; 25 | 26 | template 27 | Object call(Identifier id, T0 arg0, T1 arg1) const; 28 | 29 | template 30 | Object call(Identifier id, T0 arg0, T1 arg1, T2 arg2) const; 31 | 32 | template 33 | Object call(Identifier id, T0 arg0, T1 arg1, T2 arg2, T3 arg3) const; 34 | 35 | template 36 | Object call(Identifier id, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4) const; 37 | 38 | template 39 | Object call(Identifier id, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) const; 40 | 41 | template 42 | Object call(Identifier id, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) const; 43 | 44 | template 45 | Object call(Identifier id, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) const; 46 | 47 | template 48 | Object call(Identifier id, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) const; 49 | 50 | template 51 | Object call(Identifier id, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) const; 52 | 53 | template 54 | Object call(Identifier id, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) const; 55 | 56 | template 57 | Object call(Identifier id, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) const; 58 | 59 | template 60 | Object call(Identifier id, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) const; 61 | 62 | template 63 | Object call(Identifier id, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) const; 64 | 65 | template 66 | Object call(Identifier id, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) const; 67 | 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /rice/protect.ipp.mustache: -------------------------------------------------------------------------------- 1 | #ifndef Rice__protect__ipp_ 2 | #define Rice__protect__ipp_ 3 | 4 | // This is a generated file. DO NOT EDIT!! 5 | 6 | 7 | // This causes problems with certain C++ libraries 8 | #undef TYPE 9 | 10 | #include "detail/protect.hpp" 11 | namespace Rice 12 | { 13 | 14 | namespace detail 15 | { 16 | 17 | template 18 | class Ruby_Function_0 19 | { 20 | public: 21 | Ruby_Function_0(Fun f); 22 | inline void operator()(); 23 | static inline VALUE call(Ruby_Function_0 * f); 24 | Ret_T const & result() const { return result_; } 25 | 26 | private: 27 | Fun f_; 28 | 29 | Ret_T result_; // TODO: use placement new 30 | }; 31 | 32 | template 33 | inline Ruby_Function_0:: 34 | Ruby_Function_0(Fun f) 35 | : f_(f) 36 | { } 37 | 38 | template 39 | inline void Ruby_Function_0:: 40 | operator()() 41 | { 42 | result_ = f_(); 43 | } 44 | 45 | template 46 | inline VALUE Ruby_Function_0:: 47 | call(Ruby_Function_0 * f) 48 | { 49 | (*f)(); 50 | return Qnil; 51 | } 52 | 53 | } // namespace detail 54 | 55 | template 56 | inline Ret_T protect(Fun fun) 57 | { 58 | typedef detail::Ruby_Function_0 RF; 59 | RF f(fun); 60 | detail::protect( 61 | RUBY_VALUE_FUNC(RF::call), 62 | reinterpret_cast(&f)); 63 | return f.result(); 64 | } 65 | 66 | template 67 | inline VALUE protect(Fun fun) 68 | { 69 | typedef detail::Ruby_Function_0 RF; 70 | RF f(fun); 71 | detail::protect( 72 | RUBY_VALUE_FUNC(RF::call), 73 | reinterpret_cast(&f)); 74 | return f.result(); 75 | } 76 | 77 | // --------------------------------------------------------------------- 78 | 79 | {{#entries}} 80 | namespace detail 81 | { 82 | 83 | template 84 | class Ruby_Function_{{{count}}} 85 | { 86 | public: 87 | Ruby_Function_{{{count}}}(Fun f, {{{arguments}}}); 88 | inline void operator()(); 89 | static inline VALUE call(Ruby_Function_{{{count}}} * f); 90 | Ret_T const & result() const { return result_; } 91 | 92 | private: 93 | Fun f_; 94 | {{{members}}}; 95 | Ret_T result_; // TODO: use placement new 96 | }; 97 | 98 | template 99 | inline Ruby_Function_{{{count}}}:: 100 | Ruby_Function_{{count}}(Fun f, {{{arguments}}}) 101 | : f_(f), {{{supercalls}}} 102 | { } 103 | 104 | template 105 | inline void Ruby_Function_{{{count}}}:: 106 | operator()() 107 | { 108 | result_ = f_({{{member_call_args}}}); 109 | } 110 | 111 | template 112 | inline VALUE Ruby_Function_{{{count}}}:: 113 | call(Ruby_Function_{{{count}}} * f) 114 | { 115 | (*f)(); 116 | return Qnil; 117 | } 118 | 119 | } // namespace detail 120 | 121 | /** 122 | * protect on a function with a return type 123 | */ 124 | template 125 | inline Ret_T protect(Fun fun, {{{arguments}}}) 126 | { 127 | typedef detail::Ruby_Function_{{{count}}} RF; 128 | RF f(fun, {{{call_args}}}); 129 | detail::protect( 130 | RUBY_VALUE_FUNC(RF::call), 131 | reinterpret_cast(&f)); 132 | return f.result(); 133 | } 134 | 135 | /** 136 | * protect on a function with VALUE return type 137 | */ 138 | template 139 | inline VALUE protect(Fun fun, {{{arguments}}}) 140 | { 141 | typedef detail::Ruby_Function_{{{count}}} RF; 142 | RF f(fun, {{{call_args}}}); 143 | detail::protect( 144 | RUBY_VALUE_FUNC(RF::call), 145 | reinterpret_cast(&f)); 146 | return f.result(); 147 | } 148 | 149 | // --------------------------------------------------------------------- 150 | {{/entries}} 151 | 152 | } // namespace Rice 153 | 154 | 155 | #endif // Rice__protect__ipp_ 156 | 157 | -------------------------------------------------------------------------------- /test/test_Object.cpp: -------------------------------------------------------------------------------- 1 | #include "unittest.hpp" 2 | #include "rice/Object.hpp" 3 | #include "rice/Class.hpp" 4 | #include "rice/String.hpp" 5 | #include "rice/Array.hpp" 6 | 7 | using namespace Rice; 8 | 9 | TESTSUITE(Object); 10 | 11 | SETUP(Object) 12 | { 13 | ruby_init(); 14 | } 15 | 16 | TESTCASE(default_construct) 17 | { 18 | Object o; 19 | ASSERT_EQUAL(Qnil, o.value()); 20 | } 21 | 22 | TESTCASE(construct_with_value) 23 | { 24 | Object o(INT2NUM(42)); 25 | ASSERT_EQUAL(INT2NUM(42), o.value()); 26 | } 27 | 28 | TESTCASE(copy_construct) 29 | { 30 | Object o(INT2NUM(42)); 31 | Object o2(o); 32 | ASSERT_EQUAL(INT2NUM(42), o2.value()); 33 | } 34 | 35 | TESTCASE(test) 36 | { 37 | ASSERT_EQUAL(true, Object(Qtrue).test()); 38 | ASSERT_EQUAL(true, Object(INT2NUM(42)).test()); 39 | ASSERT_EQUAL(false, Object(Qfalse).test()); 40 | ASSERT_EQUAL(false, Object(Qnil).test()); 41 | ASSERT_EQUAL(true, Object(Qundef).test()); 42 | } 43 | 44 | TESTCASE(explicit_conversion_to_bool) 45 | { 46 | // g++ 3.3.3 can't handle constructor-style inside the assert, which 47 | // is why we use cast-style here. 48 | ASSERT_EQUAL(true, (bool)Object(Qtrue)); 49 | ASSERT_EQUAL(true, (bool)Object(INT2NUM(42))); 50 | ASSERT_EQUAL(false, (bool)Object(Qfalse)); 51 | ASSERT_EQUAL(false, (bool)Object(Qnil)); 52 | ASSERT_EQUAL(true, (bool)Object(Qundef)); 53 | } 54 | 55 | TESTCASE(is_nil) 56 | { 57 | ASSERT_EQUAL(false, Object(Qtrue).is_nil()); 58 | ASSERT_EQUAL(false, Object(INT2NUM(42)).is_nil()); 59 | ASSERT_EQUAL(false, Object(Qfalse).is_nil()); 60 | ASSERT_EQUAL(true, Object(Qnil).is_nil()); 61 | ASSERT_EQUAL(false, Object(Qundef).is_nil()); 62 | } 63 | 64 | TESTCASE(implicit_conversion_to_value) 65 | { 66 | // g++ 3.3.3 can't handle constructor-style inside the assert, which 67 | // is why we use cast-style here. 68 | ASSERT_EQUAL(Qtrue, (VALUE)Object(Qtrue)); 69 | ASSERT_EQUAL(INT2NUM(42), (VALUE)Object(INT2NUM(42))); 70 | ASSERT_EQUAL(Qfalse, (VALUE)Object(Qfalse)); 71 | ASSERT_EQUAL(Qnil, (VALUE)Object(Qnil)); 72 | ASSERT_EQUAL(Qundef, (VALUE)Object(Qundef)); 73 | } 74 | 75 | TESTCASE(explicit_conversion_to_value) 76 | { 77 | ASSERT_EQUAL(Qtrue, Object(Qtrue).value()); 78 | ASSERT_EQUAL(INT2NUM(42), Object(INT2NUM(42)).value()); 79 | ASSERT_EQUAL(Qfalse, Object(Qfalse).value()); 80 | ASSERT_EQUAL(Qnil, Object(Qnil).value()); 81 | ASSERT_EQUAL(Qundef, Object(Qundef).value()); 82 | } 83 | 84 | TESTCASE(class_of) 85 | { 86 | ASSERT_EQUAL(Class(rb_cObject), Class(rb_cObject).call("new").class_of()); 87 | ASSERT_EQUAL(Class(rb_cFloat), Object(rb_float_new(42.0)).class_of()); 88 | } 89 | 90 | TESTCASE(compare) 91 | { 92 | ASSERT_EQUAL(0, Object(INT2NUM(42)).compare(Object(INT2NUM(42)))); 93 | ASSERT_EQUAL(-1, Object(INT2NUM(42)).compare(Object(INT2NUM(43)))); 94 | ASSERT_EQUAL(1, Object(INT2NUM(42)).compare(Object(INT2NUM(41)))); 95 | } 96 | 97 | TESTCASE(to_s) 98 | { 99 | ASSERT_EQUAL(String("42"), Object(INT2NUM(42)).to_s()); 100 | } 101 | 102 | TESTCASE(inspect) 103 | { 104 | ASSERT_EQUAL(String("42"), Object(INT2NUM(42)).inspect()); 105 | ASSERT_EQUAL(String("\"foo\""), Object(rb_str_new2("foo")).inspect()); 106 | } 107 | 108 | TESTCASE(freeze) 109 | { 110 | Object o(Class(rb_cObject).call("new")); 111 | ASSERT(!OBJ_FROZEN(o.value())); 112 | o.freeze(); 113 | ASSERT(OBJ_FROZEN(o.value())); 114 | } 115 | 116 | TESTCASE(is_frozen) 117 | { 118 | Object o(Class(rb_cObject).call("new")); 119 | ASSERT(!o.is_frozen()); 120 | rb_obj_freeze(o); 121 | ASSERT(o.is_frozen()); 122 | } 123 | 124 | TESTCASE(swap) 125 | { 126 | Object o1(INT2NUM(42)); 127 | Object o2(rb_ary_new()); 128 | o1.swap(o2); 129 | ASSERT_EQUAL(to_ruby(42), o2); 130 | ASSERT_EQUAL(Class(rb_cArray), o1.class_of()); 131 | } 132 | 133 | TESTCASE(instance_eval) 134 | { 135 | Object o(Class(rb_cObject).call("new")); 136 | o.iv_set("@foo", 42); 137 | ASSERT_EQUAL(to_ruby(42), o.instance_eval("@foo")); 138 | } 139 | 140 | TESTCASE(rb_type) 141 | { 142 | ASSERT_EQUAL(T_TRUE, Object(Qtrue).rb_type()); 143 | ASSERT_EQUAL(T_FIXNUM, Object(INT2NUM(42)).rb_type()); 144 | ASSERT_EQUAL(T_FALSE, Object(Qfalse).rb_type()); 145 | ASSERT_EQUAL(T_NIL, Object(Qnil).rb_type()); 146 | ASSERT_EQUAL(T_UNDEF, Object(Qundef).rb_type()); 147 | } 148 | 149 | -------------------------------------------------------------------------------- /rice/Data_Object_defn.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__Data_Object_defn__hpp_ 2 | #define Rice__Data_Object_defn__hpp_ 3 | 4 | #include "Object_defn.hpp" 5 | #include "Data_Type_fwd.hpp" 6 | #include "ruby_mark.hpp" 7 | #include "detail/to_ruby.hpp" 8 | #include "detail/ruby.hpp" 9 | 10 | /*! \file 11 | * \brief Provides a helper class for wrapping and unwrapping C++ 12 | * objects as Ruby objects. 13 | */ 14 | 15 | namespace Rice 16 | { 17 | 18 | template 19 | struct Default_Mark_Function 20 | { 21 | typedef void (*Ruby_Data_Func)(T * obj); 22 | static const Ruby_Data_Func mark; 23 | }; 24 | 25 | template 26 | struct Default_Free_Function 27 | { 28 | static void free(T * obj) { delete obj; } 29 | }; 30 | 31 | 32 | //! A smartpointer-like wrapper for Ruby data objects. 33 | /*! A data object is a ruby object of type T_DATA, which is usually 34 | * created by using the Data_Wrap_Struct or Data_Make_Struct macro. 35 | * This class wraps creation of the data structure, providing a 36 | * type-safe object-oriented interface to the underlying C interface. 37 | * This class works in conjunction with the Data_Type class to ensure 38 | * type safety. 39 | * 40 | * Example: 41 | * \code 42 | * class Foo { }; 43 | * ... 44 | * Data_Type rb_cFoo = define_class("Foo"); 45 | * ... 46 | * // Wrap: 47 | * Data_Object foo1(new Foo); 48 | * 49 | * // Get value to return: 50 | * VALUE v = foo1.value() 51 | * 52 | * // Unwrap: 53 | * Data_Object foo2(v, rb_cFoo); 54 | * \endcode 55 | */ 56 | template 57 | class Data_Object 58 | : public Object 59 | { 60 | public: 61 | //! A function that takes a T* and returns void. 62 | typedef void (*Ruby_Data_Func)(T * obj); 63 | 64 | //! Wrap a C++ object. 65 | /*! This constructor is analogous to calling Data_Wrap_Struct. Be 66 | * careful not to call this function more than once for the same 67 | * pointer (in general, it should only be called for newly 68 | * constructed objects that need to be managed by Ruby's garbage 69 | * collector). 70 | * \param obj the object to wrap. 71 | * \param klass the Ruby class to use for the newly created Ruby 72 | * object. 73 | * \param mark_func a function that gets called by the garbage 74 | * collector to mark the object's children. 75 | * \param free_func a function that gets called by the garbage 76 | * collector to free the object. 77 | */ 78 | Data_Object( 79 | T * obj, 80 | VALUE klass = Data_Type::klass(), 81 | Ruby_Data_Func mark_func = Default_Mark_Function::mark, 82 | Ruby_Data_Func free_func = Default_Free_Function::free); 83 | 84 | //! Unwrap a Ruby object. 85 | /*! This constructor is analogous to calling Data_Get_Struct. Uses 86 | * Data_Type::klass as the class of the object. 87 | * \param value the Ruby object to unwrap. 88 | */ 89 | Data_Object( 90 | Object value); 91 | 92 | //! Unwrap a Ruby object. 93 | /*! This constructor is analogous to calling Data_Get_Struct. Will 94 | * throw an exception if the class of the object differs from the 95 | * specified class. 96 | * \param value the Ruby object to unwrap. 97 | * \param klass the expected class of the object. 98 | */ 99 | template 100 | Data_Object( 101 | Object value, 102 | Data_Type const & klass = Data_Type::klass()); 103 | 104 | //! Make a copy of a Data_Object 105 | /*! \param other the Data_Object to copy. 106 | */ 107 | Data_Object(Data_Object const & other); 108 | 109 | T & operator*() const { return *obj_; } //!< Return a reference to obj_ 110 | T * operator->() const { return obj_; } //!< Return a pointer to obj_ 111 | T * get() const { return obj_; } //!< Return a pointer to obj_ 112 | 113 | //! Swap with another data object of the same type 114 | /*! \param ref the object with which to swap. 115 | */ 116 | template 117 | void swap(Data_Object & ref); 118 | 119 | private: 120 | static void check_cpp_type(Data_Type const & klass); 121 | 122 | private: 123 | T * obj_; 124 | }; 125 | 126 | namespace detail 127 | { 128 | template 129 | struct to_ruby_ > 130 | { 131 | static Rice::Object convert(Data_Object const & x); 132 | }; 133 | } 134 | 135 | } // namespace Rice 136 | 137 | #endif // Rice__Data_Object_defn__hpp_ 138 | 139 | -------------------------------------------------------------------------------- /ruby.ac: -------------------------------------------------------------------------------- 1 | dnl Get a key from ruby's configuration table 2 | AC_DEFUN([RUBY_CONFIG], [ 3 | $RUBY -rrbconfig -e "puts(RbConfig::CONFIG[['$1']] || '')"]) 4 | 5 | AC_DEFUN([RB_INIT_RUBY], [ 6 | 7 | AC_ARG_WITH( 8 | ruby, 9 | AC_HELP_STRING( 10 | --with-ruby=PATH, 11 | [ path to the ruby interpreter [[ruby]] ]), 12 | [ RUBY=$withval ], 13 | [ RUBY=ruby ]) 14 | AC_ARG_WITH( 15 | ruby_sitelibdir, 16 | AC_HELP_STRING( 17 | --with-ruby-sitelibdir=PATH, 18 | [ path to install ruby scripts [[auto-detect]] ]), 19 | [ ruby_sitelibdir=$withval ], 20 | [ ruby_sitelibdir=NONE ]) 21 | 22 | AC_SUBST(RUBY) 23 | 24 | RUBY_VERSION_CODE=`$RUBY -e "puts RUBY_VERSION.gsub(/\./, '')"` 25 | AC_SUBST(RUBY_VERSION_CODE) 26 | 27 | RUBY_CONFIG_SO_NAME=`RUBY_CONFIG(RUBY_SO_NAME)` 28 | RUBY_CONFIG_ARCHDIR=`RUBY_CONFIG(archdir)` 29 | RUBY_CONFIG_ARCH=`RUBY_CONFIG(arch)` 30 | RUBY_CONFIG_LIBDIR=`RUBY_CONFIG(libdir)` 31 | RUBY_CONFIG_BINDIR=`RUBY_CONFIG(bindir)` 32 | RUBY_CONFIG_RUBYHDRDIR=`RUBY_CONFIG(rubyhdrdir)` 33 | RUBY_CONFIG_RUBYARCHHDRDIR=`RUBY_CONFIG(rubyarchhdrdir)` 34 | RUBY_CONFIG_CFLAGS=`RUBY_CONFIG(CFLAGS)` 35 | RUBY_CONFIG_LIBS=`RUBY_CONFIG(LIBS)` 36 | RUBY_CONFIG_DLDLIBS=`RUBY_CONFIG(DLDLIBS)` 37 | RUBY_CONFIG_LDFLAGS=`RUBY_CONFIG(LDFLAGS)` 38 | RUBY_CONFIG_LIBRUBYARG=`RUBY_CONFIG(LIBRUBYARG)` 39 | RUBY_CONFIG_LIBRUBYARG_STATIC=`RUBY_CONFIG(LIBRUBYARG_STATIC)` 40 | RUBY_CONFIG_CCDLFLAGS=`RUBY_CONFIG(CCDLFLAGS)` 41 | 42 | RUBY_CPPFLAGS="-I${RUBY_CONFIG_RUBYHDRDIR}" 43 | RUBY_CPPFLAGS="${RUBY_CPPFLAGS} -I${RUBY_CONFIG_RUBYHDRDIR}/${RUBY_CONFIG_ARCH}" 44 | 45 | if test "x${RUBY_CONFIG_RUBYARCHHDRDIR}x" != "xx"; then 46 | RUBY_CPPFLAGS="${RUBY_CPPFLAGS} -I${RUBY_CONFIG_RUBYARCHHDRDIR}" 47 | fi 48 | AC_SUBST(RUBY_CPPFLAGS) 49 | 50 | RUBY_CFLAGS="${RUBY_CONFIG_CFLAGS} ${RUBY_CONFIG_CCDLFLAGS}" 51 | AC_SUBST(RUBY_CFLAGS) 52 | 53 | RUBY_CXXFLAGS="${RUBY_CONFIG_CFLAGS} ${RUBY_CONFIG_CCDLFLAGS}" 54 | AC_SUBST(RUBY_CXXFLAGS) 55 | 56 | RUBY_LDFLAGS="-L${RUBY_CONFIG_ARCHDIR} -L${RUBY_CONFIG_LIBDIR} ${RUBY_CONFIG_LDFLAGS}" 57 | AC_SUBST(RUBY_LDFLAGS) 58 | 59 | RUBY_LIBS="${RUBY_CONFIG_LIBS} ${RUBY_CONFIG_DLDLIBS}" 60 | AC_SUBST(RUBY_LIBS) 61 | 62 | RUBY_LIBRUBYARG="${RUBY_CONFIG_LIBRUBYARG}" 63 | AC_SUBST(RUBY_LIBRUBYARG) 64 | 65 | RUBY_LIBRUBYARG_STATIC="${RUBY_CONFIG_LIBRUBYARG_STATIC}" 66 | AC_SUBST(RUBY_LIBRUBYARG_STATIC) 67 | 68 | dnl If the user specified a prefix, then use it, otherwise defalut to 69 | dnl the configured sitelibdir 70 | if test "x${ruby_sitelibdir}x" != "xNONEx" 71 | then 72 | RUBY_SITELIBDIR="${ruby_sitelibdir}" 73 | else 74 | if test "x${prefix}x" = "xNONEx" 75 | then 76 | RUBY_SITELIBDIR=`RUBY_CONFIG(sitelibdir)` 77 | else 78 | sitelibdir_no_prefix=`$RUBY -rrbconfig \ 79 | -e "include RbConfig; \ 80 | puts CONFIG[['sitelibdir']].sub(CONFIG[['prefix']], '')"` 81 | RUBY_SITELIBDIR="${prefix}/${sitelibdir_no_prefix}" 82 | fi 83 | fi 84 | AC_SUBST(RUBY_SITELIBDIR) 85 | 86 | dnl The fourth parameter to AC_CHECK_HEADER keeps autoconf from 87 | dnl searching for standard header files as a side-effect (which we want) 88 | CPPFLAGS_save="${CPPFLAGS}" 89 | CPPFLAGS="${CPPFLAGS} ${RUBY_CPPFLAGS}" 90 | CXXFLAGS="${CPPFLAGS}" 91 | AC_CHECK_HEADERS(ruby.h,,AC_MSG_ERROR( 92 | could not find ruby.h (check config.log)),[ ]) 93 | AC_CHECK_HEADERS(node.h,,,[ 94 | #include 95 | ]) 96 | AC_CHECK_HEADERS(ruby/node.h, 97 | [ AC_DEFINE(REALLY_HAVE_RUBY_NODE_H, [], 98 | [ Define this macro to use ruby/node.h ]) ], 99 | ,[ 100 | #include 101 | ]) 102 | AC_CHECK_HEADERS(version.h,,,[ 103 | #include 104 | ]) 105 | AC_CHECK_HEADERS(env.h,,,[ 106 | #include 107 | ]) 108 | 109 | CPPFLAGS="${CPPFLAGS_save}" 110 | 111 | AC_MINGW32 112 | 113 | if test x"${MINGW32}"x = xyesx; then 114 | RB_FIX_MINGW_LIBS 115 | fi 116 | 117 | ]) dnl RB_INIT_RUBY 118 | 119 | dnl We would like to be able to build using MingW against the one-click 120 | dnl installer, which is built using VC6. So, we detect this situation 121 | dnl and fix up the link step if this is the case. 122 | dnl 123 | dnl Static linking isn't likely to work correctly, so we disable it by 124 | dnl default, but if the user asks for LIBRUBYARG_STATIC, they'll still 125 | dnl get static linking. 126 | AC_DEFUN([RB_FIX_MINGW_LIBS], [ 127 | RUBY_LIBS=`echo ${RUBY_LIBS} | sed -e "s%oldnames.lib%-lmoldname%"` 128 | RUBY_LIBS=`echo ${RUBY_LIBS} | sed -e "s%user32.lib%-luser32%"` 129 | RUBY_LIBS=`echo ${RUBY_LIBS} | sed -e "s%advapi32.lib%-ladvapi32%"` 130 | RUBY_LIBS=`echo ${RUBY_LIBS} | sed -e "s%ws2_32.lib%-lws2_32%"` 131 | RUBY_LIBRUBYARG=`echo ${RUBY_LIBRUBYARG} | sed -e "s%\(msvcrt-ruby.*\).lib%${RUBY_CONFIG_BINDIR}/\1.dll%"` 132 | RUBY_LIBRUBYARG_STATIC=`echo ${RUBY_LIBRUBYARG_STATIC} | sed -e "s%\(msvcrt-ruby.*\).lib%${RUBY_CONFIG_LIBDIR}/\1.lib%"` 133 | ]) dnl RB_FIX_MINGW_LIBS 134 | 135 | dnl vim:ft=config 136 | -------------------------------------------------------------------------------- /rice/Struct.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Rice__ruby_struct__hpp_ 2 | #define Rice__ruby_struct__hpp_ 3 | 4 | #include "Array.hpp" 5 | #include "Hash.hpp" 6 | #include "Module.hpp" 7 | #include "Class.hpp" 8 | #include "Builtin_Object.hpp" 9 | #include "Address_Registration_Guard.hpp" 10 | 11 | namespace Rice 12 | { 13 | class Struct; 14 | 15 | //! Define a new Struct 16 | Struct define_struct(); 17 | 18 | //! A wrapper for creating Struct classes. 19 | /*! The Struct class is used for creating new Classes. Note that the 20 | * notation used here differs slightly from the notation inside the 21 | * interpreter. 22 | * 23 | * Inside the interpreter, calling Struct.new creates a new Class: 24 | * \code 25 | * irb(main):001:0> MyStruct = Struct.new(:a, :b, :c) 26 | * => S 27 | * irb(main):002:0> MyStruct.class 28 | * => Class 29 | * \endcode 30 | * 31 | * Instantiating that Class creates an instance of that Class: 32 | * \code 33 | * irb(main):003:0> mystruct_instance = MyStruct.new 34 | * => # 35 | * irb(main):004:0> mystruct_instance.class 36 | * => MyStruct 37 | * irb(main):005:0> mystruct_instance.class.ancestors 38 | * => [MyStruct, Struct, Enumerable, Object, Kernel] 39 | * \endcode 40 | * 41 | * Thus, inside the interpreter, MyStruct is a Class which inherits 42 | * from Struct, and mystruct_instance is an instance of MyStruct. 43 | * 44 | * At the C++ level, we might do this instead: 45 | * \code 46 | * Struct rb_cMyStruct = define_struct() 47 | * .define_member("a") 48 | * .define_member("b") 49 | * .define_member("c") 50 | * .initialize("MyStruct"); 51 | * Struct::Instance mystruct_instance(rb_cMyStruct.new_instance()); 52 | * \endcode 53 | * 54 | * Here rb_cMyStruct is an instance of Struct and that mystruct_instance 55 | * is an instance of Struct::Instance. 56 | */ 57 | class Struct 58 | : public Module_impl 59 | { 60 | public: 61 | //! Create a new Struct. 62 | Struct(); 63 | 64 | //! Copy constructor. 65 | Struct(Struct const & s); 66 | 67 | //! Destructor. 68 | virtual ~Struct(); 69 | 70 | //! Define a new Struct member. 71 | /*! Defines a new member of the Struct. Must be called before the 72 | * Struct is initialized. 73 | * \return *this 74 | */ 75 | Struct & define_member( 76 | Identifier name); 77 | 78 | //! Initialize the Struct class. 79 | /*! Must be called after all Struct members have been defined. 80 | * \param module the module under which to define the Struct. 81 | * \param name the name of the Class at the ruby level. 82 | */ 83 | Struct & initialize( 84 | Module module, 85 | Identifier name); 86 | 87 | //! Get the offset of a member in the Struct. 88 | /*! Internally, Struct members are stored as a single array of VALUE. 89 | * This function determines the offset of a given member in that 90 | * array. 91 | * \param member the name of the desired member. 92 | * \return the index of the given member. 93 | */ 94 | size_t offset_of(Identifier name) const; 95 | 96 | class Instance; 97 | friend class Instance; 98 | friend Struct Rice::define_struct(); 99 | 100 | //! Create a new instance of the Struct 101 | /*! \param args the arguments to the constructor. 102 | * \return a new Struct::Instance 103 | */ 104 | Instance new_instance(Array args = Array()) const; 105 | 106 | //! Swap with another Struct. 107 | void swap(Struct & other); 108 | 109 | Array members() const { return members_; } 110 | 111 | private: 112 | Array members_; 113 | Address_Registration_Guard members_guard_; 114 | 115 | Hash member_offset_; 116 | Address_Registration_Guard member_offset_guard_; 117 | }; 118 | 119 | 120 | //! An instance of a Struct 121 | //! \sa Struct 122 | class Struct::Instance 123 | : public Builtin_Object 124 | { 125 | public: 126 | //! Create a new Instance of a Struct. 127 | /*! \param type the Struct type to create. 128 | * \param args the initial values for the objects of the instance. 129 | */ 130 | Instance( 131 | Struct const & type, 132 | Array args = Array()); 133 | 134 | //! Encapsulate an existing Struct instance. 135 | /*! \param type the Struct type to encapsulate. 136 | * \param s the instance to encapsulate. 137 | */ 138 | Instance( 139 | Struct const & type, 140 | Object s); 141 | 142 | //! Get a member, given its offset. 143 | /*! \param index the (integral) index into the Struct's internal 144 | * array or its name (an Identifier or char const *) 145 | * \return the member. 146 | */ 147 | template 148 | Object operator[](T index); 149 | 150 | //! Swap with another Struct::Instance. 151 | void swap(Instance & other); 152 | 153 | private: 154 | Struct type_; 155 | }; 156 | 157 | } // namespace Rice 158 | 159 | #include "Struct.ipp" 160 | 161 | #endif // Rice__ruby_struct__hpp_ 162 | 163 | --------------------------------------------------------------------------------