rice 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|