There are still a lot of things in Ruby world, that don’t exist in Elixir yet. To resolve that problem. I’ve done a research. Tried to figure it out if both worlds can talk to each other. And the answer is yes. They can. I’ll try to describe few ways how to do it.
I decided to split things up, each article describes one method, the first one is about Export / Erlport.
This method launches Ruby interpreter and provides some API to convert types between each other.
So create a simple Elixir application that uses a Ruby gem.
$ mix new elixir_ruby_app
$ cd elixir_ruby_app
Add export package to deps and applications in mix.exs
def application do
[applications: [:export]]
end
def deps do
[
{:export, “~> 0.0.7”},
{:erlport, github: “hdima/erlport”, manager: :make}
]
end
And download dependencies
$ mix deps.get
Done. Moving further, create a directory for ruby scripts. I choose priv because it will be included in release package generated by exrm or distilery.
$ mkdir priv
$ mkdir priv/ruby
Create our fancy.rb
ruby script in that directory.
def sum_two_integers(one, another)
result = one + another
Tuple.new(
[:ok, result]
)
end
Function that invoke our ruby code looks like this:
defmodule ElixirRubyApp do
@ruby_dir Application.app_dir(:elixir_ruby_app, "priv/ruby")
use Export.Ruby
def sum_two_integers_in_ruby(one, another) do
{:ok, ruby} = Ruby.start(ruby_lib: @ruby_dir)
ruby
|> Ruby.call(sum_two_integers(one, another), from_file: "fancy")
end
end
It’s time to magic happen, run iex and run function.
$ iex -S mix
erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.3.3) — press Ctrl+C to exit (type h() ENTER for help)
iex(1)> ElixirRubyApp.sum_two_integers_in_ruby(1,2)
{:ok, 3}
iex(2)>
Bang! Got a result from Ruby. You can use now all rubygems that you want. For example I’m using icalendar gem to parse ical files.
But we’re not finished yet! What about calling elixir functions from ruby?
Let’s try! Add fancy.ex
file:
defmodule ElixirRubyApp.Fancy do
def sum_two_integers_in_elixir(one, another) do
result = one + another
{:ok, result}
end
end
OK, We’re changed our mind, now we want to sum these integers in Elixir, but within Ruby. Crazy idea, but why not? Change our fancy.rb
file to call a function from Elixir.
include ErlPort::Erlang
def sum_two_integers(one, another)
call('Elixir.ElixirRubyApp.Fancy'.to_sym, :sum_two_integers_in_elixir, [one, another])
end
Again, run iex
, and see what will happen.
$ iex -S mix
Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.3.3) — press Ctrl+C to exit (type h() ENTER for help)
iex(1)> ElixirRubyApp.sum_two_integers_in_ruby(14,2)
{:ok, 16}
iex(2)>
Double bang! Our crazy idea just work. Beautiful. We’re done. As you may notice, export also work with python.