From b2ddb69fd42ab803a66d91d3d89ca61fcbd450cf Mon Sep 17 00:00:00 2001 From: cfis Date: Fri, 19 Dec 2025 19:24:05 -0800 Subject: [PATCH] Documentation updates. --- .github/workflows/docs.yml | 33 +++ docs/architecture/overload_resolution.md | 341 +++++++++++++++++++++++ docs/architecture/overview.md | 3 + docs/bindings/buffers.md | 4 +- docs/bindings/overloaded_methods.md | 81 +++--- docs/bindings/overview.md | 53 ++++ docs/cpp_api/array.md | 4 +- docs/cpp_api/hash.md | 4 +- docs/cpp_api/string.md | 2 +- docs/cpp_api/struct.md | 2 +- docs/ruby_api/buffer.md | 4 +- docs/tutorial.md | 4 +- mkdocs.yml | 14 +- 13 files changed, 494 insertions(+), 55 deletions(-) create mode 100644 .github/workflows/docs.yml create mode 100644 docs/architecture/overload_resolution.md create mode 100644 docs/bindings/overview.md diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..4529f59d --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,33 @@ +name: Deploy Documentation + +on: + push: + branches: [ master ] + workflow_dispatch: # Allow manual triggering + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: Install mkdocs and dependencies + run: | + pip install mkdocs-material + + - name: Build documentation + run: mkdocs build --strict + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v4 + with: + deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }} + external_repository: ruby-rice/ruby-rice.github.io + publish_branch: main + publish_dir: ./site + destination_dir: 4.x diff --git a/docs/architecture/overload_resolution.md b/docs/architecture/overload_resolution.md new file mode 100644 index 00000000..c93194b7 --- /dev/null +++ b/docs/architecture/overload_resolution.md @@ -0,0 +1,341 @@ +# Overload Resolution + +This document explains how Rice resolves C++ method overloads when called from Ruby. + +## Overview + +When a C++ class has multiple methods with the same name but different parameter types (overloads), Rice must determine which one to call based on the Ruby arguments provided. Rice uses a numeric scoring system where each overload receives a score from 0.0 to 1.0, and the highest-scoring overload is selected. + +## Scoring Constants + +The scoring system is defined in `rice/detail/from_ruby.hpp`: + +```cpp +struct Convertible +{ + static constexpr double Exact = 1.0; // Perfect type match + static constexpr double None = 0.0; // Cannot convert + static constexpr double IntToFloat = 0.9; // Penalty for int to float conversion + static constexpr double SignedToUnsigned = 0.5;// Penalty for signed to unsigned (can't represent negatives) + static constexpr double FloatToInt = 0.5; // Penalty for float to int conversion + static constexpr double ConstMismatch = 0.99; // Penalty for const mismatch +}; +``` + +## Precision Bits + +Ruby numeric types have precision defined in terms of bits: + +| Ruby Type | Precision Bits | Notes | +|-----------|----------------|-------| +| Integer (Fixnum/Bignum) | 63 | Same as C++ long long | +| Float | 53 | Same as C++ double mantissa | + +C++ types use `std::numeric_limits::digits`: + +| C++ Type | Precision Bits | +|----------|----------------| +| char | 7 | +| signed char | 7 | +| unsigned char | 8 | +| short | 15 | +| unsigned short | 16 | +| int | 31 | +| unsigned int | 32 | +| long | 31 or 63* | +| unsigned long | 32 or 64* | +| long long | 63 | +| unsigned long long | 64 | +| float | 24 (mantissa) | +| double | 53 (mantissa) | + +\* Platform dependent + +## Same-Domain Conversions + +When converting within the same numeric domain (integer-to-integer or float-to-float): + +**Widening conversion (target >= source bits):** Score = 1.0 + +**Narrowing conversion (target < source bits):** Score = targetBits / sourceBits + +Example: Ruby Integer (63 bits) to C++ short (15 bits) +``` +Score = 15 / 63 = 0.238 +``` + +### Signed to Unsigned + +When converting a Ruby Integer (which is signed) to an unsigned C++ type, a penalty is applied because unsigned types cannot represent negative values: + +``` +Score = precisionScore * SignedToUnsigned + = precisionScore * 0.5 +``` + +Example: Ruby Integer (63 bits) to C++ unsigned int (32 bits) +``` +precisionScore = 32 / 63 = 0.508 +Score = 0.508 * 0.5 = 0.254 +``` + +This ensures signed types are preferred over unsigned types. For example, given overloads `foo(int)` and `foo(unsigned int)`: + +| Overload | Score | Calculation | +|----------|-------|-------------| +| foo(int) | 0.49 | 31/63 | +| foo(unsigned int) | 0.25 | 32/63 × 0.5 | + +Result: `foo(int)` is selected. + +## Cross-Domain Conversions + +### Integer to Float + +When converting a Ruby Integer to a C++ float type, the score combines precision loss with a domain-change penalty: + +``` +Score = precisionScore * IntToFloat + = precisionScore * 0.9 +``` + +Example: Ruby Integer (63 bits) to C++ double (53 bits) +``` +precisionScore = min(63, 53) / 63 = 53/63 = 0.841 +Score = 0.841 * 0.9 = 0.757 +``` + +Example: Ruby Integer (63 bits) to C++ float (24 bits) +``` +precisionScore = min(63, 24) / 63 = 24/63 = 0.381 +Score = 0.381 * 0.9 = 0.343 +``` + +### Float to Integer + +When converting a Ruby Float to a C++ integer type, a larger penalty is applied because the fractional part is lost: + +``` +Score = precisionScore * FloatToInt + = precisionScore * 0.5 +``` + +Example: Ruby Float (53 bits) to C++ int (31 bits) +``` +precisionScore = 31 / 53 = 0.585 +Score = 0.585 * 0.5 = 0.292 +``` + +Example: Ruby Float (53 bits) to C++ long long (63 bits) +``` +precisionScore = 53 / 53 = 1.0 (capped, since 63 >= 53) +Score = 1.0 * 0.5 = 0.5 +``` + +## Type Mapping Reference + +The following table shows conversion scores for all Ruby-to-C++ type combinations, with the underlying calculations. + +| C++ Type | Bits | True | False | Nil | String | Integer | Float | +|--------------------|:----:|:----:|:-----:|:---:|:------:|:-------:|:-----:| +| bool | - | 1.0 | 1.0 | 1.0 | | | | +| char | 7 | | | | 1.0 | 0.11 = 7/63 | 0.07 = 7/53×0.5 | +| signed char | 7 | | | | 1.0 | 0.11 = 7/63 | 0.07 = 7/53×0.5 | +| unsigned char | 8 | | | | 1.0 | 0.06 = 8/63×0.5 | 0.08 = 8/53×0.5 | +| short | 15 | | | | | 0.24 = 15/63 | 0.14 = 15/53×0.5 | +| unsigned short | 16 | | | | | 0.13 = 16/63×0.5 | 0.15 = 16/53×0.5 | +| int | 31 | | | | | 0.49 = 31/63 | 0.29 = 31/53×0.5 | +| unsigned int | 32 | | | | | 0.25 = 32/63×0.5 | 0.30 = 32/53×0.5 | +| long* | 31 | | | | | 0.49 = 31/63 | 0.29 = 31/53×0.5 | +| unsigned long* | 32 | | | | | 0.25 = 32/63×0.5 | 0.30 = 32/53×0.5 | +| long long | 63 | | | | | 1.0 = 63/63 | 0.50 = 1.0×0.5 | +| unsigned long long | 64 | | | | | 0.50 = 1.0×0.5 | 0.50 = 1.0×0.5 | +| float | 24 | | | | | 0.34 = 24/63×0.9 | 0.45 = 24/53 | +| double | 53 | | | | | 0.76 = 53/63×0.9 | 1.0 = 53/53 | + +\* `long` is platform-dependent. On 64-bit systems: `long` = 63 bits, `unsigned long` = 64 bits. + +**Score formulas:** +- **Integer → signed integer**: `targetBits / 63` (narrowing) or `1.0` (widening) +- **Integer → unsigned integer**: `(targetBits / 63) × 0.5` (SignedToUnsigned penalty) +- **Integer → float**: `min(targetBits, 63) / 63 × 0.9` (IntToFloat penalty) +- **Float → integer**: `min(targetBits, 53) / 53 × 0.5` (FloatToInt penalty) +- **Float → float**: `targetBits / 53` (narrowing) or `1.0` (widening) + +## Default Parameters + +When an overload has default parameters and the caller does not provide all arguments, a small penalty is applied for each default used: + +``` +parameterMatch = 0.99 ^ defaultCount +``` + +This ensures that overloads that exactly match the argument count are preferred over those that rely on defaults. + +## Final Score Calculation + +The final score for an overload is: + +``` +finalScore = minParameterScore * parameterMatch +``` + +Where: +- `minParameterScore` is the minimum score across all passed arguments +- `parameterMatch` is the penalty for default parameters (0.99 per default) + +Using the minimum ensures that one bad match cannot be hidden by good matches elsewhere. + +## Const Correctness + +When a Ruby-wrapped C++ object is passed as an argument: + +- Passing a const object to a non-const parameter: Score = 0.0 (not allowed) +- Passing a non-const object to a const parameter: Score *= 0.99 (small penalty) +- Matching constness: No penalty + +## Resolution Process + +The resolution happens in `rice/detail/Native.ipp`: + +1. `Native::resolve()` is called when Ruby invokes a method +2. For each registered overload, `Native::matches()` computes a score +3. Overloads are sorted by score (highest first) +4. The highest-scoring overload is selected +5. If no overload scores above 0.0, an error is raised + +## Examples + +### Example 1: Exact Match vs Type Conversion + +Given these C++ overloads: +```cpp +void foo(int x); +void foo(double x); +``` + +Called with Ruby Integer `foo(42)`: + +| Overload | Parameter Score | Final Score | +|----------|-----------------|-------------| +| foo(int) | 1.0 (exact) | 1.0 | +| foo(double) | 0.9 (int to float) | 0.9 | + +Result: `foo(int)` is selected. + +Called with Ruby Float `foo(3.14)`: + +| Overload | Parameter Score | Final Score | +|----------|-----------------|-------------| +| foo(int) | 0.5 (float to int) | 0.5 | +| foo(double) | 1.0 (exact) | 1.0 | + +Result: `foo(double)` is selected. + +### Example 2: Default Parameters + +Given these C++ overloads: +```cpp +void bar(int x); +void bar(int x, int y = 0); +``` + +Called with `bar(1)`: + +| Overload | Min Score | Param Match | Final Score | +|----------|-----------|-------------|-------------| +| bar(int) | 1.0 | 1.0 | 1.0 | +| bar(int, int=0) | 1.0 | 0.99 | 0.99 | + +Result: `bar(int)` is selected because it has no defaults. + +Called with `bar(1, 2)`: + +| Overload | Min Score | Param Match | Final Score | +|----------|-----------|-------------|-------------| +| bar(int) | N/A | N/A | 0.0 (too many args) | +| bar(int, int=0) | 1.0 | 1.0 | 1.0 | + +Result: `bar(int, int=0)` is selected. + +### Example 3: Precision-Based Selection + +Given these C++ overloads: +```cpp +void baz(short x); +void baz(long long x); +``` + +Called with Ruby Integer `baz(1)`: + +| Overload | Parameter Score | Final Score | +|----------|-----------------|-------------| +| baz(short) | 15/63 = 0.238 | 0.238 | +| baz(long long) | 63/63 = 1.0 | 1.0 | + +Result: `baz(long long)` is selected because it can hold the full precision. + +### Example 4: Mixed Arguments + +Given this C++ overload: +```cpp +void qux(int a, double b); +void qux(double a, int b); +``` + +Called with `qux(1, 2.0)` (Integer, Float): + +| Overload | Scores | Min Score | Final | +|----------|--------|-----------|-------| +| qux(int, double) | 1.0, 1.0 | 1.0 | 1.0 | +| qux(double, int) | 0.9, 0.5 | 0.5 | 0.5 | + +Result: `qux(int, double)` is selected. + +Called with `qux(1.0, 2)` (Float, Integer): + +| Overload | Scores | Min Score | Final | +|----------|--------|-----------|-------| +| qux(int, double) | 0.5, 0.9 | 0.5 | 0.5 | +| qux(double, int) | 1.0, 1.0 | 1.0 | 1.0 | + +Result: `qux(double, int)` is selected. + +### Example 5: Const Correctness + +Given these C++ overloads: +```cpp +void process(MyClass& obj); +void process(const MyClass& obj); +``` + +Called with a non-const Ruby-wrapped MyClass: + +| Overload | Score | +|----------|-------| +| process(MyClass&) | 1.0 | +| process(const MyClass&) | 0.99 | + +Result: `process(MyClass&)` is selected. + +Called with a const Ruby-wrapped MyClass: + +| Overload | Score | +|----------|-------| +| process(MyClass&) | 0.0 (not allowed) | +| process(const MyClass&) | 1.0 | + +Result: `process(const MyClass&)` is selected. + +## Key Files + +- `rice/detail/from_ruby.hpp` - Defines Convertible constants +- `rice/detail/from_ruby.ipp` - Implements rubyPrecisionBits(), precisionScore(), and FromRubyFundamental +- `rice/detail/Native.hpp` - Defines Resolved struct and Native class +- `rice/detail/Native.ipp` - Implements resolve(), matches(), and matchParameters() +- `rice/detail/Parameter.hpp` - Defines Parameter class +- `rice/detail/Parameter.ipp` - Implements Parameter::matches() + +## See Also + +- `test/test_Overloads.cpp` - Test cases for overload resolution diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md index dbb612ed..0c071274 100644 --- a/docs/architecture/overview.md +++ b/docs/architecture/overview.md @@ -62,6 +62,9 @@ Rice is organized into several subsystems: [Method Binding](method_binding.md) `Native` hierarchy - Binding C++ functions and methods to Ruby. +[Overload Resolution](overload_resolution.md) + How Rice selects the correct C++ overload based on Ruby arguments using precision-based scoring. + [Types Overview](../types/overview.md) `From_Ruby` and `To_Ruby` - Converting values between languages. diff --git a/docs/bindings/buffers.md b/docs/bindings/buffers.md index 494b0b98..cb033be5 100644 --- a/docs/bindings/buffers.md +++ b/docs/bindings/buffers.md @@ -104,7 +104,7 @@ Buffer's have the following Ruby API: * bytes(count) - A Ruby string with a binary encoding of the specified length * to_ary - A Ruby array. Buffer#size must be set * to_ary(count) - A Ruby array of the specified length -* [](index) - Get the item at the specified index -* []=(index) - Update the item at the specified index +* `[](index)` - Get the item at the specified index +* `[]=(index)` - Update the item at the specified index * data - Get a `Pointer` object to the Buffer's managed memory that can be passed to C++ APIs * release - Same as #data but tells the buffer to release ownership of its memory diff --git a/docs/bindings/overloaded_methods.md b/docs/bindings/overloaded_methods.md index 90419634..b4318a3b 100644 --- a/docs/bindings/overloaded_methods.md +++ b/docs/bindings/overloaded_methods.md @@ -12,14 +12,14 @@ For example, consider this C++ class with a getter and setter that have the same class Container { public: - size_t capacity(Rect) + size_t capacity() { return this->capacity_; } void capacity(size_t value) { - this->capacity_ - value; + this->capacity_ = value; } private: @@ -57,8 +57,8 @@ Notice the addition of the template specializations in side the `<` and '>' brac Another solution is provided by the C++ keyword `using`, like this: ```cpp -using Getter_T - size_t(Container::*)(); -using Setter_T - void(Container::*)(size_t); +using Getter_T = size_t(Container::*)(); +using Setter_T = void(Container::*)(size_t); Class c = define_class("Container") .define_constructor(Constructor()) @@ -69,8 +69,8 @@ Class c = define_class("Container") Or even like this: ```cpp -using Getter_T - size_t(Container::*)(); -using Setter_T - void(Container::*)(size_t); +using Getter_T = size_t(Container::*)(); +using Setter_T = void(Container::*)(size_t); Class c = define_class("Container") .define_constructor(Constructor()) @@ -100,39 +100,48 @@ void Init_Container() Ruby does not natively support method overloading. Thus Rice implements overloading support itself. It does this by maintaining a global registry (see [NativeRegistry](https://github.com/ruby-rice/rice/blob/master/rice/detail/NativeRegistry.hpp)) of methods keyed on class and method name. For the example above, the key would be `Container::capacity` and the value is an array of two [NativeFunction](https://github.com/ruby-rice/rice/blob/master/rice/detail/NativeFunction.hpp) instances, where each `NativeFunction` instance maps to one C++ member function. -At runtime, Rice evaluates the method parameters sent from Ruby to the `intersects` method and determines the best match. It does this by looping over the native `NativeFunction` instances and calls their `matches` method. The matches method, in turn, loops over the passed-in parameters and sends them to its array of `From_Ruby` instances (for more information see the [type conversion](../types/conversion.md) section). +At runtime, Rice evaluates the method parameters sent from Ruby and determines which overloaded C++ method is the best match. It does this by looping over the native `NativeFunction` instances and calls their `matches` method. The matches method, in turn, loops over the passed-in parameters and evaluates each one (for more information see the [type conversion](../types/conversion.md) section). -Each `From_Ruby` instance defines a `convertible` method that returns one of five results: +Matches are scored on a scale of 0.0 to 1.0: -* Exact - The types match exactly -* Const - The types only differ by `const` -* Cast - The types do not match but can be converted to each other (for example an integer to a double) -* Narrow - The types do not match but can be converted using a narrowing cast (for example a long to an int) -* None - The types do not match and cannot be converted (for example a string to an integer) +* **1.0 (Exact)** - The types match exactly +* **0.99 (ConstMismatch)** - Passing a non-const value to a const parameter +* **0.9 (IntToFloat)** - Domain change penalty when converting integer to float +* **0.5 (SignedToUnsigned)** - Penalty when converting signed Ruby Integer to unsigned C++ type +* **0.5 (FloatToInt)** - Domain change penalty when converting float to integer (lossy) +* **0.0 (None)** - The types do not match and cannot be converted -Based on the results for each parameter, each overloaded C++ method is sorted from best match to worst match. The best matching function is then called. +For numeric types, Rice uses precision-based scoring. The score is calculated as `targetBits / sourceBits` when narrowing (e.g., Ruby Integer with 63 bits to C++ `int` with 31 bits scores 31/63 ≈ 0.49). Cross-domain conversions (int↔float) multiply the precision score by the domain penalty. + +The final score for each overload is: `min(all parameter scores) × 0.99^(number of defaults used)`. + +Based on these scores, each overloaded C++ method is sorted from best match to worst match. The best matching function is then called. + +For more in-depth information about the resolution algorithm, see the [Overload Resolution Architecture](../architecture/overload_resolution.md) documentation. ## Type Mapping -The following table shows how Ruby types are mapped to C++ types. E is exact, C is cast and N is narrow. - -| | True | False | Nil | String | Integer | BigNum | Float | -|----------------------|:----:|:-----:|:---:|:------:|:-------:|:------:|:-----:| -| bool | E | E | E | | | | | -| char | | | | C | N | | | -| signed char | | | | C | N | | | -| unsigned char | | | | C | N | | | -| short | | | | | N | | | -| unsigned short | | | | | N | | | -| int | | | | | E | N | | -| unsigned int | | | | | E | N | | -| long | | | | | E | N | | -| unsigned long | | | | | E | N | | -| long long | | | | | E | E | | -| unsigned long long | | | | | E | E | | -| float | | | | | C | | N | -| double | | | | | C | C | E | - -If multiple matches are possible, the first one wins. That means the order in which native functions are defined using `define_method` is important. - -Note Rice will *not* convert a float to an integer type. +The following table shows how Ruby types are mapped to C++ types. Ruby Integer has 63 bits precision (like `long long`), and Ruby Float has 53 bits (like `double` mantissa). + +| C++ Type | True | False | Nil | String | Integer | Float | +|--------------------|:----:|:-----:|:---:|:------:|:-------:|:-----:| +| bool | 1.0 | 1.0 | 1.0 | | | | +| char | | | | 1.0 | 0.11 | 0.07 | +| signed char | | | | 1.0 | 0.11 | 0.07 | +| unsigned char | | | | 1.0 | 0.06 | 0.08 | +| short | | | | | 0.24 | 0.14 | +| unsigned short | | | | | 0.13 | 0.15 | +| int | | | | | 0.49 | 0.29 | +| unsigned int | | | | | 0.25 | 0.30 | +| long* | | | | | 0.49 | 0.29 | +| unsigned long* | | | | | 0.25 | 0.30 | +| long long | | | | | 1.0 | 0.50 | +| unsigned long long | | | | | 0.50 | 0.50 | +| float | | | | | 0.34 | 0.45 | +| double | | | | | 0.76 | 1.0 | + +\* `long` is platform-dependent. On 64-bit systems: `long` = 63 bits (score 1.0), `unsigned long` = 64 bits (score 0.50). + +See the [Type Mapping Reference](../architecture/overload_resolution.md#type-mapping-reference) for the underlying calculations. + +If multiple overloads have equal scores, the first one defined wins. diff --git a/docs/bindings/overview.md b/docs/bindings/overview.md new file mode 100644 index 00000000..2db91447 --- /dev/null +++ b/docs/bindings/overview.md @@ -0,0 +1,53 @@ +# Overview + +This section explains how to wrap C++ code for use in Ruby. Rice provides a simple, intuitive API that lets you expose C++ classes, methods, functions, and data to Ruby with minimal boilerplate. + +## Core Concepts + +Wrapping C++ code involves several key concepts: + +**Classes and Modules** + +Use `define_class()` to wrap a C++ class as a Ruby class, or `define_module()` to create a Ruby module for organizing functions. See [Constructors](constructors.md) for details on defining classes. + +**Methods and Functions** + +Use `define_method()` to wrap C++ member functions as Ruby instance methods, and `define_function()` or `define_singleton_function()` for static/class methods. See [Methods](methods.md) for details. + +**Attributes** + +Use `define_attr()` to expose C++ member variables as Ruby attributes with getter/setter methods. See [Attributes](attributes.md) for details. + +**Type Conversion** + +Rice automatically converts between C++ and Ruby types. For fundamental types (int, float, string, etc.), values are copied. For wrapped C++ classes, objects are shared between the two languages. See [Type Conversion](../types/conversion.md) for details. + +## Quick Reference + +| Task | Rice API | +|------|----------| +| Wrap a C++ class | `define_class("MyClass")` | +| Add a constructor | `.define_constructor(Constructor())` | +| Wrap a member function | `.define_method("name", &MyClass::method)` | +| Wrap a static function | `.define_singleton_function("name", &MyClass::static_method)` | +| Expose a member variable | `.define_attr("name", &MyClass::member)` | +| Wrap an enum | `define_enum("MyEnum")` | +| Add a constant | `.define_constant("NAME", value)` | + +## Topics + +- [Constructors](constructors.md) - Defining how Ruby creates C++ objects +- [Methods](methods.md) - Wrapping C++ functions and member functions +- [Overloaded Methods](overloaded_methods.md) - Handling C++ function overloading +- [Attributes](attributes.md) - Exposing C++ member variables +- [Enums](enums.md) - Wrapping C++ enumerations +- [Constants](constants.md) - Defining Ruby constants +- [Inheritance](inheritance.md) - Mapping C++ class hierarchies to Ruby +- [Operators](operators.md) - Wrapping C++ operators +- [Iterators](iterators.md) - Exposing C++ iterators to Ruby +- [Pointers](pointers.md) - Working with C++ pointers +- [Buffers](buffers.md) - Managing memory buffers +- [Exceptions](exceptions.md) - Exception handling between C++ and Ruby +- [Memory Management](memory_management.md) - Controlling object lifetimes +- [Callbacks](callbacks.md) - Calling Ruby from C++ +- [GVL](gvl.md) - Managing Ruby's Global VM Lock diff --git a/docs/cpp_api/array.md b/docs/cpp_api/array.md index 6bc27805..23349528 100644 --- a/docs/cpp_api/array.md +++ b/docs/cpp_api/array.md @@ -118,7 +118,7 @@ long sz = a.size(); // 2 --- -### operator[](long index) const → Object +### `operator[](long index) const` → Object Get the element at the given index (read-only). @@ -139,7 +139,7 @@ Object last = a[-1]; // "hello" --- -### operator[](long index) → Proxy +### `operator[](long index)` → Proxy Get a proxy for the element at the given index (read-write). diff --git a/docs/cpp_api/hash.md b/docs/cpp_api/hash.md index 9015c7e0..9dcc2f2a 100644 --- a/docs/cpp_api/hash.md +++ b/docs/cpp_api/hash.md @@ -54,7 +54,7 @@ size_t sz = h.size(); // 2 --- -### operator[](Key_T const& key) const -> Proxy const +### `operator[](Key_T const& key) const` -> Proxy const Get the value for the given key (read-only). @@ -78,7 +78,7 @@ Object value = h["name"]; // "Alice" --- -### operator[](Key_T const& key) -> Proxy +### `operator[](Key_T const& key)` -> Proxy Get a proxy for the value at the given key (read-write). diff --git a/docs/cpp_api/string.md b/docs/cpp_api/string.md index 3b6ba368..53dc8ab1 100644 --- a/docs/cpp_api/string.md +++ b/docs/cpp_api/string.md @@ -143,7 +143,7 @@ size_t len = s.length(); // 5 --- -### operator[](ptrdiff_t index) const → char +### `operator[](ptrdiff_t index) const` → char Get the character at the given index. diff --git a/docs/cpp_api/struct.md b/docs/cpp_api/struct.md index d4574ab3..8320ed5a 100644 --- a/docs/cpp_api/struct.md +++ b/docs/cpp_api/struct.md @@ -192,7 +192,7 @@ Struct::Instance instance(myStruct, existing_instance); --- -### operator[](T index) -> Object +### `operator[](T index)` -> Object Get a member by index or name. diff --git a/docs/ruby_api/buffer.md b/docs/ruby_api/buffer.md index e25d866a..e86174aa 100644 --- a/docs/ruby_api/buffer.md +++ b/docs/ruby_api/buffer.md @@ -187,7 +187,7 @@ buffer.to_ary(3) #=> [1, 2, 3] --- -### [](index) → Object +### `[](index)` → Object Returns the element at the specified index. @@ -213,7 +213,7 @@ buffer[2] #=> 30 --- -### []=(index, value) → value +### `[]=(index, value)` → value Sets the element at the specified index. diff --git a/docs/tutorial.md b/docs/tutorial.md index 05743fe1..2861cf19 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -1,7 +1,5 @@ # Tutorial -## Getting started - First [install](installation.md) Rice. Next, create an [extconf.rb](packaging/extconf.rb.md) file: @@ -418,4 +416,4 @@ For more information refer to the [Exceptions](bindings/exceptions.md) section. ## Next Steps -Hopefully this tutorial will help get you started wrapping C++ libraries for use in Ruby. For much more detailed information refer to the Bindings topic. +Hopefully this tutorial will help get you started wrapping C++ libraries for use in Ruby. For more detailed information refer to the [Wrapping C++](bindings/constructors.md) section. diff --git a/mkdocs.yml b/mkdocs.yml index cec18a9e..f5f84863 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -47,8 +47,8 @@ nav: - History: history.md - Migration: migration.md - Changelog: changelog.md - - Tutorial: tutorial.md - - Types: + - Getting Started: tutorial.md + - Type Conversion: - Overview: types/overview.md - Type Conversion: types/conversion.md - Wrapping Types: types/wrapping.md @@ -56,7 +56,8 @@ nav: - Type Naming: types/naming.md - Custom Converters: types/converters.md - Type Verification: types/verification.md - - Bindings: + - Wrapping C++: + - Overview: bindings/overview.md - Constructors: bindings/constructors.md - Methods: bindings/methods.md - Overloaded Methods: bindings/overloaded_methods.md @@ -74,7 +75,7 @@ nav: - Inheritance: bindings/inheritance.md - Callbacks: bindings/callbacks.md - Instance Registry: bindings/instance_registry.md - - STL: + - STL Support: - Overview: stl/stl.md - std::complex: stl/complex.md - std::exception: stl/exception.md @@ -94,7 +95,7 @@ nav: - std::unordered_map: stl/unordered_map.md - std::variant: stl/variant.md - std::vector: stl/vector.md - - C++ API: + - Rice Classes: - Overview: cpp_api/overview.md - Object: cpp_api/object.md - Module: cpp_api/module.md @@ -105,7 +106,7 @@ nav: - Symbol: cpp_api/symbol.md - Struct: cpp_api/struct.md - Identifier: cpp_api/identifier.md - - Ruby API: + - Ruby Runtime: - Overview: ruby_api/overview.md - Buffer: ruby_api/buffer.md - Pointer: ruby_api/pointer.md @@ -125,5 +126,6 @@ nav: - Overview: architecture/overview.md - Type Binding: architecture/type_binding.md - Method Binding: architecture/method_binding.md + - Overload Resolution: architecture/overload_resolution.md - Registries: architecture/registries.md - Enumerators: architecture/enumerators.md