From Rust to Ruby

xlii1 pts0 comments

From Rust to Ruby

Available for hire [about] ·<br>[resume].

home

2026-05-26

From Rust to Ruby

Who does things like that?!?

Apparently: me.

I have my own project, written in Rust. Not a big one, mind you, maybe approx. 30k lines of code in total. Rust is verbose so it&rsquo;s not really that impressive. I&rsquo;ve put it aside for some time and was toying with local inference, LLMs, writing agents and my attention was brought to Ruby.

It&rsquo;s been a while. So I had to take a look around to remind myself what Ruby and Ruby on Rails are doing nowadays. They&rsquo;re doing quite well. There are some typing initiatives (Sorbet), and the language itself is terse as ever.

And then I had this thought… But an introduction is in order first: In my Rust app I have an isolated crate that&rsquo;s pretty much a webapp written with Tera and Axum. 14,943 lines of Rust code in total, around 10s of compilation time (maybe the code isn&rsquo;t big, but it pulls the whole universe behind itself) and then quite heavy E2E tests involving setting up Playwright and (because of the near-impossibility of mocking) an isolated database namespace and mocking services (along with a very special internal-api crate that allows Playwright to interact with the app in headless mode…).

So I thought &ldquo;hmm, I wonder if I can get my Local Qwen3.6 to do a oneshot conversion&rdquo;. But before I did so I researched first. I asked a few instances to analyse the project in terms of gains of complexity, stability, testability, etc., and while (obviously) stability would drop (no types in Ruby) it&rsquo;s not that awful (Sorbet has types in Ruby!).

┌─────────────────────────────────┬──────────────────┬───────┬────────────────┐<br>│ Area │ Rust/Axum/Diesel │ Rails │ Rails + Sorbet │<br>├─────────────────────────────────┼──────────────────┼───────┼────────────────┤<br>│ Suitability for solo dev │ 60 │ 90 │ 85 │<br>├─────────────────────────────────┼──────────────────┼───────┼────────────────┤<br>│ Development speed │ 40 │ 90 │ 75 │<br>├─────────────────────────────────┼──────────────────┼───────┼────────────────┤<br>│ Safety │ 95 │ 55 │ 80 │<br>├─────────────────────────────────┼──────────────────┼───────┼────────────────┤<br>│ Development complexity │ 70 │ 90 │ 75 │<br>├─────────────────────────────────┼──────────────────┼───────┼────────────────┤<br>│ Performance │ 95 │ 50 │ 50 │<br>├─────────────────────────────────┼──────────────────┼───────┼────────────────┤<br>│ Boilerplate │ 30 │ 85 │ 80 │<br>├─────────────────────────────────┼──────────────────┼───────┼────────────────┤<br>│ E2E testing testability │ 40 │ 75 │ 75 │<br>├─────────────────────────────────┼──────────────────┼───────┼────────────────┤<br>│ Unit testability │ 20 │ 90 │ 90 │<br>├─────────────────────────────────┼──────────────────┼───────┼────────────────┤<br>│ Integration testing testability │ 30 │ 85 │ 85 │<br>├─────────────────────────────────┼──────────────────┼───────┼────────────────┤<br>│ Sum │ 480 │ 710 │ 695 │<br>└─────────────────────────────────┴──────────────────┴───────┴────────────────┘<br>So in the end it seems I have (licks finger and turns to the wind) 1.47x better outcomes if the app were a Ruby on Rails app instead.

I have a local LLM running on my (bought it for gaming pre-AI craze) 4090 Ti1 - I&rsquo;m a free man with unlimited tokens2. So I thought: BRING IT ON!

Since it is a relatively small project the conversion took ~30 minutes. I have no idea if it works or not because I haven&rsquo;t yet tried running it. But there is one thing I checked, and stared at in horror:

$ fd . -e rs -uu | xargs cat | wc -l<br>14943<br>$ fd . -e rb -uu | xargs cat | wc -l<br>3322

That&rsquo;s right folks! 77% decrease in line count; 4.49 lines of Rust code for each line of Ruby.

I browsed the Ruby code and it looks… fine. There are probably some bugs (no bunnies) but I must say it&rsquo;s looking clean and idiomatic for my dated eye. I&rsquo;m going to examine it further with some things in mind:

I can add types using Agents, so probably type safety can be alleviated

Ruby/Rails is pretty much batteries+kitchen sink included, which beats 3GiB of compiled deps.

Testing will be SO MUCH EASIER

VCR.use_cassette("llm_call") do<br>result = LlmClient.match(entry, data_list)<br>expect(result.results.size).to eq(data_list.size)<br>end

vs

#[derive(Debug)]<br>pub struct MockProvider {<br>responses: ArcRwLockVecResponse>>>,<br>call_count: ArcAtomicUsize>,

impl Default for MockProvider {<br>fn default() -> Self {<br>Self {<br>responses: Arc::new(RwLock::new(vec![Response::default()])),<br>call_count: Arc::new(AtomicUsize::new(0)),

impl MockProvider {<br>pub fn new(responses: VecResponse>) -> Self {<br>Self {<br>responses: Arc::new(RwLock::new(responses)),<br>call_count: Arc::new(AtomicUsize::new(0)),

#[async_trait]<br>impl Provider for MockProvider {<br>async fn match(&self, entry: &Entry, data_list: &[Data]) -> ResultMatchResult> {<br>self.call_count.fetch_add(1, Ordering::SeqCst);<br>let responses = self.responses.read().await;<br>Ok(MatchResult { results: responses.clone() })

#[cfg(test)]<br>mod...

ruby rsquo rust responses self code

Related Articles