Sign in

Зарегистрируйтесь, чтобы стать полноправным участником сообщества Masterpro.ws.

JSON RESTful API. ATM on Grape & Ruby on Rails

Сегодня в нашей программе - несложный API, построенный на основе Ruby on Rails и микрофреймворка Grape, имитирующий работу некоего банкомата. Это JSON RESTful API, банк которого вы можете "пополнить" виртуальными купюрами, и который сумеет "выдать" вам любую требуемую сумму исходя из имеющихся в наличии банкнот, при этом их количество в недрах банкомата, само собой, уменьшится. Все действия, как видно из скриншота, весьма удобно свершать посредством curl.

 

API ATM on Grape & Ruby on Rails
API ATM on Grape & Ruby on Rails

 

git clone https://github.com/cmirnow/atm-on-grape.git

 

Вы легко освоите описанную механику, посетив и клонировав репозиторий atm-on-grape, также следуя нехитрым указаниям документации. Сейчас же кратко остановлюсь всего на одном.

 

Увидеть на гитхабе.

 

Понятно, что основой логики и наиболее интересным моментом здесь является автоматический расчет требуемой суммы, исходя из числа имеющихся купюр определенных номиналов. Разберем ряд способов реализации этого механизма, часть которых вполне возможно отнести к области динамического программирования.

 

 

Два простейших решения выглядят следующим образом:

 

  def subset_sum(inp, s)
        arr = []
        loop.with_index{|_, i| arr << inp.combination(i+1).to_a.find{
    |c| (c.inject(0) {|sum,x| sum + x})  == s}; break if !a.none? || i == inp.count }
    arr
  end

  subset_sum([1,2,3,4,5,6], 15)

 

  def subset_sum(*args)
    args[0].length.downto(1).flat_map do |i|
      args[0].combination(i).to_a
    end.select do |a|
      a.inject(:+) == args[1]
    end
  end
  
  subset_sum([1,2,3,4,5,6], 15).first

 

Это отлично работает, пока первый аргумент вызова метода содержит массив из нескольких элементов (купюр), но вы не представляете, как безбожно способен затянуться процесс расчета, если количество "купюр" некритично больше; скажем, два или три десятка. В этом случае оптимально прибегнуть к такой рекурсии:

 

def subset_sum((first, *rest), target)
  return (first == target ? [first] : nil) if rest.empty?

  rv = subset_sum(rest, target)
  return rv unless rv.nil?
  return nil if first > target
  return [first] if first == target

  rv = subset_sum(rest, target - first)
  rv.nil? ? nil : [first, *rv]
end

print subset_sum([1, 2, 3, 4, 5, 6, 3, 4, 5, 6, 1, 2], 15)

 

Или даже так:

 

def subset_sum(inp, sum)
  candidates = inp.filter { |i| i < sum } # don't do this optimize if inp contain negative numbers
  sum_combi_hash = Hash.new do |hash, key|
    if key > 0
      hash[key] = { candidates[key] => [candidates[key]] }
      if hash[key - 1][sum].nil?
        hash[key - 1].each do |s, c|
          hash[key][s] = c
          new_s = s + candidates[key]
          next unless hash[key][new_s].nil?

          hash[key][new_s] = c + [candidates[key]]
          break if new_s == sum
        end
      else
        hash[key][sum] = hash[key - 1][sum]
      end
      hash[key]
    else
      hash[key] = { candidates.first => [candidates.first] }
    end
  end
  sum_combi_hash[candidates.size - 1][sum]
end

print subset_sum([1, 2, 3, 4, 5, 6, 3, 4, 5, 6, 1, 2], 15)

 

Вы сумеете провести успешные тесты описанной логики (также всего API), воспользовавшись простейшим минитестом:

 

require 'test_helper'
class Banknote::AssetTest < ActiveSupport::TestCase
  include Rack::Test::Methods

  def app
    Rails.application
  end

  test 'GET /api/v1/banknote_asset' do
    get('/api/v1/banknote_asset')
    assert last_response.ok?
    assert_equal 200, last_response.status
    assert_equal 58, last_response.length
  end

  test 'Successful cash withdrawal' do
    patch('/api/v1/banknote_asset?sum=93')
    assert_equal '[1, 2, 5, 10, 25, 50]', last_response.body
  end

  test 'Unable to issue required amount' do
    patch('/api/v1/banknote_asset?sum=94')
    assert_equal 'transaction not allowed', last_response.body
  end
end

 

Таким образом - ценность, на субъективный взгляд автора, представляют не деньги, виртуальные либо же реальные, а - сам по себе процесс познания. Воспользуйтесь моим эмпирическим опытом, если кого-то он заинтересует. cool

 

Оставить комментарий

Добавьте ваш комментарий

Комментарии в блоге

  • Гена Какой сложный и отвратительный те.... всем привет, зовут меня Гена-мудило, по профессии я срущий на чужих сайтах копеечный бот, по-совместительству…

    Суббота, 03 апреля 2021

    Опубликовано в: Про IT Selection, gray salary и Барака Обаму
  • Aleksej Доброго дня! Повторюсь, контент статьи представляет собой лишь концепт, хотя показанный код и был в свое время оттестирован и является…

    Пятница, 26 марта 2021

    Опубликовано в: Виджет amoCRM: экспорт данных в Google Docs
  • ОлегАверс Здравствуйте. Скажите, можно ли с Вашей помощью настроить и АВТОМАТИЧЕСКИ (например, ежедневно) выгружать из АМО и Битрикс24 в Эксель следующие…

    Среда, 24 марта 2021

    Опубликовано в: Виджет amoCRM: экспорт данных в Google Docs
  • Aleksej Интересно отметить: за всю свою жизнь в российском IT у меня не было ни одного проекта - а в пору,…

    Вторник, 19 января 2021

    Опубликовано в: Про IT Selection, gray salary и Барака Обаму
  • Рамат Они до сих пор такую шляпу предлагают с оформлением в известную американскую компанию через ИП или самозанятого, на прошлой неделе…

    Пятница, 15 января 2021

    Опубликовано в: Про IT Selection, gray salary и Барака Обаму