Command line calculator on Rails — dentaku
Итак, сегодня в моём блоге наконец появится первая запись по Ruby on Rails.
При разработке системы административного учёта для одного из моих клиентов на Rails я столкнулся с маленькой проблемой. Заказчик изъявил желание самостоятельно создавать новые тарифы, по которым производится расчёт платежей клиентов организации. Это значит что алгоритм работы тарифа не должен являться внутренней частью приложения. Необходимо пользователю дать возможность самостоятельно разрабатывать формулы, по которым и будут производиться расчёты. На самом деле это не проблема, это обычная практика — не обращаться же к программисту каждый раз, когда нужно изменить способ расчёта.
Для решения такой задачи тарифы легче всего хранить в виде:
ID Name Formula 1 rate1 var1+var2/var3 2 rate2 var1+var2/var3-100
При расчёте нужно просто извлечь формулу из БД, подставить переменные, рассчитать получившееся выражение и вывести результат пользователю. Самая большая сложность заключается именно на стадии «рассчитать получившееся выражение»…
В ход пошёл Google. Осознав, что найти простую и корректную функцию на Ruby (да и не только на Ruby), способную на входе принять нечто вроде «486+67/2-100», а результатом выдать «419,5», мне не удастся, я взялся за поиски информации на тему разработки простого синтаксического анализатора… И зря потерял время.
В Ruby on Rails не принято изобретать велосипед. Большинство велосипедов уже изобретено в виде гемов. Они хорошо хранятся, легко доступны и успешно причёсываются сообществом. Оказывается и мой велосипед давно изобретён. Называется он Dentaku.
Dentaku — это небольшой гем, позволяющий анализировать арифметические и логические выражения. На вход принимает строку типа «2+2*2», на выходе даёт результат операции «6».
Dentaku поддерживает работу с переменными и следующие операции:
- Математические: + — * /
- Логические: < > <= >= <> != = AND OR
- Функции: IF ROUND
Для начала нужно его установить. На Rails 3 достаточно в Gemfile просто прописать:
gem 'dentaku'
А затем выполнить в директории проекта:
bundle install
После чего увидеть его в списке установленных гемов:
Теперь можно его использовать
def calculate calculator = Dentaku::Calculator.new calculator.evaluate("2+4") #простое выражение calculator.evaluate("2+4/4*8-3*6") #более сложное выражение calculator.evaluate("var1+4/4*8-var2*6", :var1 => 3, :var2 => 6) #выражение с переменными end
Страница на Github — https://github.com/rubysolo/dentaku