ronky 1.2.5

A simple way to export Rust definitions to Arri types
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# ๐Ÿฑ RONKY ๐Ÿฑ

[![Crates.io Version](https://img.shields.io/crates/v/ronky)](https://crates.io/crates/ronky)
[![Purrs Per Minute](https://img.shields.io/badge/purrs-over%209000-orange)](https://github.com/modiimedia/arri)
[![Cat Approved](https://img.shields.io/badge/cat-approved-brightgreen)](https://github.com/modiimedia/arri)
[![Rustacean Friendly](https://img.shields.io/badge/rustacean-friendly-blue)](https://github.com/modiimedia/arri)

_"Converting Rust types shouldn't be this purr-fect, but here we are..."_

## ๐Ÿ˜บ What in the Whiskers is Ronky?

Imagine if your Rust types could speak other languages without learning a single foreign word.
That's Ronky โ€“ your code's personal polyglot translator that speaks fluent
[Arri](https://github.com/modiimedia/arri), turning your carefully crafted Rust types into
schemas that even JavaScript developers can understand.

Born from the frustration of manual schema creation (and named after a particularly vocal cat),
Ronky does the tedious work so you can focus on the important stuff โ€“ like deciding whether your
next variable should be called `data` or `info` (we both know you'll pick `data`).


<!--toc:start-->

- [๐Ÿฑ RONKY ๐Ÿฑ]#-ronky-
  - [๐Ÿ˜บ What in the Whiskers is Ronky?]#-what-in-the-whiskers-is-ronky
  - [โœจ Features That Make You Go "Meow!"]#-features-that-make-you-go-meow
  - [๐Ÿค The Cool Cats Club (Compatible Crates)]#-the-cool-cats-club-compatible-crates
  - [๐Ÿ“š The Illustrated Guide to Ronky]#-the-illustrated-guide-to-ronky
    - [๐Ÿ”„ The Basic Transformation]#-the-basic-transformation
    - [๐Ÿงฉ The Advanced Cat-egory: Building Complex Types]#-the-advanced-cat-egory-building-complex-types
  - [๐Ÿ“‹ Quick Reference]#-quick-reference
    - [The Basics]#the-basics
    - [Attribute Options]#attribute-options
  - [๐Ÿˆ The Ronky Memorial Section]#-the-ronky-memorial-section
  - [๐Ÿ› ๏ธ Development]#๏ธ-development
    - [Pre-commit Hooks]#pre-commit-hooks
    - [Running Tests]#running-tests
    - [Code Quality Checks]#code-quality-checks
  - [๐ŸŒŸ Final Thought]#-final-thought
  <!--toc:end-->

## โœจ Features That Make You Go "Meow!"

Ronky doesn't just toss your types over the fence to Arri-land. It crafts them with the same
attention to detail that a cat gives to knocking your most precious possessions off shelves:

```text
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                          RONKY'S REPERTOIRE                           โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ ๐Ÿงฌ Type Wizardry          โ”‚ - Transforms primitives with grace        โ”‚
โ”‚                           โ”‚ - Handles generic types without whining   โ”‚
โ”‚                           โ”‚ - Makes associated types feel welcome     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ ๐Ÿงฉ Collection Conjuring   โ”‚ - Vectors become elegant "elements"       โ”‚
โ”‚                           โ”‚ - Maps manifest as "values" schemas       โ”‚
โ”‚                           โ”‚ - Optional types know when to disappear   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ ๐Ÿ›ก๏ธ Guardian Features      โ”‚ - Strict mode keeps schemas pristine      โ”‚
โ”‚                           โ”‚ - Discriminators tag unions properly      โ”‚
โ”‚                           โ”‚ - Circular refs handled without dizziness โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ ๐Ÿ”„ Transformation Magic   โ”‚ - Case transformations (snake โ†’ UPPER)    โ”‚
โ”‚                           โ”‚ - Field renaming for multilingual joy     โ”‚
โ”‚                           โ”‚ - Nullable marking for optional presence  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ ๐Ÿ“ Documentation Delight  โ”‚ - Comments become documentation           โ”‚
โ”‚                           โ”‚ - Deprecation warnings that don't nag     โ”‚
โ”‚                           โ”‚ - Metadata that brings joy to readers     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
```

With Ronky, your type schema generation is both:

1. **Compile-time verified** - Errors at compile time, not at 3 AM when you're deploying
2. **Automatically generated** - Because life's too short to manually update schemas

> ๐Ÿ’ก **Pro Tip**: Ronky's powers grow with your documentation. The more doc comments you add,
> the more magnificent your schemas become. It's like feeding treats to a cat โ€“ the rewards
> are well worth it.

## ๐Ÿค The Cool Cats Club (Compatible Crates)

Ronky has an extensive social network. Think of these crates as the neighborhood cats that
regularly visit your backyard โ€“ they're all welcome and get special treatment:

```text
TEMPORAL FRIENDS         ๐Ÿ•ฐ๏ธ  chrono, time
IDENTITY SPECIALISTS     ๐Ÿชช  uuid
BIG NUMBER EXPERTS       ๐Ÿ”ข  bigdecimal, num-bigint, num-bigfloat
PRECISION MASTERS        ๐Ÿ’ฐ  rust_decimal, decimal
WEB-SAVVY NAVIGATORS     ๐ŸŒ  url
DATA-HANDLING WIZARDS    ๐Ÿ“Š  bytes
CONCURRENT COMPANIONS    ๐Ÿงต  dashmap
OPTIMIZED PERFORMERS     โšก  smallvec
DYNAMIC SHAPESHIFTERS    ๐Ÿ”ฎ  any (Value type for arbitrary JSON)
```

Each of these crates gets the VIP (Very Important Purring) treatment from Ronky. Their types
are handled with the care and respect they deserve.

> ๐Ÿˆ **Missing your favorite companion?** Check if an issue exists, and if not, create one!
> The more the merrier in Ronky's compatible crates collection.

## ๐Ÿ“š The Illustrated Guide to Ronky

### ๐Ÿ”„ The Basic Transformation

```rust
use ronky::{Exportable, Exported, SCHEMA_VERSION};
use serde_json::{Value, from_str, to_string_pretty};

// Just add water (and a derive macro)
#[derive(Exported)]
#[arri(transform = "uppercase")] // LOUD NOISES
enum Result<T: Exportable, E: Exportable> {
    /// When things go right (rarely, if you're me)
    Ok(T),
    /// When things go wrong (my default state)
    Err(E),
}

fn main() {
    // Announce our intentions to the world
    println!("๐Ÿงช Creating an Arri {} schema and hoping for the best...", SCHEMA_VERSION);

    // The cat-alchemy happens here
    let schema_json = Result::<String, ()>::export()
        .serialize()
        .expect("this to work (please, I have deadlines)");

    // Humans like pretty things
    let pretty_json = to_string_pretty(&from_str::<Value>(&schema_json).unwrap()).unwrap();

    // Admire our handiwork
    println!("{}", pretty_json);

    // Now go make a cup of tea, you've earned it
}
```

### ๐Ÿงฉ The Advanced Cat-egory: Building Complex Types

```rust
use ronky::{Exportable, Exported, SCHEMA_VERSION};

/// Metadata about things (and sometimes other things)
/// Automatically converts snake_case field names to camelCase for the schema
#[derive(Exported)]
#[arri(rename_all = "camelCase")] // firstName, lastName, etc. in the schema
struct About<T: Exportable> {
    /// What we called it before marketing got involved
    #[deprecated(since = "1.0.0", note = "Use `firstName` and `lastName` instead")]
    name: String,

    /// The name that appears on your coffee cup at Starbucks
    first_name: String, // Becomes "firstName" in the schema

    /// The name your parents use when you're in trouble
    last_name: Option<String>, // Becomes "lastName" in the schema

    /// The number that makes you sigh at birthday parties
    age: u32,

    /// The subject of our obsession
    of: T,
}

/// A creature that creates Rust crates, ironically
#[derive(Exported)]
#[arri(strict)] // No surprises allowed! Like a cat with a cucumber
struct Human {
    /// Fellow code-monkeys who review your PRs
    friends: Vec<Human>, // Recursive types? No problem!

    /// The real owners of your home
    pets: Vec<About<Pet>>,
}

/// Fashion choices for the discerning feline
#[derive(Exported)]
#[arri(transform = ["snake_case", "uppercase"])] // MULTI_STYLE_TRANSFORMATION
enum CatColor {
    /// Like my coffee and my humor
    Black,

    /// Like my documentation standards and error handling
    White,

    /// Like my moral compass when it comes to optimization
    Gray,

    /// Like my commit history after a weekend hackathon
    MixedGrayWhite,
}

/// Entities that interrupt your Zoom calls at the worst possible moment
#[derive(Exported)]
#[arri(transform = "uppercase", discriminator = "species")]
enum Pet {
    Dog {
        /// The word you'll repeat 37 times at the dog park
        name: String,

        /// What you'll forget when the vet asks
        #[arri(nullable)]
        breed: Option<String>,
    },

    #[arri(rename = "cat")] // All hail the cat overlords!
    Lion {
        /// A suggestion they might consider responding to someday
        name: String,

        /// Their royal garment
        #[arri(nullable)]
        color: Option<CatColor>,
    },
}
```

> ๐Ÿ”ฅ **Hot Tip**: These examples aren't just decorative โ€“ they're functional!
> Copy, paste, and experience the magic of Ronky firsthand. Your future self
> will thank you when your API documentation is automatically up-to-date.

### ๐Ÿ”ฎ The Dynamic Shapeshifter: Working with Any Type

Sometimes you need to handle arbitrary JSON data without knowing its structure at compile time.
Enable the `any` feature (along with `derive` for the macro) and use the `Value` type:

```toml
ronky = { version = "1.2.5", features = ["derive", "any"] }
```

```rust
use ronky::{Exported, Value, NumberValue};
use std::collections::BTreeMap;

/// A configuration that accepts arbitrary metadata
#[derive(Exported)]
struct Config {
    /// The name of this configuration
    name: String,

    /// Arbitrary metadata - could be anything!
    /// Exports to an empty Arri schema `{}` which accepts any JSON value
    metadata: Value,
}

fn main() {
    // Create dynamic values
    let mut meta = BTreeMap::new();
    meta.insert("version".to_string(), Value::Number(NumberValue::PosInt(42)));
    meta.insert("enabled".to_string(), Value::Bool(true));
    meta.insert("tags".to_string(), Value::Array(vec![
        Value::String("production".to_string()),
        Value::String("critical".to_string()),
    ]));

    let config = Config {
        name: "my-service".to_string(),
        metadata: Value::Object(meta),
    };

    // The schema exports `metadata` as `{}` - accepts any JSON value
    let schema = Config::export().serialize().unwrap();
}
```

> ๐Ÿฑ **Note**: The `Value` type maps to Arri's "Empty Schema Form" (`{}`), which accepts
> any JSON value. This is equivalent to `any` in TypeScript or `interface{}` in Go.

## ๐Ÿ“‹ Quick Reference

### The Basics

1. Add `ronky` to your `Cargo.toml`:

   ```toml
   [dependencies]
   ronky = { version = "1.2.5", features = ["derive"] }
   ```

   The `derive` feature enables the `#[derive(Exported)]` macro. Additional features can be enabled as needed:

   ```toml
   [dependencies]
   ronky = { version = "1.2.5", features = ["derive", "chrono", "uuid", "any"] }
   ```

2. Import the essentials:

   ```rust
   use ronky::{Exported, SCHEMA_VERSION};
   ```

3. Decorate your types:

   ```rust
   #[derive(Exported)]
   struct MyType { /* fields */ }
   ```

4. Export and serialize:

   ```rust
   let schema = MyType::export().serialize().unwrap();
   ```

5. Profit! (This step is not automated by Ronky, sorry)

### Attribute Options

**Struct-level attributes:**
- `#[arri(strict)]` - No extra properties allowed
- `#[arri(rename_all = "camelCase")]` - Transform all field names to a specific case
  - Supported cases: `camelCase`, `PascalCase`, `snake_case`, `SCREAMING_SNAKE_CASE`, `kebab-case`, `SCREAMING-KEBAB-CASE`
- `#[arri(transform = "snake_case")]` - Transform enum variant names (enums only)
- `#[arri(discriminator = "type")]` - Set discriminator field name (tagged unions only)

**Field-level attributes:**
- `#[arri(rename = "newName")]` - Rename a specific field or variant (overrides `rename_all`)
- `#[arri(nullable)]` - Mark a field as nullable

## ๐Ÿˆ The Ronky Memorial Section

```text
     /\_/\
    ( o.o )
     > ^ <
    /  O  \  "Meow meow, transform types meow."
                                    - Ronky (2010-2024)
```

This library immortalizes a magnificent cat named Ronky, named for his thunderous purrs
(or "ronks" in Dutch). For 14 remarkable years, this whiskered genius supervised
everything that happened in the house.

Despite battling acromegaly, Ronky maintained a proud dignity and an uncanny ability
to walk across keyboards and make his presence known. His legacy continues in this library!

He passed away peacefully, surrounded by those who loved him, and will be deeply missed.

![A beautiful picture of Ronky](./.readme/assets/ronky.jpg)
Photo by [Startshot](https://www.instagram.com/_startshot_/)

## ๐Ÿ› ๏ธ Development

### Pre-commit Hooks

This project uses pre-commit hooks to maintain code quality. We support both `pre-commit` and `prek` (a Rust implementation that uses the same `.pre-commit-config.yaml` format).

**Auto-fixing**: The hooks automatically fix formatting issues, clippy warnings, trailing whitespace, and line endings. See [docs/AUTO_FIXING.md](docs/AUTO_FIXING.md) for details.

#### Using prek (Recommended for Rust projects)

`prek` is a Rust-based pre-commit hook runner that uses the standard `.pre-commit-config.yaml` configuration file.

```bash
# Install prek (if not already installed)
cargo install prek

# Install hooks
prek install

# Run all hooks manually
prek run --all-files

# Run specific hook
prek run cargo-fmt
```

#### Using pre-commit

```bash
# Install pre-commit
pip install pre-commit

# Install hooks
pre-commit install

# Run all hooks manually
pre-commit run --all-files
```

### Running Tests

```bash
# Run all tests with nextest
cargo nextest run --all

# Run specific test
cargo nextest run serialization_export

# Run with standard cargo test
cargo test --all
```

### Code Quality Checks

```bash
# Format code
cargo fmt --all

# Run clippy
cargo clippy --all-features --all-targets -- -D warnings

# Check compilation
cargo check --all --all-features

# Run all checks at once
./scripts/pre-commit-all.sh
```

## ๐ŸŒŸ Final Thought

Remember: Type conversion should be like a cat's nap โ€“ automatic, elegant, and requiring
no effort on your part. Let Ronky handle the tedious work while you focus on building
something amazing.

Now go pet your cat (or dog, or rubber duck) โ€“ they've been waiting patiently while you
read this documentation. โค๏ธ