Можно ли проверить количество методов, назначенных Proc в Ruby? - PullRequest
0 голосов
/ 29 ноября 2010

В настоящее время я работаю над DSL в отношении бухгалтерского учета.Я хотел бы иметь возможность:

accountant do
  credit @account_1, -@amount
  debit  @account_2,  @amount
end

В настоящее время выполняется следующий метод:

class Accountant
  def accountant &block
    AccountantHelper.class_eval(&block)
  end
end

... который, в свою очередь, выполняет блок в AccountantHelper.class, вызывающий методы "credit" и "debit" соответственно:

class AccountantHelper
  def self.credit account, amount
    account.credit amount
  end

  def self.debit account, amount
    account.debit amount
  end
end

(Пожалуйста, воздержитесь от использования огня class_eval () - это всего лишь прототип!)

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

accountant do
  credit @account_1, @amount
end

... И код будет выполнен без ошибок.Это было бы плохо, поскольку нет соответствующего «дебета» для поддержания баланса счетов.

Можно ли проверить, что поступило в блок?Или я иду по неверному пути?

1 Ответ

2 голосов
/ 29 ноября 2010

Полагаю, вы можете сделать ваши действия credit и debit "ленивыми", чтобы они выполнялись методом-оболочкой после проверки.Вот подтверждение концепции, похожее на ваше, но без метапрограммирования, пропущенное для ясности:

def transaction
  yield
  if @actions.map(&:last).inject(&:+) == 0
    @actions.each do |account, amount|
      @accounts[account] += amount
    end
    @actions = []
    puts 'transaction executed ok'
  else
    puts 'balance not zero, rolling back transaction'
    # rollback (effectively, do nothing)
  end
end

def credit account, amount
  @actions << [account, amount]
end

def debit account, amount
  @actions<< [account, -amount]
end

@actions = []
@accounts = {a: 0, b: 0, c: 0} # start with three blank accounts

transaction do
  credit :a, 5
  debit :b, 2
  debit :c, 3
end
#=>transaction executed ok

p @accounts
#=>{:a=>5, :b=>-2, :c=>-3}

transaction do
  credit :a, 5
  debit :b, 4
end
#=> balance not zero, rolling back transaction

p @accounts
#=> {:a=>5, :b=>-2, :c=>-3}
...