ruby-bindgen 1.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.
Files changed (115) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +7 -0
  3. data/LICENSE +25 -0
  4. data/README.md +68 -0
  5. data/Rakefile +8 -0
  6. data/bin/ruby-bindgen +133 -0
  7. data/docs/architecture.md +238 -0
  8. data/docs/c/c_bindings.md +65 -0
  9. data/docs/c/constants.md +21 -0
  10. data/docs/c/customizing.md +19 -0
  11. data/docs/c/filtering.md +24 -0
  12. data/docs/c/getting_started.md +56 -0
  13. data/docs/c/library_loading.md +53 -0
  14. data/docs/c/output.md +96 -0
  15. data/docs/c/types.md +61 -0
  16. data/docs/c/version_guards.md +105 -0
  17. data/docs/cmake/cmake_bindings.md +19 -0
  18. data/docs/cmake/filtering.md +26 -0
  19. data/docs/cmake/getting_started.md +52 -0
  20. data/docs/cmake/output.md +110 -0
  21. data/docs/configuration.md +351 -0
  22. data/docs/contributing.md +68 -0
  23. data/docs/cpp/buffers.md +24 -0
  24. data/docs/cpp/classes.md +139 -0
  25. data/docs/cpp/cpp_bindings.md +29 -0
  26. data/docs/cpp/customizing.md +124 -0
  27. data/docs/cpp/enums.md +42 -0
  28. data/docs/cpp/filtering.md +35 -0
  29. data/docs/cpp/getting_started.md +80 -0
  30. data/docs/cpp/iterators.md +94 -0
  31. data/docs/cpp/operators.md +170 -0
  32. data/docs/cpp/output.md +125 -0
  33. data/docs/cpp/templates.md +114 -0
  34. data/docs/examples.md +133 -0
  35. data/docs/index.md +133 -0
  36. data/docs/prior_art.md +37 -0
  37. data/docs/troubleshooting.md +243 -0
  38. data/docs/type_spelling.md +200 -0
  39. data/docs/updating_bindings.md +55 -0
  40. data/docs/version_guards.md +69 -0
  41. data/lib/ruby-bindgen/config.rb +63 -0
  42. data/lib/ruby-bindgen/generators/cmake/cmake.rb +171 -0
  43. data/lib/ruby-bindgen/generators/cmake/directory.erb +29 -0
  44. data/lib/ruby-bindgen/generators/cmake/guard.rb +55 -0
  45. data/lib/ruby-bindgen/generators/cmake/presets.erb +232 -0
  46. data/lib/ruby-bindgen/generators/cmake/project.erb +89 -0
  47. data/lib/ruby-bindgen/generators/ffi/callback.erb +1 -0
  48. data/lib/ruby-bindgen/generators/ffi/constant.erb +1 -0
  49. data/lib/ruby-bindgen/generators/ffi/enum_constant_decl.erb +1 -0
  50. data/lib/ruby-bindgen/generators/ffi/enum_decl.erb +4 -0
  51. data/lib/ruby-bindgen/generators/ffi/enum_decl_anonymous.erb +4 -0
  52. data/lib/ruby-bindgen/generators/ffi/ffi.rb +687 -0
  53. data/lib/ruby-bindgen/generators/ffi/field_decl.erb +1 -0
  54. data/lib/ruby-bindgen/generators/ffi/function.erb +5 -0
  55. data/lib/ruby-bindgen/generators/ffi/library.erb +39 -0
  56. data/lib/ruby-bindgen/generators/ffi/project.erb +18 -0
  57. data/lib/ruby-bindgen/generators/ffi/struct.erb +6 -0
  58. data/lib/ruby-bindgen/generators/ffi/translation_unit.erb +9 -0
  59. data/lib/ruby-bindgen/generators/ffi/typedef_decl.erb +1 -0
  60. data/lib/ruby-bindgen/generators/ffi/union.erb +6 -0
  61. data/lib/ruby-bindgen/generators/ffi/variable.erb +1 -0
  62. data/lib/ruby-bindgen/generators/ffi/version.erb +9 -0
  63. data/lib/ruby-bindgen/generators/ffi/version_method.erb +5 -0
  64. data/lib/ruby-bindgen/generators/generator.rb +52 -0
  65. data/lib/ruby-bindgen/generators/rice/auto_generated_base_class.erb +5 -0
  66. data/lib/ruby-bindgen/generators/rice/class.erb +31 -0
  67. data/lib/ruby-bindgen/generators/rice/class_template.erb +9 -0
  68. data/lib/ruby-bindgen/generators/rice/class_template_specialization.erb +10 -0
  69. data/lib/ruby-bindgen/generators/rice/constant.erb +9 -0
  70. data/lib/ruby-bindgen/generators/rice/constructor.erb +1 -0
  71. data/lib/ruby-bindgen/generators/rice/conversion_function.erb +4 -0
  72. data/lib/ruby-bindgen/generators/rice/cxx_iterator_method.erb +1 -0
  73. data/lib/ruby-bindgen/generators/rice/cxx_method.erb +6 -0
  74. data/lib/ruby-bindgen/generators/rice/enum_constant_decl.erb +7 -0
  75. data/lib/ruby-bindgen/generators/rice/enum_decl.erb +6 -0
  76. data/lib/ruby-bindgen/generators/rice/field_decl.erb +8 -0
  77. data/lib/ruby-bindgen/generators/rice/function.erb +6 -0
  78. data/lib/ruby-bindgen/generators/rice/function_pointer.rb +68 -0
  79. data/lib/ruby-bindgen/generators/rice/incomplete_class.erb +3 -0
  80. data/lib/ruby-bindgen/generators/rice/iterator_alias.erb +1 -0
  81. data/lib/ruby-bindgen/generators/rice/iterator_collector.rb +159 -0
  82. data/lib/ruby-bindgen/generators/rice/namespace.erb +5 -0
  83. data/lib/ruby-bindgen/generators/rice/non_member_operator_binary.erb +4 -0
  84. data/lib/ruby-bindgen/generators/rice/non_member_operator_inspect.erb +6 -0
  85. data/lib/ruby-bindgen/generators/rice/non_member_operator_unary.erb +4 -0
  86. data/lib/ruby-bindgen/generators/rice/operator[].erb +4 -0
  87. data/lib/ruby-bindgen/generators/rice/project.cpp.erb +18 -0
  88. data/lib/ruby-bindgen/generators/rice/project.hpp.erb +13 -0
  89. data/lib/ruby-bindgen/generators/rice/reference_qualifier.rb +495 -0
  90. data/lib/ruby-bindgen/generators/rice/rice.rb +1724 -0
  91. data/lib/ruby-bindgen/generators/rice/rice_include.hpp.erb +7 -0
  92. data/lib/ruby-bindgen/generators/rice/signature_builder.rb +230 -0
  93. data/lib/ruby-bindgen/generators/rice/template_resolver.rb +585 -0
  94. data/lib/ruby-bindgen/generators/rice/translation_unit.cpp.erb +40 -0
  95. data/lib/ruby-bindgen/generators/rice/translation_unit.hpp.erb +7 -0
  96. data/lib/ruby-bindgen/generators/rice/translation_unit.ipp.erb +3 -0
  97. data/lib/ruby-bindgen/generators/rice/type_index.rb +117 -0
  98. data/lib/ruby-bindgen/generators/rice/type_speller.rb +509 -0
  99. data/lib/ruby-bindgen/generators/rice/union.erb +5 -0
  100. data/lib/ruby-bindgen/generators/rice/variable.erb +5 -0
  101. data/lib/ruby-bindgen/inputter.rb +54 -0
  102. data/lib/ruby-bindgen/name_mapper.rb +65 -0
  103. data/lib/ruby-bindgen/namer.rb +138 -0
  104. data/lib/ruby-bindgen/outputter.rb +40 -0
  105. data/lib/ruby-bindgen/parser.rb +82 -0
  106. data/lib/ruby-bindgen/refinements/cursor.rb +57 -0
  107. data/lib/ruby-bindgen/refinements/string.rb +41 -0
  108. data/lib/ruby-bindgen/symbol_candidates.rb +282 -0
  109. data/lib/ruby-bindgen/symbol_entry.rb +21 -0
  110. data/lib/ruby-bindgen/symbols.rb +107 -0
  111. data/lib/ruby-bindgen/type_pointer_formatter.rb +35 -0
  112. data/lib/ruby-bindgen/version.rb +3 -0
  113. data/lib/ruby-bindgen.rb +19 -0
  114. data/ruby-bindgen.gemspec +52 -0
  115. metadata +260 -0
@@ -0,0 +1,124 @@
1
+ # Customizing Bindings
2
+
3
+ `ruby-bindgen` tries its best to generate compilable Rice code. It has been battle tested against [OpenCV](https://github.com/opencv/opencv), which is a large, complex C++ API with over a thousand classes and ten thousand methods.
4
+
5
+ However, complex libraries may require some customization. Customizations fall into three categories:
6
+
7
+ * Configuration
8
+ * Refinements
9
+ * Fixes
10
+
11
+ ## Configuration
12
+
13
+ Some issues are best solved via the [configuration](../configuration.md) file rather than editing generated code:
14
+
15
+ - [Symbol filtering](../configuration.md#skip): Skip functions that cause linker errors or aren’t meant for external use by name or regex pattern
16
+ - [Version guards](../configuration.md#versions): Wrap symbols in `#if VERSION >= N` guards so bindings compile against multiple library versions
17
+ - [Export macros](../configuration.md#export-macros): Limit bindings to exported symbols, preventing linker errors from internal functions
18
+ - [Name mappings](../configuration.md#name-mappings): Override generated Ruby class and method names with exact strings or regex patterns
19
+
20
+ ## Refinements
21
+
22
+ Ruby classes are open, meaning you can reopen an existing class and add methods to it. Refinements take advantage of this to extend generated bindings with additional functionality. Note that this is not the same as Ruby's built-in [refinements](https://docs.ruby-lang.org/en/master/syntax/refinements_rdoc.html), which are scoped. These additions are global.
23
+
24
+ Common reasons to add refinements include:
25
+
26
+ | Addition | What It Adds |
27
+ |-------------------------|----------------------------------------------------------|
28
+ | Expected methods | `inspect`, `to_s` |
29
+ | Modules | `include_module(rb_mComparable)`, `define_method("<=>")` |
30
+ | Template instantiations | `Mat<unsigned char>` |
31
+ | Type conversions | `to_*` |
32
+ | Exceptions | Custom exception class hierarchy |
33
+ | Custom type handling | `Type<T>`, `From_Ruby<T>`, and `To_Ruby<T>` |
34
+ | Custom STL names | `define_vector<cv::Vec3b>(...)` |
35
+ | Non-member operators | `+`, `-`, `*`, `/`, `==` |
36
+ | Iteration | Add `std::iterator_traits` |
37
+ | Method renames | `rb_alias` to rename methods to match Ruby idioms |
38
+
39
+ Just like in Ruby, you can take advantage of Ruby’s open classes to add new functionality.
40
+
41
+ To do this, create a directory to contain additions. The directory can be named anything, but a suggested convention is to name it `refinements`. Here is an example layout:
42
+
43
+ ```
44
+ ext/
45
+ ├── generated/ # Generated files (output: ./ext/generated)
46
+ │ ├── matrix-rb.hpp
47
+ │ ├── matrix-rb.cpp
48
+ │ ├── matrix-rb.ipp
49
+ │ └── my_extension-rb.cpp
50
+ ├── include/
51
+ │ └── matrix.hpp
52
+ ├── refinements/ # Manual additions (never overwritten)
53
+ │ ├── CMakeLists.txt
54
+ │ ├── matrix_refinements.hpp
55
+ │ ├── matrix_refinements.cpp
56
+ │ └── ...
57
+ ```
58
+
59
+ Create a new file in `refinements/` for each generated Rice file you want to extend. For example, if you want to add functionality to `matrix-rb.cpp`, create `refinements/matrix_refinements.hpp` and `refinements/matrix_refinements.cpp`. Define a new init function such as `Init_Matrix_Refinements` in those files.
60
+
61
+ Next add the `.cpp` file to `refinements/CMakeLists.txt`:
62
+ ```cmake
63
+ target_sources(${CMAKE_PROJECT_NAME} PRIVATE
64
+ "matrix_refinements.cpp")
65
+ ```
66
+ Then in the generated `generated/my_extension-rb.cpp` file, include the refinement header and call `Init_Matrix_Refinements()`.
67
+
68
+ Using refinements has a lot of advantages:
69
+
70
+ - Regeneration Safe: Your updates will not be overwritten with the exception of the `my_extension-rb.cpp` file
71
+ - Reuse `_instantiate` methods - Refinements can `#include` generated `.ipp` files to call [`_instantiate` functions](templates.md#template-instantiate-files-ipp) with new type arguments.
72
+
73
+ ### Example
74
+
75
+ Here is an example `refinements/matrix_refinements.cpp` file:
76
+
77
+ ```cpp
78
+ #include <sstream>
79
+ #include "../include/matrix.hpp"
80
+ #include "../generated/matrix-rb.hpp"
81
+ #include "../generated/matrix-rb.ipp"
82
+ #include "matrix_refinements.hpp"
83
+
84
+ using namespace Rice;
85
+
86
+ void Init_Matrix_Refinements()
87
+ {
88
+ // Reopen the class that was already defined by generated code
89
+ Rice::Data_Type<Matrix> matrix;
90
+
91
+ matrix.
92
+ define_method("to_s", [](const Matrix& self) -> std::string
93
+ {
94
+ std::ostringstream stream;
95
+ stream << self;
96
+ return stream.str();
97
+ });
98
+
99
+ // Rename a method to better match Ruby idioms
100
+ rb_alias(matrix, rb_intern("[]"), rb_intern("call"));
101
+
102
+ // Instantiate additional templates not in the generated code
103
+ Matrix_instantiate<double>(rb_mMyExtension, "MatrixDouble");
104
+ }
105
+ ```
106
+
107
+ ## Fixes
108
+
109
+ ### Manual Edits
110
+
111
+ Sometimes you need to **modify** the generated Rice code. Common reasons include:
112
+
113
+ | Change Type | Example | Why |
114
+ |-------------------|---------------------------------|----------------------------------------------------------------------------------------|
115
+ | Missing includes | `#include <core.hpp>` | Generated file references types from headers it doesn't include |
116
+ | Version guards | `#if VERSION >= 2` | API only available in certain library versions |
117
+ | Default values | Remove `Stream::Null()` default | Avoid hardware-dependent functions such as CUDA initialization |
118
+
119
+ - Mark manual changes with `// Manual` comments so they're searchable: `grep -r "// Manual" ext/`
120
+ - Include order matters: System/library headers should come before the primary header, local project headers after
121
+ - Watch fluent chain syntax when commenting out methods: change the preceding `.` to `;` to terminate the chain
122
+ - Refinements can include generated `.ipp` files to reuse `_instantiate` functions with additional type arguments
123
+
124
+ If you have manual edits, you will need a strategy for preserving them when you [regenerate bindings](../updating_bindings.md).
data/docs/cpp/enums.md ADDED
@@ -0,0 +1,42 @@
1
+ # Enums
2
+
3
+ `ruby-bindgen` generates Rice enum bindings for both scoped and unscoped C++ enums. For details on the generated Ruby enum API (comparison, conversion, bitwise operations), see the Rice [Enums](https://ruby-rice.github.io/4.x/bindings/enums/) documentation.
4
+
5
+ ## Scoped Enums (enum class)
6
+
7
+ ```cpp
8
+ enum class Color
9
+ {
10
+ Red, Green, Blue
11
+ };
12
+ ```
13
+
14
+ Generates a Rice enum with properly scoped values.
15
+
16
+ ## Unscoped Enums
17
+
18
+ Unscoped enums in namespaces have values at namespace scope:
19
+
20
+ ```cpp
21
+ namespace cv
22
+ {
23
+ enum BorderType
24
+ {
25
+ BORDER_CONSTANT, BORDER_REPLICATE
26
+ };
27
+ }
28
+ // Values are cv::BORDER_CONSTANT, not cv::BorderType::BORDER_CONSTANT
29
+ ```
30
+
31
+ Unscoped enums inside classes have values qualified with the enum name:
32
+
33
+ ```cpp
34
+ class Buffer
35
+ {
36
+ enum Target
37
+ {
38
+ ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER
39
+ };
40
+ };
41
+ // Values are Buffer::Target::ARRAY_BUFFER
42
+ ```
@@ -0,0 +1,35 @@
1
+ # Filtering
2
+
3
+ `ruby-bindgen` provides several mechanisms to control which symbols are included in the generated bindings.
4
+
5
+ ## Export Macros
6
+
7
+ Many libraries use macros to control which functions are exported. `ruby-bindgen` can honor these macros so that only exported functions are included in the generated bindings. See [`export_macros`](../configuration.md#export-macros) for details.
8
+
9
+ ## Skipping Symbols
10
+
11
+ Sometimes you need to exclude specific symbols from the generated bindings — for example, internal APIs, symbols that cause linker errors, or platform-specific functions. `ruby-bindgen` supports skipping by name, qualified name, or regex pattern. See [`symbols.skip`](../configuration.md#skip) for details.
12
+
13
+ ## Version Guards
14
+
15
+ When a library evolves across versions, some symbols are only available in newer releases. `ruby-bindgen` can wrap these symbols in version guards so the same bindings compile against multiple library versions. See [`symbols.versions`](../configuration.md#versions) for details.
16
+
17
+ ## Automatic Skipping
18
+
19
+ The following are automatically skipped:
20
+
21
+ - **Deprecated**: Functions marked with `__attribute__((deprecated))` or `[[deprecated]]`
22
+ - **Variadic**: Functions with `...` parameters
23
+ - **Deleted**: Methods marked `= delete`
24
+ - **Private/Protected**: Non-public members
25
+ - **Template functions**: Non-member function templates (e.g., `template<typename T> void func()`)
26
+ - **Anonymous namespaces**: Internal implementation details
27
+
28
+ ## std:: Typedefs
29
+
30
+ Typedefs to `std::` types are skipped since Rice handles them automatically:
31
+
32
+ ```cpp
33
+ typedef std::string String; // Skipped - Rice handles std::string
34
+ ```
35
+
@@ -0,0 +1,80 @@
1
+ # Getting Started with Rice Bindings
2
+
3
+ This guide walks you through generating Rice (C++) bindings for a C++ library.
4
+
5
+ ## 1. Create a configuration file
6
+
7
+ Create a file named `rice-bindings.yaml`:
8
+
9
+ ```yaml
10
+ project: my_extension
11
+ input: ./include
12
+ output: ./ext/generated
13
+ format: Rice
14
+
15
+ match:
16
+ - "**/*.hpp"
17
+
18
+ clang:
19
+ args:
20
+ - -I./include
21
+ - -std=c++17
22
+ - -xc++
23
+ ```
24
+
25
+ Key options:
26
+
27
+ - `project` — name used for the extension init function (`Init_my_extension`) and project wrapper files
28
+ - `input` — directory containing header files
29
+ - `output` — where generated C++ files are written
30
+ - `match` — glob patterns selecting which headers to process
31
+ - `clang.args` — compiler arguments; `-xc++` tells clang to parse as C++, `-std=c++17` sets the language standard
32
+
33
+ Paths are relative to the config file's directory, not the working directory.
34
+
35
+ See [Configuration](../configuration.md) for all options, including [symbol filtering](../configuration.md#symbols), [export macros](../configuration.md#export-macros), [name mappings](../configuration.md#name-mappings), and [version guards](../configuration.md#versions).
36
+
37
+ ## 2. Generate bindings
38
+
39
+ ```bash
40
+ ruby-bindgen rice-bindings.yaml
41
+ ```
42
+
43
+ This produces `.cpp`, `.hpp`, and optionally `.ipp` files for each matched header, plus project wrapper files. See [Rice Output](output.md) for details.
44
+
45
+ ## 3. Generate CMake build files (optional)
46
+
47
+ If you want `ruby-bindgen` to generate CMake build files, create a second config:
48
+
49
+ `cmake-bindings.yaml`:
50
+
51
+ ```yaml
52
+ project: my_extension
53
+ output: ./ext/generated
54
+ format: CMake
55
+
56
+ include_dirs:
57
+ - "${CMAKE_CURRENT_SOURCE_DIR}/../include"
58
+ ```
59
+
60
+ Then run it **after** the Rice generation:
61
+
62
+ ```bash
63
+ ruby-bindgen cmake-bindings.yaml
64
+ ```
65
+
66
+ See [CMake Bindings](../cmake/cmake_bindings.md) for details.
67
+
68
+ ## 4. Build the extension
69
+
70
+ ```bash
71
+ cd ./ext/generated
72
+ cmake --preset linux-debug # or macos-debug, msvc-debug, etc.
73
+ cmake --build build/linux-debug
74
+ ```
75
+
76
+ ## 5. Packaging
77
+
78
+ For packaging your extension as a gem, see the Rice [Packaging](https://ruby-rice.github.io/4.x/packaging/packaging/) documentation.
79
+
80
+ For a complete, fully automated example see [BitmapPlusPlus-ruby](https://ruby-rice.github.io/BitmapPlusPlus-ruby/).
@@ -0,0 +1,94 @@
1
+ # Iterators
2
+
3
+ `ruby-bindgen` automatically generates Rice `define_iterator` calls for C++ classes that expose iterator methods. This provides Ruby's `Enumerable` module support for C++ containers. For details on how Rice bridges C++ iterators to Ruby, see the Rice [Iterators](https://ruby-rice.github.io/4.x/bindings/iterators/) documentation.
4
+
5
+ ## Automatic Iterator Detection
6
+
7
+ When `ruby-bindgen` encounters a C++ class with `begin()` and `end()` methods that return iterators, it automatically generates the appropriate `define_iterator` calls. For example, a C++ class like:
8
+
9
+ ```cpp
10
+ class Bitmap {
11
+ public:
12
+ PixelIterator begin();
13
+ PixelIterator end();
14
+ };
15
+ ```
16
+
17
+ Will generate:
18
+
19
+ ```cpp
20
+ define_class_under<Bitmap>(rb_mModule, "Bitmap").
21
+ define_iterator<PixelIterator(Bitmap::*)()>(&Bitmap::begin, &Bitmap::end, "each");
22
+ ```
23
+
24
+ **Note:** If a class only defines `begin() const` and `end() const` (without non-const versions), the generated method will be `each_const`. Since Ruby conventions expect `each`, `ruby-bindgen` automatically aliases `each` to `each_const` in this case.
25
+
26
+ ## Multiple Iterator Types
27
+
28
+ `ruby-bindgen` handles classes with multiple iterator types, such as const iterators, reverse iterators, and const reverse iterators:
29
+
30
+ | Method Pair | Ruby Method Name |
31
+ |-----------------------|----------------------|
32
+ | `begin()`/`end()` | `each` |
33
+ | `begin() const`/`end() const` | `each_const` |
34
+ | `rbegin()`/`rend()` | `each_reverse` |
35
+ | `rbegin() const`/`rend() const` | `each_reverse_const` |
36
+
37
+ ## Incomplete Iterator Traits
38
+
39
+ Some C++ libraries define iterators that lack the required `std::iterator_traits` typedefs. These iterators are missing one or more of:
40
+
41
+ - `value_type`
42
+ - `reference`
43
+ - `pointer`
44
+ - `difference_type`
45
+ - `iterator_category`
46
+
47
+ Rice's `define_iterator` requires these traits to function properly. Without them, you'll see compile errors like:
48
+
49
+ ```
50
+ error C2039: 'value_type': is not a member of 'std::iterator_traits<MyIterator>'
51
+ ```
52
+
53
+ ### Automatic Traits Generation
54
+
55
+ `ruby-bindgen` automatically detects incomplete iterators and generates `std::iterator_traits` specializations for them. For example, given an iterator like:
56
+
57
+ ```cpp
58
+ // Iterator WITHOUT proper std::iterator_traits
59
+ class IncompleteIterator
60
+ {
61
+ public:
62
+ IncompleteIterator() : ptr_(nullptr) {}
63
+ explicit IncompleteIterator(Pixel* p) : ptr_(p) {}
64
+ Pixel& operator*() const { return *ptr_; }
65
+ IncompleteIterator& operator++() { ++ptr_; return *this; }
66
+ bool operator!=(const IncompleteIterator& other) const { return ptr_ != other.ptr_; }
67
+
68
+ private:
69
+ Pixel* ptr_;
70
+ // NOTE: Missing value_type, reference, pointer, difference_type, iterator_category
71
+ };
72
+ ```
73
+
74
+ `ruby-bindgen` will generate:
75
+
76
+ ```cpp
77
+ // Iterator traits specializations for iterators missing std::iterator_traits
78
+ namespace std
79
+ {
80
+ template<>
81
+ struct iterator_traits<iter::IncompleteIterator>
82
+ {
83
+ using iterator_category = forward_iterator_tag;
84
+ using value_type = iter::Pixel;
85
+ using difference_type = ptrdiff_t;
86
+ using pointer = iter::Pixel*;
87
+ using reference = iter::Pixel&;
88
+ };
89
+ }
90
+ ```
91
+
92
+ ## Examples
93
+
94
+ See [test/headers/cpp/iterators.hpp](https://github.com/ruby-rice/ruby-bindgen/blob/main/test/headers/cpp/iterators.hpp) for example iterator classes, including both complete and incomplete iterators. The generated bindings are in [test/bindings/cpp/iterators-rb.cpp](https://github.com/ruby-rice/ruby-bindgen/blob/main/test/bindings/cpp/iterators-rb.cpp).
@@ -0,0 +1,170 @@
1
+ # Operators
2
+
3
+ `ruby-bindgen` automatically generates Rice bindings for C++ operators, mapping them to Ruby methods. For the complete C++ to Ruby operator mapping tables, see the Rice [Operators](https://ruby-rice.github.io/4.x/bindings/operators/) documentation.
4
+
5
+ ## Non-Member Operators
6
+
7
+ C++ allows operators to be defined as non-member (free) functions. Ruby doesn't have the concept of non-member functions — all methods belong to a class. Therefore, `ruby-bindgen` automatically converts non-member operators to instance methods on the first argument's class:
8
+
9
+ ```cpp
10
+ class Matrix
11
+ {
12
+ public:
13
+ int rows, cols;
14
+ };
15
+
16
+ // Non-member operators
17
+ Matrix& operator+=(Matrix& a, const Matrix& b);
18
+ Matrix& operator-=(Matrix& a, const Matrix& b);
19
+ Matrix& operator*=(Matrix& a, double scalar);
20
+ ```
21
+
22
+ `ruby-bindgen` generates:
23
+
24
+ ```cpp
25
+ rb_cMatrix.
26
+ define_method("assign_plus", [](Matrix& self, const Matrix& other) -> Matrix&
27
+ {
28
+ self += other;
29
+ return self;
30
+ }).
31
+ define_method("assign_minus", [](Matrix& self, const Matrix& other) -> Matrix&
32
+ {
33
+ self -= other;
34
+ return self;
35
+ }).
36
+ define_method("assign_multiply", [](Matrix& self, double other) -> Matrix&
37
+ {
38
+ self *= other;
39
+ return self;
40
+ });
41
+ ```
42
+
43
+ Ruby usage:
44
+
45
+ ```ruby
46
+ matrix1 = Matrix.new
47
+ matrix2 = Matrix.new
48
+
49
+ matrix1.assign_plus(matrix2) # Calls operator+=(matrix1, matrix2)
50
+ matrix1.assign_multiply(2.0) # Calls operator*=(matrix1, 2.0)
51
+ ```
52
+
53
+ ### Non-Member Unary Operators
54
+
55
+ Non-member unary operators (common in libraries like OpenCV) are wrapped via lambdas:
56
+
57
+ ```cpp
58
+ MatExpr operator~(const Mat& m); // Bitwise NOT
59
+ MatExpr operator-(const Mat& m); // Negation
60
+ MatExpr operator+(const Mat& m); // Unary plus
61
+ ```
62
+
63
+ `ruby-bindgen` generates:
64
+
65
+ ```cpp
66
+ rb_cMat.
67
+ define_method("~", [](const Mat& self) -> MatExpr
68
+ {
69
+ return ~self;
70
+ }).
71
+ define_method("-@", [](const Mat& self) -> MatExpr
72
+ {
73
+ return -self;
74
+ }).
75
+ define_method("+@", [](const Mat& self) -> MatExpr
76
+ {
77
+ return +self;
78
+ });
79
+ ```
80
+
81
+ Ruby usage:
82
+
83
+ ```ruby
84
+ mat = Mat.new
85
+ result = ~mat # Bitwise NOT
86
+ result = -mat # Negation
87
+ result = +mat # Unary plus
88
+ ```
89
+
90
+ ### Streaming Operator
91
+
92
+ The `<<` operator is often used for stream-like semantics in C++. `ruby-bindgen` handles two cases:
93
+
94
+ 1. **Output streaming** (`std::ostream& operator<<(std::ostream&, const T&)`) — converted to `inspect` methods on the streamed class.
95
+
96
+ 2. **Other streaming** (e.g., `FileStorage& operator<<(FileStorage&, const T&)`) — converted to `<<` instance methods.
97
+
98
+ ```cpp
99
+ // Output streaming - generates inspect method on Printable
100
+ std::ostream& operator<<(std::ostream& os, const Printable& p);
101
+
102
+ // FileStorage streaming - generates << method on FileStorage
103
+ FileStorage& operator<<(FileStorage& fs, const std::string& value);
104
+ FileStorage& operator<<(FileStorage& fs, int value);
105
+ FileStorage& operator<<(FileStorage& fs, const cv::Mat& mat);
106
+ ```
107
+
108
+ The generated Ruby code groups all non-member operators by their target class:
109
+
110
+ ```cpp
111
+ rb_cPrintable.
112
+ define_method("inspect", [](const Printable& self) -> std::string
113
+ {
114
+ std::ostringstream stream;
115
+ stream << self;
116
+ return stream.str();
117
+ });
118
+
119
+ rb_cFileStorage.
120
+ define_method("<<", [](FileStorage& self, const std::string& other) -> FileStorage&
121
+ {
122
+ self << other;
123
+ return self;
124
+ }).
125
+ define_method("<<", [](FileStorage& self, int other) -> FileStorage&
126
+ {
127
+ self << other;
128
+ return self;
129
+ });
130
+ ```
131
+
132
+ ## Conversion Operators
133
+
134
+ C++ [conversion operators](https://en.cppreference.com/w/cpp/language/cast_operator) are mapped to Ruby `to_*` methods:
135
+
136
+ ```cpp
137
+ operator double() const; // to_f
138
+ operator bool() const; // to_bool
139
+ operator std::string() const; // to_s
140
+ ```
141
+
142
+ ### Conversion Type Mappings
143
+
144
+ | C++ Type | Ruby Method | Ruby Class |
145
+ |:---------|:------------|:-----------|
146
+ | `int` | `to_i` | `Integer` |
147
+ | `long` | `to_l` | `Integer` |
148
+ | `long long` | `to_i64` | `Integer` |
149
+ | `short` | `to_i16` | `Integer` |
150
+ | `unsigned int` | `to_u` | `Integer` |
151
+ | `unsigned long` | `to_ul` | `Integer` |
152
+ | `unsigned long long` | `to_u64` | `Integer` |
153
+ | `unsigned short` | `to_u16` | `Integer` |
154
+ | `int8_t` | `to_i8` | `Integer` |
155
+ | `int16_t` | `to_i16` | `Integer` |
156
+ | `int32_t` | `to_i32` | `Integer` |
157
+ | `int64_t` | `to_i64` | `Integer` |
158
+ | `uint8_t` | `to_u8` | `Integer` |
159
+ | `uint16_t` | `to_u16` | `Integer` |
160
+ | `uint32_t` | `to_u32` | `Integer` |
161
+ | `uint64_t` | `to_u64` | `Integer` |
162
+ | `size_t` | `to_size` | `Integer` |
163
+ | `float` | `to_f32` | `Float` |
164
+ | `double` | `to_f` | `Float` |
165
+ | `long double` | `to_ld` | `Float` |
166
+ | `bool` | `to_bool` | `TrueClass` / `FalseClass` |
167
+ | `std::string` | `to_s` | `String` |
168
+ | `const char*` | `to_s` | `String` |
169
+
170
+ Custom types are mapped to `to_<typename>` in snake_case (e.g., `operator MyClass()` becomes `to_my_class`). Pointer conversions map to `to_ptr` or `to_const_ptr`.
@@ -0,0 +1,125 @@
1
+ # Rice Output
2
+
3
+ ## Header Files
4
+
5
+ For every C++ header file, `ruby-bindgen` generates a .hpp and .cpp file. These files have the same name as the C++ header but with the addition of `-rb` at the end. For example, a C++ header file called `matrix.hpp` will generate in `matrix-rb.hpp` and `matrix-rb.cpp`. If the C++ header file declares a template class, then a third file will be generated called `matrix-rb.ipp`.
6
+
7
+ ``` mermaid
8
+ flowchart LR
9
+ subgraph Input
10
+ H1["matrix.hpp"]
11
+ CF["rice-bindings.yaml"]
12
+ end
13
+
14
+ H1 & CF --> RB["ruby-bindgen"]
15
+
16
+ subgraph "Rice Output"
17
+ R1["matrix-rb.cpp"]
18
+ R2["matrix-rb.hpp"]
19
+ R3["matrix-rb.ipp"]
20
+ end
21
+
22
+ RB --> R1 & R2 & R3
23
+ ```
24
+
25
+ The `.hpp` file declares an `Init_` function (e.g., `Init_Matrix`) that registers the classes, methods, and enums from that header with Rice.
26
+
27
+ The `.cpp` file defines that `Init_` function with the actual Rice bindings code.
28
+
29
+ The `.ipp` file is only generated when the header declares template classes. It contains one `_instantiate` function per template class that can be used to instantiate the template. The `-rb.ipp` files can be reused across translated units. See [Templates](templates.md#template-instantiate-files-ipp) for details.
30
+
31
+ ## Init Function Names
32
+
33
+ Each generated file has an `Init_` function. To avoid conflicts when multiple files have the same name in different directories (e.g., `core/version.hpp` and `dnn/version.hpp`), the function name includes the directory path:
34
+
35
+ | File Path | Init Function |
36
+ |-----------|---------------|
37
+ | `version.hpp` | `Init_Version` |
38
+ | `core/version.hpp` | `Init_Core_Version` |
39
+ | `dnn/version.hpp` | `Init_Dnn_Version` |
40
+ | `core/hal/interface.hpp` | `Init_Core_Hal_Interface` |
41
+
42
+ The top-level directory is always removed to avoid overly long names (e.g., `opencv2/calib3d.hpp` becomes `Init_Calib3d`, and `opencv2/core/version.hpp` becomes `Init_Core_Version`).
43
+
44
+ ## Project Files
45
+
46
+ When you set the `project` option in your configuration, `ruby-bindgen` also generates project-level wrapper files that tie everything together:
47
+
48
+ ```mermaid
49
+ flowchart LR
50
+ subgraph Input
51
+ CF["rice-bindings.yaml"]
52
+ end
53
+
54
+ CF --> RB["ruby-bindgen"]
55
+
56
+ subgraph "Project Files"
57
+ P1["my_extension-rb.cpp"]
58
+ P2["my_extension-rb.hpp"]
59
+ P3["rice_include.hpp"]
60
+ end
61
+
62
+ RB --> P1 & P2 & P3
63
+ ```
64
+
65
+ * `my_extension-rb.hpp` declares the main Ruby init function `Init_my_extension` with the appropriate export attribute (`__declspec(dllexport)` on Windows, `__attribute__((visibility("default")))` on Linux/macOS)
66
+ * `my_extension-rb.cpp` defines `Init_my_extension`, which calls each per-header `Init_` function (e.g., `Init_Matrix`, `Init_Image`, `Init_Filter`)
67
+ * `rice_include.hpp` is the default [include header](#include-header) that all generated translation units include
68
+
69
+ To suppress project file generation, omit the `project` option from your configuration. This is useful when you want to manage the top-level init function yourself.
70
+
71
+ ## Include Header
72
+
73
+ By default `ruby-bindgen` creates a default include files called `rice_include.hpp`. Its content is:
74
+
75
+ ```cpp
76
+ #pragma once
77
+
78
+ // Default Rice include header generated by ruby-bindgen
79
+ // To customize, create your own header and specify it with the 'include:' config option
80
+ #include <rice/rice.hpp>
81
+ #include <rice/stl.hpp>
82
+ ```
83
+ If the `rice_include.hpp` already exists, `ruby-bindgen` will not overwrite it.
84
+
85
+ All generated headers include this file:
86
+
87
+ ```cpp
88
+ #include "../../rice_include.hpp" // relative path computed automatically
89
+
90
+ void Init_MyClass();
91
+ ```
92
+
93
+ Remember that C++ templates are instantiated per translation unit. If different translation units see different template definitions (e.g., one sees a `Type<T>` specialization and another doesn't), this causes an ODR (One Definition Rule) violation. The linker may silently pick the wrong instantiation, leading to subtle bugs.
94
+
95
+ By centralizing all Rice includes in a single header that every generated file includes, all translation units see the same template definitions, preventing ODR violations.
96
+
97
+ The include header is an ideal candidate for precompiled headers (PCH). Since every generated file includes it, precompiling this header can significantly speed up build times:
98
+
99
+ ```cmake
100
+ # CMake example
101
+ target_precompile_headers(my_extension PRIVATE
102
+ "${CMAKE_SOURCE_DIR}/rice_include.hpp"
103
+ )
104
+ ```
105
+
106
+ You can specify a custom include file by setting the `include` option in the configuration file. This will replace the default `rice_include.hpp` file and thus allow you to specify your own `include` files if necessary. Your custom header must include the Rice headers, plus any additional includes or definitions you want to be global.
107
+
108
+ For example, it is a good place to add support for custom smart pointers. For example, OpenCV defines `cv::Ptr<T>` which inherits from `std::shared_ptr<T>`. The opencv-ruby bindings wrap this smart pointer in a custom header file that is then added to `rice_include.hpp`. That means all translation units see it, preventing ODR violations.
109
+
110
+ A custom include file will not be overwritten by `ruby-bindgen`.
111
+
112
+ ## Init Function Call Graph
113
+
114
+ When Ruby loads an extension, it calls the top-level `Init_<extension>` function, which in turn calls each per-header `Init_*` function to register classes, methods, and enums.
115
+
116
+ ```mermaid
117
+ flowchart TD
118
+ A["Ruby loads extension"] --> B["Init_my_extension"]
119
+ B --> C["Init_Core"]
120
+ B --> D["Init_Mat"]
121
+ B --> E["Init_*"]
122
+ B --> G["Init_*_Refinements (manual, optional)"]
123
+ ```
124
+
125
+ The extension `Init_<extension>` function is the top-level entry point and calls all per-header `Init_*` functions. Refinement init functions are optional manual hooks that run after generated definitions. See [refinements](customizing.md#refinements) for details.