The third method that allows us to communicate Ruby and Elixir is Erlectricity. It’s only a Ruby gem that you have to open an Erlang Port yourself, also you have to take care of data conversion (on Elixir side). Erlport using same trick underneath. Regardless I want do describe how to connect to Ruby with Erlectricity. Let’s do it!

Install erlectricity gem

$ gem install erlectricity

Generate new elixir project and directory for ruby script

$ mix new erlectricity_app $ cd erlectricity_app $ mkdir priv $ mkdir priv/ruby

In this example, we also try, to sum up two integers in ruby.

require 'rubygems' require 'erlectricity' receive do |f| f.when([:sum_two_integers, Integer, Integer]) do |a, b| f.send!([:result, [:ok, a+b]]) f.receive_loop end end

As you can see, Ruby DSL is more like the Elixir. We’re creating a receive loop, match incoming messages, and if matched, send a message back.

I this example, we’re waiting for the message like this {:sum_two_integers, 1, 2} and send back message like {:result, {:ok, 3}} .

Moving to Elixir part, we have to create a function that will open an Erlang Port to ruby process and send the message to this process.

defmodule ErlectricityApp do @ruby_echo Application.app_dir(:erlectricity_app, "priv/ruby/sum.rb") @command "ruby #{@ruby_echo}" def sum_two_integers_in_ruby(one, another) do pid = Port.open({:spawn, @command}, [{:packet, 4}, :nouse_stdio, :exit_status, :binary]) encoded_msg = {:sum_two_integers, one, another} |> encode_data pid |> Port.command(encoded_msg) receive do {_, {:data, data}} -> case data |> decode_data do {:result, result} -> result _ -> {:error, "Unknown message"} end end end defp encode_data(data) do data |> :erlang.term_to_binary end defp decode_data(data) do data |> :erlang.binary_to_term end end

What exactly going on here ? We need to know where is our ruby script. @ruby_echo stores that data. Next one is @command , this one stores command that will start or ruby process. Which is ruby with the path to the ruby file.

Our function first launches an Erlang port. Spawn a process with parameters.More about these parameters you can read here.

Because we’re using port protocol, we must encode our data. encode_data function will do it for us.

Finally, we can send a message to our ruby process and wait for a response. Yes, all things are happening asynchronously.

When we receive a message from Ruby process, we need to decode them withdecode*data function, match if it is a {:result, *} message, and return the result.

Fire up iex and check if it works

$ iex -S mix Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] Compiling 1 file (.ex) Interactive Elixir (1.3.3) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> ErlectricityApp.sum_two_integers_in_ruby(1,2) {:ok, 3} iex(2)> ErlectricityApp.sum_two_integers_in_ruby(5,2) {:ok, 7} iex(3)>

Work as expected. We’ve made it. Simple right ?