After nearly two years it is finally time for the first full release of Anyolite!
Anyolite (https://github.com/Anyolite/anyolite) is a Crystal shard that includes a Ruby interpreter (either mruby or regular Ruby) into Crystal and allows for binding Crystal classes and functions directly to Ruby.
You can bind entire module hierarchies to Ruby with one single code line, you can call Ruby functions and manipulate Ruby objects from Crystal, and even share objects between both languages without worrying about memory leaks or Garbage Collector clashes. Anyolite helps you focus on the more important tasks instead of struggling with the mruby/Ruby API.
It is also possible to compile entire Ruby scripts to bytecode and even include them into your executable, all at compiletime!
Generally, Anyolite should be a perfect tool for scripting utilities in games, science or other applications, as it combines the performance of Crystal with the flexibility of Ruby, wherever you need it, without boilerplate code.
If you have any questions about Anyolite, feel free to ask!
There are currently some limitations to this (you effectively have to embed the Ruby interpreter into your project and then install the gems), but other wise this should work perfectly fine.
I’m a newbie to Crystal so please forgive me if my questions have obvious answers:
How do I retrieve the result of a script? e.g. I have a Crystal HTTP server that runs an Anyolite script and I want the script’s result as a JSON string to return to the client.
The documentation says don’t create more than one interpreter but it’s possible I’d want one for each concurrent client of my HTTP server, is that possible?
You can’t get the result of a script file directly, but you can always call a script line using Anyolite.eval (see Anyolite - anyolite 1.1.0). This will return either a generic Ruby reference or ensure a specific type at compiletime (if you pass it to the cast_to keyword).
Thank you for the offer of assistance, I do appreciate it
Below is a skeleton of a methodology that seems to give me what I want, I would just need a convention that each script must expose a run function.
Crystal
require "anyolite"
Anyolite::RbInterpreter.create do |rb|
Anyolite.set_gv("$request", "Steve")
rb.load_script_from_file("src/test.rb")
response = Anyolite.eval("run", String)
puts response
end
Would I need to use a mutex if I were to do this?
To be honest for my immediate use case I don’t expect any concurrency but it’s always good to know for the future, especially if you find an application architecture that you enjoy and would like to use again.
I will return to your post about your use case later, but I can quickly answer your questions about the hashes. Usually something like this should work, if your scripts always return hashes from a String into a union of String and Int32:
You still have to specify the type, since Crystal wants to know all possible types for a variable at compiletime - but you can do unions. If something other than the specified type is passed from Ruby, this line will throw an exception at runtime.
Crystal currently uses it for the REPL. I don’t know if it has an interface. It’d make the build process simpler by removing C dependencies and maybe remove a few of the interop limitations that come from Crystal and Ruby being different languages. It’s currently experimental though and in’t enabled for some toolchains by default and it still has bugs.
This is a bit off-topic from embedding the Crystal interpreter, but here are three lesser known Ruby implementations for embedded systems (the mruby family).
mruby
General-purpose embedded Ruby. Compiler and VM are separate. Supports most of Ruby’s syntax. Too heavy for small microcontrollers, but used in systems like satellites. Matz’s current main project.
mruby/c
A much lighter version with only a VM. It runs bytecode generated by mruby, making them interoperable. Designed for resource-constrained MCUs. Known use cases include industrial devices like sewing machines.
PicoRuby
Combines a minimal Ruby compiler with mruby/c. Optimized for RP2040 boards like the Raspberry Pi Pico. Often used in hobbyist projects such as custom keyboards.
If you search for real-world use cases of these mruby projects, most press releases are in Japanese, and results mainly point to companies in Hukuoka and Shimane (where Matz lives).
Still, these implementations are open source, and technically adventurous communities such as Crystal may benefit directly or indirectly from them…