rice 2.1.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/COPYING +2 -2
- data/Doxyfile +4 -16
- data/Makefile.am +2 -2
- data/Makefile.in +28 -17
- data/{README → README.md} +323 -328
- data/aclocal.m4 +104 -107
- data/ax_cxx_compile_stdcxx.m4 +951 -0
- data/configure +549 -238
- data/configure.ac +3 -3
- data/extconf.rb +11 -10
- data/rice/Array.hpp +16 -16
- data/rice/Array.ipp +11 -11
- data/rice/Class_defn.hpp +1 -0
- data/rice/Constructor.hpp +27 -371
- data/rice/Data_Object_defn.hpp +3 -3
- data/rice/Director.hpp +3 -3
- data/rice/Enum.ipp +1 -1
- data/rice/Exception.cpp +2 -7
- data/rice/Hash.hpp +8 -5
- data/rice/Hash.ipp +2 -2
- data/rice/Makefile.am +1 -4
- data/rice/Makefile.in +80 -35
- data/rice/Module_impl.ipp +1 -1
- data/rice/Object.cpp +1 -1
- data/rice/Object.ipp +15 -1
- data/rice/Object_defn.hpp +24 -1
- data/rice/String.cpp +2 -7
- data/rice/Struct.cpp +2 -2
- data/rice/Struct.hpp +1 -1
- data/rice/Struct.ipp +1 -1
- data/rice/config.hpp +2 -2
- data/rice/config.hpp.in +2 -2
- data/rice/detail/Arguments.hpp +1 -1
- data/rice/detail/Auto_Function_Wrapper.ipp +512 -1025
- data/rice/detail/Auto_Member_Function_Wrapper.ipp +272 -545
- data/rice/detail/Iterator.hpp +2 -2
- data/rice/detail/method_data.cpp +8 -2
- data/rice/detail/ruby.hpp +1 -4
- data/rice/detail/ruby_version_code.hpp +1 -1
- data/rice/detail/wrap_function.hpp +32 -307
- data/rice/protect.hpp +3 -57
- data/rice/to_from_ruby.ipp +128 -4
- data/ruby/Makefile.in +11 -8
- data/ruby/lib/Makefile.in +10 -7
- data/ruby/lib/version.rb +1 -1
- data/sample/Makefile.am +10 -4
- data/sample/Makefile.in +20 -11
- data/sample/callbacks/extconf.rb +3 -0
- data/sample/callbacks/sample_callbacks.cpp +38 -0
- data/sample/callbacks/test.rb +28 -0
- data/test/Makefile.am +1 -0
- data/test/Makefile.in +118 -49
- data/test/embed_ruby.cpp +21 -0
- data/test/embed_ruby.hpp +4 -0
- data/test/ext/Makefile.in +10 -7
- data/test/test_Address_Registration_Guard.cpp +2 -1
- data/test/test_Array.cpp +2 -1
- data/test/test_Builtin_Object.cpp +2 -1
- data/test/test_Class.cpp +7 -4
- data/test/test_Data_Object.cpp +2 -1
- data/test/test_Data_Type.cpp +2 -1
- data/test/test_Director.cpp +2 -1
- data/test/test_Enum.cpp +24 -3
- data/test/test_Exception.cpp +2 -1
- data/test/test_Hash.cpp +2 -1
- data/test/test_Identifier.cpp +2 -1
- data/test/test_Memory_Management.cpp +2 -1
- data/test/test_Module.cpp +2 -1
- data/test/test_Object.cpp +13 -1
- data/test/test_String.cpp +2 -1
- data/test/test_Struct.cpp +2 -1
- data/test/test_Symbol.cpp +2 -1
- data/test/test_To_From_Ruby.cpp +102 -1
- data/test/test_global_functions.cpp +2 -1
- data/test/test_rice.rb +4 -0
- data/test/unittest.cpp +35 -9
- metadata +72 -16
- data/check_stdcxx_11.ac +0 -142
- data/rice/detail/object_call.hpp +0 -69
- data/rice/detail/object_call.ipp +0 -131
- data/rice/detail/traits.hpp +0 -43
- data/rice/detail/wrap_function.ipp +0 -514
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b94a556a35a6622bc3a5e9ca9f124020b0d22fffa319df33e3aa0bb35bae4d56
|
4
|
+
data.tar.gz: bcd79c325fb7cc04396720a8d987d55ba197079743971f012ca71ceeb16de2df
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6122026933d06b8866e486fcd954f6e55a148caab22fe95072cbf5ff6937936d2900e0374b6e276fb14c476c1413833cbd05e536757aea13f7ee431ac163a27
|
7
|
+
data.tar.gz: a7202f164e6cf63259bc3d2b8aa90a7306e53f88305f1c558a4ebd6d1d60b22e7eacf8466667b0fd3ce8123002e44a62a3896f9e4ecb69b3b412f09b23bf64af
|
data/COPYING
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
Copyright (C)
|
2
|
-
|
1
|
+
Copyright (C) 2020 Jason Roelofs <jasongroelofs@gmail.com>
|
2
|
+
Paul Brannan <curlypaul924@gmail.com>,
|
3
3
|
|
4
4
|
Redistribution and use in source and binary forms, with or without
|
5
5
|
modification, are permitted provided that the following conditions
|
data/Doxyfile
CHANGED
@@ -38,7 +38,7 @@ PROJECT_NAME = "Rice"
|
|
38
38
|
# could be handy for archiving the generated documentation or if some version
|
39
39
|
# control system is used.
|
40
40
|
|
41
|
-
PROJECT_NUMBER =
|
41
|
+
PROJECT_NUMBER = 3.0.0
|
42
42
|
|
43
43
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
44
44
|
# for a project that appears at the top of each page and should give viewer a
|
@@ -733,7 +733,7 @@ WARN_LOGFILE =
|
|
733
733
|
# spaces.
|
734
734
|
# Note: If this tag is empty the current directory is searched.
|
735
735
|
|
736
|
-
INPUT = rice
|
736
|
+
INPUT = rice README.md
|
737
737
|
|
738
738
|
# This tag can be used to specify the character encoding of the source files
|
739
739
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
@@ -753,7 +753,7 @@ INPUT_ENCODING = UTF-8
|
|
753
753
|
# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
|
754
754
|
# *.qsf, *.as and *.js.
|
755
755
|
|
756
|
-
FILE_PATTERNS = *.hpp
|
756
|
+
FILE_PATTERNS = *.hpp
|
757
757
|
|
758
758
|
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
759
759
|
# be searched for input files as well.
|
@@ -869,7 +869,7 @@ FILTER_SOURCE_PATTERNS =
|
|
869
869
|
# (index.html). This can be useful if you have a project on for instance GitHub
|
870
870
|
# and want to reuse the introduction page also for the doxygen output.
|
871
871
|
|
872
|
-
USE_MDFILE_AS_MAINPAGE =
|
872
|
+
USE_MDFILE_AS_MAINPAGE = README.md
|
873
873
|
|
874
874
|
#---------------------------------------------------------------------------
|
875
875
|
# Configuration options related to source browsing
|
@@ -1779,18 +1779,6 @@ GENERATE_XML = NO
|
|
1779
1779
|
|
1780
1780
|
XML_OUTPUT = xml
|
1781
1781
|
|
1782
|
-
# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
|
1783
|
-
# validating XML parser to check the syntax of the XML files.
|
1784
|
-
# This tag requires that the tag GENERATE_XML is set to YES.
|
1785
|
-
|
1786
|
-
XML_SCHEMA =
|
1787
|
-
|
1788
|
-
# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
|
1789
|
-
# validating XML parser to check the syntax of the XML files.
|
1790
|
-
# This tag requires that the tag GENERATE_XML is set to YES.
|
1791
|
-
|
1792
|
-
XML_DTD =
|
1793
|
-
|
1794
1782
|
# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
|
1795
1783
|
# listings (including syntax highlighting and cross-referencing information) to
|
1796
1784
|
# the XML output. Note that enabling this will significantly increase the size
|
data/Makefile.am
CHANGED
@@ -20,7 +20,7 @@ EXTRA_DIST = \
|
|
20
20
|
doxygen.am \
|
21
21
|
doc
|
22
22
|
|
23
|
-
rice/README.doxygen: README
|
23
|
+
rice/README.doxygen: README.md
|
24
24
|
@echo Generating documentation
|
25
|
-
@$(RUBY) -e 'File.open("README") { |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 " */" } }'
|
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
26
|
|
data/Makefile.in
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
# Makefile.in generated by automake 1.
|
1
|
+
# Makefile.in generated by automake 1.16.3 from Makefile.am.
|
2
2
|
# @configure_input@
|
3
3
|
|
4
|
-
# Copyright (C) 1994-
|
4
|
+
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
|
5
5
|
|
6
6
|
# This Makefile.in is free software; the Free Software Foundation
|
7
7
|
# gives unlimited permission to copy and/or distribute it,
|
@@ -119,7 +119,7 @@ build_triplet = @build@
|
|
119
119
|
host_triplet = @host@
|
120
120
|
subdir = .
|
121
121
|
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
122
|
-
am__aclocal_m4_deps = $(top_srcdir)/
|
122
|
+
am__aclocal_m4_deps = $(top_srcdir)/ax_cxx_compile_stdcxx.m4 \
|
123
123
|
$(top_srcdir)/ruby.ac $(top_srcdir)/doxygen.ac \
|
124
124
|
$(top_srcdir)/configure.ac
|
125
125
|
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
@@ -166,7 +166,7 @@ am__recursive_targets = \
|
|
166
166
|
$(RECURSIVE_CLEAN_TARGETS) \
|
167
167
|
$(am__extra_recursive_targets)
|
168
168
|
AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
|
169
|
-
cscope distdir dist dist-all distcheck
|
169
|
+
cscope distdir distdir-am dist dist-all distcheck
|
170
170
|
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
171
171
|
# Read a list of newline-separated strings from the standard input,
|
172
172
|
# and print each of them once, without duplicates. Input order is
|
@@ -190,7 +190,7 @@ CSCOPE = cscope
|
|
190
190
|
DIST_SUBDIRS = $(SUBDIRS)
|
191
191
|
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/doxygen.am \
|
192
192
|
$(top_srcdir)/rice/detail/ruby_version_code.hpp.in COPYING \
|
193
|
-
|
193
|
+
config.guess config.sub depcomp install-sh missing
|
194
194
|
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
195
195
|
distdir = $(PACKAGE)-$(VERSION)
|
196
196
|
top_distdir = "$(distdir)"
|
@@ -229,6 +229,8 @@ am__relativize = \
|
|
229
229
|
DIST_ARCHIVES = "$(distdir)".tar.gz
|
230
230
|
GZIP_ENV = --best
|
231
231
|
DIST_TARGETS = dist-gzip
|
232
|
+
# Exists only to be overridden by the user if desired.
|
233
|
+
AM_DISTCHECK_DVI_TARGET = dvi
|
232
234
|
distuninstallcheck_listfiles = find . -type f -print
|
233
235
|
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
|
234
236
|
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
|
@@ -275,7 +277,7 @@ ECHO_C = @ECHO_C@
|
|
275
277
|
ECHO_N = @ECHO_N@
|
276
278
|
ECHO_T = @ECHO_T@
|
277
279
|
EXEEXT = @EXEEXT@
|
278
|
-
|
280
|
+
HAVE_CXX14 = @HAVE_CXX14@
|
279
281
|
INSTALL = @INSTALL@
|
280
282
|
INSTALL_DATA = @INSTALL_DATA@
|
281
283
|
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
@@ -429,8 +431,8 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
|
429
431
|
echo ' $(SHELL) ./config.status'; \
|
430
432
|
$(SHELL) ./config.status;; \
|
431
433
|
*) \
|
432
|
-
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(
|
433
|
-
cd $(top_builddir) && $(SHELL) ./config.status $@ $(
|
434
|
+
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \
|
435
|
+
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \
|
434
436
|
esac;
|
435
437
|
$(srcdir)/doxygen.am $(am__empty):
|
436
438
|
|
@@ -551,7 +553,10 @@ distclean-tags:
|
|
551
553
|
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
552
554
|
-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
|
553
555
|
|
554
|
-
distdir: $(
|
556
|
+
distdir: $(BUILT_SOURCES)
|
557
|
+
$(MAKE) $(AM_MAKEFLAGS) distdir-am
|
558
|
+
|
559
|
+
distdir-am: $(DISTFILES)
|
555
560
|
$(am__remove_distdir)
|
556
561
|
test -d "$(distdir)" || mkdir "$(distdir)"
|
557
562
|
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
@@ -616,7 +621,7 @@ distdir: $(DISTFILES)
|
|
616
621
|
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|
617
622
|
|| chmod -R a+r "$(distdir)"
|
618
623
|
dist-gzip: distdir
|
619
|
-
tardir="$(distdir)" && $(am__tar) | GZIP
|
624
|
+
tardir="$(distdir)" && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >"$(distdir)".tar.gz
|
620
625
|
$(am__post_remove_distdir)
|
621
626
|
|
622
627
|
dist-bzip2: distdir
|
@@ -631,6 +636,10 @@ dist-xz: distdir
|
|
631
636
|
tardir="$(distdir)" && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >"$(distdir)".tar.xz
|
632
637
|
$(am__post_remove_distdir)
|
633
638
|
|
639
|
+
dist-zstd: distdir
|
640
|
+
tardir="$(distdir)" && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >"$(distdir)".tar.zst
|
641
|
+
$(am__post_remove_distdir)
|
642
|
+
|
634
643
|
dist-tarZ: distdir
|
635
644
|
@echo WARNING: "Support for distribution archives compressed with" \
|
636
645
|
"legacy program 'compress' is deprecated." >&2
|
@@ -642,7 +651,7 @@ dist-shar: distdir
|
|
642
651
|
@echo WARNING: "Support for shar distribution archives is" \
|
643
652
|
"deprecated." >&2
|
644
653
|
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
|
645
|
-
shar "$(distdir)" | GZIP
|
654
|
+
shar "$(distdir)" | eval GZIP= gzip $(GZIP_ENV) -c >"$(distdir)".shar.gz
|
646
655
|
$(am__post_remove_distdir)
|
647
656
|
|
648
657
|
dist-zip: distdir
|
@@ -660,7 +669,7 @@ dist dist-all:
|
|
660
669
|
distcheck: dist
|
661
670
|
case '$(DIST_ARCHIVES)' in \
|
662
671
|
*.tar.gz*) \
|
663
|
-
GZIP
|
672
|
+
eval GZIP= gzip $(GZIP_ENV) -dc "$(distdir)".tar.gz | $(am__untar) ;;\
|
664
673
|
*.tar.bz2*) \
|
665
674
|
bzip2 -dc "$(distdir)".tar.bz2 | $(am__untar) ;;\
|
666
675
|
*.tar.lz*) \
|
@@ -670,9 +679,11 @@ distcheck: dist
|
|
670
679
|
*.tar.Z*) \
|
671
680
|
uncompress -c "$(distdir)".tar.Z | $(am__untar) ;;\
|
672
681
|
*.shar.gz*) \
|
673
|
-
GZIP
|
682
|
+
eval GZIP= gzip $(GZIP_ENV) -dc "$(distdir)".shar.gz | unshar ;;\
|
674
683
|
*.zip*) \
|
675
684
|
unzip "$(distdir)".zip ;;\
|
685
|
+
*.tar.zst*) \
|
686
|
+
zstd -dc "$(distdir)".tar.zst | $(am__untar) ;;\
|
676
687
|
esac
|
677
688
|
chmod -R a-w "$(distdir)"
|
678
689
|
chmod u+w "$(distdir)"
|
@@ -688,7 +699,7 @@ distcheck: dist
|
|
688
699
|
$(DISTCHECK_CONFIGURE_FLAGS) \
|
689
700
|
--srcdir=../.. --prefix="$$dc_install_base" \
|
690
701
|
&& $(MAKE) $(AM_MAKEFLAGS) \
|
691
|
-
&& $(MAKE) $(AM_MAKEFLAGS)
|
702
|
+
&& $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \
|
692
703
|
&& $(MAKE) $(AM_MAKEFLAGS) check \
|
693
704
|
&& $(MAKE) $(AM_MAKEFLAGS) install \
|
694
705
|
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
|
@@ -849,7 +860,7 @@ uninstall-am:
|
|
849
860
|
am--refresh check check-am clean clean-cscope clean-generic \
|
850
861
|
cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
|
851
862
|
dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \
|
852
|
-
distcheck distclean distclean-generic distclean-tags \
|
863
|
+
dist-zstd distcheck distclean distclean-generic distclean-tags \
|
853
864
|
distcleancheck distdir distuninstallcheck dvi dvi-am html \
|
854
865
|
html-am info info-am install install-am install-data \
|
855
866
|
install-data-am install-dvi install-dvi-am install-exec \
|
@@ -911,9 +922,9 @@ uninstall-am:
|
|
911
922
|
|
912
923
|
doc: doxygen-doc
|
913
924
|
|
914
|
-
rice/README.doxygen: README
|
925
|
+
rice/README.doxygen: README.md
|
915
926
|
@echo Generating documentation
|
916
|
-
@$(RUBY) -e 'File.open("README") { |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 " */" } }'
|
927
|
+
@$(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
|
917
928
|
|
918
929
|
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
919
930
|
# Otherwise a system limit (for SysV at least) may be exceeded.
|
data/{README → README.md}
RENAMED
@@ -1,85 +1,87 @@
|
|
1
|
-
|
1
|
+
# Rice - Ruby Interface for C++ Extensions {#mainpage}
|
2
2
|
|
3
|
+
# Introduction {#intro}
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
Rice is a C++ interface to Ruby's C API. It provides a type-safe and
|
5
|
+
Rice is a C++ interface to Ruby's C API. It provides a type-safe and
|
7
6
|
exception-safe interface in order to make embedding Ruby and writing
|
8
|
-
Ruby extensions with C++ easier.
|
9
|
-
ways, but also attempts to provide an object-oriented interface to all
|
7
|
+
Ruby extensions with C++ easier. It is similar to Boost.Python or pybind11
|
8
|
+
in many ways, but also attempts to provide an object-oriented interface to all
|
10
9
|
of the Ruby C API.
|
11
10
|
|
12
11
|
What Rice gives you:
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
- A simple C++-based syntax for wrapping and defining classes
|
13
|
+
- Automatic conversion of exceptions between C++ and Ruby
|
14
|
+
- Smart pointers for handling garbage collection
|
15
|
+
- Wrappers for most builtin types to simplify calling code
|
17
16
|
|
18
|
-
|
17
|
+
# Project Details {#project}
|
19
18
|
|
20
|
-
The source is hosted on
|
19
|
+
The source is hosted on GitHub: http://github.com/jasonroelofs/rice
|
21
20
|
|
22
21
|
Bug tracking: http://github.com/jasonroelofs/rice/issues
|
23
22
|
|
24
|
-
|
23
|
+
API documentation: http://jasonroelofs.github.io/rice
|
24
|
+
|
25
|
+
# Installation {#installation}
|
25
26
|
|
26
|
-
|
27
|
+
~~~
|
27
28
|
gem install rice
|
28
|
-
|
29
|
+
~~~
|
29
30
|
|
30
31
|
Building it locally from a clone of the repository is as follows:
|
31
32
|
|
32
|
-
|
33
|
+
~~~
|
33
34
|
./bootstrap
|
34
35
|
ruby extconf.rb
|
35
36
|
make
|
36
|
-
|
37
|
+
~~~
|
38
|
+
|
39
|
+
Rice is known to work on *nix, OSX, and Windows.
|
37
40
|
|
38
|
-
Rice
|
39
|
-
supported.
|
41
|
+
Rice requires a C++ compiler with support for C++14 or later.
|
40
42
|
|
41
|
-
|
43
|
+
# Tutorial {#tutorial}
|
42
44
|
|
43
|
-
|
45
|
+
## Getting started {#getting_started}
|
44
46
|
|
45
47
|
Writing an extension with Rice is very similar to writing an extension
|
46
48
|
with the C API.
|
47
49
|
|
48
50
|
The first step is to create an extconf.rb file:
|
49
51
|
|
50
|
-
|
52
|
+
~~~{.cpp}
|
51
53
|
require 'mkmf-rice'
|
52
54
|
create_makefile('test')
|
53
|
-
|
55
|
+
~~~
|
54
56
|
|
55
|
-
Note that we use mkmf-rice instead of mkmf
|
57
|
+
Note that we use `mkmf-rice` instead of `mkmf`. This will ensure that the
|
56
58
|
extension will be linked with standard C++ library along with the Rice
|
57
59
|
library, and allow access to the Rice header files.
|
58
60
|
|
59
61
|
Next we create our extension and save it to test.cpp:
|
60
62
|
|
61
|
-
|
63
|
+
~~~{.cpp}
|
62
64
|
extern "C"
|
63
65
|
void Init_test()
|
64
66
|
{
|
65
67
|
}
|
66
|
-
|
68
|
+
~~~
|
67
69
|
|
68
|
-
Note the extern "C" line above.
|
69
|
-
function Init_test should have C linkage and calling convention.
|
70
|
+
Note the extern "C" line above. This tells the compiler that the
|
71
|
+
function `Init_test` should have C linkage and calling convention. This
|
70
72
|
turns off name mangling so that the Ruby interpreter will be able to
|
71
73
|
find the function (remember that Ruby is written in C, not C++).
|
72
74
|
|
73
75
|
So far we haven't put anything into the extension, so it isn't
|
74
|
-
particularly useful.
|
76
|
+
particularly useful. The next step is to define a class so we can add
|
75
77
|
methods to it.
|
76
78
|
|
77
79
|
|
78
|
-
|
80
|
+
## Defining clases {#classes}
|
79
81
|
|
80
|
-
Defining a class in Rice is
|
82
|
+
Defining a class in Rice is a single call:
|
81
83
|
|
82
|
-
|
84
|
+
~~~{.cpp}
|
83
85
|
#include "rice/Class.hpp"
|
84
86
|
|
85
87
|
using namespace Rice;
|
@@ -89,12 +91,12 @@ Defining a class in Rice is easy:
|
|
89
91
|
{
|
90
92
|
Class rb_cTest = define_class("Test");
|
91
93
|
}
|
92
|
-
|
94
|
+
~~~
|
93
95
|
|
94
|
-
This will create a class called Test that inherits from Object
|
95
|
-
wanted to inherit from a different class, we
|
96
|
+
This will create a class called `Test` that inherits from `Object`. If we
|
97
|
+
wanted to inherit from a different class, we do so with the second parameter:
|
96
98
|
|
97
|
-
|
99
|
+
~~~{.cpp}
|
98
100
|
#include "rice/Class.hpp"
|
99
101
|
|
100
102
|
using namespace Rice;
|
@@ -104,34 +106,34 @@ wanted to inherit from a different class, we could easily do so:
|
|
104
106
|
{
|
105
107
|
Class rb_cMySocket = define_class("MySocket", rb_cIO);
|
106
108
|
}
|
107
|
-
|
109
|
+
~~~
|
108
110
|
|
109
|
-
Note the prefix rb_c on the name of the class.
|
110
|
-
that the Ruby interpreter and many extensions tend to use.
|
111
|
-
that this is a class and not some other type of object.
|
111
|
+
Note the prefix rb_c on the name of the class. This is a convention
|
112
|
+
that the Ruby interpreter and many extensions tend to use. It signifies
|
113
|
+
that this is a class and not some other type of object. Some other
|
112
114
|
naming conventions that are commonly used:
|
113
115
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
116
|
+
- rb_c variable name prefix for a Class
|
117
|
+
- rb_m variable name prefix for a Module
|
118
|
+
- rb_e variable name prefix for an Exception type
|
119
|
+
- rb_ function prefix for a function in the Ruby C API
|
120
|
+
- rb_f_ function prefix to differentiate between an API function that
|
119
121
|
takes Ruby objects as arguments and one that takes C argument types
|
120
|
-
|
121
|
-
|
122
|
+
- rb_*_s_ indicates the function is a singleton function
|
123
|
+
- *_m suffix to indicate the function takes variable number of
|
122
124
|
arguments
|
123
125
|
|
124
126
|
|
125
|
-
Also note that we don't include "ruby.h" directly.
|
127
|
+
Also note that we don't include "ruby.h" directly. Rice has a wrapper
|
126
128
|
for ruby.h that handles some compatibility issues across platforms and
|
127
|
-
Ruby versions.
|
129
|
+
Ruby versions. Always include Rice headers before including anything
|
128
130
|
that might include "ruby.h".
|
129
131
|
|
130
|
-
|
132
|
+
## Defining methods {#methods}
|
131
133
|
|
132
134
|
Now let's add a method to our class:
|
133
135
|
|
134
|
-
|
136
|
+
~~~{.cpp}
|
135
137
|
#include "rice/Class.hpp"
|
136
138
|
#include "rice/String.hpp"
|
137
139
|
|
@@ -150,15 +152,15 @@ Now let's add a method to our class:
|
|
150
152
|
define_class("Test")
|
151
153
|
.define_method("hello", &test_hello);
|
152
154
|
}
|
153
|
-
|
155
|
+
~~~
|
154
156
|
|
155
|
-
Here we add a method Test#hello that
|
156
|
-
"Hello, World".
|
157
|
+
Here we add a method `%Test#hello` that returns the string
|
158
|
+
"Hello, World". The method takes self as an implicit parameter, but
|
157
159
|
isn't used, so we comment it out to prevent a compiler warning.
|
158
160
|
|
159
|
-
We could also add an
|
161
|
+
We could also add an `#initialize` method to our class:
|
160
162
|
|
161
|
-
|
163
|
+
~~~{.cpp}
|
162
164
|
#include "rice/Class.hpp"
|
163
165
|
#include "rice/String.hpp"
|
164
166
|
|
@@ -180,21 +182,21 @@ We could also add an #initialize method to our class:
|
|
180
182
|
{
|
181
183
|
Class rb_cTest =
|
182
184
|
define_class("Test")
|
183
|
-
.define_method("initialize", &test_initialize)
|
185
|
+
.define_method("initialize", &test_initialize)
|
184
186
|
.define_method("hello", &test_hello);
|
185
187
|
}
|
186
|
-
|
188
|
+
~~~
|
187
189
|
|
188
|
-
The initialize method sets an instance variable
|
189
|
-
The number is automatically converted to a Fixnum before doing the
|
190
|
+
The `initialize` method sets an instance variable `@foo` to the value 42.
|
191
|
+
The number is automatically converted to a `Fixnum` before doing the
|
190
192
|
assignment.
|
191
193
|
|
192
|
-
Note that we're chaining calls on the Class object.
|
193
|
-
functions in Module and Class return a reference to self
|
194
|
+
Note that we're chaining calls on the `Class` object. Most member
|
195
|
+
functions in `Module` and `Class` return a reference to `self`, so we can
|
194
196
|
chain as many calls as we want to define as many methods as we want.
|
195
197
|
|
196
198
|
|
197
|
-
|
199
|
+
## Wrapping C++ Types {#data_types}
|
198
200
|
|
199
201
|
It's useful to be able to define Ruby classes in a C++ style rather than
|
200
202
|
using the Ruby API directly, but the real power Rice is in wrapping
|
@@ -202,19 +204,19 @@ already-defined C++ types.
|
|
202
204
|
|
203
205
|
Let's assume we have the following C++ class that we want to wrap:
|
204
206
|
|
205
|
-
|
207
|
+
~~~{.cpp}
|
206
208
|
class Test
|
207
209
|
{
|
208
210
|
public:
|
209
211
|
Test();
|
210
212
|
std::string hello();
|
211
213
|
};
|
212
|
-
|
214
|
+
~~~
|
213
215
|
|
214
216
|
This is a C++ version of the Ruby class we just created in the previous
|
215
|
-
section.
|
217
|
+
section. To wrap it:
|
216
218
|
|
217
|
-
|
219
|
+
~~~{.cpp}
|
218
220
|
#include "rice/Data_Type.hpp"
|
219
221
|
#include "rice/Constructor.hpp"
|
220
222
|
|
@@ -228,57 +230,57 @@ section. To wrap it:
|
|
228
230
|
.define_constructor(Constructor<Test>())
|
229
231
|
.define_method("hello", &Test::hello);
|
230
232
|
}
|
231
|
-
|
233
|
+
~~~
|
232
234
|
|
233
|
-
This example is similar to the one before, but we use Data_Type
|
234
|
-
instead of Class and the template version of define_class() instead of
|
235
|
-
the non-template version.
|
236
|
-
between the Ruby class Test and the C++ class Test such that Rice passes
|
237
|
-
member function pointers to define_method()
|
235
|
+
This example is similar to the one before, but we use `Data_Type<>`
|
236
|
+
instead of `Class` and the template version of define_class() instead of
|
237
|
+
the non-template version. This creates a binding in the Rice library
|
238
|
+
between the Ruby class `Test` and the C++ class Test such that Rice passes
|
239
|
+
member function pointers to `define_method()`.
|
238
240
|
|
239
241
|
It is possible to write the conversion functions ourself (as we'll see
|
240
242
|
below), but Rice does all the dirty work for us.
|
241
243
|
|
242
244
|
|
243
|
-
|
245
|
+
## Type conversions {#conversions}
|
244
246
|
|
245
247
|
Let's look again at our example class:
|
246
248
|
|
247
|
-
|
249
|
+
~~~{.cpp}
|
248
250
|
class Test
|
249
251
|
{
|
250
252
|
public:
|
251
253
|
Test();
|
252
254
|
std::string hello();
|
253
255
|
};
|
254
|
-
|
256
|
+
~~~
|
255
257
|
|
256
258
|
When we wrote our class, we never wrote a single line of code to convert
|
257
|
-
the std::string returned by hello() into a Ruby type.
|
259
|
+
the `std::string` returned by `hello()` into a Ruby type. Neverthless, the
|
258
260
|
conversion works, and when we write:
|
259
261
|
|
260
|
-
|
262
|
+
~~~{.cpp}
|
261
263
|
test = Test.new
|
262
264
|
puts test.hello
|
263
|
-
|
265
|
+
~~~
|
264
266
|
|
265
267
|
We get the expected result.
|
266
268
|
|
267
269
|
Rice has two template conversion functions to convert between C++ and
|
268
270
|
Ruby types:
|
269
271
|
|
270
|
-
|
272
|
+
~~~{.cpp}
|
271
273
|
template<typename T>
|
272
274
|
T from_ruby(Object x);
|
273
275
|
|
274
276
|
template<typename T>
|
275
277
|
Object to_ruby(T const & x);
|
276
|
-
|
278
|
+
~~~
|
277
279
|
|
278
|
-
Rice
|
279
|
-
types.
|
280
|
+
Rice includes default specializations for many of the builtin
|
281
|
+
types. To define your own conversion, write a template specialization:
|
280
282
|
|
281
|
-
|
283
|
+
~~~{.cpp}
|
282
284
|
template<>
|
283
285
|
Foo from_ruby<Foo>(Object x)
|
284
286
|
{
|
@@ -290,17 +292,17 @@ types. To define your own conversion, you can write a specialization:
|
|
290
292
|
{
|
291
293
|
// ...
|
292
294
|
}
|
293
|
-
|
295
|
+
~~~
|
294
296
|
|
295
297
|
The implementation of these functions would, of course, depend on the
|
296
|
-
implementation of Foo
|
298
|
+
implementation of `Foo`.
|
297
299
|
|
298
300
|
|
299
|
-
|
301
|
+
## Conversions for wrapped C++ types {#data_conversions}
|
300
302
|
|
301
|
-
Take another look at the wrapper we wrote for the Test class:
|
303
|
+
Take another look at the wrapper we wrote for the `Test` class:
|
302
304
|
|
303
|
-
|
305
|
+
~~~{.cpp}
|
304
306
|
extern "C"
|
305
307
|
void Init_test()
|
306
308
|
{
|
@@ -309,62 +311,62 @@ Take another look at the wrapper we wrote for the Test class:
|
|
309
311
|
.define_constructor(Constructor<Test>())
|
310
312
|
.define_method("hello", &Test::hello);
|
311
313
|
}
|
312
|
-
|
314
|
+
~~~
|
313
315
|
|
314
|
-
When we called define_class<Test
|
316
|
+
When we called `define_class<Test>`, it created a Class for us and
|
315
317
|
automatically registered the new Class with the type system, so that the
|
316
318
|
calls:
|
317
319
|
|
318
|
-
|
320
|
+
~~~{.cpp}
|
319
321
|
Data_Object<Foo> obj(new Foo);
|
320
322
|
Foo * f = from_ruby<Foo *>(obj);
|
321
323
|
Foo const * f = from_ruby<Foo const *>(obj);
|
322
|
-
|
324
|
+
~~~
|
323
325
|
|
324
|
-
|
326
|
+
works as expected.
|
325
327
|
|
326
|
-
The Data_Object class is a wrapper for the Data_Wrap_Struct and the
|
327
|
-
Data_Get_Struct macros in C extensions.
|
328
|
-
unwrap any class that has been assigned to a Data_Type
|
329
|
-
from Object
|
330
|
-
also call on a Data_Object
|
328
|
+
The `Data_Object` class is a wrapper for the `Data_Wrap_Struct` and the
|
329
|
+
`Data_Get_Struct` macros in C extensions. It can be used to wrap or
|
330
|
+
unwrap any class that has been assigned to a `Data_Type`. It inherits
|
331
|
+
from `Object`, so any member functions we can call on an `Object` we can
|
332
|
+
also call on a `Data_Object`:
|
331
333
|
|
332
|
-
|
334
|
+
~~~{.cpp}
|
333
335
|
Object object_id = obj.call("object_id");
|
334
336
|
std::cout << object_id << std::endl;
|
335
|
-
|
337
|
+
~~~
|
336
338
|
|
337
|
-
The Data_Object class can be used to wrap a newly-created object:
|
339
|
+
The `Data_Object` class can be used to wrap a newly-created object:
|
338
340
|
|
339
|
-
|
341
|
+
~~~{.cpp}
|
340
342
|
Data_Object<Foo> foo(new Foo);
|
341
|
-
|
343
|
+
~~~
|
342
344
|
|
343
345
|
or to unwrap an already-created object:
|
344
346
|
|
345
|
-
|
347
|
+
~~~{.cpp}
|
346
348
|
VALUE obj = ...;
|
347
349
|
Data_Object<Foo> foo(obj);
|
348
|
-
|
350
|
+
~~~
|
349
351
|
|
350
|
-
A Data_Object functions like a smart pointer:
|
352
|
+
A `Data_Object` functions like a smart pointer:
|
351
353
|
|
352
|
-
|
354
|
+
~~~{.cpp}
|
353
355
|
Data_Object<Foo> foo(obj);
|
354
356
|
foo->foo();
|
355
357
|
std::cout << *foo << std::endl;
|
356
|
-
|
358
|
+
~~~
|
357
359
|
|
358
|
-
Like a VALUE or an Object
|
359
|
-
by the garbage collector as long as the Data_Object is on the stack.
|
360
|
+
Like a `VALUE` or an `Object`, data stored in a `Data_Object` will be marked
|
361
|
+
by the garbage collector as long as the `Data_Object` is on the stack.
|
360
362
|
|
361
363
|
|
362
|
-
|
364
|
+
## Exceptions {#exception}
|
363
365
|
|
364
366
|
Suppose we added a member function to our example class that throws an
|
365
367
|
exception:
|
366
368
|
|
367
|
-
|
369
|
+
~~~{.cpp}
|
368
370
|
class MyException
|
369
371
|
: public std::exception
|
370
372
|
{
|
@@ -377,11 +379,11 @@ exception:
|
|
377
379
|
std::string hello();
|
378
380
|
void error();
|
379
381
|
};
|
380
|
-
|
382
|
+
~~~
|
381
383
|
|
382
384
|
If we were to wrap this function:
|
383
385
|
|
384
|
-
|
386
|
+
~~~{.cpp}
|
385
387
|
extern "C"
|
386
388
|
void Init_test()
|
387
389
|
{
|
@@ -391,22 +393,22 @@ If we were to wrap this function:
|
|
391
393
|
.define_method("hello", &Test::hello)
|
392
394
|
.define_method("error", &Test::error);
|
393
395
|
}
|
394
|
-
|
396
|
+
~~~
|
395
397
|
|
396
398
|
and call it from inside Ruby:
|
397
399
|
|
398
|
-
|
400
|
+
~~~{.cpp}
|
399
401
|
test = Test.new
|
400
402
|
test.error()
|
401
|
-
|
403
|
+
~~~
|
402
404
|
|
403
|
-
we would get an exception.
|
404
|
-
C++ exception it catches into a Ruby exception.
|
405
|
+
we would get an exception. Rice will automatically convert any
|
406
|
+
C++ exception it catches into a Ruby exception. But what if we wanted
|
405
407
|
to use a custom error message when we convert the exception, or what if
|
406
|
-
we wanted to convert to a different type of exception?
|
407
|
-
|
408
|
+
we wanted to convert to a different type of exception? We can write
|
409
|
+
an exception handler like so:
|
408
410
|
|
409
|
-
|
411
|
+
~~~{.cpp}
|
410
412
|
extern "C"
|
411
413
|
void Init_test()
|
412
414
|
{
|
@@ -417,70 +419,70 @@ this:
|
|
417
419
|
.define_method("hello", &Test::hello)
|
418
420
|
.define_method("error", &Test::error);
|
419
421
|
}
|
420
|
-
|
422
|
+
~~~
|
421
423
|
|
422
|
-
The handle_my_exception function need only rethrow the exception as a
|
423
|
-
Rice::Exception
|
424
|
+
The `handle_my_exception` function need only rethrow the exception as a
|
425
|
+
`Rice::Exception`:
|
424
426
|
|
425
|
-
|
427
|
+
~~~{.cpp}
|
426
428
|
void handle_my_exception(MyException const & ex)
|
427
429
|
{
|
428
430
|
throw Exception(rb_eRuntimeError, "Goodnight, moon");
|
429
431
|
}
|
430
|
-
|
432
|
+
~~~
|
431
433
|
|
432
|
-
And what if we want to call Ruby code from C++?
|
434
|
+
And what if we want to call Ruby code from C++? These exceptions are
|
433
435
|
also converted:
|
434
436
|
|
435
|
-
|
437
|
+
~~~{.cpp}
|
436
438
|
Object o;
|
437
439
|
o.call("some_function_that_raises", 42);
|
438
440
|
|
439
441
|
protect(rb_raise, rb_eRuntimeError, "some exception msg");
|
440
|
-
|
442
|
+
~~~
|
441
443
|
|
442
444
|
Internally whenever Rice catches a C++ or a Ruby exception, it converts
|
443
|
-
it to an Exception object.
|
445
|
+
it to an `Exception` object. This object will later be re-raised as a
|
444
446
|
Ruby exception when control is returned to the Ruby VM.
|
445
447
|
|
446
|
-
Rice uses a similar class called Jump_Tag to handle symbols thrown by
|
447
|
-
Ruby's throw
|
448
|
+
Rice uses a similar class called `Jump_Tag` to handle symbols thrown by
|
449
|
+
Ruby's `throw`/`catch` or other non-local jumps from inside the Ruby VM.
|
448
450
|
|
449
451
|
|
450
|
-
|
452
|
+
## Builtin Types {#builtin}
|
451
453
|
|
452
454
|
You've seen this example:
|
453
455
|
|
454
|
-
|
456
|
+
~~~{.cpp}
|
455
457
|
Object object_id = obj.call("object_id");
|
456
458
|
std::cout << object_id << std::endl;
|
457
|
-
|
459
|
+
~~~
|
458
460
|
|
459
461
|
Rice mimics the Ruby class hierarchy as closely as it can.
|
460
462
|
In fact, the above code also works for Classes:
|
461
463
|
|
462
|
-
|
464
|
+
~~~{.cpp}
|
463
465
|
Class rb_cTest = define_class<Test>("Test");
|
464
466
|
Object object_id = rb_cTest.call("object_id");
|
465
467
|
std::cout << object_id << std::endl;
|
466
|
-
|
468
|
+
~~~
|
467
469
|
|
468
470
|
Rice provides builtin wrappers for many builtin Ruby types, including:
|
469
471
|
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
The Array and Hash types can even be iterated over the same way one
|
472
|
+
- Object
|
473
|
+
- Module
|
474
|
+
- Class
|
475
|
+
- String
|
476
|
+
- Array
|
477
|
+
- Hash
|
478
|
+
- Struct
|
479
|
+
- Symbol
|
480
|
+
- Exception
|
481
|
+
|
482
|
+
The `Array` and `Hash` types can even be iterated over the same way one
|
481
483
|
would iterate over an STL container:
|
482
484
|
|
483
|
-
|
485
|
+
~~~{.cpp}
|
484
486
|
Array a;
|
485
487
|
a.push(to_ruby(42));
|
486
488
|
a.push(to_ruby(43));
|
@@ -491,21 +493,21 @@ would iterate over an STL container:
|
|
491
493
|
{
|
492
494
|
std::cout << *it << std::endl;
|
493
495
|
}
|
494
|
-
|
496
|
+
~~~
|
495
497
|
|
496
|
-
STL algorithms should also work as expected on Array and Hash containers.
|
498
|
+
STL algorithms should also work as expected on `Array` and `Hash` containers.
|
497
499
|
|
498
500
|
|
499
|
-
|
501
|
+
## Inheritance {#inheritance}
|
500
502
|
|
501
|
-
Inheritance is a tricky problem to solve in extensions.
|
503
|
+
Inheritance is a tricky problem to solve in extensions. This is because
|
502
504
|
wrapper functions for base classes typically don't know how to accept
|
503
|
-
pointers to derived classes.
|
505
|
+
pointers to derived classes. It is possible to write this logic, but
|
504
506
|
the code is nontrivial.
|
505
507
|
|
506
|
-
|
508
|
+
Rice also provides a solution to this problem:
|
507
509
|
|
508
|
-
|
510
|
+
~~~{.cpp}
|
509
511
|
class Base
|
510
512
|
{
|
511
513
|
public:
|
@@ -526,33 +528,33 @@ Forunately Rice handles this gracefully:
|
|
526
528
|
Data_Type<Derived> rb_cDerived =
|
527
529
|
define_class<Derived, Base>("Derived");
|
528
530
|
}
|
529
|
-
|
531
|
+
~~~
|
530
532
|
|
531
|
-
The second template parameter to define_class indicates that Derived
|
532
|
-
inherits from Base
|
533
|
+
The second template parameter to define_class indicates that `Derived`
|
534
|
+
inherits from `Base`.
|
533
535
|
|
534
536
|
Rice does not support multiple inheritance.
|
535
537
|
|
536
538
|
|
537
|
-
|
539
|
+
## Overloaded functions {#overloading}
|
538
540
|
|
539
541
|
If you try to create a member function pointer to an overloaded
|
540
|
-
function, you will get an error.
|
542
|
+
function, you will get an error. So how do we wrap classes that have
|
541
543
|
overloaded functions?
|
542
544
|
|
543
545
|
Consider a class that uses this idiom for accessors:
|
544
546
|
|
545
|
-
|
547
|
+
~~~{.cpp}
|
546
548
|
class Container
|
547
549
|
{
|
548
550
|
size_t capacity(); // Get the capacity
|
549
551
|
void capacity(size_t cap); // Set the capacity
|
550
552
|
};
|
551
|
-
|
553
|
+
~~~
|
552
554
|
|
553
|
-
We can wrap this class by using
|
555
|
+
We can wrap this class by using `typedef`s:
|
554
556
|
|
555
|
-
|
557
|
+
~~~{.cpp}
|
556
558
|
extern "C"
|
557
559
|
void Init_Container()
|
558
560
|
{
|
@@ -564,45 +566,44 @@ We can wrap this class by using typedefs:
|
|
564
566
|
.define_method("capacity", get_capacity(&Container::capacity))
|
565
567
|
.define_method("capacity=", set_capacity(&Container::capacity))
|
566
568
|
}
|
567
|
-
|
569
|
+
~~~
|
568
570
|
|
569
571
|
|
570
|
-
|
572
|
+
## User-defined type conversions {#user_defined_conversions}
|
571
573
|
|
572
|
-
Rice provides default conversions for many built-in types.
|
573
|
-
however, the default conversion is not what is expected.
|
574
|
+
Rice provides default conversions for many built-in types. Sometimes,
|
575
|
+
however, the default conversion is not what is expected. For
|
574
576
|
example, consider a function:
|
575
577
|
|
576
|
-
|
578
|
+
~~~{.cpp}
|
577
579
|
void foo(char * x);
|
578
|
-
|
580
|
+
~~~
|
579
581
|
|
580
|
-
Is x a pointer to a single character or a pointer to the first character
|
582
|
+
Is `x` a pointer to a single character or a pointer to the first character
|
581
583
|
of a null-terminated string or a pointer to the first character of an
|
582
584
|
array of char?
|
583
585
|
|
584
586
|
Because the second case is the most common use case (a pointer to the
|
585
587
|
first character of a C string), Rice provides a default conversion that
|
586
|
-
treats a char
|
587
|
-
pointer to a char instead?
|
588
|
+
treats a `char *` as a C string. But suppose the above function actually
|
589
|
+
expects to receive a pointer to a single char instead?
|
588
590
|
|
589
591
|
If we write this:
|
590
592
|
|
591
|
-
|
592
|
-
|
593
|
-
\code
|
593
|
+
~~~{.cpp}
|
594
594
|
extern "C"
|
595
595
|
void Init_test()
|
596
596
|
{
|
597
597
|
define_global_function("foo", &foo);
|
598
598
|
}
|
599
|
-
|
599
|
+
~~~
|
600
600
|
|
601
601
|
It will likely have the wrong behavior.
|
602
602
|
|
603
|
-
To avoid this problem, it is necessary to write a wrapper function
|
603
|
+
To avoid this problem, it is necessary to write a wrapper function where
|
604
|
+
the extension can be more explicit about how to handle the parameters:
|
604
605
|
|
605
|
-
|
606
|
+
~~~{.cpp}
|
606
607
|
Object wrap_foo(Object o)
|
607
608
|
{
|
608
609
|
char c = from_ruby<char>(o);
|
@@ -615,30 +616,30 @@ To avoid this problem, it is necessary to write a wrapper function:
|
|
615
616
|
{
|
616
617
|
define_global_function("foo", &wrap_foo);
|
617
618
|
}
|
618
|
-
|
619
|
+
~~~
|
619
620
|
|
620
|
-
Note that the out parameter is returned from wrap_foo
|
621
|
+
Note that the out parameter is returned from `wrap_foo`, as Ruby does not
|
621
622
|
have pass-by-variable-reference (it uses pass-by-object-reference).
|
622
623
|
|
623
624
|
|
624
|
-
|
625
|
+
## Default Arguments {#default_arguments}
|
625
626
|
|
626
|
-
Going back to our initial C++ class example, lets say that hello() now
|
627
|
+
Going back to our initial C++ class example, lets say that `hello()` now
|
627
628
|
takes more arguments, one of which has a default value:
|
628
629
|
|
629
|
-
|
630
|
+
~~~{.cpp}
|
630
631
|
class Test
|
631
632
|
{
|
632
633
|
public:
|
633
634
|
Test();
|
634
635
|
std::string hello(std::string first, std::string second = "world");
|
635
636
|
};
|
636
|
-
|
637
|
+
~~~
|
637
638
|
|
638
639
|
As default parameter information is not available through templates,
|
639
|
-
it is necessary to define this in Rice explicitly using Rice::Arg
|
640
|
+
it is necessary to define this in Rice explicitly using `Rice::Arg`:
|
640
641
|
|
641
|
-
|
642
|
+
~~~{.cpp}
|
642
643
|
#include "rice/Data_Type.hpp"
|
643
644
|
#include "rice/Constructor.hpp"
|
644
645
|
|
@@ -655,70 +656,70 @@ it is necessary to define this in Rice explicitly using Rice::Arg:
|
|
655
656
|
(Arg("hello"), Arg("second") = "world")
|
656
657
|
);
|
657
658
|
}
|
658
|
-
|
659
|
+
~~~
|
659
660
|
|
660
|
-
The syntax here is
|
661
|
-
parameter is not important here (
|
661
|
+
The syntax here is `Arg(nameOfParameter)[ = defaultValue]`. The name of the
|
662
|
+
parameter is not important here (it is for readability), but the value set via `operator=`
|
662
663
|
must match the type of the parameter. As such it may be necessary to
|
663
664
|
explicitly cast the default value.
|
664
665
|
|
665
|
-
|
666
|
+
~~~{.cpp}
|
666
667
|
.define_method("hello",
|
667
668
|
&Test::hello,
|
668
669
|
(Arg("hello"), Arg("second") = (std::string)"world")
|
669
670
|
);
|
670
|
-
|
671
|
+
~~~
|
671
672
|
|
672
|
-
These Rice::Arg objects must be in the correct order and must be
|
673
|
+
These `Rice::Arg` objects must be in the correct order and must be
|
673
674
|
surrounded with parentheses if more than one exists.
|
674
675
|
|
675
676
|
Now, Ruby will now know about the default arguments, and this wrapper
|
676
677
|
can be used as expected:
|
677
678
|
|
678
|
-
|
679
|
+
~~~{.cpp}
|
679
680
|
t = Test.new
|
680
681
|
t.hello("hello")
|
681
682
|
t.hello("goodnight", "moon")
|
682
|
-
|
683
|
+
~~~
|
683
684
|
|
684
685
|
This also works with Constructors:
|
685
686
|
|
686
|
-
|
687
|
+
~~~{.cpp}
|
687
688
|
.define_constructor(Constructor<SomeClass, int, int>(),
|
688
689
|
( Arg("arg1") = 1, Arg("otherArg") = 12 );
|
689
|
-
|
690
|
+
~~~
|
690
691
|
|
691
|
-
|
692
|
+
## Director {#director}
|
692
693
|
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
694
|
+
Polymorphism creates yet another wrinkle in building exceptions around C++ code,
|
695
|
+
because now we have to deal with cross-language polymorphism, where C++ can call
|
696
|
+
into a Ruby subclass, and a Ruby subclass can `super` back into C++ land. `super`
|
697
|
+
calls already work through define_class, but making code travel from C++ into Ruby
|
698
|
+
via polymorphism is tricker. Rice provides the `Rice::Director` class and the
|
699
|
+
`define_director` method to enable this code path.
|
699
700
|
|
700
|
-
Like SWIG_Director
|
701
|
-
to properly send execution up or down the object
|
701
|
+
Like `SWIG_Director`, `Rice::Director` is a class that is used to build a proxy class
|
702
|
+
to properly send execution up or down the object hierarchy for that class. Take
|
702
703
|
the following class:
|
703
704
|
|
704
|
-
|
705
|
+
~~~{.cpp}
|
705
706
|
class VirtualBase {
|
706
707
|
public:
|
707
708
|
VirtualBase();
|
708
709
|
virtual int doWork();
|
709
710
|
virtual int processWorker() = 0;
|
710
711
|
};
|
711
|
-
|
712
|
+
~~~
|
712
713
|
|
713
|
-
Due to the abstract nature of this class,
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
any Ruby subclasses.
|
714
|
+
Due to the abstract nature of this class, we cannot directly wrap it in Rice, as
|
715
|
+
any C++ compiler will complain about trying to instantiate a virtual class.
|
716
|
+
Even without the pure virtual function, any call to `VirtualBase::doWork` will stop
|
717
|
+
at the C++ level and execution will not pass down into any Ruby subclasses.
|
718
718
|
|
719
|
-
To properly wrap both of these methods, use a Rice::Director subclass as a proxy
|
719
|
+
To properly wrap both of these methods, use a `Rice::Director` subclass as a proxy
|
720
|
+
and use this new proxy class as the type to wrap with `define_class`:
|
720
721
|
|
721
|
-
|
722
|
+
~~~{.cpp}
|
722
723
|
#include "rice/Director.hpp"
|
723
724
|
|
724
725
|
class VirtualBaseProxy : public VirtualBase, public Rice::Director {
|
@@ -741,27 +742,27 @@ To properly wrap both of these methods, use a Rice::Director subclass as a proxy
|
|
741
742
|
raisePureVirtual();
|
742
743
|
}
|
743
744
|
};
|
744
|
-
|
745
|
+
~~~
|
745
746
|
|
746
747
|
There is a lot going on here, so we'll go through each part.
|
747
748
|
|
748
|
-
|
749
|
+
~~~{.cpp}
|
749
750
|
class VirtualBaseProxy : public Virtualbase, public Rice::Director {
|
750
|
-
|
751
|
+
~~~
|
751
752
|
|
752
|
-
First, the class needs to subclass both the virtual class in question and Rice::Director
|
753
|
+
First, the class needs to subclass both the virtual class in question and `Rice::Director`.
|
753
754
|
|
754
|
-
|
755
|
+
~~~{.cpp}
|
755
756
|
public:
|
756
757
|
VirtualBaseProxy(Object self) : Rice::Director(self) { }
|
757
|
-
|
758
|
+
~~~
|
758
759
|
|
759
|
-
For Rice::Director to work its magic, every instance of this class needs to
|
760
|
-
have a handle to
|
761
|
-
must take a Rice::Object as the first argument and pass it up into
|
762
|
-
Rice::Director
|
760
|
+
For `Rice::Director` to work its magic, every instance of this class needs to
|
761
|
+
have a handle to its Ruby instance. The constructor
|
762
|
+
must take a `Rice::Object` as the first argument and pass it up into
|
763
|
+
`Rice::Director`. The code here is the minimum required for a `Rice::Director` proxy.
|
763
764
|
|
764
|
-
|
765
|
+
~~~{.cpp}
|
765
766
|
virtual int doWork() {
|
766
767
|
return from_ruby<int>( getSelf().call("do_work") );
|
767
768
|
}
|
@@ -769,33 +770,29 @@ Rice::Director. The code here is the minimum required for a Rice::Director proxy
|
|
769
770
|
int default_doWork() {
|
770
771
|
return VirtualBase::doWork();
|
771
772
|
}
|
772
|
-
|
773
|
-
|
774
|
-
Here the directory proxy overrides the methods for Ruby exposure and
|
775
|
-
implements the required actions to pass flow around the heirarchy
|
776
|
-
appropriately. The pattern shown here is that the actual override will
|
777
|
-
call down into Ruby, handling any type conversions, while a
|
778
|
-
default_methodName method handles calling up into C++ and will be the
|
779
|
-
method wrapped into Rice.
|
773
|
+
~~~
|
780
774
|
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
775
|
+
Here the proxy class implements the virtual methods and provides implementations
|
776
|
+
that delegate execution in the correct direction. The actual method calls into Ruby,
|
777
|
+
providing all necessary type conversions to and from C++ types. The other method
|
778
|
+
is how Ruby calls back into C++ and is the method that must be exposed with
|
779
|
+
`define_method`. The `default_` prefix is a naming convention to help keep straight
|
780
|
+
which methods perform which function. If Ruby should never call into C++, then the
|
781
|
+
`default_` implementation should call `raisePureVirtual()`:
|
785
782
|
|
786
|
-
|
783
|
+
~~~{.cpp}
|
787
784
|
int default_processWorker() {
|
788
785
|
raisePureVirtual();
|
789
786
|
}
|
790
|
-
|
787
|
+
~~~
|
791
788
|
|
792
|
-
The method raisePureVirtual() exists to allow wrapping a pure virtual method into Ruby
|
793
|
-
(and ensuring compliation is possible) but making sure any users of this extension are
|
789
|
+
The method `raisePureVirtual()` exists to allow wrapping a pure virtual method into Ruby
|
790
|
+
(and ensuring compliation is possible) but making sure any users of this extension are
|
794
791
|
informed quickly that there's nothing callable in the C++ side of the library.
|
795
792
|
|
796
793
|
Once the proxy class is built, it's time to wrap it into Ruby:
|
797
794
|
|
798
|
-
|
795
|
+
~~~{.cpp}
|
799
796
|
extern "C"
|
800
797
|
void Init_virtual() {
|
801
798
|
define_class<VirtualBase>("VirtualBase")
|
@@ -804,28 +801,28 @@ void Init_virtual() {
|
|
804
801
|
.define_method("do_work", &VirtualBaseProxy::default_doWork)
|
805
802
|
.define_method("process_worker", &VirtualBaseProxy::default_processWorker);
|
806
803
|
}
|
807
|
-
|
804
|
+
~~~
|
808
805
|
|
809
806
|
The wrapping is the same as is described earlier in this document. Expose the class
|
810
|
-
VirtualBase
|
811
|
-
Rice::Data_Type::define_director
|
807
|
+
`VirtualBase`, and register `VirtualBaseProxy` as a director proxy of `VirtualBase` with
|
808
|
+
`Rice::Data_Type::define_director`, then `define_method`s pointing to the proxy methods as necessary.
|
812
809
|
|
813
|
-
You must use the Rice::Director proxy class in the Constructor line, this allows proper
|
810
|
+
You must use the `Rice::Director` proxy class in the Constructor line, this allows proper
|
814
811
|
object construction / destruction of the types in question.
|
815
812
|
|
816
|
-
|
813
|
+
## Implicit Casting {#implicit_cast}
|
817
814
|
|
818
815
|
There are times when a library exposes classes that, while unrelated, are
|
819
816
|
built to be interchangeable across the library. One example of this is found in
|
820
817
|
the Open Source 3d rendering engine <a
|
821
818
|
href="http://www.ogre3d.org/">OGRE</a>: Ogre::Degree and Ogre::Radian.
|
822
|
-
When a given method takes a Radian, you're free to pass in a Degree, and vice versa.
|
819
|
+
When a given method takes a Radian, you're free to pass in a Degree, and vice versa.
|
823
820
|
|
824
821
|
Rice cannot automatically figure out if this kind of functionality is
|
825
822
|
possible in a given library but it does provide an API for defining
|
826
|
-
these relationships: Rice::define_implicit_cast<From, To>()
|
823
|
+
these relationships: `Rice::define_implicit_cast<From, To>()`.
|
827
824
|
|
828
|
-
|
825
|
+
~~~{.cpp}
|
829
826
|
class Degree { ... };
|
830
827
|
class Radian { ... };
|
831
828
|
|
@@ -839,79 +836,79 @@ void Init_implicit() {
|
|
839
836
|
define_implicit_cast<Degree, Radian>();
|
840
837
|
define_implicit_cast<Radian, Degree>();
|
841
838
|
}
|
842
|
-
|
839
|
+
~~~
|
843
840
|
|
844
|
-
Using Rice::define_implicit_cast has the following requirements:
|
841
|
+
Using `Rice::define_implicit_cast` has the following requirements:
|
845
842
|
|
846
|
-
|
847
|
-
|
848
|
-
|
843
|
+
- The two types must be bound in Rice before defining the cast.
|
844
|
+
- The classes must have constructors that take the other type.
|
845
|
+
- This feature cannot be used with fundamental types.
|
849
846
|
|
850
847
|
To see a full example of this feature, please check out
|
851
848
|
test/test_Data_Type.cpp.
|
852
849
|
|
853
|
-
|
850
|
+
# Motivation {#motivation}
|
854
851
|
|
855
852
|
There are a number of common problems when writing C or C++ extensions
|
856
853
|
for Ruby:
|
857
854
|
|
858
|
-
|
859
|
-
VALUE.
|
855
|
+
- Type safety. It is easy to mix-up integral types such as ID and
|
856
|
+
VALUE. Some of the functions in the Ruby API are not consistent with
|
860
857
|
which types they take (e.g. rb_const_defined takes an ID and
|
861
858
|
rb_mod_remove_const takes a Symbol).
|
862
859
|
|
863
|
-
|
864
|
-
function takes is easy to get wrong.
|
860
|
+
- DRY principle. Specifying the number of arguments that each wrapped
|
861
|
+
function takes is easy to get wrong. Adding a new argument to the
|
865
862
|
function means that the number of arguments passed to rb_define_method
|
866
863
|
must also be updated.
|
867
864
|
|
868
|
-
|
869
|
-
to and from ruby types.
|
870
|
-
different forms.
|
865
|
+
- Type conversion. There are many different functions to convert data
|
866
|
+
to and from ruby types. Many of them have different semantics or
|
867
|
+
different forms. For example, to convert a string, one might use the
|
871
868
|
StringValue macro, but to convert a fixnum, one might use FIX2INT.
|
872
869
|
Unwrapping previously wrapped C data uses yet another form.
|
873
870
|
|
874
|
-
|
871
|
+
- Exception safety. It is imperative that C++ exceptions never make
|
875
872
|
their way into C code, and it is also imperative that a Ruby exception
|
876
873
|
never escape while there are objects on the stack with nontrivial
|
877
|
-
destructors.
|
874
|
+
destructors. Rules for when it is okay to use which exceptions are
|
878
875
|
difficult to get right, especially as code is maintained through time.
|
879
876
|
|
880
|
-
|
877
|
+
- Thread safety. Because the Ruby interpreter is not thread-safe,
|
881
878
|
the Ruby interpreter must not be run from more than one thread.
|
882
879
|
Because of tricks the GC and scheduler play with the C stack, it's not
|
883
880
|
enough to ensure that only one thread runs the interpreter at any
|
884
881
|
given time; once the interpreter has been run from one thread, it must
|
885
|
-
only ever be run from that thread in the future.
|
882
|
+
only ever be run from that thread in the future. Additionally,
|
886
883
|
because Ruby copies the stack when it switches threads, C++ code must
|
887
884
|
be careful not to access objects in one Ruby thread that were created
|
888
885
|
on the stack in another Ruby thread.
|
889
886
|
|
890
|
-
|
887
|
+
- C-based API. The Ruby API is not always convenient for accessing
|
891
888
|
Ruby data structurs such as Hash and Array, especially when writing C++
|
892
889
|
code, as the interface for these containers is not consistent with
|
893
890
|
standard containers.
|
894
891
|
|
895
|
-
|
896
|
-
follow the C calling convention.
|
892
|
+
- Calling convention. Function pointers passed into the Ruby API must
|
893
|
+
follow the C calling convention. This means that it is not possible to
|
897
894
|
pass a pointer to a template function or static member function (that
|
898
895
|
is, it will work on some platforms, but isn't portable).
|
899
896
|
|
900
|
-
|
897
|
+
- Inheritance. When wrapping C++ objects, it is easy to store a
|
901
898
|
pointer to a derived class, but then methods in the base class must have
|
902
|
-
knowledge of the derived class in order to unwrap the object.
|
899
|
+
knowledge of the derived class in order to unwrap the object. It is
|
903
900
|
possible to always store a pointer to the base class and then
|
904
901
|
dynamic_cast the pointer to the derived type when necessary, but this
|
905
902
|
can be slow and cumbersome, and it isn't likely to work with multiple
|
906
|
-
inheritance.
|
903
|
+
inheritance. A system that properly handles inheritance for all corner
|
907
904
|
cases is nontrivial.
|
908
905
|
|
909
|
-
|
910
|
-
the Ruby object model uses single inheritance with mixins.
|
906
|
+
- Multiple inheritance. C++ supports true multiple inheritance, but
|
907
|
+
the Ruby object model uses single inheritance with mixins. When
|
911
908
|
wrapping a library whose public interface uses multiple inheritance,
|
912
909
|
care must be taken in constructing the mapping.
|
913
910
|
|
914
|
-
|
911
|
+
- GC safety. All live Ruby objects must be marked during the garbage
|
915
912
|
collector's mark phase, otherwise they will be prematurely destroyed.
|
916
913
|
The general rule is that object references stored on the heap should be
|
917
914
|
either registered with rb_gc_register_address or marked by a data
|
@@ -919,96 +916,96 @@ object's mark function; object references stored on the stack will be
|
|
919
916
|
automatically marked, provided the Ruby interpreter was properly
|
920
917
|
initialized at startup.
|
921
918
|
|
922
|
-
|
923
|
-
typically implements callbacks via procs.
|
919
|
+
- Callbacks. C implements callbacks via function pointers, while Ruby
|
920
|
+
typically implements callbacks via procs. Writing an adapter function
|
924
921
|
to call the proc is not difficult, but there is much opportunity for
|
925
922
|
error (particularly with exception-safety).
|
926
923
|
|
927
|
-
|
928
|
-
are not marshalable.
|
924
|
+
- Data serialization. By default data objects defined at the C layer
|
925
|
+
are not marshalable. The user must explicitly define functions to
|
929
926
|
marshal the data member-by-member.
|
930
927
|
|
931
928
|
Rice addresses these issues in many ways:
|
932
929
|
|
933
|
-
|
934
|
-
such as Object, Identifier, Class, Module, and String.
|
930
|
+
- Type safety. Rice provides encapsulation for all builtin types,
|
931
|
+
such as Object, Identifier, Class, Module, and String. It
|
935
932
|
automatically checks the dynamic type of an object before constructing
|
936
933
|
an instance of a wrapper.
|
937
934
|
|
938
|
-
|
935
|
+
- DRY principle. Rice uses introspection through the use of templates
|
939
936
|
and function overloading to automatically determine the number and types
|
940
|
-
of arguments to functions.
|
937
|
+
of arguments to functions. Default arguments must still be handled
|
941
938
|
explicitly, however.
|
942
939
|
|
943
|
-
|
940
|
+
- Type conversions. Rice provides cast-style to_ruby<> and
|
944
941
|
from_ruby<> template functions to simplify explicit type conversions.
|
945
942
|
Automatic type conversions for parameters and return values are
|
946
943
|
generated for all wrapped functions.
|
947
944
|
|
948
|
-
|
949
|
-
provides a mechanism for converting user-defined exception types.
|
945
|
+
- Exception safety. Rice automatically converts common exceptions and
|
946
|
+
provides a mechanism for converting user-defined exception types. Rice
|
950
947
|
also provides convenience functions for converting exceptions when
|
951
948
|
calling back into ruby code.
|
952
949
|
|
953
|
-
|
954
|
-
safety.
|
950
|
+
- Thread safety. Rice provides no mechanisms for dealing with thread
|
951
|
+
safety. Many common thread safety issues should be alleviated by YARV,
|
955
952
|
which supports POSIX threads.
|
956
953
|
|
957
|
-
|
954
|
+
- C++-based API. Rice provides an object-oriented C++-style API to
|
958
955
|
most common functions in the Ruby C API.
|
959
956
|
|
960
|
-
|
957
|
+
- Calling convention. Rice automatically uses C calling convention
|
961
958
|
for all function pointers passed into the Ruby API.
|
962
959
|
|
963
|
-
|
960
|
+
- Inheritance. Rice provides automatic conversion to the base class
|
964
961
|
type when a wrapped member function is called on the base class.
|
965
962
|
|
966
|
-
|
967
|
-
inheritance.
|
963
|
+
- Multiple inheritance. Rice provides no mechanism for multiple
|
964
|
+
inheritance. Multiple inheritance can be simulated via mixins, though
|
968
965
|
this is not yet as easy as it could be.
|
969
966
|
|
970
|
-
|
971
|
-
interacting with the garbage collector.
|
967
|
+
- GC safety. Rice provides a handful of convenience classes for
|
968
|
+
interacting with the garbage collector. There are still basic rules
|
972
969
|
which must be followed to ensure that objects get properly destroyed.
|
973
970
|
|
974
|
-
|
971
|
+
- Callbacks. Rice provides a handful of convenience classes for
|
975
972
|
dealing with callbacks.
|
976
973
|
|
977
|
-
|
974
|
+
- Data serialization. Rice provides no mechanism for data
|
978
975
|
serialization, but it is likely this may be added in a future release.
|
979
976
|
|
980
977
|
|
981
|
-
|
978
|
+
# What Rice is Not {#what_not}
|
982
979
|
|
983
|
-
There are a number projects which server similar functions to Rice.
|
984
|
-
such popular projects are SWIG and Boost.Python.
|
980
|
+
There are a number projects which server similar functions to Rice. Two
|
981
|
+
such popular projects are SWIG and Boost.Python. Rice has some
|
985
982
|
distinct features which set it apart from both of these projects.
|
986
983
|
|
987
|
-
Rice is not trying to replace SWIG.
|
988
|
-
interface generator.
|
989
|
-
Ruby C API.
|
984
|
+
Rice is not trying to replace SWIG. Rice is not a generic wrapper
|
985
|
+
interface generator. Rice is a C++ library for interfacing with the
|
986
|
+
Ruby C API. This provides a very natural way for C++ programmers to
|
990
987
|
wrap their C++ code, without having to learn a new domain-specific
|
991
|
-
language.
|
992
|
-
together; a SWIG module could be written to generate Rice code.
|
988
|
+
language. However, there is no reason why SWIG and Rice could not work
|
989
|
+
together; a SWIG module could be written to generate Rice code. Such a
|
993
990
|
module would combine the portability of SWIG with the maintainability of
|
994
991
|
Rice (I have written extensions using both, and I have found Rice
|
995
992
|
extensions to be more maintainable when the interface is constantly
|
996
|
-
changing.
|
993
|
+
changing. Your mileage may vary).
|
997
994
|
|
998
995
|
Rice is also not trying to simply be a Ruby version of Boost.Python.
|
999
996
|
Rice does use some of the same template tricks that Boost.Python uses,
|
1000
|
-
however there are some important distinctions.
|
997
|
+
however there are some important distinctions. First of all,
|
1001
998
|
Boost.Python attempts to create a declarative DSL in C++ using
|
1002
|
-
templates.
|
999
|
+
templates. Rice is a wrapper around the Ruby C API and attempts to make
|
1003
1000
|
its interface look like an OO version of the API; this means that class
|
1004
|
-
declarations look procedural rather than declarative.
|
1005
|
-
Ruby object model is different from the python object model.
|
1001
|
+
declarations look procedural rather than declarative. Secondly, the
|
1002
|
+
Ruby object model is different from the python object model. This is
|
1006
1003
|
reflected in the interface to Rice; it mimics the Ruby object model at
|
1007
|
-
the C++ level.
|
1004
|
+
the C++ level. Thirdly, Rice uses Ruby as a code generator; I find this
|
1008
1005
|
to be much more readable than using the Boost preprocessor library.
|
1009
1006
|
|
1010
1007
|
|
1011
|
-
|
1008
|
+
# History {#history}
|
1012
1009
|
|
1013
1010
|
Rice originated as Excruby, a project to interface with C++-based trading
|
1014
1011
|
software at Automated Trading Desk in Mount Pleasant, South Carolina.
|
@@ -1017,7 +1014,7 @@ today, and did not suit the needs of the project.
|
|
1017
1014
|
|
1018
1015
|
Excruby was written not as a wrapper for the Ruby API, but rather as a
|
1019
1016
|
set of helper functions and classes for interfacing with the Ruby
|
1020
|
-
interpreter in an exception-safe manner.
|
1017
|
+
interpreter in an exception-safe manner. Over the course of five years,
|
1021
1018
|
the project grew into wrappers for pieces of the API, but the original
|
1022
1019
|
helper functions remained as part of the public interface.
|
1023
1020
|
|
@@ -1026,30 +1023,28 @@ multiple ways of accomplishing most tasks -- directly through the C API,
|
|
1026
1023
|
through a low-level wrapper around the C API, and through a high-level
|
1027
1024
|
abstraction of the lower-level interfaces.
|
1028
1025
|
|
1029
|
-
Rice was then born in an attempt to clean up the interface.
|
1026
|
+
Rice was then born in an attempt to clean up the interface. Rice keeps
|
1030
1027
|
the lower-level wrappers, but as an implementation detail; the public
|
1031
1028
|
interface is truly a high-level abstraction around the Ruby C API.
|
1032
1029
|
|
1033
1030
|
|
1034
|
-
|
1031
|
+
# The GC {#gc}
|
1035
1032
|
|
1036
|
-
|
1033
|
+
- Objects are not automatically registered with the garbage collector.
|
1037
1034
|
|
1038
|
-
|
1035
|
+
- If an Object is on the stack, it does not need to be registered with
|
1039
1036
|
the garbage collector.
|
1040
1037
|
|
1041
|
-
|
1038
|
+
- If an Object is allocated on the heap or if it is a member of an
|
1042
1039
|
object that might be allocated on the heap, use an
|
1043
1040
|
Rice::Address_Registration_Guard to register the object with the garbage
|
1044
1041
|
collector.
|
1045
1042
|
|
1046
|
-
|
1043
|
+
- If a reference counted object is being wrapped, or if another type
|
1047
1044
|
of smart pointer is wrapped, ensure that only one mechanism is used to
|
1048
|
-
destroy the object.
|
1045
|
+
destroy the object. In general, the smart pointer manages the
|
1049
1046
|
allocation of the object, and Ruby should hold only a reference to the
|
1050
|
-
smart pointer.
|
1047
|
+
smart pointer. When the garbage collector determines that it is time to
|
1051
1048
|
clean up the object, the smart pointer will be destroyed, decrementing
|
1052
1049
|
the reference count; when the reference count drops to 0, underlying
|
1053
1050
|
object will be destroyed.
|
1054
|
-
|
1055
|
-
vim:ft=cpp:tw=72:ts=2:sw=2:fo=cqrtn:noci:si
|