Elixir і Ruby — не сваріться. Взаємодійте! (ExPort/ErlPort)


Нарешті сталося, я більше не розробляю програми на Rails. Тепер Elixir — мій основний інструмент, і я радий цьому.
Тим не менше все ще існує безліч напрацювань у Ruby-світі, аналогів яких немає у Elixir. Щоб обійти цю проблему, я вирішив з'ясувати можуть обидва світу взаємодіяти один з одним. І відповідь — так! Вони можуть.
Я спробую описати кілька способів, як це зробити.
Щоб не змішувати все в одну купу, матеріал буде розбитий на кілька статей, кожна з яких буде описувати тільки один спосіб. Перша — про ExPort / ErlPort.
Примітка: ExPort також дозволяє взаємодіяти з Python.

Цей спосіб запускає інтерпретатор Ruby і надає допоміжний API для перетворення типів.
Отже, давайте створимо просте додаток на Elixir, використовує Ruby-код.
$ mix new elixir_ruby_app
$ cd elixir_ruby_app

Додайте пакет
export
в списки
deps
та
applications
у mix.exs
def application do
[applications: [:export]]
end

def deps do
[
{:export, "~> 0.0.7"},
{:erlport, github: "hdima/erlport", manager: :make}
]
end

Скачайте залежності
$ mix deps.get

Готово. Тепер давайте створимо директорію для Ruby-скриптів. Я вибрав priv, оскільки вона буде включена в релізну збірку, генеровану exrm або distilery.
$ mkdir -p priv/ruby

скрипт Створіть fancy.rb в цій директорії з наступним вмістом:
def sum_two_integers(one, another)
result = one + another
Tuple.new(
[:ok, result]
)
end

Код, що викликає функцію з Ruby, виглядає так:
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

Настав час чарівництва. Запустіть iex і викличте функцію:
$ iex -S mix
erlang/OTP 19 [ea-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}

Бац! Ми отримали результат з Ruby. Ви можете використовувати будь-які Ruby gems, які захочете. Наприклад, я використовую гем icalendar для розбору ical-файлів.
Але ми ще не закінчили! Як щодо виклику Elixir-функцій з Ruby?
Давайте спробуємо! Створіть файл fancy.ex:
defmodule ElixirRubyApp.Fancy do
def sum_two_integers_in_elixir(one, another) do
result = one + another
{:ok, result}
end
end

Добре, ми передумали і тепер хочемо підсумувати числа Elixir, але всередині Ruby. Божевільна ідея, але чому б і ні? Змінимо наш файл fancy.rb, щоб він викликав функцію з Elixir:
include ErlPort::Erlang

def sum_two_integers(one, another)
call('Elixir.ElixirRubyApp.Fancy'.to_sym, :sum_two_integers_in_elixir, [one, another])
end

знову Запустимо iex і подивимося, що станеться.
$ iex -S mix
Erlang/OTP 19 [ea-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}

Наша божевільна ідея спрацювала без проблем. Чудово.
Існують і інші способи викликати Ruby з Elixir і навпаки. Але про них ми поговоримо в наступних статтях.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.